From 6b27fa0b24625a5ac1e6b9154e984b0352d33814 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 28 Jun 2023 07:59:21 +0000 Subject: [PATCH 001/189] Bump release-drafter/release-drafter from 5.23.0 to 5.24.0 Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 5.23.0 to 5.24.0. - [Release notes](https://github.com/release-drafter/release-drafter/releases) - [Commits](https://github.com/release-drafter/release-drafter/compare/v5.23.0...v5.24.0) --- updated-dependencies: - dependency-name: release-drafter/release-drafter dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 4088e489..f70c434f 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -11,6 +11,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Run release-drafter - uses: release-drafter/release-drafter@v5.23.0 + uses: release-drafter/release-drafter@v5.24.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From ef8d641b59658a0a5eef57f4856eb6ffaf1b6a01 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 31 Jul 2023 07:37:27 +0000 Subject: [PATCH 002/189] Bump svenstaro/upload-release-action from 2.6.1 to 2.7.0 Bumps [svenstaro/upload-release-action](https://github.com/svenstaro/upload-release-action) from 2.6.1 to 2.7.0. - [Release notes](https://github.com/svenstaro/upload-release-action/releases) - [Changelog](https://github.com/svenstaro/upload-release-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/svenstaro/upload-release-action/compare/2.6.1...2.7.0) --- updated-dependencies: - dependency-name: svenstaro/upload-release-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d1cff464..20bc9ab6 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: filename: frigate-hass-card.zip - name: Upload JS files to release - uses: svenstaro/upload-release-action@2.6.1 + uses: svenstaro/upload-release-action@2.7.0 with: repo_token: ${{ secrets.GITHUB_TOKEN }} @@ -41,7 +41,7 @@ jobs: overwrite: true - name: Upload Zip file to release - uses: svenstaro/upload-release-action@2.6.1 + uses: svenstaro/upload-release-action@2.7.0 with: repo_token: ${{ secrets.GITHUB_TOKEN }} From b663e0b73183454d905b895eda93f87faf493df9 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 8 Aug 2023 22:26:25 -0700 Subject: [PATCH 003/189] Initial support for grid for live and media viewer. --- .vscode/settings.json | 3 +- package.json | 2 + src/card.ts | 74 +++- src/components/gallery.ts | 6 +- src/components/live/live-image.ts | 6 +- src/components/live/live.ts | 232 ++++++++--- src/components/media-carousel.ts | 3 - src/components/media-grid.ts | 80 ++++ src/components/surround.ts | 24 +- src/components/thumbnail-carousel.ts | 2 +- src/components/timeline-core.ts | 71 ++-- src/components/timeline.ts | 13 +- src/components/title-control.ts | 22 +- src/components/viewer.ts | 358 ++++++++++++----- src/components/views.ts | 3 +- src/conditions.ts | 12 +- src/const.ts | 19 +- src/editor.ts | 79 +++- src/localize/languages/en.json | 15 + src/localize/languages/it.json | 14 + src/localize/languages/pt-BR.json | 15 + src/localize/languages/pt-PT.json | 15 + src/scss/{live.scss => basic-block.scss} | 0 src/scss/live-carousel.scss | 9 + src/scss/live-image.scss | 5 - src/scss/media-filter.scss | 2 +- src/scss/media-grid.scss | 50 +++ src/scss/surround.scss | 5 - src/scss/timeline.scss | 5 - src/scss/title-control.scss | 2 + src/scss/viewer-carousel.scss | 32 ++ src/types.ts | 43 +- src/utils/action.ts | 13 + src/utils/basic.ts | 5 + src/utils/media-grid-controller.ts | 328 ++++++++++++++++ src/utils/media-info.ts | 30 ++ src/utils/media-to-view.ts | 57 ++- src/utils/menu-controller.ts | 30 +- src/utils/zoom/zoom.ts | 15 +- src/view/media-queries-results.ts | 268 ++++++++++--- src/view/media-queries.ts | 12 +- src/view/media.ts | 3 - src/view/view.ts | 30 +- tests/camera-manager/utils.test.ts | 44 +-- tests/conditions.test.ts | 13 +- tests/test-utils.ts | 81 +++- tests/utils/action.test.ts | 18 + tests/utils/basic.test.ts | 18 +- tests/utils/media-grid-controller.test.ts | 400 +++++++++++++++++++ tests/utils/media-to-view.test.ts | 452 ++++++++++++++++++++++ tests/utils/media.test.ts | 7 + tests/utils/menu-controller.test.ts | 33 +- tests/utils/screenshot.test.ts | 26 +- tests/view/media-classifier.test.ts | 66 ++++ tests/view/media-queries-results.test.ts | 233 +++++++++++ tests/view/media-queries.test.ts | 102 +++++ tests/view/media.test.ts | 60 +++ tests/view/view.test.ts | 94 ++++- yarn.lock | 78 ++++ 59 files changed, 3308 insertions(+), 429 deletions(-) create mode 100644 src/components/media-grid.ts rename src/scss/{live.scss => basic-block.scss} (100%) delete mode 100644 src/scss/live-image.scss create mode 100644 src/scss/media-grid.scss delete mode 100644 src/scss/surround.scss delete mode 100644 src/scss/timeline.scss create mode 100644 src/utils/media-grid-controller.ts create mode 100644 tests/utils/media-grid-controller.test.ts create mode 100644 tests/utils/media-to-view.test.ts create mode 100644 tests/view/media-classifier.test.ts create mode 100644 tests/view/media-queries-results.test.ts create mode 100644 tests/view/media-queries.test.ts create mode 100644 tests/view/media.test.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 31c57af5..1814a117 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -5,5 +5,6 @@ "i18n-ally.keepFulfilled": true, "i18n-ally.editor.preferEditor": true, "i18n-ally.translate.saveAsCandidates": true, - "vitest.commandLine": "npx vitest --root ." + "vitest.commandLine": "npx vitest --root .", + "diffEditor.experimental.useVersion2": true } diff --git a/package.json b/package.json index 260fa40f..ef7c35fd 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "lit": "^2.3.1", "lit-flatpickr": "^0.4.0", "lodash-es": "^4.17.21", + "masonry-layout": "^4.2.2", "moment": "^2.29.4", "propagating-hammerjs": "^2.0.1", "quick-lru": "^6.1.0", @@ -58,6 +59,7 @@ "@rollup/plugin-node-resolve": "^13.3.0", "@rollup/plugin-replace": "^4.0.0", "@types/lodash-es": "^4.17.5", + "@types/masonry-layout": "^4.2.5", "@typescript-eslint/eslint-plugin": "^5.36.2", "@typescript-eslint/parser": "^5.36.2", "@vitest/coverage-c8": "^0.29.8", diff --git a/src/card.ts b/src/card.ts index b0ead46e..21f182b9 100644 --- a/src/card.ts +++ b/src/card.ts @@ -59,6 +59,7 @@ import { Message, MESSAGE_TYPE_PRIORITIES, RawFrigateCardConfig, + ViewDisplayMode, } from './types.js'; import { convertActionToFrigateCardCustomAction, @@ -97,6 +98,7 @@ import { } from './utils/substream'; import { Timer } from './utils/timer'; import { getParseErrorPaths } from './utils/zod.js'; +import { ViewMediaClassifier } from './view/media-classifier'; import { View } from './view/view.js'; /** A note on media callbacks: @@ -186,6 +188,9 @@ class FrigateCard extends LitElement { @state() protected _expand = false; + @state() + protected _viewDisplayMode?: ViewDisplayMode; + protected _microphoneController?: MicrophoneController; protected _conditionController?: ConditionController; protected _automationsController?: AutomationsController; @@ -414,6 +419,7 @@ class FrigateCard extends LitElement { state: this._hass.states, }), media_loaded: this._mediaLoadedInfoController.has(), + displayMode: undefined, }); } @@ -466,6 +472,7 @@ class FrigateCard extends LitElement { this._conditionController?.setState({ view: this._view.view, camera: this._view.camera, + displayMode: this._view.displayMode ?? undefined, }); }; @@ -493,10 +500,14 @@ class FrigateCard extends LitElement { } if (cameraID) { + const viewName = args?.viewName ?? this._getConfig().view.default; + const displayMode = + this._viewDisplayMode ?? this._getDefaultDisplayModeForView(viewName); changeView( new View({ - view: args?.viewName ?? this._getConfig().view.default, + view: viewName, camera: cameraID, + displayMode: displayMode, }), ); @@ -641,7 +652,10 @@ class FrigateCard extends LitElement { targetCamera && (this._view.camera !== targetCamera || !this._view.is('live')) ) { - this._changeView({ view: new View({ view: 'live', camera: targetCamera }) }); + this._changeView({ + viewName: 'live', + cameraID: targetCamera, + }); changedCamera = true; } } @@ -1003,7 +1017,7 @@ class FrigateCard extends LitElement { if (this._view.isViewerView() && media) { media_content_id = media.getContentID(); - media_content_type = media.getContentType(); + media_content_type = ViewMediaClassifier.isVideo(media) ? 'video' : 'image'; title = media.getTitle(); thumbnail = media.getThumbnail(); } else if (this._view?.is('live') && cameraEntity) { @@ -1049,6 +1063,24 @@ class FrigateCard extends LitElement { } } + protected _getDefaultDisplayModeForView(view: FrigateCardView): ViewDisplayMode { + let mode: ViewDisplayMode | null = null; + switch (view) { + case 'clip': + case 'clips': + case 'recording': + case 'recordings': + case 'snapshot': + case 'snapshots': + mode = this._getConfig().media_viewer.display?.mode ?? null; + break; + case 'live': + mode = this._getConfig().live.display?.mode ?? null; + break; + } + return mode ?? 'single'; + } + protected _cardActionHandler(frigateCardAction: FrigateCardCustomAction): void { // Note: This function needs to process (view-related) commands even when // _view has not yet been initialized (since it may be used to set a view @@ -1119,7 +1151,8 @@ class FrigateCard extends LitElement { ? targetView : FRIGATE_CARD_VIEW_DEFAULT; this._changeView({ - view: new View({ view: actualView, camera: selectCameraID }), + viewName: actualView, + cameraID: selectCameraID, }); } break; @@ -1203,6 +1236,25 @@ class FrigateCard extends LitElement { } }); break; + case 'display_mode_select': + this._viewDisplayMode = frigateCardAction.display_mode; + this._conditionController?.setState({ + displayMode: this._viewDisplayMode, + }); + // If the new mode is for all cameras, but the current query does not + // have a query for every cameraID, reset it. + const resetQuery = + frigateCardAction.mode === 'grid' && + !this._view?.query?.hasQueriesForCameraIDs( + this._cameraManager.getStore().getVisibleCameraIDs(), + ); + this._changeView({ + view: this._view?.evolve({ + displayMode: frigateCardAction.display_mode, + ...(resetQuery && { query: null, queryResults: null }), + }), + }); + break; default: console.warn(`Frigate card received unknown card action: ${action}`); } @@ -1501,15 +1553,21 @@ class FrigateCard extends LitElement { ? `${lastKnown.width} / ${lastKnown.height}` : 'unset', ); - // Non-media mays have no intrinsic dimensions and so we need to explicit - // request the dialog to use all available space. + // Non-media may have no intrinsic dimensions (or multiple media items in a + // grid) and so we need to explicit request the dialog to use all available + // space. + const isGrid = this._view?.isGrid(); this.style.setProperty( '--frigate-card-expand-width', - this._view?.isAnyMediaView() ? 'none' : 'var(--frigate-card-expand-max-width)', + !isGrid && this._view?.isAnyMediaView() + ? 'none' + : 'var(--frigate-card-expand-max-width)', ); this.style.setProperty( '--frigate-card-expand-height', - this._view?.isAnyMediaView() ? 'none' : 'var(--frigate-card-expand-max-height)', + !isGrid && this._view?.isAnyMediaView() + ? 'none' + : 'var(--frigate-card-expand-max-height)', ); } diff --git a/src/components/gallery.ts b/src/components/gallery.ts index c331be0d..fcf6fed6 100644 --- a/src/components/gallery.ts +++ b/src/components/gallery.ts @@ -368,7 +368,9 @@ export class FrigateCardGalleryCore extends LitElement { this.view ?.evolve({ query: newMediaQueries, - queryResults: new MediaQueriesResults(extension.results).selectResultIfFound( + queryResults: new MediaQueriesResults({ + results: extension.results, + }).selectResultIfFound( (media) => media === this.view?.queryResults?.getSelectedResult(), ), }) @@ -468,7 +470,7 @@ export class FrigateCardGalleryCore extends LitElement { this.view .evolve({ view: 'media', - queryResults: this.view.queryResults?.clone().selectResult( + queryResults: this.view.queryResults?.clone().selectIndex( // Media in the gallery is reversed vs the queryResults (see // note above). this._media.length - index - 1, diff --git a/src/components/live/live-image.ts b/src/components/live/live-image.ts index 58e4a03d..3aad8aa6 100644 --- a/src/components/live/live-image.ts +++ b/src/components/live/live-image.ts @@ -2,7 +2,7 @@ import { HomeAssistant } from 'custom-card-helpers'; import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { createRef, ref, Ref } from 'lit/directives/ref.js'; -import liveImageStyle from '../../scss/live-image.scss'; +import basicBlockStyle from '../../scss/basic-block.scss'; import { CameraConfig, FrigateCardMediaPlayer } from '../../types.js'; import '../image.js'; import { getStateObjOrDispatchError } from './live.js'; @@ -50,7 +50,7 @@ export class FrigateCardLiveImage extends LitElement implements FrigateCardMedia } public async getScreenshotURL(): Promise { - return await this._refImage.value?.getScreenshotURL() ?? null; + return (await this._refImage.value?.getScreenshotURL()) ?? null; } protected render(): TemplateResult | void { @@ -77,7 +77,7 @@ export class FrigateCardLiveImage extends LitElement implements FrigateCardMedia } static get styles(): CSSResultGroup { - return unsafeCSS(liveImageStyle); + return unsafeCSS(basicBlockStyle); } } diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 23e34688..cdbf87e8 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -16,12 +16,12 @@ import { guard } from 'lit/directives/guard.js'; import { keyed } from 'lit/directives/keyed.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js'; import { CameraManager } from '../../camera-manager/manager.js'; -import { CameraEndpoints } from '../../camera-manager/types.js'; +import { CameraConfigs, CameraEndpoints } from '../../camera-manager/types.js'; import { ConditionControllerEpoch, getOverriddenConfig } from '../../conditions.js'; import { localize } from '../../localize/localize.js'; import liveCarouselStyle from '../../scss/live-carousel.scss'; import liveProviderStyle from '../../scss/live-provider.scss'; -import liveStyle from '../../scss/live.scss'; +import basicBlockStyle from '../../scss/basic-block.scss'; import { CameraConfig, CardWideConfig, @@ -56,6 +56,9 @@ import '../surround.js'; import '../title-control.js'; import { AutoMediaPlugin } from './../embla-plugins/automedia.js'; import { Lazyload } from './../embla-plugins/lazyload.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; +import { MediaGridSelected } from '../../utils/media-grid-controller.js'; +import { getDefaultTitleConfigForView } from '../title-control.js'; interface LiveViewContext { // A cameraID override (used for dependencies/substreams to force a different @@ -126,7 +129,10 @@ export class FrigateCardLive extends LitElement { public view?: Readonly; @property({ attribute: false }) - public liveConfig?: LiveConfig; + public nonOverriddenLiveConfig?: LiveConfig; + + @property({ attribute: false }) + public overriddenLiveConfig?: LiveConfig; @property({ attribute: false, hasChanged: contentsChanged }) public liveOverrides?: LiveOverrides; @@ -228,13 +234,18 @@ export class FrigateCardLive extends LitElement { * @returns A rendered template. */ protected render(): TemplateResult | void { - if (!this.hass || !this.liveConfig || !this.cameraManager || !this.view) { + if ( + !this.hass || + !this.nonOverriddenLiveConfig || + !this.cameraManager || + !this.view + ) { return; } // Notes: - // - See use of liveConfig and not config below -- the carousel will - // independently override the liveConfig to reflect the camera in the + // - See use of liveConfig and not config below -- the underlying carousel + // will independently override the liveConfig to reflect the camera in the // carousel (not necessarily the selected camera). // - Various events are captured to prevent them propagating upwards if the // card is in the background. @@ -244,10 +255,11 @@ export class FrigateCardLive extends LitElement { const result = html`${keyed( this._renderKey, html` - - + `, )}`; @@ -284,16 +296,13 @@ export class FrigateCardLive extends LitElement { return result; } - /** - * Get styles. - */ static get styles(): CSSResultGroup { - return unsafeCSS(liveStyle); + return unsafeCSS(basicBlockStyle); } } -@customElement('frigate-card-live-carousel') -export class FrigateCardLiveCarousel extends LitElement { +@customElement('frigate-card-live-grid') +export class FrigateCardLiveGrid extends LitElement { @property({ attribute: false }) public hass?: ExtendedHomeAssistant; @@ -301,7 +310,10 @@ export class FrigateCardLiveCarousel extends LitElement { public view?: Readonly; @property({ attribute: false }) - public liveConfig?: LiveConfig; + public nonOverriddenLiveConfig?: LiveConfig; + + @property({ attribute: false }) + public overriddenLiveConfig?: LiveConfig; @property({ attribute: false, hasChanged: contentsChanged }) public liveOverrides?: LiveOverrides; @@ -321,6 +333,109 @@ export class FrigateCardLiveCarousel extends LitElement { @property({ attribute: false }) public microphoneStream?: MediaStream; + protected _renderCarousel(cameraID?: string): TemplateResult { + return html` + + + `; + } + + protected _gridSelectCamera(cameraID: string, view?: View): void { + (view ?? this.view) + ?.evolve({ + camera: cameraID, + }) + .dispatchChangeEvent(this); + } + + protected _needsGrid(): boolean { + const cameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); + return !!this.view?.isGrid() && !!cameraIDs && cameraIDs.size >= 1; + } + + protected willUpdate(changedProps: PropertyValues): void { + if (changedProps.has('view') && this._needsGrid()) { + import('../media-grid.js'); + } + } + + protected render(): TemplateResult | void { + if (!this.conditionControllerEpoch || !this.nonOverriddenLiveConfig) { + return; + } + const cameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); + if (!this._needsGrid() || !cameraIDs) { + return this._renderCarousel(); + } + return html` + ) => + this._gridSelectCamera(ev.detail.selected)} + @frigate-card:view:change=${(ev: CustomEvent) => { + ev.stopPropagation(); + this._gridSelectCamera(ev.detail.camera, ev.detail); + }} + > + ${[...cameraIDs].map((cameraID) => this._renderCarousel(cameraID))} + + `; + } + + static get styles(): CSSResultGroup { + return unsafeCSS(basicBlockStyle); + } +} + +@customElement('frigate-card-live-carousel') +export class FrigateCardLiveCarousel extends LitElement { + @property({ attribute: false }) + public hass?: ExtendedHomeAssistant; + + @property({ attribute: false }) + public view?: Readonly; + + @property({ attribute: false }) + public nonOverriddenLiveConfig?: LiveConfig; + + @property({ attribute: false }) + public overriddenLiveConfig?: LiveConfig; + + @property({ attribute: false, hasChanged: contentsChanged }) + public liveOverrides?: LiveOverrides; + + @property({ attribute: false }) + public inBackground?: boolean; + + @property({ attribute: false }) + public conditionControllerEpoch?: ConditionControllerEpoch; + + @property({ attribute: false }) + public cardWideConfig?: CardWideConfig; + + @property({ attribute: false }) + public cameraManager?: CameraManager; + + @property({ attribute: false }) + public microphoneStream?: MediaStream; + + @property({ attribute: false }) + public viewFilterCameraID?: string; + // Index between camera name and slide number. protected _cameraToSlide: Record = {}; protected _refMediaCarousel: Ref = createRef(); @@ -357,7 +472,7 @@ export class FrigateCardLiveCarousel extends LitElement { */ protected _getTransitionEffect(): TransitionEffect { return ( - this.liveConfig?.transition_effect ?? + this.overriddenLiveConfig?.transition_effect ?? frigateCardConfigDefaults.live.transition_effect ); } @@ -376,7 +491,9 @@ export class FrigateCardLiveCarousel extends LitElement { */ protected _getOptions(): EmblaOptionsType { return { - draggable: this.liveConfig?.draggable, + // If the carousel is being filtered to a single cameraID, it is never + // draggable. + draggable: !this.viewFilterCameraID && this.overriddenLiveConfig?.draggable, loop: true, }; } @@ -386,10 +503,12 @@ export class FrigateCardLiveCarousel extends LitElement { * @returns A list of EmblaOptionsTypes. */ protected _getPlugins(): EmblaCarouselPlugins { - const cameras = this.cameraManager?.getStore().getVisibleCameraIDs(); + const cameraCount = this.viewFilterCameraID + ? 1 + : this.cameraManager?.getStore().getVisibleCameraCount() ?? 0; return [ // Only enable wheel plugin if there is more than one camera. - ...(cameras && cameras.size > 1 + ...(cameraCount > 1 ? [ WheelGesturesPlugin({ // Whether the carousel is vertical or horizontal, interpret y-axis wheel @@ -399,28 +518,28 @@ export class FrigateCardLiveCarousel extends LitElement { ] : []), Lazyload({ - ...(this.liveConfig?.lazy_load && { + ...(this.overriddenLiveConfig?.lazy_load && { lazyLoadCallback: (index, slide) => this._lazyloadOrUnloadSlide('load', index, slide), }), - lazyUnloadCondition: this.liveConfig?.lazy_unload, + lazyUnloadCondition: this.overriddenLiveConfig?.lazy_unload, lazyUnloadCallback: (index, slide) => this._lazyloadOrUnloadSlide('unload', index, slide), }), AutoMediaPlugin({ playerSelector: FRIGATE_CARD_LIVE_PROVIDER, - ...(this.liveConfig?.auto_play && { - autoPlayCondition: this.liveConfig.auto_play, + ...(this.overriddenLiveConfig?.auto_play && { + autoPlayCondition: this.overriddenLiveConfig.auto_play, }), - ...(this.liveConfig?.auto_pause && { - autoPauseCondition: this.liveConfig.auto_pause, + ...(this.overriddenLiveConfig?.auto_pause && { + autoPauseCondition: this.overriddenLiveConfig.auto_pause, }), - ...(this.liveConfig?.auto_mute && { - autoMuteCondition: this.liveConfig.auto_mute, + ...(this.overriddenLiveConfig?.auto_mute && { + autoMuteCondition: this.overriddenLiveConfig.auto_mute, }), - ...(this.liveConfig?.auto_unmute && { - autoUnmuteCondition: this.liveConfig.auto_unmute, + ...(this.overriddenLiveConfig?.auto_unmute && { + autoUnmuteCondition: this.overriddenLiveConfig.auto_unmute, }), }), ]; @@ -435,7 +554,7 @@ export class FrigateCardLiveCarousel extends LitElement { */ protected _getLazyLoadCount(): number | null { // Defaults to fully-lazy loading. - return this.liveConfig?.lazy_load === false ? null : 0; + return this.overriddenLiveConfig?.lazy_load === false ? null : 0; } /** @@ -444,15 +563,25 @@ export class FrigateCardLiveCarousel extends LitElement { * name to slide number. */ protected _getSlides(): [TemplateResult[], Record] { - const visibleCameras = this.cameraManager?.getStore().getVisibleCameras(); - if (!visibleCameras) { + let cameras: CameraConfigs | null = null; + if (this.viewFilterCameraID) { + const config = this.cameraManager + ?.getStore() + .getCameraConfig(this.viewFilterCameraID); + if (config) { + cameras = new Map([[this.viewFilterCameraID, config]]); + } + } else { + cameras = this.cameraManager?.getStore().getVisibleCameras() ?? null; + } + if (!cameras) { return [[], {}]; } const slides: TemplateResult[] = []; const cameraToSlide: Record = {}; - for (const [cameraID, cameraConfig] of visibleCameras) { + for (const [cameraID, cameraConfig] of cameras) { const liveCameraID = this.view?.context?.live?.overrides?.get(cameraID) ?? cameraID; const liveCameraConfig = @@ -525,7 +654,8 @@ export class FrigateCardLiveCarousel extends LitElement { slideIndex: number, ): TemplateResult | void { if ( - !this.liveConfig || + !this.overriddenLiveConfig || + !this.nonOverriddenLiveConfig || !this.hass || !this.cameraManager || !this.conditionControllerEpoch @@ -538,7 +668,7 @@ export class FrigateCardLiveCarousel extends LitElement { // stateOverride to evaluate the condition in that context. const config = getOverriddenConfig( this.conditionControllerEpoch.controller, - this.liveConfig, + this.nonOverriddenLiveConfig, this.liveOverrides, { camera: cameraID }, ) as LiveConfig; @@ -548,7 +678,7 @@ export class FrigateCardLiveCarousel extends LitElement { return html`
{ await this.updateComplete; await this._refProvider.value?.updateComplete; - return await this._refProvider.value?.getScreenshotURL() ?? null; + return (await this._refProvider.value?.getScreenshotURL()) ?? null; } /** @@ -1002,6 +1139,7 @@ declare global { interface HTMLElementTagNameMap { FRIGATE_CARD_LIVE_PROVIDER: FrigateCardLiveProvider; 'frigate-card-live-carousel': FrigateCardLiveCarousel; + 'frigate-card-live-grid': FrigateCardLiveGrid; 'frigate-card-live': FrigateCardLive; } } diff --git a/src/components/media-carousel.ts b/src/components/media-carousel.ts index 5e9df428..470e564b 100644 --- a/src/components/media-carousel.ts +++ b/src/components/media-carousel.ts @@ -428,9 +428,6 @@ export class FrigateCardMediaCarousel extends LitElement { : ``}`; } - /** - * Get element styles. - */ static get styles(): CSSResultGroup { return unsafeCSS(mediaCarouselStyle); } diff --git a/src/components/media-grid.ts b/src/components/media-grid.ts new file mode 100644 index 00000000..e0b599b3 --- /dev/null +++ b/src/components/media-grid.ts @@ -0,0 +1,80 @@ +// TODO: Performance of video scanning (pause/play?) +// TODO: Investigate query spam during a grid load +// TODO: Test live pre-load +// TODO: Is the query reset in card.ts correct for media filter multi-camera queries that are not all cameras? +// TODO: Do I need column max? +// TODO: test changing tabs in a dashboard (to trigger disconnect, do I still receive media loads from media that was already loaded)? +// TODO: Can SELECT_CHILD_EVENTS only be 'click' and it still work on Android? + +import { + CSSResultGroup, + html, + LitElement, + PropertyValues, + TemplateResult, + unsafeCSS, +} from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { createRef, ref, Ref } from 'lit/directives/ref.js'; +import mediaGridStyle from '../scss/media-grid.scss'; +import { ViewDisplayConfig } from '../types.js'; +import { MediaGridController } from '../utils/media-grid-controller.js'; + +@customElement('frigate-card-media-grid') +export class FrigateCardMediaGrid extends LitElement { + @property({ attribute: false }) + public selected?: string; + + @property({ attribute: false }) + public displayConfig?: ViewDisplayConfig; + + protected _controller: MediaGridController | null = null; + protected _refSlot: Ref = createRef(); + + connectedCallback(): void { + super.connectedCallback(); + + // Ensure the controller is recreated. + this.requestUpdate(); + } + + disconnectedCallback(): void { + this._controller?.destroy(); + this._controller = null; + super.disconnectedCallback(); + } + + protected updated(changedProps: PropertyValues): void { + if (!this._controller && this._refSlot.value) { + this._controller = new MediaGridController(this._refSlot.value, { + selected: this.selected, + }); + } + + if (changedProps.has('selected')) { + if (this.selected) { + this._controller?.selectCell(this.selected); + } else { + this._controller?.unselectAll(); + } + } + + if (changedProps.has('displayConfig')) { + this._controller?.setDisplayConfig(this.displayConfig ?? null); + } + } + + protected render(): TemplateResult | void { + return html` `; + } + + static get styles(): CSSResultGroup { + return unsafeCSS(mediaGridStyle); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'frigate-card-media-grid': FrigateCardMediaGrid; + } +} diff --git a/src/components/surround.ts b/src/components/surround.ts index 79f69242..ec771339 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -7,7 +7,9 @@ import { unsafeCSS, } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import surroundStyle from '../scss/surround.scss'; +import { CameraManager } from '../camera-manager/manager.js'; +import type { DataQuery } from '../camera-manager/types'; +import basicBlockStyle from '../scss/basic-block.scss'; import { CardWideConfig, ClipsOrSnapshotsOrAll, @@ -16,13 +18,11 @@ import { ThumbnailsControlConfig, } from '../types.js'; import { contentsChanged, dispatchFrigateCardEvent } from '../utils/basic.js'; -import { CameraManager } from '../camera-manager/manager.js'; -import { View } from '../view/view.js'; -import { ThumbnailCarouselTap } from './thumbnail-carousel.js'; -import './surround-basic.js'; -import { changeViewToRecentEventsForCameraAndDependents } from '../utils/media-to-view'; import { getAllDependentCameras } from '../utils/camera.js'; -import type { DataQuery } from '../camera-manager/types'; +import { changeViewToRecentEventsForCameraAndDependents } from '../utils/media-to-view'; +import { View } from '../view/view.js'; +import './surround-basic.js'; +import { ThumbnailCarouselTap } from './thumbnail-carousel.js'; interface ThumbnailViewContext { // Whether or not to fetch thumbnails. @@ -88,6 +88,7 @@ export class FrigateCardSurround extends LitElement { this.cardWideConfig, this.view, { + allCameras: this.view.isGrid(), targetView: this.view.view, mediaType: this.fetchMedia, select: 'latest', @@ -151,10 +152,6 @@ export class FrigateCardSurround extends LitElement { return null; } - /** - * Master render method. - * @returns A rendered template. - */ protected render(): TemplateResult | void { if (!this.hass || !this.view) { return; @@ -230,11 +227,8 @@ export class FrigateCardSurround extends LitElement { `; } - /** - * Return compiled CSS styles. - */ static get styles(): CSSResultGroup { - return unsafeCSS(surroundStyle); + return unsafeCSS(basicBlockStyle); } } diff --git a/src/components/thumbnail-carousel.ts b/src/components/thumbnail-carousel.ts index cc550fe7..c7a20351 100644 --- a/src/components/thumbnail-carousel.ts +++ b/src/components/thumbnail-carousel.ts @@ -170,7 +170,7 @@ export class FrigateCardThumbnailCarousel extends LitElement { this, 'thumbnail-carousel:tap', { - queryResults: this.view.queryResults.clone().selectResult(index), + queryResults: this.view.queryResults.clone().selectIndex(index), }, ); } diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 18eff32e..8b33f147 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -485,7 +485,10 @@ export class FrigateCardTimelineCore extends LitElement { : results .clone() .resetSelectedResult() - .selectBestResult((media) => findBestMediaIndex(media, targetTime)); + .selectBestResult((media) => findBestMediaIndex(media, targetTime), { + allCameras: true, + main: true, + }); const desiredView: FrigateCardView = this.mini ? targetTime >= new Date() @@ -496,8 +499,7 @@ export class FrigateCardTimelineCore extends LitElement { this.view .evolve({ view: desiredView, - ...(newResults && - newResults.hasSelectedResult() && { queryResults: newResults }), + queryResults: newResults, }) // Whether or not to set the timeline window. .mergeInContext({ ...(canSeek && { mediaViewer: { seek: targetTime } }), @@ -597,10 +599,15 @@ export class FrigateCardTimelineCore extends LitElement { ); } } else if (properties.item && properties.what === 'item') { + const cameraID = String(properties.group); + const criteria = { + main: true, + ...(cameraID && this.view.isGrid() && { cameraID: cameraID }), + }; const newResults = this.view.queryResults ?.clone() .resetSelectedResult() - .selectResultIfFound((media) => media.getID() === properties.item); + .selectResultIfFound((media) => media.getID() === properties.item, criteria); if (!newResults || !newResults.hasSelectedResult()) { // This can happen in a few situations: @@ -788,11 +795,12 @@ export class FrigateCardTimelineCore extends LitElement { return new DataSet(groups); } - protected _getPerfectWindowFromMedia(media: ViewMedia): TimelineWindow | null { - const startTime = media.getStartTime(); - const endTime = media.getEndTime(); - - if (ViewMediaClassifier.isEvent(media)) { + protected _getPerfectWindowFromMediaStartAndEndTime( + isEvent: boolean, + startTime: Date | null, + endTime: Date | null, + ): TimelineWindow | null { + if (isEvent) { const windowSeconds = this._getConfiguredWindowSeconds(); if (startTime && endTime) { @@ -820,7 +828,7 @@ export class FrigateCardTimelineCore extends LitElement { end: add(startTime, { seconds: windowSeconds / 2 }), }; } - } else if (ViewMediaClassifier.isRecording(media) && startTime && endTime) { + } else if (startTime && endTime) { return { start: startTime, end: endTime, @@ -980,8 +988,10 @@ export class FrigateCardTimelineCore extends LitElement { let desiredWindow = timelineWindow; const media = this.view.queryResults?.getSelectedResult(); - const mediaStartTime = media?.getStartTime(); - const mediaEndTime = media?.getEndTime(); + const mediaStartTime = media?.getStartTime() ?? null; + const mediaEndTime = media?.getEndTime() ?? null; + const mediaIsEvent = media ? ViewMediaClassifier.isEvent(media) : false; + const mediaWindow: TimelineWindow | null = media && mediaStartTime ? // If this media has no end time, it's just a "point" in time so the @@ -996,8 +1006,12 @@ export class FrigateCardTimelineCore extends LitElement { if (context && context.window) { desiredWindow = context.window; - } else if (media && mediaWindow && !rangesOverlap(mediaWindow, timelineWindow)) { - const perfectMediaWindow = this._getPerfectWindowFromMedia(media); + } else if (mediaWindow && !rangesOverlap(mediaWindow, timelineWindow)) { + const perfectMediaWindow = this._getPerfectWindowFromMediaStartAndEndTime( + mediaIsEvent, + mediaStartTime, + mediaEndTime, + ); if (perfectMediaWindow) { desiredWindow = perfectMediaWindow; } @@ -1013,22 +1027,22 @@ export class FrigateCardTimelineCore extends LitElement { await this._timelineSource?.refresh(this.hass, prefetchedWindow); } + const currentSelection = this._timeline.getSelection(); const mediaID = media?.getID(); - if (media && mediaID && this._isClustering()) { - // Hack: Clustering may not update unless the dataset changes, artifically - // update the dataset to ensure the newly selected item cannot be included - // in a cluster. Only do this when the pointer is not held to avoid - // interrupting the user and to make the timeline smoother. + const needToSelect = mediaID && mediaIsEvent && !currentSelection.includes(mediaID); - // Need to this rewrite prior to setting the selection (just below), or - // the selection will be lost on rewrite. - this._timelineSource?.rewriteEvent(mediaID); - } + if (needToSelect) { + if (this._isClustering()) { + // Hack: Clustering may not update unless the dataset changes, artifically + // update the dataset to ensure the newly selected item cannot be included + // in a cluster. - const desiredId = - !!media && ViewMediaClassifier.isEvent(media) ? media.getID() : null; - if (desiredId) { - this._timeline?.setSelection([desiredId], { + // Need to this rewrite prior to setting the selection (just below), or + // the selection will be lost on rewrite. + this._timelineSource?.rewriteEvent(mediaID); + } + + this._timeline?.setSelection([mediaID], { focus: false, animation: { animation: false, @@ -1244,9 +1258,6 @@ export class FrigateCardTimelineCore extends LitElement { } } - /** - * Return compiled CSS styles. - */ static get styles(): CSSResultGroup { return unsafeCSS(timelineCoreStyle); } diff --git a/src/components/timeline.ts b/src/components/timeline.ts index f70a7db1..4f3cce06 100644 --- a/src/components/timeline.ts +++ b/src/components/timeline.ts @@ -1,8 +1,8 @@ import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import timelineStyle from '../scss/timeline.scss'; -import { CardWideConfig, ExtendedHomeAssistant, TimelineConfig } from '../types'; import { CameraManager } from '../camera-manager/manager'; +import basicBlockStyle from '../scss/basic-block.scss'; +import { CardWideConfig, ExtendedHomeAssistant, TimelineConfig } from '../types'; import { View } from '../view/view'; import './surround.js'; import './timeline-core.js'; @@ -24,10 +24,6 @@ export class FrigateCardTimeline extends LitElement { @property({ attribute: false }) public cardWideConfig?: CardWideConfig; - /** - * Master render method. - * @returns A rendered template. - */ protected render(): TemplateResult | void { if (!this.timelineConfig) { return html``; @@ -49,11 +45,8 @@ export class FrigateCardTimeline extends LitElement { `; } - /** - * Return compiled CSS styles. - */ static get styles(): CSSResultGroup { - return unsafeCSS(timelineStyle); + return unsafeCSS(basicBlockStyle); } } diff --git a/src/components/title-control.ts b/src/components/title-control.ts index 16f14c9e..7bbda1e9 100644 --- a/src/components/title-control.ts +++ b/src/components/title-control.ts @@ -1,14 +1,28 @@ -import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit'; -import { createRef, ref, Ref } from 'lit/directives/ref.js'; +import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { TitleControlConfig } from '../types.js'; - +import { createRef, Ref, ref } from 'lit/directives/ref.js'; import titleStyle from '../scss/title-control.scss'; +import { TitleControlConfig } from '../types.js'; +import { View } from '../view/view.js'; type PaperToast = HTMLElement & { opened: boolean; }; +export const getDefaultTitleConfigForView = ( + view?: Readonly, + baseConfig?: TitleControlConfig, +): TitleControlConfig | null => { + if (!baseConfig && view?.isGrid()) { + return { mode: 'none', duration_seconds: 2 }; + } + return { + mode: 'popup-bottom-right', + duration_seconds: 2, + ...baseConfig, + }; +}; + @customElement('frigate-card-title-control') export class FrigateCardTitleControl extends LitElement { @property({ attribute: false }) diff --git a/src/components/viewer.ts b/src/components/viewer.ts index 37980d93..fd030904 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -10,7 +10,9 @@ import { } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { guard } from 'lit/directives/guard.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js'; +import basicBlockStyle from '../../scss/basic-block.scss'; import { CameraManager } from '../camera-manager/manager.js'; import { dispatchMessageEvent, renderProgressIndicator } from '../components/message.js'; import { localize } from '../localize/localize.js'; @@ -29,9 +31,14 @@ import { } from '../types.js'; import { stopEventFromActivatingCardWideActions } from '../utils/action.js'; import { mayHaveAudio } from '../utils/audio.js'; -import { contentsChanged, errorToConsole } from '../utils/basic.js'; +import { + contentsChanged, + errorToConsole, + setOrRemoveAttribute, +} from '../utils/basic.js'; import { canonicalizeHAURL } from '../utils/ha/index.js'; import { ResolvedMediaCache, resolveMedia } from '../utils/ha/resolved-media.js'; +import { MediaGridSelected } from '../utils/media-grid-controller.js'; import { dispatchMediaLoadedEvent, dispatchMediaPauseEvent, @@ -65,6 +72,7 @@ import { import './next-prev-control.js'; import './surround.js'; import './title-control.js'; +import { getDefaultTitleConfigForView } from './title-control.js'; export interface MediaViewerViewContext { seek?: Date; @@ -76,6 +84,16 @@ declare module 'view' { } } +interface MediaNeighbor { + index: number; + media: ViewMedia; +} + +interface MediaNeighbors { + previous?: MediaNeighbor; + next?: MediaNeighbor; +} + @customElement('frigate-card-viewer') export class FrigateCardViewer extends LitElement { @property({ attribute: false }) @@ -129,6 +147,7 @@ export class FrigateCardViewer extends LitElement { this.cardWideConfig, this.view, { + allCameras: this.view.isGrid(), targetView: 'recording', select: 'latest', }, @@ -141,6 +160,7 @@ export class FrigateCardViewer extends LitElement { this.cardWideConfig, this.view, { + allCameras: this.view.isGrid(), targetView: 'media', mediaType: mediaType, select: 'latest', @@ -150,17 +170,15 @@ export class FrigateCardViewer extends LitElement { return renderProgressIndicator({ cardWideConfig: this.cardWideConfig }); } - return html` - - - `; + return html` + `; } /** @@ -181,6 +199,9 @@ export class FrigateCardViewerCarousel extends LitElement { @property({ attribute: false }) public view?: Readonly; + @property({ attribute: false }) + public viewFilterCameraID?: string; + // Resetting the viewer configuration causes a full reset so ensure the config // has actually changed with a full comparison (dynamic configuration // overrides may causes changes elsewhere in the full card configuration that @@ -198,7 +219,11 @@ export class FrigateCardViewerCarousel extends LitElement { @property({ attribute: false }) public cameraManager?: CameraManager; + @property({ attribute: false }) + public selected = 0; + protected _refMediaCarousel: Ref = createRef(); + protected _media: ViewMedia[] | null = null; /** * The updated lifecycle callback for this element. @@ -255,7 +280,7 @@ export class FrigateCardViewerCarousel extends LitElement { protected _getPlugins(): EmblaPluginType[] { return [ // Only enable wheel plugin if there is more than one media item. - ...(this.view?.queryResults?.getResultsCount() ?? 0 > 1 + ...(this._media && this._media.length > 1 ? [ WheelGesturesPlugin({ // Whether the carousel is vertical or horizontal, interpret y-axis wheel @@ -292,20 +317,28 @@ export class FrigateCardViewerCarousel extends LitElement { * @returns A BrowseMediaNeighbors with indices and objects of true media * neighbors. */ - protected _getMediaNeighbors(): [ViewMedia | null, ViewMedia | null] { - const selectedIndex = this.view?.queryResults?.getSelectedIndex() ?? null; - const resultCount = this.view?.queryResults?.getResultsCount() ?? 0; - if (!this.view || !this.view.queryResults || selectedIndex === null) { - return [null, null]; + protected _getMediaNeighbors(): MediaNeighbors | null { + const mediaCount = this._media?.length ?? 0; + if (!this._media || this.selected === null) { + return null; } - const previous: ViewMedia | null = - selectedIndex > 0 ? this.view.queryResults.getResult(selectedIndex - 1) : null; - const next: ViewMedia | null = - selectedIndex + 1 < resultCount - ? this.view.queryResults.getResult(selectedIndex + 1) - : null; - return [previous, next]; + const prevIndex = this.selected > 0 ? this.selected - 1 : null; + const nextIndex = this.selected + 1 < mediaCount ? this.selected + 1 : null; + return { + ...(prevIndex !== null && { + previous: { + index: prevIndex, + media: this._media[prevIndex], + }, + }), + ...(nextIndex !== null && { + next: { + index: nextIndex, + media: this._media[nextIndex], + }, + }), + }; } protected _setViewHandler(ev: CustomEvent): void { @@ -313,23 +346,26 @@ export class FrigateCardViewerCarousel extends LitElement { } protected _setViewSelectedIndex(index: number): void { - if (!this.view?.queryResults) { + if (!this._media) { return; } - const selectedIndex = this.view.queryResults.getSelectedIndex(); - if (selectedIndex === null || selectedIndex === index) { + if (this.selected === null || this.selected === index) { // The slide may already be selected on load, so don't dispatch a new view // unless necessary (i.e. the new index is different from the current // index). return; } - const newResults = this.view?.queryResults?.clone().selectResult(index); + const newResults = this.view?.queryResults + ?.clone() + .selectIndex(index, this.viewFilterCameraID); if (!newResults) { return; } - const cameraID = newResults.getSelectedResult()?.getCameraID(); + const cameraID = newResults + .getSelectedResult(this.viewFilterCameraID) + ?.getCameraID(); this.view ?.evolve({ @@ -338,6 +374,7 @@ export class FrigateCardViewerCarousel extends LitElement { // Always change the camera to the owner of the selected media. ...(cameraID && { camera: cameraID }), }) + .removeContextProperty('mediaViewer', 'seek') .dispatchChangeEvent(this); } @@ -363,13 +400,13 @@ export class FrigateCardViewerCarousel extends LitElement { * @returns The slides to include in the render. */ protected _getSlides(): TemplateResult[] { - if (!this.view || !this.view.queryResults) { + if (!this._media) { return []; } const slides: TemplateResult[] = []; - for (let i = 0; i < this.view.queryResults.getResultsCount(); ++i) { - const media = this.view.queryResults.getResult(i); + for (let i = 0; i < this._media.length; ++i) { + const media = this._media[i]; if (media) { const slide = this._renderMediaItem(media, i); if (slide) { @@ -388,11 +425,25 @@ export class FrigateCardViewerCarousel extends LitElement { if (changedProps.has('viewerConfig')) { updateElementStyleFromMediaLayoutConfig(this, this.viewerConfig?.layout); } + + if (changedProps.has('view')) { + const newMedia = + this.view?.queryResults?.getResults(this.viewFilterCameraID) ?? null; + const newSelected = + this.view?.queryResults?.getSelectedIndex(this.viewFilterCameraID) ?? 0; + const newSeek = this.view?.context?.mediaViewer?.seek; + + if (newMedia !== this._media || newSelected !== this.selected || !newSeek) { + setOrRemoveAttribute(this, false, 'unseekable'); + this._media = newMedia; + this.selected = newSelected; + } + } } protected render(): TemplateResult | void { - const resultCount = this.view?.queryResults?.getResultsCount() ?? 0; - if (!resultCount) { + const mediaCount = this._media?.length ?? 0; + if (!this._media || !mediaCount) { return dispatchMessageEvent(this, localize('common.no_media'), 'info', { icon: 'mdi:multimedia', }); @@ -401,82 +452,86 @@ export class FrigateCardViewerCarousel extends LitElement { // If there's no selected media, just choose the last (most recent one) to // avoid rendering a blank. This situation should not occur in practice, as // this view should not be called without a selected media. - const media = - this.view?.queryResults?.getSelectedResult() ?? - this.view?.queryResults?.getResult(resultCount - 1); - if ( - !this.hass || - !this.cameraManager || - !media || - !this.view || - !this.view.queryResults - ) { + const selectedMedia = this._media[this.selected] ?? this._media[mediaCount - 1]; + + if (!this.hass || !this.cameraManager || !selectedMedia) { return; } - const [prev, next] = this._getMediaNeighbors(); - + const neighbors = this._getMediaNeighbors(); const scroll = (direction: 'previous' | 'next'): void => { - const currentIndex = this.view?.queryResults?.getSelectedIndex() ?? null; - if (!this.view || !this.view?.queryResults || currentIndex === null) { + if (!neighbors || !this._media) { return; } - const newIndex = direction === 'previous' ? currentIndex - 1 : currentIndex + 1; - if (newIndex >= 0 && newIndex < this.view.queryResults.getResultsCount()) { + const newIndex = + (direction === 'previous' ? neighbors.previous?.index : neighbors.next?.index) ?? + null; + if (newIndex !== null) { this._setViewSelectedIndex(newIndex); } }; const cameraMetadata = this.cameraManager.getCameraMetadata( this.hass, - media.getCameraID(), + selectedMedia.getCameraID(), ); - return html` ({ - draggable: this.viewerConfig?.draggable ?? true, - }))} - .carouselPlugins=${guard( - [this.viewerConfig, this.view.queryResults.getResults()], - this._getPlugins.bind(this), - )} - .label=${media.getTitle() ?? undefined} - .logo=${cameraMetadata?.engineLogo} - .titlePopupConfig=${this.viewerConfig?.controls.title} - .selected=${this.view?.queryResults?.getSelectedIndex() ?? 0} - transitionEffect=${this._getTransitionEffect()} - @frigate-card:media-carousel:select=${this._setViewHandler.bind(this)} - @frigate-card:media:loaded=${this._seekHandler.bind(this)} - > - { - scroll('previous'); - stopEventFromActivatingCardWideActions(ev); - }} - > - ${guard(this.view?.queryResults?.getResults(), () => this._getSlides())} - { - scroll('next'); - stopEventFromActivatingCardWideActions(ev); - }} - > - `; + const titleConfig = getDefaultTitleConfigForView( + this.view, + this.viewerConfig?.controls.title, + ); + + return html` + ({ + draggable: this.viewerConfig?.draggable ?? true, + }))} + .carouselPlugins=${guard( + [this.viewerConfig, this._media], + this._getPlugins.bind(this), + )} + .label=${selectedMedia.getTitle() ?? undefined} + .logo=${cameraMetadata?.engineLogo} + .titlePopupConfig=${titleConfig ?? undefined} + .selected=${this.selected ?? 0} + transitionEffect=${this._getTransitionEffect()} + @frigate-card:media-carousel:select=${this._setViewHandler.bind(this)} + @frigate-card:media:loaded=${this._seekHandler.bind(this)} + > + { + scroll('previous'); + stopEventFromActivatingCardWideActions(ev); + }} + > + ${guard(this._media, () => this._getSlides())} + { + scroll('next'); + stopEventFromActivatingCardWideActions(ev); + }} + > + +
+ + +
+ `; } /** @@ -484,13 +539,26 @@ export class FrigateCardViewerCarousel extends LitElement { */ protected async _seekHandler(): Promise { const seek = this.view?.context?.mediaViewer?.seek; - const media = this.view?.queryResults?.getSelectedResult(); - if (!this.hass || !media || !seek) { + if (!this.hass || !seek || !this._media || this.selected === null) { + return; + } + const selectedMedia = this._media[this.selected]; + if (!selectedMedia) { return; } + const seekTimeInMedia = selectedMedia.includesTime(seek); + + setOrRemoveAttribute(this, !seekTimeInMedia, 'unseekable'); + if (!seekTimeInMedia) { + this._getPlayer()?.pause(); + } else { + this._getPlayer()?.play(); + } + const seekTime = - (await this.cameraManager?.getMediaSeekTime(this.hass, media, seek)) ?? null; + (await this.cameraManager?.getMediaSeekTime(this.hass, selectedMedia, seek)) ?? + null; const player = this._getPlayer(); if (player && seekTime !== null) { player.seek(seekTime); @@ -530,6 +598,93 @@ export class FrigateCardViewerCarousel extends LitElement { } } +@customElement('frigate-card-viewer-grid') +export class FrigateCardViewerGrid extends LitElement { + @property({ attribute: false }) + public hass?: ExtendedHomeAssistant; + + @property({ attribute: false }) + public view?: Readonly; + + @property({ attribute: false }) + public viewerConfig?: ViewerConfig; + + @property({ attribute: false }) + public resolvedMediaCache?: ResolvedMediaCache; + + @property({ attribute: false }) + public cardWideConfig?: CardWideConfig; + + @property({ attribute: false }) + public cameraManager?: CameraManager; + + protected _renderCarousel(filterCamera?: string): TemplateResult { + return html` + + + `; + } + + protected _gridSelectCamera(cameraID: string, view?: View): void { + const newView = view ?? this.view; + const promotedQueryResults = newView?.queryResults + ?.clone() + .promoteCameraSelectionToMainSelection(cameraID); + newView + ?.evolve({ + camera: cameraID, + queryResults: promotedQueryResults, + }) + .dispatchChangeEvent(this); + } + + protected willUpdate(changedProps: PropertyValues): void { + if ( + changedProps.has('view') && + this.view?.isGrid() && + this.view?.hasMultipleDisplayModes() + ) { + import('./media-grid.js'); + } + } + + protected render(): TemplateResult { + const cameraIDs = this.view?.queryResults?.getCameraIDs(); + if (!cameraIDs || !this.view?.isGrid() || !this.view?.hasMultipleDisplayModes()) { + return this._renderCarousel(); + } + + return html` + ) => + this._gridSelectCamera(ev.detail.selected)} + @frigate-card:view:change=${(ev: CustomEvent) => { + ev.stopPropagation(); + const childView = ev.detail; + this._gridSelectCamera(childView.camera, childView); + }} + > + ${[...cameraIDs].map((cameraID) => this._renderCarousel(cameraID))} + + `; + } + + static get styles(): CSSResultGroup { + return unsafeCSS(basicBlockStyle); + } +} + @customElement(FRIGATE_CARD_VIEWER_PROVIDER) export class FrigateCardViewerProvider extends LitElement @@ -679,7 +834,7 @@ export class FrigateCardViewerProvider return; } - const results = new MediaQueriesResults(mediaArray); + const results = new MediaQueriesResults({ results: mediaArray }); results.selectResultIfFound( (clipMedia) => clipMedia.getID() === this.media?.getID(), ); @@ -830,6 +985,7 @@ declare global { interface HTMLElementTagNameMap { 'frigate-card-viewer-carousel': FrigateCardViewerCarousel; 'frigate-card-viewer': FrigateCardViewer; + 'frigate-card-viewer-grid': FrigateCardViewerGrid; FRIGATE_CARD_VIEWER_PROVIDER: FrigateCardViewerProvider; } } diff --git a/src/components/views.ts b/src/components/views.ts index f7032397..97a9a54b 100644 --- a/src/components/views.ts +++ b/src/components/views.ts @@ -199,7 +199,8 @@ export class FrigateCardViews extends LitElement { ` @@ -1826,6 +1885,13 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor CONF_LIVE_SHOW_IMAGE_DURING_LOAD, this._defaults.live.show_image_during_load, )} + ${this._renderViewDisplay( + MENU_LIVE_DISPLAY, + CONF_LIVE_DISPLAY_MODE, + CONF_LIVE_DISPLAY_GRID_SELECTED_WIDTH_FACTOR, + CONF_LIVE_DISPLAY_GRID_COLUMNS, + CONF_LIVE_DISPLAY_GRID_MAX_COLUMNS, + )} ${this._putInSubmenu( MENU_LIVE_CONTROLS, true, @@ -1957,6 +2023,13 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor CONF_MEDIA_VIEWER_SNAPSHOT_CLICK_PLAYS_CLIP, this._defaults.media_viewer.snapshot_click_plays_clip, )} + ${this._renderViewDisplay( + MENU_MEDIA_VIEWER_DISPLAY, + CONF_MEDIA_VIEWER_DISPLAY_MODE, + CONF_MEDIA_VIEWER_DISPLAY_GRID_SELECTED_WIDTH_FACTOR, + CONF_MEDIA_VIEWER_DISPLAY_GRID_COLUMNS, + CONF_MEDIA_VIEWER_DISPLAY_GRID_MAX_COLUMNS, + )} ${this._putInSubmenu( MENU_MEDIA_VIEWER_CONTROLS, true, diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index a5b5b780..e84d933f 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -148,6 +148,17 @@ } } }, + "display": { + "editor_label": "Display", + "grid_columns": "Exact number of grid columns", + "grid_max_columns": "Maximum number of grid columns", + "grid_selected_width_factor": "Increase selected media width by this factor", + "mode": "Mode", + "modes": { + "single": "Show single media viewer", + "grid": "Show media viewer for each camera in a grid" + } + }, "layout": { "fit": "Layout fit", "fits": { @@ -269,6 +280,7 @@ "cameras": "Cameras", "clips": "Clips", "download": "Download", + "display_mode": "Display mode", "enabled": "Button enabled", "expand": "Expand", "frigate": "Frigate menu / Default view", @@ -454,6 +466,9 @@ "what": "What", "where": "Where" }, + "media_viewer": { + "unseekable": "Seek time not found in media" + }, "media_filter": { "all": "All", "camera": "Camera", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 2643abd5..35a150c4 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -148,6 +148,16 @@ } } }, + "display": { + "editor_label": "", + "grid_columns": "", + "grid_max_columns": "", + "grid_selected_width_factor": "", + "modes": { + "single": "", + "grid": "" + } + }, "layout": { "fit": "Adatta al layout", "fits": { @@ -267,6 +277,7 @@ "camera_ui": "Interfaccia utente della fotocamera", "cameras": "Telecamere", "clips": "Clip", + "display_mode": "", "download": "Download", "enabled": "Pulsante abilitato", "expand": "Espandere", @@ -473,6 +484,9 @@ }, "where": "Dove" }, + "media_viewer": { + "unseekable": "" + }, "recording": { "camera": "Camera", "duration": "Durata", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index c873ceb9..1609d398 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -148,6 +148,17 @@ } } }, + "display": { + "editor_label": "", + "grid_columns": "", + "grid_max_columns": "", + "grid_selected_width_factor": "", + "mode": "", + "modes": { + "single": "", + "grid": "" + } + }, "layout": { "fit": "Ajuste de layout", "fits": { @@ -268,6 +279,7 @@ "camera_ui": "Interface de usuário da câmera", "cameras": "Selecionar câmera", "clips": "Clipes", + "display_mode": "", "download": "Baixe a mídia do evento", "enabled": "Botão ativado", "expand": "Expandir", @@ -482,6 +494,9 @@ }, "where": "Onde" }, + "media_viewer": { + "unseekable": "" + }, "recording": { "camera": "Câmera", "duration": "Duração", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 6f4cd0ef..57fc800f 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -148,6 +148,17 @@ } } }, + "display": { + "editor_label": "", + "grid_columns": "", + "grid_max_columns": "", + "grid_selected_width_factor": "", + "mode": "", + "modes": { + "single": "", + "grid": "" + } + }, "layout": { "fit": "Fit", "fits": { @@ -260,6 +271,7 @@ "camera_ui": "Camera", "cameras": "Selecionar câmera", "clips": "Clipes", + "display_mode": "", "download": "Descarregar mídia do evento", "enabled": "Botão ativado", "expand": "Expandir", @@ -465,6 +477,9 @@ }, "where": "Onde" }, + "media_viewer": { + "unseekable": "" + }, "recording": { "camera": "Camera", "duration": "Duração", diff --git a/src/scss/live.scss b/src/scss/basic-block.scss similarity index 100% rename from src/scss/live.scss rename to src/scss/basic-block.scss diff --git a/src/scss/live-carousel.scss b/src/scss/live-carousel.scss index aab21ed3..d4dafaf1 100644 --- a/src/scss/live-carousel.scss +++ b/src/scss/live-carousel.scss @@ -1,3 +1,12 @@ +// If the carousel has an unselected attribute set on it, do not let the +// pointer interact (e.g. hover, scroll) with underlying elements. This is used +// when the carousel is part of a media-grid. Without this next/prev controls +// will enlarge on hover, and the wheel-gestures plugin may block scrolling. +// See matching in viewer-carousel.scss . +:host([unselected]) frigate-card-media-carousel { + pointer-events: none; +} + .embla__slide { height: 100%; flex: 0 0 100%; diff --git a/src/scss/live-image.scss b/src/scss/live-image.scss deleted file mode 100644 index f0f64c07..00000000 --- a/src/scss/live-image.scss +++ /dev/null @@ -1,5 +0,0 @@ -:host { - width: 100%; - height: 100%; - display: block; -} \ No newline at end of file diff --git a/src/scss/media-filter.scss b/src/scss/media-filter.scss index 46ad7beb..6dc9aa2f 100644 --- a/src/scss/media-filter.scss +++ b/src/scss/media-filter.scss @@ -21,4 +21,4 @@ frigate-card-select { padding: 5px; -} \ No newline at end of file +} diff --git a/src/scss/media-grid.scss b/src/scss/media-grid.scss new file mode 100644 index 00000000..a6b9b49c --- /dev/null +++ b/src/scss/media-grid.scss @@ -0,0 +1,50 @@ +:host { + display: block; + width: 100%; + height: 100%; + + --frigate-card-grid-border-size: 3px; + --frigate-card-grid-column-size: 100%; + --frigate-card-grid-selected-width-factor: 2; + + // Allow the grid to scroll if necessary (e.g. fullscreen). + overflow: auto; + + // Hide scrollbar: Firefox + scrollbar-width: none; + // Hide scrollbar: IE and Edge + -ms-overflow-style: none; +} + +/* Hide scrollbar for Chrome, Safari and Opera */ +:host::-webkit-scrollbar { + display: none; +} + +::slotted(*) { + box-sizing: border-box; + border-radius: var(--ha-card-border-radius, 4px); + overflow: hidden; + width: var(--frigate-card-grid-column-size); + + // Unselected items included a transparent border to act as the effective + // gutter between elements, and to ensure when the item is selected it does + // not change in size (even border-box sizing appears to allow size to change + // when the element has a non-fixed height). + border: var(--frigate-card-grid-border-size) solid transparent; +} + +::slotted([selected]) { + border: var(--frigate-card-grid-border-size) solid var(--primary-color); + width: min( + 100%, + calc( + var(--frigate-card-grid-selected-width-factor) * + var(--frigate-card-grid-column-size) + ) + ); +} + +slot { + display: block; +} diff --git a/src/scss/surround.scss b/src/scss/surround.scss deleted file mode 100644 index 9f92a4e0..00000000 --- a/src/scss/surround.scss +++ /dev/null @@ -1,5 +0,0 @@ -:host { - width: 100%; - height: 100%; - display: block; -} diff --git a/src/scss/timeline.scss b/src/scss/timeline.scss deleted file mode 100644 index f0f64c07..00000000 --- a/src/scss/timeline.scss +++ /dev/null @@ -1,5 +0,0 @@ -:host { - width: 100%; - height: 100%; - display: block; -} \ No newline at end of file diff --git a/src/scss/title-control.scss b/src/scss/title-control.scss index 6f2c9264..ca49513a 100644 --- a/src/scss/title-control.scss +++ b/src/scss/title-control.scss @@ -1,6 +1,8 @@ :host { --paper-toast-background-color: rgba(0,0,0,0.6); --paper-toast-color: white; + + pointer-events: none; } paper-toast { diff --git a/src/scss/viewer-carousel.scss b/src/scss/viewer-carousel.scss index aab21ed3..b7bc6bfb 100644 --- a/src/scss/viewer-carousel.scss +++ b/src/scss/viewer-carousel.scss @@ -1,3 +1,35 @@ +:host { + // Center unseekable icon. + position: relative; +} + +// If the carousel has an unselected attribute set on it, do not let the +// pointer interact (e.g. hover, scroll) with underlying elements. This is used +// when the carousel is part of a media-grid. Without this next/prev controls +// will enlarge on hover, and the wheel-gestures plugin may block scrolling. +// See matching in live-carousel.scss . +:host([unselected]) frigate-card-media-carousel, +:host([unselected]) .seek-warning +{ + pointer-events: none; +} + +:host([unseekable]) frigate-card-media-carousel { + filter: brightness(50%); +} +:host([unseekable]) .seek-warning { + display: block +} + +.seek-warning { + display: none; + position: absolute; + top: 50%; + left: 50%; + transform: translateX(-50%) translateY(-50%); + color: white; +} + .embla__slide { height: 100%; flex: 0 0 100%; diff --git a/src/types.ts b/src/types.ts index 7f3e0f7d..d98ec638 100644 --- a/src/types.ts +++ b/src/types.ts @@ -105,6 +105,17 @@ export class FrigateCardError extends Error { } } +const viewDisplayModeSchema = z.enum(['single', 'grid']); +export type ViewDisplayMode = z.infer; + +const viewDisplaySchema = z.object({ + mode: viewDisplayModeSchema, + grid_selected_width_factor: z.number().min(0).optional(), + grid_max_columns: z.number().min(0).optional(), + grid_columns: z.number().min(0).optional(), +}).optional(); +export type ViewDisplayConfig = z.infer; + /** * Action Types (for "Picture Elements" / Menu) */ @@ -231,6 +242,7 @@ const FRIGATE_CARD_ACTIONS = [ 'camera_select', 'live_substream_select', 'media_player', + 'display_mode_select', ] as const; export type FrigateCardAction = (typeof FRIGATE_CARD_ACTIONS)[number]; @@ -256,6 +268,12 @@ const frigateCardMediaPlayerActionSchema = frigateCardCustomActionsBaseSchema.ex media_player: z.string(), media_player_action: z.enum(['play', 'stop']), }); +const frigateCardViewDisplayModeActionSchema = frigateCardCustomActionsBaseSchema.extend( + { + frigate_card_action: z.literal('display_mode_select'), + display_mode: viewDisplayModeSchema, + }, +); export const frigateCardCustomActionSchema = z.union([ frigateCardViewActionSchema, @@ -263,6 +281,7 @@ export const frigateCardCustomActionSchema = z.union([ frigateCardCameraSelectActionSchema, frigateCardLiveDependencySelectActionSchema, frigateCardMediaPlayerActionSchema, + frigateCardViewDisplayModeActionSchema, ]); export type FrigateCardCustomAction = z.infer; @@ -647,6 +666,7 @@ export const frigateCardConditionSchema = z.object({ media_loaded: z.boolean().optional(), state: stateConditions.optional(), media_query: z.string().optional(), + display_mode: viewDisplayModeSchema.optional(), }); export type FrigateCardCondition = z.infer; @@ -946,6 +966,7 @@ const liveConfigDefault = { zoomable: true, transition_effect: 'slide' as const, show_image_during_load: true, + mode: 'single' as const, controls: { builtin: true, next_previous: { @@ -954,10 +975,6 @@ const liveConfigDefault = { }, thumbnails: liveThumbnailControlsDefaults, timeline: miniTimelineConfigDefault, - title: { - mode: 'popup-bottom-right' as const, - duration_seconds: 2, - }, }, microphone: { ...microphoneConfigDefault, @@ -990,16 +1007,7 @@ const liveOverridableConfigSchema = z liveConfigDefault.controls.thumbnails, ), timeline: miniTimelineConfigSchema.default(liveConfigDefault.controls.timeline), - title: titleControlConfigSchema - .extend({ - mode: titleControlConfigSchema.shape.mode.default( - liveConfigDefault.controls.title.mode, - ), - duration_seconds: titleControlConfigSchema.shape.duration_seconds.default( - liveConfigDefault.controls.title.duration_seconds, - ), - }) - .default(liveConfigDefault.controls.title), + title: titleControlConfigSchema.optional(), }) .default(liveConfigDefault.controls), show_image_during_load: z @@ -1008,6 +1016,7 @@ const liveOverridableConfigSchema = z layout: mediaLayoutConfigSchema.optional(), microphone: microphoneConfigSchema.default(liveConfigDefault.microphone), zoomable: z.boolean().default(liveConfigDefault.zoomable), + display: viewDisplaySchema, }) .merge(actionsSchema); @@ -1078,6 +1087,7 @@ const menuConfigDefault = { play: hiddenButtonDefault, recordings: hiddenButtonDefault, screenshot: hiddenButtonDefault, + display_mode: visibleButtonDefault, }, button_size: 40, }; @@ -1124,6 +1134,7 @@ const menuConfigSchema = z mute: hiddenButtonSchema.default(menuConfigDefault.buttons.mute), play: hiddenButtonSchema.default(menuConfigDefault.buttons.play), screenshot: hiddenButtonSchema.default(menuConfigDefault.buttons.screenshot), + display_mode: visibleButtonSchema.default(menuConfigDefault.buttons.display_mode), }) .default(menuConfigDefault.buttons), button_size: z.number().min(BUTTON_SIZE_MIN).default(menuConfigDefault.button_size), @@ -1144,6 +1155,7 @@ const viewerConfigDefault = { zoomable: true, transition_effect: 'slide' as const, snapshot_click_plays_clip: true, + display_mode: 'single' as const, controls: { builtin: true, next_previous: { @@ -1190,6 +1202,7 @@ const viewerConfigSchema = z snapshot_click_plays_clip: z .boolean() .default(viewerConfigDefault.snapshot_click_plays_clip), + display: viewDisplaySchema, controls: z .object({ builtin: z.boolean().default(viewerConfigDefault.controls.builtin), @@ -1373,7 +1386,7 @@ const performanceConfigDefault = { }, }; -const performanceConfigSchema = z +export const performanceConfigSchema = z .object({ profile: z.enum(['low', 'high']).default(performanceConfigDefault.profile), features: z diff --git a/src/utils/action.ts b/src/utils/action.ts index e065d7be..2c7ce74a 100644 --- a/src/utils/action.ts +++ b/src/utils/action.ts @@ -11,6 +11,7 @@ import { FrigateCardCustomAction, frigateCardCustomActionSchema, FrigateCardViewAction, + ViewDisplayMode, } from '../types.js'; /** @@ -42,6 +43,7 @@ export function createFrigateCardCustomAction( camera?: string; media_player?: string; media_player_action?: 'play' | 'stop'; + display_mode?: ViewDisplayMode; }, ): FrigateCardCustomAction | null { if (action === 'camera_select' || action === 'live_substream_select') { @@ -67,6 +69,17 @@ export function createFrigateCardCustomAction( ...(args.cardID && { card_id: args.cardID }), }; } + if (action === 'display_mode_select') { + if (!args?.display_mode) { + return null; + } + return { + action: 'fire-dom-event', + frigate_card_action: action, + display_mode: args?.display_mode, + ...(args.cardID && { card_id: args.cardID }), + }; + } return { action: 'fire-dom-event', frigate_card_action: action, diff --git a/src/utils/basic.ts b/src/utils/basic.ts index ac4b9a2d..2321fe5e 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -221,3 +221,8 @@ export const setOrRemoveAttribute = ( element.removeAttribute(name); } }; + +/** + * Allow typescript to narrow types based on truthy filter. + */ +export const filterTruthy = (x: T | false | undefined | null | '' | 0): x is T => !!x; diff --git a/src/utils/media-grid-controller.ts b/src/utils/media-grid-controller.ts new file mode 100644 index 00000000..6f09dfb9 --- /dev/null +++ b/src/utils/media-grid-controller.ts @@ -0,0 +1,328 @@ +import throttle from 'lodash-es/throttle'; +import Masonry from 'masonry-layout'; +import { MediaLoadedInfo, ViewDisplayConfig } from '../types'; +import { dispatchFrigateCardEvent, setOrRemoveAttribute } from './basic'; +import { + FrigateMediaLoadedEventTarget, + dispatchExistingMediaLoadedInfoAsEvent, + dispatchMediaUnloadedEvent, +} from './media-info'; + +// The default minimum cell width: if the columns are not specified this value +// is used to compute the number of columns, always trying to keep each cell as +// at least this width. On Android, a card in portrait mode is 396 pixels, and +// we'd like to support two cells wide in that configuration. +const MEDIA_GRID_DEFAULT_MIN_CELL_WIDTH = 190; +const MEDIA_GRID_DEFAULT_IDEAL_CELL_WIDTH = 600; +const MEDIA_GRID_DEFAULT_SELECTED_WIDTH_FACTOR = 2.0; + +type GridID = string; +type MediaGridChild = HTMLElement & FrigateMediaLoadedEventTarget; +type MediaGridContents = Map; + +export interface MediaGridSelected { + selected: GridID; +} + +export interface MediaGridConstructorOptions { + selected?: GridID; + idAttribute?: string; +} + +const SELECT_CHILD_EVENTS = ['click', 'touchend']; + +export class MediaGridController { + protected _host: HTMLElement; + + protected _selected: GridID | null; + protected _mediaLoadedInfoMap: Map = new Map(); + protected _gridContents: MediaGridContents = new Map(); + protected _masonry: Masonry | null = null; + protected _displayConfig: ViewDisplayConfig | null = null; + protected _hostWidth: number; + protected _idAttribute: string; + + protected _throttledLayout = throttle( + () => this._masonry?.layout?.(), + // Throttle layout calls to larger than the masonry.js transitionDuration + // value specified below. + 500, + { trailing: true, leading: false }, + ); + + protected _mutationObserver = new MutationObserver( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + (_mutations: MutationRecord[], _observer: MutationObserver) => + this._calculateGridContentsFromHost(), + ); + protected _cellResizeObserver = new ResizeObserver(this._cellResizeHandler.bind(this)); + protected _hostResizeObserver = new ResizeObserver(this._hostResizeHandler.bind(this)); + + constructor(host: HTMLElement, options?: MediaGridConstructorOptions) { + this._host = host; + this._selected = options?.selected ?? null; + this._idAttribute = options?.idAttribute ?? 'grid-id'; + this._hostWidth = this._host.getBoundingClientRect().width; + this._hostResizeObserver.observe(host); + + this._calculateGridContentsFromHost(); + this._mutationObserver.observe(host, { childList: true }); + } + + public destroy(): void { + this._hostResizeObserver.disconnect(); + this._cellResizeObserver.disconnect(); + this._mediaLoadedInfoMap.clear(); + this._masonry?.destroy?.(); + this._masonry = null; + + for (const child of this._gridContents.values()) { + this._removeChildEventListeners(child); + } + this._gridContents.clear(); + } + + public setDisplayConfig(displayConfig: ViewDisplayConfig | null): void { + this._displayConfig = displayConfig; + this._calculateGridContentsFromHost(); + } + + public getGridContents(): MediaGridContents { + return this._gridContents; + } + + public getGridSize(): number { + return this._gridContents.size; + } + + public getSelected(): GridID | null { + return this._selected; + } + + public selectCell(id: GridID) { + if (this._selected === id) { + return; + } + + this._selected = id; + dispatchFrigateCardEvent(this._host, 'media-grid:selected', { selected: id }); + + const mediaLoadedInfo = this._mediaLoadedInfoMap.get(id); + if (mediaLoadedInfo) { + dispatchExistingMediaLoadedInfoAsEvent(this._host, mediaLoadedInfo); + } + + this._updateSelectedStylesOnElements(); + + // Sizes may change when an element is selected, so re-do the layout (must + // come after the call to _updateStylesOnElements in order to ensure the + // right styles are applied first). + this._throttledLayout(); + } + + public unselectAll() { + if (this._selected !== null) { + dispatchMediaUnloadedEvent(this._host); + dispatchFrigateCardEvent(this._host, 'media-grid:unselected'); + } + this._selected = null; + this._updateSelectedStylesOnElements(); + } + + protected _calculateGridContentsFromHost(): void { + let childrenElements: Element[]; + + if (this._host instanceof HTMLSlotElement) { + childrenElements = this._host.assignedElements({ flatten: true }); + } else { + childrenElements = [...this._host.children]; + } + + const gridContents: MediaGridContents = new Map(); + for (const child of childrenElements) { + if (child instanceof HTMLElement) { + const id = child.getAttribute(this._idAttribute) || String(gridContents.size); + gridContents.set(id, child); + } + } + + this._setGridContents(gridContents); + } + + protected _setGridContents(elements: MediaGridContents): void { + this._gridContents = elements; + + // Remove media loaded info objects that belong to objects no longer in the + // grid. + for (const key of this._mediaLoadedInfoMap.keys()) { + if (!elements.has(key)) { + this._mediaLoadedInfoMap.delete(key); + } + } + + if (this._selected !== null && !this._gridContents.has(this._selected)) { + this.unselectAll(); + } + + for (const element of elements.values()) { + this._removeChildEventListeners(element); + this._addChildEventListeners(element); + } + + this._setColumnSizeStyles(); + this._createMasonry(); + + // Observe grid elements for size changes. + this._cellResizeObserver.disconnect(); + for (const child of elements.values()) { + this._cellResizeObserver.observe(child); + } + + this._updateSelectedStylesOnElements(); + this._setColumnSizeStyles(); + } + + protected _handleMediaLoadedInfoEvent = (ev: CustomEvent): void => { + const eventPath = ev.composedPath(); + + for (const [id, element] of this._gridContents.entries()) { + if (eventPath.includes(element)) { + this._mediaLoadedInfoMap.set(id, ev.detail); + if (id !== this._selected) { + ev.stopPropagation(); + } + break; + } + } + }; + + protected _hostResizeHandler(): void { + const dimensions = this._host.getBoundingClientRect(); + + // Only resize things if the width has changed. It is expected that the + // height may change during the layout. + if (dimensions.width !== this._hostWidth) { + this._hostWidth = dimensions.width; + + // Reset the column CSS sizes first. + this._setColumnSizeStyles(); + + // Need to recreate the masonry layout since the column width will differ. + this._createMasonry(); + } + } + + protected _cellResizeHandler(): void { + this._throttledLayout(); + } + + protected _removeChildEventListeners(child: MediaGridChild): void { + for (const event of SELECT_CHILD_EVENTS) { + child.removeEventListener(event, this._handleSelectGridCellEvent, { + capture: true, + }); + } + + child.removeEventListener( + 'frigate-card:media:loaded', + this._handleMediaLoadedInfoEvent, + ); + } + + protected _addChildEventListeners(child: MediaGridChild): void { + for (const event of SELECT_CHILD_EVENTS) { + child.addEventListener(event, this._handleSelectGridCellEvent, { + capture: true, + }); + } + + child.addEventListener( + 'frigate-card:media:loaded', + this._handleMediaLoadedInfoEvent, + ); + } + + protected _createMasonry(): void { + if (this._masonry) { + this._masonry.destroy?.(); + } + + this._masonry = new Masonry(this._host, { + columnWidth: this._getColumnSize(), + initLayout: false, + percentPosition: true, + transitionDuration: '0.3s', + }); + this._masonry.addItems?.([...this._gridContents.values()]); + this._throttledLayout(); + } + + protected _handleSelectGridCellEvent = (ev: Event): void => { + const eventPath = ev.composedPath(); + + for (const [id, element] of this._gridContents.entries()) { + if (eventPath.includes(element)) { + if (this._selected !== id) { + this.selectCell(id); + ev.stopPropagation(); + } + break; + } + } + }; + + protected _updateSelectedStylesOnElements(): void { + for (const [id, element] of this._gridContents.entries()) { + setOrRemoveAttribute(element, id === this._selected, 'selected'); + + // Explicitly use an 'unselected' attribute vs a :not(selected) such that + // a carousel with neither selected nor unselected will behave normally. + // This matches a css selector in viewer-carousel.scss . + setOrRemoveAttribute(element, id !== this._selected, 'unselected'); + } + } + + protected _getColumnSize(): number { + return Math.round(this._hostWidth / this._getColumns()); + } + + protected _getColumns(): number { + if (this._displayConfig?.grid_columns) { + return this._displayConfig?.grid_columns; + } + + const maxColumns = this._displayConfig?.grid_max_columns ?? Infinity; + + // See if we can get a multi-column layout using the ideal cell width. + const idealColumns = Math.min( + maxColumns, + Math.floor(this._hostWidth / MEDIA_GRID_DEFAULT_IDEAL_CELL_WIDTH), + ); + if (idealColumns > 1) { + return idealColumns; + } + + // If not, get a multi-column view using the minimum cell width. + const minColumns = Math.floor( + Math.min(maxColumns, this._hostWidth / MEDIA_GRID_DEFAULT_MIN_CELL_WIDTH), + ); + + // Last result use at least 1 column. + return Math.max(1, minColumns); + } + + protected _setColumnSizeStyles(): void { + this._host.style.setProperty( + '--frigate-card-grid-column-size', + `${this._getColumnSize()}px`, + ); + + this._host.style.setProperty( + '--frigate-card-grid-selected-width-factor', + `${ + this._displayConfig?.grid_selected_width_factor ?? + MEDIA_GRID_DEFAULT_SELECTED_WIDTH_FACTOR + }`, + ); + } +} diff --git a/src/utils/media-info.ts b/src/utils/media-info.ts index 22637d7d..3e01807a 100644 --- a/src/utils/media-info.ts +++ b/src/utils/media-info.ts @@ -111,3 +111,33 @@ export function isValidMediaLoadedInfo(info: MediaLoadedInfo): boolean { info.height >= MEDIA_INFO_HEIGHT_CUTOFF && info.width >= MEDIA_INFO_WIDTH_CUTOFF ); } + +// Facilities correct Typescript typing of media:loaded event handlers. +export interface FrigateMediaLoadedEventTarget extends EventTarget { + addEventListener( + event: 'frigate-card:media:loaded', + listener: ( + this: FrigateMediaLoadedEventTarget, + ev: CustomEvent, + ) => void, + options?: AddEventListenerOptions | boolean, + ): void; + addEventListener( + type: string, + callback: EventListenerOrEventListenerObject, + options?: AddEventListenerOptions | boolean, + ): void; + removeEventListener( + event: 'frigate-card:media:loaded', + listener: ( + this: FrigateMediaLoadedEventTarget, + ev: CustomEvent, + ) => void, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + callback: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} diff --git a/src/utils/media-to-view.ts b/src/utils/media-to-view.ts index 655b5ca9..76215f78 100644 --- a/src/utils/media-to-view.ts +++ b/src/utils/media-to-view.ts @@ -1,20 +1,20 @@ +import { HomeAssistant } from 'custom-card-helpers'; import { ViewContext } from 'view'; +import { CameraManager } from '../camera-manager/manager'; +import { MediaQuery } from '../camera-manager/types'; +import { dispatchFrigateCardErrorEvent } from '../components/message'; +import { MEDIA_CHUNK_SIZE_DEFAULT } from '../const'; import { CardWideConfig, ClipsOrSnapshotsOrAll, FrigateCardView } from '../types'; -import { View } from '../view/view'; +import { ViewMedia } from '../view/media'; import { EventMediaQueries, MediaQueries, RecordingMediaQueries, } from '../view/media-queries'; -import { CameraManager } from '../camera-manager/manager'; -import { getAllDependentCameras } from './camera.js'; -import { ViewMedia } from '../view/media'; -import { HomeAssistant } from 'custom-card-helpers'; -import { dispatchFrigateCardErrorEvent } from '../components/message'; import { MediaQueriesResults } from '../view/media-queries-results'; +import { View } from '../view/view'; import { errorToConsole } from './basic'; -import { MediaQuery } from '../camera-manager/types'; -import { MEDIA_CHUNK_SIZE_DEFAULT } from '../const'; +import { getAllDependentCameras } from './camera.js'; type ResultSelectType = 'latest' | 'time' | 'none'; @@ -25,13 +25,16 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( cardWideConfig: CardWideConfig, view: View, options?: { + allCameras?: boolean; mediaType?: ClipsOrSnapshotsOrAll; targetView?: FrigateCardView; select?: ResultSelectType; }, ): Promise => { - const cameraIDs = getAllDependentCameras(cameraManager, view.camera); - if (!cameraIDs) { + const cameraIDs = options?.allCameras + ? cameraManager.getStore().getVisibleCameraIDs() + : getAllDependentCameras(cameraManager, view.camera); + if (!cameraIDs.size) { return; } @@ -84,12 +87,15 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( cardWideConfig: CardWideConfig, view: View, options?: { + allCameras?: boolean; targetView?: 'recording' | 'recordings'; select?: ResultSelectType; }, ): Promise => { - const cameraIDs = getAllDependentCameras(cameraManager, view.camera); - if (!cameraIDs) { + const cameraIDs = options?.allCameras + ? cameraManager.getStore().getVisibleCameraIDs() + : getAllDependentCameras(cameraManager, view.camera); + if (!cameraIDs.size) { return; } @@ -161,12 +167,7 @@ export const executeMediaQueryForView = async ( return null; } - const queryResults = new MediaQueriesResults( - mediaArray, - options?.select === 'latest' && mediaArray.length - ? mediaArray.length - 1 - : undefined, - ); + const queryResults = new MediaQueriesResults({ results: mediaArray }); let viewerContext: ViewContext | undefined = {}; if (options?.select === 'time' && options?.targetTime) { @@ -180,16 +181,14 @@ export const executeMediaQueryForView = async ( }; } - return ( - view - ?.evolve({ - query: query, - queryResults: queryResults, - view: options?.targetView, - camera: options?.targetCameraID, - }) - .mergeInContext(viewerContext) ?? null - ); + return view + .evolve({ + query: query, + queryResults: queryResults, + view: options?.targetView, + camera: options?.targetCameraID, + }) + .mergeInContext(viewerContext); }; /** @@ -201,7 +200,7 @@ export const executeMediaQueryForView = async ( */ export const findBestMediaIndex = ( mediaArray: ViewMedia[], - targetTime: Date + targetTime: Date, ): number | null => { let bestMatch: | { diff --git a/src/utils/menu-controller.ts b/src/utils/menu-controller.ts index 18d9a841..64123abd 100644 --- a/src/utils/menu-controller.ts +++ b/src/utils/menu-controller.ts @@ -5,11 +5,11 @@ import { CameraManager } from '../camera-manager/manager'; import { FRIGATE_BUTTON_MENU_ICON } from '../const'; import { localize } from '../localize/localize.js'; import { - FRIGATE_CARD_VIEWS_USER_SPECIFIED, - FrigateCardConfig, - FrigateCardCustomAction, - MediaLoadedInfo, - MenuButton, + FrigateCardConfig, + FrigateCardCustomAction, + FRIGATE_CARD_VIEWS_USER_SPECIFIED, + MediaLoadedInfo, + MenuButton, } from '../types'; import { View } from '../view/view'; import { createFrigateCardCustomAction } from './action'; @@ -388,10 +388,28 @@ export class MenuButtonController { ...config.menu.buttons.screenshot, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.screenshot'), - tap_action: createFrigateCardCustomAction('screenshot') as FrigateCardCustomAction, + tap_action: createFrigateCardCustomAction( + 'screenshot', + ) as FrigateCardCustomAction, }); } + if (view.hasMultipleDisplayModes(visibleCameras.size)) { + const isGrid = view.isGrid(); + const action = createFrigateCardCustomAction('display_mode_select', { + display_mode: isGrid ? 'single' : 'grid', + }); + if (action) { + buttons.push({ + icon: isGrid ? 'mdi:grid-off' : 'mdi:grid', + ...config.menu.buttons.display_mode, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.display_mode'), + tap_action: action, + }); + } + } + const styledDynamicButtons = this._dynamicMenuButtons.map((button) => ({ style: this._getStyleFromActions(config, view, button), ...button, diff --git a/src/utils/zoom/zoom.ts b/src/utils/zoom/zoom.ts index b3fc9d0d..08f1ce06 100644 --- a/src/utils/zoom/zoom.ts +++ b/src/utils/zoom/zoom.ts @@ -141,15 +141,20 @@ export class Zoom { } public deactivate(): void { - const unregisterListener = (events: string[], func: (ev: Event) => void) => { + const unregisterListener = ( + events: string[], + func: (ev: Event) => void, + options?: EventListenerOptions, + ) => { events.forEach((eventName) => { - this._element.removeEventListener(eventName, func); + this._element.removeEventListener(eventName, func, options); }); }; - unregisterListener(this._events['down'], this._downHandler); - unregisterListener(this._events['move'], this._moveHandler); - unregisterListener(this._events['up'], this._upHandler); + unregisterListener(this._events['down'], this._downHandler, { capture: true }); + unregisterListener(this._events['move'], this._moveHandler, { capture: true }); + unregisterListener(this._events['up'], this._upHandler, { capture: true }); unregisterListener(['wheel'], this._wheelHandler); + unregisterListener(['click'], this._clickHandler, { capture: true }); } } diff --git a/src/view/media-queries-results.ts b/src/view/media-queries-results.ts index e0d9f5d4..cde420c2 100644 --- a/src/view/media-queries-results.ts +++ b/src/view/media-queries-results.ts @@ -1,40 +1,151 @@ -import clone from 'lodash-es/clone.js'; import { isSuperset } from '../utils/basic.js'; import { ViewMedia } from './media.js'; -export class MediaQueriesResults { - protected _results: ViewMedia[] | null = null; - protected _resultsTimestamp: Date | null = null; - protected _selectedIndex: number | null = null; +type CameraResultSlices = Map; +type SelectApproach = 'first' | 'last'; - constructor(results?: ViewMedia[], selectedIndex?: number | null) { - if (results) { - this.setResults(results); +interface ResultSliceOptions { + results?: ViewMedia[]; + selectedIndex?: number | null; + selectApproach?: SelectApproach; +} + +class ResultSlice { + protected _results: ViewMedia[]; + protected _selectedIndex: number | null; + + constructor(options?: ResultSliceOptions) { + this._results = options?.results ?? []; + this._selectedIndex = this._getInitialSelectedIndex(options); + } + + protected _getInitialSelectedIndex(options?: ResultSliceOptions): number | null { + if (options?.selectedIndex !== undefined && options?.selectedIndex !== null) { + return options.selectedIndex; } - if (selectedIndex !== undefined) { - this.selectResult(selectedIndex); + if (options?.results && options.results.length) { + if (!options?.selectApproach || options?.selectApproach === 'last') { + return options.results.length - 1; + } else if (options.selectApproach === 'first') { + return 0; + } + } + return null; + } + + public clone(): ResultSlice { + return new ResultSlice({ + results: this._results, + selectedIndex: this._selectedIndex, + }); + } + + public getResults(): ViewMedia[] { + return this._results; + } + public getSelectedIndex(): number | null { + return this._selectedIndex; + } + public getResultsCount(): number { + return this.getResults().length; + } + public hasResults(): boolean { + return this.getResultsCount() !== 0; + } + public getResult(index?: number): ViewMedia | null { + return index === undefined ? null : this._results[index]; + } + public getSelectedResult(): ViewMedia | null { + const index = this.getSelectedIndex(); + return index !== null ? this.getResult(index) : null; + } + public hasSelectedResult(): boolean { + return this.getSelectedResult() !== null; + } + public resetSelectedResult(): void { + this._selectedIndex = null; + } + + public selectIndex(index: number | null): void { + if (index === null || (index >= 0 && index < this._results.length)) { + this._selectedIndex = index; + } + } + public selectResultIfFound(func: (media: ViewMedia) => boolean): void { + for (const [index, result] of this._results.entries()) { + if (func(result)) { + this.selectIndex(index); + break; + } + } + } + public selectBestResult(func: (media: ViewMedia[]) => number | null): void { + const resultIndex = func(this._results); + if (resultIndex !== null) { + this.selectIndex(resultIndex); + } + } +} + +interface ResultSliceSelectionCriteria { + main?: boolean; + cameraID?: string; + allCameras?: boolean; +} + +export class MediaQueriesResults { + protected _resultsTimestamp: Date | null = null; + protected _main: ResultSlice; + protected _cameras: CameraResultSlices = new Map(); + + constructor(options?: ResultSliceOptions) { + this._resultsTimestamp = new Date(); + this._main = new ResultSlice(options); + this._buildByCameraSlices(options?.selectApproach); + } + + protected _buildByCameraSlices(selectApproach?: SelectApproach): void { + const cameraMap: Map = new Map(); + for (const result of this._main.getResults()) { + const cameraID = result.getCameraID(); + const media: ViewMedia[] = cameraMap.get(cameraID) ?? []; + media.push(result); + cameraMap.set(cameraID, media); + } + + for (const [cameraID, media] of cameraMap.entries()) { + this._cameras.set( + cameraID, + new ResultSlice({ + results: media, + selectApproach: selectApproach, + }), + ); } } public clone(): MediaQueriesResults { - // Shallow clone -- will reuse the same _results object (as there are no + // Shallow clone -- will reuse the same results object (as there are no // methods that support modification of the results themselves, and since - // changing the selectedIndex on a consistent set of results is a common + // changing the index on a consistent set of results is a very common // operation). - return clone(this); + const copy = new MediaQueriesResults(); + copy._resultsTimestamp = this._resultsTimestamp; + copy._main = this._main.clone(); + + for (const [cameraID, slice] of this._cameras.entries()) { + copy._cameras.set(cameraID, slice.clone()); + } + return copy; } public isSupersetOf(that: MediaQueriesResults): boolean { - if (!this._results || !that._results) { - return false; - } - - const thisMediaIDs = new Set(this._results.map((media) => media.getID())); - const thatMediaIDs = new Set(that._results.map((media) => media.getID())); + const thisMediaIDs = new Set(this._main.getResults()?.map((media) => media.getID())); + const thatMediaIDs = new Set(that._main.getResults()?.map((media) => media.getID())); if ( - !thisMediaIDs || - !thatMediaIDs || + !thisMediaIDs.size || + !thatMediaIDs.size || // If either media sets contain a null identifier (i.e. a media item with // no ID) we must assume this is not a subset as multiple media items may // reduce to the same null identifier above. @@ -46,68 +157,105 @@ export class MediaQueriesResults { return isSuperset(thisMediaIDs, thatMediaIDs); } - public getResults(): ViewMedia[] | null { - return this._results; + public getCameraIDs(): Set { + return new Set(this._cameras.keys()); } - public getResultsCount(): number { - return this._results?.length ?? 0; + + public getSlice(cameraID?: string): ResultSlice | null { + return cameraID ? this._cameras.get(cameraID) ?? null : this._main; } - public hasResults(): boolean { - return !!this._results; + + public getResults(cameraID?: string): ViewMedia[] | null { + return this.getSlice(cameraID)?.getResults() ?? null; } - public setResults(results: ViewMedia[]) { - this._results = results; - this._resultsTimestamp = new Date(); + public getResultsCount(cameraID?: string): number { + return this.getSlice(cameraID)?.getResultsCount() ?? 0; } - public getResult(index?: number): ViewMedia | null { - if (!this._results || index === undefined) { - return null; - } - return this._results[index]; + public hasResults(cameraID?: string): boolean { + return this.getSlice(cameraID)?.getResultsCount() !== 0; } - public getSelectedResult(): ViewMedia | null { - return this._selectedIndex === null ? null : this.getResult(this._selectedIndex); + public getResult(index?: number, cameraID?: string): ViewMedia | null { + return this.getSlice(cameraID)?.getResult(index) ?? null; } - public getSelectedIndex(): number | null { - return this._selectedIndex; + public getSelectedIndex(cameraID?: string): number | null { + return this.getSlice(cameraID)?.getSelectedIndex() ?? null; } - public hasSelectedResult(): boolean { - return this.getSelectedResult() !== null; + public getSelectedResult(cameraID?: string): ViewMedia | null { + return this.getSlice(cameraID)?.getSelectedResult() ?? null; } - public resetSelectedResult(): MediaQueriesResults { - this._selectedIndex = null; + public hasSelectedResult(cameraID?: string): boolean { + return this.getSlice(cameraID)?.hasSelectedResult() ?? false; + } + public resetSelectedResult(cameraID?: string): MediaQueriesResults { + this.getSlice(cameraID)?.resetSelectedResult(); return this; } public getResultsTimestamp(): Date | null { return this._resultsTimestamp; } - public selectResult(index: number | null): MediaQueriesResults { - if ( - index === null || - (this._results && index >= 0 && index < this._results.length) - ) { - this._selectedIndex = index; + public selectIndex(index: number, cameraID?: string): MediaQueriesResults { + this.getSlice(cameraID)?.selectIndex(index); + if (!cameraID) { + // If the main selection is changed, it must also change the matching + // camera selection. + this.demoteMainSelectionToCameraSelection(); } return this; } - public selectResultIfFound(func: (media: ViewMedia) => boolean): MediaQueriesResults { - for (const [index, result] of this._results?.entries() ?? []) { - if (func(result)) { - this._selectedIndex = index; - break; - } + + public demoteMainSelectionToCameraSelection(): MediaQueriesResults { + const selected = this.getSelectedResult(); + if (selected) { + const cameraID = selected.getCameraID(); + this.resetSelectedResult(cameraID); + this.selectResultIfFound((media) => media === selected, { cameraID: cameraID }); + } + return this; + } + + public promoteCameraSelectionToMainSelection(cameraID: string): MediaQueriesResults { + const selected = this.getSelectedResult(cameraID); + this.resetSelectedResult(); + this.selectResultIfFound((media) => media === selected); + return this; + } + + protected _getCameraIDsFromCriteria( + criteria?: ResultSliceSelectionCriteria, + ): Set | null { + return criteria?.allCameras + ? this.getCameraIDs() + : criteria?.cameraID + ? new Set([criteria.cameraID]) + : null; + } + + public selectResultIfFound( + func: (media: ViewMedia) => boolean, + criteria?: ResultSliceSelectionCriteria, + ): MediaQueriesResults { + if (!criteria || criteria?.main) { + this._main.selectResultIfFound(func); + this.demoteMainSelectionToCameraSelection(); + } + const cameraIDs = this._getCameraIDsFromCriteria(criteria); + for (const cameraID of cameraIDs ?? []) { + this.getSlice(cameraID)?.selectResultIfFound(func); } return this; } public selectBestResult( func: (media: ViewMedia[]) => number | null, + criteria?: ResultSliceSelectionCriteria, ): MediaQueriesResults { - if (this._results) { - const resultIndex = func(this._results); - if (resultIndex !== null) { - this._selectedIndex = resultIndex; - } + if (!criteria || criteria.main) { + this._main.selectBestResult(func); + this.demoteMainSelectionToCameraSelection(); + } + const cameraIDs = this._getCameraIDsFromCriteria(criteria); + for (const cameraID of cameraIDs ?? []) { + this.getSlice(cameraID)?.selectBestResult(func); } return this; } diff --git a/src/view/media-queries.ts b/src/view/media-queries.ts index 718c1d98..2a75e5e3 100644 --- a/src/view/media-queries.ts +++ b/src/view/media-queries.ts @@ -23,14 +23,24 @@ class MediaQueriesBase { public setQueries(queries: T[]): void { this._queries = queries; } + + public hasQueriesForCameraIDs(cameraIDs: Set) { + for (const cameraID of cameraIDs) { + if (!this._queries?.some((query) => query.cameraIDs.has(cameraID))) { + return false; + } + } + return true; + } } export class EventMediaQueries extends MediaQueriesBase { - public convertToClipsQueries(): void { + public convertToClipsQueries(): this { for (const query of this._queries ?? []) { delete query.hasSnapshot; query.hasClip = true; } + return this; } public clone(): EventMediaQueries { diff --git a/src/view/media.ts b/src/view/media.ts index abb62371..369aa63e 100644 --- a/src/view/media.ts +++ b/src/view/media.ts @@ -13,9 +13,6 @@ export class ViewMedia { this._mediaType = mediaType; this._cameraID = cameraID; } - public getContentType(): 'image' | 'video' { - return this._mediaType === 'snapshot' ? 'image' : 'video'; - } public getCameraID(): string { return this._cameraID; } diff --git a/src/view/view.ts b/src/view/view.ts index 0f417081..e0f13ec1 100644 --- a/src/view/view.ts +++ b/src/view/view.ts @@ -1,5 +1,5 @@ import { ViewContext } from 'view'; -import { ClipsOrSnapshots, FrigateCardView } from '../types.js'; +import { ClipsOrSnapshots, FrigateCardView, ViewDisplayMode } from '../types.js'; import { dispatchFrigateCardEvent } from '../utils/basic.js'; import { MediaQueries } from './media-queries'; import { MediaQueriesClassifier } from './media-queries-classifier.js'; @@ -11,6 +11,7 @@ interface ViewEvolveParameters { query?: MediaQueries | null; queryResults?: MediaQueriesResults | null; context?: ViewContext | null; + displayMode?: ViewDisplayMode | null; } export interface ViewParameters extends ViewEvolveParameters { @@ -24,6 +25,7 @@ export class View { public query: MediaQueries | null; public queryResults: MediaQueriesResults | null; public context: ViewContext | null; + public displayMode: ViewDisplayMode | null; constructor(params: ViewParameters) { this.view = params.view; @@ -31,6 +33,7 @@ export class View { this.query = params.query ?? null; this.queryResults = params.queryResults ?? null; this.context = params.context ?? null; + this.displayMode = params.displayMode ?? null; } /** @@ -142,6 +145,7 @@ export class View { query: this.query?.clone() ?? null, queryResults: this.queryResults?.clone() ?? null, context: this.context, + displayMode: this.displayMode, }); } @@ -160,6 +164,8 @@ export class View { ? params.queryResults : this.queryResults?.clone() ?? null, context: params.context !== undefined ? params.context : this.context, + displayMode: + params.displayMode !== undefined ? params.displayMode : this.displayMode, }); } @@ -185,6 +191,17 @@ export class View { return this; } + public removeContextProperty( + contextKey: keyof ViewContext, + removeKey: PropertyKey, + ): View { + const contextObj = this.context?.[contextKey]; + if (contextObj) { + delete contextObj[removeKey]; + } + return this; + } + /** * Determine if current view matches a named view. */ @@ -214,6 +231,13 @@ export class View { return ['clip', 'snapshot', 'media', 'recording'].includes(this.view); } + public hasMultipleDisplayModes(cameraCount?: number): boolean { + return ( + (this.is('live') && (cameraCount ?? 0) > 1) || + (this.isViewerView() && (this.queryResults?.getCameraIDs().size ?? 0) > 1) + ); + } + /** * Get the default media type for this view if available. * @returns Whether the default media is `clips`, `snapshots`, `recordings` or unknown @@ -232,6 +256,10 @@ export class View { return null; } + public isGrid(): boolean { + return this.displayMode === 'grid'; + } + /** * Dispatch an event to request a view change. * @param target The target dispatching the event. diff --git a/tests/camera-manager/utils.test.ts b/tests/camera-manager/utils.test.ts index 0a870cc4..913ad754 100644 --- a/tests/camera-manager/utils.test.ts +++ b/tests/camera-manager/utils.test.ts @@ -76,30 +76,26 @@ describe('capEndDate', () => { }); describe('sortMedia', () => { - const media_1 = new TestViewMedia( - 'id-1', - new Date('2023-04-29T14:25'), - 'clip', - 'camera-1', - ); - const media_2 = new TestViewMedia( - 'id-2', - new Date('2023-04-29T14:26'), - 'clip', - 'camera-1', - ); - const media_3_dup_id = new TestViewMedia( - 'id-2', - new Date('2023-04-29T14:26'), - 'clip', - 'camera-1', - ); - const media_4_no_id = new TestViewMedia( - null, - new Date('2023-04-29T14:27'), - 'clip', - 'camera-1', - ); + const media_1 = new TestViewMedia({ + id: 'id-1', + startTime: new Date('2023-04-29T14:25'), + cameraID: 'camera-1', + }); + const media_2 = new TestViewMedia({ + id: 'id-2', + startTime: new Date('2023-04-29T14:26'), + cameraID: 'camera-1', + }); + const media_3_dup_id = new TestViewMedia({ + id: 'id-2', + startTime: new Date('2023-04-29T14:26'), + cameraID: 'camera-1', + }); + const media_4_no_id = new TestViewMedia({ + id: null, + startTime: new Date('2023-04-29T14:27'), + cameraID: 'camera-1', + }); it('should sort sorted media', () => { const media = [media_1, media_2]; diff --git a/tests/conditions.test.ts b/tests/conditions.test.ts index 3c98db99..d5eb3fbc 100644 --- a/tests/conditions.test.ts +++ b/tests/conditions.test.ts @@ -1,4 +1,4 @@ -import { afterEach, describe, it, expect, vi } from 'vitest'; +import { afterEach, describe, expect, it, vi } from 'vitest'; import { ConditionController, ConditionEvaluateRequestEvent, @@ -6,6 +6,7 @@ import { getOverriddenConfig, getOverridesByKey, } from '../src/conditions'; +import { FrigateCardCondition } from '../src/types'; import { createCondition, createConfig, createStateEntity } from './test-utils'; // @vitest-environment jsdom @@ -347,4 +348,14 @@ describe('ConditionController', () => { controller.destroy(); expect(removeEventListener).toBeCalled(); }); + + it('should evaluate conditions with display mode', () => { + const controller = new ConditionController(); + const condition: FrigateCardCondition = { display_mode: 'grid' }; + expect(controller.evaluateCondition(condition)).toBeFalsy(); + controller.setState({ displayMode: 'grid' }); + expect(controller.evaluateCondition(condition)).toBeTruthy(); + controller.setState({ displayMode: 'single' }); + expect(controller.evaluateCondition(condition)).toBeFalsy(); + }); }); diff --git a/tests/test-utils.ts b/tests/test-utils.ts index e7bda43d..1dc0bcec 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -9,6 +9,7 @@ import { CameraConfigs, CameraManagerCameraCapabilities, CameraManagerMediaCapabilities, + QueryType, } from '../src/camera-manager/types'; import { CameraConfig, @@ -16,10 +17,12 @@ import { FrigateCardCondition, FrigateCardConfig, MediaLoadedInfo, + PerformanceConfig, RawFrigateCardConfig, cameraConfigSchema, frigateCardConditionSchema, frigateCardConfigSchema, + performanceConfigSchema, } from '../src/types'; import { Entity } from '../src/utils/ha/entity-registry/types'; import { ViewMedia, ViewMediaType } from '../src/view/media'; @@ -126,11 +129,25 @@ export const createCameraManager = (options?: { const configs = options?.configs ?? new Map([['camera', createCameraConfig()]]); vi.mocked(store.getCameras).mockReturnValue(configs); vi.mocked(store.getVisibleCameras).mockReturnValue(configs); + vi.mocked(store.getVisibleCameraIDs).mockReturnValue(new Set(configs.keys())); vi.mocked(store.getCameraConfig).mockImplementation((cameraID): CameraConfig => { return configs.get(cameraID) ?? createCameraConfig(); }); } vi.mocked(cameraManager.getStore).mockReturnValue(store); + vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue([ + { + cameraIDs: new Set(['camera']), + type: QueryType.Event, + }, + ]); + vi.mocked(cameraManager.generateDefaultRecordingQueries).mockReturnValue([ + { + cameraIDs: new Set(['camera']), + type: QueryType.Recording, + }, + ]); + return cameraManager; }; @@ -169,21 +186,44 @@ export const createMediaLoadedInfo = ( }; }; +export const createPerformanceConfig = (config: unknown): PerformanceConfig => { + return performanceConfigSchema.parse(config); +}; + +export const generateViewMediaArray = (options?: { + cameraIDs?: string[]; + count?: number; +}): ViewMedia[] => { + const media: ViewMedia[] = []; + for (let i = 0; i < (options?.count ?? 100); ++i) { + for (const cameraID of options?.cameraIDs ?? ['kitchen', 'office']) { + media.push(new TestViewMedia({ cameraID: cameraID, id: `id-${cameraID}-${i}` })); + } + } + return media; +}; + // ViewMedia itself has no native way to set startTime and ID that aren't linked // to an engine. export class TestViewMedia extends ViewMedia { protected _id: string | null; - protected _startTime: Date; + protected _startTime: Date | null; + protected _endTime: Date | null; + protected _inProgress: boolean | null; - constructor( - id: string | null, - startTime: Date, - mediaType: ViewMediaType, - cameraID: string, - ) { - super(mediaType, cameraID); - this._id = id; - this._startTime = startTime; + constructor(options?: { + id?: string | null; + startTime?: Date; + mediaType?: ViewMediaType; + cameraID?: string; + endTime?: Date; + inProgress?: boolean; + }) { + super(options?.mediaType ?? 'clip', options?.cameraID ?? 'camera'); + this._id = options?.id !== undefined ? options.id : 'id'; + this._startTime = options?.startTime ?? null; + this._endTime = options?.endTime ?? null; + this._inProgress = options?.inProgress !== undefined ? options.inProgress : false; } public getID(): string | null { return this._id; @@ -191,4 +231,25 @@ export class TestViewMedia extends ViewMedia { public getStartTime(): Date | null { return this._startTime; } + public getEndTime(): Date | null { + return this._endTime; + } + public inProgress(): boolean | null { + return this._inProgress; + } } + +export const createResizeObserverImplementation = (): (() => void) => { + return () => ({ + observe: vi.fn(), + unobserve: vi.fn(), + disconnect: vi.fn(), + }); +}; + +export const createMutationObserverImplementation = (): (() => void) => { + return () => ({ + observe: vi.fn(), + disconnect: vi.fn(), + }); +}; diff --git a/tests/utils/action.test.ts b/tests/utils/action.test.ts index d4ae8af8..3b0e6970 100644 --- a/tests/utils/action.test.ts +++ b/tests/utils/action.test.ts @@ -103,6 +103,24 @@ describe('createFrigateCardCustomAction', () => { card_id: 'card_id', }); }); + + it('should create display mode action', () => { + expect( + createFrigateCardCustomAction('display_mode_select', { + display_mode: 'grid', + cardID: 'card_id', + }), + ).toEqual({ + action: 'fire-dom-event', + frigate_card_action: 'display_mode_select', + display_mode: 'grid', + card_id: 'card_id', + }); + }); + + it('should not create display mode action without display mode', () => { + expect(createFrigateCardCustomAction('display_mode_select')).toBeNull(); + }); }); describe('getActionConfigGivenAction', () => { diff --git a/tests/utils/basic.test.ts b/tests/utils/basic.test.ts index a17fd576..6d45f08c 100644 --- a/tests/utils/basic.test.ts +++ b/tests/utils/basic.test.ts @@ -8,6 +8,7 @@ import { dayToDate, dispatchFrigateCardEvent, errorToConsole, + filterTruthy, formatDate, formatDateAndTime, getDurationString, @@ -227,7 +228,13 @@ describe('isValidDate', () => { }); describe('setOrRemoveAttribute', () => { - it('should set attribute', () => { + it('should set attribute without value', () => { + const element = document.createElement('div'); + setOrRemoveAttribute(element, true, 'key'); + expect(element.getAttribute('key')).toBe(''); + }); + + it('should set attribute with value', () => { const element = document.createElement('div'); setOrRemoveAttribute(element, true, 'key', 'value'); expect(element.getAttribute('key')).toBe('value'); @@ -240,3 +247,12 @@ describe('setOrRemoveAttribute', () => { expect(element.getAttribute('key')).toBeFalsy(); }); }); + +describe('filterTruthy', () => { + it('should return true for true', () => { + expect(filterTruthy(true)).toBeTruthy(); + }); + it('should return false for false', () => { + expect(filterTruthy(false)).toBeFalsy(); + }); +}); diff --git a/tests/utils/media-grid-controller.test.ts b/tests/utils/media-grid-controller.test.ts new file mode 100644 index 00000000..255c2105 --- /dev/null +++ b/tests/utils/media-grid-controller.test.ts @@ -0,0 +1,400 @@ +import Masonry from 'masonry-layout'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { MediaLoadedInfo } from '../../src/types'; +import { + MediaGridConstructorOptions, + MediaGridController, +} from '../../src/utils/media-grid-controller'; +import { dispatchExistingMediaLoadedInfoAsEvent } from '../../src/utils/media-info'; +import { + createMutationObserverImplementation, + createResizeObserverImplementation, +} from '../test-utils'; + +vi.mock('lodash-es/throttle', () => ({ + default: vi.fn((fn) => fn), +})); + +const masonry = mock(); +vi.mock('masonry-layout', () => ({ + default: vi.fn().mockImplementation(() => { + return masonry; + }), +})); + +const createChildren = (childIDs?: string[], idAttribute?: string): HTMLElement[] => { + const children: HTMLElement[] = []; + for (let i = 0; i < (childIDs?.length ?? 3); ++i) { + const child = document.createElement('div'); + if (childIDs) { + child.setAttribute(idAttribute ?? 'grid-id', childIDs[i]); + } + children.push(child); + } + return children; +}; + +const setElementWidth = (element: HTMLElement, width: number): void => { + element.getBoundingClientRect = vi.fn().mockReturnValue({ + width: width, + }); +}; + +const createHost = (options?: { + children?: HTMLElement[]; + width?: number; +}): HTMLElement => { + const host = document.createElement('div'); + if (options?.children) { + host.append(...options.children); + } + // Default Lovelace card width is 492. + setElementWidth(host, options?.width ?? 492); + return host; +}; + +const createSlotParent = (): HTMLElement => { + const parent = document.createElement('div'); + parent.attachShadow({ mode: 'open' }); + return parent; +}; + +const createSlotHost = (options?: { + children?: HTMLElement[]; + parent?: HTMLElement; +}): HTMLElement => { + const parent = options?.parent ?? createSlotParent(); + const slot = document.createElement('slot'); + parent.shadowRoot?.append(slot); + + if (options?.children) { + // Children will automatically be slotted into the default slot. + parent.append(...options.children); + } + + return slot; +}; + +const createController = (host: HTMLElement, options?: MediaGridConstructorOptions) => { + return new MediaGridController(host, options); +}; + +const triggerMutationObserver = (): void => { + const mutationObserverTrigger = vi.mocked(global.MutationObserver).mock.calls[0][0]; + mutationObserverTrigger([], mock()); +}; + +const triggerResizeObserver = (cellOrHost: 'cell' | 'host'): void => { + const resizeObserverTrigger = vi.mocked(global.ResizeObserver).mock.calls[ + cellOrHost === 'cell' ? 0 : 1 + ][0]; + resizeObserverTrigger([], mock()); +}; + +// @vitest-environment jsdom +describe('MediaGridController', () => { + const mediaLoadedInfo: MediaLoadedInfo = { + width: 10, + height: 20, + }; + + beforeEach(() => { + vi.clearAllMocks(); + + global.ResizeObserver = vi + .fn() + // Caution: Order must match the order of initialization in + // media-grid-controller.ts . + .mockImplementationOnce(createResizeObserverImplementation()) + .mockImplementationOnce(createResizeObserverImplementation()); + + global.MutationObserver = vi + .fn() + .mockImplementation(createMutationObserverImplementation()); + //global.MutationObserver = mock(); + }); + + it('should be constructable', () => { + const controller = createController(createHost()); + expect(controller).toBeTruthy(); + expect(masonry.layout).toBeCalled(); + }); + + it('should set grid contents correctly from regular elements', () => { + const children = createChildren(); + const host = createHost({ children: children }); + const controller = createController(host); + expect(controller.getGridContents()).toEqual( + new Map([ + ['0', children[0]], + ['1', children[1]], + ['2', children[2]], + ]), + ); + expect(controller.getGridSize()).toBe(3); + expect(masonry.layout).toBeCalled(); + }); + + it('should set grid contents correctly from slotted elements', () => { + const children = createChildren(); + const host = createSlotHost({ children: children }); + const controller = createController(host); + expect(controller.getGridContents()).toEqual( + new Map([ + ['0', children[0]], + ['1', children[1]], + ['2', children[2]], + ]), + ); + expect(controller.getGridSize()).toBe(3); + }); + + it('should select element', () => { + const children = createChildren(); + const controller = createController(createSlotHost({ children: children })); + + // All children should be unselected. + expect(controller.getSelected()).toBeNull(); + for (const child of children) { + expect(child.getAttribute('selected')).toBeNull(); + expect(child.getAttribute('unselected')).toEqual(''); + } + + controller.selectCell('0'); + expect(controller.getSelected()).toBe('0'); + + // 1st child should now be selected. + expect(children[0].getAttribute('selected')).toEqual(''); + expect(children[0].getAttribute('unselected')).toBeNull(); + + // 2nd and 3rd should be unselected. + for (const child of children.slice(1)) { + expect(child.getAttribute('selected')).toBeNull(); + expect(child.getAttribute('unselected')).toEqual(''); + } + }); + + it('should re-select element', () => { + const controller = createController(createSlotHost({ children: createChildren() })); + + // All children should be unselected. + expect(controller.getSelected()).toBeNull(); + + controller.selectCell('0'); + expect(controller.getSelected()).toBe('0'); + + controller.selectCell('0'); + expect(controller.getSelected()).toBe('0'); + }); + + it('should dispatch media loaded info on selection', () => { + const children = createChildren(); + const host = createSlotHost({ children: children }); + const controller = createController(host); + + const mediaLoadedInfoHandler = vi.fn(); + host.addEventListener('frigate-card:media:loaded', mediaLoadedInfoHandler); + dispatchExistingMediaLoadedInfoAsEvent(children[0], mediaLoadedInfo); + + // Nothing is selected, so the event should not have propagated. + expect(mediaLoadedInfoHandler).not.toBeCalled(); + + controller.selectCell('0'); + expect(mediaLoadedInfoHandler).toBeCalledWith( + expect.objectContaining({ + detail: mediaLoadedInfo, + }), + ); + }); + + it('should unselect', () => { + const children = createChildren(); + const host = createSlotHost({ children: children }); + const controller = createController(host); + + const unselectedHandler = vi.fn(); + const unloadMediaHandler = vi.fn(); + host.addEventListener('frigate-card:media-grid:unselected', unselectedHandler); + host.addEventListener('frigate-card:media:unloaded', unloadMediaHandler); + + controller.selectCell('0'); + expect(controller.getSelected()).toBe('0'); + + // Unselect all elements. + controller.unselectAll(); + + // Expect selected to now be null. + expect(controller.getSelected()).toBeNull(); + + // Expect styles to have been updated. + for (const child of children) { + expect(child.getAttribute('selected')).toBeNull(); + expect(child.getAttribute('unselected')).toEqual(''); + } + + // Expect handlers to have been called. + expect(unselectedHandler).toBeCalled(); + expect(unloadMediaHandler).toBeCalled(); + }); + + it('should select in constructor', () => { + const children = createChildren(); + const host = createSlotHost({ children: children }); + const controller = createController(host, { selected: '2' }); + expect(controller.getSelected()).toBe('2'); + }); + + it('should respect grid attribute option', () => { + const children = createChildren(['one', 'two', 'three'], 'test-id'); + const host = createSlotHost({ children: children }); + const controller = createController(host, { idAttribute: 'test-id' }); + expect(controller.getGridContents()).toEqual( + new Map([ + ['one', children[0]], + ['two', children[1]], + ['three', children[2]], + ]), + ); + }); + + it('should destroy', () => { + const children = createChildren(); + const host = createSlotHost({ children: children }); + const controller = createController(host); + expect(controller.getGridSize()).toBe(3); + controller.destroy(); + expect(controller.getGridSize()).toBe(0); + }); + + it('should replace children when they change', () => { + const children = createChildren(); + const host = createHost({ children: children }); + const controller = createController(host, { selected: '1' }); + dispatchExistingMediaLoadedInfoAsEvent(children[0], mediaLoadedInfo); + + expect(controller.getSelected()).toBe('1'); + expect(controller.getGridSize()).toBe(3); + + children.forEach((child) => host.removeChild(child)); + const newChildren = createChildren(['one', 'two', 'three']); + newChildren.forEach((child) => host.appendChild(child)); + + triggerMutationObserver(); + + expect(controller.getGridContents()).toEqual( + new Map([ + ['one', newChildren[0]], + ['two', newChildren[1]], + ['three', newChildren[2]], + ]), + ); + expect(controller.getSelected()).toBeNull(); + }); + + it('should construct masonry correctly', () => { + const children = createChildren(); + const host = createHost({ children: children }); + createController(host); + expect(Masonry).toBeCalledWith( + host, + expect.objectContaining({ + initLayout: false, + percentPosition: true, + transitionDuration: '0.3s', + }), + ); + }); + + it('should set default column size correctly', () => { + const host = createHost({ children: createChildren() }); + createController(host); + expect(Masonry).toBeCalledWith( + host, + expect.objectContaining({ + columnWidth: 246, + }), + ); + expect(host.style.getPropertyValue('--frigate-card-grid-column-size')).toBe('246px'); + }); + + it('should respect exact columns', () => { + const host = createHost({ children: createChildren(), width: 2000 }); + const controller = createController(host); + controller.setDisplayConfig({ mode: 'grid', grid_columns: 2 }); + + // Will have been called once on construction, and then again when the + // number of columns changes. + expect(Masonry).toBeCalledTimes(2); + expect(Masonry).toBeCalledWith( + host, + expect.objectContaining({ + columnWidth: 1000, + }), + ); + expect(host.style.getPropertyValue('--frigate-card-grid-column-size')).toBe( + '1000px', + ); + }); + + it('should respect selected width factor', () => { + const host = createHost({ children: createChildren(), width: 2000 }); + const controller = createController(host); + controller.setDisplayConfig({ mode: 'grid', grid_selected_width_factor: 3 }); + expect( + host.style.getPropertyValue('--frigate-card-grid-selected-width-factor'), + ).toBe('3'); + }); + + it('should select cell with interacted with', () => { + const children = createChildren(); + const host = createHost({ children: children, width: 2000 }); + const controller = createController(host); + + expect(controller.getSelected()).toBeNull(); + + const touchEvent = new TouchEvent('touchend'); + children[1].dispatchEvent(touchEvent); + + expect(controller.getSelected()).toBe('1'); + }); + + it('should re-layout when child size changes', () => { + createController(createHost({ children: createChildren() })); + + vi.mocked(masonry.layout)?.mockClear(); + triggerResizeObserver('cell'); + expect(masonry.layout).toBeCalled(); + }); + + it('should re-create masonry when host size changes', () => { + const children = createChildren(); + const host = createHost({ children: children }); + const controller = createController(host); + expect(Masonry).toBeCalledWith( + host, + expect.objectContaining({ + columnWidth: 246, + }), + ); + expect(host.style.getPropertyValue('--frigate-card-grid-column-size')).toBe('246px'); + + // Clear mock state. + vi.mocked(Masonry).mockClear(); + vi.mocked(masonry.layout)?.mockClear(); + + // Resize the host. + setElementWidth(host, 2000); + triggerResizeObserver('host'); + + // Masonry should be reconstructed, styles set and layout called. + expect(Masonry).toBeCalledWith( + host, + expect.objectContaining({ + columnWidth: 667, + }), + ); + expect(host.style.getPropertyValue('--frigate-card-grid-column-size')).toBe('667px'); + expect(masonry.layout).toBeCalled(); + }); +}); diff --git a/tests/utils/media-to-view.test.ts b/tests/utils/media-to-view.test.ts new file mode 100644 index 00000000..5b108127 --- /dev/null +++ b/tests/utils/media-to-view.test.ts @@ -0,0 +1,452 @@ +import add from 'date-fns/add'; +import sub from 'date-fns/sub'; +import { beforeEach, describe, expect, it, Mock, vi } from 'vitest'; +import { + CameraConfigs, + PartialRecordingQuery, + QueryType, +} from '../../src/camera-manager/types'; +import { setify } from '../../src/utils/basic'; +import { + changeViewToRecentEventsForCameraAndDependents, + changeViewToRecentRecordingForCameraAndDependents, + createQueriesForRecordingsView, + executeMediaQueryForView, + findBestMediaIndex, +} from '../../src/utils/media-to-view'; +import { ViewMedia } from '../../src/view/media'; +import { EventMediaQueries } from '../../src/view/media-queries'; +import { + createCameraManager, + createHASS, + createPerformanceConfig, + createView, + TestViewMedia, +} from '../test-utils'; + +vi.mock('../../src/camera-manager/manager.js'); + +const createElementListenForView = (): { + element: HTMLElement; + viewHandler: Mock; + messageHandler: Mock; +} => { + const element = document.createElement('div'); + + const viewHandler = vi.fn(); + element.addEventListener('frigate-card:view:change', viewHandler); + + const messageHandler = vi.fn(); + element.addEventListener('frigate-card:message', messageHandler); + + return { + element: element, + viewHandler: viewHandler, + messageHandler: messageHandler, + }; +}; + +const getMediaFromHandlerCall = (handler: Mock): ViewMedia[] | null => { + return handler.mock.calls[0][0].detail.queryResults.getResults(); +}; + +const generateViewMedia = ( + index: number, + base: Date, + durationSeconds: number, +): ViewMedia => { + return new TestViewMedia({ + id: `id-${index}`, + startTime: base, + endTime: add(base, { seconds: durationSeconds }), + }); +}; + +// @vitest-environment jsdom +describe('changeViewToRecentEventsForCameraAndDependents', () => { + beforeEach(() => { + vi.resetAllMocks(); + }); + + it('should do nothing without camera config for selected camera', async () => { + const elementHandler = createElementListenForView(); + const cameraManager = createCameraManager({ configs: new Map() }); + + await changeViewToRecentEventsForCameraAndDependents( + elementHandler.element, + createHASS(), + cameraManager, + {}, + createView(), + ); + expect(elementHandler.viewHandler).not.toBeCalled(); + }); + + it('should do nothing without camera configs for all cameras', async () => { + const elementHandler = createElementListenForView(); + const cameraManager = createCameraManager({ configs: new Map() }); + + await changeViewToRecentEventsForCameraAndDependents( + elementHandler.element, + createHASS(), + cameraManager, + {}, + createView(), + { + allCameras: true, + }, + ); + expect(elementHandler.viewHandler).not.toBeCalled(); + }); + + it('should do nothing unless queries can be created', async () => { + const elementHandler = createElementListenForView(); + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue(null); + + await changeViewToRecentEventsForCameraAndDependents( + elementHandler.element, + createHASS(), + cameraManager, + {}, + createView(), + { + mediaType: 'clips', + }, + ); + expect(elementHandler.viewHandler).not.toBeCalled(); + }); + + it('should dispatch new view on success', async () => { + const elementHandler = createElementListenForView(); + const cameraManager = createCameraManager(); + + const mediaArray = [new ViewMedia('clip', 'camera')]; + vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(mediaArray); + + await changeViewToRecentEventsForCameraAndDependents( + elementHandler.element, + createHASS(), + cameraManager, + {}, + createView(), + { + targetView: 'clips', + select: 'latest', + }, + ); + expect(elementHandler.viewHandler).toBeCalled(); + expect(getMediaFromHandlerCall(elementHandler.viewHandler)).toBe(mediaArray); + }); + + it('should dispatch error message on fail', async () => { + vi.spyOn(global.console, 'warn').mockImplementation(() => true); + + const elementHandler = createElementListenForView(); + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.executeMediaQueries).mockRejectedValue(new Error()); + + await changeViewToRecentEventsForCameraAndDependents( + elementHandler.element, + createHASS(), + cameraManager, + {}, + createView(), + ); + expect(elementHandler.viewHandler).not.toBeCalled(); + expect(elementHandler.messageHandler).toBeCalled(); + }); + + it('should respect media chunk size', async () => { + const cameraManager = createCameraManager(); + + await changeViewToRecentEventsForCameraAndDependents( + createElementListenForView().element, + createHASS(), + cameraManager, + { + performance: createPerformanceConfig({ + features: { + media_chunk_size: 1000, + }, + }), + }, + createView(), + ); + + expect(cameraManager.generateDefaultEventQueries).toBeCalledWith( + expect.anything(), + expect.objectContaining({ + limit: 1000, + }), + ); + }); + + describe('should respect request for media type', () => { + it.each([ + ['snapshots' as const, 'hasSnapshot'], + ['clips' as const, 'hasClip'], + ])('%s', async (mediaType, queryParameter) => { + const cameraManager = createCameraManager(); + + await changeViewToRecentEventsForCameraAndDependents( + createElementListenForView().element, + createHASS(), + cameraManager, + {}, + createView(), + { + mediaType: mediaType, + }, + ); + + expect(cameraManager.generateDefaultEventQueries).toBeCalledWith( + expect.anything(), + expect.objectContaining({ + [queryParameter]: true, + }), + ); + }); + }); +}); + +// @vitest-environment jsdom +describe('executeMediaQueryForView', () => { + beforeEach(() => { + vi.resetAllMocks(); + }); + + it('should not execute empty queries', async () => { + const elementHandler = createElementListenForView(); + const cameraConfigs: CameraConfigs = new Map(); + const cameraManager = createCameraManager({ configs: cameraConfigs }); + + expect( + await executeMediaQueryForView( + elementHandler.element, + createHASS(), + cameraManager, + createView(), + new EventMediaQueries(), + ), + ).toBeNull(); + }); + + it('should select time-based result', async () => { + const elementHandler = createElementListenForView(); + const cameraConfigs: CameraConfigs = new Map(); + const cameraManager = createCameraManager({ configs: cameraConfigs }); + + const now = new Date(); + const mediaArray = [ + generateViewMedia(0, now, 60), + generateViewMedia(1, now, 120), + generateViewMedia(2, now, 10), + ]; + vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(mediaArray); + + const view = await executeMediaQueryForView( + elementHandler.element, + createHASS(), + cameraManager, + createView(), + new EventMediaQueries( + cameraManager.generateDefaultEventQueries('camera') ?? undefined, + ), + { + select: 'time', + targetTime: add(now, { seconds: 30 }), + }, + ); + + // Should select the longest event. + expect(view?.queryResults?.getSelectedIndex()).toBe(1); + expect(view?.queryResults?.getResults()).toBe(mediaArray); + }); + + it('should select nothing when time-based selection does not match', async () => { + const elementHandler = createElementListenForView(); + const cameraConfigs: CameraConfigs = new Map(); + const cameraManager = createCameraManager({ configs: cameraConfigs }); + + const now = new Date(); + const mediaArray = [ + generateViewMedia(0, now, 60), + generateViewMedia(1, now, 120), + generateViewMedia(2, now, 10), + ]; + + vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(mediaArray); + + const view = await executeMediaQueryForView( + elementHandler.element, + createHASS(), + cameraManager, + createView(), + new EventMediaQueries( + cameraManager.generateDefaultEventQueries('camera') ?? undefined, + ), + { + select: 'time', + targetTime: sub(now, { seconds: 30 }), + }, + ); + + // Should leave selection untouched (last item will remain selected). + expect(view?.queryResults?.getSelectedIndex()).toBe(2); + expect(view?.queryResults?.getResults()).toBe(mediaArray); + }); +}); + +// @vitest-environment jsdom +describe('changeViewToRecentRecordingForCameraAndDependents', () => { + beforeEach(() => { + vi.resetAllMocks(); + }); + + it('should do nothing without camera config for selected camera', async () => { + const elementHandler = createElementListenForView(); + const cameraManager = createCameraManager({ configs: new Map() }); + + await changeViewToRecentRecordingForCameraAndDependents( + elementHandler.element, + createHASS(), + cameraManager, + {}, + createView(), + ); + expect(elementHandler.viewHandler).not.toBeCalled(); + }); + + it('should do nothing without camera configs for all cameras', async () => { + const elementHandler = createElementListenForView(); + const cameraManager = createCameraManager({ configs: new Map() }); + + await changeViewToRecentRecordingForCameraAndDependents( + elementHandler.element, + createHASS(), + cameraManager, + {}, + createView(), + { + allCameras: true, + }, + ); + expect(elementHandler.viewHandler).not.toBeCalled(); + }); + + it('should do nothing unless queries can be created', async () => { + const elementHandler = createElementListenForView(); + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.generateDefaultRecordingQueries).mockReturnValue(null); + + await changeViewToRecentRecordingForCameraAndDependents( + elementHandler.element, + createHASS(), + cameraManager, + {}, + createView(), + ); + expect(elementHandler.viewHandler).not.toBeCalled(); + }); + + it('should dispatch new view on success', async () => { + const elementHandler = createElementListenForView(); + const cameraManager = createCameraManager(); + + const mediaArray = [new ViewMedia('recording', 'camera')]; + vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(mediaArray); + + await changeViewToRecentRecordingForCameraAndDependents( + elementHandler.element, + createHASS(), + cameraManager, + {}, + createView(), + { + targetView: 'recordings', + select: 'latest', + }, + ); + expect(elementHandler.viewHandler).toBeCalled(); + expect(getMediaFromHandlerCall(elementHandler.viewHandler)).toBe(mediaArray); + }); + + it('should respect media chunk size', async () => { + const cameraManager = createCameraManager(); + + await changeViewToRecentRecordingForCameraAndDependents( + createElementListenForView().element, + createHASS(), + cameraManager, + { + performance: createPerformanceConfig({ + features: { + media_chunk_size: 1000, + }, + }), + }, + createView(), + ); + + expect(cameraManager.generateDefaultRecordingQueries).toBeCalledWith( + expect.anything(), + expect.objectContaining({ + limit: 1000, + }), + ); + }); +}); + +// @vitest-environment jsdom +describe('createQueriesForRecordingsView', () => { + it('should respect start and end date in recording query', async () => { + const cameraManager = createCameraManager({ configs: new Map() }); + + vi.mocked(cameraManager.generateDefaultRecordingQueries).mockImplementation( + (cameraIDs: string | Set, partialQuery?: PartialRecordingQuery) => [ + { + cameraIDs: setify(cameraIDs), + type: QueryType.Recording, + ...partialQuery, + }, + ], + ); + + const start = new Date('2023-04-29T14:00:00'); + const end = new Date('2023-04-29T14:59:59'); + + const queries = createQueriesForRecordingsView( + cameraManager, + {}, + new Set(['camera']), + { + start: start, + end: end, + }, + ); + + expect(queries?.getQueries()).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + start: start, + end: end, + }), + ]), + ); + }); +}); + +// @vitest-environment jsdom +describe('findBestMediaIndex', () => { + it('should find best media index', async () => { + const now = new Date(); + const mediaArray = [ + generateViewMedia(0, now, 60), + generateViewMedia(1, now, 120), + generateViewMedia(2, now, 10), + ]; + + expect(findBestMediaIndex(mediaArray, add(now, { seconds: 30 }))).toBe(1); + }); +}); diff --git a/tests/utils/media.test.ts b/tests/utils/media.test.ts index 3a9d6cd3..5e4aefc9 100644 --- a/tests/utils/media.test.ts +++ b/tests/utils/media.test.ts @@ -3,6 +3,7 @@ import { mock } from 'vitest-mock-extended'; import { FrigateCardMediaPlayer } from '../../src/types.js'; import { FrigateCardHTMLVideoElement, + MEDIA_LOAD_CONTROLS_HIDE_SECONDS, hideMediaControlsTemporarily, playMediaMutingIfNecessary, setControlsOnVideo, @@ -108,3 +109,9 @@ describe('playMediaMutingIfNecessary', () => { expect(player.mute).toBeCalled(); }); }); + +describe('constants', () => { + it('MEDIA_LOAD_CONTROLS_HIDE_SECONDS', () => { + expect(MEDIA_LOAD_CONTROLS_HIDE_SECONDS).toBe(2); + }); +}); diff --git a/tests/utils/menu-controller.test.ts b/tests/utils/menu-controller.test.ts index ffff040a..36adc42b 100644 --- a/tests/utils/menu-controller.test.ts +++ b/tests/utils/menu-controller.test.ts @@ -9,6 +9,7 @@ import { FrigateCardMediaPlayer, MediaLoadedInfo, MenuButton, + ViewDisplayMode, } from '../../src/types'; import { createFrigateCardCustomAction } from '../../src/utils/action'; import { MenuButtonController } from '../../src/utils/menu-controller'; @@ -67,6 +68,7 @@ const calculateButtons = ( ); }; +// @vitest-environment jsdom describe('MenuButtonController', () => { let controller: MenuButtonController; const dynamicButton: MenuButton = { @@ -612,7 +614,10 @@ describe('MenuButtonController', () => { const cameraManager = createCameraManager(); const view = createView({ - queryResults: new MediaQueriesResults([new ViewMedia('clip', 'camera-1')], 0), + queryResults: new MediaQueriesResults({ + results: [new ViewMedia('clip', 'camera-1')], + selectedIndex: 0, + }), }); mock(cameraManager).getMediaCapabilities.mockReturnValue( createMediaCapabilities({ canDownload: true }), @@ -640,7 +645,10 @@ describe('MenuButtonController', () => { const cameraManager = createCameraManager(); const view = createView({ - queryResults: new MediaQueriesResults([new ViewMedia('clip', 'camera-1')], 0), + queryResults: new MediaQueriesResults({ + results: [new ViewMedia('clip', 'camera-1')], + selectedIndex: 0, + }), }); mock(cameraManager).getMediaCapabilities.mockReturnValue( createMediaCapabilities({ canDownload: true }), @@ -1084,6 +1092,27 @@ describe('MenuButtonController', () => { }); }); + describe('should have grid button when display mode is', () => { + it.each([['single' as const], ['grid' as const]])( + '%s', + (displayMode: ViewDisplayMode) => { + const view = createView({ view: 'live', displayMode: displayMode }); + expect(calculateButtons(controller, { view: view })).toContainEqual({ + icon: displayMode === 'single' ? 'mdi:grid' : 'mdi:grid-off', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Display mode', + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'display_mode_select', + display_mode: displayMode === 'single' ? 'grid' : 'single', + }, + }); + }, + ); + }); + it('should handle dynamic buttons', () => { const button: MenuButton = { ...dynamicButton, diff --git a/tests/utils/screenshot.test.ts b/tests/utils/screenshot.test.ts index f6fcdd37..89241a99 100644 --- a/tests/utils/screenshot.test.ts +++ b/tests/utils/screenshot.test.ts @@ -62,32 +62,30 @@ describe('generateScreenshotTitle', () => { }); it('should get title for media viewer view with id', () => { - const media = new TestViewMedia( - 'id1', - new Date('2023-06-16T18:52'), - 'clip', - 'camera-1', - ); + const media = new TestViewMedia({ + id: 'id1', + startTime: new Date('2023-06-16T18:52'), + cameraID: 'camera-1', + }); const view = createView({ view: 'media', camera: 'camera-1', - queryResults: new MediaQueriesResults([media], 0), + queryResults: new MediaQueriesResults({ results: [media], selectedIndex: 0 }), }); expect(generateScreenshotTitle(view)).toBe('media-camera-1-id1.jpg'); }); it('should get title for media viewer view without id', () => { - const media = new TestViewMedia( - null, - new Date('2023-06-16T18:52'), - 'clip', - 'camera-1', - ); + const media = new TestViewMedia({ + id: null, + startTime: new Date('2023-06-16T18:52'), + cameraID: 'camera-1', + }); const view = createView({ view: 'media', camera: 'camera-1', - queryResults: new MediaQueriesResults([media], 0), + queryResults: new MediaQueriesResults({ results: [media], selectedIndex: 0 }), }); expect(generateScreenshotTitle(view)).toBe('media-camera-1.jpg'); diff --git a/tests/view/media-classifier.test.ts b/tests/view/media-classifier.test.ts new file mode 100644 index 00000000..af7d2e7f --- /dev/null +++ b/tests/view/media-classifier.test.ts @@ -0,0 +1,66 @@ +import { describe, expect, it } from 'vitest'; +import { ViewMediaType } from '../../src/view/media'; +import { ViewMediaClassifier } from '../../src/view/media-classifier'; +import { TestViewMedia } from '../test-utils'; + +describe('ViewMediaClassifier', () => { + describe('isEvent', () => { + it.each([ + ['clip' as const, true], + ['snapshot' as const, true], + ['recording' as const, false], + ])('%s', (mediaType: ViewMediaType, expectedResult: boolean) => { + expect( + ViewMediaClassifier.isEvent(new TestViewMedia({ mediaType: mediaType })), + ).toBe(expectedResult); + }); + }); + + describe('isRecording', () => { + it.each([ + ['clip' as const, false], + ['snapshot' as const, false], + ['recording' as const, true], + ])('%s', (mediaType: ViewMediaType, expectedResult: boolean) => { + expect( + ViewMediaClassifier.isRecording(new TestViewMedia({ mediaType: mediaType })), + ).toBe(expectedResult); + }); + }); + + describe('isClip', () => { + it.each([ + ['clip' as const, true], + ['snapshot' as const, false], + ['recording' as const, false], + ])('%s', (mediaType: ViewMediaType, expectedResult: boolean) => { + expect( + ViewMediaClassifier.isClip(new TestViewMedia({ mediaType: mediaType })), + ).toBe(expectedResult); + }); + }); + + describe('isSnapshot', () => { + it.each([ + ['clip' as const, false], + ['snapshot' as const, true], + ['recording' as const, false], + ])('%s', (mediaType: ViewMediaType, expectedResult: boolean) => { + expect( + ViewMediaClassifier.isSnapshot(new TestViewMedia({ mediaType: mediaType })), + ).toBe(expectedResult); + }); + }); + + describe('isVideo', () => { + it.each([ + ['clip' as const, true], + ['snapshot' as const, false], + ['recording' as const, true], + ])('%s', (mediaType: ViewMediaType, expectedResult: boolean) => { + expect( + ViewMediaClassifier.isVideo(new TestViewMedia({ mediaType: mediaType })), + ).toBe(expectedResult); + }); + }); +}); diff --git a/tests/view/media-queries-results.test.ts b/tests/view/media-queries-results.test.ts new file mode 100644 index 00000000..ce11c9e7 --- /dev/null +++ b/tests/view/media-queries-results.test.ts @@ -0,0 +1,233 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { ViewMedia } from '../../src/view/media'; +import { MediaQueriesResults } from '../../src/view/media-queries-results'; +import { generateViewMediaArray } from '../test-utils'; + +describe('dispatchViewContextChangeEvent', () => { + beforeEach(() => { + vi.useRealTimers(); + }); + + it('should function with empty results', () => { + const fakeNow = new Date('2023-08-07T20:44'); + vi.useFakeTimers(); + vi.setSystemTime(fakeNow); + + const results = new MediaQueriesResults(); + expect(results.isSupersetOf(results)).toBeFalsy(); + expect(results.getCameraIDs()).toEqual(new Set()); + expect(results.getResults()).toEqual([]); + expect(results.getResultsCount()).toEqual(0); + expect(results.hasResults()).toBeFalsy(); + expect(results.getResult(0)).toBeNull(); + expect(results.getSelectedIndex()).toBeNull(); + expect(results.getSelectedResult()).toBeNull(); + expect(results.hasSelectedResult()).toBeFalsy(); + + expect(results.resetSelectedResult()).toBe(results); + expect(results.getResultsTimestamp()).toEqual(fakeNow); + + expect(results.selectIndex(0)).toEqual(results); + expect(results.getSelectedResult()).toBeNull(); + + expect(results.selectResultIfFound((_media: ViewMedia) => true)).toEqual(results); + expect(results.getSelectedResult()).toBeNull(); + + expect(results.selectBestResult((_media: ViewMedia[]) => null)).toEqual(results); + expect(results.getSelectedResult()).toBeNull(); + }); + + it('should function with basic results', () => { + const testResults = generateViewMediaArray(); + const results = new MediaQueriesResults({ results: testResults }); + + expect(results.isSupersetOf(results)).toBeTruthy(); + expect(results.getCameraIDs()).toEqual(new Set(['kitchen', 'office'])); + expect(results.getResults()).toEqual(testResults); + expect(results.getResultsCount()).toEqual(200); + expect(results.hasResults()).toBeTruthy(); + expect(results.getResult(0)).not.toBeNull(); + expect(results.getSelectedIndex()).toBe(199); + expect(results.getSelectedResult()).not.toBeNull(); + expect(results.hasSelectedResult()).toBeTruthy(); + + expect(results.resetSelectedResult()).toBe(results); + expect(results.getSelectedResult()).toBeNull(); + + expect(results.selectIndex(100)).toEqual(results); + expect(results.getSelectedIndex()).toBe(100); + + expect( + results.selectResultIfFound( + (media: ViewMedia) => media.getID() === 'id-kitchen-42', + ), + ).toEqual(results); + expect(results.getSelectedResult()?.getID()).toBe('id-kitchen-42'); + + expect( + results.selectBestResult((mediaArray: ViewMedia[]) => + mediaArray.findIndex((media) => media.getID() === 'id-kitchen-43'), + ), + ).toEqual(results); + expect(results.getSelectedResult()?.getID()).toBe('id-kitchen-43'); + }); + + it('should function with camera slice', () => { + const testResults = generateViewMediaArray(); + const results = new MediaQueriesResults({ results: testResults }); + const slice = results.getSlice('office'); + expect(slice).not.toBeNull(); + expect(slice!.getResults()).toEqual( + testResults.filter((media) => media.getCameraID() === 'office'), + ); + expect(slice!.getResultsCount()).toEqual(100); + expect(slice!.hasResults()).toBeTruthy(); + expect(slice!.getResult(0)).not.toBeNull(); + expect(slice!.getResult()).toBeNull(); + expect(slice!.getSelectedIndex()).toBe(99); + expect(slice!.getSelectedResult()?.getID()).toEqual('id-office-99'); + expect(slice!.hasSelectedResult()).toBeTruthy(); + + expect(slice!.resetSelectedResult()); + expect(slice!.getSelectedResult()).toBeNull(); + + expect(slice!.selectIndex(10)); + expect(slice!.getSelectedIndex()).toBe(10); + + expect(slice!.selectIndex(10000)); + expect(slice!.getSelectedIndex()).toBe(10); + + expect(slice!.selectIndex(-10000)); + expect(slice!.getSelectedIndex()).toBe(10); + + slice!.selectResultIfFound((media: ViewMedia) => media.getID() === 'id-office-42'); + expect(slice!.getSelectedResult()?.getID()).toBe('id-office-42'); + + slice!.selectBestResult((mediaArray: ViewMedia[]) => + mediaArray.findIndex((media) => media.getID() === 'id-office-43'), + ); + expect(slice!.getSelectedResult()?.getID()).toBe('id-office-43'); + }); + + describe('should respect select approach during construction', () => { + it.each([ + ['first' as const, 0], + ['last' as const, 199], + ])('%s', async (selectApproach, expectedIndex) => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + selectApproach: selectApproach, + }); + expect(results.getSelectedIndex()).toBe(expectedIndex); + }); + }); + + it('should respect selectIndex during construction', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + selectedIndex: 42, + }); + expect(results.getSelectedIndex()).toBe(42); + }); + + it('should correctly clone a slice', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + }); + const slice = results.getSlice('office'); + const clone = slice?.clone(); + expect(clone?.getResults()).toBe(slice?.getResults()); + expect(clone?.getSelectedIndex()).toBe(slice?.getSelectedIndex()); + }); + + it('should not get slice for non-existent camera', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + }); + expect(results.getSlice('not-a-camera')).toBeNull(); + }); + + it('should get main slice', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + }); + expect(results.getSlice()?.getResults()).toBe(results.getResults()); + }); + + it('should correctly clone', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + }); + const clone = results.clone(); + expect(results.getResultsTimestamp()).toBe(clone.getResultsTimestamp()); + expect(results.getResults()).toBe(clone.getResults()); + for (const cameraID of results.getCameraIDs()) { + expect(results.getSlice(cameraID)?.getResults()).toBe( + clone.getSlice(cameraID)?.getResults(), + ); + } + }); + + it('should not getResults on invalid slice', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + }); + expect(results.getResults('not-a-camera')).toBeNull(); + expect(results.getResultsCount('not-a-camera')).toBe(0); + expect(results.hasSelectedResult('not-a-camera')).toBeFalsy(); + }); + + it('should always demote main selection', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + }); + + results + .getSlice('office') + ?.selectResultIfFound((media) => media.getID() === 'id-office-42'); + + // Verify main and office selections are as expected. + expect(results.getSelectedIndex()).toBe(199); + expect(results.getSelectedResult('office')?.getID()).toBe('id-office-42'); + + // Select a different main result... + results?.selectResultIfFound((media) => media.getID() === 'id-office-80'); + + // ... and ensure that selection has been demoted into the camera slice. + expect(results.getSelectedResult('office')?.getID()).toBe('id-office-80'); + }); + + it('should promote camera selection', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + }); + + results + .getSlice('office') + ?.selectResultIfFound((media) => media.getID() === 'id-office-42'); + + expect(results.getSelectedIndex()).toBe(199); + + results.promoteCameraSelectionToMainSelection('office'); + + expect(results.getSelectedIndex()).not.toBe(199); + expect(results.getSelectedResult()?.getID()).toBe('id-office-42'); + }); + + it('should selectBestResult via advanced selection criteria', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + }); + + results.selectBestResult( + (mediaArray: ViewMedia[]) => { + const index = mediaArray.findIndex((media) => media.getID()?.endsWith('-42')); + return index < 0 ? null : index; + }, + { allCameras: true }, + ); + + expect(results.getSelectedResult('office')?.getID()).toBe('id-office-42'); + expect(results.getSelectedResult('kitchen')?.getID()).toBe('id-kitchen-42'); + }); +}); diff --git a/tests/view/media-queries.test.ts b/tests/view/media-queries.test.ts new file mode 100644 index 00000000..9ac570f5 --- /dev/null +++ b/tests/view/media-queries.test.ts @@ -0,0 +1,102 @@ +import { describe, expect, it } from 'vitest'; +import { + EventQuery, + PartialEventQuery, + PartialRecordingQuery, + QueryType, + RecordingQuery, +} from '../../src/camera-manager/types'; +import { setify } from '../../src/utils/basic'; +import { EventMediaQueries, RecordingMediaQueries } from '../../src/view/media-queries'; + +describe('EventMediaQueries', () => { + const createRawEventQueries = ( + cameraIDs: string | Set, + query?: PartialEventQuery, + ): EventQuery[] => { + return [ + { + type: QueryType.Event, + cameraIDs: setify(cameraIDs), + ...query, + }, + ]; + }; + + it('should construct', () => { + const rawQueries = createRawEventQueries('office'); + const queries = new EventMediaQueries(rawQueries); + expect(queries.getQueries()).toBe(rawQueries); + }); + + it('should set', () => { + const rawQueries = createRawEventQueries('office'); + const queries = new EventMediaQueries(rawQueries); + + const newRawQueries = createRawEventQueries('kitchen'); + queries.setQueries(newRawQueries); + expect(queries.getQueries()).toBe(newRawQueries); + }); + + it('should determine if queries exist for CameraIDs', () => { + const rawQueries = createRawEventQueries(new Set(['office', 'kitchen'])); + const queries = new EventMediaQueries(rawQueries); + + expect(queries.hasQueriesForCameraIDs(new Set(['office']))).toBeTruthy(); + expect(queries.hasQueriesForCameraIDs(new Set(['office', 'kitchen']))).toBeTruthy(); + expect( + queries.hasQueriesForCameraIDs(new Set(['office', 'front_door'])), + ).toBeFalsy(); + }); + + it('should convert to clips querys', () => { + const rawQueries = createRawEventQueries('office', { hasSnapshot: true }); + const queries = new EventMediaQueries(rawQueries); + + expect(queries.convertToClipsQueries().getQueries()).toEqual([ + { + type: QueryType.Event, + cameraIDs: new Set(['office']), + hasClip: true, + }, + ]); + }); + + it('should convert when queries are null', () => { + const queries = new EventMediaQueries(); + expect(queries.convertToClipsQueries().getQueries()).toBeNull(); + }); + + it('should clone', () => { + const rawQueries = createRawEventQueries('office', { hasSnapshot: true }); + const queries = new EventMediaQueries(rawQueries); + expect(queries.clone().getQueries()).toEqual(queries.getQueries()); + }); +}); + +describe('RecordingMediaQueries', () => { + const createRawRecordingQueries = ( + cameraIDs: string | Set, + query?: PartialRecordingQuery, + ): RecordingQuery[] => { + return [ + { + type: QueryType.Recording, + cameraIDs: setify(cameraIDs), + ...query, + }, + ]; + }; + + it('should construct', () => { + const rawQueries = createRawRecordingQueries('office'); + const queries = new RecordingMediaQueries(rawQueries); + expect(queries.getQueries()).toBe(rawQueries); + }); + + it('should clone', () => { + const rawQueries = createRawRecordingQueries('office'); + const queries = new RecordingMediaQueries(rawQueries); + expect(queries.clone().getQueries()).toEqual(queries.getQueries()); + }); +}); diff --git a/tests/view/media.test.ts b/tests/view/media.test.ts new file mode 100644 index 00000000..7aaa8131 --- /dev/null +++ b/tests/view/media.test.ts @@ -0,0 +1,60 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { VideoContentType, ViewMedia } from '../../src/view/media'; +import { TestViewMedia } from '../test-utils'; + +describe('ViewMedia', () => { + beforeEach(() => { + vi.useRealTimers(); + }); + + it('should construct', () => { + const media = new ViewMedia('clip', 'camera'); + expect(media.getCameraID()).toBe('camera'); + expect(media.getMediaType()).toBe('clip'); + expect(media.getVideoContentType()).toBeNull(); + expect(media.getID()).toBeNull(); + expect(media.getStartTime()).toBeNull(); + expect(media.getEndTime()).toBeNull(); + expect(media.getUsableEndTime()).toBeNull(); + expect(media.inProgress()).toBeNull(); + expect(media.getContentID()).toBeNull(); + expect(media.getTitle()).toBeNull(); + expect(media.getThumbnail()).toBeNull(); + expect(media.getTitle()).toBeNull(); + expect(media.includesTime(new Date())).toBeFalsy(); + expect(media.getWhere()).toBeNull(); + expect(media.setFavorite(true)).toBeUndefined(); + expect(media.isFavorite()).toBeNull(); + }); + + it('should correctly determine if a media item includes a time', () => { + const media = new TestViewMedia({ + startTime: new Date('2023-08-08T17:00:00'), + endTime: new Date('2023-08-08T17:59:59'), + }); + expect(media.includesTime(new Date('2023-08-08T17:30:30'))).toBeTruthy(); + expect(media.includesTime(new Date('2023-08-08T18:00:00'))).toBeFalsy(); + }); + + it('should correctly get usable end time for in-progress event', () => { + const media = new TestViewMedia({ + startTime: new Date('2023-08-08T17:00:00'), + inProgress: true, + }); + + vi.useFakeTimers(); + const fakeNow = new Date('2023-08-08T17:15:00'); + vi.setSystemTime(fakeNow); + + expect(media.getUsableEndTime()).toEqual(fakeNow) + }); +}); + +describe('VideoContentType', () => { + it('MP4', () => { + expect(VideoContentType.MP4).toBe('mp4'); + }); + it('HLS', () => { + expect(VideoContentType.HLS).toBe('hls'); + }); +}); diff --git a/tests/view/view.test.ts b/tests/view/view.test.ts index 1d97f060..de6a1912 100644 --- a/tests/view/view.test.ts +++ b/tests/view/view.test.ts @@ -1,10 +1,10 @@ -import { describe, expect, it, test, vi } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { QueryType } from '../../src/camera-manager/types'; import { ViewMedia } from '../../src/view/media'; import { EventMediaQueries, RecordingMediaQueries } from '../../src/view/media-queries'; import { MediaQueriesResults } from '../../src/view/media-queries-results'; import { View, dispatchViewContextChangeEvent } from '../../src/view/view'; -import { createView } from '../test-utils'; +import { createView, generateViewMediaArray } from '../test-utils'; // @vitest-environment jsdom describe('View Basics', () => { @@ -52,6 +52,7 @@ describe('View Basics', () => { query: new EventMediaQueries(), queryResults: new MediaQueriesResults(), context: {}, + displayMode: 'single', }); const evolved = view.evolve({ @@ -60,12 +61,14 @@ describe('View Basics', () => { query: new EventMediaQueries(), queryResults: new MediaQueriesResults(), context: {}, + displayMode: 'grid', }); expect(evolved.view).not.toBe(view.view); expect(evolved.camera).not.toBe(view.camera); expect(evolved.query).not.toBe(view.query); expect(evolved.queryResults).not.toBe(view.queryResults); expect(evolved.context).not.toBe(view.context); + expect(evolved.displayMode).not.toBe(view.displayMode); }); it('should evolve with nothing set', () => { @@ -119,6 +122,13 @@ describe('View Basics', () => { expect(view.context).toEqual({}); }); + it('should remove context property', () => { + const view = createView({ context: { live: { overrides: new Map() } } }); + + view.removeContextProperty('live', 'overrides'); + expect(view.context).toEqual({ live: {} }); + }); + it('should detect gallery views', () => { expect(createView({ view: 'clips' }).isGalleryView()).toBeTruthy(); expect(createView({ view: 'snapshots' }).isGalleryView()).toBeTruthy(); @@ -240,8 +250,8 @@ describe('View.isMajorMediaChange', () => { it('should consider result change as major in other view', () => { const media = [new ViewMedia('clip', 'camera-1'), new ViewMedia('clip', 'camera-2')]; - const queryResults_1 = new MediaQueriesResults(media, 0); - const queryResults_2 = new MediaQueriesResults(media, 1); + const queryResults_1 = new MediaQueriesResults({ results: media, selectedIndex: 0 }); + const queryResults_2 = new MediaQueriesResults({ results: media, selectedIndex: 1 }); expect( View.isMajorMediaChange( createView({ view: 'media', queryResults: queryResults_1 }), @@ -252,8 +262,8 @@ describe('View.isMajorMediaChange', () => { it('should not consider selected result change as major in live view', () => { const media = [new ViewMedia('clip', 'camera-1'), new ViewMedia('clip', 'camera-2')]; - const queryResults_1 = new MediaQueriesResults(media, 0); - const queryResults_2 = new MediaQueriesResults(media, 1); + const queryResults_1 = new MediaQueriesResults({ results: media, selectedIndex: 0 }); + const queryResults_2 = new MediaQueriesResults({ results: media, selectedIndex: 1 }); expect( View.isMajorMediaChange( createView({ queryResults: queryResults_1 }), @@ -282,7 +292,7 @@ describe('View.adoptFromViewIfAppropriate', () => { expect(next.queryResults).toBe(queryResults); }); - test.each([ + it.each([ [ new EventMediaQueries([ { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, @@ -409,6 +419,76 @@ describe('View.adoptFromViewIfAppropriate', () => { View.adoptFromViewIfAppropriate(next, current); expect(next.context?.live).toEqual(current.context?.live); }); + + it('should determine if display mode is grid', () => { + expect(createView({ displayMode: 'grid' }).isGrid()).toBeTruthy(); + expect(createView({ displayMode: 'single' }).isGrid()).toBeFalsy(); + expect(createView().isGrid()).toBeFalsy(); + }); + + it('should determine if view supports multiple display modes', () => { + const resultsOne = new MediaQueriesResults({ + results: generateViewMediaArray({ cameraIDs: ['office'] }), + }); + const resultsTwo = new MediaQueriesResults({ + results: generateViewMediaArray({ cameraIDs: ['office', 'kitchen'] }), + }); + + expect(createView({ view: 'live' }).hasMultipleDisplayModes()).toBeFalsy(); + expect(createView({ view: 'live' }).hasMultipleDisplayModes(0)).toBeFalsy(); + expect(createView({ view: 'live' }).hasMultipleDisplayModes(1)).toBeFalsy(); + expect(createView({ view: 'live' }).hasMultipleDisplayModes(2)).toBeTruthy(); + + expect(createView({ view: 'media' }).hasMultipleDisplayModes()).toBeFalsy(); + expect( + createView({ view: 'media', queryResults: resultsOne }).hasMultipleDisplayModes(), + ).toBeFalsy(); + expect( + createView({ view: 'media', queryResults: resultsTwo }).hasMultipleDisplayModes(), + ).toBeTruthy(); + + expect(createView({ view: 'clip' }).hasMultipleDisplayModes()).toBeFalsy(); + expect( + createView({ view: 'clip', queryResults: resultsOne }).hasMultipleDisplayModes(), + ).toBeFalsy(); + expect( + createView({ view: 'clip', queryResults: resultsTwo }).hasMultipleDisplayModes(), + ).toBeTruthy(); + + expect(createView({ view: 'snapshot' }).hasMultipleDisplayModes()).toBeFalsy(); + expect( + createView({ + view: 'snapshot', + queryResults: resultsOne, + }).hasMultipleDisplayModes(), + ).toBeFalsy(); + expect( + createView({ + view: 'snapshot', + queryResults: resultsTwo, + }).hasMultipleDisplayModes(), + ).toBeTruthy(); + + expect(createView({ view: 'recording' }).hasMultipleDisplayModes()).toBeFalsy(); + expect( + createView({ + view: 'recording', + queryResults: resultsOne, + }).hasMultipleDisplayModes(), + ).toBeFalsy(); + expect( + createView({ + view: 'recording', + queryResults: resultsTwo, + }).hasMultipleDisplayModes(), + ).toBeTruthy(); + + expect(createView({ view: 'clips' }).hasMultipleDisplayModes()).toBeFalsy(); + expect(createView({ view: 'snapshots' }).hasMultipleDisplayModes()).toBeFalsy(); + expect(createView({ view: 'recordings' }).hasMultipleDisplayModes()).toBeFalsy(); + expect(createView({ view: 'image' }).hasMultipleDisplayModes()).toBeFalsy(); + expect(createView({ view: 'timeline' }).hasMultipleDisplayModes()).toBeFalsy(); + }); }); // @vitest-environment jsdom diff --git a/yarn.lock b/yarn.lock index 8cf2f48d..7bc02b0e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1052,6 +1052,15 @@ __metadata: languageName: node linkType: hard +"@types/jquery@npm:*": + version: 3.5.16 + resolution: "@types/jquery@npm:3.5.16" + dependencies: + "@types/sizzle": "*" + checksum: 13c995f15d1c2f1d322103dc1cb0a22b95eecc3e7546f00279b8731aea21d7ec04550af40e609ee48e755d4e11bf61c25b4aa9f53df3bcbec4b8fe8e81471732 + languageName: node + linkType: hard + "@types/json-schema@npm:^7.0.9": version: 7.0.11 resolution: "@types/json-schema@npm:7.0.11" @@ -1082,6 +1091,15 @@ __metadata: languageName: node linkType: hard +"@types/masonry-layout@npm:^4.2.5": + version: 4.2.5 + resolution: "@types/masonry-layout@npm:4.2.5" + dependencies: + "@types/jquery": "*" + checksum: 68961e4dd393a8d51e6e80676a814a6741c0c9175501a1a556ec6d4ef5438aa1e982248a90c7f00099fb18da9529e9f6733be5ffebdb9b2e95cd36a6adeecb40 + languageName: node + linkType: hard + "@types/node@npm:*": version: 18.11.19 resolution: "@types/node@npm:18.11.19" @@ -1112,6 +1130,13 @@ __metadata: languageName: node linkType: hard +"@types/sizzle@npm:*": + version: 2.3.3 + resolution: "@types/sizzle@npm:2.3.3" + checksum: 586a9fb1f6ff3e325e0f2cc1596a460615f0bc8a28f6e276ac9b509401039dd242fa8b34496d3a30c52f5b495873922d09a9e76c50c2ab2bcc70ba3fb9c4e160 + languageName: node + linkType: hard + "@types/trusted-types@npm:^2.0.2": version: 2.0.2 resolution: "@types/trusted-types@npm:2.0.2" @@ -2238,6 +2263,13 @@ __metadata: languageName: node linkType: hard +"desandro-matches-selector@npm:^2.0.0": + version: 2.0.2 + resolution: "desandro-matches-selector@npm:2.0.2" + checksum: 30979e6b45d7720d259d4db11ec026fcbee242deee5ec0944c265d7e386a7358ab29f7417cbc3631830d0dbe6e827940dee31f789ed865dba22880d209fc9f8e + languageName: node + linkType: hard + "diff@npm:^5.1.0": version: 5.1.0 resolution: "diff@npm:5.1.0" @@ -2864,6 +2896,13 @@ __metadata: languageName: node linkType: hard +"ev-emitter@npm:^1.0.0": + version: 1.1.1 + resolution: "ev-emitter@npm:1.1.1" + checksum: 3dd78a7620701ef8095794f611dd251bdd9023badf322b3d6fa5e10a660c50e83eec5ee5bbc7654682635cf7b8858c94e2c77e1d10bdc188a2b0593436403476 + languageName: node + linkType: hard + "eventemitter3@npm:^4.0.4": version: 4.0.7 resolution: "eventemitter3@npm:4.0.7" @@ -2977,6 +3016,15 @@ __metadata: languageName: node linkType: hard +"fizzy-ui-utils@npm:^2.0.0": + version: 2.0.7 + resolution: "fizzy-ui-utils@npm:2.0.7" + dependencies: + desandro-matches-selector: ^2.0.0 + checksum: 001e54effa22c4f62728b90a25e8eb5477057ab53d0184e1c3231bbdfc7c34e278418fbcaf7d63c75ede823d82e61245e668ce8cba90e1c5699de960188c654f + languageName: node + linkType: hard + "flat-cache@npm:^3.0.4": version: 3.0.4 resolution: "flat-cache@npm:3.0.4" @@ -3052,6 +3100,7 @@ __metadata: "@rollup/plugin-replace": ^4.0.0 "@types/bluebird": ^3.5.36 "@types/lodash-es": ^4.17.5 + "@types/masonry-layout": ^4.2.5 "@typescript-eslint/eslint-plugin": ^5.36.2 "@typescript-eslint/parser": ^5.36.2 "@vitest/coverage-c8": ^0.29.8 @@ -3073,6 +3122,7 @@ __metadata: lit: ^2.3.1 lit-flatpickr: ^0.4.0 lodash-es: ^4.17.21 + masonry-layout: ^4.2.2 moment: ^2.29.4 prettier: ^2.6.0 propagating-hammerjs: ^2.0.1 @@ -3221,6 +3271,13 @@ __metadata: languageName: node linkType: hard +"get-size@npm:^2.0.2": + version: 2.0.3 + resolution: "get-size@npm:2.0.3" + checksum: 18d5a5fdb3f541db8b1e6ad46a5411d4bb7da3061d2ef7e544db3bbce7a13543f05c91fd40c7f68b4bc4bc035c160fed23c45514cde7d5fb18de1cce10208b19 + languageName: node + linkType: hard + "get-symbol-description@npm:^1.0.0": version: 1.0.0 resolution: "get-symbol-description@npm:1.0.0" @@ -4229,6 +4286,16 @@ __metadata: languageName: node linkType: hard +"masonry-layout@npm:^4.2.2": + version: 4.2.2 + resolution: "masonry-layout@npm:4.2.2" + dependencies: + get-size: ^2.0.2 + outlayer: ^2.1.0 + checksum: b947029b8fdfb384d17d7749d80a4f00f88d885acea04d77e1fefd36827cc2a345fd40d9ccddf720ed9323e133d8ea498125eece91d2c8517f69fd4e9e1bbdf4 + languageName: node + linkType: hard + "mdn-data@npm:2.0.14": version: 2.0.14 resolution: "mdn-data@npm:2.0.14" @@ -4653,6 +4720,17 @@ __metadata: languageName: node linkType: hard +"outlayer@npm:^2.1.0": + version: 2.1.1 + resolution: "outlayer@npm:2.1.1" + dependencies: + ev-emitter: ^1.0.0 + fizzy-ui-utils: ^2.0.0 + get-size: ^2.0.2 + checksum: a8b69d07bad6b498ea1956f89a4bae6d38414d81a5feeae6af06cd8206a1bf47db82f664dc3ccd13b8d2c5886a6cded4a4642d0fafcbbd80f68873b7eb9f4153 + languageName: node + linkType: hard + "p-finally@npm:^1.0.0": version: 1.0.0 resolution: "p-finally@npm:1.0.0" From e7094718bbf31e5e08c12d6b26df1f0dabf46e73 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 8 Aug 2023 22:48:50 -0700 Subject: [PATCH 004/189] Add documentation. --- README.md | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/README.md b/README.md index 264efabd..cb808211 100644 --- a/README.md +++ b/README.md @@ -474,6 +474,7 @@ See the [fully expanded live configuration example](#config-expanded-live) for h | `controls` | | :white_check_mark: | Configuration for the `live` view controls. See below. | | `layout` | | :white_check_mark: | See [media layout](#media-layout) below.| | `microphone` | | :white_check_mark: | See [microphone](#microphone) below.| +| `display` | | :white_check_mark: | See [display](#live-display) below.| #### Live Controls @@ -579,6 +580,35 @@ live: See [Using 2-way audio](#using-2-way-audio) for more information about the very particular requirements that must be followed for 2-way audio to work. + + +#### Live: Display + +All configuration is under: + +```yaml +live: + display: +``` + +| Option | Default | Overridable | Description | +| - | - | - | - | +| `mode` | `single` | :white_check_mark: | Whether to display a `single` media item at a time, or a media item for all cameras in a `grid`` configuration.| +| `grid_selected_width_factor` | `2` | :white_check_mark: | How much to scale up the selected media item in a grid. A value of `1` will not scale the selected item at all, the default value of `2` will scale the media item width to twice what it would otherwise be, etc. | +| `grid_columns` | | :white_check_mark: | If specified the grid will always have exactly this number of columns.| +| `grid_max_columns` | `4` | :white_check_mark: | If specified, and `grid_columns` is not specified, the grid will not render more than this number of columns. The precise number will be calculated based on the [grid layout algorithm](#grid-layout-algorith). | + + + +##### Grid Layout Algorithm + +The grid will lay out cameras roughly in the order they are specified in the config (items may be moved to optimize grid 'density'). The following algorithm is used to calculate the number of columns. This attempts to offers a balance between configurability, reasonable display in a typical Lovelace card width and reasonable display in a typical fullscreen display. + +* Use `grid_columns` if specified. +* Otherwise, use the largest number of columns in the range `[2 - grid_max_columns]` that will fit at least a `600px` column width. +* Otherwise, use the largest number of columns in the range `[2 - grid_max_columns]` that will fit at least a `190px` column width. +* Otherwise, there will be `1` column only. + ### Media Viewer Options The `media_viewer` is used for viewing all `clip`, `snapshot` or recording media, in a media carousel. @@ -689,6 +719,24 @@ media_viewer: | `mode` | `popup-bottom-right` | :heavy_multiplication_x: | How to display the Media viewer media title. Acceptable values: `none`, `popup-top-left`, `popup-top-right`, `popup-bottom-left`, `popup-bottom-right` . | | `duration_seconds` | `2` | :heavy_multiplication_x: | The number of seconds to display the title popup. `0` implies forever.| + + +#### Media Viewer: Display + +All configuration is under: + +```yaml +media_viewer: + display: +``` + +| Option | Default | Overridable | Description | +| - | - | - | - | +| `mode` | `single` | :white_check_mark: | Whether to display a `single` media item at a time, or a media item for all cameras in a `grid`` configuration.| +| `grid_selected_width_factor` | `2` | :white_check_mark: | How much to scale up the selected media item in a grid. A value of `1` will not scale the selected item at all, the default value of `2` will scale the media item width to twice what it would otherwise be, etc. | +| `grid_columns` | | :white_check_mark: | If specified the grid will always have exactly this number of columns.| +| `grid_max_columns` | `4` | :white_check_mark: | If specified, and `grid_columns` is not specified, the grid will not render more than this number of columns. The precise number will be calculated based on the [grid layout algorithm](#grid-layout-algorith). | + ### Media Gallery Options @@ -1946,6 +1994,10 @@ live: microphone: always_connected: false disconnect_seconds: 60 + display: + mode: single + grid_selected_width_factor: 2 + grid_max_columns: 4 actions: entity: light.office_main_lights tap_action: @@ -2007,6 +2059,10 @@ media_viewer: position: x: 50 y: 50 + display: + mode: single + grid_selected_width_factor: 2 + grid_max_columns: 4 actions: entity: light.office_main_lights tap_action: @@ -3823,6 +3879,32 @@ automations: ``` +### Grid display overrides + +
+ Expand: Change the grid layout configuration in fullscreen mode + +This example will always render 5 columns in fullscreen mode in both the live +and media viewer views, and will not enlarge the selected item. The normal +auto-layout behavior will be used outside of fullscreen mode. + +```yaml +overrides: + - conditions: + fullscreen: true + display_mode: grid + overrides: + live: + display: + grid_columns: 5 + grid_selected_width_factor: 1 + media_viewer: + display: + grid_columns: 5 + grid_selected_width_factor: 1 +``` +
+ ## Card Refreshes From d9b2b4d4d8e2a4ea8ca79663056846c7db1635c2 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 8 Aug 2023 22:49:52 -0700 Subject: [PATCH 005/189] Minor fixes. --- src/components/viewer.ts | 2 +- src/const.ts | 2 +- src/scss/media-grid.scss | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/viewer.ts b/src/components/viewer.ts index fd030904..945d74ec 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -12,7 +12,7 @@ import { customElement, property } from 'lit/decorators.js'; import { guard } from 'lit/directives/guard.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js'; -import basicBlockStyle from '../../scss/basic-block.scss'; +import basicBlockStyle from '../scss/basic-block.scss'; import { CameraManager } from '../camera-manager/manager.js'; import { dispatchMessageEvent, renderProgressIndicator } from '../components/message.js'; import { localize } from '../localize/localize.js'; diff --git a/src/const.ts b/src/const.ts index bfa27ea3..4cda24fe 100644 --- a/src/const.ts +++ b/src/const.ts @@ -287,7 +287,7 @@ export const MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA = 131072; // The number of media items to fetch at a time (for clips/snapshot views, and // gallery chunks). Smaller values will cause more frequent smaller fetches, but // improved rendering performance. -export const MEDIA_CHUNK_SIZE_DEFAULT = 500; +export const MEDIA_CHUNK_SIZE_DEFAULT = 50; export const MEDIA_CHUNK_SIZE_MAX = 1000; export const FRIGATE_BUTTON_MENU_ICON = 'frigate'; diff --git a/src/scss/media-grid.scss b/src/scss/media-grid.scss index a6b9b49c..9efa5f6c 100644 --- a/src/scss/media-grid.scss +++ b/src/scss/media-grid.scss @@ -43,6 +43,10 @@ var(--frigate-card-grid-column-size) ) ); + + // When at item is selected, it may be enlarged -- it should render "in-front" + // of the other cameras that will then "move out of the way". + z-index: 2; } slot { From 330f927fdbd9866f335bebb20dd959aa68798f77 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 9 Aug 2023 21:26:12 -0700 Subject: [PATCH 006/189] Fix controls issue. --- src/action-handler-directive.ts | 5 ++++- src/components/media-grid.ts | 3 +-- src/utils/media-grid-controller.ts | 4 ++-- src/utils/media.ts | 5 ++++- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/action-handler-directive.ts b/src/action-handler-directive.ts index 0dd34d12..17cad147 100644 --- a/src/action-handler-directive.ts +++ b/src/action-handler-directive.ts @@ -53,7 +53,10 @@ class ActionHandler extends HTMLElement implements ActionHandler { }); } - public bind(element: ActionHandlerElement, options): void { + public bind( + element: ActionHandlerElement, + options: FrigateCardActionHandlerOptions, + ): void { if (element.actionHandlerOptions) { // Reset the options on an existing actionHandler. element.actionHandlerOptions = options; diff --git a/src/components/media-grid.ts b/src/components/media-grid.ts index e0b599b3..f43b1c92 100644 --- a/src/components/media-grid.ts +++ b/src/components/media-grid.ts @@ -1,10 +1,9 @@ // TODO: Performance of video scanning (pause/play?) // TODO: Investigate query spam during a grid load -// TODO: Test live pre-load // TODO: Is the query reset in card.ts correct for media filter multi-camera queries that are not all cameras? // TODO: Do I need column max? -// TODO: test changing tabs in a dashboard (to trigger disconnect, do I still receive media loads from media that was already loaded)? // TODO: Can SELECT_CHILD_EVENTS only be 'click' and it still work on Android? +// TODO: With live autoplay off only white frames appear? import { CSSResultGroup, diff --git a/src/utils/media-grid-controller.ts b/src/utils/media-grid-controller.ts index 6f09dfb9..ac79a60d 100644 --- a/src/utils/media-grid-controller.ts +++ b/src/utils/media-grid-controller.ts @@ -46,7 +46,7 @@ export class MediaGridController { () => this._masonry?.layout?.(), // Throttle layout calls to larger than the masonry.js transitionDuration // value specified below. - 500, + 300, { trailing: true, leading: false }, ); @@ -251,7 +251,7 @@ export class MediaGridController { columnWidth: this._getColumnSize(), initLayout: false, percentPosition: true, - transitionDuration: '0.3s', + transitionDuration: '0.2s', }); this._masonry.addItems?.([...this._gridContents.values()]); this._throttledLayout(); diff --git a/src/utils/media.ts b/src/utils/media.ts index 7f3704ed..6bf63a93 100644 --- a/src/utils/media.ts +++ b/src/utils/media.ts @@ -9,6 +9,7 @@ const MEDIA_SEEK_CONTROLS_HIDE_SECONDS = 1; export type FrigateCardHTMLVideoElement = HTMLVideoElement & { _controlsHideTimer?: Timer; + _controlsOriginalValue?: boolean; }; /** @@ -24,6 +25,7 @@ export const setControlsOnVideo = ( if (video._controlsHideTimer) { video._controlsHideTimer.stop(); delete video._controlsHideTimer; + delete video._controlsOriginalValue; } video.controls = value; }; @@ -38,9 +40,10 @@ export const hideMediaControlsTemporarily = ( video: FrigateCardHTMLVideoElement, seconds = MEDIA_SEEK_CONTROLS_HIDE_SECONDS, ): void => { - const oldValue = video.controls; + const oldValue = video._controlsOriginalValue ?? video.controls; setControlsOnVideo(video, false); video._controlsHideTimer ??= new Timer(); + video._controlsOriginalValue = oldValue; video._controlsHideTimer.start(seconds, () => { setControlsOnVideo(video, oldValue); }); From fe2adb5b89d58ba4f8baef0b74b719ae13ca60d2 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 9 Aug 2023 21:32:53 -0700 Subject: [PATCH 007/189] Reduce number of event listeners. --- src/components/media-grid.ts | 2 -- src/utils/media-grid-controller.ts | 26 ++++++++++---------------- 2 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/components/media-grid.ts b/src/components/media-grid.ts index f43b1c92..4b5b27b1 100644 --- a/src/components/media-grid.ts +++ b/src/components/media-grid.ts @@ -2,8 +2,6 @@ // TODO: Investigate query spam during a grid load // TODO: Is the query reset in card.ts correct for media filter multi-camera queries that are not all cameras? // TODO: Do I need column max? -// TODO: Can SELECT_CHILD_EVENTS only be 'click' and it still work on Android? -// TODO: With live autoplay off only white frames appear? import { CSSResultGroup, diff --git a/src/utils/media-grid-controller.ts b/src/utils/media-grid-controller.ts index ac79a60d..c6633c3f 100644 --- a/src/utils/media-grid-controller.ts +++ b/src/utils/media-grid-controller.ts @@ -29,8 +29,6 @@ export interface MediaGridConstructorOptions { idAttribute?: string; } -const SELECT_CHILD_EVENTS = ['click', 'touchend']; - export class MediaGridController { protected _host: HTMLElement; @@ -216,27 +214,23 @@ export class MediaGridController { this._throttledLayout(); } - protected _removeChildEventListeners(child: MediaGridChild): void { - for (const event of SELECT_CHILD_EVENTS) { - child.removeEventListener(event, this._handleSelectGridCellEvent, { - capture: true, - }); - } + protected _addChildEventListeners(child: MediaGridChild): void { + child.addEventListener('click', this._handleSelectGridCellEvent, { + capture: true, + }); - child.removeEventListener( + child.addEventListener( 'frigate-card:media:loaded', this._handleMediaLoadedInfoEvent, ); } - protected _addChildEventListeners(child: MediaGridChild): void { - for (const event of SELECT_CHILD_EVENTS) { - child.addEventListener(event, this._handleSelectGridCellEvent, { - capture: true, - }); - } + protected _removeChildEventListeners(child: MediaGridChild): void { + child.removeEventListener('click', this._handleSelectGridCellEvent, { + capture: true, + }); - child.addEventListener( + child.removeEventListener( 'frigate-card:media:loaded', this._handleMediaLoadedInfoEvent, ); From cc77caa96d5ba1faa33185f0654badaec58a6ab4 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Fri, 11 Aug 2023 19:49:42 -0700 Subject: [PATCH 008/189] Reset the query on grid change in a smarter way. --- src/card.ts | 43 +++++++++----- src/components/live/live.ts | 9 ++- src/components/media-grid.ts | 3 +- src/components/viewer.ts | 19 +++--- src/utils/menu-controller.ts | 2 +- src/view/media-queries.ts | 34 +++++++++-- src/view/view.ts | 7 +-- tests/utils/media-grid-controller.test.ts | 7 +-- tests/view/media-queries.test.ts | 30 ++++++++-- tests/view/view.test.ts | 70 ++++------------------- 10 files changed, 116 insertions(+), 108 deletions(-) diff --git a/src/card.ts b/src/card.ts index 21f182b9..9356401f 100644 --- a/src/card.ts +++ b/src/card.ts @@ -48,12 +48,12 @@ import { CameraConfig, CardWideConfig, ExtendedHomeAssistant, + FRIGATE_CARD_VIEW_DEFAULT, FrigateCardConfig, frigateCardConfigSchema, FrigateCardCustomAction, FrigateCardError, FrigateCardView, - FRIGATE_CARD_VIEW_DEFAULT, MediaLoadedInfo, MenuButton, Message, @@ -87,6 +87,7 @@ import { supportsFeature } from './utils/ha/update.js'; import { FrigateCardInitializer } from './utils/initializer.js'; import { MediaLoadedInfoController } from './utils/media-info-controller'; import { isValidMediaLoadedInfo } from './utils/media-info.js'; +import { executeMediaQueryForView } from './utils/media-to-view'; import { MenuButtonController } from './utils/menu-controller'; import { MicrophoneController } from './utils/microphone'; import { getActionsFromQueryString } from './utils/querystring.js'; @@ -1085,7 +1086,7 @@ class FrigateCard extends LitElement { // Note: This function needs to process (view-related) commands even when // _view has not yet been initialized (since it may be used to set a view // via the querystring). - if (!this._cameraManager) { + if (!this._cameraManager || !this._hass) { return; } @@ -1241,19 +1242,33 @@ class FrigateCard extends LitElement { this._conditionController?.setState({ displayMode: this._viewDisplayMode, }); - // If the new mode is for all cameras, but the current query does not - // have a query for every cameraID, reset it. - const resetQuery = - frigateCardAction.mode === 'grid' && - !this._view?.query?.hasQueriesForCameraIDs( - this._cameraManager.getStore().getVisibleCameraIDs(), - ); - this._changeView({ - view: this._view?.evolve({ - displayMode: frigateCardAction.display_mode, - ...(resetQuery && { query: null, queryResults: null }), - }), + + const newView = this._view?.evolve({ + displayMode: frigateCardAction.display_mode, }); + + const generateNewQuery = + newView?.isGrid() && + newView.query && + (newView.query.getQueryCameraIDs()?.size ?? 0) <= 1; + + if (generateNewQuery && newView && newView.query) { + // If the user requests a grid but the current query does not have a + // query for more than one camera, reset the query results, change the + // existing query to refer to all cameras and execute it to fetch new + // results. + executeMediaQueryForView( + this, + this._hass, + this._cameraManager, + newView, + newView.query + .clone() + .setQueryCameraIDs(this._cameraManager.getStore().getVisibleCameraIDs()), + ).then((view) => view && this._changeView({ view: view })); + } else { + this._changeView({ view: newView }); + } break; default: console.warn(`Frigate card received unknown card action: ${action}`); diff --git a/src/components/live/live.ts b/src/components/live/live.ts index cdbf87e8..957ce164 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -363,7 +363,12 @@ export class FrigateCardLiveGrid extends LitElement { protected _needsGrid(): boolean { const cameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); - return !!this.view?.isGrid() && !!cameraIDs && cameraIDs.size >= 1; + return ( + !!this.view?.isGrid() && + !!this.view?.supportsMultipleDisplayModes() && + !!cameraIDs && + cameraIDs.size > 1 + ); } protected willUpdate(changedProps: PropertyValues): void { @@ -377,7 +382,7 @@ export class FrigateCardLiveGrid extends LitElement { return; } const cameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); - if (!this._needsGrid() || !cameraIDs) { + if (!cameraIDs || !this._needsGrid()) { return this._renderCarousel(); } return html` diff --git a/src/components/media-grid.ts b/src/components/media-grid.ts index 4b5b27b1..af09624d 100644 --- a/src/components/media-grid.ts +++ b/src/components/media-grid.ts @@ -1,7 +1,8 @@ // TODO: Performance of video scanning (pause/play?) // TODO: Investigate query spam during a grid load -// TODO: Is the query reset in card.ts correct for media filter multi-camera queries that are not all cameras? + // TODO: Do I need column max? +// TODO: What thumbnails do I show in the live drawer? import { CSSResultGroup, diff --git a/src/components/viewer.ts b/src/components/viewer.ts index 945d74ec..b18c4ded 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -149,7 +149,6 @@ export class FrigateCardViewer extends LitElement { { allCameras: this.view.isGrid(), targetView: 'recording', - select: 'latest', }, ); } else { @@ -163,7 +162,6 @@ export class FrigateCardViewer extends LitElement { allCameras: this.view.isGrid(), targetView: 'media', mediaType: mediaType, - select: 'latest', }, ); } @@ -648,18 +646,23 @@ export class FrigateCardViewerGrid extends LitElement { } protected willUpdate(changedProps: PropertyValues): void { - if ( - changedProps.has('view') && - this.view?.isGrid() && - this.view?.hasMultipleDisplayModes() - ) { + if (changedProps.has('view') && this._needsGrid()) { import('./media-grid.js'); } } + protected _needsGrid(): boolean { + const cameraIDs = this.view?.queryResults?.getCameraIDs(); + return ( + !!this.view?.isGrid() && + !!this.view?.supportsMultipleDisplayModes() && + (cameraIDs?.size ?? 0) > 1 + ); + } + protected render(): TemplateResult { const cameraIDs = this.view?.queryResults?.getCameraIDs(); - if (!cameraIDs || !this.view?.isGrid() || !this.view?.hasMultipleDisplayModes()) { + if (!cameraIDs || !this._needsGrid()) { return this._renderCarousel(); } diff --git a/src/utils/menu-controller.ts b/src/utils/menu-controller.ts index 64123abd..2790e2c6 100644 --- a/src/utils/menu-controller.ts +++ b/src/utils/menu-controller.ts @@ -394,7 +394,7 @@ export class MenuButtonController { }); } - if (view.hasMultipleDisplayModes(visibleCameras.size)) { + if (view.supportsMultipleDisplayModes() && visibleCameras.size > 1) { const isGrid = view.isGrid(); const action = createFrigateCardCustomAction('display_mode_select', { display_mode: isGrid ? 'single' : 'grid', diff --git a/src/view/media-queries.ts b/src/view/media-queries.ts index 2a75e5e3..4a77ae7f 100644 --- a/src/view/media-queries.ts +++ b/src/view/media-queries.ts @@ -1,4 +1,6 @@ import cloneDeep from 'lodash-es/cloneDeep.js'; +import isEqual from 'lodash-es/isEqual.js'; +import uniqWith from 'lodash-es/uniqWith.js'; import { EventQuery, MediaQuery, RecordingQuery } from '../camera-manager/types.js'; export type MediaQueries = EventMediaQueries | RecordingMediaQueries; @@ -12,7 +14,7 @@ class MediaQueriesBase { } } - public clone(): MediaQueriesBase { + public clone(): this { return cloneDeep(this); } @@ -20,8 +22,32 @@ class MediaQueriesBase { return this._queries; } - public setQueries(queries: T[]): void { + public setQueries(queries: T[]): this { this._queries = queries; + return this; + } + + public getQueryCameraIDs(): Set | null { + if (!this._queries) { + return null; + } + const cameraIDs: Set = new Set(); + this._queries.forEach((query) => + [...query.cameraIDs].forEach((cameraID) => cameraIDs.add(cameraID)), + ); + return cameraIDs; + } + + public setQueryCameraIDs(cameraIDs: Set): this { + if (!this._queries) { + return this; + } + const rewrittenQueries: T[] = []; + this._queries.forEach((query) => + rewrittenQueries.push({ ...query, cameraIDs: cameraIDs }), + ); + this._queries = uniqWith(rewrittenQueries, isEqual); + return this; } public hasQueriesForCameraIDs(cameraIDs: Set) { @@ -42,10 +68,6 @@ export class EventMediaQueries extends MediaQueriesBase { } return this; } - - public clone(): EventMediaQueries { - return cloneDeep(this); - } } export class RecordingMediaQueries extends MediaQueriesBase {} diff --git a/src/view/view.ts b/src/view/view.ts index e0f13ec1..f4619678 100644 --- a/src/view/view.ts +++ b/src/view/view.ts @@ -231,11 +231,8 @@ export class View { return ['clip', 'snapshot', 'media', 'recording'].includes(this.view); } - public hasMultipleDisplayModes(cameraCount?: number): boolean { - return ( - (this.is('live') && (cameraCount ?? 0) > 1) || - (this.isViewerView() && (this.queryResults?.getCameraIDs().size ?? 0) > 1) - ); + public supportsMultipleDisplayModes(): boolean { + return this.isViewerView() || this.is('live'); } /** diff --git a/tests/utils/media-grid-controller.test.ts b/tests/utils/media-grid-controller.test.ts index 255c2105..f254a718 100644 --- a/tests/utils/media-grid-controller.test.ts +++ b/tests/utils/media-grid-controller.test.ts @@ -301,7 +301,7 @@ describe('MediaGridController', () => { expect.objectContaining({ initLayout: false, percentPosition: true, - transitionDuration: '0.3s', + transitionDuration: '0.2s', }), ); }); @@ -352,10 +352,7 @@ describe('MediaGridController', () => { const controller = createController(host); expect(controller.getSelected()).toBeNull(); - - const touchEvent = new TouchEvent('touchend'); - children[1].dispatchEvent(touchEvent); - + children[1].click(); expect(controller.getSelected()).toBe('1'); }); diff --git a/tests/view/media-queries.test.ts b/tests/view/media-queries.test.ts index 9ac570f5..b8c9c817 100644 --- a/tests/view/media-queries.test.ts +++ b/tests/view/media-queries.test.ts @@ -72,6 +72,30 @@ describe('EventMediaQueries', () => { const queries = new EventMediaQueries(rawQueries); expect(queries.clone().getQueries()).toEqual(queries.getQueries()); }); + + it('should get camera IDs when queries are null', () => { + expect(new EventMediaQueries().getQueryCameraIDs()).toBeNull(); + }); + + it('should get camera IDs', () => { + const cameraIDs = ['office', 'kitchen']; + const queries = new EventMediaQueries(createRawEventQueries(new Set(cameraIDs))); + expect(queries.getQueryCameraIDs()).toEqual(new Set(cameraIDs)); + }); + + it('should set camera IDs when queries are null', () => { + expect( + new EventMediaQueries().setQueryCameraIDs(new Set(['office'])).getQueryCameraIDs(), + ).toBeNull(); + }); + + it('should set camera IDs', () => { + const queries = new EventMediaQueries(createRawEventQueries('sitting_room')); + const newCameraIDs = new Set(['office', 'kitchen']); + expect(queries.setQueryCameraIDs(newCameraIDs).getQueryCameraIDs()).toEqual( + newCameraIDs, + ); + }); }); describe('RecordingMediaQueries', () => { @@ -93,10 +117,4 @@ describe('RecordingMediaQueries', () => { const queries = new RecordingMediaQueries(rawQueries); expect(queries.getQueries()).toBe(rawQueries); }); - - it('should clone', () => { - const rawQueries = createRawRecordingQueries('office'); - const queries = new RecordingMediaQueries(rawQueries); - expect(queries.clone().getQueries()).toEqual(queries.getQueries()); - }); }); diff --git a/tests/view/view.test.ts b/tests/view/view.test.ts index de6a1912..165c7dc7 100644 --- a/tests/view/view.test.ts +++ b/tests/view/view.test.ts @@ -427,67 +427,17 @@ describe('View.adoptFromViewIfAppropriate', () => { }); it('should determine if view supports multiple display modes', () => { - const resultsOne = new MediaQueriesResults({ - results: generateViewMediaArray({ cameraIDs: ['office'] }), - }); - const resultsTwo = new MediaQueriesResults({ - results: generateViewMediaArray({ cameraIDs: ['office', 'kitchen'] }), - }); + expect(createView({ view: 'live' }).supportsMultipleDisplayModes()).toBeFalsy(); + expect(createView({ view: 'media' }).supportsMultipleDisplayModes()).toBeTruthy(); + expect(createView({ view: 'clip' }).supportsMultipleDisplayModes()).toBeTruthy(); + expect(createView({ view: 'snapshot' }).supportsMultipleDisplayModes()).toBeTruthy(); + expect(createView({ view: 'recording' }).supportsMultipleDisplayModes()).toBeTruthy(); - expect(createView({ view: 'live' }).hasMultipleDisplayModes()).toBeFalsy(); - expect(createView({ view: 'live' }).hasMultipleDisplayModes(0)).toBeFalsy(); - expect(createView({ view: 'live' }).hasMultipleDisplayModes(1)).toBeFalsy(); - expect(createView({ view: 'live' }).hasMultipleDisplayModes(2)).toBeTruthy(); - - expect(createView({ view: 'media' }).hasMultipleDisplayModes()).toBeFalsy(); - expect( - createView({ view: 'media', queryResults: resultsOne }).hasMultipleDisplayModes(), - ).toBeFalsy(); - expect( - createView({ view: 'media', queryResults: resultsTwo }).hasMultipleDisplayModes(), - ).toBeTruthy(); - - expect(createView({ view: 'clip' }).hasMultipleDisplayModes()).toBeFalsy(); - expect( - createView({ view: 'clip', queryResults: resultsOne }).hasMultipleDisplayModes(), - ).toBeFalsy(); - expect( - createView({ view: 'clip', queryResults: resultsTwo }).hasMultipleDisplayModes(), - ).toBeTruthy(); - - expect(createView({ view: 'snapshot' }).hasMultipleDisplayModes()).toBeFalsy(); - expect( - createView({ - view: 'snapshot', - queryResults: resultsOne, - }).hasMultipleDisplayModes(), - ).toBeFalsy(); - expect( - createView({ - view: 'snapshot', - queryResults: resultsTwo, - }).hasMultipleDisplayModes(), - ).toBeTruthy(); - - expect(createView({ view: 'recording' }).hasMultipleDisplayModes()).toBeFalsy(); - expect( - createView({ - view: 'recording', - queryResults: resultsOne, - }).hasMultipleDisplayModes(), - ).toBeFalsy(); - expect( - createView({ - view: 'recording', - queryResults: resultsTwo, - }).hasMultipleDisplayModes(), - ).toBeTruthy(); - - expect(createView({ view: 'clips' }).hasMultipleDisplayModes()).toBeFalsy(); - expect(createView({ view: 'snapshots' }).hasMultipleDisplayModes()).toBeFalsy(); - expect(createView({ view: 'recordings' }).hasMultipleDisplayModes()).toBeFalsy(); - expect(createView({ view: 'image' }).hasMultipleDisplayModes()).toBeFalsy(); - expect(createView({ view: 'timeline' }).hasMultipleDisplayModes()).toBeFalsy(); + expect(createView({ view: 'clips' }).supportsMultipleDisplayModes()).toBeFalsy(); + expect(createView({ view: 'snapshots' }).supportsMultipleDisplayModes()).toBeFalsy(); + expect(createView({ view: 'recordings' }).supportsMultipleDisplayModes()).toBeFalsy(); + expect(createView({ view: 'image' }).supportsMultipleDisplayModes()).toBeFalsy(); + expect(createView({ view: 'timeline' }).supportsMultipleDisplayModes()).toBeFalsy(); }); }); From 8a0ba11fa96ffab2288f74cd22b9f9559d0f0f6f Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 12 Aug 2023 09:46:47 -0700 Subject: [PATCH 009/189] Reset query when changing to non-grid . --- src/card.ts | 12 ++++++++---- src/components/media-grid.ts | 2 -- src/view/media-queries.ts | 5 +++-- tests/view/view.test.ts | 2 +- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/card.ts b/src/card.ts index 9356401f..16f6c201 100644 --- a/src/card.ts +++ b/src/card.ts @@ -1248,9 +1248,9 @@ class FrigateCard extends LitElement { }); const generateNewQuery = - newView?.isGrid() && - newView.query && - (newView.query.getQueryCameraIDs()?.size ?? 0) <= 1; + newView?.query && + ((newView.isGrid() && (newView.query.getQueryCameraIDs()?.size ?? 0) <= 1) || + (!newView.isGrid() && (newView.query.getQueryCameraIDs()?.size ?? 0) > 1)); if (generateNewQuery && newView && newView.query) { // If the user requests a grid but the current query does not have a @@ -1264,7 +1264,11 @@ class FrigateCard extends LitElement { newView, newView.query .clone() - .setQueryCameraIDs(this._cameraManager.getStore().getVisibleCameraIDs()), + .setQueryCameraIDs( + newView.isGrid() + ? this._cameraManager.getStore().getVisibleCameraIDs() + : newView.camera, + ), ).then((view) => view && this._changeView({ view: view })); } else { this._changeView({ view: newView }); diff --git a/src/components/media-grid.ts b/src/components/media-grid.ts index af09624d..344e82cc 100644 --- a/src/components/media-grid.ts +++ b/src/components/media-grid.ts @@ -1,8 +1,6 @@ // TODO: Performance of video scanning (pause/play?) // TODO: Investigate query spam during a grid load - // TODO: Do I need column max? -// TODO: What thumbnails do I show in the live drawer? import { CSSResultGroup, diff --git a/src/view/media-queries.ts b/src/view/media-queries.ts index 4a77ae7f..2b5268c1 100644 --- a/src/view/media-queries.ts +++ b/src/view/media-queries.ts @@ -2,6 +2,7 @@ import cloneDeep from 'lodash-es/cloneDeep.js'; import isEqual from 'lodash-es/isEqual.js'; import uniqWith from 'lodash-es/uniqWith.js'; import { EventQuery, MediaQuery, RecordingQuery } from '../camera-manager/types.js'; +import { setify } from '../utils/basic.js'; export type MediaQueries = EventMediaQueries | RecordingMediaQueries; @@ -38,13 +39,13 @@ class MediaQueriesBase { return cameraIDs; } - public setQueryCameraIDs(cameraIDs: Set): this { + public setQueryCameraIDs(cameraIDs: string | Set): this { if (!this._queries) { return this; } const rewrittenQueries: T[] = []; this._queries.forEach((query) => - rewrittenQueries.push({ ...query, cameraIDs: cameraIDs }), + rewrittenQueries.push({ ...query, cameraIDs: setify(cameraIDs) }), ); this._queries = uniqWith(rewrittenQueries, isEqual); return this; diff --git a/tests/view/view.test.ts b/tests/view/view.test.ts index 165c7dc7..e19f5da3 100644 --- a/tests/view/view.test.ts +++ b/tests/view/view.test.ts @@ -427,7 +427,7 @@ describe('View.adoptFromViewIfAppropriate', () => { }); it('should determine if view supports multiple display modes', () => { - expect(createView({ view: 'live' }).supportsMultipleDisplayModes()).toBeFalsy(); + expect(createView({ view: 'live' }).supportsMultipleDisplayModes()).toBeTruthy(); expect(createView({ view: 'media' }).supportsMultipleDisplayModes()).toBeTruthy(); expect(createView({ view: 'clip' }).supportsMultipleDisplayModes()).toBeTruthy(); expect(createView({ view: 'snapshot' }).supportsMultipleDisplayModes()).toBeTruthy(); From c61ceb905df8e9727e1050d9d943e773d7229178 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 12 Aug 2023 20:35:02 -0700 Subject: [PATCH 010/189] Fix query/queryResults issue. --- src/components/carousel.ts | 45 ++++++++++++++++++-------------- src/components/media-carousel.ts | 6 ++--- src/components/media-grid.ts | 2 ++ src/components/viewer.ts | 2 +- 4 files changed, 31 insertions(+), 24 deletions(-) diff --git a/src/components/carousel.ts b/src/components/carousel.ts index 351bf339..c7de9885 100644 --- a/src/components/carousel.ts +++ b/src/components/carousel.ts @@ -1,20 +1,16 @@ import EmblaCarousel, { EmblaCarouselType, EmblaOptionsType } from 'embla-carousel'; import { EmblaNodesType } from 'embla-carousel/components'; -import { - CreatePluginType, - EmblaPluginsType, - LoosePluginType, -} from 'embla-carousel/components/Plugins'; +import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins'; import { CSSResultGroup, - html, LitElement, PropertyValues, TemplateResult, + html, unsafeCSS, } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { createRef, ref, Ref } from 'lit/directives/ref.js'; +import { Ref, createRef, ref } from 'lit/directives/ref.js'; import throttle from 'lodash-es/throttle'; import carouselStyle from '../scss/carousel.scss'; import { TransitionEffect } from '../types'; @@ -101,8 +97,8 @@ export class FrigateCardCarousel extends LitElement { * Get the selected slide. * @returns A CarouselSelect object (index & element). */ - public getCarouselSelected(): CarouselSelect | null { - const index = this._carousel?.selectedScrollSnap(); + public getCarouselSelected(slide?: number): CarouselSelect | null { + const index = slide ?? this._carousel?.selectedScrollSnap(); const element = index !== undefined ? this._carousel?.slideNodes()[index] ?? null : null; if (index !== undefined && element) { @@ -151,13 +147,6 @@ export class FrigateCardCarousel extends LitElement { } } - /** - * Get the live carousel plugins. - */ - public getCarouselPlugins(): EmblaPluginsType | null { - return this._carousel?.plugins() ?? null; - } - /** * The updated lifecycle callback for this element. * @param changedProperties The properties that were changed in this render. @@ -212,8 +201,8 @@ export class FrigateCardCarousel extends LitElement { }, this.carouselPlugins, ); - const selectSlide = (): void => { - const selected = this.getCarouselSelected(); + const selectSlide = (slide?: number): void => { + const selected = this.getCarouselSelected(slide); if (selected) { dispatchFrigateCardEvent(this, 'carousel:select', selected); } @@ -223,8 +212,24 @@ export class FrigateCardCarousel extends LitElement { this.requestUpdate(); }; - this._carousel.on('init', selectSlide); - this._carousel.on('select', selectSlide); + this._carousel.on( + 'init', + // On initialization selectedScrollSnap() will return 0, even if the + // startIndex during initialization is different, as such we override + // the selected slide as returned by the carousel. This need should be + // verified in future versions of Embla (tested as necessary on v7.0.9). + // Test case: + // + // - Start in `live` view in grid mode. + // - Select any camera that is not the first one. + // - Go to non-grid mode. + // - Go back to grid mode. + // - If successful, thumbnails will load correctly (and the query and + // queryResults in the view will be set vs having been reset in + // `_setViewCameraID` in `live.ts`). + () => selectSlide(this.selected), + ); + this._carousel.on('select', () => selectSlide()); this._carousel.on('scroll', () => { this._scrolling = true; }); diff --git a/src/components/media-carousel.ts b/src/components/media-carousel.ts index 470e564b..8e8a2f0e 100644 --- a/src/components/media-carousel.ts +++ b/src/components/media-carousel.ts @@ -3,6 +3,7 @@ import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit import { customElement, property } from 'lit/decorators.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { createRef, ref, Ref } from 'lit/directives/ref.js'; +import debounce from 'lodash-es/debounce'; import mediaCarouselStyle from '../scss/media-carousel.scss'; import type { MediaLoadedInfo, @@ -15,14 +16,13 @@ import { dispatchExistingMediaLoadedInfoAsEvent, isValidMediaLoadedInfo, } from '../utils/media-info.js'; +import { Timer } from '../utils/timer'; import { CarouselSelect, EmblaCarouselPlugins, FrigateCardCarousel } from './carousel'; +import './carousel.js'; import { AutoMediaType } from './embla-plugins/automedia.js'; import './next-prev-control.js'; -import './carousel.js'; import { FrigateCardNextPreviousControl } from './next-prev-control.js'; import { FrigateCardTitleControl } from './title-control.js'; -import debounce from 'lodash-es/debounce'; -import { Timer } from '../utils/timer'; interface CarouselMediaLoadedInfo { slide: number; diff --git a/src/components/media-grid.ts b/src/components/media-grid.ts index 344e82cc..2c2f5d72 100644 --- a/src/components/media-grid.ts +++ b/src/components/media-grid.ts @@ -1,6 +1,8 @@ // TODO: Performance of video scanning (pause/play?) // TODO: Investigate query spam during a grid load // TODO: Do I need column max? +// TODO: frigate-card-live-go2rtc.hidden double media load event. +// TODO: Why am I creating so many carousels in the race-condition issue? Expecting 5, getting 10. import { CSSResultGroup, diff --git a/src/components/viewer.ts b/src/components/viewer.ts index b18c4ded..dfcb896f 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -253,7 +253,7 @@ export class FrigateCardViewerCarousel extends LitElement { } /** - * The the HLS player on a slide (or current slide if not provided.) + * Get the media player on a slide (or current slide if not provided). * @param slide An optional slide. * @returns The FrigateCardMediaPlayer or null if not found. */ From b4595867b3c55560e736384f4e8228cdd1d43d17 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 13 Aug 2023 10:00:29 -0700 Subject: [PATCH 011/189] Avoid carousel init duplication. --- src/components/carousel.ts | 26 +++++++++++++++++++------- src/components/media-grid.ts | 4 ---- src/utils/basic.ts | 8 +++++++- tests/utils/basic.test.ts | 20 ++++++++++++++++---- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/components/carousel.ts b/src/components/carousel.ts index c7de9885..59a43c87 100644 --- a/src/components/carousel.ts +++ b/src/components/carousel.ts @@ -11,10 +11,11 @@ import { } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { Ref, createRef, ref } from 'lit/directives/ref.js'; +import isEqual from 'lodash-es/isEqual'; import throttle from 'lodash-es/throttle'; import carouselStyle from '../scss/carousel.scss'; import { TransitionEffect } from '../types'; -import { dispatchFrigateCardEvent } from '../utils/basic.js'; +import { dispatchFrigateCardEvent, isHTMLElement } from '../utils/basic.js'; export interface CarouselSelect { index: number; @@ -175,6 +176,13 @@ export class FrigateCardCarousel extends LitElement { this._carousel = undefined; } + protected _getSlideElements(): HTMLElement[] { + return ( + this._refSlot.value?.assignedElements({ flatten: true }).filter(isHTMLElement) ?? + [] + ); + } + /** * Initialize the carousel. */ @@ -187,7 +195,7 @@ export class FrigateCardCarousel extends LitElement { root: carouselNode, // As the slides are slotted, need to explicitly pull them out and pass // them to Embla. - slides: this._refSlot.value?.assignedElements({ flatten: true }) as HTMLElement[], + slides: this._getSlideElements(), }; if (carouselNode && nodes.slides) { @@ -219,7 +227,7 @@ export class FrigateCardCarousel extends LitElement { // the selected slide as returned by the carousel. This need should be // verified in future versions of Embla (tested as necessary on v7.0.9). // Test case: - // + // // - Start in `live` view in grid mode. // - Select any camera that is not the first one. // - Go to non-grid mode. @@ -256,10 +264,14 @@ export class FrigateCardCarousel extends LitElement { * Called when the slotted children in the carousel change. */ protected _slotChanged(): void { - // Cannot just re-init, because the slide elements themselves may have - // changed, and only a carousel init can pass in new (slotted) children. If - this._destroyCarousel(); - this.requestUpdate(); + // Check whether the slotted elements have changed (without this check the + // carousel initializations are duplicated). + if (!isEqual(this._getSlideElements(), this._carousel?.slideNodes())) { + // Cannot just re-init, because the slide elements themselves may have + // changed, and only a carousel init can pass in new (slotted) children. + this._destroyCarousel(); + this.requestUpdate(); + } } protected render(): TemplateResult | void { diff --git a/src/components/media-grid.ts b/src/components/media-grid.ts index 2c2f5d72..b894f32b 100644 --- a/src/components/media-grid.ts +++ b/src/components/media-grid.ts @@ -1,8 +1,4 @@ // TODO: Performance of video scanning (pause/play?) -// TODO: Investigate query spam during a grid load -// TODO: Do I need column max? -// TODO: frigate-card-live-go2rtc.hidden double media load event. -// TODO: Why am I creating so many carousels in the race-condition issue? Expecting 5, getting 10. import { CSSResultGroup, diff --git a/src/utils/basic.ts b/src/utils/basic.ts index 2321fe5e..51efa4cc 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -225,4 +225,10 @@ export const setOrRemoveAttribute = ( /** * Allow typescript to narrow types based on truthy filter. */ -export const filterTruthy = (x: T | false | undefined | null | '' | 0): x is T => !!x; +export const isTruthy = (x: T | false | undefined | null | '' | 0): x is T => !!x; + +/** + * Allow typescript to narrow types for HTMLElements. + */ +export const isHTMLElement = (element: unknown): element is HTMLElement => + element instanceof HTMLElement; diff --git a/tests/utils/basic.test.ts b/tests/utils/basic.test.ts index 6d45f08c..574a9803 100644 --- a/tests/utils/basic.test.ts +++ b/tests/utils/basic.test.ts @@ -8,7 +8,7 @@ import { dayToDate, dispatchFrigateCardEvent, errorToConsole, - filterTruthy, + isTruthy, formatDate, formatDateAndTime, getDurationString, @@ -20,6 +20,7 @@ import { setify, setOrRemoveAttribute, sleep, + isHTMLElement, } from '../../src/utils/basic'; // @vitest-environment jsdom @@ -248,11 +249,22 @@ describe('setOrRemoveAttribute', () => { }); }); -describe('filterTruthy', () => { +describe('isTruthy', () => { it('should return true for true', () => { - expect(filterTruthy(true)).toBeTruthy(); + expect(isTruthy(true)).toBeTruthy(); }); it('should return false for false', () => { - expect(filterTruthy(false)).toBeFalsy(); + expect(isTruthy(false)).toBeFalsy(); + }); +}); + +describe('isHTMLElement', () => { + it('should return true for HTMLElement', () => { + const htmlElement = document.createElement('div'); + expect(isHTMLElement(htmlElement)).toBeTruthy(); + }); + it('should return false for Element', () => { + const svgElement = document.createElementNS('http://www.w3.org/2000/svg', 'circle'); + expect(isHTMLElement(svgElement)).toBeFalsy(); }); }); From c665f1b3514dae0a76047db02811e05f2e3302c7 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 13 Aug 2023 12:37:20 -0700 Subject: [PATCH 012/189] Clean up seek handler. --- src/components/media-grid.ts | 3 ++- src/components/viewer.ts | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/components/media-grid.ts b/src/components/media-grid.ts index b894f32b..45135747 100644 --- a/src/components/media-grid.ts +++ b/src/components/media-grid.ts @@ -1,4 +1,5 @@ -// TODO: Performance of video scanning (pause/play?) +// TODO: Video scanning not select other camera? +// TODO: Drag from live results in different cameras being shown in timeline in media viewer? import { CSSResultGroup, diff --git a/src/components/viewer.ts b/src/components/viewer.ts index dfcb896f..03480a80 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -541,24 +541,24 @@ export class FrigateCardViewerCarousel extends LitElement { return; } const selectedMedia = this._media[this.selected]; - if (!selectedMedia) { + const player = this._getPlayer(); + if (!selectedMedia || !player) { return; } const seekTimeInMedia = selectedMedia.includesTime(seek); - setOrRemoveAttribute(this, !seekTimeInMedia, 'unseekable'); - if (!seekTimeInMedia) { - this._getPlayer()?.pause(); - } else { - this._getPlayer()?.play(); + if (!seekTimeInMedia && !player.isPaused()) { + player.pause(); + } else if (seekTimeInMedia && player.isPaused()) { + player.play(); } const seekTime = (await this.cameraManager?.getMediaSeekTime(this.hass, selectedMedia, seek)) ?? null; - const player = this._getPlayer(); - if (player && seekTime !== null) { + + if (seekTime !== null) { player.seek(seekTime); } } From 5364c828ebb82fdf7018360d5082a633f12118b4 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 13 Aug 2023 15:31:10 -0700 Subject: [PATCH 013/189] Show all cameras on timeline in grid mode. --- src/components/surround.ts | 12 ++++-------- src/components/timeline-core.ts | 2 ++ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/components/surround.ts b/src/components/surround.ts index ec771339..ef4a3995 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -8,7 +8,6 @@ import { } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { CameraManager } from '../camera-manager/manager.js'; -import type { DataQuery } from '../camera-manager/types'; import basicBlockStyle from '../scss/basic-block.scss'; import { CardWideConfig, @@ -139,15 +138,12 @@ export class FrigateCardSurround extends LitElement { return null; } if (this.view?.is('live')) { - return getAllDependentCameras(this.cameraManager, this.view.camera); + return this.view.isGrid() + ? this.cameraManager?.getStore().getVisibleCameraIDs() ?? null + : getAllDependentCameras(this.cameraManager, this.view.camera); } if (this.view.isViewerView()) { - return new Set( - this.view.query - ?.getQueries() - ?.map((query: DataQuery) => [...query.cameraIDs]) - .flat(), - ); + return this.view.query?.getQueryCameraIDs() ?? null; } return null; } diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 8b33f147..bcc4ef3d 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -496,8 +496,10 @@ export class FrigateCardTimelineCore extends LitElement { : 'media' : this.view.view; + const selectedCamera = newResults?.getSelectedResult()?.getCameraID(); this.view .evolve({ + ...(selectedCamera && { camera: selectedCamera }), view: desiredView, queryResults: newResults, }) // Whether or not to set the timeline window. From 17bfe4f38b074c8d0f34d1ec3adcfadbb1cefd51 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 19 Aug 2023 12:28:11 -0700 Subject: [PATCH 014/189] Recalculate grid for a slot change. --- src/components/media-grid.ts | 4 ++ src/components/timeline-core.ts | 48 ++++++++++++++++------- src/components/viewer.ts | 11 +++++- src/types.ts | 33 ++++++---------- src/utils/media-grid-controller.ts | 28 ++++++++++--- src/utils/media-to-view.ts | 24 ++++++++++-- src/view/media-queries-results.ts | 19 +++++++++ tests/utils/media-grid-controller.test.ts | 28 ++++++++++++- tests/utils/media-to-view.test.ts | 19 +++++++++ tests/view/media-queries-results.test.ts | 13 ++++++ 10 files changed, 179 insertions(+), 48 deletions(-) diff --git a/src/components/media-grid.ts b/src/components/media-grid.ts index 45135747..a3bd54bf 100644 --- a/src/components/media-grid.ts +++ b/src/components/media-grid.ts @@ -1,5 +1,8 @@ // TODO: Video scanning not select other camera? // TODO: Drag from live results in different cameras being shown in timeline in media viewer? +// TODO: It's possible to get a single entry in the grid, rendered without the +// grid (correctly), but still with isGrid so the menu button still shows the +// take it out of grid mode option. import { CSSResultGroup, @@ -43,6 +46,7 @@ export class FrigateCardMediaGrid extends LitElement { if (!this._controller && this._refSlot.value) { this._controller = new MediaGridController(this._refSlot.value, { selected: this.selected, + displayConfig: this.displayConfig, }); } diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index bcc4ef3d..729dcb63 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -48,6 +48,7 @@ import { dispatchFrigateCardEvent, formatDateAndTime, isHoverableDevice, + isTruthy, setOrRemoveAttribute, } from '../utils/basic'; import { @@ -485,10 +486,13 @@ export class FrigateCardTimelineCore extends LitElement { : results .clone() .resetSelectedResult() - .selectBestResult((media) => findBestMediaIndex(media, targetTime), { - allCameras: true, - main: true, - }); + .selectBestResult( + (media) => findBestMediaIndex(media, targetTime, this.view?.camera), + { + allCameras: true, + main: true, + }, + ); const desiredView: FrigateCardView = this.mini ? targetTime >= new Date() @@ -899,8 +903,7 @@ export class FrigateCardTimelineCore extends LitElement { maxItems: this.timelineConfig.clustering_threshold, clusterCriteria: (first: TimelineItem, second: TimelineItem): boolean => { - const media = this.view?.queryResults?.getSelectedResult(); - const selectedId = media?.getID(); + const selectedIDs = this._getAllSelectedMediaIDsFromView(); const firstMedia = (first).media; const secondMedia = (second).media; @@ -910,8 +913,8 @@ export class FrigateCardTimelineCore extends LitElement { return ( first.type !== 'background' && first.type === second.type && - first.id !== selectedId && - second.id !== selectedId && + !selectedIDs.includes(first.id) && + !selectedIDs.includes(second.id) && !!firstMedia && !!secondMedia && ViewMediaClassifier.isEvent(firstMedia) && @@ -966,6 +969,18 @@ export class FrigateCardTimelineCore extends LitElement { return !!this.hass && !!this.cameraManager; } + protected _getAllSelectedMediaIDsFromView(): IdType[] { + return ( + this.view?.queryResults?.getMultipleSelectedResults({ + main: true, + ...(this.view.isGrid() && { allCameras: true }), + }) ?? [] + ) + .filter((media) => ViewMediaClassifier.isEvent(media)) + .map((media) => media.getID()) + .filter(isTruthy); + } + /** * Update the timeline from the view object. */ @@ -1030,8 +1045,11 @@ export class FrigateCardTimelineCore extends LitElement { } const currentSelection = this._timeline.getSelection(); - const mediaID = media?.getID(); - const needToSelect = mediaID && mediaIsEvent && !currentSelection.includes(mediaID); + const mediaIDsToSelect = this._getAllSelectedMediaIDsFromView(); + + const needToSelect = mediaIDsToSelect.some( + (mediaID) => !currentSelection.includes(mediaID), + ); if (needToSelect) { if (this._isClustering()) { @@ -1039,12 +1057,14 @@ export class FrigateCardTimelineCore extends LitElement { // update the dataset to ensure the newly selected item cannot be included // in a cluster. - // Need to this rewrite prior to setting the selection (just below), or - // the selection will be lost on rewrite. - this._timelineSource?.rewriteEvent(mediaID); + for (const mediaID of mediaIDsToSelect) { + // Need to this rewrite prior to setting the selection (just below), or + // the selection will be lost on rewrite. + this._timelineSource?.rewriteEvent(mediaID); + } } - this._timeline?.setSelection([mediaID], { + this._timeline?.setSelection(mediaIDsToSelect, { focus: false, animation: { animation: false, diff --git a/src/components/viewer.ts b/src/components/viewer.ts index 03480a80..e20244be 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -14,7 +14,7 @@ import { ifDefined } from 'lit/directives/if-defined.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js'; import basicBlockStyle from '../scss/basic-block.scss'; import { CameraManager } from '../camera-manager/manager.js'; -import { dispatchMessageEvent, renderProgressIndicator } from '../components/message.js'; +import { dispatchMessageEvent, renderMessage, renderProgressIndicator } from '../components/message.js'; import { localize } from '../localize/localize.js'; import '../patches/ha-hls-player'; import viewerCarouselStyle from '../scss/viewer-carousel.scss'; @@ -136,7 +136,14 @@ export class FrigateCardViewer extends LitElement { // timeline). const mediaType = this.view.getDefaultMediaType(); if (!mediaType) { - return; + // Directly render an error message (instead of dispatching it upwards) + // to preserve the mini-timeline if the user scans into an area with no + // media. + return renderMessage({ + type: 'info', + message: localize('common.no_media'), + icon: 'mdi:multimedia', + }); } if (mediaType === 'recordings') { diff --git a/src/types.ts b/src/types.ts index d98ec638..5d9c0963 100644 --- a/src/types.ts +++ b/src/types.ts @@ -108,12 +108,14 @@ export class FrigateCardError extends Error { const viewDisplayModeSchema = z.enum(['single', 'grid']); export type ViewDisplayMode = z.infer; -const viewDisplaySchema = z.object({ - mode: viewDisplayModeSchema, - grid_selected_width_factor: z.number().min(0).optional(), - grid_max_columns: z.number().min(0).optional(), - grid_columns: z.number().min(0).optional(), -}).optional(); +const viewDisplaySchema = z + .object({ + mode: viewDisplayModeSchema, + grid_selected_width_factor: z.number().min(0).optional(), + grid_max_columns: z.number().min(0).optional(), + grid_columns: z.number().min(0).optional(), + }) + .optional(); export type ViewDisplayConfig = z.infer; /** @@ -1134,7 +1136,9 @@ const menuConfigSchema = z mute: hiddenButtonSchema.default(menuConfigDefault.buttons.mute), play: hiddenButtonSchema.default(menuConfigDefault.buttons.play), screenshot: hiddenButtonSchema.default(menuConfigDefault.buttons.screenshot), - display_mode: visibleButtonSchema.default(menuConfigDefault.buttons.display_mode), + display_mode: visibleButtonSchema.default( + menuConfigDefault.buttons.display_mode, + ), }) .default(menuConfigDefault.buttons), button_size: z.number().min(BUTTON_SIZE_MIN).default(menuConfigDefault.button_size), @@ -1164,10 +1168,6 @@ const viewerConfigDefault = { }, thumbnails: thumbnailControlsDefaults, timeline: miniTimelineConfigDefault, - title: { - mode: 'popup-bottom-right' as const, - duration_seconds: 2, - }, }, }; const viewerNextPreviousControlConfigSchema = nextPreviousControlConfigSchema.extend({ @@ -1215,16 +1215,7 @@ const viewerConfigSchema = z timeline: miniTimelineConfigSchema.default( viewerConfigDefault.controls.timeline, ), - title: titleControlConfigSchema - .extend({ - mode: titleControlConfigSchema.shape.mode.default( - viewerConfigDefault.controls.title.mode, - ), - duration_seconds: titleControlConfigSchema.shape.duration_seconds.default( - viewerConfigDefault.controls.title.duration_seconds, - ), - }) - .default(viewerConfigDefault.controls.title), + title: titleControlConfigSchema.optional(), }) .default(viewerConfigDefault.controls), layout: mediaLayoutConfigSchema.optional(), diff --git a/src/utils/media-grid-controller.ts b/src/utils/media-grid-controller.ts index c6633c3f..32787d58 100644 --- a/src/utils/media-grid-controller.ts +++ b/src/utils/media-grid-controller.ts @@ -1,3 +1,4 @@ +import isEqual from 'lodash-es/isEqual'; import throttle from 'lodash-es/throttle'; import Masonry from 'masonry-layout'; import { MediaLoadedInfo, ViewDisplayConfig } from '../types'; @@ -27,6 +28,7 @@ export interface MediaGridSelected { export interface MediaGridConstructorOptions { selected?: GridID; idAttribute?: string; + displayConfig?: ViewDisplayConfig; } export class MediaGridController { @@ -62,14 +64,26 @@ export class MediaGridController { this._idAttribute = options?.idAttribute ?? 'grid-id'; this._hostWidth = this._host.getBoundingClientRect().width; this._hostResizeObserver.observe(host); + this._displayConfig = options?.displayConfig ?? null; - this._calculateGridContentsFromHost(); this._mutationObserver.observe(host, { childList: true }); + // Need to separately listen for slotchanges since mutation observer will + // not be called for shadom DOM slotted changes. + if (host instanceof HTMLSlotElement) { + host.addEventListener('slotchange', this._calculateGridContentsFromHost); + } + this._calculateGridContentsFromHost(); } public destroy(): void { this._hostResizeObserver.disconnect(); this._cellResizeObserver.disconnect(); + + this._mutationObserver.disconnect(); + if (this._host instanceof HTMLSlotElement) { + this._host.removeEventListener('slotchange', this._calculateGridContentsFromHost); + } + this._mediaLoadedInfoMap.clear(); this._masonry?.destroy?.(); this._masonry = null; @@ -81,8 +95,10 @@ export class MediaGridController { } public setDisplayConfig(displayConfig: ViewDisplayConfig | null): void { - this._displayConfig = displayConfig; - this._calculateGridContentsFromHost(); + if (!isEqual(displayConfig, this._displayConfig)) { + this._displayConfig = displayConfig; + this._calculateGridContentsFromHost(); + } } public getGridContents(): MediaGridContents { @@ -127,11 +143,11 @@ export class MediaGridController { this._updateSelectedStylesOnElements(); } - protected _calculateGridContentsFromHost(): void { + protected _calculateGridContentsFromHost = (): void => { let childrenElements: Element[]; if (this._host instanceof HTMLSlotElement) { - childrenElements = this._host.assignedElements({ flatten: true }); + childrenElements = this._host.assignedElements(); } else { childrenElements = [...this._host.children]; } @@ -145,7 +161,7 @@ export class MediaGridController { } this._setGridContents(gridContents); - } + }; protected _setGridContents(elements: MediaGridContents): void { this._gridContents = elements; diff --git a/src/utils/media-to-view.ts b/src/utils/media-to-view.ts index 76215f78..6e0059f3 100644 --- a/src/utils/media-to-view.ts +++ b/src/utils/media-to-view.ts @@ -169,10 +169,11 @@ export const executeMediaQueryForView = async ( const queryResults = new MediaQueriesResults({ results: mediaArray }); let viewerContext: ViewContext | undefined = {}; + const cameraID = options?.targetCameraID ?? view.camera; if (options?.select === 'time' && options?.targetTime) { queryResults.selectBestResult((media) => - findBestMediaIndex(media, options.targetTime as Date), + findBestMediaIndex(media, options.targetTime as Date, cameraID), ); viewerContext = { mediaViewer: { @@ -186,7 +187,7 @@ export const executeMediaQueryForView = async ( query: query, queryResults: queryResults, view: options?.targetView, - camera: options?.targetCameraID, + camera: cameraID, }) .mergeInContext(viewerContext); }; @@ -201,11 +202,13 @@ export const executeMediaQueryForView = async ( export const findBestMediaIndex = ( mediaArray: ViewMedia[], targetTime: Date, + favorCameraID?: string, ): number | null => { let bestMatch: | { index: number; duration: number; + cameraID: string; } | undefined; @@ -215,8 +218,21 @@ export const findBestMediaIndex = ( if (media.includesTime(targetTime) && start && end) { const duration = end.getTime() - start.getTime(); - if (!bestMatch || duration > bestMatch.duration) { - bestMatch = { index: i, duration: duration }; + + if ( + // No best match so far ... + !bestMatch || + // ... or there is a best-match, but it's from a non-favored camera (unlike this one) ... + (favorCameraID && + bestMatch.cameraID !== favorCameraID && + media.getCameraID() === favorCameraID) || + // ... or this match is longer and either there's no favored camera or this is it. + (duration > bestMatch.duration && + (!favorCameraID || + bestMatch.cameraID !== favorCameraID || + media.getCameraID() === favorCameraID)) + ) { + bestMatch = { index: i, duration: duration, cameraID: media.getCameraID() }; } } } diff --git a/src/view/media-queries-results.ts b/src/view/media-queries-results.ts index cde420c2..3eec71be 100644 --- a/src/view/media-queries-results.ts +++ b/src/view/media-queries-results.ts @@ -183,6 +183,25 @@ export class MediaQueriesResults { public getSelectedResult(cameraID?: string): ViewMedia | null { return this.getSlice(cameraID)?.getSelectedResult() ?? null; } + public getMultipleSelectedResults( + criteria?: ResultSliceSelectionCriteria, + ): ViewMedia[] { + const results: ViewMedia[] = []; + if (!criteria || criteria.main) { + const mainResult = this.getSelectedResult(); + if (mainResult) { + results.push(mainResult); + } + } + const cameraIDs = this._getCameraIDsFromCriteria(criteria); + for (const cameraID of cameraIDs ?? []) { + const result = this.getSelectedResult(cameraID); + if (result) { + results.push(result); + } + } + return results; + } public hasSelectedResult(cameraID?: string): boolean { return this.getSlice(cameraID)?.hasSelectedResult() ?? false; } diff --git a/tests/utils/media-grid-controller.test.ts b/tests/utils/media-grid-controller.test.ts index f254a718..2066647b 100644 --- a/tests/utils/media-grid-controller.test.ts +++ b/tests/utils/media-grid-controller.test.ts @@ -63,7 +63,7 @@ const createSlotParent = (): HTMLElement => { const createSlotHost = (options?: { children?: HTMLElement[]; parent?: HTMLElement; -}): HTMLElement => { +}): HTMLSlotElement => { const parent = options?.parent ?? createSlotParent(); const slot = document.createElement('slot'); parent.shadowRoot?.append(slot); @@ -292,6 +292,32 @@ describe('MediaGridController', () => { expect(controller.getSelected()).toBeNull(); }); + it('should replace children of a slot when they change', () => { + const children = createChildren(); + const slotParent = createSlotParent(); + const host = createSlotHost({ children: children, parent: slotParent }); + + const controller = createController(host, { selected: '1' }); + + expect(controller.getSelected()).toBe('1'); + expect(controller.getGridSize()).toBe(3); + + children.forEach((child) => slotParent.removeChild(child)); + const newChildren = createChildren(['one', 'two', 'three']); + newChildren.forEach((child) => slotParent.append(child)); + + host.dispatchEvent(new Event('slotchange')); + + expect(controller.getGridContents()).toEqual( + new Map([ + ['one', newChildren[0]], + ['two', newChildren[1]], + ['three', newChildren[2]], + ]), + ); + expect(controller.getSelected()).toBeNull(); + }); + it('should construct masonry correctly', () => { const children = createChildren(); const host = createHost({ children: children }); diff --git a/tests/utils/media-to-view.test.ts b/tests/utils/media-to-view.test.ts index 5b108127..561bbc65 100644 --- a/tests/utils/media-to-view.test.ts +++ b/tests/utils/media-to-view.test.ts @@ -54,11 +54,13 @@ const generateViewMedia = ( index: number, base: Date, durationSeconds: number, + cameraID?: string, ): ViewMedia => { return new TestViewMedia({ id: `id-${index}`, startTime: base, endTime: add(base, { seconds: durationSeconds }), + ...(cameraID && { cameraID: cameraID }), }); }; @@ -449,4 +451,21 @@ describe('findBestMediaIndex', () => { expect(findBestMediaIndex(mediaArray, add(now, { seconds: 30 }))).toBe(1); }); + + it('should find best media index respecting favored cameraID', async () => { + const now = new Date(); + const mediaArray = [ + generateViewMedia(0, now, 60, 'less-good-camera'), + generateViewMedia(1, now, 120, 'less-good-camera'), + generateViewMedia(2, now, 10, 'favored-camera'), + generateViewMedia(3, now, 35, 'favored-camera'), + generateViewMedia(4, now, 40, 'favored-camera'), + generateViewMedia(5, now, 30, 'favored-camera'), + generateViewMedia(6, now, 300, 'less-good-camera'), + ]; + + expect( + findBestMediaIndex(mediaArray, add(now, { seconds: 30 }), 'favored-camera'), + ).toBe(4); + }); }); diff --git a/tests/view/media-queries-results.test.ts b/tests/view/media-queries-results.test.ts index ce11c9e7..aae224ef 100644 --- a/tests/view/media-queries-results.test.ts +++ b/tests/view/media-queries-results.test.ts @@ -35,6 +35,7 @@ describe('dispatchViewContextChangeEvent', () => { expect(results.selectBestResult((_media: ViewMedia[]) => null)).toEqual(results); expect(results.getSelectedResult()).toBeNull(); + expect(results.getMultipleSelectedResults()).toEqual([]); }); it('should function with basic results', () => { @@ -230,4 +231,16 @@ describe('dispatchViewContextChangeEvent', () => { expect(results.getSelectedResult('office')?.getID()).toBe('id-office-42'); expect(results.getSelectedResult('kitchen')?.getID()).toBe('id-kitchen-42'); }); + + it('should get multiple selected results', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + }); + + expect( + results + .getMultipleSelectedResults({ main: true, allCameras: true }) + .map((media) => media.getID()), + ).toEqual(['id-office-99', 'id-kitchen-99', 'id-office-99']); + }); }); From 89c16b58c5d7ce2fd7a06dba56f821198375ca6e Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 19 Aug 2023 15:49:30 -0700 Subject: [PATCH 015/189] Remove old TODOs. --- src/components/media-grid.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/components/media-grid.ts b/src/components/media-grid.ts index a3bd54bf..913e1aa7 100644 --- a/src/components/media-grid.ts +++ b/src/components/media-grid.ts @@ -1,9 +1,3 @@ -// TODO: Video scanning not select other camera? -// TODO: Drag from live results in different cameras being shown in timeline in media viewer? -// TODO: It's possible to get a single entry in the grid, rendered without the -// grid (correctly), but still with isGrid so the menu button still shows the -// take it out of grid mode option. - import { CSSResultGroup, html, From 3c23894c6da1701a5966847011b9954bbb25cbe8 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 19 Aug 2023 19:51:16 -0700 Subject: [PATCH 016/189] Scrubbing performance improvements. --- src/components/thumbnail.ts | 17 ++++++++++------- src/scss/drawer.scss | 8 ++++---- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/components/thumbnail.ts b/src/components/thumbnail.ts index 1625056c..edc157e2 100644 --- a/src/components/thumbnail.ts +++ b/src/components/thumbnail.ts @@ -333,11 +333,18 @@ export class FrigateCardThumbnailDetailsRecording extends LitElement { @customElement('frigate-card-thumbnail') export class FrigateCardThumbnail extends LitElement { - // HomeAssistant object may be required for thumbnail signing (for Frigate - // events). - @property({ attribute: false }) + // Performance: During timeline scrubbing, hass may be updated + // continuously. As it is not needed for the thumbnail rendering itself, it + // does not trigger a re-render. The HomeAssistant object may be required for + // thumbnail signing (after initial signing the thumbnail is stored in a data + // URL, so the signing will not expire). public hass?: ExtendedHomeAssistant; + // Performance: During timeline scrubbing, the view will be updated + // continuously. As it is not needed for the thumbnail rendering itself, it + // does not trigger a re-render. + public view?: Readonly; + @property({ attribute: false }) public cameraManager?: CameraManager; @@ -359,9 +366,6 @@ export class FrigateCardThumbnail extends LitElement { @property({ attribute: false }) public seek?: Date; - @property({ attribute: false }) - public view?: Readonly; - /** * Render the element. * @returns A template to display to the user. @@ -381,7 +385,6 @@ export class FrigateCardThumbnail extends LitElement { const shouldShowTimelineControl = this.show_timeline_control && - this.view && (!ViewMediaClassifier.isRecording(this.media) || // Only show timeline control if the recording has a start & end time. (this.media.getStartTime() && this.media.getEndTime())); diff --git a/src/scss/drawer.scss b/src/scss/drawer.scss index a86b3070..ebbb47fc 100644 --- a/src/scss/drawer.scss +++ b/src/scss/drawer.scss @@ -13,14 +13,14 @@ div.control-surround { padding-top: $drawer-padding-extend; padding-bottom: $drawer-padding-extend; } -:host([location=left]) div.control-surround { +:host([location='left']) div.control-surround { @if $drawer-icon-size < 32 { // Ensure the clickable area is at least 32px wide. padding-right: calc(32px - $drawer-icon-size); } left: 100%; } -:host([location=right]) div.control-surround { +:host([location='right']) div.control-surround { @if $drawer-icon-size < 32 { // See note above. padding-left: calc(32px - $drawer-icon-size); @@ -54,12 +54,12 @@ ha-icon.control { background-color: black; } -:host([location=left]) ha-icon.control { +:host([location='left']) ha-icon.control { border-top-right-radius: $drawer-icon-size; border-bottom-right-radius: $drawer-icon-size; } -:host([location=right]) ha-icon.control { +:host([location='right']) ha-icon.control { border-top-left-radius: $drawer-icon-size; border-bottom-left-radius: $drawer-icon-size; } From d23d412fbf3fa8c29ed26d09cf72034763cc3f83 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 19 Aug 2023 20:24:19 -0700 Subject: [PATCH 017/189] Fix typos. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index cb808211..334d3166 100644 --- a/README.md +++ b/README.md @@ -593,7 +593,7 @@ live: | Option | Default | Overridable | Description | | - | - | - | - | -| `mode` | `single` | :white_check_mark: | Whether to display a `single` media item at a time, or a media item for all cameras in a `grid`` configuration.| +| `mode` | `single` | :white_check_mark: | Whether to display a `single` media item at a time, or a media item for all cameras in a `grid` configuration.| | `grid_selected_width_factor` | `2` | :white_check_mark: | How much to scale up the selected media item in a grid. A value of `1` will not scale the selected item at all, the default value of `2` will scale the media item width to twice what it would otherwise be, etc. | | `grid_columns` | | :white_check_mark: | If specified the grid will always have exactly this number of columns.| | `grid_max_columns` | `4` | :white_check_mark: | If specified, and `grid_columns` is not specified, the grid will not render more than this number of columns. The precise number will be calculated based on the [grid layout algorithm](#grid-layout-algorith). | @@ -732,7 +732,7 @@ media_viewer: | Option | Default | Overridable | Description | | - | - | - | - | -| `mode` | `single` | :white_check_mark: | Whether to display a `single` media item at a time, or a media item for all cameras in a `grid`` configuration.| +| `mode` | `single` | :white_check_mark: | Whether to display a `single` media item at a time, or a media item for all cameras in a `grid` configuration.| | `grid_selected_width_factor` | `2` | :white_check_mark: | How much to scale up the selected media item in a grid. A value of `1` will not scale the selected item at all, the default value of `2` will scale the media item width to twice what it would otherwise be, etc. | | `grid_columns` | | :white_check_mark: | If specified the grid will always have exactly this number of columns.| | `grid_max_columns` | `4` | :white_check_mark: | If specified, and `grid_columns` is not specified, the grid will not render more than this number of columns. The precise number will be calculated based on the [grid layout algorithm](#grid-layout-algorith). | From 2df22b96ea93cc5137019b1509394bc96d0c1c80 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 20 Aug 2023 11:00:57 -0700 Subject: [PATCH 018/189] Fix various small issues. --- src/card.ts | 11 ++--------- src/components/timeline-core.ts | 2 +- src/view/view.ts | 7 ++++++- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/card.ts b/src/card.ts index 16f6c201..cfccf191 100644 --- a/src/card.ts +++ b/src/card.ts @@ -189,9 +189,6 @@ class FrigateCard extends LitElement { @state() protected _expand = false; - @state() - protected _viewDisplayMode?: ViewDisplayMode; - protected _microphoneController?: MicrophoneController; protected _conditionController?: ConditionController; protected _automationsController?: AutomationsController; @@ -503,7 +500,7 @@ class FrigateCard extends LitElement { if (cameraID) { const viewName = args?.viewName ?? this._getConfig().view.default; const displayMode = - this._viewDisplayMode ?? this._getDefaultDisplayModeForView(viewName); + this._view?.displayMode ?? this._getDefaultDisplayModeForView(viewName); changeView( new View({ view: viewName, @@ -1067,6 +1064,7 @@ class FrigateCard extends LitElement { protected _getDefaultDisplayModeForView(view: FrigateCardView): ViewDisplayMode { let mode: ViewDisplayMode | null = null; switch (view) { + case 'media': case 'clip': case 'clips': case 'recording': @@ -1238,11 +1236,6 @@ class FrigateCard extends LitElement { }); break; case 'display_mode_select': - this._viewDisplayMode = frigateCardAction.display_mode; - this._conditionController?.setState({ - displayMode: this._viewDisplayMode, - }); - const newView = this._view?.evolve({ displayMode: frigateCardAction.display_mode, }); diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 729dcb63..984400f6 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -482,7 +482,7 @@ export class FrigateCardTimelineCore extends LitElement { const canSeek = this._shouldSupportSeeking(); const newResults = this._panBehavior === 'seek-in-media' - ? null + ? results : results .clone() .resetSelectedResult() diff --git a/src/view/view.ts b/src/view/view.ts index f4619678..e41e1db4 100644 --- a/src/view/view.ts +++ b/src/view/view.ts @@ -91,7 +91,12 @@ export class View { let currentQueriesView: ClipsOrSnapshots | 'recordings' | null = null; if (MediaQueriesClassifier.areEventQueries(curr.query)) { const queries = curr.query.getQueries(); - if (queries?.every((query) => query.hasClip)) { + if ( + queries?.every((query) => query.hasClip) || + queries?.every( + (query) => query.hasClip === undefined && query.hasSnapshot === undefined, + ) + ) { currentQueriesView = 'clips'; } else if (queries?.every((query) => query.hasSnapshot)) { currentQueriesView = 'snapshots'; From 0e5e99419f88f016577dadbb4d14e024edce4b2d Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 20 Aug 2023 15:50:37 -0700 Subject: [PATCH 019/189] Better timeline functionality for recordings. --- src/components/timeline-core.ts | 152 ++++++++------------ src/scss/timeline-core.scss | 4 +- src/utils/media-to-view.ts | 8 +- src/utils/timeline-source.ts | 23 ++- src/view/media-queries-classifier.ts | 9 ++ tests/utils/media-to-view.test.ts | 47 +----- tests/view/media-queries-classifier.test.ts | 29 ++++ 7 files changed, 112 insertions(+), 160 deletions(-) create mode 100644 tests/view/media-queries-classifier.test.ts diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 984400f6..3e63d4d7 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -1,9 +1,7 @@ import add from 'date-fns/add'; import differenceInSeconds from 'date-fns/differenceInSeconds'; import endOfDay from 'date-fns/endOfDay'; -import endOfHour from 'date-fns/endOfHour'; import startOfDay from 'date-fns/startOfDay'; -import startOfHour from 'date-fns/startOfHour'; import sub from 'date-fns/sub'; import { CSSResultGroup, @@ -31,6 +29,7 @@ import { import { CameraManager } from '../camera-manager/manager'; import { rangesOverlap } from '../camera-manager/range'; import { MediaQuery } from '../camera-manager/types'; +import { convertRangeToCacheFriendlyTimes } from '../camera-manager/util'; import { localize } from '../localize/localize'; import timelineCoreStyle from '../scss/timeline-core.scss'; import { @@ -51,16 +50,19 @@ import { isTruthy, setOrRemoveAttribute, } from '../utils/basic'; -import { - createQueriesForRecordingsView, - executeMediaQueryForView, - findBestMediaIndex, -} from '../utils/media-to-view'; +import { executeMediaQueryForView, findBestMediaIndex } from '../utils/media-to-view'; import { FrigateCardTimelineItem, TimelineDataSource } from '../utils/timeline-source'; import { ViewMedia } from '../view/media'; import { ViewMediaClassifier } from '../view/media-classifier'; -import { EventMediaQueries, MediaQueries } from '../view/media-queries'; -import { MediaQueriesClassifier } from '../view/media-queries-classifier'; +import { + EventMediaQueries, + MediaQueries, + RecordingMediaQueries, +} from '../view/media-queries'; +import { + MediaQueriesClassifier, + MediaQueriesType, +} from '../view/media-queries-classifier'; import { View } from '../view/view'; import './date-picker.js'; import { DatePickerEvent, FrigateCardDatePicker } from './date-picker.js'; @@ -541,6 +543,7 @@ export class FrigateCardTimelineCore extends LitElement { !this.cameraManager || !this.cardWideConfig || !timelineCameraIDs || + !this._timelineSource || !properties.what ) { return; @@ -551,45 +554,10 @@ export class FrigateCardTimelineCore extends LitElement { if ( this.timelineConfig?.show_recordings && - ['background', 'group-label'].includes(properties.what) + properties.time && + ['background', 'axis'].includes(properties.what) ) { - const cameraIDs = properties.group - ? new Set([String(properties.group)]) - : this._getTimelineCameraIDs(); - const query = cameraIDs - ? createQueriesForRecordingsView( - this.cameraManager, - this.cardWideConfig, - cameraIDs, - ) - : null; - if (query) { - view = await executeMediaQueryForView( - this, - this.hass, - this.cameraManager, - this.view, - query, - { - targetView: 'recording', - targetTime: - properties.what === 'background' - ? properties.time - : this._timeline.getWindow().end, - select: 'time', - }, - ); - } - } else if (this.timelineConfig?.show_recordings && properties.what === 'axis') { - const query = createQueriesForRecordingsView( - this.cameraManager, - this.cardWideConfig, - timelineCameraIDs, - { - start: startOfHour(properties.time), - end: endOfHour(properties.time), - }, - ); + const query = this._createMediaQueries('recording'); if (query) { view = await executeMediaQueryForView( this, @@ -623,8 +591,8 @@ export class FrigateCardTimelineCore extends LitElement { // gallery (i.e. any case where the thumbnails may not be match the // events on the timeline, e.g. in the snapshots viewer but // mini-timeline showing all media). - const fullEventView = await this._createViewWithEventMediaQuery( - this._createEventMediaQuerys(), + const fullEventView = await this._createViewWithMediaQueries( + this._createMediaQueries('event'), { selectedItem: properties.item, targetView: 'media', @@ -686,59 +654,58 @@ export class FrigateCardTimelineCore extends LitElement { } this._removeTargetBar(); - if (!this.hass) { + if (!this.hass || !this._timeline || !this.view) { return; } - const prefetchedWindow = this._getPrefetchWindow(properties); - await this._timelineSource?.refresh(this.hass, prefetchedWindow); + await this._timelineSource?.refresh(this.hass, this._getPrefetchWindow(properties)); - // Don't show event thumbnails if the user is looking at recordings, - // as the recording "hours" are the media, not the event - // clips/snapshots. - if ( - this._timeline && - this.view && - !MediaQueriesClassifier.areRecordingQueries(this.view.query) - ) { - const newView = await this._createViewWithEventMediaQuery( - this._createEventMediaQuerys({ window: this._timeline.getWindow() }), - ); + const queryType = MediaQueriesClassifier.getQueriesType(this.view.query); + if (!queryType) { + return; + } + const mediaQuery = this._createMediaQueries(queryType); + const newView = await this._createViewWithMediaQueries(mediaQuery); - // Specifically avoid dispatching new results on range change unless there - // is something to be gained by doing so. Example usecase: On initial view - // load in mini timeline mode, the first 50 events are fetched -- the - // first drag of the timeline should not dispatch new results unless - // something is actually useful (as otherwise it creates a visible - // 'flicker' for the user as the viewer reloads all the media). - const newResults = newView?.queryResults; - if (newView && newResults && !this.view.queryResults?.isSupersetOf(newResults)) { - newView?.mergeInContext(this._getTimelineContext())?.dispatchChangeEvent(this); - } + // Specifically avoid dispatching new results on range change unless there + // is something to be gained by doing so. Example usecase: On initial view + // load in mini timeline mode, the first 50 events are fetched -- the + // first drag of the timeline should not dispatch new results unless + // something is actually useful (as otherwise it creates a visible + // 'flicker' for the user as the viewer reloads all the media). + const newResults = newView?.queryResults; + if (newView && newResults && !this.view.queryResults?.isSupersetOf(newResults)) { + newView?.mergeInContext(this._getTimelineContext())?.dispatchChangeEvent(this); } } - protected _createEventMediaQuerys(options?: { - window?: TimelineWindow; - }): EventMediaQueries | null { - if (!this._timeline || !this._timelineSource || !this.cardWideConfig) { + protected _createMediaQueries( + type: MediaQueriesType, + options?: { + window?: TimelineWindow; + }, + ): MediaQueries | null { + if (!this._timeline || !this._timelineSource) { return null; } - const cacheFriendlyWindow = this._timelineSource.getCacheFriendlyEventWindow( - options?.window ?? this._timeline.getWindow(), + const cacheFriendlyWindow = convertRangeToCacheFriendlyTimes( + this._getPrefetchWindow(options?.window ?? this._timeline.getWindow()), ); - const eventQueries = - this._timelineSource.getTimelineEventQueries(cacheFriendlyWindow); - if (!eventQueries) { - return null; + if (type === 'event') { + const queries = this._timelineSource.getTimelineEventQueries(cacheFriendlyWindow); + return queries ? new EventMediaQueries(queries) : null; + } else if (type === 'recording') { + const queries = + this._timelineSource.getTimelineRecordingQueries(cacheFriendlyWindow); + return queries ? new RecordingMediaQueries(queries) : null; } - return new EventMediaQueries(eventQueries); + return null; } - protected async _createViewWithEventMediaQuery( - query: EventMediaQueries | null, + protected async _createViewWithMediaQueries( + query: MediaQueries | null, options?: { targetView?: FrigateCardView; selectedItem?: IdType; @@ -1089,20 +1056,23 @@ export class FrigateCardTimelineCore extends LitElement { // -> New view received ... [loop] // // Also don't generate thumbnails in mini-timelines (they will already have - // been generated), or if the view is for recordings (media thumbnails are - // recordings, not events in this case). + // been generated). - const freshMediaQuery = this._createEventMediaQuerys({ + const queryType = MediaQueriesClassifier.getQueriesType(this.view.query); + if (!queryType) { + return; + } + + const freshMediaQuery = this._createMediaQueries(queryType, { window: desiredWindow, }); if ( !this.mini && - !MediaQueriesClassifier.areRecordingQueries(this.view.query) && freshMediaQuery && !this._alreadyHasAcceptableMediaQuery(freshMediaQuery) ) { - (await this._createViewWithEventMediaQuery(freshMediaQuery)) + (await this._createViewWithMediaQueries(freshMediaQuery)) ?.mergeInContext(this._getTimelineContext(desiredWindow)) .dispatchChangeEvent(this); } diff --git a/src/scss/timeline-core.scss b/src/scss/timeline-core.scss index 299cd2f4..6d876cc9 100644 --- a/src/scss/timeline-core.scss +++ b/src/scss/timeline-core.scss @@ -84,7 +84,6 @@ div.timeline { cursor: pointer; } :host([recordings]) .vis-item.vis-background, -:host([recordings]) .vis-labelset, :host([recordings]) .vis-time-axis { cursor: crosshair; } @@ -119,8 +118,7 @@ div.timeline { .vis-label { transition: background-color 0.5s ease-out; } -:host([recordings]) .vis-text.vis-minor:hover, -:host([recordings]) .vis-label:hover { +:host([recordings]) .vis-text.vis-minor:hover { background-color: var(--primary-color); } diff --git a/src/utils/media-to-view.ts b/src/utils/media-to-view.ts index 6e0059f3..b47b7a8b 100644 --- a/src/utils/media-to-view.ts +++ b/src/utils/media-to-view.ts @@ -116,21 +116,15 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( )?.dispatchChangeEvent(element); }; -export const createQueriesForRecordingsView = ( +const createQueriesForRecordingsView = ( cameraManager: CameraManager, cardWideConfig: CardWideConfig, cameraIDs: Set, - options?: { - start?: Date; - end?: Date; - }, ): RecordingMediaQueries | null => { const limit = cardWideConfig.performance?.features.media_chunk_size ?? MEDIA_CHUNK_SIZE_DEFAULT; const recordingQueries = cameraManager.generateDefaultRecordingQueries(cameraIDs, { limit: limit, - ...(options?.start && { start: options.start }), - ...(options?.end && { end: options.end }), }); return recordingQueries ? new RecordingMediaQueries(recordingQueries) : null; }; diff --git a/src/utils/timeline-source.ts b/src/utils/timeline-source.ts index f2646457..e50299b1 100644 --- a/src/utils/timeline-source.ts +++ b/src/utils/timeline-source.ts @@ -5,7 +5,7 @@ import { DataSet } from 'vis-data'; import { IdType, TimelineItem, TimelineWindow } from 'vis-timeline/esnext'; import { ClipsOrSnapshotsOrAll } from '../types'; import { CameraManager } from '../camera-manager/manager'; -import { EventQuery, RecordingSegment } from '../camera-manager/types'; +import { EventQuery, RecordingQuery, RecordingSegment } from '../camera-manager/types'; import { capEndDate, convertRangeToCacheFriendlyTimes } from '../camera-manager/util'; import { ViewMedia } from '../view/media'; import { @@ -98,12 +98,6 @@ export class TimelineDataSource { } } - public getCacheFriendlyEventWindow(window: TimelineWindow): TimelineWindow { - return convertRangeToCacheFriendlyTimes(window, { - endCap: true, - }); - } - public getTimelineEventQueries(window: TimelineWindow): EventQuery[] | null { return this._cameraManager.generateDefaultEventQueries(this._cameraIDs, { start: window.start, @@ -113,6 +107,13 @@ export class TimelineDataSource { }); } + public getTimelineRecordingQueries(window: TimelineWindow): RecordingQuery[] | null { + return this._cameraManager.generateDefaultRecordingQueries(this._cameraIDs, { + start: window.start, + end: window.end, + }); + } + protected async _refreshEvents( hass: HomeAssistant, window: TimelineWindow, @@ -127,8 +128,7 @@ export class TimelineDataSource { ) { return; } - - const cacheFriendlyWindow = this.getCacheFriendlyEventWindow(window); + const cacheFriendlyWindow = convertRangeToCacheFriendlyTimes(window); const eventQueries = this.getTimelineEventQueries(cacheFriendlyWindow); if (!eventQueries) { return; @@ -217,10 +217,7 @@ export class TimelineDataSource { return; } - const cacheFriendlyWindow = convertRangeToCacheFriendlyTimes(window, { - endCap: true, - }); - + const cacheFriendlyWindow = convertRangeToCacheFriendlyTimes(window); const recordingQueries = this._cameraManager.generateDefaultRecordingSegmentsQueries( this._cameraIDs, { diff --git a/src/view/media-queries-classifier.ts b/src/view/media-queries-classifier.ts index 4508e97f..b63210bc 100644 --- a/src/view/media-queries-classifier.ts +++ b/src/view/media-queries-classifier.ts @@ -1,5 +1,6 @@ import { EventMediaQueries, MediaQueries, RecordingMediaQueries } from './media-queries'; +export type MediaQueriesType = 'event' | 'recording'; export class MediaQueriesClassifier { public static areEventQueries( queries?: MediaQueries | null, @@ -12,4 +13,12 @@ export class MediaQueriesClassifier { ): queries is RecordingMediaQueries { return queries instanceof RecordingMediaQueries; } + + public static getQueriesType(queries?: MediaQueries | null): MediaQueriesType | null { + return this.areEventQueries(queries) + ? 'event' + : this.areRecordingQueries(queries) + ? 'recording' + : null; + } } diff --git a/tests/utils/media-to-view.test.ts b/tests/utils/media-to-view.test.ts index 561bbc65..5e8974d5 100644 --- a/tests/utils/media-to-view.test.ts +++ b/tests/utils/media-to-view.test.ts @@ -1,16 +1,10 @@ import add from 'date-fns/add'; import sub from 'date-fns/sub'; import { beforeEach, describe, expect, it, Mock, vi } from 'vitest'; -import { - CameraConfigs, - PartialRecordingQuery, - QueryType, -} from '../../src/camera-manager/types'; -import { setify } from '../../src/utils/basic'; +import { CameraConfigs } from '../../src/camera-manager/types'; import { changeViewToRecentEventsForCameraAndDependents, changeViewToRecentRecordingForCameraAndDependents, - createQueriesForRecordingsView, executeMediaQueryForView, findBestMediaIndex, } from '../../src/utils/media-to-view'; @@ -400,45 +394,6 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => { }); }); -// @vitest-environment jsdom -describe('createQueriesForRecordingsView', () => { - it('should respect start and end date in recording query', async () => { - const cameraManager = createCameraManager({ configs: new Map() }); - - vi.mocked(cameraManager.generateDefaultRecordingQueries).mockImplementation( - (cameraIDs: string | Set, partialQuery?: PartialRecordingQuery) => [ - { - cameraIDs: setify(cameraIDs), - type: QueryType.Recording, - ...partialQuery, - }, - ], - ); - - const start = new Date('2023-04-29T14:00:00'); - const end = new Date('2023-04-29T14:59:59'); - - const queries = createQueriesForRecordingsView( - cameraManager, - {}, - new Set(['camera']), - { - start: start, - end: end, - }, - ); - - expect(queries?.getQueries()).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - start: start, - end: end, - }), - ]), - ); - }); -}); - // @vitest-environment jsdom describe('findBestMediaIndex', () => { it('should find best media index', async () => { diff --git a/tests/view/media-queries-classifier.test.ts b/tests/view/media-queries-classifier.test.ts new file mode 100644 index 00000000..0b96608b --- /dev/null +++ b/tests/view/media-queries-classifier.test.ts @@ -0,0 +1,29 @@ +import { describe, expect, it } from 'vitest'; +import { EventMediaQueries, RecordingMediaQueries } from '../../src/view/media-queries'; +import { MediaQueriesClassifier } from '../../src/view/media-queries-classifier'; + +describe('MediaQueriesClassifier', () => { + it('areEventQueries', () => { + expect(MediaQueriesClassifier.areEventQueries(new EventMediaQueries())).toBeTruthy(); + expect( + MediaQueriesClassifier.areEventQueries(new RecordingMediaQueries()), + ).toBeFalsy(); + }); + + it('areRecordingQueries', () => { + expect( + MediaQueriesClassifier.areRecordingQueries(new RecordingMediaQueries()), + ).toBeTruthy(); + expect( + MediaQueriesClassifier.areRecordingQueries(new EventMediaQueries()), + ).toBeFalsy(); + }); + + it('getQueriesType', () => { + expect(MediaQueriesClassifier.getQueriesType(new EventMediaQueries())).toBe('event'); + expect(MediaQueriesClassifier.getQueriesType(new RecordingMediaQueries())).toBe( + 'recording', + ); + expect(MediaQueriesClassifier.getQueriesType()).toBeNull(); + }); +}); From ef7598cd84efeec0489df0083de3b61c95773a1a Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 20 Aug 2023 16:10:36 -0700 Subject: [PATCH 020/189] Use usable time for in progress events. --- src/utils/timeline-source.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/timeline-source.ts b/src/utils/timeline-source.ts index e50299b1..75bd426e 100644 --- a/src/utils/timeline-source.ts +++ b/src/utils/timeline-source.ts @@ -148,7 +148,7 @@ export class TimelineDataSource { media: media, start: startTime.getTime(), type: 'range', - end: endTime?.getTime() ?? startTime.getTime(), + end: media.getUsableEndTime()?.getTime() ?? startTime.getTime(), }); } } From 74f00e19855d92c5fe86fc43cc132818ec5d4b43 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 21 Aug 2023 19:46:35 -0700 Subject: [PATCH 021/189] Remove unused variable. --- src/utils/timeline-source.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/utils/timeline-source.ts b/src/utils/timeline-source.ts index 75bd426e..ba8ba6f7 100644 --- a/src/utils/timeline-source.ts +++ b/src/utils/timeline-source.ts @@ -137,7 +137,6 @@ export class TimelineDataSource { const mediaArray = await this._cameraManager.executeMediaQueries(hass, eventQueries); const data: FrigateCardTimelineItem[] = []; for (const media of mediaArray ?? []) { - const endTime = media.getEndTime(); const startTime = media.getStartTime(); const id = media.getID(); if (id && startTime) { From 87f137b474565bfe1a07478f49f6979b56db2c85 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 26 Aug 2023 11:11:44 -0700 Subject: [PATCH 022/189] Add support for timeline seeking locked to a camera. --- README.md | 11 ++++++ src/components/timeline-core.ts | 63 ++++++++++++++++++++----------- src/localize/languages/en.json | 1 + src/localize/languages/it.json | 1 + src/localize/languages/pt-BR.json | 1 + src/localize/languages/pt-PT.json | 7 ++-- 6 files changed, 60 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 334d3166..124f6e59 100644 --- a/README.md +++ b/README.md @@ -854,6 +854,17 @@ timeline: +#### Timeline Seek Behavior + +The behavior of the timeline during seeking/dragging can be controlled by means of the icon on the bottom-right of the timeline. + +| Option | Behavior | +| - | - | +| filmstrip-box-multiple | Dragging the timeline will seek / select across all available media from all cameras, selecting the media item with the longest duration whilst favoring (but not limited to) the currently selected camera. | +| play-box-lock | Dragging the timeline will seek within the selected media item only. | +| camera-lock | Dragging the timeline will seek / select across all available media from the selected camera only, selecting the media item with the longest duration. | +| pan-horizontal | Dragging the timeline will pan only without selected or seeking any media. | + ### Dimensions Options These options control the aspect-ratio of the entire card to make placement in diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 3e63d4d7..126ea111 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -63,6 +63,7 @@ import { MediaQueriesClassifier, MediaQueriesType, } from '../view/media-queries-classifier'; +import { MediaQueriesResults } from '../view/media-queries-results'; import { View } from '../view/view'; import './date-picker.js'; import { DatePickerEvent, FrigateCardDatePicker } from './date-picker.js'; @@ -85,7 +86,7 @@ interface TimelineViewContext { } type TimelineItemClickAction = 'play' | 'select'; -type TimelinePanBehavior = 'pan' | 'seek' | 'seek-in-media'; +type TimelinePanBehavior = 'pan' | 'seek' | 'seek-in-media' | 'seek-in-camera'; declare module 'view' { interface ViewContext { @@ -288,13 +289,17 @@ export class FrigateCardTimelineCore extends LitElement { ? localize('timeline.pan_behavior.pan') : this._panBehavior === 'seek' ? localize('timeline.pan_behavior.seek') - : localize('timeline.pan_behavior.seek-in-media'); + : this._panBehavior === 'seek-in-media' + ? localize('timeline.pan_behavior.seek-in-media') + : localize('timeline.pan_behavior.seek-in-camera'); const panIcon = this._panBehavior === 'pan' ? 'mdi:pan-horizontal' : this._panBehavior === 'seek' - ? 'mdi:filmstrip' - : 'mdi:lock'; + ? 'mdi:filmstrip-box-multiple' + : this._panBehavior === 'seek-in-media' + ? 'mdi:play-box-lock' + : 'mdi:camera-lock'; return html` ${capabilities?.supportsTimeline ? html`
{ const item = this._timelineSource?.dataset?.get(id); return ( + this._panBehavior !== 'seek-in-camera' || + item?.media?.getCameraID() === this.view?.camera, item && - item.start && - item.end && - targetTime.getTime() >= item.start && - targetTime.getTime() <= item.end + item.start && + item.end && + targetTime.getTime() >= item.start && + targetTime.getTime() <= item.end ); }))); @@ -482,19 +492,30 @@ export class FrigateCardTimelineCore extends LitElement { } const canSeek = this._shouldSupportSeeking(); - const newResults = - this._panBehavior === 'seek-in-media' - ? results - : results - .clone() - .resetSelectedResult() - .selectBestResult( - (media) => findBestMediaIndex(media, targetTime, this.view?.camera), - { - allCameras: true, - main: true, - }, - ); + let newResults: MediaQueriesResults | null = null; + + if (this._panBehavior === 'seek') { + newResults = results + .clone() + .resetSelectedResult() + .selectBestResult( + (mediaArray) => findBestMediaIndex(mediaArray, targetTime, this.view?.camera), + { + allCameras: true, + main: true, + }, + ); + } else if (this._panBehavior === 'seek-in-camera') { + newResults = results + .clone() + .resetSelectedResult() + .selectBestResult((mediaArray) => findBestMediaIndex(mediaArray, targetTime), { + cameraID: this.view.camera, + }) + .promoteCameraSelectionToMainSelection(this.view.camera); + } else if (this._panBehavior === 'seek-in-media') { + newResults = results; + } const desiredView: FrigateCardView = this.mini ? targetTime >= new Date() diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index e84d933f..d95f7d5b 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -516,6 +516,7 @@ "pan_behavior": { "pan": "Pan", "seek": "Pan seeks across all media", + "seek-in-camera": "Pan seeks within selected camera only", "seek-in-media": "Pan seeks within selected media item only" }, "select_date": "Choose date" diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 35a150c4..25fdaf4a 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -504,6 +504,7 @@ "pan_behavior": { "pan": "", "seek": "", + "seek-in-camera": "", "seek-in-media": "" }, "select_date": "Scegli la data" diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 1609d398..f5da9fb5 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -515,6 +515,7 @@ "pan_behavior": { "pan": "", "seek": "", + "seek-in-camera": "", "seek-in-media": "" }, "select_date": "Escolha a data" diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 57fc800f..f25d95f6 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -495,9 +495,10 @@ }, "timeline": { "pan_behavior": { - "pan": "Pan", - "seek": "Pan seeks across all media", - "seek-in-media": "Pan seeks within selected media item only" + "pan": "", + "seek": "", + "seek-in-camera": "", + "seek-in-media": "" }, "select_date": "Selecionar a data" } From af5b0f7f238e300f7350c1b095d8faf36a7d82dd Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 26 Aug 2023 11:41:06 -0700 Subject: [PATCH 023/189] Be less eager with carousel resizes. --- src/components/media-carousel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/media-carousel.ts b/src/components/media-carousel.ts index 8e8a2f0e..6f9e5a82 100644 --- a/src/components/media-carousel.ts +++ b/src/components/media-carousel.ts @@ -136,7 +136,7 @@ export class FrigateCardMediaCarousel extends LitElement { // Debounce multiple calls to adapt the container height. protected _debouncedAdaptContainerHeightToSlide = debounce( this._adaptContainerHeightToSlide.bind(this), - 1 * 100, + 1 * 250, {trailing: true}); // This carousel may be resized by Lovelace resizes, window resizes, From 48ece1e1546fbc115f4b5564386045b789ada3c4 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 26 Aug 2023 14:51:48 -0700 Subject: [PATCH 024/189] Improve display mode button text. --- src/editor.ts | 4 ++-- src/localize/languages/en.json | 10 +++++----- src/localize/languages/it.json | 9 +++++---- src/localize/languages/pt-BR.json | 10 +++++----- src/localize/languages/pt-PT.json | 10 +++++----- src/utils/menu-controller.ts | 4 +++- tests/utils/menu-controller.test.ts | 5 ++++- 7 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/editor.ts b/src/editor.ts index 56a3b231..2bbc2b2c 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -557,8 +557,8 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor protected _displayModes: EditorSelectOption[] = [ { value: '', label: '' }, - { value: 'single', label: localize('config.common.display.modes.single') }, - { value: 'grid', label: localize('config.common.display.modes.grid') }, + { value: 'single', label: localize('display_modes.single') }, + { value: 'grid', label: localize('display_modes.grid') }, ]; public setConfig(config: RawFrigateCardConfig): void { diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index d95f7d5b..a5e860f4 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -153,11 +153,7 @@ "grid_columns": "Exact number of grid columns", "grid_max_columns": "Maximum number of grid columns", "grid_selected_width_factor": "Increase selected media width by this factor", - "mode": "Mode", - "modes": { - "single": "Show single media viewer", - "grid": "Show media viewer for each camera in a grid" - } + "mode": "Mode" }, "layout": { "fit": "Layout fit", @@ -376,6 +372,10 @@ } } }, + "display_modes": { + "single": "Show single media viewer", + "grid": "Show media viewer for each camera in a grid" + }, "editor": { "add_new_camera": "Add new camera", "button": "Button", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 25fdaf4a..fa1b9a97 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -153,10 +153,7 @@ "grid_columns": "", "grid_max_columns": "", "grid_selected_width_factor": "", - "modes": { - "single": "", - "grid": "" - } + "mode": "" }, "layout": { "fit": "Adatta al layout", @@ -369,6 +366,10 @@ } } }, + "display_modes": { + "grid": "", + "single": "" + }, "editor": { "add_new_camera": "Aggiungi nuova telecamera", "button": "Pulsante", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index f5da9fb5..827c014d 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -153,11 +153,7 @@ "grid_columns": "", "grid_max_columns": "", "grid_selected_width_factor": "", - "mode": "", - "modes": { - "single": "", - "grid": "" - } + "mode": "" }, "layout": { "fit": "Ajuste de layout", @@ -375,6 +371,10 @@ } } }, + "display_modes": { + "grid": "", + "single": "" + }, "editor": { "add_new_camera": "Adicionar nova câmera", "button": "Botão", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index f25d95f6..5ec59b7f 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -153,11 +153,7 @@ "grid_columns": "", "grid_max_columns": "", "grid_selected_width_factor": "", - "mode": "", - "modes": { - "single": "", - "grid": "" - } + "mode": "" }, "layout": { "fit": "Fit", @@ -363,6 +359,10 @@ } } }, + "display_modes": { + "grid": "", + "single": "" + }, "editor": { "add_new_camera": "Adicionar nova câmera", "button": "Botão", diff --git a/src/utils/menu-controller.ts b/src/utils/menu-controller.ts index 2790e2c6..f069397f 100644 --- a/src/utils/menu-controller.ts +++ b/src/utils/menu-controller.ts @@ -404,7 +404,9 @@ export class MenuButtonController { icon: isGrid ? 'mdi:grid-off' : 'mdi:grid', ...config.menu.buttons.display_mode, type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.display_mode'), + title: isGrid + ? localize('display_modes.single') + : localize('display_modes.grid'), tap_action: action, }); } diff --git a/tests/utils/menu-controller.test.ts b/tests/utils/menu-controller.test.ts index 36adc42b..00c578c5 100644 --- a/tests/utils/menu-controller.test.ts +++ b/tests/utils/menu-controller.test.ts @@ -1102,7 +1102,10 @@ describe('MenuButtonController', () => { enabled: true, priority: 50, type: 'custom:frigate-card-menu-icon', - title: 'Display mode', + title: + displayMode === 'grid' + ? 'Show single media viewer' + : 'Show media viewer for each camera in a grid', tap_action: { action: 'fire-dom-event', frigate_card_action: 'display_mode_select', From e830db1a7775475f946f79a7541948f8bb72facc Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 4 Sep 2023 16:25:32 -0700 Subject: [PATCH 025/189] Complete carousel refactor. Reduces one layer of DOM nesting for simplication, uses the latest Embla version, unittests for everything. --- package.json | 10 +- src/action-handler-directive.ts | 2 +- src/cached-value-controller.ts | 12 +- src/camera-manager/engine-factory.ts | 2 +- src/camera-manager/range.ts | 19 +- src/components/carousel.ts | 292 ++---- src/components/drawer.ts | 20 +- src/components/embla-plugins/automedia.ts | 234 ----- src/components/live/live.ts | 209 ++-- src/components/media-carousel.ts | 440 --------- src/components/thumbnail-carousel.ts | 214 ++--- src/components/title-control.ts | 41 +- src/components/viewer.ts | 169 ++-- src/scss/carousel.scss | 3 + src/scss/live-carousel.scss | 6 +- src/scss/live-ha.scss | 2 - src/scss/media-carousel.scss | 9 - src/scss/viewer-carousel.scss | 11 +- src/utils/basic.ts | 8 + src/utils/camera.ts | 4 +- src/utils/embla/carousel-controller.ts | 178 ++++ .../plugins/auto-lazy-load/auto-lazy-load.ts} | 106 +-- .../auto-media-actions/auto-media-actions.ts | 232 +++++ .../auto-media-loaded-info.ts | 94 ++ .../embla/plugins/auto-size/auto-size.ts | 143 +++ src/utils/embla/reinit-controller.ts | 63 ++ src/utils/media-grid-controller.ts | 21 +- src/utils/media-info.ts | 12 +- src/utils/menu-controller.ts | 3 +- src/utils/zod.ts | 17 +- src/view/media-queries-results.ts | 2 +- src/view/view.ts | 10 +- tests/camera-manager/cache.test.ts | 28 +- tests/camera-manager/engine-factory.test.ts | 5 + tests/camera-manager/range.test.ts | 5 + tests/conditions.test.ts | 7 + tests/test-utils.ts | 58 +- tests/utils/basic.test.ts | 33 +- tests/utils/download.test.ts | 97 +- tests/utils/embla/carousel-controller.test.ts | 291 ++++++ .../auto-lazy-load/auto-lazy-load.test.ts | 219 +++++ .../auto-media-actions.test.ts | 304 ++++++ .../auto-media-loaded-info.test.ts | 92 ++ .../embla/plugins/auto-size/auto-size.test.ts | 161 ++++ tests/utils/embla/reinit-controller.test.ts | 59 ++ tests/utils/embla/test-utils.ts | 132 +++ tests/utils/media-grid-controller.test.ts | 250 +++-- tests/utils/media.test.ts | 10 + tests/utils/menu-controller.test.ts | 33 +- tests/utils/substream.test.ts | 22 +- tests/utils/zod.test.ts | 11 +- tests/utils/zoom.test.ts | 67 ++ tests/view/media-queries-results.test.ts | 36 + tests/view/view.test.ts | 97 +- vite.config.ts | 11 + yarn.lock | 895 ++++++++++++------ 56 files changed, 3561 insertions(+), 1950 deletions(-) delete mode 100644 src/components/embla-plugins/automedia.ts delete mode 100644 src/components/media-carousel.ts delete mode 100644 src/scss/media-carousel.scss create mode 100644 src/utils/embla/carousel-controller.ts rename src/{components/embla-plugins/lazyload.ts => utils/embla/plugins/auto-lazy-load/auto-lazy-load.ts} (57%) create mode 100644 src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts create mode 100644 src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.ts create mode 100644 src/utils/embla/plugins/auto-size/auto-size.ts create mode 100644 src/utils/embla/reinit-controller.ts create mode 100644 tests/utils/embla/carousel-controller.test.ts create mode 100644 tests/utils/embla/plugins/auto-lazy-load/auto-lazy-load.test.ts create mode 100644 tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts create mode 100644 tests/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.test.ts create mode 100644 tests/utils/embla/plugins/auto-size/auto-size.test.ts create mode 100644 tests/utils/embla/reinit-controller.test.ts create mode 100644 tests/utils/embla/test-utils.ts create mode 100644 vite.config.ts diff --git a/package.json b/package.json index ef7c35fd..e7f479de 100644 --- a/package.json +++ b/package.json @@ -27,8 +27,8 @@ "custom-card-helpers": "^1.9.0", "date-fns": "^2.29.2", "date-fns-tz": "^1.3.7", - "embla-carousel": "^7.0.9", - "embla-carousel-wheel-gestures": "^3.0.0", + "embla-carousel": "8.0.0-rc12", + "embla-carousel-wheel-gestures": "8.0.0-rc04", "home-assistant-js-websocket": "^8.0.0", "keycharm": "^0.4.0", "lit": "^2.3.1", @@ -62,7 +62,7 @@ "@types/masonry-layout": "^4.2.5", "@typescript-eslint/eslint-plugin": "^5.36.2", "@typescript-eslint/parser": "^5.36.2", - "@vitest/coverage-c8": "^0.29.8", + "@vitest/coverage-istanbul": "^0.34.3", "eslint": "^8.23.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^8.5.0", @@ -80,8 +80,8 @@ "sass": "^1.54.9", "ts-prune": "^0.10.3", "typescript": "^4.9.5", - "vitest": "^0.29.8", - "vitest-mock-extended": "^1.1.3" + "vitest": "^0.34.3", + "vitest-mock-extended": "^1.2.1" }, "scripts": { "start": "rollup -c --watch", diff --git a/src/action-handler-directive.ts b/src/action-handler-directive.ts index 17cad147..170c3e41 100644 --- a/src/action-handler-directive.ts +++ b/src/action-handler-directive.ts @@ -6,9 +6,9 @@ import type { import { noChange } from 'lit'; import { AttributePart, - directive, Directive, DirectiveParameters, + directive, } from 'lit/directive.js'; import { stopEventFromActivatingCardWideActions } from './utils/action.js'; import { Timer } from './utils/timer.js'; diff --git a/src/cached-value-controller.ts b/src/cached-value-controller.ts index f0ce59dd..894d15c7 100644 --- a/src/cached-value-controller.ts +++ b/src/cached-value-controller.ts @@ -69,13 +69,11 @@ export class CachedValueController implements ReactiveController { public startTimer(): void { this.stopTimer(); - if (this._timerSeconds > 0) { - this._timerStartCallback?.(); - this._timer.startRepeated(this._timerSeconds, () => { - this.updateValue(); - this._host.requestUpdate(); - }); - } + this._timerStartCallback?.(); + this._timer.startRepeated(this._timerSeconds, () => { + this.updateValue(); + this._host.requestUpdate(); + }); } public hasTimer(): boolean { diff --git a/src/camera-manager/engine-factory.ts b/src/camera-manager/engine-factory.ts index 7aab5ed1..61dd5901 100644 --- a/src/camera-manager/engine-factory.ts +++ b/src/camera-manager/engine-factory.ts @@ -66,7 +66,7 @@ export class CameraManagerEngineFactory { engine = Engine.MotionEye; } else if (cameraConfig.engine === 'generic') { engine = Engine.Generic; - } else if (cameraConfig.engine === 'auto') { + } else { const cameraEntity = getCameraEntityFromConfig(cameraConfig); if (cameraEntity) { diff --git a/src/camera-manager/range.ts b/src/camera-manager/range.ts index c358395b..e680a5e1 100644 --- a/src/camera-manager/range.ts +++ b/src/camera-manager/range.ts @@ -58,8 +58,8 @@ export class ExpiringMemoryRangeSet } public add(range: ExpiringRange): void { - this._expireOldRanges(); this._ranges.push(range); + this._expireOldRanges(); } protected _expireOldRanges(): void { @@ -95,26 +95,25 @@ export const compressRanges = ( ranges = orderBy(ranges, (range) => range.start, 'asc'); let current: Range | null = null; - for (let i = 0; i < ranges.length; ++i) { - const item = ranges[i]; - const itemStartSeconds = - item.start instanceof Date ? item.start.getTime() : item.start; + for (const range of ranges) { + const rangeStartSeconds: number = + range.start instanceof Date ? range.start.getTime() : range.start; if (!current) { - current = { ...item }; + current = { ...range }; continue; } const currentEndSeconds = current.end instanceof Date ? current.end.getTime() : (current.end as number); - if (currentEndSeconds + toleranceSeconds * 1000 >= itemStartSeconds) { - if (item.end > current.end) { - current.end = item.end; + if (currentEndSeconds + toleranceSeconds * 1000 >= rangeStartSeconds) { + if (range.end > current.end) { + current.end = range.end; } } else { compressedRanges.push(current); - current = { ...item }; + current = { ...range }; } } if (current) { diff --git a/src/components/carousel.ts b/src/components/carousel.ts index 59a43c87..1b83b78c 100644 --- a/src/components/carousel.ts +++ b/src/components/carousel.ts @@ -1,5 +1,3 @@ -import EmblaCarousel, { EmblaCarouselType, EmblaOptionsType } from 'embla-carousel'; -import { EmblaNodesType } from 'embla-carousel/components'; import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins'; import { CSSResultGroup, @@ -11,16 +9,12 @@ import { } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { Ref, createRef, ref } from 'lit/directives/ref.js'; -import isEqual from 'lodash-es/isEqual'; -import throttle from 'lodash-es/throttle'; import carouselStyle from '../scss/carousel.scss'; import { TransitionEffect } from '../types'; -import { dispatchFrigateCardEvent, isHTMLElement } from '../utils/basic.js'; - -export interface CarouselSelect { - index: number; - element: HTMLElement; -} +import { + CarouselController, + CarouselDirection, +} from '../utils/embla/carousel-controller'; export type EmblaCarouselPlugins = CreatePluginType< LoosePluginType, @@ -30,269 +24,91 @@ export type EmblaCarouselPlugins = CreatePluginType< @customElement('frigate-card-carousel') export class FrigateCardCarousel extends LitElement { @property({ attribute: true, reflect: true }) - public direction: 'vertical' | 'horizontal' = 'horizontal'; - - @property({ attribute: false }) - public carouselOptions?: EmblaOptionsType; - - @property({ attribute: false }) - public carouselPlugins?: EmblaCarouselPlugins; - - @property({ attribute: false }) - public selected = 0; + public direction: CarouselDirection = 'horizontal'; @property({ attribute: true }) public transitionEffect?: TransitionEffect; - protected _refSlot: Ref = createRef(); + @property({ attribute: false }) + public loop?: boolean; - protected _carousel?: EmblaCarouselType; + @property({ attribute: false }) + public dragFree?: boolean; - // Whether the carousel is actively scrolling. - protected _scrolling = false; + @property({ attribute: false }) + public dragEnabled = true; - // Whether to reinit the carousel when it settles. - protected _reInitOnSettle = false; + @property({ attribute: false }) + public plugins?: EmblaCarouselPlugins; - protected _carouselReInitInPlace = throttle( - this._carouselReInitInPlaceInternal.bind(this), - 500, - { trailing: true }, - ); + @property({ attribute: false }) + public selected = 0; + + protected _refParent: Ref = createRef(); + protected _refRoot: Ref = createRef(); + protected _carousel: CarouselController | null = null; connectedCallback(): void { super.connectedCallback(); - // Guarantee a re-render if the component is reconnected. See note in - // disconnectedCallback(). + // Guarantee recreation of carousel if the component is reconnected. this.requestUpdate(); } - /** - * Component disconnected callback. - */ disconnectedCallback(): void { // Destroy the carousel when the component is disconnected, which forces the // plugins (which may have registered event handlers) to also be destroyed. // The carousel will automatically reconstruct if the component is re-rendered. - this._destroyCarousel(); + this._carousel?.destroy(); super.disconnectedCallback(); } - /** - * Destroy the carousel if certain properties change. - * @param changedProps The changed properties - */ protected willUpdate(changedProps: PropertyValues): void { - const destroyProperties = [ - 'direction', - 'carouselOptions', - 'carouselPlugins', - ] as const; + if (changedProps.has('direction')) { + this.setAttribute('direction', this.direction); + } + + const destroyProperties = ['direction', 'dragFree', 'transitionEffect'] as const; if (destroyProperties.some((prop) => changedProps.has(prop))) { - this._destroyCarousel(); - } - } - - /** - * Get the selected slide. - * @returns A CarouselSelect object (index & element). - */ - public getCarouselSelected(slide?: number): CarouselSelect | null { - const index = slide ?? this._carousel?.selectedScrollSnap(); - const element = - index !== undefined ? this._carousel?.slideNodes()[index] ?? null : null; - if (index !== undefined && element) { - return { - index: index, - element: element, - }; - } - return null; - } - - /** - * Get the carousel. - */ - public carousel(): EmblaCarouselType | null { - return this._carousel ?? null; - } - - /** - * ReInit the carousel but stay on the current slide. - */ - protected _carouselReInitInPlaceInternal(): void { - const carouselReInit = (options?: EmblaOptionsType): void => { - // Allow the browser a moment to paint components that are inflight, to - // ensure accurate measurements are taken during the carousel - // reinitialization. - window.requestAnimationFrame(() => { - this._carousel?.reInit({ ...options }); - }); - }; - - carouselReInit({ - startIndex: this.selected, - }); - } - - /** - * ReInit the carousel when it is safe to do so without disturbing the - * appearance (i.e. cutting off a scroll in progress). - */ - public carouselReInitWhenSafe(): void { - if (this._scrolling) { - this._reInitOnSettle = true; - } else { - this._carouselReInitInPlace(); - } - } - - /** - * The updated lifecycle callback for this element. - * @param changedProperties The properties that were changed in this render. - */ - updated(changedProperties: PropertyValues): void { - super.updated(changedProperties); - - if (!this._carousel) { - this._initCarousel(); - } - - if (changedProperties.has('selected')) { - this._carousel?.scrollTo(this.selected, this.transitionEffect === 'none'); - } - } - - /** - * Destroy the carousel. - * @param options If `savePosition` is set the existing carousel position - * will be saved so it can be restored if the carousel is recreated. - */ - protected _destroyCarousel(): void { - if (this._carousel) { - this._carousel.destroy(); - } - this._carousel = undefined; - } - - protected _getSlideElements(): HTMLElement[] { - return ( - this._refSlot.value?.assignedElements({ flatten: true }).filter(isHTMLElement) ?? - [] - ); - } - - /** - * Initialize the carousel. - */ - protected _initCarousel(): void { - const carouselNode = this.renderRoot.querySelector( - '.embla__viewport', - ) as HTMLElement; - - const nodes: EmblaNodesType = { - root: carouselNode, - // As the slides are slotted, need to explicitly pull them out and pass - // them to Embla. - slides: this._getSlideElements(), - }; - - if (carouselNode && nodes.slides) { - this._carousel = EmblaCarousel( - nodes, - { - axis: this.direction == 'horizontal' ? 'x' : 'y', - speed: 30, - startIndex: this.selected, - ...this.carouselOptions, - }, - this.carouselPlugins, - ); - const selectSlide = (slide?: number): void => { - const selected = this.getCarouselSelected(slide); - if (selected) { - dispatchFrigateCardEvent(this, 'carousel:select', selected); - } - - // Make sure every select causes a refresh to allow for re-paint of the - // next/previous controls. - this.requestUpdate(); - }; - - this._carousel.on( - 'init', - // On initialization selectedScrollSnap() will return 0, even if the - // startIndex during initialization is different, as such we override - // the selected slide as returned by the carousel. This need should be - // verified in future versions of Embla (tested as necessary on v7.0.9). - // Test case: - // - // - Start in `live` view in grid mode. - // - Select any camera that is not the first one. - // - Go to non-grid mode. - // - Go back to grid mode. - // - If successful, thumbnails will load correctly (and the query and - // queryResults in the view will be set vs having been reset in - // `_setViewCameraID` in `live.ts`). - () => selectSlide(this.selected), - ); - this._carousel.on('select', () => selectSlide()); - this._carousel.on('scroll', () => { - this._scrolling = true; - }); - this._carousel.on('settle', () => { - // Reinitialize the carousel if a request to reinitialize was made - // during scrolling (instead the request is handled after the scrolling - // has settled). - this._scrolling = false; - if (this._reInitOnSettle) { - this._reInitOnSettle = false; - this._carouselReInitInPlace(); - } - }); - this._carousel.on('settle', () => { - const selected = this.getCarouselSelected(); - if (selected) { - dispatchFrigateCardEvent(this, 'carousel:settle', selected); - } - }); - } - } - - /** - * Called when the slotted children in the carousel change. - */ - protected _slotChanged(): void { - // Check whether the slotted elements have changed (without this check the - // carousel initializations are duplicated). - if (!isEqual(this._getSlideElements(), this._carousel?.slideNodes())) { - // Cannot just re-init, because the slide elements themselves may have - // changed, and only a carousel init can pass in new (slotted) children. - this._destroyCarousel(); - this.requestUpdate(); + this._carousel?.destroy(); + this._carousel = null; } } protected render(): TemplateResult | void { - const slides = this._refSlot.value?.assignedElements({ flatten: true }) || []; - const showPrevious = this.carouselOptions?.loop || this.selected > 0; - const showNext = this.carouselOptions?.loop || this.selected + 1 < slides.length; - return html`
- ${showPrevious ? html`` : ``} -
+ +
- +
- ${showNext ? html`` : ``} +
`; } - /** - * Get element styles. - */ + protected updated(changedProps: PropertyValues): void { + if (!this._carousel && this._refRoot.value && this._refParent.value) { + this._carousel = new CarouselController( + this._refRoot.value, + this._refParent.value, + { + direction: this.direction, + dragEnabled: this.dragEnabled, + dragFree: this.dragFree, + startIndex: this.selected, + transitionEffect: this.transitionEffect, + loop: this.loop, + plugins: this.plugins, + }, + ); + } + + if (changedProps.has('selected')) { + this._carousel?.selectSlide(this.selected); + } + } + static get styles(): CSSResultGroup { return unsafeCSS(carouselStyle); } diff --git a/src/components/drawer.ts b/src/components/drawer.ts index 0639c707..6ea33139 100644 --- a/src/components/drawer.ts +++ b/src/components/drawer.ts @@ -13,7 +13,7 @@ import { SideDrawer } from 'side-drawer'; import drawerInjectStyle from '../scss/drawer-inject.scss'; import drawerStyle from '../scss/drawer.scss'; import { stopEventFromActivatingCardWideActions } from '../utils/action'; -import { isHoverableDevice } from '../utils/basic'; +import { getChildrenFromElement, isHoverableDevice } from '../utils/basic'; export interface DrawerIcons { open?: string; @@ -67,12 +67,14 @@ export class FrigateCardDrawer extends LitElement { * Called when the slotted children in the drawer change. */ protected _slotChanged(): void { - const elements = this._refSlot.value?.assignedElements({ flatten: true }); + const children = this._refSlot.value + ? getChildrenFromElement(this._refSlot.value) + : []; // Watch all slot children for size changes. this._resizeObserver.disconnect(); - for (const element of elements ?? []) { - this._resizeObserver.observe(element); + for (const child of children) { + this._resizeObserver.observe(child); } this._hideDrawerIfNecessary(); } @@ -86,11 +88,13 @@ export class FrigateCardDrawer extends LitElement { return; } - const elements = this._refSlot.value?.assignedElements({ flatten: true }); + const children = this._refSlot.value + ? getChildrenFromElement(this._refSlot.value) + : null; this.empty = - !elements || - !elements.length || - elements.every((element) => { + !children || + !children.length || + children.every((element) => { const box = element.getBoundingClientRect(); return !box.width || !box.height; }); diff --git a/src/components/embla-plugins/automedia.ts b/src/components/embla-plugins/automedia.ts deleted file mode 100644 index a4f3dbd6..00000000 --- a/src/components/embla-plugins/automedia.ts +++ /dev/null @@ -1,234 +0,0 @@ -import EmblaCarousel, { EmblaCarouselType } from 'embla-carousel'; -import { CreateOptionsType } from 'embla-carousel/components/Options.js'; -import { CreatePluginType } from 'embla-carousel/components/Plugins.js'; -import { - AutoMuteCondition, - AutoPauseCondition, - AutoPlayCondition, - AutoUnmuteCondition, - FrigateCardMediaPlayer, -} from '../../types.js'; - -type OptionsType = CreateOptionsType<{ - playerSelector?: string; - - // Note: Neither play nor unmute will activate on selection. The caller is - // expected to call the `play()` or `unmute()` methods manually when the media - // is actually loaded (and not just when the slide is visible -- the browser - // cannot play media that is not actually loaded yet, e.g. lazy loading). - autoPlayCondition?: AutoPlayCondition; - autoUnmuteCondition?: AutoUnmuteCondition; - autoPauseCondition?: AutoPauseCondition; - autoMuteCondition?: AutoMuteCondition; -}>; - -const defaultOptions: OptionsType = { - active: true, - breakpoints: {}, -}; - -type AutoMediaOptionsType = Partial - -export type AutoMediaType = CreatePluginType< - { - play: () => void; - pause: () => void; - mute: () => void; - unmute: () => void; - }, - AutoMediaOptionsType ->; - -declare module 'embla-carousel/components/Plugins' { - interface EmblaPluginsType { - autoMedia?: AutoMediaType - } -} - -/** - * An Embla plugin to take automated actions on media (e.g. pause, unmute, etc). - * @param userOptions - * @returns - */ -export function AutoMediaPlugin( - userOptions?: AutoMediaOptionsType, -): AutoMediaType { - const optionsHandler = EmblaCarousel.optionsHandler(); - const optionsBase = optionsHandler.merge( - defaultOptions, - AutoMediaPlugin.globalOptions, - ); - - let options: AutoMediaType['options']; - let carousel: EmblaCarouselType; - let slides: HTMLElement[]; - - /** - * Initialize the plugin. - */ - function init(embla: EmblaCarouselType): void { - carousel = embla; - options = optionsHandler.atMedia(self.options); - slides = carousel.slideNodes(); - - // Frigate card media autoplays when the media loads not necessarily when the - // slide is selected, so only pause (and not play/unmute) based on carousel - // events. - carousel.on('destroy', pause); - if ( - options.autoPauseCondition && - ['all', 'unselected'].includes(options.autoPauseCondition) - ) { - carousel.on('select', pausePrevious); - } - carousel.on('destroy', mute); - if ( - options.autoMuteCondition && - ['all', 'unselected'].includes(options.autoMuteCondition) - ) { - carousel.on('select', mutePrevious); - } - - document.addEventListener('visibilitychange', visibilityHandler); - } - - /** - * Destroy the plugin. - */ - function destroy(): void { - carousel.off('destroy', pause); - if ( - options.autoPauseCondition && - ['all', 'unselected'].includes(options.autoPauseCondition) - ) { - carousel.off('select', pausePrevious); - } - carousel.off('destroy', mute); - if ( - options.autoMuteCondition && - ['all', 'unselected'].includes(options.autoMuteCondition) - ) { - carousel.off('select', mutePrevious); - } - - document.removeEventListener('visibilitychange', visibilityHandler); - } - - /** - * Handle document visibility changes. - */ - function visibilityHandler(): void { - if (document.visibilityState === 'hidden') { - if ( - options.autoPauseCondition && - ['all', 'hidden'].includes(options.autoPauseCondition) - ) { - pauseAll(); - } - if ( - options.autoMuteCondition && - ['all', 'hidden'].includes(options.autoMuteCondition) - ) { - muteAll(); - } - } else if (document.visibilityState === 'visible') { - if ( - options.autoPlayCondition && - ['all', 'visible'].includes(options.autoPlayCondition) - ) { - play(); - } - if ( - options.autoUnmuteCondition && - ['all', 'visible'].includes(options.autoUnmuteCondition) - ) { - unmute(); - } - } - } - - /** - * Get the media player from a slide. - * @param slide - * @returns A FrigateCardMediaPlayer object or `null`. - */ - function getPlayer(slide: HTMLElement | undefined): FrigateCardMediaPlayer | null { - return options.playerSelector - ? (slide?.querySelector(options.playerSelector) as FrigateCardMediaPlayer | null) - : null; - } - - /** - * Play the current slide. - */ - function play(): void { - getPlayer(slides[carousel.selectedScrollSnap()])?.play(); - } - - /** - * Pause the current slide. - */ - function pause(): void { - getPlayer(slides[carousel.selectedScrollSnap()])?.pause(); - } - - /** - * Pause the previous slide. - */ - function pausePrevious(): void { - getPlayer(slides[carousel.previousScrollSnap()])?.pause(); - } - - /** - * Pause all slides. - */ - function pauseAll(): void { - for (const slide of slides) { - getPlayer(slide)?.pause(); - } - } - - /** - * Unmute the current slide. - */ - function unmute(): void { - getPlayer(slides[carousel.selectedScrollSnap()])?.unmute(); - } - - /** - * Mute the current slide. - */ - function mute(): void { - getPlayer(slides[carousel.selectedScrollSnap()])?.mute(); - } - - /** - * Mute the previous slide. - */ - function mutePrevious(): void { - getPlayer(slides[carousel.previousScrollSnap()])?.mute(); - } - - /** - * Mute all slides. - */ - function muteAll(): void { - for (const slide of slides) { - getPlayer(slide)?.mute(); - } - } - - const self: AutoMediaType = { - name: 'autoMedia', - options: optionsHandler.merge(optionsBase, userOptions), - init, - destroy, - play, - pause, - mute, - unmute, - }; - return self; -} - -AutoMediaPlugin.globalOptions = undefined; diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 957ce164..25bfd7a0 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -1,6 +1,4 @@ import { HomeAssistant } from 'custom-card-helpers'; -import { EmblaOptionsType } from 'embla-carousel'; -import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures'; import { HassEntity } from 'home-assistant-js-websocket'; import { CSSResultGroup, @@ -13,15 +11,16 @@ import { import { customElement, property, state } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { guard } from 'lit/directives/guard.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { keyed } from 'lit/directives/keyed.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js'; import { CameraManager } from '../../camera-manager/manager.js'; import { CameraConfigs, CameraEndpoints } from '../../camera-manager/types.js'; import { ConditionControllerEpoch, getOverriddenConfig } from '../../conditions.js'; import { localize } from '../../localize/localize.js'; +import basicBlockStyle from '../../scss/basic-block.scss'; import liveCarouselStyle from '../../scss/live-carousel.scss'; import liveProviderStyle from '../../scss/live-provider.scss'; -import basicBlockStyle from '../../scss/basic-block.scss'; import { CameraConfig, CardWideConfig, @@ -37,28 +36,30 @@ import { } from '../../types.js'; import { stopEventFromActivatingCardWideActions } from '../../utils/action.js'; import { contentsChanged } from '../../utils/basic.js'; +import { CarouselSelected } from '../../utils/embla/carousel-controller.js'; +import { AutoLazyLoad } from '../../utils/embla/plugins/auto-lazy-load/auto-lazy-load.js'; +import { AutoMediaActions } from '../../utils/embla/plugins/auto-media-actions/auto-media-actions.js'; +import AutoMediaLoadedInfo from '../../utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.js'; +import AutoSize from '../../utils/embla/plugins/auto-size/auto-size.js'; +import { MediaGridSelected } from '../../utils/media-grid-controller.js'; import { dispatchExistingMediaLoadedInfoAsEvent, dispatchMediaUnloadedEvent, } from '../../utils/media-info.js'; import { updateElementStyleFromMediaLayoutConfig } from '../../utils/media-layout.js'; import { playMediaMutingIfNecessary } from '../../utils/media.js'; +import { Timer } from '../../utils/timer.js'; import { dispatchViewContextChangeEvent, View } from '../../view/view.js'; -import { CarouselSelect, EmblaCarouselPlugins } from '../carousel.js'; -import { - FrigateCardMediaCarousel, - wrapMediaLoadedEventForCarousel, - wrapMediaUnloadedEventForCarousel, -} from '../media-carousel.js'; +import { EmblaCarouselPlugins } from '../carousel.js'; import { dispatchErrorMessageEvent, dispatchMessageEvent } from '../message.js'; import '../next-prev-control.js'; import '../surround.js'; import '../title-control.js'; -import { AutoMediaPlugin } from './../embla-plugins/automedia.js'; -import { Lazyload } from './../embla-plugins/lazyload.js'; -import { ifDefined } from 'lit/directives/if-defined.js'; -import { MediaGridSelected } from '../../utils/media-grid-controller.js'; -import { getDefaultTitleConfigForView } from '../title-control.js'; +import { + FrigateCardTitleControl, + getDefaultTitleConfigForView, + showTitleControlAfterDelay, +} from '../title-control.js'; interface LiveViewContext { // A cameraID override (used for dependencies/substreams to force a different @@ -200,11 +201,6 @@ export class FrigateCardLive extends LitElement { } } - /** - * Determine whether the element should be updated. - * @param _changedProps The changed properties if any. - * @returns `true` if the element should be updated. - */ // eslint-disable-next-line @typescript-eslint/no-unused-vars protected shouldUpdate(_changedProps: PropertyValues): boolean { // Don't process updates if it's in the background and a message was @@ -213,26 +209,16 @@ export class FrigateCardLive extends LitElement { return !this._inBackground || !this._messageReceivedPostRender; } - /** - * Component connected callback. - */ connectedCallback(): void { this._intersectionObserver.observe(this); super.connectedCallback(); } - /** - * Component disconnected callback. - */ disconnectedCallback(): void { super.disconnectedCallback(); this._intersectionObserver.disconnect(); } - /** - * Master render method. - * @returns A rendered template. - */ protected render(): TemplateResult | void { if ( !this.hass || @@ -318,9 +304,6 @@ export class FrigateCardLiveGrid extends LitElement { @property({ attribute: false, hasChanged: contentsChanged }) public liveOverrides?: LiveOverrides; - @property({ attribute: false }) - public inBackground?: boolean; - @property({ attribute: false }) public conditionControllerEpoch?: ConditionControllerEpoch; @@ -342,7 +325,6 @@ export class FrigateCardLiveGrid extends LitElement { .viewFilterCameraID=${cameraID} .nonOverriddenLiveConfig=${this.nonOverriddenLiveConfig} .overriddenLiveConfig=${this.overriddenLiveConfig} - .inBackground=${this.inBackground} .conditionControllerEpoch=${this.conditionControllerEpoch} .liveOverrides=${this.liveOverrides} .cardWideConfig=${this.cardWideConfig} @@ -423,9 +405,6 @@ export class FrigateCardLiveCarousel extends LitElement { @property({ attribute: false, hasChanged: contentsChanged }) public liveOverrides?: LiveOverrides; - @property({ attribute: false }) - public inBackground?: boolean; - @property({ attribute: false }) public conditionControllerEpoch?: ConditionControllerEpoch; @@ -443,38 +422,9 @@ export class FrigateCardLiveCarousel extends LitElement { // Index between camera name and slide number. protected _cameraToSlide: Record = {}; - protected _refMediaCarousel: Ref = createRef(); + protected _titleTimer = new Timer(); + protected _refTitleControl: Ref = createRef(); - /** - * The updated lifecycle callback for this element. - * @param changedProperties The properties that were changed in this render. - */ - updated(changedProperties: PropertyValues): void { - super.updated(changedProperties); - - if (changedProperties.has('inBackground')) { - this.updateComplete.then(async () => { - const frigateCardMediaCarousel = this._refMediaCarousel.value; - if (frigateCardMediaCarousel) { - await frigateCardMediaCarousel.updateComplete; - // If this has changed to be in the background (i.e. preloaded but not - // visible) take the appropriate play/pause/mute/unmute actions. - if (this.inBackground) { - frigateCardMediaCarousel.autoPause(); - frigateCardMediaCarousel.autoMute(); - } else { - frigateCardMediaCarousel.autoPlay(); - frigateCardMediaCarousel.autoUnmute(); - } - } - }); - } - } - - /** - * Get the transition effect to use. - * @returns An TransitionEffect object. - */ protected _getTransitionEffect(): TransitionEffect { return ( this.overriddenLiveConfig?.transition_effect ?? @@ -490,49 +440,19 @@ export class FrigateCardLiveCarousel extends LitElement { return Math.max(0, Array.from(cameraIDs).indexOf(this.view.camera)); } - /** - * Get the Embla options to use. - * @returns An EmblaOptionsType object or undefined for no options. - */ - protected _getOptions(): EmblaOptionsType { - return { - // If the carousel is being filtered to a single cameraID, it is never - // draggable. - draggable: !this.viewFilterCameraID && this.overriddenLiveConfig?.draggable, - loop: true, - }; - } - - /** - * Get the Embla plugins to use. - * @returns A list of EmblaOptionsTypes. - */ protected _getPlugins(): EmblaCarouselPlugins { - const cameraCount = this.viewFilterCameraID - ? 1 - : this.cameraManager?.getStore().getVisibleCameraCount() ?? 0; return [ - // Only enable wheel plugin if there is more than one camera. - ...(cameraCount > 1 - ? [ - WheelGesturesPlugin({ - // Whether the carousel is vertical or horizontal, interpret y-axis wheel - // gestures as scrolling for the carousel. - forceWheelAxis: 'y', - }), - ] - : []), - Lazyload({ + AutoLazyLoad({ ...(this.overriddenLiveConfig?.lazy_load && { lazyLoadCallback: (index, slide) => this._lazyloadOrUnloadSlide('load', index, slide), }), - lazyUnloadCondition: this.overriddenLiveConfig?.lazy_unload, lazyUnloadCallback: (index, slide) => this._lazyloadOrUnloadSlide('unload', index, slide), }), - AutoMediaPlugin({ + AutoMediaLoadedInfo(), + AutoMediaActions({ playerSelector: FRIGATE_CARD_LIVE_PROVIDER, ...(this.overriddenLiveConfig?.auto_play && { autoPlayCondition: this.overriddenLiveConfig.auto_play, @@ -547,6 +467,7 @@ export class FrigateCardLiveCarousel extends LitElement { autoUnmuteCondition: this.overriddenLiveConfig.auto_unmute, }), }), + AutoSize(), ]; } @@ -562,11 +483,6 @@ export class FrigateCardLiveCarousel extends LitElement { return this.overriddenLiveConfig?.lazy_load === false ? null : 0; } - /** - * Get slides to include in the render. - * @returns The slides to include in the render and an index keyed by camera - * name to slide number. - */ protected _getSlides(): [TemplateResult[], Record] { let cameras: CameraConfigs | null = null; if (this.viewFilterCameraID) { @@ -595,7 +511,7 @@ export class FrigateCardLiveCarousel extends LitElement { : this.cameraManager?.getStore().getCameraConfig(liveCameraID); const slide = liveCameraConfig - ? this._renderLive(liveCameraID, liveCameraConfig, slides.length) + ? this._renderLive(liveCameraID, liveCameraConfig) : null; if (slide) { cameraToSlide[cameraID] = slides.length; @@ -605,10 +521,7 @@ export class FrigateCardLiveCarousel extends LitElement { return [slides, cameraToSlide]; } - /** - * Handle the user selecting a new slide in the carousel. - */ - protected _setViewHandler(ev: CustomEvent): void { + protected _setViewHandler(ev: CustomEvent): void { const cameras = this.cameraManager?.getStore().getVisibleCameras(); if (cameras && ev.detail.index !== this._getSelectedCameraIndex()) { this._setViewCameraID(Array.from(cameras.keys())[ev.detail.index]); @@ -631,11 +544,6 @@ export class FrigateCardLiveCarousel extends LitElement { } } - /** - * Lazy load a slide. - * @param _index The slide number to lazy load. - * @param slide The slide to lazy load. - */ protected _lazyloadOrUnloadSlide( action: 'load' | 'unload', _index: number, @@ -649,14 +557,13 @@ export class FrigateCardLiveCarousel extends LitElement { FRIGATE_CARD_LIVE_PROVIDER, ) as FrigateCardLiveProvider | null; if (liveProvider) { - liveProvider.disabled = action !== 'load'; + liveProvider.load = action === 'load'; } } protected _renderLive( cameraID: string, cameraConfig: CameraConfig, - slideIndex: number, ): TemplateResult | void { if ( !this.overriddenLiveConfig || @@ -683,7 +590,7 @@ export class FrigateCardLiveCarousel extends LitElement { return html`
) => { - wrapMediaLoadedEventForCarousel(slideIndex, ev); - }} - @frigate-card:media:unloaded=${(ev: CustomEvent) => { - wrapMediaUnloadedEventForCarousel(slideIndex, ev); - }} >
@@ -728,10 +629,6 @@ export class FrigateCardLiveCarousel extends LitElement { ]; } - /** - * Render the element. - * @returns A template to display to the user. - */ protected render(): TemplateResult | void { if (!this.overriddenLiveConfig || !this.view || !this.hass || !this.cameraManager) { return; @@ -743,6 +640,7 @@ export class FrigateCardLiveCarousel extends LitElement { return; } + const hasMultipleCameras = slides.length > 1; const [prevID, nextID] = this._getCameraIDsOfNeighbors(); const overrideCameraID = (cameraID: string): string => { @@ -776,28 +674,25 @@ export class FrigateCardLiveCarousel extends LitElement { // little later). return html` - { // Fetch the thumbnails after the carousel has settled. dispatchViewContextChangeEvent(this, { thumbnails: { fetch: true } }); }} + @frigate-card:media:loaded=${() => { + if (this._refTitleControl.value) { + showTitleControlAfterDelay(this._refTitleControl.value, this._titleTimer); + } + }} > - + + ${cameraMetadataCurrent && titleConfig + ? html` + ` + : ``} `; } - /** - * Get styles. - */ static get styles(): CSSResultGroup { return unsafeCSS(liveCarouselStyle); } @@ -857,10 +761,11 @@ export class FrigateCardLiveProvider @property({ attribute: false }) public liveConfig?: LiveConfig; - // Whether or not to disable this entity. If `true`, no contents are rendered - // until this attribute is set to `false` (this is useful for lazy loading). + // Whether or not to load the video for this camera. If `false`, no contents + // are rendered until this attribute is set to `true` (this is useful for lazy + // loading). @property({ attribute: true, type: Boolean }) - public disabled = false; + public load = false; // Label that is used for ARIA support and as tooltip. @property({ attribute: false }) @@ -995,8 +900,8 @@ export class FrigateCardLiveProvider * Called before each update. */ protected willUpdate(changedProps: PropertyValues): void { - if (changedProps.has('disabled')) { - if (this.disabled) { + if (changedProps.has('load')) { + if (!this.load) { this._isVideoMediaLoaded = false; dispatchMediaUnloadedEvent(this); } @@ -1051,7 +956,7 @@ export class FrigateCardLiveProvider * @returns A rendered template. */ protected render(): TemplateResult | void { - if (this.disabled || !this.hass || !this.liveConfig || !this.cameraConfig) { + if (!this.load || !this.hass || !this.liveConfig || !this.cameraConfig) { return; } diff --git a/src/components/media-carousel.ts b/src/components/media-carousel.ts deleted file mode 100644 index 6f9e5a82..00000000 --- a/src/components/media-carousel.ts +++ /dev/null @@ -1,440 +0,0 @@ -import { EmblaOptionsType } from 'embla-carousel'; -import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; -import { ifDefined } from 'lit/directives/if-defined.js'; -import { createRef, ref, Ref } from 'lit/directives/ref.js'; -import debounce from 'lodash-es/debounce'; -import mediaCarouselStyle from '../scss/media-carousel.scss'; -import type { - MediaLoadedInfo, - NextPreviousControlConfig, - TitleControlConfig, - TransitionEffect, -} from '../types.js'; -import { dispatchFrigateCardEvent } from '../utils/basic'; -import { - dispatchExistingMediaLoadedInfoAsEvent, - isValidMediaLoadedInfo, -} from '../utils/media-info.js'; -import { Timer } from '../utils/timer'; -import { CarouselSelect, EmblaCarouselPlugins, FrigateCardCarousel } from './carousel'; -import './carousel.js'; -import { AutoMediaType } from './embla-plugins/automedia.js'; -import './next-prev-control.js'; -import { FrigateCardNextPreviousControl } from './next-prev-control.js'; -import { FrigateCardTitleControl } from './title-control.js'; - -interface CarouselMediaLoadedInfo { - slide: number; - mediaLoadedInfo: MediaLoadedInfo; -} - -interface CarouselMediaUnloadedInfo { - slide: number; -} - -/** - * Dispatch a carousel media loaded event. - * @param target The target to send it from. - * @param carouselMediaLoadedInfo The CarouselMediaLoadedInfo. - */ -const dispatchFrigateCardCarouselMediaLoaded = ( - target: EventTarget, - carouselMediaLoadedInfo: CarouselMediaLoadedInfo, -): void => { - dispatchFrigateCardEvent( - target, - 'carousel:media:loaded', - carouselMediaLoadedInfo, - ); -}; - -/** - * Dispatch a carousel media UNloaded event. - * @param target The target to send it from. - * @param carouselMediaUnloadedInfo The CarouselMediaUnloadedInfo. - */ -const dispatchFrigateCardCarouselMediaUnloaded = ( - target: EventTarget, - carouselMediaUnloadedInfo: CarouselMediaUnloadedInfo, -): void => { - dispatchFrigateCardEvent( - target, - 'carousel:media:unloaded', - carouselMediaUnloadedInfo, - ); -}; - -/** - * Turn a MediaLoadedInfo into a CarouselMediaLoadedInfo. - * @param slide The slide number. - * @param event The MediaShowEvent. - */ -export const wrapMediaLoadedEventForCarousel = ( - slide: number, - event: CustomEvent, -) => { - event.stopPropagation(); - dispatchFrigateCardCarouselMediaLoaded(event.composedPath()[0], { - slide: slide, - mediaLoadedInfo: event.detail, - }); -}; - -/** - * Turn a MediaUnloadedInfo into a CarouselMediaUnloadedInfo. - * @param slide The slide number. - * @param event The MediaUnloadedEvent. - */ -export const wrapMediaUnloadedEventForCarousel = ( - slide: number, - event: CustomEvent, -) => { - event.stopPropagation(); - dispatchFrigateCardCarouselMediaUnloaded(event.composedPath()[0], { - slide: slide, - }); -}; - -@customElement('frigate-card-media-carousel') -export class FrigateCardMediaCarousel extends LitElement { - @property({ attribute: false }) - public nextPreviousConfig?: NextPreviousControlConfig; - - @property({ attribute: false }) - public carouselOptions?: EmblaOptionsType; - - @property({ attribute: false }) - public carouselPlugins?: EmblaCarouselPlugins; - - @property({ attribute: false, type: Number }) - public selected = 0; - - @property({ attribute: true }) - public transitionEffect?: TransitionEffect; - - @property({ attribute: false }) - public label?: string; - - @property({ attribute: false }) - public logo?: string; - - @property({ attribute: false }) - public titlePopupConfig?: TitleControlConfig; - - // A "map" from slide number to MediaLoadedInfo object. - protected _mediaLoadedInfo: Record = {}; - protected _nextControlRef: Ref = createRef(); - protected _previousControlRef: Ref = createRef(); - protected _titleControlRef: Ref = createRef(); - protected _titleTimer = new Timer(); - - protected _boundAutoPlayHandler = this.autoPlay.bind(this); - protected _boundAutoUnmuteHandler = this.autoUnmute.bind(this); - protected _boundTitleHandler = this._titleHandler.bind(this); - - // Debounce multiple calls to adapt the container height. - protected _debouncedAdaptContainerHeightToSlide = debounce( - this._adaptContainerHeightToSlide.bind(this), - 1 * 250, - {trailing: true}); - - // This carousel may be resized by Lovelace resizes, window resizes, - // fullscreen, etc. Always call the adaptive height handler when the size - // changes. - protected _slideResizeObserver: ResizeObserver; - protected _intersectionObserver: IntersectionObserver; - - protected _refCarousel: Ref = createRef(); - - constructor() { - super(); - // Need to watch both changes in this element (e.g. caused by a window - // resize or fullscreen change) and changes in the selected slide itself - // (e.g. changing from a progress indicator to a loaded media). - this._slideResizeObserver = new ResizeObserver( - this._reInitAndAdjustHeight.bind(this), - ); - this._intersectionObserver = new IntersectionObserver( - this._intersectionHandler.bind(this), - ); - } - - /** - * Get the underlying carousel. - */ - public frigateCardCarousel(): FrigateCardCarousel | null { - return this._refCarousel.value ?? null; - } - - /** - * Get the AutoMedia plugin (if any). - * @returns The plugin or `null`. - */ - protected _getAutoMediaPlugin(): AutoMediaType | null { - return this.frigateCardCarousel()?.carousel()?.plugins().autoMedia ?? null; - } - - /** - * Play the media on the selected slide. - */ - public autoPlay(): void { - const automediaOptions = this._getAutoMediaPlugin()?.options; - if ( - automediaOptions?.autoPlayCondition && - ['all', 'selected'].includes(automediaOptions?.autoPlayCondition) - ) { - this._getAutoMediaPlugin()?.play(); - } - } - - /** - * Pause the media on the selected slide. - */ - public autoPause(): void { - const automediaOptions = this._getAutoMediaPlugin()?.options; - if ( - automediaOptions?.autoPauseCondition && - ['all', 'selected'].includes(automediaOptions.autoPauseCondition) - ) { - this._getAutoMediaPlugin()?.pause(); - } - } - - /** - * Unmute the media on the selected slide. - */ - public autoUnmute(): void { - const automediaOptions = this._getAutoMediaPlugin()?.options; - if ( - automediaOptions?.autoUnmuteCondition && - ['all', 'selected'].includes(automediaOptions?.autoUnmuteCondition) - ) { - this._getAutoMediaPlugin()?.unmute(); - } - } - - /** - * Mute the media on the selected slide. - */ - public autoMute(): void { - const automediaOptions = this._getAutoMediaPlugin()?.options; - if ( - automediaOptions?.autoMuteCondition && - ['all', 'selected'].includes(automediaOptions?.autoMuteCondition) - ) { - this._getAutoMediaPlugin()?.mute(); - } - } - - /** - * Show the media title after the media loads. - */ - protected _titleHandler(): void { - const show = () => { - this._titleTimer.stop(); - this._titleControlRef.value?.show(); - }; - - if (this._titleControlRef.value?.isVisible()) { - // If it's already visible, update it immediately (but also update it - // after the timer expires to ensure it re-positions if necessary, see - // comment below). - show(); - } - - // Allow a brief pause after the media loads, but before the title is - // displayed. This allows for a pleasant appearance/disappear of the title, - // and allows for the browser to finish rendering the carousel. - this._titleTimer.start(0.5, show); - } - - /** - * Component connected callback. - */ - connectedCallback(): void { - super.connectedCallback(); - - this.addEventListener('frigate-card:media:loaded', this._boundAutoPlayHandler); - this.addEventListener('frigate-card:media:loaded', this._boundAutoUnmuteHandler); - this.addEventListener( - 'frigate-card:media:loaded', - this._debouncedAdaptContainerHeightToSlide, - ); - this.addEventListener('frigate-card:media:loaded', this._boundTitleHandler); - this._intersectionObserver.observe(this); - } - - /** - * Component disconnected callback. - */ - disconnectedCallback(): void { - this.removeEventListener('frigate-card:media:loaded', this._boundAutoPlayHandler); - this.removeEventListener('frigate-card:media:loaded', this._boundAutoUnmuteHandler); - this.removeEventListener( - 'frigate-card:media:loaded', - this._debouncedAdaptContainerHeightToSlide, - ); - this.removeEventListener('frigate-card:media:loaded', this._boundTitleHandler); - this._intersectionObserver.disconnect(); - - this._mediaLoadedInfo = {}; - super.disconnectedCallback(); - } - - /** - * ReInit the carousel and adapt the container height. - */ - protected _reInitAndAdjustHeight(): void { - this.frigateCardCarousel()?.carouselReInitWhenSafe(); - this._debouncedAdaptContainerHeightToSlide(); - } - - /** - * Called when the carousel intersects with the viewport. - * @param entries The IntersectionObserverEntry entries (should be only 1). - */ - protected _intersectionHandler(entries: IntersectionObserverEntry[]): void { - /** - * - If the DOM that contains this carousel changes such that it causes - * slides to entirely appear/disappear (e.g. `display: none` or hidden), - * then the displayed slide sizes will significantly change and the - * carousel will need to be reinitialized. Without this, odd bugs may - * occur for some users in some circumstances causing the carousel to - * appear 'stuck'. - * - Example bug when this reinitialization is not performed: - * https://github.com/dermotduffy/frigate-hass-card/issues/651 - */ - if (entries.some((entry) => entry.isIntersecting)) { - this._reInitAndAdjustHeight(); - } - } - - /** - * Set the the height of the component on media load in case the dimensions - * have changed. This handler is not triggered from carousel events, as it's - * actually the media load/show that will change the dimensions, and that is - * async from carousel actions (e.g. lazy-loaded media). - * - * This component does not use the stock Embla auto-height plugin as that - * resizes the container only on selection rather than media load. - */ - protected _adaptContainerHeightToSlide(): void { - const selected = this.frigateCardCarousel()?.getCarouselSelected(); - if (selected) { - this.style.removeProperty('max-height'); - const height = selected.element.getBoundingClientRect().height; - if (height !== undefined && height > 0) { - this.style.maxHeight = `${height}px`; - } - } - } - - /** - * Fire a media show event when a slide is selected. - */ - protected _dispatchMediaLoadedInfo(selected: CarouselSelect): void { - const slideIndex = selected.index; - if (slideIndex !== undefined && slideIndex in this._mediaLoadedInfo) { - dispatchExistingMediaLoadedInfoAsEvent(this, this._mediaLoadedInfo[slideIndex]); - } - } - - /** - * Handle a media:loaded event that is generated by a child component, saving the - * contents for future use when the relevant slide is actually shown. - * @param slideIndex The relevant slide index. - * @param event The media:loaded event from the child component. - */ - protected _storeMediaLoadedInfo(event: CustomEvent): void { - // Don't allow the inbound event to propagate upwards, that will be - // automatically done at the appropriate time as the slide is shown. - event.stopPropagation(); - const mediaLoadedInfo = event.detail.mediaLoadedInfo; - const slideIndex = event.detail.slide; - - // isValidMediaLoadedInfo is used to prevent saving media info that will be - // rejected upstream (empty 1x1 images will be rejected here). - if (mediaLoadedInfo && isValidMediaLoadedInfo(mediaLoadedInfo)) { - this._mediaLoadedInfo[slideIndex] = mediaLoadedInfo; - if (this.frigateCardCarousel()?.getCarouselSelected()?.index === slideIndex) { - dispatchExistingMediaLoadedInfoAsEvent(this, mediaLoadedInfo); - } - } - } - - /** - * Remove a media loaded info (i.e. a media item has unloaded). - * @param event The CarouselMediaUnloadedInfo event. - */ - protected _removeMediaLoadedInfo(event: CustomEvent): void { - const slideIndex = event.detail.slide; - delete this._mediaLoadedInfo[slideIndex]; - - // If the slide that unloaded is not visible, don't propagate the event upwards. - if (this.frigateCardCarousel()?.getCarouselSelected()?.index !== slideIndex) { - event.stopPropagation(); - } - } - - protected render(): TemplateResult | void { - const selectSlide = (ev: CustomEvent): void => { - this._slideResizeObserver.disconnect(); - const parent = this.getRootNode(); - if (parent && parent instanceof ShadowRoot) { - this._slideResizeObserver.observe(parent.host); - } - - const selected = ev.detail; - this._slideResizeObserver.observe(selected.element); - - // Pass up the media-carousel select event first to allow parents to - // initialize/reset before the media info is dispatched. - dispatchFrigateCardEvent( - this, - 'media-carousel:select', - selected, - ); - - // Dispatch media info. - this._dispatchMediaLoadedInfo(selected); - } - - return html` ) => { - selectSlide(ev); - }} - @frigate-card:carousel:media:loaded=${this._storeMediaLoadedInfo.bind(this)} - @frigate-card:carousel:media:unloaded=${this._removeMediaLoadedInfo.bind(this)} - > - - - - - ${this.label && this.titlePopupConfig - ? html` - ` - : ``}`; - } - - static get styles(): CSSResultGroup { - return unsafeCSS(mediaCarouselStyle); - } -} - -declare global { - interface HTMLElementTagNameMap { - 'frigate-card-media-carousel': FrigateCardMediaCarousel; - } -} diff --git a/src/components/thumbnail-carousel.ts b/src/components/thumbnail-carousel.ts index c7a20351..1248efe0 100644 --- a/src/components/thumbnail-carousel.ts +++ b/src/components/thumbnail-carousel.ts @@ -1,5 +1,3 @@ -import { EmblaOptionsType, EmblaPluginType } from 'embla-carousel'; -import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures'; import { CSSResultGroup, html, @@ -10,18 +8,16 @@ import { } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; -import { createRef, ref, Ref } from 'lit/directives/ref.js'; +import { CameraManager } from '../camera-manager/manager.js'; import thumbnailCarouselStyle from '../scss/thumbnail-carousel.scss'; import { ExtendedHomeAssistant, ThumbnailsControlConfig } from '../types.js'; import { stopEventFromActivatingCardWideActions } from '../utils/action.js'; import { dispatchFrigateCardEvent } from '../utils/basic.js'; -import { View } from '../view/view.js'; +import { CarouselDirection } from '../utils/embla/carousel-controller.js'; import { MediaQueriesResults } from '../view/media-queries-results'; -import { FrigateCardCarousel } from './carousel.js'; -import './thumbnail.js'; +import { View } from '../view/view.js'; import './carousel.js'; -import { ifDefined } from 'lit/directives/if-defined.js'; -import { CameraManager } from '../camera-manager/manager.js'; +import './thumbnail.js'; export interface ThumbnailCarouselTap { queryResults: MediaQueriesResults; @@ -38,83 +34,11 @@ export class FrigateCardThumbnailCarousel extends LitElement { @property({ attribute: false }) public cameraManager?: CameraManager; - protected _refCarousel: Ref = createRef(); - - // Thumbnail carousels can expand (e.g. drawer-based carousels after the main - // media loads). The carousel must be re-initialized in these cases, or the - // dynamic sizing fails (and users can scroll past the end of the carousel). - protected _resizeObserver: ResizeObserver; - @property({ attribute: false }) public config?: ThumbnailsControlConfig; - @property({ attribute: false }) - public selected? = 0; + protected _thumbnailSlides: TemplateResult[] = []; - protected _carouselOptions?: EmblaOptionsType = { - containScroll: 'keepSnaps', - dragFree: true, - }; - - protected _carouselPlugins: EmblaPluginType[] = [ - WheelGesturesPlugin({ - // Whether the carousel is vertical or horizontal, interpret y-axis wheel - // gestures as scrolling for the carousel. - forceWheelAxis: 'y', - }), - ]; - - constructor() { - super(); - this._resizeObserver = new ResizeObserver(this._resizeHandler.bind(this)); - } - - /** - * Handle gallery resize. - */ - protected _resizeHandler(): void { - this._refCarousel.value?.carouselReInitWhenSafe(); - } - - /** - * Component connected callback. - */ - connectedCallback(): void { - super.connectedCallback(); - this._resizeObserver.observe(this); - } - - /** - * Component disconnected callback. - */ - disconnectedCallback(): void { - this._resizeObserver.disconnect(); - super.disconnectedCallback(); - } - - /** - * Get slides to include in the render. - * @returns The slides to include in the render. - */ - protected _getSlides(): TemplateResult[] { - if (!this.view?.query || !this.view.queryResults?.hasResults()) { - return []; - } - - const slides: TemplateResult[] = []; - for (let i = 0; i < this.view.queryResults.getResultsCount(); ++i) { - const thumbnail = this._renderThumbnail(i); - if (thumbnail) { - slides[i] = thumbnail; - } - } - return slides; - } - - /** - * Called when an update will occur. - * @param changedProps The changed properties - */ protected willUpdate(changedProps: PropertyValues): void { if (changedProps.has('config')) { if (this.config?.size) { @@ -128,95 +52,93 @@ export class FrigateCardThumbnailCarousel extends LitElement { } } - if (changedProps.has('selected')) { + const renderProperties = [ + 'cameraManager', + 'config', + 'transitionEffect', + 'view', + ] as const; + if (renderProperties.some((prop) => changedProps.has(prop))) { + this._thumbnailSlides = this._renderSlides(); + } + + if (changedProps.has('view')) { this.style.setProperty( '--frigate-card-carousel-thumbnail-opacity', - this.selected === undefined ? '1.0' : '0.4', + this._getSelectedSlide() === null ? '1.0' : '0.4', ); } } - /** - * Render a given thumbnail. - * @param mediaToRender The media item to render. - * @returns A template or void if the item could not be rendered. - */ - protected _renderThumbnail(index: number): TemplateResult | void { - const media = this.view?.queryResults?.getResult(index) ?? null; - if (!media || !this.view) { - return; - } - - const classes = { - embla__slide: true, - 'slide-selected': this.selected === index, - }; - - const seekTarget = this.view?.context?.mediaViewer?.seek; - return html` { - if (this.view && this.view.queryResults) { - dispatchFrigateCardEvent( - this, - 'thumbnail-carousel:tap', - { - queryResults: this.view.queryResults.clone().selectIndex(index), - }, - ); - } - stopEventFromActivatingCardWideActions(ev); - }} - > - `; + protected _getSelectedSlide(view?: View): number | null { + return (view ?? this.view)?.queryResults?.getSelectedIndex() ?? null; } - /** - * Get the direction of the thumbnail carousel. - * @returns `vertical`, `horizontal` or undefined. - */ - protected _getDirection(): 'horizontal' | 'vertical' | undefined { + protected _renderSlides(): TemplateResult[] { + const slides: TemplateResult[] = []; + const seekTarget = this.view?.context?.mediaViewer?.seek; + const selectedIndex = this._getSelectedSlide(); + + for (const media of this.view?.queryResults?.getResults() ?? []) { + const index = slides.length; + const classes = { + embla__slide: true, + 'slide-selected': selectedIndex === index, + }; + + slides.push(html` { + if (this.view && this.view.queryResults) { + dispatchFrigateCardEvent( + this, + 'thumbnail-carousel:tap', + { + queryResults: this.view.queryResults.clone().selectIndex(index), + }, + ); + } + stopEventFromActivatingCardWideActions(ev); + }} + > + `); + } + return slides; + } + + protected _getDirection(): CarouselDirection | null { if (this.config?.mode === 'left' || this.config?.mode === 'right') { return 'vertical'; } else if (this.config?.mode === 'above' || this.config?.mode === 'below') { return 'horizontal'; } - return undefined; + return null; } - /** - * Render the element. - * @returns A template to display to the user. - */ protected render(): TemplateResult | void { - const slides = this._getSlides(); - if (!slides.length || !this.config || this.config.mode === 'none') { + const direction = this._getDirection(); + if (!this._thumbnailSlides.length || !this.config || !direction) { return; } return html` - ${slides} + ${this._thumbnailSlides} `; } - /** - * Get element styles. - */ static get styles(): CSSResultGroup { return unsafeCSS(thumbnailCarouselStyle); } diff --git a/src/components/title-control.ts b/src/components/title-control.ts index 7bbda1e9..d6423a68 100644 --- a/src/components/title-control.ts +++ b/src/components/title-control.ts @@ -3,12 +3,36 @@ import { customElement, property } from 'lit/decorators.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js'; import titleStyle from '../scss/title-control.scss'; import { TitleControlConfig } from '../types.js'; +import { Timer } from '../utils/timer'; import { View } from '../view/view.js'; type PaperToast = HTMLElement & { opened: boolean; }; +export const showTitleControlAfterDelay = ( + control: FrigateCardTitleControl, + timer: Timer, + delay = 0.5, +): void => { + const show = () => { + timer.stop(); + control.show(); + }; + + if (control.isVisible()) { + // If it's already visible, update it immediately (but also update it + // after the timer expires to ensure it re-positions if necessary, see + // comment below). + show(); + } + + // Allow a brief pause after the media loads, but before the title is + // displayed. This allows for a pleasant appearance/disappear of the title, + // and allows for the browser to finish rendering the carousel. + timer.start(delay, show); +}; + export const getDefaultTitleConfigForView = ( view?: Readonly, baseConfig?: TitleControlConfig, @@ -39,10 +63,6 @@ export class FrigateCardTitleControl extends LitElement { protected _toastRef: Ref = createRef(); - /** - * Master render method. - * @returns A rendered template. - */ protected render(): TemplateResult { if (!this.text || !this.config || this.config.mode == 'none' || !this.fitInto) { return html``; @@ -64,17 +84,10 @@ export class FrigateCardTitleControl extends LitElement { `; } - /** - * Determine if the toast is visible. - * @returns `true` if the toast is visible, `false` otherwise. - */ public isVisible(): boolean { return this._toastRef.value?.opened ?? false; } - /** - * Show the toast. - */ public hide(): void { if (this._toastRef.value) { // Set it to false first, to ensure the timer resets. @@ -82,9 +95,6 @@ export class FrigateCardTitleControl extends LitElement { } } - /** - * Show the toast. - */ public show(): void { if (this._toastRef.value) { // Set it to false first, to ensure the timer resets. @@ -93,9 +103,6 @@ export class FrigateCardTitleControl extends LitElement { } } - /** - * Get element styles. - */ static get styles(): CSSResultGroup { return unsafeCSS(titleStyle); } diff --git a/src/components/viewer.ts b/src/components/viewer.ts index e20244be..1b01f5bd 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -1,5 +1,3 @@ -import { EmblaPluginType } from 'embla-carousel'; -import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures'; import { CSSResultGroup, html, @@ -12,11 +10,15 @@ import { customElement, property } from 'lit/decorators.js'; import { guard } from 'lit/directives/guard.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js'; -import basicBlockStyle from '../scss/basic-block.scss'; import { CameraManager } from '../camera-manager/manager.js'; -import { dispatchMessageEvent, renderMessage, renderProgressIndicator } from '../components/message.js'; +import { + dispatchMessageEvent, + renderMessage, + renderProgressIndicator, +} from '../components/message.js'; import { localize } from '../localize/localize.js'; import '../patches/ha-hls-player'; +import basicBlockStyle from '../scss/basic-block.scss'; import viewerCarouselStyle from '../scss/viewer-carousel.scss'; import viewerProviderStyle from '../scss/viewer-provider.scss'; import viewerStyle from '../scss/viewer.scss'; @@ -36,6 +38,11 @@ import { errorToConsole, setOrRemoveAttribute, } from '../utils/basic.js'; +import { CarouselSelected } from '../utils/embla/carousel-controller.js'; +import { AutoLazyLoad } from '../utils/embla/plugins/auto-lazy-load/auto-lazy-load.js'; +import { AutoMediaActions } from '../utils/embla/plugins/auto-media-actions/auto-media-actions.js'; +import AutoMediaLoadedInfo from '../utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.js'; +import AutoSize from '../utils/embla/plugins/auto-size/auto-size.js'; import { canonicalizeHAURL } from '../utils/ha/index.js'; import { ResolvedMediaCache, resolveMedia } from '../utils/ha/resolved-media.js'; import { MediaGridSelected } from '../utils/media-grid-controller.js'; @@ -57,22 +64,21 @@ import { setControlsOnVideo, } from '../utils/media.js'; import { screenshotMedia } from '../utils/screenshot.js'; +import { Timer } from '../utils/timer'; import { ViewMediaClassifier } from '../view/media-classifier'; import { MediaQueriesClassifier } from '../view/media-queries-classifier'; import { MediaQueriesResults } from '../view/media-queries-results.js'; import { VideoContentType, ViewMedia } from '../view/media.js'; import { View } from '../view/view.js'; -import type { CarouselSelect } from './carousel.js'; -import { AutoMediaPlugin } from './embla-plugins/automedia.js'; -import { Lazyload } from './embla-plugins/lazyload.js'; -import { - FrigateCardMediaCarousel, - wrapMediaLoadedEventForCarousel, -} from './media-carousel.js'; +import type { EmblaCarouselPlugins } from './carousel.js'; import './next-prev-control.js'; import './surround.js'; import './title-control.js'; -import { getDefaultTitleConfigForView } from './title-control.js'; +import { + FrigateCardTitleControl, + getDefaultTitleConfigForView, + showTitleControlAfterDelay, +} from './title-control.js'; export interface MediaViewerViewContext { seek?: Date; @@ -114,10 +120,6 @@ export class FrigateCardViewer extends LitElement { @property({ attribute: false }) public cardWideConfig?: CardWideConfig; - /** - * Master render method. - * @returns A rendered template. - */ protected render(): TemplateResult | void { if ( !this.hass || @@ -186,9 +188,6 @@ export class FrigateCardViewer extends LitElement { `; } - /** - * Get element styles. - */ static get styles(): CSSResultGroup { return unsafeCSS(viewerStyle); } @@ -227,8 +226,10 @@ export class FrigateCardViewerCarousel extends LitElement { @property({ attribute: false }) public selected = 0; - protected _refMediaCarousel: Ref = createRef(); protected _media: ViewMedia[] | null = null; + protected _titleTimer = new Timer(); + protected _refTitleControl: Ref = createRef(); + protected _player: FrigateCardMediaPlayer | null = null; /** * The updated lifecycle callback for this element. @@ -259,47 +260,19 @@ export class FrigateCardViewerCarousel extends LitElement { ); } - /** - * Get the media player on a slide (or current slide if not provided). - * @param slide An optional slide. - * @returns The FrigateCardMediaPlayer or null if not found. - */ - protected _getPlayer(slide?: HTMLElement | null): FrigateCardMediaPlayer | null { - if (!slide) { - slide = this._refMediaCarousel.value - ?.frigateCardCarousel() - ?.getCarouselSelected()?.element; - } - - return ( - (slide?.querySelector( - FRIGATE_CARD_VIEWER_PROVIDER, - ) as unknown as FrigateCardMediaPlayer) ?? null - ); - } - /** * Get the Embla plugins to use. * @returns A list of EmblaOptionsTypes. */ - protected _getPlugins(): EmblaPluginType[] { + protected _getPlugins(): EmblaCarouselPlugins { return [ - // Only enable wheel plugin if there is more than one media item. - ...(this._media && this._media.length > 1 - ? [ - WheelGesturesPlugin({ - // Whether the carousel is vertical or horizontal, interpret y-axis wheel - // gestures as scrolling for the carousel. - forceWheelAxis: 'y', - }), - ] - : []), - Lazyload({ + AutoLazyLoad({ ...(this.viewerConfig?.lazy_load && { lazyLoadCallback: (_index, slide) => this._lazyloadSlide(slide), }), }), - AutoMediaPlugin({ + AutoMediaLoadedInfo(), + AutoMediaActions({ playerSelector: FRIGATE_CARD_VIEWER_PROVIDER, ...(this.viewerConfig?.auto_play && { autoPlayCondition: this.viewerConfig.auto_play, @@ -314,6 +287,7 @@ export class FrigateCardViewerCarousel extends LitElement { autoUnmuteCondition: this.viewerConfig.auto_unmute, }), }), + AutoSize(), ]; } @@ -346,10 +320,6 @@ export class FrigateCardViewerCarousel extends LitElement { }; } - protected _setViewHandler(ev: CustomEvent): void { - this._setViewSelectedIndex(ev.detail.index); - } - protected _setViewSelectedIndex(index: number): void { if (!this._media) { return; @@ -396,7 +366,7 @@ export class FrigateCardViewerCarousel extends LitElement { 'frigate-card-viewer-provider', ) as FrigateCardViewerProvider | null; if (viewerProvider) { - viewerProvider.disabled = false; + viewerProvider.load = true; } } @@ -413,7 +383,7 @@ export class FrigateCardViewerCarousel extends LitElement { for (let i = 0; i < this._media.length; ++i) { const media = this._media[i]; if (media) { - const slide = this._renderMediaItem(media, i); + const slide = this._renderMediaItem(media); if (slide) { slides[i] = slide; } @@ -487,22 +457,24 @@ export class FrigateCardViewerCarousel extends LitElement { ); return html` - ({ - draggable: this.viewerConfig?.draggable ?? true, - }))} - .carouselPlugins=${guard( - [this.viewerConfig, this._media], - this._getPlugins.bind(this), - )} - .label=${selectedMedia.getTitle() ?? undefined} - .logo=${cameraMetadata?.engineLogo} - .titlePopupConfig=${titleConfig ?? undefined} + ) => { + this._setViewSelectedIndex(ev.detail.index); + }} + @frigate-card:media:loaded=${(ev: CustomEvent) => { + if (this._refTitleControl.value) { + showTitleControlAfterDelay(this._refTitleControl.value, this._titleTimer); + } + this._player = ev.detail.player ?? null; + this._seekHandler(); + }} + @frigate-card:media:unloaded=${() => { + this._player = null; + }} > - +
+ ${cameraMetadata && titleConfig + ? html` + ` + : ``} `; } @@ -544,21 +526,20 @@ export class FrigateCardViewerCarousel extends LitElement { */ protected async _seekHandler(): Promise { const seek = this.view?.context?.mediaViewer?.seek; - if (!this.hass || !seek || !this._media || this.selected === null) { + if (!this.hass || !seek || !this._media || this.selected === null || !this._player) { return; } const selectedMedia = this._media[this.selected]; - const player = this._getPlayer(); - if (!selectedMedia || !player) { + if (!selectedMedia) { return; } const seekTimeInMedia = selectedMedia.includesTime(seek); setOrRemoveAttribute(this, !seekTimeInMedia, 'unseekable'); - if (!seekTimeInMedia && !player.isPaused()) { - player.pause(); - } else if (seekTimeInMedia && player.isPaused()) { - player.play(); + if (!seekTimeInMedia && !this._player.isPaused()) { + this._player.pause(); + } else if (seekTimeInMedia && this._player.isPaused()) { + this._player.play(); } const seekTime = @@ -566,17 +547,11 @@ export class FrigateCardViewerCarousel extends LitElement { null; if (seekTime !== null) { - player.seek(seekTime); + this._player.seek(seekTime); } } - /** - * Render a single media item in the viewer carousel. - * @param media The ViewMedia to render. - * @param index The (slide|queryResult) index of the item to render. - * @returns A rendered template. - */ - protected _renderMediaItem(media: ViewMedia, index: number): TemplateResult | null { + protected _renderMediaItem(media: ViewMedia): TemplateResult | null { if (!this.hass || !this.view || !this.viewerConfig) { return null; } @@ -589,11 +564,8 @@ export class FrigateCardViewerCarousel extends LitElement { .viewerConfig=${this.viewerConfig} .resolvedMediaCache=${this.resolvedMediaCache} .cameraManager=${this.cameraManager} - .disabled=${this.viewerConfig.lazy_load} + .load=${!this.viewerConfig.lazy_load} .cardWideConfig=${this.cardWideConfig} - @frigate-card:media:loaded=${(e: CustomEvent) => { - wrapMediaLoadedEventForCarousel(index, e); - }} >
`; } @@ -715,10 +687,11 @@ export class FrigateCardViewerProvider @property({ attribute: false }) public resolvedMediaCache?: ResolvedMediaCache; - // Whether or not to disable this entity. If `true`, no contents are rendered - // until this attribute is set to `false` (this is useful for lazy loading). + // Whether or not to load the viewer media. If `false`, no contents are + // rendered until this attribute is set to `true` (this is useful for lazy + // loading). @property({ attribute: false }) - public disabled = false; + public load = false; @property({ attribute: false }) public cameraManager?: CameraManager; @@ -865,7 +838,7 @@ export class FrigateCardViewerProvider const mediaContentID = this.media ? this.media.getContentID() : null; if ( - (changedProps.has('disabled') || + (changedProps.has('load') || changedProps.has('media') || changedProps.has('viewerConfig') || changedProps.has('resolvedMediaCache') || @@ -873,7 +846,7 @@ export class FrigateCardViewerProvider this.hass && mediaContentID && !this.resolvedMediaCache?.has(mediaContentID) && - (!this.viewerConfig?.lazy_load || !this.disabled) + (!this.viewerConfig?.lazy_load || this.load) ) { resolveMedia(this.hass, mediaContentID, this.resolvedMediaCache).then(() => { this.requestUpdate(); @@ -897,7 +870,7 @@ export class FrigateCardViewerProvider } protected render(): TemplateResult | void { - if (this.disabled || !this.media || !this.hass || !this.view || !this.viewerConfig) { + if (!this.load || !this.media || !this.hass || !this.view || !this.viewerConfig) { return; } diff --git a/src/scss/carousel.scss b/src/scss/carousel.scss index 167146a8..2ea19de8 100644 --- a/src/scss/carousel.scss +++ b/src/scss/carousel.scss @@ -2,6 +2,9 @@ display: block; height: 100%; width: 100%; + + // Keep carousel controls relative to the media carousel itself. + position: relative; } .embla { diff --git a/src/scss/live-carousel.scss b/src/scss/live-carousel.scss index d4dafaf1..81c26c13 100644 --- a/src/scss/live-carousel.scss +++ b/src/scss/live-carousel.scss @@ -1,9 +1,13 @@ +:host { + --video-max-height: none; +} + // If the carousel has an unselected attribute set on it, do not let the // pointer interact (e.g. hover, scroll) with underlying elements. This is used // when the carousel is part of a media-grid. Without this next/prev controls // will enlarge on hover, and the wheel-gestures plugin may block scrolling. // See matching in viewer-carousel.scss . -:host([unselected]) frigate-card-media-carousel { +:host([unselected]) frigate-card-carousel { pointer-events: none; } diff --git a/src/scss/live-ha.scss b/src/scss/live-ha.scss index a9b9a68b..f0f64c07 100644 --- a/src/scss/live-ha.scss +++ b/src/scss/live-ha.scss @@ -2,6 +2,4 @@ width: 100%; height: 100%; display: block; - - --video-max-height: none; } \ No newline at end of file diff --git a/src/scss/media-carousel.scss b/src/scss/media-carousel.scss deleted file mode 100644 index 45964ad6..00000000 --- a/src/scss/media-carousel.scss +++ /dev/null @@ -1,9 +0,0 @@ -:host { - display: block; - width: 100%; - height: 100%; - --video-max-height: none; - - // Keep the controls relative to the media carousel itself. - position: relative; -} diff --git a/src/scss/viewer-carousel.scss b/src/scss/viewer-carousel.scss index b7bc6bfb..5d4a4501 100644 --- a/src/scss/viewer-carousel.scss +++ b/src/scss/viewer-carousel.scss @@ -1,6 +1,8 @@ :host { // Center unseekable icon. position: relative; + + --video-max-height: none; } // If the carousel has an unselected attribute set on it, do not let the @@ -8,17 +10,16 @@ // when the carousel is part of a media-grid. Without this next/prev controls // will enlarge on hover, and the wheel-gestures plugin may block scrolling. // See matching in live-carousel.scss . -:host([unselected]) frigate-card-media-carousel, -:host([unselected]) .seek-warning -{ +:host([unselected]) frigate-card-carousel, +:host([unselected]) .seek-warning { pointer-events: none; } -:host([unseekable]) frigate-card-media-carousel { +:host([unseekable]) frigate-card-carousel { filter: brightness(50%); } :host([unseekable]) .seek-warning { - display: block + display: block; } .seek-warning { diff --git a/src/utils/basic.ts b/src/utils/basic.ts index 51efa4cc..7209771a 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -232,3 +232,11 @@ export const isTruthy = (x: T | false | undefined | null | '' | 0): x is T => */ export const isHTMLElement = (element: unknown): element is HTMLElement => element instanceof HTMLElement; + +export const getChildrenFromElement = (parent: HTMLElement): HTMLElement[] => { + const children = + parent instanceof HTMLSlotElement + ? parent.assignedElements({ flatten: true }) + : [...parent.children]; + return children.filter(isHTMLElement); +}; diff --git a/src/utils/camera.ts b/src/utils/camera.ts index a9b8c6d7..497d9355 100644 --- a/src/utils/camera.ts +++ b/src/utils/camera.ts @@ -65,8 +65,6 @@ export function getAllDependentCameras( } } }; - if (cameraID) { - getDependentCameras(cameraID); - } + getDependentCameras(cameraID); return cameraIDs; } diff --git a/src/utils/embla/carousel-controller.ts b/src/utils/embla/carousel-controller.ts new file mode 100644 index 00000000..acfb4849 --- /dev/null +++ b/src/utils/embla/carousel-controller.ts @@ -0,0 +1,178 @@ +import EmblaCarousel, { EmblaCarouselType } from 'embla-carousel'; +import { WheelGesturesPlugin } from 'embla-carousel-wheel-gestures'; +import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins'; +import isEqual from 'lodash-es/isEqual'; +import { TransitionEffect } from '../../types'; +import { dispatchFrigateCardEvent, getChildrenFromElement } from '../basic.js'; + +export interface CarouselSelected { + index: number; + element: HTMLElement; +} + +type EmblaCarouselPlugins = CreatePluginType>[]; + +export type CarouselDirection = 'vertical' | 'horizontal'; + +export class CarouselController { + protected _parent: HTMLElement; + protected _root: HTMLElement; + protected _direction: CarouselDirection; + protected _startIndex: number; + protected _transitionEffect: TransitionEffect; + protected _loop: boolean; + protected _dragFree: boolean; + protected _draggable: boolean; + + protected _plugins: EmblaCarouselPlugins; + protected _carousel: EmblaCarouselType; + + protected _mutationObserver = new MutationObserver( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + (_mutations: MutationRecord[], _observer: MutationObserver) => + this._refreshCarouselContents(), + ); + + constructor( + root: HTMLElement, + parent: HTMLElement, + options?: { + direction?: CarouselDirection; + transitionEffect?: TransitionEffect; + startIndex?: number; + loop?: boolean; + dragEnabled?: boolean; + dragFree?: boolean; + plugins?: EmblaCarouselPlugins; + }, + ) { + this._root = root; + this._parent = parent; + this._direction = options?.direction ?? 'horizontal'; + this._transitionEffect = options?.transitionEffect ?? 'slide'; + this._startIndex = options?.startIndex ?? 0; + this._dragFree = options?.dragFree ?? false; + this._loop = options?.loop ?? false; + this._draggable = options?.dragEnabled ?? true; + this._plugins = options?.plugins ?? []; + + this._carousel = this._createCarousel(getChildrenFromElement(this._parent)); + + // Need to separately listen for slotchanges since mutation observer will + // not be called for shadom DOM slotted changes. + if (parent instanceof HTMLSlotElement) { + parent.addEventListener('slotchange', this._refreshCarouselContents); + } + this._mutationObserver.observe(this._parent, { childList: true }); + } + + public destroy() { + if (this._parent instanceof HTMLSlotElement) { + this._parent.removeEventListener('slotchange', this._refreshCarouselContents); + } + this._mutationObserver.disconnect(); + this._carousel.destroy(); + } + + public getSlide(index: number): HTMLElement | null { + return this._carousel.slideNodes()[index] ?? null; + } + + public getSelectedSlide(): HTMLElement | null { + return this.getSlide(this.getSelectedIndex()); + } + + public getSelectedIndex(): number { + return this._carousel.selectedScrollSnap(); + } + + public selectSlide(index: number): void { + this._carousel.scrollTo(index, this._transitionEffect === 'none'); + } + + protected _refreshCarouselContents = (): void => { + const newSlides = getChildrenFromElement(this._parent); + const slidesChanged = !isEqual(this._carousel.slideNodes(), newSlides); + if (slidesChanged) { + this._carousel.destroy(); + this._carousel = this._createCarousel(newSlides); + } + }; + + protected _createCarousel(slides: HTMLElement[]): EmblaCarouselType { + const carousel = EmblaCarousel( + this._root, + { + slides: slides, + + axis: this._direction === 'horizontal' ? 'x' : 'y', + duration: 20, + startIndex: this._startIndex, + dragFree: this._dragFree, + loop: this._loop, + + containScroll: 'trimSnaps', + + // This controller manages slide changes (including shadow DOM + // assignments, which the stock watcher does not handle). + watchSlides: false, + + // We use the auto-size plugin to manage resizes without carousel resets + // mid-scroll. + watchResize: false, + watchDrag: this._draggable, + }, + [ + ...this._plugins, + ...(slides.length > 1 + ? [ + WheelGesturesPlugin({ + // Whether the carousel is vertical or horizontal, interpret y-axis wheel + // gestures as scrolling for the carousel. + forceWheelAxis: 'y', + }), + ] + : []), + ], + ); + + const getCarouselSelectedObject = (): CarouselSelected | null => { + const selectedIndex = this.getSelectedIndex(); + const slide = this.getSlide(selectedIndex); + + if (selectedIndex !== null && slide) { + return { + index: selectedIndex, + element: slide, + }; + } + return null; + }; + + const selectSlide = (): void => { + const carouselSelected = getCarouselSelectedObject(); + if (carouselSelected) { + dispatchFrigateCardEvent( + this._parent, + 'carousel:select', + carouselSelected, + ); + } + }; + + carousel.on('init', () => selectSlide()); + carousel.on('select', () => selectSlide()); + carousel.on('settle', () => { + const carouselSelected = getCarouselSelectedObject(); + if (carouselSelected) { + dispatchFrigateCardEvent( + this._parent, + 'carousel:settle', + carouselSelected, + ); + } + }); + + return carousel; + } +} diff --git a/src/components/embla-plugins/lazyload.ts b/src/utils/embla/plugins/auto-lazy-load/auto-lazy-load.ts similarity index 57% rename from src/components/embla-plugins/lazyload.ts rename to src/utils/embla/plugins/auto-lazy-load/auto-lazy-load.ts index 311ee6cc..2941f983 100644 --- a/src/components/embla-plugins/lazyload.ts +++ b/src/utils/embla/plugins/auto-lazy-load/auto-lazy-load.ts @@ -1,17 +1,26 @@ +import { EmblaCarouselType, EmblaEventType } from 'embla-carousel'; import { CreateOptionsType } from 'embla-carousel/components/Options'; -import { CreatePluginType } from 'embla-carousel/components/Plugins'; -import EmblaCarousel, { EmblaCarouselType, EmblaEventType } from 'embla-carousel'; -import { LazyUnloadCondition } from '../../types'; +import { OptionsHandlerType } from 'embla-carousel/components/OptionsHandler'; +import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins'; +import { LazyUnloadCondition } from '../../../../types'; + +declare module 'embla-carousel/components/Plugins' { + interface EmblaPluginsType { + lazyload?: AutoLazyLoadType; + } +} type OptionsType = CreateOptionsType<{ // Number of slides to lazyload left/right of selected (0 == only selected // slide). - lazyLoadCount?: number; + lazyLoadCount: number; lazyUnloadCondition?: LazyUnloadCondition; lazyLoadCallback?: (index: number, slide: HTMLElement) => void; lazyUnloadCallback?: (index: number, slide: HTMLElement) => void; }>; +type AutoLazyLoadOptionsType = Partial; +type AutoLazyLoadType = CreatePluginType; const defaultOptions: OptionsType = { active: true, @@ -19,74 +28,54 @@ const defaultOptions: OptionsType = { lazyLoadCount: 0, }; -type LazyloadOptionsType = Partial; - -type LazyloadType = CreatePluginType< - { - hasLazyloaded(index: number): boolean; - }, - LazyloadOptionsType ->; - -declare module 'embla-carousel/components/Plugins' { - interface EmblaPluginsType { - lazyload?: LazyloadType; - } -} - -export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType { - const optionsHandler = EmblaCarousel.optionsHandler(); - const optionsBase = optionsHandler.merge(defaultOptions, Lazyload.globalOptions); - let options: LazyloadType['options']; - - let carousel: EmblaCarouselType; +export function AutoLazyLoad( + userOptions: AutoLazyLoadOptionsType = {}, +): AutoLazyLoadType { + let options: OptionsType; + let emblaApi: EmblaCarouselType; let slides: HTMLElement[]; const lazyLoadedSlides: Set = new Set(); - const loadEvents: EmblaEventType[] = ['init', 'select', 'resize']; + const loadEvents: EmblaEventType[] = ['init', 'select']; const unloadEvents: EmblaEventType[] = ['select']; - /** - * Initialize the plugin. - */ - function init(embla: EmblaCarouselType): void { - carousel = embla; - options = optionsHandler.atMedia(self.options); - slides = carousel.slideNodes(); + function init( + emblaApiInstance: EmblaCarouselType, + optionsHandler: OptionsHandlerType, + ): void { + const { mergeOptions, optionsAtMedia } = optionsHandler; + const allOptions = mergeOptions(defaultOptions, userOptions); + options = optionsAtMedia(allOptions); + + emblaApi = emblaApiInstance; + slides = emblaApi.slideNodes(); if (options.lazyLoadCallback) { - loadEvents.forEach((evt) => carousel.on(evt, lazyLoadHandler)); + loadEvents.forEach((evt) => emblaApi.on(evt, lazyLoadHandler)); } if ( options.lazyUnloadCallback && options.lazyUnloadCondition && ['all', 'unselected'].includes(options.lazyUnloadCondition) ) { - unloadEvents.forEach((evt) => carousel.on(evt, lazyUnloadPreviousHandler)); + unloadEvents.forEach((evt) => emblaApi.on(evt, lazyUnloadPreviousHandler)); } document.addEventListener('visibilitychange', visibilityHandler); } - /** - * Destroy the plugin. - */ function destroy(): void { if (options.lazyLoadCallback) { - loadEvents.forEach((evt) => carousel.off(evt, lazyLoadHandler)); + loadEvents.forEach((evt) => emblaApi.off(evt, lazyLoadHandler)); } if (options.lazyUnloadCallback) { - unloadEvents.forEach((evt) => carousel.off(evt, lazyUnloadPreviousHandler)); + unloadEvents.forEach((evt) => emblaApi.off(evt, lazyUnloadPreviousHandler)); } document.removeEventListener('visibilitychange', visibilityHandler); } - /** - * Handle document visibility changes. - */ function visibilityHandler(): void { if ( document.visibilityState === 'hidden' && - options.lazyUnloadCallback && options.lazyUnloadCondition && ['all', 'hidden'].includes(options.lazyUnloadCondition) ) { @@ -96,21 +85,13 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType { } } - /** - * Determine if a slide index has been lazily loaded. - * @param index Slide index. - * @returns `true` if the slide has been lazily loaded. - */ function hasLazyloaded(index: number): boolean { return lazyLoadedSlides.has(index); } - /** - * Lazily load media in the carousel. - */ function lazyLoadHandler(): void { - const lazyLoadCount = options.lazyLoadCount ?? 0; - const currentIndex = carousel.selectedScrollSnap(); + const lazyLoadCount = options.lazyLoadCount; + const currentIndex = emblaApi.selectedScrollSnap(); const slidesToLoad = new Set(); // Lazily load 'count' slides on either side of the slides in view. @@ -130,9 +111,6 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType { }); } - /** - * Lazily unload all media in the carousel. - */ function lazyUnloadAllHandler(): void { lazyLoadedSlides.forEach((index) => { if (options.lazyUnloadCallback) { @@ -142,11 +120,8 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType { }); } - /** - * Lazily unload the previously selected media in the carousel. - */ function lazyUnloadPreviousHandler(): void { - const index = carousel.previousScrollSnap(); + const index = emblaApi.previousScrollSnap(); if (hasLazyloaded(index) && options.lazyUnloadCallback) { options.lazyUnloadCallback(index, slides[index]); @@ -154,14 +129,11 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType { } } - const self: LazyloadType = { - name: 'lazyload', - options: optionsHandler.merge(optionsBase, userOptions), + const self: AutoLazyLoadType = { + name: 'autoLazyLoad', + options: userOptions, init, destroy, - hasLazyloaded, }; return self; } - -Lazyload.globalOptions = undefined; diff --git a/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts b/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts new file mode 100644 index 00000000..fbb3f3cf --- /dev/null +++ b/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts @@ -0,0 +1,232 @@ +import { EmblaCarouselType } from 'embla-carousel'; +import { CreateOptionsType } from 'embla-carousel/components/Options.js'; +import { OptionsHandlerType } from 'embla-carousel/components/OptionsHandler.js'; +import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins.js'; +import { + AutoMuteCondition, + AutoPauseCondition, + AutoPlayCondition, + AutoUnmuteCondition, + FrigateCardMediaPlayer, +} from '../../../../types.js'; + +declare module 'embla-carousel/components/Plugins' { + interface EmblaPluginsType { + autoMediaActions?: AutoMediaActionsType; + } +} + +type OptionsType = CreateOptionsType<{ + playerSelector?: string; + + autoPlayCondition?: AutoPlayCondition; + autoUnmuteCondition?: AutoUnmuteCondition; + autoPauseCondition?: AutoPauseCondition; + autoMuteCondition?: AutoMuteCondition; +}>; +export type AutoMediaActionsOptionsType = Partial; + +const defaultOptions: OptionsType = { + active: true, + breakpoints: {}, +}; + +export type AutoMediaActionsType = CreatePluginType< + LoosePluginType, + AutoMediaActionsOptionsType +>; + +export function AutoMediaActions( + userOptions: AutoMediaActionsOptionsType = {}, +): AutoMediaActionsType { + let options: OptionsType; + let emblaApi: EmblaCarouselType; + let slides: HTMLElement[]; + let hadInitialIntersectionCall: boolean | null = false; + + const intersectionObserver: IntersectionObserver = new IntersectionObserver( + intersectionHandler, + ); + + function init( + emblaApiInstance: EmblaCarouselType, + optionsHandler: OptionsHandlerType, + ): void { + emblaApi = emblaApiInstance; + + const { mergeOptions, optionsAtMedia } = optionsHandler; + options = optionsAtMedia(mergeOptions(defaultOptions, userOptions)); + + slides = emblaApi.slideNodes(); + + if ( + options.autoPlayCondition && + ['all', 'selected'].includes(options.autoPlayCondition) + ) { + // Auto play when the media loads not necessarily when the slide is + // selected (to allow for lazyloading). + emblaApi.containerNode().addEventListener('frigate-card:media:loaded', play); + } + + if ( + options.autoUnmuteCondition && + ['all', 'selected'].includes(options.autoUnmuteCondition) + ) { + // Auto unmute when the media loads not necessarily when the slide is + // selected (to allow for lazyloading). + emblaApi.containerNode().addEventListener('frigate-card:media:loaded', unmute); + } + + if ( + options.autoPauseCondition && + ['all', 'unselected'].includes(options.autoPauseCondition) + ) { + emblaApi.on('select', pausePrevious); + } + + if ( + options.autoMuteCondition && + ['all', 'unselected'].includes(options.autoMuteCondition) + ) { + emblaApi.on('select', mutePrevious); + } + + emblaApi.on('destroy', pause); + emblaApi.on('destroy', mute); + + document.addEventListener('visibilitychange', visibilityHandler); + intersectionObserver.observe(emblaApi.containerNode()); + } + + function destroy(): void { + if ( + options.autoPlayCondition && + ['all', 'selected'].includes(options.autoPlayCondition) + ) { + emblaApi.containerNode().removeEventListener('frigate-card:media:loaded', play); + } + + if ( + options.autoUnmuteCondition && + ['all', 'selected'].includes(options.autoUnmuteCondition) + ) { + emblaApi.containerNode().removeEventListener('frigate-card:media:loaded', unmute); + } + + if ( + options.autoPauseCondition && + ['all', 'unselected'].includes(options.autoPauseCondition) + ) { + emblaApi.off('select', pausePrevious); + } + + if ( + options.autoMuteCondition && + ['all', 'unselected'].includes(options.autoMuteCondition) + ) { + emblaApi.off('select', mutePrevious); + } + + emblaApi.off('destroy', pause); + emblaApi.off('destroy', mute); + + document.removeEventListener('visibilitychange', visibilityHandler); + intersectionObserver.disconnect(); + } + + function actOnVisibilityChange(visible: boolean): void { + if (visible) { + if ( + options.autoPlayCondition && + ['all', 'visible'].includes(options.autoPlayCondition) + ) { + play(); + } + if ( + options.autoUnmuteCondition && + ['all', 'visible'].includes(options.autoUnmuteCondition) + ) { + unmute(); + } + } else { + if ( + options.autoPauseCondition && + ['all', 'hidden'].includes(options.autoPauseCondition) + ) { + pauseAll(); + } + if ( + options.autoMuteCondition && + ['all', 'hidden'].includes(options.autoMuteCondition) + ) { + muteAll(); + } + } + } + + function visibilityHandler(): void { + actOnVisibilityChange(document.visibilityState === 'visible'); + } + + function intersectionHandler(entries: IntersectionObserverEntry[]): void { + if (!hadInitialIntersectionCall) { + hadInitialIntersectionCall = true; + return; + } + + // If the live view is preloaded (i.e. in the background) we may need to + // take media actions, e.g. muting a live stream that is now running in the + // background. + actOnVisibilityChange(entries.some((entry) => entry.isIntersecting)); + } + + function getPlayer(slide: HTMLElement | undefined): FrigateCardMediaPlayer | null { + return options.playerSelector + ? (slide?.querySelector(options.playerSelector) as FrigateCardMediaPlayer | null) + : null; + } + + function play(): void { + getPlayer(slides[emblaApi.selectedScrollSnap()])?.play(); + } + + function pause(): void { + getPlayer(slides[emblaApi.selectedScrollSnap()])?.pause(); + } + + function pausePrevious(): void { + getPlayer(slides[emblaApi.previousScrollSnap()])?.pause(); + } + + function pauseAll(): void { + for (const slide of slides) { + getPlayer(slide)?.pause(); + } + } + + function unmute(): void { + getPlayer(slides[emblaApi.selectedScrollSnap()])?.unmute(); + } + + function mute(): void { + getPlayer(slides[emblaApi.selectedScrollSnap()])?.mute(); + } + + function mutePrevious(): void { + getPlayer(slides[emblaApi.previousScrollSnap()])?.mute(); + } + + function muteAll(): void { + for (const slide of slides) { + getPlayer(slide)?.mute(); + } + } + + const self: AutoMediaActionsType = { + name: 'autoMediaActions', + options: userOptions, + init, + destroy, + }; + return self; +} diff --git a/src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.ts b/src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.ts new file mode 100644 index 00000000..402b9d9e --- /dev/null +++ b/src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.ts @@ -0,0 +1,94 @@ +import { EmblaCarouselType } from 'embla-carousel'; +import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins'; +import { MediaLoadedInfo } from '../../../../types'; +import { + dispatchExistingMediaLoadedInfoAsEvent, + FrigateMediaLoadedEventTarget, +} from '../../../media-info'; +import { LooseOptionsType } from 'embla-carousel/components/Options'; + +declare module 'embla-carousel/components/Plugins' { + interface EmblaPluginsType { + autoMediaLoadedInfo?: AutoMediaLoadedInfoType; + } +} + +type AutoMediaLoadedInfoType = CreatePluginType; + +function AutoMediaLoadedInfo(): AutoMediaLoadedInfoType { + let emblaApi: EmblaCarouselType; + let slides: (HTMLElement & FrigateMediaLoadedEventTarget)[] = []; + const mediaLoadedInfo: MediaLoadedInfo[] = []; + + function init(emblaApiInstance: EmblaCarouselType): void { + emblaApi = emblaApiInstance; + slides = emblaApi.slideNodes(); + + for (const slide of slides) { + slide.addEventListener('frigate-card:media:loaded', mediaLoadedInfoHandler); + slide.addEventListener('frigate-card:media:unloaded', mediaUnloadedInfoHandler); + } + + emblaApi.on('init', slideSelectHandler); + emblaApi.on('select', slideSelectHandler); + } + + function destroy(): void { + for (const slide of slides) { + slide.removeEventListener('frigate-card:media:loaded', mediaLoadedInfoHandler); + slide.removeEventListener('frigate-card:media:unloaded', mediaUnloadedInfoHandler); + } + + emblaApi.off('init', slideSelectHandler); + emblaApi.off('select', slideSelectHandler); + } + + function mediaLoadedInfoHandler(ev: CustomEvent): void { + const eventPath = ev.composedPath(); + + for (const [index, slide] of slides.entries()) { + if (eventPath.includes(slide)) { + mediaLoadedInfo[index] = ev.detail; + if (index !== emblaApi.selectedScrollSnap()) { + ev.stopPropagation(); + } + break; + } + } + } + + function mediaUnloadedInfoHandler(ev: CustomEvent): void { + const eventPath = ev.composedPath(); + + for (const [index, slide] of slides.entries()) { + if (eventPath.includes(slide)) { + delete mediaLoadedInfo[index]; + if (index !== emblaApi.selectedScrollSnap()) { + ev.stopPropagation(); + } + break; + } + } + } + + function slideSelectHandler(): void { + const index = emblaApi.selectedScrollSnap(); + const savedMediaLoadedInfo: MediaLoadedInfo | undefined = mediaLoadedInfo[index]; + if (savedMediaLoadedInfo) { + dispatchExistingMediaLoadedInfoAsEvent( + emblaApi.containerNode(), + savedMediaLoadedInfo, + ); + } + } + + const self: AutoMediaLoadedInfoType = { + name: 'autoMediaLoadedInfo', + options: {}, + init, + destroy, + }; + return self; +} + +export default AutoMediaLoadedInfo; diff --git a/src/utils/embla/plugins/auto-size/auto-size.ts b/src/utils/embla/plugins/auto-size/auto-size.ts new file mode 100644 index 00000000..bfadef33 --- /dev/null +++ b/src/utils/embla/plugins/auto-size/auto-size.ts @@ -0,0 +1,143 @@ +import { EmblaCarouselType } from 'embla-carousel'; +import { LooseOptionsType } from 'embla-carousel/components/Options'; +import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins'; +import { EmblaReInitController } from '../../reinit-controller'; + +declare module 'embla-carousel/components/Plugins' { + interface EmblaPluginsType { + AutoSize?: AutoSizeType; + } +} + +type AutoSizeType = CreatePluginType; +interface SlideDimensions { + height: number; + width: number; +} + +/** + * This plugin offers the following functionality: + * - Auto-height: Automatically resize the container to fit the largest slide on + * view. Unlike the stock `auto-height` plugin, this version will use active + * DOM sizing vs the internal engine sizes to account for pre-reinit resize + * detection. + * - Resize and intersection re-initializing: Re-initialize the carousel on + * slide or container resizes, or container intersection changes. + */ + +function AutoSize(): AutoSizeType { + let emblaApi: EmblaCarouselType; + let reInitController: EmblaReInitController | null = null; + + let previousContainerIntersecting: boolean | null = null; + const previousDimensions: Map = new Map(); + + const resizeObserver: ResizeObserver = new ResizeObserver(resizeHandler); + const intersectionObserver: IntersectionObserver = new IntersectionObserver( + intersectionHandler, + ); + + function init(emblaApiInstance: EmblaCarouselType): void { + emblaApi = emblaApiInstance; + reInitController = new EmblaReInitController(emblaApi); + + intersectionObserver.observe(emblaApi.containerNode()); + resizeObserver.observe(emblaApi.containerNode()); + for (const slide of emblaApi.slideNodes()) { + resizeObserver.observe(slide); + } + + emblaApi.on('settle', setContainerHeight); + } + + function destroy(): void { + intersectionObserver.disconnect(); + resizeObserver.disconnect(); + reInitController?.destroy(); + + emblaApi.off('settle', setContainerHeight); + } + + function intersectionHandler(entries: IntersectionObserverEntry[]): void { + /** + * - If the DOM that contains this carousel changes such that it causes + * slides to entirely appear/disappear (e.g. `display: none` or hidden), + * then the displayed slide sizes will significantly change and the + * carousel will need to be reinitialized. Without this, odd bugs may + * occur for some users in some circumstances causing the carousel to + * appear 'stuck'. + * - Example bug when this reinitialization is not performed: + * https://github.com/dermotduffy/frigate-hass-card/issues/651 + */ + const isContainerIntersectingNow = entries.some((entry) => entry.isIntersecting); + + if (isContainerIntersectingNow !== previousContainerIntersecting) { + // Don't reinitialize on first call (intersectionHandler is always called + // on initial observation). + const callReInit = previousContainerIntersecting !== null; + previousContainerIntersecting = isContainerIntersectingNow; + if (callReInit) { + reInitController?.reinit(); + } + } + } + + function resizeHandler(entries: ResizeObserverEntry[]): void { + let callReInit = false; + + for (const entry of entries) { + const newDimensions: SlideDimensions = { + height: entry.contentRect.height, + width: entry.contentRect.width, + }; + + const oldDimensions = previousDimensions.get(entry.target); + if ( + newDimensions.width && + newDimensions.height && + (oldDimensions?.height !== newDimensions.height || + oldDimensions?.width !== newDimensions.width) + ) { + previousDimensions.set(entry.target, newDimensions); + callReInit = true; + } + } + + if (callReInit) { + reInitController?.reinit(); + } + } + + function setContainerHeight(): void { + const { + slideRegistry, + options: { axis }, + } = emblaApi.internalEngine(); + + if (axis === 'y') { + return; + } + + emblaApi.containerNode().style.removeProperty('max-height'); + + const selectedIndexes = slideRegistry[emblaApi.selectedScrollSnap()]; + const slides = emblaApi.slideNodes(); + const highest = Math.max( + ...selectedIndexes.map((i) => slides[i].getBoundingClientRect().height), + ); + + if (!isNaN(highest) && highest > 0) { + emblaApi.containerNode().style.maxHeight = `${highest}px`; + } + } + + const self: AutoSizeType = { + name: 'autoSize', + options: {}, + init, + destroy, + }; + return self; +} + +export default AutoSize; diff --git a/src/utils/embla/reinit-controller.ts b/src/utils/embla/reinit-controller.ts new file mode 100644 index 00000000..572e0f9c --- /dev/null +++ b/src/utils/embla/reinit-controller.ts @@ -0,0 +1,63 @@ +import { EmblaCarouselType } from 'embla-carousel'; +import debounce from 'lodash-es/debounce'; + +/** + * This class takes care of "safe re-initializing": Only re-initializing the + * carousel when it is not scrolling (unlike the builtin Embla reinitializations, + * e.g. slide additions or resizes). Without this class the carousel is visually + * jarring as in-progress transitions are skipped (vs completing prior to + * reinit). + */ + +export class EmblaReInitController { + protected _emblaApi: EmblaCarouselType; + protected _scrolling = false; + protected _shouldReInitOnScrollStop = false; + + constructor(emblaApi: EmblaCarouselType) { + this._emblaApi = emblaApi; + this._emblaApi.on('scroll', this._scrollingStart); + this._emblaApi.on('settle', this._scrollingStop); + this._emblaApi.on('destroy', this.destroy); + } + + public destroy(): void { + this._emblaApi.off('scroll', this._scrollingStart); + this._emblaApi.off('settle', this._scrollingStop); + this._emblaApi.off('destroy', this.destroy); + } + + public reinit(): void { + if (this._scrolling) { + this._shouldReInitOnScrollStop = true; + } else { + this._debouncedReInit(); + } + } + + protected _scrollingStart = (): void => { + this._scrolling = true; + }; + + protected _scrollingStop = (): void => { + this._scrolling = false; + + if (this._shouldReInitOnScrollStop) { + this._shouldReInitOnScrollStop = false; + this._debouncedReInit(); + } + }; + + protected _debouncedReInit = debounce( + () => { + // Allow the browser a moment to paint components that are inflight, to + // ensure accurate measurements are taken during the carousel + // reinitialization. + this._scrolling = false; + this._shouldReInitOnScrollStop = false; + this._emblaApi?.reInit(); + }, + 200, + { trailing: true }, + ); +} diff --git a/src/utils/media-grid-controller.ts b/src/utils/media-grid-controller.ts index 32787d58..f39f013e 100644 --- a/src/utils/media-grid-controller.ts +++ b/src/utils/media-grid-controller.ts @@ -2,7 +2,7 @@ import isEqual from 'lodash-es/isEqual'; import throttle from 'lodash-es/throttle'; import Masonry from 'masonry-layout'; import { MediaLoadedInfo, ViewDisplayConfig } from '../types'; -import { dispatchFrigateCardEvent, setOrRemoveAttribute } from './basic'; +import { dispatchFrigateCardEvent, getChildrenFromElement, setOrRemoveAttribute } from './basic'; import { FrigateMediaLoadedEventTarget, dispatchExistingMediaLoadedInfoAsEvent, @@ -144,20 +144,11 @@ export class MediaGridController { } protected _calculateGridContentsFromHost = (): void => { - let childrenElements: Element[]; - - if (this._host instanceof HTMLSlotElement) { - childrenElements = this._host.assignedElements(); - } else { - childrenElements = [...this._host.children]; - } - + const children = getChildrenFromElement(this._host); const gridContents: MediaGridContents = new Map(); - for (const child of childrenElements) { - if (child instanceof HTMLElement) { - const id = child.getAttribute(this._idAttribute) || String(gridContents.size); - gridContents.set(id, child); - } + for (const child of children) { + const id = child.getAttribute(this._idAttribute) || String(gridContents.size); + gridContents.set(id, child); } this._setGridContents(gridContents); @@ -200,6 +191,7 @@ export class MediaGridController { const eventPath = ev.composedPath(); for (const [id, element] of this._gridContents.entries()) { + /* istanbul ignore else: the else path cannot be reached -- @preserve */ if (eventPath.includes(element)) { this._mediaLoadedInfoMap.set(id, ev.detail); if (id !== this._selected) { @@ -271,6 +263,7 @@ export class MediaGridController { const eventPath = ev.composedPath(); for (const [id, element] of this._gridContents.entries()) { + /* istanbul ignore else: the else path cannot be reached -- @preserve */ if (eventPath.includes(element)) { if (this._selected !== id) { this.selectCell(id); diff --git a/src/utils/media-info.ts b/src/utils/media-info.ts index 3e01807a..71886649 100644 --- a/src/utils/media-info.ts +++ b/src/utils/media-info.ts @@ -112,7 +112,7 @@ export function isValidMediaLoadedInfo(info: MediaLoadedInfo): boolean { ); } -// Facilities correct Typescript typing of media:loaded event handlers. +// Facilitates correct Typescript typing of media:loaded/unloaded event handlers. export interface FrigateMediaLoadedEventTarget extends EventTarget { addEventListener( event: 'frigate-card:media:loaded', @@ -122,6 +122,11 @@ export interface FrigateMediaLoadedEventTarget extends EventTarget { ) => void, options?: AddEventListenerOptions | boolean, ): void; + addEventListener( + event: 'frigate-card:media:unloaded', + listener: (this: FrigateMediaLoadedEventTarget, ev: CustomEvent) => void, + options?: AddEventListenerOptions | boolean, + ): void; addEventListener( type: string, callback: EventListenerOrEventListenerObject, @@ -135,6 +140,11 @@ export interface FrigateMediaLoadedEventTarget extends EventTarget { ) => void, options?: boolean | EventListenerOptions, ): void; + removeEventListener( + event: 'frigate-card:media:unloaded', + listener: (this: FrigateMediaLoadedEventTarget, ev: CustomEvent) => void, + options?: boolean | EventListenerOptions, + ): void; removeEventListener( type: string, callback: EventListenerOrEventListenerObject, diff --git a/src/utils/menu-controller.ts b/src/utils/menu-controller.ts index f069397f..92ca9bdc 100644 --- a/src/utils/menu-controller.ts +++ b/src/utils/menu-controller.ts @@ -82,7 +82,7 @@ export class MenuButtonController { ) as FrigateCardCustomAction, }); - if (visibleCameras) { + if (visibleCameras.size) { const menuItems = Array.from(visibleCameras, ([cameraID, config]) => { const action = createFrigateCardCustomAction('camera_select', { camera: cameraID, @@ -399,6 +399,7 @@ export class MenuButtonController { const action = createFrigateCardCustomAction('display_mode_select', { display_mode: isGrid ? 'single' : 'grid', }); + /* istanbul ignore else: the else path cannot be reached -- @preserve */ if (action) { buttons.push({ icon: isGrid ? 'mdi:grid-off' : 'mdi:grid', diff --git a/src/utils/zod.ts b/src/utils/zod.ts index d3d53e8b..9f8037d6 100644 --- a/src/utils/zod.ts +++ b/src/utils/zod.ts @@ -74,23 +74,22 @@ export const getParseErrorPaths = (error: z.ZodError): Set | null * available unions). This usually suggests the user specified an incorrect * type name entirely. */ const contenders = new Set(); - if (error && error.issues) { - for (let i = 0; i < error.issues.length; i++) { - const issue = error.issues[i]; - if (issue.code == 'invalid_union') { + if (error.issues.length) { + for (const issue of error.issues) { + if (issue.code === 'invalid_union') { const unionErrors = (issue as z.ZodInvalidUnionIssue).unionErrors; - for (let j = 0; j < unionErrors.length; j++) { - const nestedErrors = getParseErrorPaths(unionErrors[j]); + for (const unionError of unionErrors) { + const nestedErrors = getParseErrorPaths(unionError); if (nestedErrors && nestedErrors.size) { nestedErrors.forEach(contenders.add, contenders); } } - } else if (issue.code == 'invalid_type') { - if (issue.path[issue.path.length - 1] == 'type') { + } else if (issue.code === 'invalid_type') { + if (issue.path[issue.path.length - 1] === 'type') { return null; } contenders.add(getParseErrorPathString(issue.path)); - } else if (issue.code != 'custom') { + } else { contenders.add(getParseErrorPathString(issue.path)); } } diff --git a/src/view/media-queries-results.ts b/src/view/media-queries-results.ts index 3eec71be..f3d2588d 100644 --- a/src/view/media-queries-results.ts +++ b/src/view/media-queries-results.ts @@ -26,7 +26,7 @@ class ResultSlice { if (options?.results && options.results.length) { if (!options?.selectApproach || options?.selectApproach === 'last') { return options.results.length - 1; - } else if (options.selectApproach === 'first') { + } else { return 0; } } diff --git a/src/view/view.ts b/src/view/view.ts index e41e1db4..e89d010f 100644 --- a/src/view/view.ts +++ b/src/view/view.ts @@ -111,13 +111,9 @@ export class View { const switchingToMediaFromMedia = curr?.is('media') && next.is('media'); if (hasNoQueryOrResults) { - if (switchingToGalleryFromViewer) { - if (curr.query) { - next.query = curr.query; - } - if (curr.queryResults) { - next.queryResults = curr.queryResults; - } + if (switchingToGalleryFromViewer && curr.query && curr.queryResults) { + next.query = curr.query; + next.queryResults = curr.queryResults; } else if (switchingToMediaFromMedia && currentQueriesView) { next.view = currentQueriesView === 'clips' diff --git a/tests/camera-manager/cache.test.ts b/tests/camera-manager/cache.test.ts index 70889913..6746ec8a 100644 --- a/tests/camera-manager/cache.test.ts +++ b/tests/camera-manager/cache.test.ts @@ -59,7 +59,7 @@ describe('RecordingSegmentsCache', () => { start: now, end: add(now, { hours: 1 }), }; - const badRange = { start: sub(now, { hours: 1 }), end: now }; + const pastRange = { start: sub(now, { hours: 1 }), end: now }; const createSegment = (date: Date, id: string): RecordingSegment => { return { start_time: date.getTime() / 1000, @@ -89,7 +89,7 @@ describe('RecordingSegmentsCache', () => { }); it('should not get for other range', () => { cache.add('camera-1', range, segments); - expect(cache.get('camera-1', badRange)).toBeNull(); + expect(cache.get('camera-1', pastRange)).toBeNull(); }); it('should have coverage when added', () => { @@ -102,7 +102,7 @@ describe('RecordingSegmentsCache', () => { }); it('should not have coverage for other range', () => { cache.add('camera-1', range, segments); - expect(cache.hasCoverage('camera-1', badRange)).toBeFalsy(); + expect(cache.hasCoverage('camera-1', pastRange)).toBeFalsy(); }); it('should be empty when cleared', () => { @@ -114,11 +114,11 @@ describe('RecordingSegmentsCache', () => { it('should get size', () => { cache.add('camera-1', range, segments); - expect(cache.getSize("camera-1")).toBe(3); + expect(cache.getSize('camera-1')).toBe(3); }); it('should not size for other camera', () => { cache.add('camera-1', range, segments); - expect(cache.getSize("camera-2")).toBeNull(); + expect(cache.getSize('camera-2')).toBeNull(); }); it('should return cameraIDs', () => { @@ -127,6 +127,24 @@ describe('RecordingSegmentsCache', () => { expect(sortBy(cache.getCameraIDs())).toEqual(sortBy(['camera-1', 'camera-2'])); }); + it('should add segments to existing range', () => { + cache.add('camera-1', range, segments); + cache.add('camera-1', range, [ + createSegment(add(now, { seconds: 15 }), 'segment-2.5'), + ]); + expect(cache.get('camera-1', range)?.length).toBe(4); + }); + it('should not get segments that are outside range', () => { + cache.add('camera-1', range, segments); + expect(cache.get('camera-1', range)?.length).toBe(3); + // Add a segment before and after the desired range. + cache.add('camera-1', range, [ + createSegment(sub(now, { seconds: 15 }), 'segment-0'), + createSegment(add(range.end, { seconds: 10 }), 'segment-4'), + ]); + expect(cache.get('camera-1', range)?.length).toBe(3); + }); + it('should remove expired matches', () => { cache.add('camera-1', range, segments); cache.expireMatches('camera-1', (segment) => segment === segments[0]); diff --git a/tests/camera-manager/engine-factory.test.ts b/tests/camera-manager/engine-factory.test.ts index 24ebde87..db8df3e0 100644 --- a/tests/camera-manager/engine-factory.test.ts +++ b/tests/camera-manager/engine-factory.test.ts @@ -100,6 +100,11 @@ describe('CameraManagerEngineFactory.getEngineForCamera()', () => { Engine.Frigate, ); }); + it('should get no engine from config with insufficient details', async () => { + const config = createCameraConfig({}); + expect(await createFactory().getEngineForCamera(createHASS(), config)).toBeNull(); + }); + it('should throw error on invalid entity', async () => { const config = createCameraConfig({ engine: 'auto', camera_entity: 'camera.foo' }); const entityRegistryManager = new EntityRegistryManager(new EntityCache()); diff --git a/tests/camera-manager/range.test.ts b/tests/camera-manager/range.test.ts index 8051baad..5d2a40c4 100644 --- a/tests/camera-manager/range.test.ts +++ b/tests/camera-manager/range.test.ts @@ -135,6 +135,7 @@ describe('compressRanges', () => { compressRanges([ { start: now, end: nowPlusOne }, { start: nowPlusOne, end: nowPlusTwo }, + { start: now, end: nowPlusOne }, ]), ).toEqual([{ start: now, end: nowPlusTwo }]); }); @@ -162,4 +163,8 @@ describe('compressRanges', () => { ]; expect(compressRanges(input)).toEqual([{ start: 1, end: 3 }]); }); + + it('should return nothing with no input', () => { + expect(compressRanges([])).toEqual([]); + }); }); diff --git a/tests/conditions.test.ts b/tests/conditions.test.ts index d5eb3fbc..de76966b 100644 --- a/tests/conditions.test.ts +++ b/tests/conditions.test.ts @@ -99,6 +99,13 @@ describe('getOverriddenConfig', () => { }, }); }); + + it('should do nothing without overrides', () => { + const controller = new ConditionController(); + controller.setState({ fullscreen: true }); + + expect(getOverriddenConfig(controller, config)).toBe(config); + }); }); describe('getOverridesByKey', () => { diff --git a/tests/test-utils.ts b/tests/test-utils.ts index 1dc0bcec..d55088ec 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -239,17 +239,53 @@ export class TestViewMedia extends ViewMedia { } } -export const createResizeObserverImplementation = (): (() => void) => { - return () => ({ - observe: vi.fn(), - unobserve: vi.fn(), - disconnect: vi.fn(), - }); +export const ResizeObserverMock = vi.fn(() => ({ + disconnect: vi.fn(), + observe: vi.fn(), + unobserve: vi.fn(), +})); + +export const IntersectionObserverMock = vi.fn(() => ({ + disconnect: vi.fn(), + observe: vi.fn(), + unobserve: vi.fn(), +})); + +export const MutationObserverMock = vi.fn(() => ({ + disconnect: vi.fn(), + observe: vi.fn(), + unobserve: vi.fn(), +})); + +export const requestAnimationFrameMock = (callback: FrameRequestCallback) => { + callback(new Date().getTime()); + return 1; }; -export const createMutationObserverImplementation = (): (() => void) => { - return () => ({ - observe: vi.fn(), - disconnect: vi.fn(), - }); +export const createSlotHost = (options?: { + slot?: HTMLSlotElement; + children?: HTMLElement[]; +}): HTMLElement => { + const parent = document.createElement('div'); + parent.attachShadow({ mode: 'open' }); + + if (options?.slot) { + parent.shadowRoot?.append(options.slot); + } + if (options?.children) { + // Children will automatically be slotted into the default slot when it is + // created. + parent.append(...options.children); + } + return parent; +}; + +export const createSlot = (): HTMLSlotElement => { + return document.createElement('slot'); +}; + +export const createParent = (options?: { children?: HTMLElement[] }): HTMLElement => { + const parent = document.createElement('div'); + parent.append(...(options?.children ?? [])); + return parent; }; diff --git a/tests/utils/basic.test.ts b/tests/utils/basic.test.ts index 574a9803..0a58c87c 100644 --- a/tests/utils/basic.test.ts +++ b/tests/utils/basic.test.ts @@ -1,27 +1,29 @@ -import { describe, it, expect, vi, afterAll } from 'vitest'; +import { afterAll, describe, expect, it, vi } from 'vitest'; import { FrigateCardError } from '../../src/types'; import { allPromises, - arrayify, arrayMove, + arrayify, contentsChanged, dayToDate, dispatchFrigateCardEvent, errorToConsole, - isTruthy, formatDate, formatDateAndTime, + getChildrenFromElement, getDurationString, + isHTMLElement, isHoverableDevice, isSuperset, + isTruthy, isValidDate, prettifyTitle, runWhenIdleIfSupported, - setify, setOrRemoveAttribute, + setify, sleep, - isHTMLElement, } from '../../src/utils/basic'; +import { createSlot, createSlotHost } from '../test-utils'; // @vitest-environment jsdom describe('dispatchFrigateCardEvent', () => { @@ -183,6 +185,11 @@ describe('getDurationString', () => { const end = new Date(2023, 3, 14, 15, 37, 20); expect(getDurationString(start, end)).toBe('2h 2m 20s'); }); + it('should return very short duration', () => { + const start = new Date(2023, 3, 14, 13, 35, 10); + const end = new Date(2023, 3, 14, 13, 35, 12); + expect(getDurationString(start, end)).toBe('2s'); + }); }); describe('allPromises', () => { @@ -268,3 +275,19 @@ describe('isHTMLElement', () => { expect(isHTMLElement(svgElement)).toBeFalsy(); }); }); + +describe('getChildrenFromElement', () => { + it('should return children for simple parent', () => { + const children = [document.createElement('div'), document.createElement('div')]; + const parent = document.createElement('div'); + children.forEach((child) => parent.appendChild(child)); + expect(getChildrenFromElement(parent)).toEqual(children); + }); + + it('should return children for slot', () => { + const children = [document.createElement('div'), document.createElement('div')]; + const slot = createSlot(); + createSlotHost({ slot: slot, children: children }); + expect(getChildrenFromElement(slot)).toEqual(children); + }); +}); diff --git a/tests/utils/download.test.ts b/tests/utils/download.test.ts index 850528f3..c5c9ac0b 100644 --- a/tests/utils/download.test.ts +++ b/tests/utils/download.test.ts @@ -12,13 +12,66 @@ vi.mock('../../src/utils/ha'); const media = new ViewMedia('clip', 'camera-1'); // @vitest-environment jsdom +describe('downloadURL', () => { + afterEach(() => { + vi.restoreAllMocks(); + global.window.location = mock(); + }); + + it('should download same origin via link', () => { + const location: Location & { origin: string } = mock(); + location.origin = 'http://foo'; + global.window.location = location; + + const link = document.createElement('a'); + link.click = vi.fn(); + link.setAttribute = vi.fn(); + vi.spyOn(document, 'createElement').mockReturnValue(link); + + downloadURL('http://foo/url.mp4'); + + expect(link.href).toBe('http://foo/url.mp4'); + expect(link.setAttribute).toBeCalledWith('download', 'download'); + expect(link.click).toBeCalled(); + }); + + it('should download data URL via link', () => { + const link = document.createElement('a'); + link.click = vi.fn(); + link.setAttribute = vi.fn(); + vi.spyOn(document, 'createElement').mockReturnValue(link); + + downloadURL('data:text/plain;charset=utf-8;base64,VEhJUyBJUyBEQVRB'); + + expect(link.href).toBe('data:text/plain;charset=utf-8;base64,VEhJUyBJUyBEQVRB'); + expect(link.setAttribute).toBeCalledWith('download', 'download'); + expect(link.click).toBeCalled(); + }); + + it('should download in apps via window.open', () => { + // Set the origin to the same. + const location: Location & { origin: string } = mock(); + location.origin = 'http://foo'; + global.window.location = location; + + vi.stubGlobal('navigator', { + userAgent: 'Home Assistant/2023.3.0-3260 (Android 13; Pixel 7 Pro)', + }); + + const windowSpy = vi.spyOn(window, 'open').mockReturnValue(null); + + downloadURL('http://foo/url.mp4'); + expect(windowSpy).toBeCalledWith('http://foo/url.mp4', '_blank'); + }); +}); + describe('downloadMedia', () => { afterEach(() => { vi.resetAllMocks(); global.window.location = mock(); }); - it('should throw error when no media', async () => { + it('should throw error when no media', () => { const cameraManager = createCameraManager(); mock(cameraManager).getMediaDownloadPath.mockResolvedValue(null); @@ -55,44 +108,16 @@ describe('downloadMedia', () => { await downloadMedia(createHASS(), cameraManager, media); expect(windowSpy).toBeCalledWith('http://foo/signed-url', '_blank'); }); -}); -describe('downloadURL', () => { - afterEach(() => { - vi.resetAllMocks(); - global.window.location = mock(); - }); - - it('should download same origin via link', async () => { - const location: Location & { origin: string } = mock(); - location.origin = 'http://foo'; - global.window.location = location; - - const link = document.createElement('a'); - link.click = vi.fn(); - link.setAttribute = vi.fn(); - vi.spyOn(document, 'createElement').mockReturnValue(link); - - downloadURL('http://foo/url.mp4'); - - expect(link.href).toBe('http://foo/url.mp4'); - expect(link.setAttribute).toBeCalledWith('download', 'download'); - expect(link.click).toBeCalled(); - }); - - it('should download in apps via window.open', async () => { - // Set the origin to the same. - const location: Location & { origin: string } = mock(); - location.origin = 'http://foo'; - global.window.location = location; - - vi.stubGlobal('navigator', { - userAgent: 'Home Assistant/2023.3.0-3260 (Android 13; Pixel 7 Pro)', + it('should download media without signing', async () => { + const cameraManager = createCameraManager(); + mock(cameraManager).getMediaDownloadPath.mockResolvedValue({ + sign: false, + endpoint: 'https://foo/', }); - const windowSpy = vi.spyOn(window, 'open').mockReturnValue(null); - downloadURL('http://foo/url.mp4'); - expect(windowSpy).toBeCalledWith('http://foo/url.mp4', '_blank'); + await downloadMedia(createHASS(), cameraManager, media); + expect(windowSpy).toBeCalledWith('https://foo/', '_blank'); }); }); diff --git a/tests/utils/embla/carousel-controller.test.ts b/tests/utils/embla/carousel-controller.test.ts new file mode 100644 index 00000000..bc5eb5be --- /dev/null +++ b/tests/utils/embla/carousel-controller.test.ts @@ -0,0 +1,291 @@ +import EmblaCarousel, { EmblaCarouselType } from 'embla-carousel'; +import { MockedObject, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { CarouselController } from '../../../src/utils/embla/carousel-controller'; +import AutoMediaLoadedInfo from '../../../src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info'; +import { + MutationObserverMock, + createParent, + createSlot, + createSlotHost, +} from '../../test-utils'; +import { + callEmblaHandler, + callMutationHandler, + createEmblaApiInstance, + createTestSlideNodes, +} from './test-utils'; + +vi.mock('embla-carousel', () => ({ + default: vi.fn().mockImplementation(() => { + return createEmblaApiInstance(); + }), +})); + +// Get the nth most recently constructed EmblaAPI instance. +const getEmblaApi = (n = 0): MockedObject | null => { + const constructions = vi.mocked(EmblaCarousel).mock.results; + const mostRecentResult = constructions[constructions.length - 1 - n] ?? null; + if (mostRecentResult && mostRecentResult.type === 'return') { + return vi.mocked(mostRecentResult.value); + } + return null; +}; + +const createRoot = (): HTMLElement => { + return document.createElement('div'); +}; + +// @vitest-environment jsdom +describe('CarouselController', () => { + beforeAll(() => { + vi.stubGlobal('MutationObserver', MutationObserverMock); + }); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should construct', () => { + const children = createTestSlideNodes(); + const parent = createParent({ children: children }); + const carousel = new CarouselController(createRoot(), parent); + expect(carousel).toBeTruthy(); + }); + + it('should construct with slot parent', () => { + const slot = createSlot(); + const host = createSlotHost({ slot: slot, children: createTestSlideNodes() }); + const carousel = new CarouselController(host, slot); + expect(carousel).toBeTruthy(); + }); + + it('should destroy', () => { + const children = createTestSlideNodes(); + const parent = createParent({ children: children }); + const carousel = new CarouselController(createRoot(), parent); + + carousel.destroy(); + + expect(getEmblaApi()?.destroy).toBeCalled(); + }); + + it('should destroy with slot', () => { + const slot = createSlot(); + const host = createSlotHost({ slot: slot, children: createTestSlideNodes() }); + const carousel = new CarouselController(host, slot); + + carousel.destroy(); + + expect(getEmblaApi()?.destroy).toBeCalled(); + }); + + it('should get slide by index', () => { + const children = createTestSlideNodes(); + const parent = createParent({ children: children }); + const carousel = new CarouselController(createRoot(), parent); + + getEmblaApi()?.slideNodes.mockReturnValue(children); + expect(carousel.getSlide(2)).toBe(children[2]); + }); + + it('should get slide by index when index is invalid', () => { + const children = createTestSlideNodes(); + const parent = createParent({ children: children }); + const carousel = new CarouselController(createRoot(), parent); + + expect(carousel.getSlide(1000)).toBeNull(); + }); + + it('should get selected slide', () => { + const children = createTestSlideNodes(); + const parent = createParent({ children: children }); + const carousel = new CarouselController(createRoot(), parent); + + getEmblaApi()?.slideNodes.mockReturnValue(children); + getEmblaApi()?.selectedScrollSnap.mockReturnValue(3); + expect(carousel.getSelectedIndex()).toBe(3); + expect(carousel.getSelectedSlide()).toBe(children[3]); + }); + + it('should select given slide', () => { + const children = createTestSlideNodes(); + const parent = createParent({ children: children }); + const carousel = new CarouselController(createRoot(), parent); + + carousel.selectSlide(4); + + expect(getEmblaApi()?.scrollTo).toBeCalledWith(4, false); + }); + + it('should dispatch settle event', () => { + const children = createTestSlideNodes(); + const parent = createParent({ children: children }); + new CarouselController(createRoot(), parent); + + const settleHandler = vi.fn(); + parent.addEventListener('frigate-card:carousel:settle', settleHandler); + + callEmblaHandler(getEmblaApi(), 'settle'); + + expect(settleHandler).toBeCalled(); + }); + + describe('should dispatch select event on', () => { + it.each([['init' as const], ['select' as const]])( + '%s', + (emblaApiEvt: 'init' | 'select') => { + const children = createTestSlideNodes(); + const parent = createParent({ children: children }); + new CarouselController(createRoot(), parent); + + const selectHandler = vi.fn(); + parent.addEventListener('frigate-card:carousel:select', selectHandler); + + getEmblaApi()?.selectedScrollSnap.mockReturnValue(6); + getEmblaApi()?.slideNodes.mockReturnValue(children); + callEmblaHandler(getEmblaApi(), emblaApiEvt); + + expect(selectHandler).toBeCalledWith( + expect.objectContaining({ + detail: { + index: 6, + element: children[6], + }, + }), + ); + }, + ); + }); + + it('should not dispatch anything with an invalid scroll snap', () => { + const children = createTestSlideNodes(); + const parent = createParent({ children: children }); + new CarouselController(createRoot(), parent); + + const selectHandler = vi.fn(); + parent.addEventListener('frigate-card:carousel:select', selectHandler); + + getEmblaApi()?.selectedScrollSnap.mockReturnValue(1000); + getEmblaApi()?.slideNodes.mockReturnValue(children); + callEmblaHandler(getEmblaApi(), 'init'); + callEmblaHandler(getEmblaApi(), 'select'); + callEmblaHandler(getEmblaApi(), 'settle'); + + expect(selectHandler).not.toBeCalled(); + }); + + it('should honor creation options', () => { + const children = createTestSlideNodes({ n: 1 }); + const root = createRoot(); + const parent = createParent({ children: children }); + const plugins = [AutoMediaLoadedInfo()]; + + new CarouselController(root, parent, { + direction: 'vertical', + transitionEffect: 'none', + startIndex: 7, + dragFree: true, + loop: true, + dragEnabled: false, + plugins: plugins, + }); + + expect(EmblaCarousel).toBeCalledWith( + root, + { + slides: children, + axis: 'y', + duration: 20, + startIndex: 7, + dragFree: true, + loop: true, + containScroll: 'trimSnaps', + watchSlides: false, + watchResize: false, + watchDrag: false, + }, + plugins, + ); + }); + + it('should include wheel plugin when slides > 1', () => { + const children = createTestSlideNodes(); + const root = createRoot(); + const parent = createParent({ children: children }); + new CarouselController(root, parent); + + expect(EmblaCarousel).toBeCalledWith( + root, + expect.anything(), + expect.arrayContaining([ + expect.objectContaining({ + name: 'wheelGestures', + }), + ]), + ); + }); + + it('should recreate carousel when children are added', () => { + const children = createTestSlideNodes(); + const root = createRoot(); + const parent = createParent({ children: children }); + new CarouselController(root, parent); + + expect(EmblaCarousel).toBeCalledTimes(1); + + const originalEmblaApi = getEmblaApi(); + expect(originalEmblaApi).toBeTruthy(); + + originalEmblaApi?.slideNodes.mockReturnValue(children); + parent.appendChild(document.createElement('div')); + callMutationHandler(); + + expect(originalEmblaApi?.destroy).toBeCalled(); + expect(getEmblaApi()).not.toBe(originalEmblaApi); + + expect(EmblaCarousel).toBeCalledTimes(2); + }); + + it('should not recreate carousel when children have not changed', () => { + const children = createTestSlideNodes(); + const root = createRoot(); + const parent = createParent({ children: children }); + new CarouselController(root, parent); + + expect(EmblaCarousel).toBeCalledTimes(1); + + const originalEmblaApi = getEmblaApi(); + expect(originalEmblaApi).toBeTruthy(); + + originalEmblaApi?.slideNodes.mockReturnValue(children); + callMutationHandler(); + + expect(originalEmblaApi?.destroy).not.toBeCalled(); + expect(getEmblaApi()).toBe(originalEmblaApi); + + expect(EmblaCarousel).toBeCalledTimes(1); + }); + + it('should recreate carousel when children are added to slot', () => { + const children = createTestSlideNodes(); + const slot = createSlot(); + const host = createSlotHost({ slot: slot, children: children }); + + new CarouselController(host, slot); + + expect(EmblaCarousel).toBeCalledTimes(1); + + const originalEmblaApi = getEmblaApi(); + expect(originalEmblaApi).toBeTruthy(); + + originalEmblaApi?.slideNodes.mockReturnValue(children); + + host.appendChild(document.createElement('div')); + slot.dispatchEvent(new Event('slotchange')); + + expect(originalEmblaApi?.destroy).toBeCalled(); + expect(getEmblaApi()).not.toBe(originalEmblaApi); + + expect(EmblaCarousel).toBeCalledTimes(2); + }); +}); diff --git a/tests/utils/embla/plugins/auto-lazy-load/auto-lazy-load.test.ts b/tests/utils/embla/plugins/auto-lazy-load/auto-lazy-load.test.ts new file mode 100644 index 00000000..d2ec3916 --- /dev/null +++ b/tests/utils/embla/plugins/auto-lazy-load/auto-lazy-load.test.ts @@ -0,0 +1,219 @@ +import { describe, expect, it, vi } from 'vitest'; +import { AutoLazyLoad } from '../../../../../src/utils/embla/plugins/auto-lazy-load/auto-lazy-load'; +import { + callEmblaHandler, + callVisibilityHandler, + createEmblaApiInstance, + createTestEmblaOptionHandler, + createTestSlideNodes, +} from '../../test-utils'; + +// @vitest-environment jsdom +describe('AutoLazyLoad', () => { + it('should construct', () => { + const plugin = AutoLazyLoad(); + expect(plugin.name).toBe('autoLazyLoad'); + }); + + it('should destroy', () => { + const plugin = AutoLazyLoad({ + lazyLoadCallback: vi.fn(), + lazyUnloadCallback: vi.fn(), + }); + const emblaApi = createEmblaApiInstance(); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + plugin.destroy(); + + expect(emblaApi.off).toBeCalledWith('init', expect.anything()); + expect(emblaApi.off).toBeCalledWith('select', expect.anything()); + }); + + it('should do nothing without callbacks', () => { + const plugin = AutoLazyLoad({ + // No callbacks provided. + }); + + const children = createTestSlideNodes(); + const emblaApi = createEmblaApiInstance({ slideNodes: children }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + expect(emblaApi.on).not.toBeCalled(); + + plugin.destroy(); + expect(emblaApi.off).not.toBeCalled(); + }); + + it('should lazy load single slide on select', () => { + const lazyLoadCallback = vi.fn(); + const plugin = AutoLazyLoad({ + lazyLoadCallback: lazyLoadCallback, + }); + + const children = createTestSlideNodes(); + const emblaApi = createEmblaApiInstance({ slideNodes: children }); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + expect(emblaApi.on).toBeCalledWith('init', expect.anything()); + expect(emblaApi.on).toBeCalledWith('select', expect.anything()); + + callEmblaHandler(emblaApi, 'init'); + expect(lazyLoadCallback).toBeCalledWith(0, children[0]); + + callEmblaHandler(emblaApi, 'select'); + + // The select call will not re-lazyload the same slide. + expect(lazyLoadCallback).toBeCalledTimes(1); + }); + + it('should lazy load multiple slides on select', () => { + const lazyLoadCallback = vi.fn(); + const plugin = AutoLazyLoad({ + lazyLoadCallback: lazyLoadCallback, + lazyLoadCount: 3, + }); + + const children = createTestSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + selectedScrollSnap: 5, + }); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + callEmblaHandler(emblaApi, 'select'); + for (let i = 3; i <= 8; ++i) { + expect(lazyLoadCallback).toBeCalledWith(i, children[i]); + } + }); + + it('should lazy unload on select', () => { + const lazyUnloadCallback = vi.fn(); + const plugin = AutoLazyLoad({ + lazyLoadCallback: vi.fn(), + lazyLoadCount: 3, + lazyUnloadCallback: lazyUnloadCallback, + lazyUnloadCondition: 'all', + }); + + const children = createTestSlideNodes(); + const emblaApi = createEmblaApiInstance({ + selectedScrollSnap: 5, + slideNodes: children, + }); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + callEmblaHandler(emblaApi, 'select'); + + // First call will not unload anything, since it was not lazy loaded. + expect(lazyUnloadCallback).not.toBeCalled(); + + vi.mocked(emblaApi.previousScrollSnap).mockReturnValue(5); + callEmblaHandler(emblaApi, 'select'); + + // Second call should lazy unload the previous slide. + expect(lazyUnloadCallback).toBeCalledWith(5, children[5]); + }); + + it('should lazy load on visibility', () => { + vi.spyOn(global.document, 'addEventListener'); + + const lazyLoadCallback = vi.fn(); + const plugin = AutoLazyLoad({ + lazyLoadCallback: lazyLoadCallback, + }); + + const children = createTestSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + }); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + callVisibilityHandler(); + expect(lazyLoadCallback).toBeCalledWith(0, children[0]); + }); + + it('should lazy unload on visibility', () => { + vi.spyOn(global.document, 'addEventListener'); + + const lazyUnloadCallback = vi.fn(); + + const plugin = AutoLazyLoad({ + lazyLoadCallback: vi.fn(), + lazyUnloadCallback: lazyUnloadCallback, + lazyUnloadCondition: 'all', + }); + + const children = createTestSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + }); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + callVisibilityHandler(); + + Object.defineProperty(document, 'visibilityState', { + value: 'hidden', + writable: true, + }); + callVisibilityHandler(); + expect(lazyUnloadCallback).toBeCalledWith(0, children[0]); + }); + + it('should not lazy unload on visibility without a callback', () => { + vi.spyOn(global.document, 'addEventListener'); + + const lazyLoadCallback = vi.fn(); + const plugin = AutoLazyLoad({ + lazyLoadCallback: lazyLoadCallback, + lazyUnloadCondition: 'all', + // No lazy unload callback. + }); + const children = createTestSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + }); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + callVisibilityHandler(); + expect(lazyLoadCallback).toBeCalledTimes(1); + + Object.defineProperty(document, 'visibilityState', { + value: 'hidden', + writable: true, + }); + callVisibilityHandler(); + expect(lazyLoadCallback).toBeCalledTimes(1); + }); + + it('should not lazy load or unload on visibility when no callback provided', () => { + vi.spyOn(global.document, 'addEventListener'); + + const plugin = AutoLazyLoad({ + lazyUnloadCondition: 'all', + // No callbacks provided. + }); + + const children = createTestSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + }); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + callVisibilityHandler(); + }); +}); diff --git a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts new file mode 100644 index 00000000..9e8b7092 --- /dev/null +++ b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts @@ -0,0 +1,304 @@ +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { FrigateCardMediaPlayer } from '../../../../../src/types'; +import { + AutoMediaActions, + AutoMediaActionsOptionsType, + AutoMediaActionsType, +} from '../../../../../src/utils/embla/plugins/auto-media-actions/auto-media-actions'; +import { dispatchExistingMediaLoadedInfoAsEvent } from '../../../../../src/utils/media-info'; +import { + IntersectionObserverMock, + createMediaLoadedInfo, + createParent, +} from '../../../../test-utils'; +import { + callEmblaHandler, + callIntersectionHandler, + callVisibilityHandler, + createEmblaApiInstance, + createTestEmblaOptionHandler, + createTestSlideNodes, +} from '../../test-utils'; + +const getPlayer = ( + element: HTMLElement, + selector: string, +): (HTMLElement & FrigateCardMediaPlayer) | null => { + return element.querySelector(selector); +}; + +const createPlayerSlideNodes = (n = 10): HTMLElement[] => { + const slides = createTestSlideNodes({ n: n }); + for (const slide of slides) { + const player = document.createElement('video'); + + player['play'] = vi.fn(); + player['pause'] = vi.fn(); + player['mute'] = vi.fn(); + player['unmute'] = vi.fn(); + player['isMuted'] = vi.fn().mockReturnValue(true); + player['seek'] = vi.fn(); + player['getScreenshotURL'] = vi.fn(); + player['setControls'] = vi.fn(); + player['isPaused'] = vi.fn(); + + slide.appendChild(player); + } + return slides; +}; + +const createPlugin = (options?: AutoMediaActionsOptionsType): AutoMediaActionsType => { + return AutoMediaActions({ + playerSelector: 'video', + autoPlayCondition: 'all', + autoUnmuteCondition: 'all', + autoPauseCondition: 'all', + autoMuteCondition: 'all', + ...options, + }); +}; + +// @vitest-environment jsdom +describe('AutoMediaActions', () => { + beforeAll(() => { + vi.stubGlobal('IntersectionObserver', IntersectionObserverMock); + }); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should construct', () => { + const plugin = AutoMediaActions(); + expect(plugin.name).toBe('autoMediaActions'); + }); + + it('should init without any conditions', () => { + const plugin = AutoMediaActions(); + + const parent = createParent(); + const addEventListener = vi.fn(); + parent.addEventListener = addEventListener; + const emblaApi = createEmblaApiInstance({ containerNode: parent }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + expect(emblaApi.on).toBeCalledWith('destroy', expect.anything()); + expect(emblaApi.on).not.toBeCalledWith('select', expect.anything()); + expect(addEventListener).not.toBeCalled(); + }); + + it('should destroy', () => { + const plugin = createPlugin(); + const parent = createParent(); + const removeEventListener = vi.fn(); + parent.removeEventListener = removeEventListener; + const emblaApi = createEmblaApiInstance({ containerNode: parent }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + plugin.destroy(); + + expect(emblaApi.off).toBeCalledWith('destroy', expect.anything()); + expect(emblaApi.off).toBeCalledWith('select', expect.anything()); + expect(removeEventListener).toBeCalled(); + }); + + it('should destroy without any conditions', () => { + const plugin = AutoMediaActions(); + const parent = createParent(); + const removeEventListener = vi.fn(); + parent.removeEventListener = removeEventListener; + const emblaApi = createEmblaApiInstance({ containerNode: parent }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + plugin.destroy(); + + expect(emblaApi.off).toBeCalledWith('destroy', expect.anything()); + expect(emblaApi.off).not.toBeCalledWith('select', expect.anything()); + expect(removeEventListener).not.toBeCalled(); + }); + + it('should mute and pause on destroy', () => { + const plugin = createPlugin(); + const children = createPlayerSlideNodes(); + const parent = createParent({ children: children }); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + containerNode: parent, + selectedScrollSnap: 5, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + callEmblaHandler(emblaApi, 'destroy'); + + expect(getPlayer(children[5], 'video')?.pause).toBeCalled(); + expect(getPlayer(children[5], 'video')?.mute).toBeCalled(); + }); + + it('should play and unmute on media load', () => { + const plugin = createPlugin(); + const children = createPlayerSlideNodes(); + const parent = createParent({ children: children }); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + containerNode: parent, + selectedScrollSnap: 5, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + dispatchExistingMediaLoadedInfoAsEvent(parent, createMediaLoadedInfo()); + + expect(getPlayer(children[5], 'video')?.play).toBeCalled(); + expect(getPlayer(children[5], 'video')?.unmute).toBeCalled(); + }); + + it('should not play or unmute on media load when player selecter not provided', () => { + const plugin = createPlugin({ playerSelector: undefined }); + const children = createPlayerSlideNodes(); + const parent = createParent({ children: children }); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + containerNode: parent, + selectedScrollSnap: 5, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + dispatchExistingMediaLoadedInfoAsEvent(parent, createMediaLoadedInfo()); + + expect(getPlayer(children[5], 'video')?.play).not.toBeCalled(); + expect(getPlayer(children[5], 'video')?.unmute).not.toBeCalled(); + }); + + it('should pause and mute previous on select', () => { + const plugin = createPlugin(); + const children = createPlayerSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + previousScrollSnap: 4, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + callEmblaHandler(emblaApi, 'select'); + + expect(getPlayer(children[4], 'video')?.pause).toBeCalled(); + expect(getPlayer(children[4], 'video')?.mute).toBeCalled(); + }); + + it('should play and unmute on visibility change to visible', () => { + vi.spyOn(global.document, 'addEventListener'); + + const plugin = createPlugin(); + const children = createPlayerSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + selectedScrollSnap: 5, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + callVisibilityHandler(); + + expect(getPlayer(children[5], 'video')?.play).toBeCalled(); + expect(getPlayer(children[5], 'video')?.unmute).toBeCalled(); + }); + + it('should pause and unmute on visibility change to hidden', () => { + vi.spyOn(global.document, 'addEventListener'); + + const plugin = createPlugin(); + const children = createPlayerSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + Object.defineProperty(document, 'visibilityState', { + value: 'hidden', + writable: true, + }); + callVisibilityHandler(); + + for (const child of children) { + expect(getPlayer(child, 'video')?.pause).toBeCalled(); + expect(getPlayer(child, 'video')?.mute).toBeCalled(); + } + }); + + describe('should take no action on visibility change without callbacks', () => { + it.each([['visible' as const], ['hidden' as const]])( + '%s', + (visibilityState: 'visible' | 'hidden') => { + vi.spyOn(global.document, 'addEventListener'); + + const plugin = AutoMediaActions(); + const children = createPlayerSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + Object.defineProperty(document, 'visibilityState', { + value: visibilityState, + writable: true, + }); + callVisibilityHandler(); + + for (const child of children) { + expect(getPlayer(child, 'video')?.play).not.toBeCalled(); + expect(getPlayer(child, 'video')?.pause).not.toBeCalled(); + expect(getPlayer(child, 'video')?.mute).not.toBeCalled(); + expect(getPlayer(child, 'video')?.unmute).not.toBeCalled(); + } + }, + ); + }); + + it('should play and unmute on intersection', () => { + const plugin = createPlugin(); + const children = createPlayerSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + selectedScrollSnap: 5, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + // Intersection observer always calls handler on creation (and we ignore + // these first calls). + callIntersectionHandler(true); + callIntersectionHandler(true); + + expect(getPlayer(children[5], 'video')?.play).toBeCalled(); + expect(getPlayer(children[5], 'video')?.unmute).toBeCalled(); + }); + + it('should pause and mute on intersection', () => { + vi.spyOn(global.document, 'addEventListener'); + + const plugin = createPlugin(); + const children = createPlayerSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + // Intersection observer always calls handler on creation (and we ignore + // these first calls). + callIntersectionHandler(true); + callIntersectionHandler(false); + + for (const child of children) { + expect(getPlayer(child, 'video')?.pause).toBeCalled(); + expect(getPlayer(child, 'video')?.mute).toBeCalled(); + } + }); +}); diff --git a/tests/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.test.ts b/tests/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.test.ts new file mode 100644 index 00000000..df0e145c --- /dev/null +++ b/tests/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.test.ts @@ -0,0 +1,92 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import AutoMediaLoadedInfo from '../../../../../src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info'; +import { + dispatchExistingMediaLoadedInfoAsEvent, + dispatchMediaUnloadedEvent, +} from '../../../../../src/utils/media-info'; +import { createMediaLoadedInfo, createParent } from '../../../../test-utils'; +import { + callEmblaHandler, + createEmblaApiInstance, + createTestEmblaOptionHandler, + createTestSlideNodes, +} from '../../test-utils'; + +// @vitest-environment jsdom +describe('AutoMediaLoadedInfo', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should construct', () => { + const plugin = AutoMediaLoadedInfo(); + expect(plugin.name).toBe('autoMediaLoadedInfo'); + }); + + it('should destroy', () => { + const plugin = AutoMediaLoadedInfo(); + const emblaApi = createEmblaApiInstance(); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + plugin.destroy(); + + expect(emblaApi.off).toBeCalledWith('init', expect.anything()); + expect(emblaApi.off).toBeCalledWith('select', expect.anything()); + }); + + describe('should correctly propogate media load/unload depending on whether media is currently selected', () => { + it.each([ + ['loaded' as const, true], + ['unloaded' as const, true], + ['loaded' as const, false], + ['unloaded' as const, false], + ])('%s', (type: string, selected: boolean) => { + const plugin = AutoMediaLoadedInfo(); + const children = createTestSlideNodes(); + const parent = createParent({ children: children }); + + const emblaApi = createEmblaApiInstance({ + containerNode: parent, + slideNodes: children, + selectedScrollSnap: selected ? 5 : 4, + }); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + const mediaLoadedHandler = vi.fn(); + parent.addEventListener('frigate-card:media:' + type, mediaLoadedHandler); + if (type === 'loaded') { + dispatchExistingMediaLoadedInfoAsEvent(children[5], createMediaLoadedInfo()); + } else if (type === 'unloaded') { + dispatchMediaUnloadedEvent(children[5]); + } + + if (selected) { + expect(mediaLoadedHandler).toBeCalled(); + } else { + expect(mediaLoadedHandler).not.toBeCalled(); + } + }); + }); + + it('selecting a slide should dispatch a previously saved media loaded info if present', () => { + const plugin = AutoMediaLoadedInfo(); + const children = createTestSlideNodes(); + const parent = createParent({ children: children }); + const emblaApi = createEmblaApiInstance({ + containerNode: parent, + slideNodes: children, + }); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + const mediaLoadedHandler = vi.fn(); + parent.addEventListener('frigate-card:media:loaded', mediaLoadedHandler); + dispatchExistingMediaLoadedInfoAsEvent(children[5], createMediaLoadedInfo()); + + vi.mocked(emblaApi.selectedScrollSnap).mockReturnValue(4); + callEmblaHandler(emblaApi, 'select'); + expect(mediaLoadedHandler).not.toBeCalled(); + + vi.mocked(emblaApi.selectedScrollSnap).mockReturnValue(5); + callEmblaHandler(emblaApi, 'select'); + expect(mediaLoadedHandler).toBeCalled(); + }); +}); diff --git a/tests/utils/embla/plugins/auto-size/auto-size.test.ts b/tests/utils/embla/plugins/auto-size/auto-size.test.ts new file mode 100644 index 00000000..d8e06169 --- /dev/null +++ b/tests/utils/embla/plugins/auto-size/auto-size.test.ts @@ -0,0 +1,161 @@ +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import AutoSize from '../../../../../src/utils/embla/plugins/auto-size/auto-size'; +import { + IntersectionObserverMock, + ResizeObserverMock, + createParent, + requestAnimationFrameMock, +} from '../../../../test-utils'; +import { + callEmblaHandler, + callIntersectionHandler, + callResizeHandler, + createEmblaApiInstance, + createTestEmblaOptionHandler, + createTestSlideNodes, +} from '../../test-utils'; + +// Mock out debouncing (used in the reinit controller). +vi.mock('lodash-es/debounce', () => ({ + default: vi.fn((fn) => fn), +})); + +// @vitest-environment jsdom +describe('AutoSize', () => { + beforeAll(() => { + // Mock out requestAnimationFrame (used in the reinit controller). + window.requestAnimationFrame = requestAnimationFrameMock; + vi.stubGlobal('IntersectionObserver', IntersectionObserverMock); + vi.stubGlobal('ResizeObserver', ResizeObserverMock); + }); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should construct', () => { + const plugin = AutoSize(); + expect(plugin.name).toBe('autoSize'); + }); + + it('should destroy', () => { + const plugin = AutoSize(); + const emblaApi = createEmblaApiInstance(); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + plugin.destroy(); + + expect(emblaApi.off).toBeCalledWith('settle', expect.anything()); + + expect( + vi.mocked(IntersectionObserver).mock.results[0].value.disconnect, + ).toBeCalled(); + expect(vi.mocked(ResizeObserver).mock.results[0].value.disconnect).toBeCalled(); + }); + + it('should correctly handle intersection', () => { + const plugin = AutoSize(); + const emblaApi = createEmblaApiInstance(); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + // First intersection handler call sets the state only. + callIntersectionHandler(true); + + callIntersectionHandler(false); + callIntersectionHandler(false); + callIntersectionHandler(false); + + expect(emblaApi.reInit).toBeCalledTimes(1); + }); + + it('should correctly handle resize', () => { + const plugin = AutoSize(); + const parent = createParent(); + const emblaApi = createEmblaApiInstance({ containerNode: parent }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + callResizeHandler([{ target: parent, width: 10, height: 20 }]); + callResizeHandler([{ target: parent, width: 10, height: 20 }]); + callResizeHandler([{ target: parent, width: 10, height: 20 }]); + + expect(emblaApi.reInit).toBeCalledTimes(1); + + callResizeHandler([{ target: parent, width: 20, height: 40 }]); + + expect(emblaApi.reInit).toBeCalledTimes(2); + }); + + it('should set container height on slide settle', () => { + const plugin = AutoSize(); + const parent = createParent(); + const children = createTestSlideNodes(); + const emblaApi = createEmblaApiInstance({ + containerNode: parent, + selectedScrollSnap: 0, + slideNodes: children, + // 0th scroll snap shows the 0th slide only. + slideRegistry: [[0]], + }); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + children[0].getBoundingClientRect = vi.fn().mockReturnValue({ + width: 200, + height: 800, + }); + + // select should not do anything, we wait for it to have settled for + // smoothness. + callEmblaHandler(emblaApi, 'select'); + expect(parent.style.maxHeight).toBeFalsy(); + + callEmblaHandler(emblaApi, 'settle'); + expect(parent.style.maxHeight).toBe('800px'); + }); + + it('should not set container height on horizontal carousel', () => { + const plugin = AutoSize(); + const parent = createParent(); + const children = createTestSlideNodes(); + const emblaApi = createEmblaApiInstance({ + containerNode: parent, + selectedScrollSnap: 0, + slideNodes: children, + axis: 'y', + // 0th scroll snap shows the 0th slide only. + slideRegistry: [[0]], + }); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + children[0].getBoundingClientRect = vi.fn().mockReturnValue({ + width: 200, + height: 800, + }); + + callEmblaHandler(emblaApi, 'settle'); + + expect(parent.style.maxHeight).toBeFalsy(); + }); + + it('should not set container height when slide dimensions are invalid', () => { + const plugin = AutoSize(); + const parent = createParent(); + const children = createTestSlideNodes(); + const emblaApi = createEmblaApiInstance({ + containerNode: parent, + selectedScrollSnap: 0, + slideNodes: children, + axis: 'x', + // 0th scroll snap shows the 0th slide only. + slideRegistry: [[0]], + }); + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + children[0].getBoundingClientRect = vi.fn().mockReturnValue(NaN); + callEmblaHandler(emblaApi, 'settle'); + + children[0].getBoundingClientRect = vi.fn().mockReturnValue(0); + callEmblaHandler(emblaApi, 'settle'); + + expect(parent.style.maxHeight).toBeFalsy(); + }); +}); diff --git a/tests/utils/embla/reinit-controller.test.ts b/tests/utils/embla/reinit-controller.test.ts new file mode 100644 index 00000000..38e03ba7 --- /dev/null +++ b/tests/utils/embla/reinit-controller.test.ts @@ -0,0 +1,59 @@ +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { EmblaReInitController } from '../../../src/utils/embla/reinit-controller'; +import { requestAnimationFrameMock } from '../../test-utils'; +import { callEmblaHandler, createEmblaApiInstance } from './test-utils'; + +vi.mock('lodash-es/debounce', () => ({ + default: vi.fn((fn) => fn), +})); + +// @vitest-environment jsdom +describe('EmblaReInitController', () => { + beforeAll(() => { + window.requestAnimationFrame = requestAnimationFrameMock; + }); + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('should construct', () => { + const emblaApi = createEmblaApiInstance(); + new EmblaReInitController(emblaApi); + expect(emblaApi.on).toBeCalledWith('scroll', expect.anything()); + expect(emblaApi.on).toBeCalledWith('settle', expect.anything()); + expect(emblaApi.on).toBeCalledWith('destroy', expect.anything()); + }); + + it('should destroy', () => { + const emblaApi = createEmblaApiInstance(); + const controller = new EmblaReInitController(emblaApi); + + controller.destroy(); + + expect(emblaApi.off).toBeCalledWith('scroll', expect.anything()); + expect(emblaApi.off).toBeCalledWith('settle', expect.anything()); + expect(emblaApi.off).toBeCalledWith('destroy', expect.anything()); + }); + + it('should reinit when not scrolling', () => { + const emblaApi = createEmblaApiInstance(); + const controller = new EmblaReInitController(emblaApi); + + controller.reinit(); + + expect(emblaApi.reInit).toBeCalled(); + }); + + it('should carefully reinit when scrolling', () => { + const emblaApi = createEmblaApiInstance(); + const controller = new EmblaReInitController(emblaApi); + + callEmblaHandler(emblaApi, 'scroll'); + + controller.reinit(); + expect(emblaApi.reInit).not.toBeCalled(); + + callEmblaHandler(emblaApi, 'settle'); + expect(emblaApi.reInit).toBeCalled(); + }); +}); diff --git a/tests/utils/embla/test-utils.ts b/tests/utils/embla/test-utils.ts new file mode 100644 index 00000000..e3ab0389 --- /dev/null +++ b/tests/utils/embla/test-utils.ts @@ -0,0 +1,132 @@ +import { EmblaCarouselType, EmblaEventType } from 'embla-carousel'; +import { EngineType } from 'embla-carousel/components/Engine'; +import { LooseOptionsType } from 'embla-carousel/components/Options'; +import { OptionsHandlerType } from 'embla-carousel/components/OptionsHandler'; +import merge from 'lodash-es/merge'; +import { vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; + +export const createTestEmblaOptionHandler = (): OptionsHandlerType => ({ + mergeOptions: ( + optionsA: TypeA, + optionsB?: TypeB, + ): TypeA => { + return merge({}, optionsA, optionsB); + }, + optionsAtMedia: (options: Type): Type => { + return options; + }, + optionsMediaQueries: (_optionsList: LooseOptionsType[]): MediaQueryList[] => [], +}); + +export const callEmblaHandler = ( + emblaApi: EmblaCarouselType | null, + eventName: EmblaEventType, +): void => { + if (!emblaApi) { + return; + } + const mock = vi.mocked(emblaApi.on).mock; + for (const [evt, cb] of mock.calls) { + if (evt === eventName) { + cb(emblaApi, evt); + } + } +}; + +export const callVisibilityHandler = (): void => { + const mock = vi.mocked(global.document.addEventListener).mock; + for (const [evt, cb] of mock.calls) { + if (evt === 'visibilitychange' && typeof cb === 'function') { + cb(new Event('foo')); + } + } +}; + +export const callIntersectionHandler = (intersecting = true, n = 0): void => { + const mockResult = vi.mocked(IntersectionObserver).mock.results[n]; + if (mockResult.type !== 'return') { + return; + } + const observer = mockResult.value; + vi.mocked(IntersectionObserver).mock.calls[n][0]( + // Note this is a very incomplete / invalid IntersectionObserverEntry that + // just provides the bare basics current implementation uses. + intersecting ? [{ isIntersecting: true } as IntersectionObserverEntry] : [], + observer, + ); +}; + +export const callMutationHandler = (n = 0): void => { + const mockResult = vi.mocked(MutationObserver).mock.results[n]; + if (mockResult.type !== 'return') { + return; + } + const observer = mockResult.value; + vi.mocked(MutationObserver).mock.calls[n][0]( + // Note this is a very incomplete / invalid IntersectionObserverEntry that + // just provides the bare basics current implementation uses. + [], + observer, + ); +}; + +export const callResizeHandler = ( + entries: { + target: HTMLElement; + width: number; + height: number; + }[], + n = 0, +): void => { + const mockResult = vi.mocked(ResizeObserver).mock.results[n]; + if (mockResult.type !== 'return') { + return; + } + const observer = mockResult.value; + vi.mocked(ResizeObserver).mock.calls[n][0]( + // Note this is a very incomplete / invalid ResizeObserverEntry that + // just provides the bare basics current implementation uses. + entries.map( + (entry) => + ({ + target: entry.target, + contentRect: { + height: entry.height, + width: entry.width, + }, + } as unknown as ResizeObserverEntry), + ), + observer, + ); +}; + +export const createEmblaApiInstance = (options?: { + slideNodes?: HTMLElement[]; + selectedScrollSnap?: number; + previousScrollSnap?: number; + containerNode?: HTMLElement; + axis?: 'x' | 'y'; + slideRegistry?: number[][]; +}): EmblaCarouselType => { + const emblaApi = mock(); + emblaApi.slideNodes.mockReturnValue(options?.slideNodes ?? createTestSlideNodes()); + emblaApi.selectedScrollSnap.mockReturnValue(options?.selectedScrollSnap ?? 0); + emblaApi.previousScrollSnap.mockReturnValue(options?.previousScrollSnap ?? 0); + emblaApi.containerNode.mockReturnValue( + options?.containerNode ?? document.createElement('div'), + ); + emblaApi.internalEngine.mockReturnValue({ + options: { axis: options?.axis ?? 'x' }, + ...(options?.slideRegistry && { slideRegistry: options.slideRegistry }), + } as EngineType); + return emblaApi; +}; + +export const createTestSlideNodes = (options?: { + n?: number; +}): HTMLElement[] => { + return [...Array(options?.n ?? 10).keys()].map((_) => + document.createElement('div'), + ); +}; diff --git a/tests/utils/media-grid-controller.test.ts b/tests/utils/media-grid-controller.test.ts index 2066647b..4b19b6f9 100644 --- a/tests/utils/media-grid-controller.test.ts +++ b/tests/utils/media-grid-controller.test.ts @@ -8,8 +8,10 @@ import { } from '../../src/utils/media-grid-controller'; import { dispatchExistingMediaLoadedInfoAsEvent } from '../../src/utils/media-info'; import { - createMutationObserverImplementation, - createResizeObserverImplementation, + MutationObserverMock, + ResizeObserverMock, + createSlot, + createSlotHost, } from '../test-utils'; vi.mock('lodash-es/throttle', () => ({ @@ -41,7 +43,7 @@ const setElementWidth = (element: HTMLElement, width: number): void => { }); }; -const createHost = (options?: { +const createParent = (options?: { children?: HTMLElement[]; width?: number; }): HTMLElement => { @@ -54,28 +56,6 @@ const createHost = (options?: { return host; }; -const createSlotParent = (): HTMLElement => { - const parent = document.createElement('div'); - parent.attachShadow({ mode: 'open' }); - return parent; -}; - -const createSlotHost = (options?: { - children?: HTMLElement[]; - parent?: HTMLElement; -}): HTMLSlotElement => { - const parent = options?.parent ?? createSlotParent(); - const slot = document.createElement('slot'); - parent.shadowRoot?.append(slot); - - if (options?.children) { - // Children will automatically be slotted into the default slot. - parent.append(...options.children); - } - - return slot; -}; - const createController = (host: HTMLElement, options?: MediaGridConstructorOptions) => { return new MediaGridController(host, options); }; @@ -101,30 +81,20 @@ describe('MediaGridController', () => { beforeEach(() => { vi.clearAllMocks(); - - global.ResizeObserver = vi - .fn() - // Caution: Order must match the order of initialization in - // media-grid-controller.ts . - .mockImplementationOnce(createResizeObserverImplementation()) - .mockImplementationOnce(createResizeObserverImplementation()); - - global.MutationObserver = vi - .fn() - .mockImplementation(createMutationObserverImplementation()); - //global.MutationObserver = mock(); + vi.stubGlobal('MutationObserver', MutationObserverMock); + vi.stubGlobal('ResizeObserver', ResizeObserverMock); }); it('should be constructable', () => { - const controller = createController(createHost()); + const controller = createController(createParent()); expect(controller).toBeTruthy(); expect(masonry.layout).toBeCalled(); }); it('should set grid contents correctly from regular elements', () => { const children = createChildren(); - const host = createHost({ children: children }); - const controller = createController(host); + const parent = createParent({ children: children }); + const controller = createController(parent); expect(controller.getGridContents()).toEqual( new Map([ ['0', children[0]], @@ -138,7 +108,8 @@ describe('MediaGridController', () => { it('should set grid contents correctly from slotted elements', () => { const children = createChildren(); - const host = createSlotHost({ children: children }); + const slot = createSlot(); + const host = createSlotHost({ slot: slot, children: children }); const controller = createController(host); expect(controller.getGridContents()).toEqual( new Map([ @@ -152,7 +123,10 @@ describe('MediaGridController', () => { it('should select element', () => { const children = createChildren(); - const controller = createController(createSlotHost({ children: children })); + const slot = createSlot(); + createSlotHost({ slot: slot, children: children }); + + const controller = createController(slot); // All children should be unselected. expect(controller.getSelected()).toBeNull(); @@ -176,7 +150,10 @@ describe('MediaGridController', () => { }); it('should re-select element', () => { - const controller = createController(createSlotHost({ children: createChildren() })); + const children = createChildren(); + const slot = createSlot(); + createSlotHost({ slot: slot, children: children }); + const controller = createController(slot); // All children should be unselected. expect(controller.getSelected()).toBeNull(); @@ -190,16 +167,14 @@ describe('MediaGridController', () => { it('should dispatch media loaded info on selection', () => { const children = createChildren(); - const host = createSlotHost({ children: children }); - const controller = createController(host); + const slot = createSlot(); + const host = createSlotHost({ slot: slot, children: children }); + const controller = createController(slot); const mediaLoadedInfoHandler = vi.fn(); host.addEventListener('frigate-card:media:loaded', mediaLoadedInfoHandler); dispatchExistingMediaLoadedInfoAsEvent(children[0], mediaLoadedInfo); - // Nothing is selected, so the event should not have propagated. - expect(mediaLoadedInfoHandler).not.toBeCalled(); - controller.selectCell('0'); expect(mediaLoadedInfoHandler).toBeCalledWith( expect.objectContaining({ @@ -208,9 +183,45 @@ describe('MediaGridController', () => { ); }); + it('should dispatch media loaded info when cell is selected', () => { + const children = createChildren(); + const slot = createSlot(); + const host = createSlotHost({ slot: slot, children: children }); + const controller = createController(slot); + + controller.selectCell('0'); + + const mediaLoadedInfoHandler = vi.fn(); + host.addEventListener('frigate-card:media:loaded', mediaLoadedInfoHandler); + dispatchExistingMediaLoadedInfoAsEvent(children[0], mediaLoadedInfo); + + expect(mediaLoadedInfoHandler).toBeCalledWith( + expect.objectContaining({ + detail: mediaLoadedInfo, + }), + ); + }); + + it('should not dispatch media loaded info when cell is not selected', () => { + const children = createChildren(); + const slot = createSlot(); + const host = createSlotHost({ slot: slot, children: children }); + const controller = createController(host); + + controller.selectCell('1'); + + const mediaLoadedInfoHandler = vi.fn(); + host.addEventListener('frigate-card:media:loaded', mediaLoadedInfoHandler); + dispatchExistingMediaLoadedInfoAsEvent(children[0], mediaLoadedInfo); + + // Another element is selected, so the event should not have propagated. + expect(mediaLoadedInfoHandler).not.toBeCalled(); + }); + it('should unselect', () => { const children = createChildren(); - const host = createSlotHost({ children: children }); + const slot = createSlot(); + const host = createSlotHost({ slot: slot, children: children }); const controller = createController(host); const unselectedHandler = vi.fn(); @@ -234,20 +245,29 @@ describe('MediaGridController', () => { } // Expect handlers to have been called. - expect(unselectedHandler).toBeCalled(); - expect(unloadMediaHandler).toBeCalled(); + expect(unselectedHandler).toBeCalledTimes(1); + expect(unloadMediaHandler).toBeCalledTimes(1); + + // Unselecting a second time should do nothing. + controller.unselectAll(); + + expect(unselectedHandler).toBeCalledTimes(1); + expect(unloadMediaHandler).toBeCalledTimes(1); }); it('should select in constructor', () => { const children = createChildren(); - const host = createSlotHost({ children: children }); + const slot = createSlot(); + const host = createSlotHost({ slot: slot, children: children }); const controller = createController(host, { selected: '2' }); + expect(controller.getSelected()).toBe('2'); }); it('should respect grid attribute option', () => { const children = createChildren(['one', 'two', 'three'], 'test-id'); - const host = createSlotHost({ children: children }); + const slot = createSlot(); + const host = createSlotHost({ slot: slot, children: children }); const controller = createController(host, { idAttribute: 'test-id' }); expect(controller.getGridContents()).toEqual( new Map([ @@ -258,10 +278,21 @@ describe('MediaGridController', () => { ); }); - it('should destroy', () => { + it('should destroy with regular elements', () => { const children = createChildren(); - const host = createSlotHost({ children: children }); - const controller = createController(host); + const parent = createParent({ children: children }); + const controller = createController(parent); + expect(controller.getGridSize()).toBe(3); + controller.destroy(); + expect(controller.getGridSize()).toBe(0); + }); + + it('should destroy with slotted elements', () => { + const children = createChildren(); + const slot = createSlot(); + createSlotHost({ slot: slot, children: children }); + const controller = createController(slot); + expect(controller.getGridSize()).toBe(3); controller.destroy(); expect(controller.getGridSize()).toBe(0); @@ -269,16 +300,16 @@ describe('MediaGridController', () => { it('should replace children when they change', () => { const children = createChildren(); - const host = createHost({ children: children }); - const controller = createController(host, { selected: '1' }); + const parent = createParent({ children: children }); + const controller = createController(parent, { selected: '1' }); dispatchExistingMediaLoadedInfoAsEvent(children[0], mediaLoadedInfo); expect(controller.getSelected()).toBe('1'); expect(controller.getGridSize()).toBe(3); - children.forEach((child) => host.removeChild(child)); + children.forEach((child) => parent.removeChild(child)); const newChildren = createChildren(['one', 'two', 'three']); - newChildren.forEach((child) => host.appendChild(child)); + newChildren.forEach((child) => parent.appendChild(child)); triggerMutationObserver(); @@ -294,19 +325,19 @@ describe('MediaGridController', () => { it('should replace children of a slot when they change', () => { const children = createChildren(); - const slotParent = createSlotParent(); - const host = createSlotHost({ children: children, parent: slotParent }); + const slot = createSlot(); + const host = createSlotHost({ slot: slot, children: children }); - const controller = createController(host, { selected: '1' }); + const controller = createController(slot, { selected: '1' }); expect(controller.getSelected()).toBe('1'); expect(controller.getGridSize()).toBe(3); - children.forEach((child) => slotParent.removeChild(child)); + children.forEach((child) => host.removeChild(child)); const newChildren = createChildren(['one', 'two', 'three']); - newChildren.forEach((child) => slotParent.append(child)); + newChildren.forEach((child) => host.append(child)); - host.dispatchEvent(new Event('slotchange')); + slot.dispatchEvent(new Event('slotchange')); expect(controller.getGridContents()).toEqual( new Map([ @@ -320,10 +351,10 @@ describe('MediaGridController', () => { it('should construct masonry correctly', () => { const children = createChildren(); - const host = createHost({ children: children }); - createController(host); + const parent = createParent({ children: children }); + createController(parent); expect(Masonry).toBeCalledWith( - host, + parent, expect.objectContaining({ initLayout: false, percentPosition: true, @@ -333,57 +364,85 @@ describe('MediaGridController', () => { }); it('should set default column size correctly', () => { - const host = createHost({ children: createChildren() }); - createController(host); + const parent = createParent({ children: createChildren() }); + createController(parent); expect(Masonry).toBeCalledWith( - host, + parent, expect.objectContaining({ columnWidth: 246, }), ); - expect(host.style.getPropertyValue('--frigate-card-grid-column-size')).toBe('246px'); + expect(parent.style.getPropertyValue('--frigate-card-grid-column-size')).toBe('246px'); }); it('should respect exact columns', () => { - const host = createHost({ children: createChildren(), width: 2000 }); - const controller = createController(host); + const parent = createParent({ children: createChildren(), width: 2000 }); + const controller = createController(parent); controller.setDisplayConfig({ mode: 'grid', grid_columns: 2 }); // Will have been called once on construction, and then again when the // number of columns changes. expect(Masonry).toBeCalledTimes(2); expect(Masonry).toBeCalledWith( - host, + parent, expect.objectContaining({ columnWidth: 1000, }), ); - expect(host.style.getPropertyValue('--frigate-card-grid-column-size')).toBe( + expect(parent.style.getPropertyValue('--frigate-card-grid-column-size')).toBe( '1000px', ); }); it('should respect selected width factor', () => { - const host = createHost({ children: createChildren(), width: 2000 }); - const controller = createController(host); + const parent = createParent({ children: createChildren(), width: 2000 }); + const controller = createController(parent); controller.setDisplayConfig({ mode: 'grid', grid_selected_width_factor: 3 }); expect( - host.style.getPropertyValue('--frigate-card-grid-selected-width-factor'), + parent.style.getPropertyValue('--frigate-card-grid-selected-width-factor'), + ).toBe('3'); + + // Setting the same config again should do nothing. + controller.setDisplayConfig({ mode: 'grid', grid_selected_width_factor: 3 }); + expect( + parent.style.getPropertyValue('--frigate-card-grid-selected-width-factor'), ).toBe('3'); }); - it('should select cell with interacted with', () => { + it('should select cell when interacted with', () => { const children = createChildren(); - const host = createHost({ children: children, width: 2000 }); - const controller = createController(host); + const parent = createParent({ children: children, width: 2000 }); + const controller = createController(parent); expect(controller.getSelected()).toBeNull(); + + const clickHandler = vi.fn(); + parent.addEventListener('click', clickHandler); + children[1].click(); + + // Click will not be allowed through. + expect(clickHandler).not.toBeCalled(); + expect(controller.getSelected()).toBe('1'); + }); + + it('should ignore interaction events on already selected cell', () => { + const children = createChildren(); + const parent = createParent({ children: children, width: 2000 }); + const controller = createController(parent); + controller.selectCell('1'); + + const clickHandler = vi.fn(); + parent.addEventListener('click', clickHandler); + children[1].click(); + + // Click will be allowed through. + expect(clickHandler).toBeCalled(); expect(controller.getSelected()).toBe('1'); }); it('should re-layout when child size changes', () => { - createController(createHost({ children: createChildren() })); + createController(createParent({ children: createChildren() })); vi.mocked(masonry.layout)?.mockClear(); triggerResizeObserver('cell'); @@ -392,32 +451,41 @@ describe('MediaGridController', () => { it('should re-create masonry when host size changes', () => { const children = createChildren(); - const host = createHost({ children: children }); - const controller = createController(host); + const parent = createParent({ children: children }); + createController(parent); expect(Masonry).toBeCalledWith( - host, + parent, expect.objectContaining({ columnWidth: 246, }), ); - expect(host.style.getPropertyValue('--frigate-card-grid-column-size')).toBe('246px'); + expect(parent.style.getPropertyValue('--frigate-card-grid-column-size')).toBe('246px'); // Clear mock state. vi.mocked(Masonry).mockClear(); vi.mocked(masonry.layout)?.mockClear(); // Resize the host. - setElementWidth(host, 2000); + setElementWidth(parent, 2000); triggerResizeObserver('host'); // Masonry should be reconstructed, styles set and layout called. expect(Masonry).toBeCalledWith( - host, + parent, expect.objectContaining({ columnWidth: 667, }), ); - expect(host.style.getPropertyValue('--frigate-card-grid-column-size')).toBe('667px'); + expect(parent.style.getPropertyValue('--frigate-card-grid-column-size')).toBe('667px'); expect(masonry.layout).toBeCalled(); + + // Clear mock state. + vi.mocked(Masonry).mockClear(); + vi.mocked(masonry.layout)?.mockClear(); + + // Triger with the same sizes. + triggerResizeObserver('host'); + expect(Masonry).not.toBeCalled(); + expect(masonry.layout).not.toBeCalled(); }); }); diff --git a/tests/utils/media.test.ts b/tests/utils/media.test.ts index 5e4aefc9..01859e85 100644 --- a/tests/utils/media.test.ts +++ b/tests/utils/media.test.ts @@ -108,6 +108,16 @@ describe('playMediaMutingIfNecessary', () => { expect(player.isMuted).toBeCalled(); expect(player.mute).toBeCalled(); }); + + it('should ignore calls without a video', async () => { + const player = mock(); + player.isMuted.mockReturnValue(false); + + await playMediaMutingIfNecessary(player); + + expect(player.isMuted).not.toBeCalled(); + expect(player.mute).not.toBeCalled(); + }); }); describe('constants', () => { diff --git a/tests/utils/menu-controller.test.ts b/tests/utils/menu-controller.test.ts index 00c578c5..ef193ef0 100644 --- a/tests/utils/menu-controller.test.ts +++ b/tests/utils/menu-controller.test.ts @@ -1,4 +1,5 @@ import { HomeAssistant } from 'custom-card-helpers'; +import isEqual from 'lodash-es/isEqual'; import screenfull from 'screenfull'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; @@ -160,6 +161,26 @@ describe('MenuButtonController', () => { }); }); + it('should not have a cameras menu without a visible camera', () => { + const cameraManager = createCameraManager({ + configs: new Map([ + ['camera-1', createCameraConfig()], + ['camera-2', createCameraConfig()], + ]), + }); + + vi.mocked(cameraManager.getStore()).getVisibleCameras.mockReturnValue(new Map()); + + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ + title: 'Cameras', + }), + ]), + ); + }); + it('should have substream button with single dependency', () => { const cameraManager = createCameraManager({ configs: new Map([ @@ -1122,7 +1143,17 @@ describe('MenuButtonController', () => { style: {}, }; controller.addDynamicMenuButton(button); - expect(calculateButtons(controller)).toContainEqual(button); + expect( + calculateButtons(controller).filter((menuButton) => isEqual(button, menuButton)) + .length, + ).toBe(1); + + // Adding it again will have no effect. + controller.addDynamicMenuButton(button); + expect( + calculateButtons(controller).filter((menuButton) => isEqual(button, menuButton)) + .length, + ).toBe(1); controller.removeDynamicMenuButton(button); expect(calculateButtons(controller)).not.toContainEqual(button); diff --git a/tests/utils/substream.test.ts b/tests/utils/substream.test.ts index 5a4dd1bd..bc0227b1 100644 --- a/tests/utils/substream.test.ts +++ b/tests/utils/substream.test.ts @@ -52,6 +52,20 @@ describe('createViewWithoutSubstream', () => { const newView = createViewWithoutSubstream(view); expect(newView?.context?.live?.overrides).toEqual(new Map()); }); + + it('should create view with overrides untouched', () => { + const view = new View({ + view: 'live', + camera: 'camera-1', + context: { + live: { + overrides: new Map([['camera-2', 'camera-3']]), + }, + }, + }); + const newView = createViewWithoutSubstream(view); + expect(newView?.context?.live?.overrides).toEqual(view.context?.live?.overrides); + }); }); describe('hasSubstream', () => { @@ -95,7 +109,7 @@ describe('createViewWithNextStream', () => { camera: 'camera', }); vi.mocked(getAllDependentCameras).mockReturnValue(new Set(['camera'])); - const cameraManager = createCameraManager() + const cameraManager = createCameraManager(); const newView = createViewWithNextStream(cameraManager, view); expect(newView.camera).toBe(view.camera); expect(newView.view).toBe(view.view); @@ -107,7 +121,7 @@ describe('createViewWithNextStream', () => { camera: 'camera', }); vi.mocked(getAllDependentCameras).mockReturnValue(new Set(['camera', 'camera2'])); - const cameraManager = createCameraManager() + const cameraManager = createCameraManager(); const newView = createViewWithNextStream(cameraManager, view); expect(newView.context?.live?.overrides).toEqual(new Map([['camera', 'camera2']])); }); @@ -122,7 +136,7 @@ describe('createViewWithNextStream', () => { }, }); vi.mocked(getAllDependentCameras).mockReturnValue(new Set(['camera', 'camera2'])); - const cameraManager = createCameraManager() + const cameraManager = createCameraManager(); const newView = createViewWithNextStream(cameraManager, view); expect(newView.context?.live?.overrides).toEqual(new Map([['camera', 'camera']])); }); @@ -137,7 +151,7 @@ describe('createViewWithNextStream', () => { }, }); vi.mocked(getAllDependentCameras).mockReturnValue(new Set(['camera', 'camera2'])); - const cameraManager = createCameraManager() + const cameraManager = createCameraManager(); const newView = createViewWithNextStream(cameraManager, view); expect(newView.context?.live?.overrides).toEqual(new Map([['camera', 'camera']])); }); diff --git a/tests/utils/zod.test.ts b/tests/utils/zod.test.ts index 0d55f48e..b2d1b837 100644 --- a/tests/utils/zod.test.ts +++ b/tests/utils/zod.test.ts @@ -1,9 +1,9 @@ import { describe, expect, it } from 'vitest'; -import { z } from 'zod'; +import { z, ZodError } from 'zod'; import { - deepRemoveDefaults, - getParseErrorKeys, - getParseErrorPaths, + deepRemoveDefaults, + getParseErrorKeys, + getParseErrorPaths, } from '../../src/utils/zod'; describe('deepRemoveDefaults', () => { @@ -88,4 +88,7 @@ describe('getParseErrorPaths', () => { new Set(['array[0] -> type', 'array[0] -> data']), ); }); + it('should get no paths for empty error', () => { + expect(getParseErrorPaths(new ZodError([]))).toEqual(new Set()); + }); }); diff --git a/tests/utils/zoom.test.ts b/tests/utils/zoom.test.ts index 9c81d8fe..f8817e2c 100644 --- a/tests/utils/zoom.test.ts +++ b/tests/utils/zoom.test.ts @@ -92,6 +92,27 @@ describe('Zoom', () => { expect(panzoom.handleUp).toBeCalledWith(ev_5); }); + it('should not respond to pointer when not zoomed', () => { + const element = document.createElement('div'); + + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + createAndRegisterZoom(element); + + const ev_1 = new PointerEvent('pointerdown'); + element.dispatchEvent(ev_1); + expect(panzoom.handleDown).not.toBeCalledWith(ev_1); + + const ev_2 = new PointerEvent('pointermove'); + element.dispatchEvent(ev_2); + expect(panzoom.handleDown).not.toBeCalledWith(ev_2); + + const ev_3 = new PointerEvent('pointerup'); + element.dispatchEvent(ev_3); + expect(panzoom.handleDown).not.toBeCalledWith(ev_3); + }); + it('should respond with touch', () => { mediaMediSpy.mockReturnValue({ matches: false }); @@ -252,4 +273,50 @@ describe('Zoom', () => { element.dispatchEvent(ev_2); expect(element.style.touchAction).toBeFalsy(); }); + + it('should not fire frigate cards when state has not changed or spurious events received', () => { + const element = document.createElement('div'); + + const zoomedFunc = vi.fn(); + const unzoomedFunc = vi.fn(); + + element.addEventListener('frigate-card:zoom:zoomed', zoomedFunc); + element.addEventListener('frigate-card:zoom:unzoomed', unzoomedFunc); + + vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); + + createAndRegisterZoom(element); + + const ev_1 = new CustomEvent('panzoomzoom', { + detail: { + x: 0, + y: 0, + scale: 1, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_1); + + // Unzoomed event with scale === 1, this._zoomed will already be false. + expect(unzoomedFunc).not.toBeCalled(); + expect(zoomedFunc).not.toBeCalled(); + + const ev_2 = new CustomEvent('panzoomzoom', { + detail: { + x: 0, + y: 0, + scale: 1.2, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_2); + expect(zoomedFunc).toBeCalledTimes(1); + expect(unzoomedFunc).not.toBeCalled(); + + // Another call when already zoomed will be ignored. + element.dispatchEvent(ev_2); + expect(zoomedFunc).toBeCalledTimes(1); + }); }); diff --git a/tests/view/media-queries-results.test.ts b/tests/view/media-queries-results.test.ts index aae224ef..4129af3a 100644 --- a/tests/view/media-queries-results.test.ts +++ b/tests/view/media-queries-results.test.ts @@ -243,4 +243,40 @@ describe('dispatchViewContextChangeEvent', () => { .map((media) => media.getID()), ).toEqual(['id-office-99', 'id-kitchen-99', 'id-office-99']); }); + + it('should get multiple selected results without main', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + }); + + expect( + results + .getMultipleSelectedResults({ main: false, allCameras: true }) + .map((media) => media.getID()), + ).toEqual(['id-kitchen-99', 'id-office-99']); + }); + + it('should get no results with invalid camera ID without main', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + }); + + expect( + results + .getMultipleSelectedResults({ main: false, cameraID: 'not-a-real-camera' }) + .map((media) => media.getID()), + ).toEqual([]); + }); + + it('should not demote main selection when selecting from a specific camera', () => { + const results = new MediaQueriesResults({ + results: generateViewMediaArray(), + }); + + results.selectIndex(42); + results.selectIndex(24, 'office'); + + expect(results.getSelectedIndex()).toBe(42); + expect(results.getSelectedIndex('office')).toBe(24); + }); }); diff --git a/tests/view/view.test.ts b/tests/view/view.test.ts index e19f5da3..0703f226 100644 --- a/tests/view/view.test.ts +++ b/tests/view/view.test.ts @@ -4,7 +4,7 @@ import { ViewMedia } from '../../src/view/media'; import { EventMediaQueries, RecordingMediaQueries } from '../../src/view/media-queries'; import { MediaQueriesResults } from '../../src/view/media-queries-results'; import { View, dispatchViewContextChangeEvent } from '../../src/view/view'; -import { createView, generateViewMediaArray } from '../test-utils'; +import { createView } from '../test-utils'; // @vitest-environment jsdom describe('View Basics', () => { @@ -122,6 +122,14 @@ describe('View Basics', () => { expect(view.context).toEqual({}); }); + it('should not remove context when no context', () => { + const view = createView(); + expect(view.context).toBeNull(); + + view.removeContext('live'); + expect(view.context).toBeNull(); + }); + it('should remove context property', () => { const view = createView({ context: { live: { overrides: new Map() } } }); @@ -129,6 +137,13 @@ describe('View Basics', () => { expect(view.context).toEqual({ live: {} }); }); + it('should not remove context property that does not exist', () => { + const view = createView({ context: {} }); + + view.removeContextProperty('live', 'overrides'); + expect(view.context).toEqual({}); + }); + it('should detect gallery views', () => { expect(createView({ view: 'clips' }).isGalleryView()).toBeTruthy(); expect(createView({ view: 'snapshots' }).isGalleryView()).toBeTruthy(); @@ -292,6 +307,28 @@ describe('View.adoptFromViewIfAppropriate', () => { expect(next.queryResults).toBe(queryResults); }); + it('should not adopt for gallery case if neither query nor results in current view', () => { + const current = createView({ + view: 'clip', + query: null, + queryResults: null, + }); + + const nextQuery = new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, + ]); + const nextResults = new MediaQueriesResults(); + const next = createView({ + view: 'clips', + query: nextQuery, + queryResults: nextResults, + }); + View.adoptFromViewIfAppropriate(next, current); + expect(next.view).toBe('clips'); + expect(next.query).toBe(nextQuery); + expect(next.queryResults).toBe(nextResults); + }); + it.each([ [ new EventMediaQueries([ @@ -311,7 +348,7 @@ describe('View.adoptFromViewIfAppropriate', () => { ]), 'recording', ], - ])('should adopt for media case', (mediaQueries, expectedView) => { + ])('should adopt in media case', (mediaQueries, expectedView) => { const current = createView({ view: 'media', query: mediaQueries, @@ -324,6 +361,54 @@ describe('View.adoptFromViewIfAppropriate', () => { expect(next.queryResults).toBeFalsy(); }); + it('should not adopt for mixed queries in media case', () => { + const query = new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasSnapshot: true }, + ]); + const results = new MediaQueriesResults(); + const current = createView({ + view: 'media', + query: query, + queryResults: results, + }); + const next = createView({ view: 'media' }); + View.adoptFromViewIfAppropriate(next, current); + + expect(next.view).toBe('media'); + expect(next.query).toBeNull(); + expect(next.queryResults).toBeNull(); + }); + + it('should not adopt when queries and results present in next view in media case', () => { + const currentQuery = new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera-1']), hasClip: true }, + { type: QueryType.Event, cameraIDs: new Set(['camera-1']), hasSnapshot: true }, + ]); + const currentResults = new MediaQueriesResults(); + const current = createView({ + view: 'media', + query: currentQuery, + queryResults: currentResults, + }); + + const nextQuery = new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera-2']), hasClip: true }, + { type: QueryType.Event, cameraIDs: new Set(['camera-2']), hasSnapshot: true }, + ]); + const nextResults = new MediaQueriesResults(); + const next = createView({ + view: 'media', + query: nextQuery, + queryResults: nextResults, + }); + View.adoptFromViewIfAppropriate(next, current); + + expect(next.view).toBe('media'); + expect(next.query).toBe(nextQuery); + expect(next.queryResults).toBe(nextResults); + }); + it('should not adopt for other case', () => { const query = new EventMediaQueries([ { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, @@ -431,11 +516,15 @@ describe('View.adoptFromViewIfAppropriate', () => { expect(createView({ view: 'media' }).supportsMultipleDisplayModes()).toBeTruthy(); expect(createView({ view: 'clip' }).supportsMultipleDisplayModes()).toBeTruthy(); expect(createView({ view: 'snapshot' }).supportsMultipleDisplayModes()).toBeTruthy(); - expect(createView({ view: 'recording' }).supportsMultipleDisplayModes()).toBeTruthy(); + expect( + createView({ view: 'recording' }).supportsMultipleDisplayModes(), + ).toBeTruthy(); expect(createView({ view: 'clips' }).supportsMultipleDisplayModes()).toBeFalsy(); expect(createView({ view: 'snapshots' }).supportsMultipleDisplayModes()).toBeFalsy(); - expect(createView({ view: 'recordings' }).supportsMultipleDisplayModes()).toBeFalsy(); + expect( + createView({ view: 'recordings' }).supportsMultipleDisplayModes(), + ).toBeFalsy(); expect(createView({ view: 'image' }).supportsMultipleDisplayModes()).toBeFalsy(); expect(createView({ view: 'timeline' }).supportsMultipleDisplayModes()).toBeFalsy(); }); diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 00000000..c5d2f145 --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'vitest/config'; + +// ts-prune-ignore-next +export default defineConfig({ + test: { + coverage: { + // Favor istanbul for coverage over v8 due to better accuracy. + provider: 'istanbul', + }, + }, +}); diff --git a/yarn.lock b/yarn.lock index 7bc02b0e..4d52591e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -22,6 +22,16 @@ __metadata: languageName: node linkType: hard +"@ampproject/remapping@npm:^2.2.0": + version: 2.2.1 + resolution: "@ampproject/remapping@npm:2.2.1" + dependencies: + "@jridgewell/gen-mapping": ^0.3.0 + "@jridgewell/trace-mapping": ^0.3.9 + checksum: 03c04fd526acc64a1f4df22651186f3e5ef0a9d6d6530ce4482ec9841269cf7a11dbb8af79237c282d721c5312024ff17529cd72cc4768c11e999b58e2302079 + languageName: node + linkType: hard + "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.18.6": version: 7.18.6 resolution: "@babel/code-frame@npm:7.18.6" @@ -31,6 +41,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.22.10, @babel/code-frame@npm:^7.22.5": + version: 7.22.13 + resolution: "@babel/code-frame@npm:7.22.13" + dependencies: + "@babel/highlight": ^7.22.13 + chalk: ^2.4.2 + checksum: 22e342c8077c8b77eeb11f554ecca2ba14153f707b85294fcf6070b6f6150aae88a7b7436dd88d8c9289970585f3fe5b9b941c5aa3aa26a6d5a8ef3f292da058 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.20.5": version: 7.20.14 resolution: "@babel/compat-data@npm:7.20.14" @@ -38,6 +58,36 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.22.9": + version: 7.22.9 + resolution: "@babel/compat-data@npm:7.22.9" + checksum: bed77d9044ce948b4327b30dd0de0779fa9f3a7ed1f2d31638714ed00229fa71fc4d1617ae0eb1fad419338d3658d0e9a5a083297451e09e73e078d0347ff808 + languageName: node + linkType: hard + +"@babel/core@npm:^7.12.3": + version: 7.22.11 + resolution: "@babel/core@npm:7.22.11" + dependencies: + "@ampproject/remapping": ^2.2.0 + "@babel/code-frame": ^7.22.10 + "@babel/generator": ^7.22.10 + "@babel/helper-compilation-targets": ^7.22.10 + "@babel/helper-module-transforms": ^7.22.9 + "@babel/helpers": ^7.22.11 + "@babel/parser": ^7.22.11 + "@babel/template": ^7.22.5 + "@babel/traverse": ^7.22.11 + "@babel/types": ^7.22.11 + convert-source-map: ^1.7.0 + debug: ^4.1.0 + gensync: ^1.0.0-beta.2 + json5: ^2.2.3 + semver: ^6.3.1 + checksum: f258b2539ea2e5bfe55a708c2f3e1093a1b4744f12becc35abeb896037b66210de9a8ad6296a706046d5dc3a24e564362b73a9b814e5bfe500c8baab60c22d2e + languageName: node + linkType: hard + "@babel/core@npm:^7.19.0": version: 7.20.12 resolution: "@babel/core@npm:7.20.12" @@ -72,6 +122,18 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.22.10": + version: 7.22.10 + resolution: "@babel/generator@npm:7.22.10" + dependencies: + "@babel/types": ^7.22.10 + "@jridgewell/gen-mapping": ^0.3.2 + "@jridgewell/trace-mapping": ^0.3.17 + jsesc: ^2.5.1 + checksum: 59a79730abdff9070692834bd3af179e7a9413fa2ff7f83dff3eb888765aeaeb2bfc7b0238a49613ed56e1af05956eff303cc139f2407eda8df974813e486074 + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-annotate-as-pure@npm:7.18.6" @@ -96,6 +158,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-compilation-targets@npm:^7.22.10": + version: 7.22.10 + resolution: "@babel/helper-compilation-targets@npm:7.22.10" + dependencies: + "@babel/compat-data": ^7.22.9 + "@babel/helper-validator-option": ^7.22.5 + browserslist: ^4.21.9 + lru-cache: ^5.1.1 + semver: ^6.3.1 + checksum: f6f1896816392bcff671bbe6e277307729aee53befb4a66ea126e2a91eda78d819a70d06fa384c74ef46c1595544b94dca50bef6c78438d9ffd31776dafbd435 + languageName: node + linkType: hard + "@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.20.12": version: 7.20.12 resolution: "@babel/helper-create-class-features-plugin@npm:7.20.12" @@ -121,6 +196,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-environment-visitor@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-environment-visitor@npm:7.22.5" + checksum: 248532077d732a34cd0844eb7b078ff917c3a8ec81a7f133593f71a860a582f05b60f818dc5049c2212e5baa12289c27889a4b81d56ef409b4863db49646c4b1 + languageName: node + linkType: hard + "@babel/helper-function-name@npm:^7.19.0": version: 7.19.0 resolution: "@babel/helper-function-name@npm:7.19.0" @@ -131,6 +213,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-function-name@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-function-name@npm:7.22.5" + dependencies: + "@babel/template": ^7.22.5 + "@babel/types": ^7.22.5 + checksum: 6b1f6ce1b1f4e513bf2c8385a557ea0dd7fa37971b9002ad19268ca4384bbe90c09681fe4c076013f33deabc63a53b341ed91e792de741b4b35e01c00238177a + languageName: node + linkType: hard + "@babel/helper-hoist-variables@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-hoist-variables@npm:7.18.6" @@ -140,6 +232,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-hoist-variables@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-hoist-variables@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: 394ca191b4ac908a76e7c50ab52102669efe3a1c277033e49467913c7ed6f7c64d7eacbeabf3bed39ea1f41731e22993f763b1edce0f74ff8563fd1f380d92cc + languageName: node + linkType: hard + "@babel/helper-member-expression-to-functions@npm:^7.20.7": version: 7.20.7 resolution: "@babel/helper-member-expression-to-functions@npm:7.20.7" @@ -158,6 +259,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-module-imports@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: 9ac2b0404fa38b80bdf2653fbeaf8e8a43ccb41bd505f9741d820ed95d3c4e037c62a1bcdcb6c9527d7798d2e595924c4d025daed73283badc180ada2c9c49ad + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.20.11": version: 7.20.11 resolution: "@babel/helper-module-transforms@npm:7.20.11" @@ -174,6 +284,21 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.22.9": + version: 7.22.9 + resolution: "@babel/helper-module-transforms@npm:7.22.9" + dependencies: + "@babel/helper-environment-visitor": ^7.22.5 + "@babel/helper-module-imports": ^7.22.5 + "@babel/helper-simple-access": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/helper-validator-identifier": ^7.22.5 + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 2751f77660518cf4ff027514d6f4794f04598c6393be7b04b8e46c6e21606e11c19f3f57ab6129a9c21bacdf8b3ffe3af87bb401d972f34af2d0ffde02ac3001 + languageName: node + linkType: hard + "@babel/helper-optimise-call-expression@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-optimise-call-expression@npm:7.18.6" @@ -213,6 +338,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-simple-access@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-simple-access@npm:7.22.5" + dependencies: + "@babel/types": ^7.22.5 + checksum: fe9686714caf7d70aedb46c3cce090f8b915b206e09225f1e4dbc416786c2fdbbee40b38b23c268b7ccef749dd2db35f255338fb4f2444429874d900dede5ad2 + languageName: node + linkType: hard + "@babel/helper-skip-transparent-expression-wrappers@npm:^7.20.0": version: 7.20.0 resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.20.0" @@ -231,6 +365,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-split-export-declaration@npm:^7.22.6": + version: 7.22.6 + resolution: "@babel/helper-split-export-declaration@npm:7.22.6" + dependencies: + "@babel/types": ^7.22.5 + checksum: e141cace583b19d9195f9c2b8e17a3ae913b7ee9b8120246d0f9ca349ca6f03cb2c001fd5ec57488c544347c0bb584afec66c936511e447fd20a360e591ac921 + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.19.4": version: 7.19.4 resolution: "@babel/helper-string-parser@npm:7.19.4" @@ -238,6 +381,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-string-parser@npm:7.22.5" + checksum: 836851ca5ec813077bbb303acc992d75a360267aa3b5de7134d220411c852a6f17de7c0d0b8c8dcc0f567f67874c00f4528672b2a4f1bc978a3ada64c8c78467 + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.18.6, @babel/helper-validator-identifier@npm:^7.19.1": version: 7.19.1 resolution: "@babel/helper-validator-identifier@npm:7.19.1" @@ -245,6 +395,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-validator-identifier@npm:7.22.5" + checksum: 7f0f30113474a28298c12161763b49de5018732290ca4de13cdaefd4fd0d635a6fe3f6686c37a02905fb1e64f21a5ee2b55140cf7b070e729f1bd66866506aea + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.18.6": version: 7.18.6 resolution: "@babel/helper-validator-option@npm:7.18.6" @@ -252,6 +409,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-validator-option@npm:7.22.5" + checksum: bbeca8a85ee86990215c0424997438b388b8d642d69b9f86c375a174d3cdeb270efafd1ff128bc7a1d370923d13b6e45829ba8581c027620e83e3a80c5c414b3 + languageName: node + linkType: hard + "@babel/helpers@npm:^7.20.7": version: 7.20.13 resolution: "@babel/helpers@npm:7.20.13" @@ -263,6 +427,17 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/helpers@npm:7.22.11" + dependencies: + "@babel/template": ^7.22.5 + "@babel/traverse": ^7.22.11 + "@babel/types": ^7.22.11 + checksum: 93186544228b5e371486466ec3b86a77cce91beeff24a5670ca8ec46d50328f7700dab82d532351286e9d68624dc51d6d71589b051dd9535e44be077a43ec013 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.18.6": version: 7.18.6 resolution: "@babel/highlight@npm:7.18.6" @@ -274,6 +449,26 @@ __metadata: languageName: node linkType: hard +"@babel/highlight@npm:^7.22.13": + version: 7.22.13 + resolution: "@babel/highlight@npm:7.22.13" + dependencies: + "@babel/helper-validator-identifier": ^7.22.5 + chalk: ^2.4.2 + js-tokens: ^4.0.0 + checksum: 7266d2bff8aa8fc78eb65b6e92a8211e12897a731126a282d2f9bb50d8fcaa4c1b02af2284f990ac7e3ab8d892d448a2cab8f5ed0ea8a90bce2c025b11ebe802 + languageName: node + linkType: hard + +"@babel/parser@npm:^7.14.7, @babel/parser@npm:^7.22.11, @babel/parser@npm:^7.22.5": + version: 7.22.14 + resolution: "@babel/parser@npm:7.22.14" + bin: + parser: ./bin/babel-parser.js + checksum: a2293971f0889726a3d5a35fcceedc71d2fa4c8d97f438fc348fe0cf7e739affc6e2665e4c6ddd4900714772e19bfd5d6feb967ca1f623b894c0099ecb148b52 + languageName: node + linkType: hard + "@babel/parser@npm:^7.20.13, @babel/parser@npm:^7.20.7": version: 7.20.15 resolution: "@babel/parser@npm:7.20.15" @@ -332,6 +527,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/template@npm:7.22.5" + dependencies: + "@babel/code-frame": ^7.22.5 + "@babel/parser": ^7.22.5 + "@babel/types": ^7.22.5 + checksum: c5746410164039aca61829cdb42e9a55410f43cace6f51ca443313f3d0bdfa9a5a330d0b0df73dc17ef885c72104234ae05efede37c1cc8a72dc9f93425977a3 + languageName: node + linkType: hard + "@babel/traverse@npm:^7.20.10, @babel/traverse@npm:^7.20.12, @babel/traverse@npm:^7.20.13, @babel/traverse@npm:^7.20.7": version: 7.20.13 resolution: "@babel/traverse@npm:7.20.13" @@ -350,6 +556,24 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.22.11": + version: 7.22.11 + resolution: "@babel/traverse@npm:7.22.11" + dependencies: + "@babel/code-frame": ^7.22.10 + "@babel/generator": ^7.22.10 + "@babel/helper-environment-visitor": ^7.22.5 + "@babel/helper-function-name": ^7.22.5 + "@babel/helper-hoist-variables": ^7.22.5 + "@babel/helper-split-export-declaration": ^7.22.6 + "@babel/parser": ^7.22.11 + "@babel/types": ^7.22.11 + debug: ^4.1.0 + globals: ^11.1.0 + checksum: 4ad62d548ca8b95dbf45bae16cc167428f174f3c837d55a5878b1f17bdbc8b384d6df741dc7c461b62c04d881cf25644d3ab885909ba46e3ac43224e2b15b504 + languageName: node + linkType: hard + "@babel/types@npm:^7.18.6, @babel/types@npm:^7.19.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.2, @babel/types@npm:^7.20.7, @babel/types@npm:^7.8.3": version: 7.20.7 resolution: "@babel/types@npm:7.20.7" @@ -361,10 +585,14 @@ __metadata: languageName: node linkType: hard -"@bcoe/v8-coverage@npm:^0.2.3": - version: 0.2.3 - resolution: "@bcoe/v8-coverage@npm:0.2.3" - checksum: 850f9305536d0f2bd13e9e0881cb5f02e4f93fad1189f7b2d4bebf694e3206924eadee1068130d43c11b750efcc9405f88a8e42ef098b6d75239c0f047de1a27 +"@babel/types@npm:^7.22.10, @babel/types@npm:^7.22.11, @babel/types@npm:^7.22.5": + version: 7.22.11 + resolution: "@babel/types@npm:7.22.11" + dependencies: + "@babel/helper-string-parser": ^7.22.5 + "@babel/helper-validator-identifier": ^7.22.5 + to-fast-properties: ^2.0.0 + checksum: 431a6446896adb62c876d0fe75263835735d3c974aae05356a87eb55f087c20a777028cf08eadcace7993e058bbafe3b21ce2119363222c6cef9eedd7a204810 languageName: node linkType: hard @@ -672,13 +900,22 @@ __metadata: languageName: node linkType: hard -"@istanbuljs/schema@npm:^0.1.2, @istanbuljs/schema@npm:^0.1.3": +"@istanbuljs/schema@npm:^0.1.2": version: 0.1.3 resolution: "@istanbuljs/schema@npm:0.1.3" checksum: 5282759d961d61350f33d9118d16bcaed914ebf8061a52f4fa474b2cb08720c9c81d165e13b82f2e5a8a212cc5af482f0c6fc1ac27b9e067e5394c9a6ed186c9 languageName: node linkType: hard +"@jest/schemas@npm:^29.6.3": + version: 29.6.3 + resolution: "@jest/schemas@npm:29.6.3" + dependencies: + "@sinclair/typebox": ^0.27.8 + checksum: 910040425f0fc93cd13e68c750b7885590b8839066dfa0cd78e7def07bbb708ad869381f725945d66f2284de5663bbecf63e8fdd856e2ae6e261ba30b1687e93 + languageName: node + linkType: hard + "@jridgewell/gen-mapping@npm:^0.1.0": version: 0.1.1 resolution: "@jridgewell/gen-mapping@npm:0.1.1" @@ -707,6 +944,13 @@ __metadata: languageName: node linkType: hard +"@jridgewell/resolve-uri@npm:^3.1.0": + version: 3.1.1 + resolution: "@jridgewell/resolve-uri@npm:3.1.1" + checksum: f5b441fe7900eab4f9155b3b93f9800a916257f4e8563afbcd3b5a5337b55e52bd8ae6735453b1b745457d9f6cdb16d74cd6220bbdd98cf153239e13f6cbb653 + languageName: node + linkType: hard + "@jridgewell/set-array@npm:^1.0.0, @jridgewell/set-array@npm:^1.0.1": version: 1.1.2 resolution: "@jridgewell/set-array@npm:1.1.2" @@ -731,7 +975,24 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.12, @jridgewell/trace-mapping@npm:^0.3.9": +"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.15": + version: 1.4.15 + resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" + checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.17": + version: 0.3.19 + resolution: "@jridgewell/trace-mapping@npm:0.3.19" + dependencies: + "@jridgewell/resolve-uri": ^3.1.0 + "@jridgewell/sourcemap-codec": ^1.4.14 + checksum: 956a6f0f6fec060fb48c6bf1f5ec2064e13cd38c8be3873877d4b92b4a27ba58289a34071752671262a3e3c202abcc3fa2aac64d8447b4b0fa1ba3c9047f1c20 + languageName: node + linkType: hard + +"@jridgewell/trace-mapping@npm:^0.3.9": version: 0.3.17 resolution: "@jridgewell/trace-mapping@npm:0.3.17" dependencies: @@ -957,6 +1218,13 @@ __metadata: languageName: node linkType: hard +"@sinclair/typebox@npm:^0.27.8": + version: 0.27.8 + resolution: "@sinclair/typebox@npm:0.27.8" + checksum: 00bd7362a3439021aa1ea51b0e0d0a0e8ca1351a3d54c606b115fdcc49b51b16db6e5f43b4fe7a28c38688523e22a94d49dd31168868b655f0d4d50f032d07a1 + languageName: node + linkType: hard + "@stencil/core@npm:^2.20.0, @stencil/core@npm:^2.3.0": version: 2.22.2 resolution: "@stencil/core@npm:2.22.2" @@ -1008,13 +1276,20 @@ __metadata: languageName: node linkType: hard -"@types/chai@npm:*, @types/chai@npm:^4.3.4": +"@types/chai@npm:*": version: 4.3.4 resolution: "@types/chai@npm:4.3.4" checksum: 571184967beb03bf64c4392a13a7d44e72da9af5a1e83077ff81c39cf59c0fda2a5c78d2005084601cf8f3d11726608574d8b5b4a0e3e9736792807afd926cd0 languageName: node linkType: hard +"@types/chai@npm:^4.3.5": + version: 4.3.5 + resolution: "@types/chai@npm:4.3.5" + checksum: c8f26a88c6b5b53a3275c7f5ff8f107028e3cbb9ff26795fff5f3d9dea07106a54ce9e2dce5e40347f7c4cc35657900aaf0c83934a25a1ae12e61e0f5516e431 + languageName: node + linkType: hard + "@types/cssnano@npm:^5.0.0": version: 5.1.0 resolution: "@types/cssnano@npm:5.1.0" @@ -1045,13 +1320,6 @@ __metadata: languageName: node linkType: hard -"@types/istanbul-lib-coverage@npm:^2.0.1": - version: 2.0.4 - resolution: "@types/istanbul-lib-coverage@npm:2.0.4" - checksum: a25d7589ee65c94d31464c16b72a9dc81dfa0bea9d3e105ae03882d616e2a0712a9c101a599ec482d297c3591e16336962878cb3eb1a0a62d5b76d277a890ce7 - languageName: node - linkType: hard - "@types/jquery@npm:*": version: 3.5.16 resolution: "@types/jquery@npm:3.5.16" @@ -1265,59 +1533,72 @@ __metadata: languageName: node linkType: hard -"@vitest/coverage-c8@npm:^0.29.8": - version: 0.29.8 - resolution: "@vitest/coverage-c8@npm:0.29.8" +"@vitest/coverage-istanbul@npm:^0.34.3": + version: 0.34.3 + resolution: "@vitest/coverage-istanbul@npm:0.34.3" dependencies: - c8: ^7.13.0 - picocolors: ^1.0.0 - std-env: ^3.3.1 + istanbul-lib-coverage: ^3.2.0 + istanbul-lib-instrument: ^6.0.0 + istanbul-lib-report: ^3.0.1 + istanbul-lib-source-maps: ^4.0.1 + istanbul-reports: ^3.1.5 + test-exclude: ^6.0.0 peerDependencies: - vitest: ">=0.29.0 <1" - checksum: 610bd2917aa160f5bf641f4d4dec539524039ea98fdc98a8d9288c7ea05090d7028d4504b8e1ecc1de1d1700c9a61a55abf285559da2c4bc8df238e559a505f7 + vitest: ">=0.32.0 <1" + checksum: 6e5f437d8b3d1e93aa25180661d47339b2a1df24686a5d7154cd266db47fbf0c2a2faa58290f79dd009e531e16c14bfb8a0fb49031d9a14b6e962de82155eb12 languageName: node linkType: hard -"@vitest/expect@npm:0.29.8": - version: 0.29.8 - resolution: "@vitest/expect@npm:0.29.8" +"@vitest/expect@npm:0.34.3": + version: 0.34.3 + resolution: "@vitest/expect@npm:0.34.3" dependencies: - "@vitest/spy": 0.29.8 - "@vitest/utils": 0.29.8 + "@vitest/spy": 0.34.3 + "@vitest/utils": 0.34.3 chai: ^4.3.7 - checksum: a80f9c352a979eb46690be2ea54b5ca391d3575b4053be80c1359325fb0cea913d6217f48d54e64ff5dda3b15bd7a6873a5f8128e8c098f7ebad1365d4065c5e + checksum: 79afaa37d2efb7bb5503332caf389860b2261f198dbe61557e8061262b628d18658e59eb51d1808ecd35fc59f4bb4d04c0e0f97a27c7db02584ab5b424147b8d languageName: node linkType: hard -"@vitest/runner@npm:0.29.8": - version: 0.29.8 - resolution: "@vitest/runner@npm:0.29.8" +"@vitest/runner@npm:0.34.3": + version: 0.34.3 + resolution: "@vitest/runner@npm:0.34.3" dependencies: - "@vitest/utils": 0.29.8 + "@vitest/utils": 0.34.3 p-limit: ^4.0.0 - pathe: ^1.1.0 - checksum: 8305370ff6c3fc6aea7189bd138ee4ff0e040a959c0fe6ab64bcb9e70ae5bf836b8dc058b1de288aa75c9d1cd648e5f112e7cd5691c03b7a1d32466d8bfc71a9 + pathe: ^1.1.1 + checksum: 945580eaa58e8edbe29a64059bc2a524a9e85117b6d600fdb457cfe84cbfb81bf6d7e98e1227e7cb4e7399992c8fe8d83d0791d0385ff005dc1a4d9da125443b languageName: node linkType: hard -"@vitest/spy@npm:0.29.8": - version: 0.29.8 - resolution: "@vitest/spy@npm:0.29.8" +"@vitest/snapshot@npm:0.34.3": + version: 0.34.3 + resolution: "@vitest/snapshot@npm:0.34.3" dependencies: - tinyspy: ^1.0.2 - checksum: 7b1607b696275bf94a497e92d7d10c466b9b3d08726bbedb3735bdf57f003763a9516e328af22746829526ce573f87eb6119ab64ce7db95794b2d220aa53b607 + magic-string: ^0.30.1 + pathe: ^1.1.1 + pretty-format: ^29.5.0 + checksum: 234893e91a1efd4bdbbde047a68de40975e02ead8407724ce8ca4a24edf0fb2d725f8a3efceb104965388407b598faf22407aadfbf4164cc74b3cf1e0e9f4543 languageName: node linkType: hard -"@vitest/utils@npm:0.29.8": - version: 0.29.8 - resolution: "@vitest/utils@npm:0.29.8" +"@vitest/spy@npm:0.34.3": + version: 0.34.3 + resolution: "@vitest/spy@npm:0.34.3" dependencies: - cli-truncate: ^3.1.0 - diff: ^5.1.0 + tinyspy: ^2.1.1 + checksum: a2b64b9c357a56ad2f2340ecd225ffe787e61afba4ffb24a6670aad3fc90ea2606ed48daa188ed62b3ef67d55c0259fda6b101143d6c91b58c9ac4298d8be4f9 + languageName: node + linkType: hard + +"@vitest/utils@npm:0.34.3": + version: 0.34.3 + resolution: "@vitest/utils@npm:0.34.3" + dependencies: + diff-sequences: ^29.4.3 loupe: ^2.3.6 - pretty-format: ^27.5.1 - checksum: fa18cccb6ab5295e43a1a43b9c022f070646a893adb0561c50b3e0c39f05ea74cbf379aef22ef485ea9acbf2bb8f0a224d457fd4f16b9e1bf509c13052c7f08b + pretty-format: ^29.5.0 + checksum: aeb8ef7fd98b32cb6c403796880d0aa8f5411bbdb249bb23b3301a70e1b7d1ee025ddb204aae8c1db5756f6ac428c49ebbb8e2ed23ce185c8a659b67413efa85 languageName: node linkType: hard @@ -1361,7 +1642,7 @@ __metadata: languageName: node linkType: hard -"acorn@npm:^8.1.0, acorn@npm:^8.5.0, acorn@npm:^8.8.0, acorn@npm:^8.8.1, acorn@npm:^8.8.2": +"acorn@npm:^8.1.0, acorn@npm:^8.5.0, acorn@npm:^8.8.0, acorn@npm:^8.8.2": version: 8.8.2 resolution: "acorn@npm:8.8.2" bin: @@ -1370,6 +1651,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:^8.10.0, acorn@npm:^8.9.0": + version: 8.10.0 + resolution: "acorn@npm:8.10.0" + bin: + acorn: bin/acorn + checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d + languageName: node + linkType: hard + "agent-base@npm:6, agent-base@npm:^6.0.2": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -1419,13 +1709,6 @@ __metadata: languageName: node linkType: hard -"ansi-regex@npm:^6.0.1": - version: 6.0.1 - resolution: "ansi-regex@npm:6.0.1" - checksum: 1ff8b7667cded1de4fa2c9ae283e979fc87036864317da86a2e546725f96406746411d0d85e87a2d12fa5abd715d90006de7fa4fa0477c92321ad3b4c7d4e169 - languageName: node - linkType: hard - "ansi-styles@npm:^3.2.1": version: 3.2.1 resolution: "ansi-styles@npm:3.2.1" @@ -1451,13 +1734,6 @@ __metadata: languageName: node linkType: hard -"ansi-styles@npm:^6.0.0": - version: 6.2.1 - resolution: "ansi-styles@npm:6.2.1" - checksum: ef940f2f0ced1a6347398da88a91da7930c33ecac3c77b72c5905f8b8fe402c52e6fde304ff5347f616e27a742da3f1dc76de98f6866c69251ad0b07a66776d9 - languageName: node - linkType: hard - "anymatch@npm:~3.1.2": version: 3.1.3 resolution: "anymatch@npm:3.1.3" @@ -1620,6 +1896,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.21.9": + version: 4.21.10 + resolution: "browserslist@npm:4.21.10" + dependencies: + caniuse-lite: ^1.0.30001517 + electron-to-chromium: ^1.4.477 + node-releases: ^2.0.13 + update-browserslist-db: ^1.0.11 + bin: + browserslist: cli.js + checksum: 1e27c0f111a35d1dd0e8fc2c61781b0daefabc2c9471b0b10537ce54843014bceb2a1ce4571af1a82b2bf1e6e6e05d38865916689a158f03bc2c7a4ec2577db8 + languageName: node + linkType: hard + "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" @@ -1634,28 +1924,6 @@ __metadata: languageName: node linkType: hard -"c8@npm:^7.13.0": - version: 7.13.0 - resolution: "c8@npm:7.13.0" - dependencies: - "@bcoe/v8-coverage": ^0.2.3 - "@istanbuljs/schema": ^0.1.3 - find-up: ^5.0.0 - foreground-child: ^2.0.0 - istanbul-lib-coverage: ^3.2.0 - istanbul-lib-report: ^3.0.0 - istanbul-reports: ^3.1.4 - rimraf: ^3.0.2 - test-exclude: ^6.0.0 - v8-to-istanbul: ^9.0.0 - yargs: ^16.2.0 - yargs-parser: ^20.2.9 - bin: - c8: bin/c8.js - checksum: 491abf4cf3097cdcfd24dbac49162f1383861c22c77fdd9280bcd38240e1e07d2c6a59da5d4df59a61a8204e2fc297d31fd526e495faf8d2f20dcc12a37b144c - languageName: node - linkType: hard - "cac@npm:^6.7.14": version: 6.7.14 resolution: "cac@npm:6.7.14" @@ -1725,6 +1993,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001517": + version: 1.0.30001525 + resolution: "caniuse-lite@npm:1.0.30001525" + checksum: a0d190c185b8e1220dbc72e42f310633059aa175ca3396eb781b249ac3da6c62b30cb8efc5fa24d632cb938f58d90b0c7772d1c9942b6643cf418c27c2cb8632 + languageName: node + linkType: hard + "chai@npm:^4.3.7": version: 4.3.7 resolution: "chai@npm:4.3.7" @@ -1740,7 +2015,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^2.0.0": +"chalk@npm:^2.0.0, chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: @@ -1801,27 +2076,6 @@ __metadata: languageName: node linkType: hard -"cli-truncate@npm:^3.1.0": - version: 3.1.0 - resolution: "cli-truncate@npm:3.1.0" - dependencies: - slice-ansi: ^5.0.0 - string-width: ^5.0.0 - checksum: c3243e41974445691c63f8b405df1d5a24049dc33d324fe448dc572e561a7b772ae982692900b1a5960901cc4fc7def25a629b9c69a4208ee89d12ab3332617a - languageName: node - linkType: hard - -"cliui@npm:^7.0.2": - version: 7.0.4 - resolution: "cliui@npm:7.0.4" - dependencies: - string-width: ^4.2.0 - strip-ansi: ^6.0.0 - wrap-ansi: ^7.0.0 - checksum: ce2e8f578a4813806788ac399b9e866297740eecd4ad1823c27fd344d78b22c5f8597d548adbcc46f0573e43e21e751f39446c5a5e804a12aace402b7a315d7f - languageName: node - linkType: hard - "cliui@npm:^8.0.1": version: 8.0.1 resolution: "cliui@npm:8.0.1" @@ -1953,7 +2207,7 @@ __metadata: languageName: node linkType: hard -"convert-source-map@npm:^1.6.0, convert-source-map@npm:^1.7.0": +"convert-source-map@npm:^1.7.0": version: 1.9.0 resolution: "convert-source-map@npm:1.9.0" checksum: dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8 @@ -1973,7 +2227,7 @@ __metadata: languageName: node linkType: hard -"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2": +"cross-spawn@npm:^7.0.2": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" dependencies: @@ -2270,10 +2524,10 @@ __metadata: languageName: node linkType: hard -"diff@npm:^5.1.0": - version: 5.1.0 - resolution: "diff@npm:5.1.0" - checksum: c7bf0df7c9bfbe1cf8a678fd1b2137c4fb11be117a67bc18a0e03ae75105e8533dbfb1cda6b46beb3586ef5aed22143ef9d70713977d5fb1f9114e21455fba90 +"diff-sequences@npm:^29.4.3": + version: 29.6.3 + resolution: "diff-sequences@npm:29.6.3" + checksum: f4914158e1f2276343d98ff5b31fc004e7304f5470bf0f1adb2ac6955d85a531a6458d33e87667f98f6ae52ebd3891bb47d420bb48a5bd8b7a27ee25b20e33aa languageName: node linkType: hard @@ -2351,13 +2605,6 @@ __metadata: languageName: node linkType: hard -"eastasianwidth@npm:^0.2.0": - version: 0.2.0 - resolution: "eastasianwidth@npm:0.2.0" - checksum: 7d00d7cd8e49b9afa762a813faac332dee781932d6f2c848dc348939c4253f1d4564341b7af1d041853bc3f32c2ef141b58e0a4d9862c17a7f08f68df1e0f1ed - languageName: node - linkType: hard - "electron-to-chromium@npm:^1.4.284": version: 1.4.288 resolution: "electron-to-chromium@npm:1.4.288" @@ -2365,21 +2612,28 @@ __metadata: languageName: node linkType: hard -"embla-carousel-wheel-gestures@npm:^3.0.0": - version: 3.0.0 - resolution: "embla-carousel-wheel-gestures@npm:3.0.0" - dependencies: - wheel-gestures: ^2.2.5 - peerDependencies: - embla-carousel: ^7.0.0 - checksum: 109c1d10fa6f892fe4c627212ee5d24ae2d2d0c28210af16a9770901c2b65faf32eb1a5c95e87451aec9407ec8e3248e49789d6998b7079c83fd13b50532431d +"electron-to-chromium@npm:^1.4.477": + version: 1.4.508 + resolution: "electron-to-chromium@npm:1.4.508" + checksum: 4475eb18f5805d43f84d9542364045a39b183a14cd9f4626e0951ea61d0fa4f84a5ed579c2c32189f9af4a27a31041d09fed78f60930ac36b3baa08547dd3aa6 languageName: node linkType: hard -"embla-carousel@npm:^7.0.9": - version: 7.0.9 - resolution: "embla-carousel@npm:7.0.9" - checksum: dabb371a44c2d67f21aa7a0ff3f452a5c2678b79e80cb251e0a83b707c4b684fbdbe010927142cdcae3d1c9711a269e05655bd05c39608337fd1b6f5d2c20371 +"embla-carousel-wheel-gestures@npm:8.0.0-rc04": + version: 8.0.0-rc04 + resolution: "embla-carousel-wheel-gestures@npm:8.0.0-rc04" + dependencies: + wheel-gestures: ^2.2.5 + peerDependencies: + embla-carousel: 8.0.0-rc03 + checksum: ace8ab88b661e8d360c2d99ae61c0fe61085ccd71f059ac7c6b8dc1ebb52c17919a00025010502d86012273490940c25c6c1fdb143f932670ab36c09fb4c6bca + languageName: node + linkType: hard + +"embla-carousel@npm:8.0.0-rc12": + version: 8.0.0-rc12 + resolution: "embla-carousel@npm:8.0.0-rc12" + checksum: 553f33f562458d7fd0cd4eff1db96ac3a02352b620705d892eb3d9a297924fa12fedaf5a5aa03418dd41905ce80997a99f8aeca955d024d5a49a56f5c7fbe63b languageName: node linkType: hard @@ -2390,13 +2644,6 @@ __metadata: languageName: node linkType: hard -"emoji-regex@npm:^9.2.2": - version: 9.2.2 - resolution: "emoji-regex@npm:9.2.2" - checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601 - languageName: node - linkType: hard - "emojis-list@npm:^3.0.0": version: 3.0.0 resolution: "emojis-list@npm:3.0.0" @@ -3058,16 +3305,6 @@ __metadata: languageName: node linkType: hard -"foreground-child@npm:^2.0.0": - version: 2.0.0 - resolution: "foreground-child@npm:2.0.0" - dependencies: - cross-spawn: ^7.0.0 - signal-exit: ^3.0.2 - checksum: f77ec9aff621abd6b754cb59e690743e7639328301fbea6ff09df27d2befaf7dd5b77cec51c32323d73a81a7d91caaf9413990d305cbe3d873eec4fe58960956 - languageName: node - linkType: hard - "form-data@npm:^4.0.0": version: 4.0.0 resolution: "form-data@npm:4.0.0" @@ -3103,14 +3340,14 @@ __metadata: "@types/masonry-layout": ^4.2.5 "@typescript-eslint/eslint-plugin": ^5.36.2 "@typescript-eslint/parser": ^5.36.2 - "@vitest/coverage-c8": ^0.29.8 + "@vitest/coverage-istanbul": ^0.34.3 component-emitter: ^1.3.0 crypto: ^1.0.1 custom-card-helpers: ^1.9.0 date-fns: ^2.29.2 date-fns-tz: ^1.3.7 - embla-carousel: ^7.0.9 - embla-carousel-wheel-gestures: ^3.0.0 + embla-carousel: 8.0.0-rc12 + embla-carousel-wheel-gestures: 8.0.0-rc04 eslint: ^8.23.0 eslint-config-airbnb-base: ^15.0.0 eslint-config-prettier: ^8.5.0 @@ -3143,8 +3380,8 @@ __metadata: vis-data: ^7.1.4 vis-timeline: ^7.7.0 vis-util: ^5.0.2 - vitest: ^0.29.8 - vitest-mock-extended: ^1.1.3 + vitest: ^0.34.3 + vitest-mock-extended: ^1.2.1 web-dialog: ^0.0.11 xss: ^1.0.14 zod: ^3.21.4 @@ -3744,13 +3981,6 @@ __metadata: languageName: node linkType: hard -"is-fullwidth-code-point@npm:^4.0.0": - version: 4.0.0 - resolution: "is-fullwidth-code-point@npm:4.0.0" - checksum: 8ae89bf5057bdf4f57b346fb6c55e9c3dd2549983d54191d722d5c739397a903012cc41a04ee3403fd872e811243ef91a7c5196da7b5841dc6b6aae31a264a8d - languageName: node - linkType: hard - "is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1": version: 4.0.3 resolution: "is-glob@npm:4.0.3" @@ -3902,6 +4132,19 @@ __metadata: languageName: node linkType: hard +"istanbul-lib-instrument@npm:^6.0.0": + version: 6.0.0 + resolution: "istanbul-lib-instrument@npm:6.0.0" + dependencies: + "@babel/core": ^7.12.3 + "@babel/parser": ^7.14.7 + "@istanbuljs/schema": ^0.1.2 + istanbul-lib-coverage: ^3.2.0 + semver: ^7.5.4 + checksum: b9dc3723a769e65dbe1b912f935088ffc07cf393fa78a3ce79022c91aabb0ad01405ffd56083cdd822e514798e9daae3ea7bfe85633b094ecb335d28eb0a3f97 + languageName: node + linkType: hard + "istanbul-lib-report@npm:^3.0.0": version: 3.0.0 resolution: "istanbul-lib-report@npm:3.0.0" @@ -3913,13 +4156,35 @@ __metadata: languageName: node linkType: hard -"istanbul-reports@npm:^3.1.4": - version: 3.1.5 - resolution: "istanbul-reports@npm:3.1.5" +"istanbul-lib-report@npm:^3.0.1": + version: 3.0.1 + resolution: "istanbul-lib-report@npm:3.0.1" + dependencies: + istanbul-lib-coverage: ^3.0.0 + make-dir: ^4.0.0 + supports-color: ^7.1.0 + checksum: fd17a1b879e7faf9bb1dc8f80b2a16e9f5b7b8498fe6ed580a618c34df0bfe53d2abd35bf8a0a00e628fb7405462576427c7df20bbe4148d19c14b431c974b21 + languageName: node + linkType: hard + +"istanbul-lib-source-maps@npm:^4.0.1": + version: 4.0.1 + resolution: "istanbul-lib-source-maps@npm:4.0.1" + dependencies: + debug: ^4.1.1 + istanbul-lib-coverage: ^3.0.0 + source-map: ^0.6.1 + checksum: 21ad3df45db4b81852b662b8d4161f6446cd250c1ddc70ef96a585e2e85c26ed7cd9c2a396a71533cfb981d1a645508bc9618cae431e55d01a0628e7dec62ef2 + languageName: node + linkType: hard + +"istanbul-reports@npm:^3.1.5": + version: 3.1.6 + resolution: "istanbul-reports@npm:3.1.6" dependencies: html-escaper: ^2.0.0 istanbul-lib-report: ^3.0.0 - checksum: 7867228f83ed39477b188ea07e7ccb9b4f5320b6f73d1db93a0981b7414fa4ef72d3f80c4692c442f90fc250d9406e71d8d7ab65bb615cb334e6292b73192b89 + checksum: 44c4c0582f287f02341e9720997f9e82c071627e1e862895745d5f52ec72c9b9f38e1d12370015d2a71dcead794f34c7732aaef3fab80a24bc617a21c3d911d6 languageName: node linkType: hard @@ -4039,7 +4304,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.1.3, json5@npm:^2.2.2": +"json5@npm:^2.1.3, json5@npm:^2.2.2, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: @@ -4150,7 +4415,7 @@ __metadata: languageName: node linkType: hard -"local-pkg@npm:^0.4.2": +"local-pkg@npm:^0.4.3": version: 0.4.3 resolution: "local-pkg@npm:0.4.3" checksum: 7825aca531dd6afa3a3712a0208697aa4a5cd009065f32e3fb732aafcc42ed11f277b5ac67229222e96f4def55197171cdf3d5522d0381b489d2e5547b407d55 @@ -4253,6 +4518,15 @@ __metadata: languageName: node linkType: hard +"magic-string@npm:^0.30.1": + version: 0.30.3 + resolution: "magic-string@npm:0.30.3" + dependencies: + "@jridgewell/sourcemap-codec": ^1.4.15 + checksum: a5a9ddf9bd3bf49a2de1048bf358464f1bda7b3cc1311550f4a0ba8f81a4070e25445d53a5ee28850161336f1bff3cf28aa3320c6b4aeff45ce3e689f300b2f3 + languageName: node + linkType: hard + "make-dir@npm:^3.0.0, make-dir@npm:^3.0.2": version: 3.1.0 resolution: "make-dir@npm:3.1.0" @@ -4262,6 +4536,15 @@ __metadata: languageName: node linkType: hard +"make-dir@npm:^4.0.0": + version: 4.0.0 + resolution: "make-dir@npm:4.0.0" + dependencies: + semver: ^7.5.3 + checksum: bf0731a2dd3aab4db6f3de1585cea0b746bb73eb5a02e3d8d72757e376e64e6ada190b1eddcde5b2f24a81b688a9897efd5018737d05e02e2a671dda9cff8a8a + languageName: node + linkType: hard + "make-fetch-happen@npm:^10.0.3": version: 10.2.1 resolution: "make-fetch-happen@npm:10.2.1" @@ -4472,15 +4755,15 @@ __metadata: languageName: node linkType: hard -"mlly@npm:^1.1.0, mlly@npm:^1.1.1": - version: 1.2.0 - resolution: "mlly@npm:1.2.0" +"mlly@npm:^1.2.0, mlly@npm:^1.4.0": + version: 1.4.1 + resolution: "mlly@npm:1.4.1" dependencies: - acorn: ^8.8.2 - pathe: ^1.1.0 - pkg-types: ^1.0.2 - ufo: ^1.1.1 - checksum: 640b019eb20e8e556bd623141b861d47e5c05f8af00210376ce1015912695dbd93a38cfe7ba18ca04f00e75645378f0f94a48a90bfa6e1b5dee1f0ec9c14eed1 + acorn: ^8.10.0 + pathe: ^1.1.1 + pkg-types: ^1.0.3 + ufo: ^1.3.0 + checksum: b2b59ab3d70196127be4e54609d2a442bd252345727138940fb245672a238b2fbdd431e8c75ec5c741ff90410ce488c5fd6446d5d3e6476d21dbf4c3fa35d4a0 languageName: node linkType: hard @@ -4555,6 +4838,13 @@ __metadata: languageName: node linkType: hard +"node-releases@npm:^2.0.13": + version: 2.0.13 + resolution: "node-releases@npm:2.0.13" + checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 + languageName: node + linkType: hard + "node-releases@npm:^2.0.8": version: 2.0.10 resolution: "node-releases@npm:2.0.10" @@ -4897,6 +5187,13 @@ __metadata: languageName: node linkType: hard +"pathe@npm:^1.1.1": + version: 1.1.1 + resolution: "pathe@npm:1.1.1" + checksum: 34ab3da2e5aa832ebc6a330ffe3f73d7ba8aec6e899b53b8ec4f4018de08e40742802deb12cf5add9c73b7bf719b62c0778246bd376ca62b0fb23e0dde44b759 + languageName: node + linkType: hard + "pathval@npm:^1.1.1": version: 1.1.1 resolution: "pathval@npm:1.1.1" @@ -4927,14 +5224,14 @@ __metadata: languageName: node linkType: hard -"pkg-types@npm:^1.0.2": - version: 1.0.2 - resolution: "pkg-types@npm:1.0.2" +"pkg-types@npm:^1.0.3": + version: 1.0.3 + resolution: "pkg-types@npm:1.0.3" dependencies: jsonc-parser: ^3.2.0 - mlly: ^1.1.1 + mlly: ^1.2.0 pathe: ^1.1.0 - checksum: 2d0a70c1721c2ebbe075b912531a4f43136e6658fdcc59dc76c39966201ab5ddf265868d1211943183406d4b70d373c17e3b176487bc2020ea737d030b0fd080 + checksum: 4b305c834b912ddcc8a0fe77530c0b0321fe340396f84cbb87aecdbc126606f47f2178f23b8639e71a4870f9631c7217aef52ffed0ae17ea2dbbe7e43d116a6e languageName: node linkType: hard @@ -5347,14 +5644,14 @@ __metadata: languageName: node linkType: hard -"pretty-format@npm:^27.5.1": - version: 27.5.1 - resolution: "pretty-format@npm:27.5.1" +"pretty-format@npm:^29.5.0": + version: 29.6.3 + resolution: "pretty-format@npm:29.6.3" dependencies: - ansi-regex: ^5.0.1 + "@jest/schemas": ^29.6.3 ansi-styles: ^5.0.0 - react-is: ^17.0.1 - checksum: cf610cffcb793885d16f184a62162f2dd0df31642d9a18edf4ca298e909a8fe80bdbf556d5c9573992c102ce8bf948691da91bf9739bee0ffb6e79c8a8a6e088 + react-is: ^18.0.0 + checksum: 4e1c0db48e65571c22e80ff92123925ff8b3a2a89b71c3a1683cfde711004d492de32fe60c6bc10eea8bf6c678e5cbe544ac6c56cb8096e1eb7caf856928b1c4 languageName: node linkType: hard @@ -5440,10 +5737,10 @@ __metadata: languageName: node linkType: hard -"react-is@npm:^17.0.1": - version: 17.0.2 - resolution: "react-is@npm:17.0.2" - checksum: 9d6d111d8990dc98bc5402c1266a808b0459b5d54830bbea24c12d908b536df7883f268a7868cfaedde3dd9d4e0d574db456f84d2e6df9c4526f99bb4b5344d8 +"react-is@npm:^18.0.0": + version: 18.2.0 + resolution: "react-is@npm:18.2.0" + checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e languageName: node linkType: hard @@ -5759,6 +6056,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^6.3.1": + version: 6.3.1 + resolution: "semver@npm:6.3.1" + bin: + semver: bin/semver.js + checksum: ae47d06de28836adb9d3e25f22a92943477371292d9b665fb023fae278d345d508ca1958232af086d85e0155aee22e313e100971898bbb8d5d89b8b1d4054ca2 + languageName: node + linkType: hard + "semver@npm:^7.3.5, semver@npm:^7.3.7": version: 7.3.8 resolution: "semver@npm:7.3.8" @@ -5770,6 +6076,17 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.5.3, semver@npm:^7.5.4": + version: 7.5.4 + resolution: "semver@npm:7.5.4" + dependencies: + lru-cache: ^6.0.0 + bin: + semver: bin/semver.js + checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 + languageName: node + linkType: hard + "serialize-javascript@npm:^4.0.0": version: 4.0.0 resolution: "serialize-javascript@npm:4.0.0" @@ -5827,7 +6144,7 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.7": +"signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 @@ -5841,16 +6158,6 @@ __metadata: languageName: node linkType: hard -"slice-ansi@npm:^5.0.0": - version: 5.0.0 - resolution: "slice-ansi@npm:5.0.0" - dependencies: - ansi-styles: ^6.0.0 - is-fullwidth-code-point: ^4.0.0 - checksum: 7e600a2a55e333a21ef5214b987c8358fe28bfb03c2867ff2cbf919d62143d1812ac27b4297a077fdaf27a03da3678e49551c93e35f9498a3d90221908a1180e - languageName: node - linkType: hard - "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" @@ -5947,10 +6254,10 @@ __metadata: languageName: node linkType: hard -"std-env@npm:^3.3.1": - version: 3.3.2 - resolution: "std-env@npm:3.3.2" - checksum: c02256bb041ba1870d23f8360bc7e47a9cf1fabcd02c8b7c4246d48f2c6bb47b4f45c70964348844e6d36521df84c4a9d09d468654b51e0eb5c600e3392b4570 +"std-env@npm:^3.3.3": + version: 3.4.3 + resolution: "std-env@npm:3.4.3" + checksum: bef186fb2baddda31911234b1e58fa18f181eb6930616aaec3b54f6d5db65f2da5daaa5f3b326b98445a7d50ca81d6fe8809ab4ebab85ecbe4a802f1b40921bf languageName: node linkType: hard @@ -5972,17 +6279,6 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^5.0.0": - version: 5.1.2 - resolution: "string-width@npm:5.1.2" - dependencies: - eastasianwidth: ^0.2.0 - emoji-regex: ^9.2.2 - strip-ansi: ^7.0.1 - checksum: 7369deaa29f21dda9a438686154b62c2c5f661f8dda60449088f9f980196f7908fc39fdd1803e3e01541970287cf5deae336798337e9319a7055af89dafa7193 - languageName: node - linkType: hard - "string.prototype.trimend@npm:^1.0.6": version: 1.0.6 resolution: "string.prototype.trimend@npm:1.0.6" @@ -6023,15 +6319,6 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^7.0.1": - version: 7.0.1 - resolution: "strip-ansi@npm:7.0.1" - dependencies: - ansi-regex: ^6.0.1 - checksum: 257f78fa433520e7f9897722731d78599cb3fce29ff26a20a5e12ba4957463b50a01136f37c43707f4951817a75e90820174853d6ccc240997adc5df8f966039 - languageName: node - linkType: hard - "strip-bom@npm:^3.0.0": version: 3.0.0 resolution: "strip-bom@npm:3.0.0" @@ -6046,12 +6333,12 @@ __metadata: languageName: node linkType: hard -"strip-literal@npm:^1.0.0": - version: 1.0.1 - resolution: "strip-literal@npm:1.0.1" +"strip-literal@npm:^1.0.1": + version: 1.3.0 + resolution: "strip-literal@npm:1.3.0" dependencies: - acorn: ^8.8.2 - checksum: ab40496820f02220390d95cdd620a997168efb69d5bd7d180bc4ef83ca562a95447843d8c7c88b8284879a29cf4eedc89d8001d1e098c1a1e23d12a9c755dff4 + acorn: ^8.10.0 + checksum: f5fa7e289df8ebe82e90091fd393974faf8871be087ca50114327506519323cf15f2f8fee6ebe68b5e58bfc795269cae8bdc7cb5a83e27b02b3fe953f37b0a89 languageName: node linkType: hard @@ -6169,24 +6456,24 @@ __metadata: languageName: node linkType: hard -"tinybench@npm:^2.3.1": - version: 2.4.0 - resolution: "tinybench@npm:2.4.0" - checksum: cfbe90f75755488653dde256019cc810f65e90f63fdd962e71e8b209b49598c5fc90c2227d2087eb807944895fafe7f12fe9ecae2b5e89db5adde66415e9b836 +"tinybench@npm:^2.5.0": + version: 2.5.0 + resolution: "tinybench@npm:2.5.0" + checksum: 284bb9428f197ec8b869c543181315e65e41ccfdad3c4b6c916bb1fdae1b5c6785661b0d90cf135b48d833b03cb84dc5357b2d33ec65a1f5971fae0ab2023821 languageName: node linkType: hard -"tinypool@npm:^0.4.0": - version: 0.4.0 - resolution: "tinypool@npm:0.4.0" - checksum: 8abcac9e784793499f1eeeace8290c026454b9d7338c74029ce6a821643bab8dcab7caeb4051e39006baf681d6a62d57c3319e9c0f6e2317a45ab0fdbd76ee26 +"tinypool@npm:^0.7.0": + version: 0.7.0 + resolution: "tinypool@npm:0.7.0" + checksum: fdcccd5c750574fce51f8801a877f8284e145d12b79cd5f2d72bfbddfe20c895e915555bc848e122bb6aa968098e7ac4fe1e8e88104904d518dc01cccd18a510 languageName: node linkType: hard -"tinyspy@npm:^1.0.2": - version: 1.1.1 - resolution: "tinyspy@npm:1.1.1" - checksum: 4ea908fdfddb92044c4454193ec543f5980ced0bd25c5b3d240a94c1511e47e765ad39cd13ae6d3370fb730f62038eedc357f55e4e239416e126bc418f0eee79 +"tinyspy@npm:^2.1.1": + version: 2.1.1 + resolution: "tinyspy@npm:2.1.1" + checksum: cfe669803a7f11ca912742b84c18dcc4ceecaa7661c69bc5eb608a8a802d541c48aba220df8929f6c8cd09892ad37cb5ba5958ddbbb57940e91d04681d3cee73 languageName: node linkType: hard @@ -6234,12 +6521,15 @@ __metadata: languageName: node linkType: hard -"ts-essentials@npm:^9.3.1": - version: 9.3.1 - resolution: "ts-essentials@npm:9.3.1" +"ts-essentials@npm:^9.3.2": + version: 9.4.0 + resolution: "ts-essentials@npm:9.4.0" peerDependencies: typescript: ">=4.1.0" - checksum: 5accaec3eeea93cf19ad9e1959e763ba8a8253c977cd3f88cd7d8a2c04e697e77cc65fd742d9e88482b564a78b3c2dc1269119505bf7ad06320175b490dd49de + peerDependenciesMeta: + typescript: + optional: true + checksum: 50719782f9bfa31678fd1607de783a92b322ed8c26e6229bd0d1786c0649b9f1a7b9a6ac5bc60435053c4952bd3ef2356b5c930cb3a8d3519dc8f41c5576328f languageName: node linkType: hard @@ -6369,10 +6659,10 @@ __metadata: languageName: node linkType: hard -"ufo@npm:^1.1.1": - version: 1.1.1 - resolution: "ufo@npm:1.1.1" - checksum: 6bd210ed93d8c0dedd76c456b1d1dfb0e3b08c2216ee6080e61f0f545de0bac24b3d3a5530cd6a403810855f8d8fc3922583965296142e04cfc287442635e6c7 +"ufo@npm:^1.3.0": + version: 1.3.0 + resolution: "ufo@npm:1.3.0" + checksum: 01f0be86cd5c205ad1b49ebea985e000a4542c503ee75398302b0f5e4b9a6d9cd8e77af2dc614ab7bea08805fdfd9a85191fb3b5ee3df383cb936cf65e9db30d languageName: node linkType: hard @@ -6434,6 +6724,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.0.11": + version: 1.0.11 + resolution: "update-browserslist-db@npm:1.0.11" + dependencies: + escalade: ^3.1.1 + picocolors: ^1.0.0 + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: b98327518f9a345c7cad5437afae4d2ae7d865f9779554baf2a200fdf4bac4969076b679b1115434bd6557376bdd37ca7583d0f9b8f8e302d7d4cc1e91b5f231 + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -6469,17 +6773,6 @@ __metadata: languageName: node linkType: hard -"v8-to-istanbul@npm:^9.0.0": - version: 9.1.0 - resolution: "v8-to-istanbul@npm:9.1.0" - dependencies: - "@jridgewell/trace-mapping": ^0.3.12 - "@types/istanbul-lib-coverage": ^2.0.1 - convert-source-map: ^1.6.0 - checksum: 2069d59ee46cf8d83b4adfd8a5c1a90834caffa9f675e4360f1157ffc8578ef0f763c8f32d128334424159bb6b01f3876acd39cd13297b2769405a9da241f8d1 - languageName: node - linkType: hard - "vis-data@npm:^7.1.4": version: 7.1.4 resolution: "vis-data@npm:7.1.4" @@ -6517,19 +6810,19 @@ __metadata: languageName: node linkType: hard -"vite-node@npm:0.29.8": - version: 0.29.8 - resolution: "vite-node@npm:0.29.8" +"vite-node@npm:0.34.3": + version: 0.34.3 + resolution: "vite-node@npm:0.34.3" dependencies: cac: ^6.7.14 debug: ^4.3.4 - mlly: ^1.1.0 - pathe: ^1.1.0 + mlly: ^1.4.0 + pathe: ^1.1.1 picocolors: ^1.0.0 vite: ^3.0.0 || ^4.0.0 bin: vite-node: vite-node.mjs - checksum: b0981d4d63b1f373579eb9da69ca5af9123bf27c81ac246c541cdecf879ef4ef542e0b521cb6ceaafd5ead2cc3d243105d1fb8bf076953d42a6b2203607ce928 + checksum: 366c4f3fb7c038e2180abc6b18cfbac3b8684cd878eaf7ebf1ffb07d95d2ea325713fc575a7949a13bb00cfe264acbc28c02e2836b8647e1f443fe631c17805a languageName: node linkType: hard @@ -6571,45 +6864,45 @@ __metadata: languageName: node linkType: hard -"vitest-mock-extended@npm:^1.1.3": - version: 1.1.3 - resolution: "vitest-mock-extended@npm:1.1.3" +"vitest-mock-extended@npm:^1.2.1": + version: 1.2.1 + resolution: "vitest-mock-extended@npm:1.2.1" dependencies: - ts-essentials: ^9.3.1 + ts-essentials: ^9.3.2 peerDependencies: typescript: 3.x || 4.x || 5.x - vitest: ">=0.29.2" - checksum: d457dc1dcbf6b0570e9845dff7423c2b88504ce6bb189e71c0984b09b4d6c5894d883706a7639262c92e12b0b4b0d5db747e1d0b93e253b4d6c189cba15c70f9 + vitest: ">=0.31.1" + checksum: d3dc3940513cc053166bc912b0b9fdda0b073c5a5d2c2deba4f87ddae7a3b8c53a31227030a9f0eeb9f48c443b6978c451946ef0d36eea6976ef77e5bb4d6c04 languageName: node linkType: hard -"vitest@npm:^0.29.8": - version: 0.29.8 - resolution: "vitest@npm:0.29.8" +"vitest@npm:^0.34.3": + version: 0.34.3 + resolution: "vitest@npm:0.34.3" dependencies: - "@types/chai": ^4.3.4 + "@types/chai": ^4.3.5 "@types/chai-subset": ^1.3.3 "@types/node": "*" - "@vitest/expect": 0.29.8 - "@vitest/runner": 0.29.8 - "@vitest/spy": 0.29.8 - "@vitest/utils": 0.29.8 - acorn: ^8.8.1 + "@vitest/expect": 0.34.3 + "@vitest/runner": 0.34.3 + "@vitest/snapshot": 0.34.3 + "@vitest/spy": 0.34.3 + "@vitest/utils": 0.34.3 + acorn: ^8.9.0 acorn-walk: ^8.2.0 cac: ^6.7.14 chai: ^4.3.7 debug: ^4.3.4 - local-pkg: ^0.4.2 - pathe: ^1.1.0 + local-pkg: ^0.4.3 + magic-string: ^0.30.1 + pathe: ^1.1.1 picocolors: ^1.0.0 - source-map: ^0.6.1 - std-env: ^3.3.1 - strip-literal: ^1.0.0 - tinybench: ^2.3.1 - tinypool: ^0.4.0 - tinyspy: ^1.0.2 + std-env: ^3.3.3 + strip-literal: ^1.0.1 + tinybench: ^2.5.0 + tinypool: ^0.7.0 vite: ^3.0.0 || ^4.0.0 - vite-node: 0.29.8 + vite-node: 0.34.3 why-is-node-running: ^2.2.2 peerDependencies: "@edge-runtime/vm": "*" @@ -6639,7 +6932,7 @@ __metadata: optional: true bin: vitest: vitest.mjs - checksum: 203e33bf093fdb99a6832c905a6c78175bb15313e06e1dcfbeb010a0e3efb8ff0aba4d317efedb4de76bd0086691bbd2c4bc7d6631f60fb1634b96832cba144f + checksum: 4535d080feede94db5015eb60c6ed5f7b0d8cd67f12072de5ae1faded133cc640043c0c2646ef51ab9b61c2f885589da57458a65e82cf91a25cf954470018a40 languageName: node linkType: hard @@ -6854,13 +7147,6 @@ __metadata: languageName: node linkType: hard -"yargs-parser@npm:^20.2.2, yargs-parser@npm:^20.2.9": - version: 20.2.9 - resolution: "yargs-parser@npm:20.2.9" - checksum: 8bb69015f2b0ff9e17b2c8e6bfe224ab463dd00ca211eece72a4cd8a906224d2703fb8a326d36fdd0e68701e201b2a60ed7cf81ce0fd9b3799f9fe7745977ae3 - languageName: node - linkType: hard - "yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" @@ -6868,21 +7154,6 @@ __metadata: languageName: node linkType: hard -"yargs@npm:^16.2.0": - version: 16.2.0 - resolution: "yargs@npm:16.2.0" - dependencies: - cliui: ^7.0.2 - escalade: ^3.1.1 - get-caller-file: ^2.0.5 - require-directory: ^2.1.1 - string-width: ^4.2.0 - y18n: ^5.0.5 - yargs-parser: ^20.2.2 - checksum: b14afbb51e3251a204d81937c86a7e9d4bdbf9a2bcee38226c900d00f522969ab675703bee2a6f99f8e20103f608382936034e64d921b74df82b63c07c5e8f59 - languageName: node - linkType: hard - "yargs@npm:^17.5.1": version: 17.6.2 resolution: "yargs@npm:17.6.2" From cd84e490a8c9872691c4237de0b4b3bca52abdd2 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 4 Sep 2023 18:40:13 -0700 Subject: [PATCH 026/189] Watch grid DOM for id changes. --- src/components/media-grid.ts | 2 + tests/utils/media-grid-controller.test.ts | 58 +++++++++++++++++++---- 2 files changed, 51 insertions(+), 9 deletions(-) diff --git a/src/components/media-grid.ts b/src/components/media-grid.ts index 913e1aa7..70a7bc69 100644 --- a/src/components/media-grid.ts +++ b/src/components/media-grid.ts @@ -1,3 +1,5 @@ +// TODO: Live non-grid -> live grid -> timeline is different from when the timeline is dragged. + import { CSSResultGroup, html, diff --git a/tests/utils/media-grid-controller.test.ts b/tests/utils/media-grid-controller.test.ts index 4b19b6f9..15da4471 100644 --- a/tests/utils/media-grid-controller.test.ts +++ b/tests/utils/media-grid-controller.test.ts @@ -1,5 +1,5 @@ import Masonry from 'masonry-layout'; -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { MediaLoadedInfo } from '../../src/types'; import { @@ -12,6 +12,7 @@ import { ResizeObserverMock, createSlot, createSlotHost, + requestAnimationFrameMock, } from '../test-utils'; vi.mock('lodash-es/throttle', () => ({ @@ -60,14 +61,16 @@ const createController = (host: HTMLElement, options?: MediaGridConstructorOptio return new MediaGridController(host, options); }; -const triggerMutationObserver = (): void => { - const mutationObserverTrigger = vi.mocked(global.MutationObserver).mock.calls[0][0]; +const triggerMutationObserver = (hostOrCell: 'cell' | 'host'): void => { + const mutationObserverTrigger = vi.mocked(global.MutationObserver).mock.calls[ + hostOrCell === 'host' ? 0 : 1 + ][0]; mutationObserverTrigger([], mock()); }; -const triggerResizeObserver = (cellOrHost: 'cell' | 'host'): void => { +const triggerResizeObserver = (hostOrCell: 'cell' | 'host'): void => { const resizeObserverTrigger = vi.mocked(global.ResizeObserver).mock.calls[ - cellOrHost === 'cell' ? 0 : 1 + hostOrCell === 'host' ? 0 : 1 ][0]; resizeObserverTrigger([], mock()); }; @@ -79,6 +82,10 @@ describe('MediaGridController', () => { height: 20, }; + beforeAll(() => { + window.requestAnimationFrame = requestAnimationFrameMock; + }); + beforeEach(() => { vi.clearAllMocks(); vi.stubGlobal('MutationObserver', MutationObserverMock); @@ -311,7 +318,7 @@ describe('MediaGridController', () => { const newChildren = createChildren(['one', 'two', 'three']); newChildren.forEach((child) => parent.appendChild(child)); - triggerMutationObserver(); + triggerMutationObserver('host'); expect(controller.getGridContents()).toEqual( new Map([ @@ -323,6 +330,33 @@ describe('MediaGridController', () => { expect(controller.getSelected()).toBeNull(); }); + it('should re-calculate children when id attribute changes', () => { + const children = createChildren(['one', 'two', 'three'], 'test-id'); + const parent = createParent({ children: children }); + const controller = createController(parent, { + selected: 'one', + idAttribute: 'test-id', + }); + + expect(controller.getSelected()).toBe('one'); + expect(controller.getGridSize()).toBe(3); + + children[0].setAttribute('test-id', 'alpha'); + children[1].setAttribute('test-id', 'beta'); + children[2].setAttribute('test-id', 'gamma'); + + triggerMutationObserver('cell'); + + expect(controller.getGridContents()).toEqual( + new Map([ + ['alpha', children[0]], + ['beta', children[1]], + ['gamma', children[2]], + ]), + ); + expect(controller.getSelected()).toBeNull(); + }); + it('should replace children of a slot when they change', () => { const children = createChildren(); const slot = createSlot(); @@ -372,7 +406,9 @@ describe('MediaGridController', () => { columnWidth: 246, }), ); - expect(parent.style.getPropertyValue('--frigate-card-grid-column-size')).toBe('246px'); + expect(parent.style.getPropertyValue('--frigate-card-grid-column-size')).toBe( + '246px', + ); }); it('should respect exact columns', () => { @@ -459,7 +495,9 @@ describe('MediaGridController', () => { columnWidth: 246, }), ); - expect(parent.style.getPropertyValue('--frigate-card-grid-column-size')).toBe('246px'); + expect(parent.style.getPropertyValue('--frigate-card-grid-column-size')).toBe( + '246px', + ); // Clear mock state. vi.mocked(Masonry).mockClear(); @@ -476,7 +514,9 @@ describe('MediaGridController', () => { columnWidth: 667, }), ); - expect(parent.style.getPropertyValue('--frigate-card-grid-column-size')).toBe('667px'); + expect(parent.style.getPropertyValue('--frigate-card-grid-column-size')).toBe( + '667px', + ); expect(masonry.layout).toBeCalled(); // Clear mock state. From 1554cb41e8a55f2e270d5e2e895b29d35d04c5c3 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 4 Sep 2023 18:41:46 -0700 Subject: [PATCH 027/189] Add missing files changes on prior commit. --- src/utils/media-grid-controller.ts | 49 ++++++++++++++++++++++-------- 1 file changed, 36 insertions(+), 13 deletions(-) diff --git a/src/utils/media-grid-controller.ts b/src/utils/media-grid-controller.ts index f39f013e..7fd38146 100644 --- a/src/utils/media-grid-controller.ts +++ b/src/utils/media-grid-controller.ts @@ -2,7 +2,11 @@ import isEqual from 'lodash-es/isEqual'; import throttle from 'lodash-es/throttle'; import Masonry from 'masonry-layout'; import { MediaLoadedInfo, ViewDisplayConfig } from '../types'; -import { dispatchFrigateCardEvent, getChildrenFromElement, setOrRemoveAttribute } from './basic'; +import { + dispatchFrigateCardEvent, + getChildrenFromElement, + setOrRemoveAttribute, +} from './basic'; import { FrigateMediaLoadedEventTarget, dispatchExistingMediaLoadedInfoAsEvent, @@ -43,20 +47,29 @@ export class MediaGridController { protected _idAttribute: string; protected _throttledLayout = throttle( - () => this._masonry?.layout?.(), + () => { + window.requestAnimationFrame(() => this._masonry?.layout?.()); + }, // Throttle layout calls to larger than the masonry.js transitionDuration // value specified below. - 300, + 400, { trailing: true, leading: false }, ); - protected _mutationObserver = new MutationObserver( + // If the order in which the observers are declared changes, the unittest must + // be updated in triggerResizeObserver and triggerMutationObserver. + protected _hostMutationObserver = new MutationObserver( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + (_mutations: MutationRecord[], _observer: MutationObserver) => + this._calculateGridContentsFromHost(), + ); + protected _cellMutationObserver = new MutationObserver( // eslint-disable-next-line @typescript-eslint/no-unused-vars (_mutations: MutationRecord[], _observer: MutationObserver) => this._calculateGridContentsFromHost(), ); - protected _cellResizeObserver = new ResizeObserver(this._cellResizeHandler.bind(this)); protected _hostResizeObserver = new ResizeObserver(this._hostResizeHandler.bind(this)); + protected _cellResizeObserver = new ResizeObserver(this._cellResizeHandler.bind(this)); constructor(host: HTMLElement, options?: MediaGridConstructorOptions) { this._host = host; @@ -66,7 +79,10 @@ export class MediaGridController { this._hostResizeObserver.observe(host); this._displayConfig = options?.displayConfig ?? null; - this._mutationObserver.observe(host, { childList: true }); + this._hostMutationObserver.observe(host, { + childList: true, + }); + // Need to separately listen for slotchanges since mutation observer will // not be called for shadom DOM slotted changes. if (host instanceof HTMLSlotElement) { @@ -79,7 +95,9 @@ export class MediaGridController { this._hostResizeObserver.disconnect(); this._cellResizeObserver.disconnect(); - this._mutationObserver.disconnect(); + this._hostMutationObserver.disconnect(); + this._cellMutationObserver.disconnect(); + if (this._host instanceof HTMLSlotElement) { this._host.removeEventListener('slotchange', this._calculateGridContentsFromHost); } @@ -154,13 +172,13 @@ export class MediaGridController { this._setGridContents(gridContents); }; - protected _setGridContents(elements: MediaGridContents): void { - this._gridContents = elements; + protected _setGridContents(gridContents: MediaGridContents): void { + this._gridContents = gridContents; // Remove media loaded info objects that belong to objects no longer in the // grid. for (const key of this._mediaLoadedInfoMap.keys()) { - if (!elements.has(key)) { + if (!gridContents.has(key)) { this._mediaLoadedInfoMap.delete(key); } } @@ -169,7 +187,7 @@ export class MediaGridController { this.unselectAll(); } - for (const element of elements.values()) { + for (const element of gridContents.values()) { this._removeChildEventListeners(element); this._addChildEventListeners(element); } @@ -177,9 +195,14 @@ export class MediaGridController { this._setColumnSizeStyles(); this._createMasonry(); - // Observe grid elements for size changes. + // Observe grid elements for size or id changes. + this._cellMutationObserver.disconnect(); this._cellResizeObserver.disconnect(); - for (const child of elements.values()) { + for (const child of gridContents.values()) { + this._cellMutationObserver.observe(child, { + attributeFilter: [this._idAttribute], + attributes: true, + }); this._cellResizeObserver.observe(child); } From d42545778175713e5ab16fabf12467caf3589be3 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 4 Sep 2023 19:31:54 -0700 Subject: [PATCH 028/189] Resize the container based on media loads. --- src/utils/embla/plugins/auto-size/auto-size.ts | 18 ++++++++++++++++-- src/utils/embla/reinit-controller.ts | 3 --- src/utils/media-grid-controller.ts | 6 ++---- .../embla/plugins/auto-size/auto-size.test.ts | 1 - tests/utils/media-grid-controller.test.ts | 7 +------ 5 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/utils/embla/plugins/auto-size/auto-size.ts b/src/utils/embla/plugins/auto-size/auto-size.ts index bfadef33..ee226555 100644 --- a/src/utils/embla/plugins/auto-size/auto-size.ts +++ b/src/utils/embla/plugins/auto-size/auto-size.ts @@ -1,6 +1,7 @@ import { EmblaCarouselType } from 'embla-carousel'; import { LooseOptionsType } from 'embla-carousel/components/Options'; import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins'; +import debounce from 'lodash-es/debounce'; import { EmblaReInitController } from '../../reinit-controller'; declare module 'embla-carousel/components/Plugins' { @@ -37,6 +38,10 @@ function AutoSize(): AutoSizeType { intersectionHandler, ); + const debouncedSetContainerHeight = debounce(() => setContainerHeight(), 200, { + trailing: true, + }); + function init(emblaApiInstance: EmblaCarouselType): void { emblaApi = emblaApiInstance; reInitController = new EmblaReInitController(emblaApi); @@ -47,7 +52,13 @@ function AutoSize(): AutoSizeType { resizeObserver.observe(slide); } - emblaApi.on('settle', setContainerHeight); + // Need to examine container size on both settle and media load, as settle + // may happen before the media is loaded (which they subsequently changes + // the size to large than the maxHeight is set). + emblaApi + .containerNode() + .addEventListener('frigate-card:media:loaded', debouncedSetContainerHeight); + emblaApi.on('settle', debouncedSetContainerHeight); } function destroy(): void { @@ -55,7 +66,10 @@ function AutoSize(): AutoSizeType { resizeObserver.disconnect(); reInitController?.destroy(); - emblaApi.off('settle', setContainerHeight); + emblaApi + .containerNode() + .removeEventListener('frigate-card:media:loaded', debouncedSetContainerHeight); + emblaApi.off('settle', debouncedSetContainerHeight); } function intersectionHandler(entries: IntersectionObserverEntry[]): void { diff --git a/src/utils/embla/reinit-controller.ts b/src/utils/embla/reinit-controller.ts index 572e0f9c..ff3f2287 100644 --- a/src/utils/embla/reinit-controller.ts +++ b/src/utils/embla/reinit-controller.ts @@ -50,9 +50,6 @@ export class EmblaReInitController { protected _debouncedReInit = debounce( () => { - // Allow the browser a moment to paint components that are inflight, to - // ensure accurate measurements are taken during the carousel - // reinitialization. this._scrolling = false; this._shouldReInitOnScrollStop = false; this._emblaApi?.reInit(); diff --git a/src/utils/media-grid-controller.ts b/src/utils/media-grid-controller.ts index 7fd38146..4ce713fa 100644 --- a/src/utils/media-grid-controller.ts +++ b/src/utils/media-grid-controller.ts @@ -47,12 +47,10 @@ export class MediaGridController { protected _idAttribute: string; protected _throttledLayout = throttle( - () => { - window.requestAnimationFrame(() => this._masonry?.layout?.()); - }, + () => this._masonry?.layout?.(), // Throttle layout calls to larger than the masonry.js transitionDuration // value specified below. - 400, + 300, { trailing: true, leading: false }, ); diff --git a/tests/utils/embla/plugins/auto-size/auto-size.test.ts b/tests/utils/embla/plugins/auto-size/auto-size.test.ts index d8e06169..412c0fa5 100644 --- a/tests/utils/embla/plugins/auto-size/auto-size.test.ts +++ b/tests/utils/embla/plugins/auto-size/auto-size.test.ts @@ -15,7 +15,6 @@ import { createTestSlideNodes, } from '../../test-utils'; -// Mock out debouncing (used in the reinit controller). vi.mock('lodash-es/debounce', () => ({ default: vi.fn((fn) => fn), })); diff --git a/tests/utils/media-grid-controller.test.ts b/tests/utils/media-grid-controller.test.ts index 15da4471..4f5b0092 100644 --- a/tests/utils/media-grid-controller.test.ts +++ b/tests/utils/media-grid-controller.test.ts @@ -1,5 +1,5 @@ import Masonry from 'masonry-layout'; -import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { MediaLoadedInfo } from '../../src/types'; import { @@ -12,7 +12,6 @@ import { ResizeObserverMock, createSlot, createSlotHost, - requestAnimationFrameMock, } from '../test-utils'; vi.mock('lodash-es/throttle', () => ({ @@ -82,10 +81,6 @@ describe('MediaGridController', () => { height: 20, }; - beforeAll(() => { - window.requestAnimationFrame = requestAnimationFrameMock; - }); - beforeEach(() => { vi.clearAllMocks(); vi.stubGlobal('MutationObserver', MutationObserverMock); From 07bc6391ec524244fadc3abbfb468879785c176b Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 4 Sep 2023 19:51:15 -0700 Subject: [PATCH 029/189] Recalculate timeline cameras when display mode changes. --- src/components/media-grid.ts | 2 -- src/components/surround.ts | 10 ++++++---- src/components/timeline-core.ts | 2 -- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/components/media-grid.ts b/src/components/media-grid.ts index 70a7bc69..913e1aa7 100644 --- a/src/components/media-grid.ts +++ b/src/components/media-grid.ts @@ -1,5 +1,3 @@ -// TODO: Live non-grid -> live grid -> timeline is different from when the timeline is dragged. - import { CSSResultGroup, html, diff --git a/src/components/surround.ts b/src/components/surround.ts index ef4a3995..cdd95ce1 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -113,12 +113,14 @@ export class FrigateCardSurround extends LitElement { import('./timeline.js'); } - // Only reset the timeline cameraIDs when the media materially changes (and - // not on every view change, since the view will change frequently when the - // user is scrubbing video). + // Only reset the timeline cameraIDs when the media or display mode + // materially changes (and not on every view change, since the view will + // change frequently when the user is scrubbing video). + const oldView = changedProperties.get('view'); if ( changedProperties.has('view') && - View.isMajorMediaChange(changedProperties.get('view'), this.view) + (View.isMajorMediaChange(oldView, this.view) || + oldView.displayMode !== this.view?.displayMode) ) { this._cameraIDsForTimeline = this._getCameraIDsForTimeline() ?? undefined; } diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 126ea111..25dcc462 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -1221,8 +1221,6 @@ export class FrigateCardTimelineCore extends LitElement { createdTimeline = true; const noGroups = this.mini && groups.length === 1; if (noGroups) { - // In a mini timeline, if there's only one group don't bother grouping - // at all. this._timeline = new Timeline( this._refTimeline.value, this._timelineSource.dataset, From 25150be36b843f5568e8b750ae8023b2dedaf6de Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 4 Sep 2023 20:31:20 -0700 Subject: [PATCH 030/189] Set the container height on every resize. --- .../embla/plugins/auto-size/auto-size.ts | 10 ++++++---- .../embla/plugins/auto-size/auto-size.test.ts | 20 ++++++++++++++++++- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/utils/embla/plugins/auto-size/auto-size.ts b/src/utils/embla/plugins/auto-size/auto-size.ts index ee226555..96c41dd9 100644 --- a/src/utils/embla/plugins/auto-size/auto-size.ts +++ b/src/utils/embla/plugins/auto-size/auto-size.ts @@ -97,7 +97,7 @@ function AutoSize(): AutoSizeType { } function resizeHandler(entries: ResizeObserverEntry[]): void { - let callReInit = false; + let resize = false; for (const entry of entries) { const newDimensions: SlideDimensions = { @@ -113,12 +113,12 @@ function AutoSize(): AutoSizeType { oldDimensions?.width !== newDimensions.width) ) { previousDimensions.set(entry.target, newDimensions); - callReInit = true; + resize = true; } } - if (callReInit) { - reInitController?.reinit(); + if (resize) { + debouncedSetContainerHeight(); } } @@ -143,6 +143,8 @@ function AutoSize(): AutoSizeType { if (!isNaN(highest) && highest > 0) { emblaApi.containerNode().style.maxHeight = `${highest}px`; } + + reInitController?.reinit(); } const self: AutoSizeType = { diff --git a/tests/utils/embla/plugins/auto-size/auto-size.test.ts b/tests/utils/embla/plugins/auto-size/auto-size.test.ts index 412c0fa5..b04784c3 100644 --- a/tests/utils/embla/plugins/auto-size/auto-size.test.ts +++ b/tests/utils/embla/plugins/auto-size/auto-size.test.ts @@ -69,18 +69,36 @@ describe('AutoSize', () => { it('should correctly handle resize', () => { const plugin = AutoSize(); const parent = createParent(); - const emblaApi = createEmblaApiInstance({ containerNode: parent }); + const children = createTestSlideNodes(); + const emblaApi = createEmblaApiInstance({ + containerNode: parent, + selectedScrollSnap: 0, + slideNodes: children, + slideRegistry: [[0]], + }); plugin.init(emblaApi, createTestEmblaOptionHandler()); + children[0].getBoundingClientRect = vi.fn().mockReturnValue({ + width: 200, + height: 800, + }); + callResizeHandler([{ target: parent, width: 10, height: 20 }]); callResizeHandler([{ target: parent, width: 10, height: 20 }]); callResizeHandler([{ target: parent, width: 10, height: 20 }]); + expect(parent.style.maxHeight).toBe('800px'); expect(emblaApi.reInit).toBeCalledTimes(1); + children[0].getBoundingClientRect = vi.fn().mockReturnValue({ + width: 200, + height: 600, + }); + callResizeHandler([{ target: parent, width: 20, height: 40 }]); + expect(parent.style.maxHeight).toBe('600px'); expect(emblaApi.reInit).toBeCalledTimes(2); }); From 84be4ede57cdab23c32d61ced5f8e6da426bdc28 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 07:41:09 +0000 Subject: [PATCH 031/189] Bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 2 +- .github/workflows/labeler.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 344bdf89..fb851c03 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node and Yarn uses: volta-cli/action@v4 diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 95c02255..d41c81aa 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out the repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Run Labeler uses: crazy-max/ghaction-github-labeler@v4.1.0 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d1cff464..d50f0c50 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Node and Yarn uses: volta-cli/action@v4 From 1a4d38e609ad134404e8f08f1463f04776710bff Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 5 Sep 2023 20:39:54 -0700 Subject: [PATCH 032/189] Fix init/select out of sync issues. --- src/components/carousel.ts | 4 +--- src/components/live/live.ts | 4 +++- src/components/viewer.ts | 31 +++++++++++++++----------- src/utils/embla/carousel-controller.ts | 10 ++++----- 4 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/components/carousel.ts b/src/components/carousel.ts index 1b83b78c..b5a2dc68 100644 --- a/src/components/carousel.ts +++ b/src/components/carousel.ts @@ -102,9 +102,7 @@ export class FrigateCardCarousel extends LitElement { plugins: this.plugins, }, ); - } - - if (changedProps.has('selected')) { + } else if (changedProps.has('selected')) { this._carousel?.selectSlide(this.selected); } } diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 25bfd7a0..f68bdbdc 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -434,7 +434,9 @@ export class FrigateCardLiveCarousel extends LitElement { protected _getSelectedCameraIndex(): number { const cameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); - if (!cameraIDs || !this.view) { + if (!cameraIDs || !this.view || this.viewFilterCameraID) { + // If the carousel is limited to a single cameraID, the first (only) + // element is always the selected one. return 0; } return Math.max(0, Array.from(cameraIDs).indexOf(this.view.camera)); diff --git a/src/components/viewer.ts b/src/components/viewer.ts index 1b01f5bd..a676a3ae 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -6,7 +6,7 @@ import { TemplateResult, unsafeCSS, } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; +import { customElement, property, state } from 'lit/decorators.js'; import { guard } from 'lit/directives/guard.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js'; @@ -223,8 +223,8 @@ export class FrigateCardViewerCarousel extends LitElement { @property({ attribute: false }) public cameraManager?: CameraManager; - @property({ attribute: false }) - public selected = 0; + @state() + protected _selected = 0; protected _media: ViewMedia[] | null = null; protected _titleTimer = new Timer(); @@ -298,12 +298,12 @@ export class FrigateCardViewerCarousel extends LitElement { */ protected _getMediaNeighbors(): MediaNeighbors | null { const mediaCount = this._media?.length ?? 0; - if (!this._media || this.selected === null) { + if (!this._media) { return null; } - const prevIndex = this.selected > 0 ? this.selected - 1 : null; - const nextIndex = this.selected + 1 < mediaCount ? this.selected + 1 : null; + const prevIndex = this._selected > 0 ? this._selected - 1 : null; + const nextIndex = this._selected + 1 < mediaCount ? this._selected + 1 : null; return { ...(prevIndex !== null && { previous: { @@ -325,7 +325,7 @@ export class FrigateCardViewerCarousel extends LitElement { return; } - if (this.selected === null || this.selected === index) { + if (this._selected === index) { // The slide may already be selected on load, so don't dispatch a new view // unless necessary (i.e. the new index is different from the current // index). @@ -408,10 +408,10 @@ export class FrigateCardViewerCarousel extends LitElement { this.view?.queryResults?.getSelectedIndex(this.viewFilterCameraID) ?? 0; const newSeek = this.view?.context?.mediaViewer?.seek; - if (newMedia !== this._media || newSelected !== this.selected || !newSeek) { + if (newMedia !== this._media || newSelected !== this._selected || !newSeek) { setOrRemoveAttribute(this, false, 'unseekable'); this._media = newMedia; - this.selected = newSelected; + this._selected = newSelected; } } } @@ -427,7 +427,7 @@ export class FrigateCardViewerCarousel extends LitElement { // If there's no selected media, just choose the last (most recent one) to // avoid rendering a blank. This situation should not occur in practice, as // this view should not be called without a selected media. - const selectedMedia = this._media[this.selected] ?? this._media[mediaCount - 1]; + const selectedMedia = this._media[this._selected] ?? this._media[mediaCount - 1]; if (!this.hass || !this.cameraManager || !selectedMedia) { return; @@ -460,7 +460,7 @@ export class FrigateCardViewerCarousel extends LitElement { ) => { this._setViewSelectedIndex(ev.detail.index); @@ -526,10 +526,15 @@ export class FrigateCardViewerCarousel extends LitElement { */ protected async _seekHandler(): Promise { const seek = this.view?.context?.mediaViewer?.seek; - if (!this.hass || !seek || !this._media || this.selected === null || !this._player) { + if ( + !this.hass || + !seek || + !this._media || + !this._player + ) { return; } - const selectedMedia = this._media[this.selected]; + const selectedMedia = this._media[this._selected]; if (!selectedMedia) { return; } diff --git a/src/utils/embla/carousel-controller.ts b/src/utils/embla/carousel-controller.ts index acfb4849..b80f13c8 100644 --- a/src/utils/embla/carousel-controller.ts +++ b/src/utils/embla/carousel-controller.ts @@ -137,10 +137,11 @@ export class CarouselController { ); const getCarouselSelectedObject = (): CarouselSelected | null => { - const selectedIndex = this.getSelectedIndex(); - const slide = this.getSlide(selectedIndex); - - if (selectedIndex !== null && slide) { + // Caution: Must use methods/accessors of the new carousel, not the public + // API of this controller which may use a different carousel. + const selectedIndex = carousel.selectedScrollSnap(); + const slide = carousel.slideNodes()[selectedIndex] ?? null; + if (slide) { return { index: selectedIndex, element: slide, @@ -160,7 +161,6 @@ export class CarouselController { } }; - carousel.on('init', () => selectSlide()); carousel.on('select', () => selectSlide()); carousel.on('settle', () => { const carouselSelected = getCarouselSelectedObject(); From 7173743d0b43c02e552d04421399d6b7beca69f3 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 5 Sep 2023 20:47:08 -0700 Subject: [PATCH 033/189] Fix test after carousel controller changes. --- tests/utils/embla/carousel-controller.test.ts | 37 ++++++++----------- 1 file changed, 16 insertions(+), 21 deletions(-) diff --git a/tests/utils/embla/carousel-controller.test.ts b/tests/utils/embla/carousel-controller.test.ts index bc5eb5be..8eef025f 100644 --- a/tests/utils/embla/carousel-controller.test.ts +++ b/tests/utils/embla/carousel-controller.test.ts @@ -130,30 +130,25 @@ describe('CarouselController', () => { expect(settleHandler).toBeCalled(); }); - describe('should dispatch select event on', () => { - it.each([['init' as const], ['select' as const]])( - '%s', - (emblaApiEvt: 'init' | 'select') => { - const children = createTestSlideNodes(); - const parent = createParent({ children: children }); - new CarouselController(createRoot(), parent); + it('should dispatch select event', () => { + const children = createTestSlideNodes(); + const parent = createParent({ children: children }); + new CarouselController(createRoot(), parent); - const selectHandler = vi.fn(); - parent.addEventListener('frigate-card:carousel:select', selectHandler); + const selectHandler = vi.fn(); + parent.addEventListener('frigate-card:carousel:select', selectHandler); - getEmblaApi()?.selectedScrollSnap.mockReturnValue(6); - getEmblaApi()?.slideNodes.mockReturnValue(children); - callEmblaHandler(getEmblaApi(), emblaApiEvt); + getEmblaApi()?.selectedScrollSnap.mockReturnValue(6); + getEmblaApi()?.slideNodes.mockReturnValue(children); + callEmblaHandler(getEmblaApi(), 'select'); - expect(selectHandler).toBeCalledWith( - expect.objectContaining({ - detail: { - index: 6, - element: children[6], - }, - }), - ); - }, + expect(selectHandler).toBeCalledWith( + expect.objectContaining({ + detail: { + index: 6, + element: children[6], + }, + }), ); }); From 88563b59ac68a483804ca7c947a6bd33404083b2 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 5 Sep 2023 20:58:55 -0700 Subject: [PATCH 034/189] Fix thumbnail fade issue. --- src/components/surround.ts | 1 + src/components/thumbnail-carousel.ts | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/surround.ts b/src/components/surround.ts index cdd95ce1..7d1c246c 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -178,6 +178,7 @@ export class FrigateCardSurround extends LitElement { .hass=${this.hass} .config=${this.thumbnailConfig} .cameraManager=${this.cameraManager} + .fadeThumbnails=${this.view.isViewerView()} .view=${this.view} .selected=${this.view.queryResults?.getSelectedIndex() ?? undefined} @frigate-card:view:change=${(ev: CustomEvent) => changeDrawer(ev, 'close')} diff --git a/src/components/thumbnail-carousel.ts b/src/components/thumbnail-carousel.ts index 1248efe0..425d077b 100644 --- a/src/components/thumbnail-carousel.ts +++ b/src/components/thumbnail-carousel.ts @@ -37,6 +37,9 @@ export class FrigateCardThumbnailCarousel extends LitElement { @property({ attribute: false }) public config?: ThumbnailsControlConfig; + @property({ attribute: false }) + public fadeThumbnails = false; + protected _thumbnailSlides: TemplateResult[] = []; protected willUpdate(changedProps: PropertyValues): void { @@ -65,7 +68,7 @@ export class FrigateCardThumbnailCarousel extends LitElement { if (changedProps.has('view')) { this.style.setProperty( '--frigate-card-carousel-thumbnail-opacity', - this._getSelectedSlide() === null ? '1.0' : '0.4', + !this.fadeThumbnails || this._getSelectedSlide() === null ? '1.0' : '0.4', ); } } From 1c27bc55dd2a2eab6fe447aa083cad319f51823c Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 5 Sep 2023 21:25:41 -0700 Subject: [PATCH 035/189] Add screenshot. --- README.md | 6 ++++++ images/grid-small.gif | Bin 0 -> 4241252 bytes 2 files changed, 6 insertions(+) create mode 100644 images/grid-small.gif diff --git a/README.md b/README.md index 124f6e59..aa267ef8 100644 --- a/README.md +++ b/README.md @@ -1649,6 +1649,12 @@ Pan around a large camera view to only show part of the video feed in the card a Taking card actions via the URL +### Interacting with a camera grid + +Interacting with a camera grid + +## Examples + ## Examples ### Illustrative Expanded Configuration Reference diff --git a/images/grid-small.gif b/images/grid-small.gif new file mode 100644 index 0000000000000000000000000000000000000000..cdb4a6428f64a5cccec8520918492743ab2879bf GIT binary patch literal 4241252 zcmWhzcRUpSAHLc}RUg^*QAs#``j$tEi+$*N9K?ySp-iX@et zN_~-vmS4X=KA+G3@7MEw-p}WGKeqNZIFq1!pcv!_001}y0096n7zBZF@pFL%1o?!z zJ|To9MPX2JQ9-1%jHDt~O4&?WMp;HdLqSS|()G>t4YTVCi`9@Vk-&^5Kd;>r338v52A21fdZMrMWtS3@gzBTEY-J0Ii6 zTR6v)X7)bjrUplJbS+L$EX5I)YSNY#)|QqgmX>ao&i*pS_#k(PJv8 zV-9M^ypOvd^>Ft!clUGm@Q?6{D)J6K?tS@&kF$qQ;5na=Q@*VHT!g3E3x&6i>z^o=mJd<>GqkR9M96@W`4M zrxPPjUnxDE*BO;r9DV*=bP6rzq)AMqTTE0yyrV_@{MPxn*z@P&E?m5HAvG;IIX0Pg zJ|)gPCF$s;a{<)kXzG6c0?OUoXNm5shFU-(|p)>hfnSXJy) zRb5`ySXI^DQ(Z=>uE?#u*Hw4+NPRD};qh?8%P%*ZsvB#{8{1kNIpa+wrLDKyZU?2@ zzF*s3nbXd^eW#Rq=gHHK5q4*5Whb+%^C7ddpVj$%q4WKI*PYwF6x&CS?>!pmd;I9m zGQ|`e*WCu+dVk={`>cj-+%ue9{yH180*ZQD`9qQgYg{W%@AgXwUzL#173-EbCCKXQ@NiMFQ7kuqiM zyBeNc!yIe%e--=IG=7ntx@r^i#yoF(A}8xfbfrm>-0?zb)oYE;m7mT{?eV-oKdiMr z{dQ~9E#hdrvl&}@EMd{LRVO4(I^8hT+=_SoO98yaF8wliaV?>Odt`3dZK zS*)K>qBe!Lo$x%4zb4uLQP~u2{=CU;HSGA4IsN!f)hX?h6^Ji=*)HG8N2bm*S?nFX z$k42L=9=*Pvcn2Lue$-R_Z$DDI+A~D4PIIqzi~t2mDkm6wg<@I@s$+I>wArhrksKI zH&QOV0ZChL$0qPz;a22iP?lMwY${?Sj4!?`=j)gv!eMhFTxb%Ur;n6lE@-@aVw0A{rVDJ5qD+UYcA@<@w70`KT2Ll&n2W^uR%4%ZFBv>jv{D^`os_=^=*>3?sD3rduvIiTiX)Bfk0lG;4jC`;VN1?b=4`92 zSM4jHHw!5SEpCM|BPGq{u!3Xu^*gTijru5~kE6vGTpS|Mi$gxs=F_^w2>JW&C8}yo zKP8o_nidXes-&&OXCDpf?u|O5n=`v+LT{DrHlBK|8x43Qs=5(>4PKlCzSD1`jgW;%jIzMAo)Jn zG&JszbY6an@_y%?L*CaPUFRK-B+hc*{`zB{dy+KqPI3Ho;&5Hy#ey~E(a{X8WhYYh z>%H6A`3qN!iHa>%UKQJf?QI8R^iF(&NnQ><*k1XkO_C$=>)P$QSVy<2Xh+(R zuR5V~_T2hYhK7uiGA`@N5+10cS7jTd0msOM-D~(mwRX$wO|CzcSi;XEtD>A;`b&Od z?wYKfK_JclVscQ|PZN@;TdO}|V!6NekCT#8Lbb{Ff;6em*k8ZH?E|+%7 z|L)*6r&-^qlVvavbqf|_;Wn4ILge;#h0r#1((=#W0?&N^~n2(C-xDDlAd(TFA*HQ15GTUlux?^ zU4<=2$dwlr%7GMMGO;MGlN}@l9sMV`DYSg3d59%%*YLsKY4`tbDVcoq9=$~Fmj5~* zl!Cj5U;dLWljzX$O#no!#W48GD0CCTdb#WLP#JYXjHi?F^ifgSPi{;@=7erC9I1sx=pFS0%;ye zvEc|NEdjXs2i#;z6$Cy)%0Fk9NuI8rkvS95m=bBEURAf7{R<{)kXQWt^wW#x$-go? zyc&jhUZZiKbi*>aXB>0)!91$@J6*xE;twwEHkj^AQ8dOj2H-{jIxCcHTR4U~QCfs={QUPgd9y7#03 zH#WxA3Q|y%e9kca${Yqgdtpdsz3OR)lv&<;QK4|3^>CKdcwP#gF6*^r8~Q%MgVq6l zxH|(rX*m8&6ghD7#y25#f!*wxsSx=D^LkmyTMORW@a#KpY$*_$@wVJIJWlj873u0{ zJ_Xa+@Q!igQ6IalF3}DnN)v*S3a8rWvQ{2pxH+IuxahXt_3J_?j;nRe0=NK>h(5L| zeS@|CUcB|vwGEYEL5iAze8L2`3Gx1z4^GpU{rc|#&vh@JIP^jXVJJ-({$9elR*msb>BPNfP$P1SgTMe#rhz3O>Dzil z@YZNW+hEUWr^F0(*21o-X~fA1ZZ(xl!E)=mAsX$`TWyAFrz#OrIV#~P_cNC-;~z>J zS%1q;j1rPFyDp7<{6tZFP{1GGg|#pK@8PfI6FCQjG5*7EUEC7Xz?f(sMUUg1FCAtv zHh`Re3>j`QLd{G0k+o($d_kVyK0jCv1NX86a!Ii9>%@(e3T8oo0;SopV5Ey^Dp>Mxb5||v%4Wu`u?MeOP)4Y(`es*LeA^?N@>o%sZ`(wYa(Th}r|%%}K{tO#${gglOW zZM^03ufZQ#V+(J5TRr!uJ?q4&5~{}UF2@u^LRjQsSqp3Gxfl3@D!~y{_ z=1Snb(?M^lp)cm!BWM>B&-#1Vcy8Fbhy1JUtR*xqBJKsUj|(0RYf|kk@(`~({9fk zAl4VeR=FR$6>QRRx81R@s-!97l zW$*^&ao3l3K`6l0qVuHErd=3KviMQ2Qa?aV!O+nE3E`wSHqf42)nshZ3(q&X7UYd+ zex*L#i`VgVmp`j4?$-JsDRKSabf~@X!ZS?MbX7c&U+yF3i6mm9=7up&MaY%^&|WF9^uh&? zgj!+5^Xd9Mg$Trs4x4yGh$ZmJ1pTYHL2XrK5ah~#vq(Lj7w9YeXJ~IL63B2MF8jh{ZisjR7g|7mx1cLnI7V=j>um*e`|Bj-~0&Iw= z@*H0A71&HVR7Y$q-MmEPXB7+k#T}=ODu}TJe|9PX$-EE7P^;5?6Q1bOF*)n| zf{WX{IW*ch6S%ziBiaD}9RvE8f0kOw`>P5U317Uf6-%(G9(m2{&2hZ(5Rh z6Uj3~5qrsNzNIVJ9oC+_!~3zbz2hsAp>R8&997MWJUYWy1(a=ClK4C3dlS*IumiiV zE6DZG#E-y#7AupD;=MD|!Dn!8TK)Em1p%?~wu1URU)35+MHiv7OZ`)qR#umeMmN^6 z+x-yOZJgD8y0%;8b+^T@ZoG64(X7YHugB(Mk6lHN!^0k@*F7%3ddSju-OTQ~``z`t zcvme*F)v7((sBL+A@m!sxrBx#1t4W9d@mj(v;~l?o4z~D>Ij!MkvPqVZ;-Cf%=50e zpX}JPvfQNZ#$zFVe>sHD{T}SzQmeRvgwF-~9R=oEEFTOCyF+ff=+|3ZarYCR-&t{!6jdbE>lCiKK6%)`_z*rdtIj^W z==JVG8cM3<=vWFSvi2*Y>dos%-HunD>Q%(MRfyGV+tyXQR%8t5=jjjL`10#v_ z;8JdCX<_fpoCD1#7@diW4m92YxYJ!Hk`iAT^ivKFuoK94{0BkyKC7AHU`eK9|P;}UTaoGAC>ZL6lDkJ|i)=MRR_tv)im06EDT=+k#Ra~+*e9ixPn26St{_d=&+~o_5XG$d^U1DLsLt=PC5Jn#l*KU> z?4XMw{5wkjJ52~uZ~}ykwH}M_TO7{<2yC23Wj|+$7z_DE3W@69@{7YPM_dUEznLBuU~&Zw&35hefsLbG#_^=Us9Y-BVX2Eg~!c}rJvvPv$o_h>5mVWuWk1v zuRvG!Alxf{bVO4vj{KFchCVW8F zG~YE4EDx{sHx%CWz}5uYbYyNSV%@=6>1lR{WqagP=Y|-bY?TB27|mKRhwM5%An_eP zy(j)WKtx2M0Bycnr;cRDHL;+z)UGW~Ooy8&>LFGNr&agwk< zd$~$@+qycSPBZZtEcAy;3FY`jx`#T5C$HwF$|X$1rLguj!l~zT-I+3Pz|XEX#0={` zGhCA*+!b1j<+(F0>vxHMrGLRc(&OixrH5fY*H;4{5AOs4g0F;N-he=_3g()YPuorB z*ZQVznA9dbuPH{h8|a&~Tm1((88Um~d*HL*Zq|@!zP7423M|1<57*j5H?K?E`ei{= z_(de-cw=|1>8l|Jn%PF8T>P&#jR#izr|f#V}|zhxu0l}yvC1AkK59<70_G3 z?AGSY*#4PRKkq!Lp{2HpP?*YEGMa+_+?o_j7rOV{a9`IJ{#TyQ4*qKpwoeW&bc=h3 zdm}y@!|htz_TY7b(j-6x52JeCBa`MD*Iz<~8u|;{hsTVo-)Qd}`6!8u25aeI1*Rx9 zmjET)Go@E)ievZU?hU|v3Nc#{>^V>&g7&O`B*2k;ybz~523k=*d1j?7c%^05xJjGD6U{j}L;fiJo|6_@bg zj|MI?S*7+m+@xCBb536P?Z-!d;aZo}HCk;D$+~xRTg+^XG2CXLMa<`~pQZ&3#j`8p zf@kNz^+Qf-$gTHc-LQ4|=cVe3VHdTnEEk*1;K8@Yf@E#{?rlCEDPETQkHg=u(Ay}8 z5EL-KwOw6d*QVA5LagTh=fC!NSMI-UveDyn&4RAcIf}gFA9cF4l`BCA5s zE|kTc)7z~Jx~O=s48xI=;Md8Qc#1Mm)h^83k-YJy8|&A)BY)wLB_Z?_^&z|+-6Bi* z)cJ*FmZb1C>~vG|Z|VOcPw3o}C|uZexKUwZPY^W_Xy8L`zy~zus2+U zz6HOP3-S8qB`;|Bc<1kCb;m zE+77&$nXEz7Gj*(PrI_8abrL8@qYHZ{oKR-{Go<nd+3hP$d%vM@(%vi2<75Dc?m+_0e^M|1fQRioc=H7&S6Mi-=D?9cbx6!1J1;s zTmNy4SB71kLYe>l>6HJ~^4P{o#rl=yU;Ouw)~A0r{u@43`3rOLa6<_GWl2B@cIGXC z!6PIXI+}|jUi_-)P=t$9ASQj{pBitDdt;lkJ%33CrWg8z`t|#tU&c?J%k?5cA0-|W z*(fPZPWJQ5*(!!SmW?U<>4y6+=`V{^O znzGN1WjtC`G#VD{k&zG0P`Dc-eKUGJ*ZIA5gzQbzd;ZQV7CbXbHp}@(c8`sk){|dr z9;su%5I6l6F$MKj9}qu&ElM6)IdjAEqN5dJTMQK4yDlD@Pw0>c&ghJ+Xp<8q;~o7w z*Vwk&ZJ~n#M@>?Tz-NM{3E_=pDwUD!xJC)b00nGiEVICM1bK%#GZev4Yb=FIB2t-t zQHYy@0V=gLp@66h*4g4~9qS0?g;kPh0IaCq+HWI>N3JxqTrH<$Y(LmZ_rkN)n-(mBW;AqnG>waI1#owX$1X?95y7tvjtU#BqgFG6@q7hX%K=EnT>!#a=5+ zm%Fg_Ktt!TURaC#z?YWv>T?S}IWkki(&^ISdTLgAcn20b-=Mg+5sq?-1(yeA)+S)^ zNQKEf3zsYs{~R+`%SfHFPrbK5!O&&i{9WFFTr3R)RXfy_HcA_SsHdRD$b;pA3v83M zdi$j1_0qU|oyxAK9{4dbtyK_(g`^2mS{^x)+VsHm5oyEZ;!+u-|EEgle}N7vJ`F+J zTir)Ry{r_r#r*W9kc3bf23$j`_mxc%z)zl~Acu3`AOKfL#!z%%*F6Ud&;mbnr+{!uBD!%u)c`fd;FYqV9!l$-)n)-jBz;Z>+!}>%Z)@x!= zrU;*=^)X?9@$G#Oe~3`h{2xNs&I{CG*G&G;eU%A8=RxUzbMA|l2N90Dm;8|K+l{@k?Qn(mbsn1lz zbO;ubL$Q48{^@+@hS2CmU2gNm<=jcvF4-I4H_AJ8Pp<6I<*762ssx|jxW4wHcz~5c zAyB}74J1nMAR&xmZ-uVu9g5$d;8MT51hw09=&m;rz>ddiz9dt5otXh5#ZOXWVs*Hk zN~w2CmmqRZEZ$?yEZ&p(bYG(539_RM3-NO5?Se-G$KEM>f+XFT);32wiyUNN;{Rz`>jYx+`YAI}SQ7%&Xu!h2NDOlpA`qSy zoQ`u5i$2fqU)^DfOGU&8-)$c8V6w|j#|~;NlC#%^t#e&rbQ!S19Rv0+`olAiRUP(ZnOhuq_Jorh zj>ii~c#<@y(+ED6;hvEP>>OmroNr(tG3s?7LvcG08km%3n9uS%m<^VAEE|Jiu7;;7 zNc0XL(N2)i`mmvH{Cq@9`@EFVG~FZ$L1}J3d-xUhSug`X1iS+~kDH6z=0Ag7Or*&dqCH*L{L(P{@hLkbgLV84EV{CaQOzlc4=~7^&M6? zI(z->Ff$byisCMptcPfHkTkQgFyg#$dN0T6wt)A_RzyeBBchp!Jk zJ%mPGU2N0_9p~&+?{jUnCYfT=pYFfln6;PW{+M-BJ~R5nM>XvBUL7)HpTL81<;U*Rh)4!fm#)rXcw?Zx zn}(qoseaR744n6vU$rSF$CRA&0wo?oDE`!<|HXtlx1f&+1ZjoS)wZc}OTf_lG!m)j zLv!lq@SfFj#+rIN*f-TN%gpJkmUBq^+OF1yZ~OZ?h>aPNKN<3pHRTyD8i)P*UiLAvYooUJflck`k@A)%V_}v zso%#SM>ve@Ktv4P9CoW;j{;hJO*tz~$JS79>WLWfSQuTnYLHJaE3LPHiMM?;X2n^g znIOLpq~0-QBI~gvLiV0i-&s6~vbHE0xt855g+zO=#K!7|(LF?tpEV^HbnPSH2; z&7?r?afId{I>hJ!BbW(spQi|J0tuVIBe9HNJXc*Hmph8f6UA!-Fx_YYn_x_XX9ng0 zw40yss3qu^t5g{dRkG#*VvA~or>ntfSZ{(vL#{7|ZA&kG-$jrSWgqu8@QO`cTSz5u z+oGJbH>5c7FAONO8j9)NV-L06NEmm&=A0n7MO>O}m&IWWPK|5kF4#oZCcNzECRe#V z39*pIjkW*vOhM|?BdcDlt(25M`G~7G!)a5kMlsa}(CRSH)|_BiFw+0Q48@@!I6yfJ z9gCsM?bE87jho3s$qC?iv~f=hj|m>Ko*?9)B=i1Z9_5yhO>C;Aa0C5UW(+**GzAix zaW{S*db%cUo9@U=WTN=4dui(VILSJ;TKB=L4#tPiCvk`4Qv*@yk(9JZ3^a6r%dc5M zJpt^C;nILH6yPA+O)hs10L27`_i@?g(`(7q>p+M}pg#W#d`MaK&5#H3@KG}j+tYEN z)@#nV4zSiV%`uR0pr(4~>+LUr1{Al_!z-HFSJrH0L^-Qlw(s1g9Dmt5ePz8HLkX0- zq(bg0tvw7l$aB~>`wmk0)tXj;eG<%vFf~t|Sg`loHmt+i!y=wWlp?ILSG%{N<4b9^ zGX)LysXJ;NS;=KKNvTzfM4^K^9VQjA58$VRw8&!yl+3y$ve2iFItov#l{DXrv0Frl zJsCSmWP1b(+0`&YKkPJ1{Y0L~np1sGP%_ z2#%V-*Cz;^acT^k0lp07IW*4#Vq$4?&p@i1K!Xmt+BEHGep>tL?X$~VE(uL!JCNi& zP?AiO4Fp=W3}DN|j``KLj@3}u$nVlpbb@mXo%8Q#-r2PyV)YKmxH zVYkhvSsze9*=em_YQtEy0rDEw9^ItLYqr@@mG8itbG00xvTnxU7n2d>!b$byd2~QR zVYiSK*bZi@>wISPQYy30tC!)L5I(#|AI=(gbc}pVajx<==smv=5sqbecVrJmskzvx zSmC)`05pM3>Y;jmDwYGZ9pLg%gV-Xu+$a#w>HBLw)%Tx_M2XV1_S-^Cj+q{N9yg)? zk_IZ51)Jl+1|3{)_8x?ImxN>xx+@qYJctjoz=vC?p9M7Z1M06+>T)QsdD^8tgD>7( zc4t$q$KB-?n-mgLZQ%C7xPO&`yM~ogx@!JV7y>?-w&4s1Ot;`p&4^k4%kE5Jg?oyo zsd-Ad+^o#%t1@TyXRUbr6Hs$!x1ne7VzPvCxX)bHL3!BO#jjGSTEFY~_W`O%5$pjC zTT>6S9*U`QX!S=whc)6*Uh(~{ER&ai@{x$i8rSXCmlwQ2-P@ zdKeKneEGWd3fDX}T5sh~!K8%s%yqb z{`E|=o$EEtU}MY!V-1yAck$BotT^x6vt8l}ND-}Ah&git634R0VYLoRAju0it$hVB zfncMh`n!NeLtnlO02iEYy`TG^UCDal6u+?Wxr~fcOh^oh8*u5hEi9D}v7EXmWVhrl z=#%Mw_VwpB$m3py-#{v~#ZKS-j(>ewg$XWTeKuwr8gG~84ND6P9~_jbld2=-TJ_yA zxub5P)A_1UAeI*S=7<93QDYRZe%ZB1vE!wI-GRJ~B>bCr=i^6AOFiHoh*{L3Ba@4+ zaow5*QBO)mEZDwHoiV)(J=gsB^5o3Q=MY&f6LJvuNxL*BB$XQp6c2~w$Z)xYuWjGv za>PT7IU=JdE*JQ_|CG6G&OvtHX!h>(wK(NyQMzOHY)n_v^5~}XiMMaQpec6H@dJ$D z*Y6}!2mx?2Dbas;2^5|O2=A{4O97z}Nos#K& ze=)#6*|WujUwG(Zs>&mbYcm(9MVS7mS;zOj!F)d{<-S3(gMPu-;fn#D%F;1hGd+7s z;>GM{2oE^_(FSfFWCeheXSETH7Ls2xhuXNTmOy@(^yAGTnKkJx<|r;xKINPN*TNuy6`rAQe8%2?-B%X-?gaHqYmJx4jN=ejDi$3vr=9 zESpDWLhJXG??-Ej>mO;Hb6UT$2|akz?I}l(QA_oSVV!MBZQps``dLspoC<<&2%&%i z8B|s^HAoH^_%}=dM;8wV3MXyVM^pKdw#35&o32xy6oZ=MxI%FaolB2M%g|s>JAVs< z6clvy+l!-I9*0Xp;%U+DshA~+o9!0vd-a^x0u`uEvTLH_6uCdHZJ5^ zYOB#E$}XA|o)2F=;bm{fP3&2m*5E07FJmyp&yJ29@tu zSkT|FfjJ5S2^{|$uY0&VmPQ2&bA{rw4)Z!vb5Y!*JcsR7$$b^gok~?P3c?U%3FmyJlVx<(mBnlq~5dD(w&Y?QRGMq4} zKeE#Uyt%n!mZb4qBiY~|%=~N1kuHI2Hgju^rRPOe856t8Gu~n?=AW+1Hon*znOTWr zs@T35C*D&v#V;xNdhjLHk}RQ{_GG0kay-rVt z^8rBwi9|7NeUH!ZBUUXFA^ykddl37U5XX3j!=E&l7$^Bn*QDUCSN+&ho+Gfcu9hO$ zpd9|8fgr*+67quzjHVL%&Fd6cXY-e`H%JHYn{M)+e@5G`)GOf9OL26XD-0Qsloos^ z#Iz9_XP4e(_xOAu^auxF0^|PY2FS#MB>xfC6$*DC%^L#=$AFLTLqhVoPwqEF1qOKU zL!&9s$|wpr18|5cO>*hT3ye&`cR*SjeMjA3mOlEax_|HJuO{n!;J>YmU?~-ep-PrsIry*fApJ1s-F_i= z6bK3v(1Hdqb+?xWG;1+Ft)AM8_u{^8u+U!G@5~+ZG+#-LMpx)3ZLnVj+r})IpXz6t zNPqjduI5^-Nl4y<2{+i7NE-U~!1Cqs831f>Vs~M)*Zq9N#SKwO_kZ@Qb(q7JdS|fj z88LL~#9XIu@aY|?)A!ouOLU?qfBg`uF2+VoGiQ!@<-O@U_lBtkUe}Sp(zr&|qL|yo zC};7*ixDfSycMW`Vsdp~XuOOAjzs7hDii5Cy=s;4$#YUt&qWXZrpr3|<>|<-7G;{& zmwU{_*FASXRZY&o__!o+NlOFXMn`70_Tx(&6Bh!lk4vBV``C^ZagkV1UFGs7Rt?5_R@Z5hO@r12cL(BJ=ZL@ADQfdy zcE;tRx{I{#m7b08z1#LJQ|tc3>QlcI4_1kE;s+0};}IzeP*Hp=a5ykHHf}!1*>1#J zBr2)%G`z^evrHmAe9q@o(ZK!JhBtFOo$DwDEIyrU9B4(JO|x_FQDp5dIP{vJ#r^P z_3VqaG@0PgXFfN6EtklTWJVX1w9F>8VoXK3INtJ7X9IeU=i_1){unn z03lm<2nAlL2_rZ@QM#r{TS2Ex;EA~=tu-J43mBHpdt`fnlqCKlQ>1^kSWu(#1I!_c0P&UV91^QTp9Z$ zR0Mqurp#R(&+j2hDvsUdt#R{7$TpzT> zksiJg>No!C3k5WMyvZ%q|F8fmf$#a*8mN4RioEUaukxzB;r?fXx#t->5bM5fi*he$`$0#B2 z13eovy|~;n`yiPb&Xn0MSJwFyMd^2&BYJ(nt1;$8;Jr;JI4uOoW4DA*T^SPpevI2T zmcZ@LK7A%xuyh)% zFaVUA3g^{p*tvdZ8D%sc(Y&5)m1tN7BhV7kD^=7J2q;7q~R^_E3Qfo^i zTFkgi=W4~oCME-oG`?!_LP78>Zb$)+=pn~GJroNr^&YN1*<-*~-;40{PV z>U}c#OW#EMiVyea8HUJWw}1FZlR%6+Sn7TUMC@Z=j=fS{O{5*;w{UXBuNJf{D`V8S z6p`hGuSLAmh2kLlS>Xm~>B)?6GtK=RA~J+F>1|{57LgUT7A*M&HEKvEfUxj-#GQGf zYy%3&hXH`woeG@qq0&)|8h*`uAiNolELtWDrVh|0_bA+EMYXLYrIiyk9W^SLIHFXN zk0^Esf+6onvSTx+iVk>PJ3O@R9HO|?TnHI*6EzVQ+bnoSU~0bwi`N!KLu4=6h&gH5 zT8x3_*x&1q1UrMXlz~Svu2*B*=*XK<5cGV3Q2gSGcmmDp8k>-PDfWZpwq1q(vwMPL zU3BRR_p6wZpu%Ub*pek3JeR+?BfZB8g>S*QR6XMyk8i}QGnYm!=4NtIC}VOPfnO|t zFFy_F**JG^b7jk5xF!5vWBE(|>qc(|CLgABdst?$gr42X>Su^q;=|GQ@!0BoLia=yMMb5hGG_%$sZZ?%Id{K_)-;WztXd)>y09Eb*Nj z`sDWjm#)(V6g;j87GJPSJH(b22pp#jA|LESHRo#uf|Tl!CCoHrb1a|b#0N1eNh(PA zpCZ@Pv5W%@Dd@&#m@c9&#N-o2j65@HtPESvA?Y6AuUuRahAk$W>c)CY^O!U-{;;zn z>G)8-yC`eXsNmVm#Z-0izzD9??IPk=!Pp|pB zIcLmY)s&S@K$yk&wEYomV6;CP$>|spQd!O<^#uxyWt<>(50j&s2c_O{(y+zLd?z+* zVH>a^`_=1N=kaKfClnjKLPU1pCL0;Td1Axq1G1r(qf1yptlLc(@`abs$S@4{n9EYJ-jGtHR4Wx?oza6Ot%kS{)3k zwX`hx9RF2+u2R&o+1|N{!_d;DW=2k3;JxroUlOtd_30pqUHtx4Yp=exU_WRt`gy(=Q+(*=%M_3Q`&5~HKeVM%fsCKj(VBs z)sgZuow*mb=(3^7sWuc9(YIsq!nLufTG0_($5#qVN~Ueh6<_>IJ^zsZ6U(iwTafAU zMzFlhH^IQ{Y?k{T@%(lNpYfl6`uY-(*D{|4BM#6ITUWSEGtLJws6l-t{RdlOX4 zNyW;dw2DS(nNFUXr_ZtlAl+uK1 zi27E8#zRXe1ES7il`f2gU88Alf^1v(Fq&ZfP?}LF-Nb!RE1Rg}Pm$3jHdP*`BNrix z*%V0S04xx|lLL^z;4kk}WdKB3CP4Q>=@|0S}2{kxf-DwbEPOUDZu5{9mtdY#4K>sxD4Ov2s z^V{cZcJFrv6gLU-GL!2;0(EDrR<=*GcrFN~#L~3wKlyaENBnb zN407|s!Sl%3J-#m$-e+9atJcI^~gp0%QzRoxFD&FY)*DIG6i^1i$m{tW10Uix;+5P zmQ2G_#UX?G$Uy_ALHRBZW!Or22aifVTUDk`y$H0@PhE+i9oeD>jj^R+Dl0w&sR)+J z1_wD0J~A+(m z?Zs(GCQxmOC@)U>#0k|N0y%xDdC*)MuSwENqI=@Ns2ZBI5}-*Jq!dMU^?W07R>8Rv z0OwEyl>lomfF2_R$tbGy(jlC@PnGA-^SCd)4qH1%YHHmg8tO3G@?cT54HTfYZ*7yu~aH1jPwMLn%g5-L6aKIM(-x9#^=9%)EV z|6^DQD*G^9AHPN+kgy#MNN=zXhNQGK!q9%9-=VG{-$X|J_$fcnlSLk z8IY52o1hd)x0$9MN-`><84V~Ia0ve(fC;66?5O-1Yykz@i~>=_4iDl`Ac1&Lk^-M7 zUb4r{dJJe8>?CO#;r@MCN{YIR;?NkZ1$&NZ23yjfQW`N(V)_r;xwlj4`tIy97hjYI zTiG9^!iYZcou=mf?_Wu%iewvafi3q*7Kt>K--O^VR7rCn0`PHdR!k_IAnkOrPCN1$ zYVIGrl|yM}(}U(2jb=&olf#2%r6kl$pt;k>rgLDk3>7mZ9bE)c!4c7n!xQLzph=It zvXfQhE0ST+2d5g25{jm@H+M$seXI}osnu|T3*BOoWJICq34Bd}tvbL~#j(3h**UC14Q7s3k=ii8 z`IFHJHq`1ve`_5|qbKH+2aRM?U zfn)J@H!&6YnP2exBTW{K#{h0nkoeLipyTEKGjh|^D{lI-(}a^Xwtv{%+DjUPCY8z@ zibmAhK<1#5`=D_sSbyK&PP7;@XWv}=&h%iOanIBs`Di+T7?3_zz0>fSmLLNss<#pq&N!$@S@6w^zX7a&|-KS z1-?Ci^wzeVA5^0Nm&8Bv@8K07Y-I}jgHsbD>4b%5jJg30jUTjdSAP)ut_eyn)5U5A zwi+veHN6)!e$ccSB%IYP4B07jv9;q;*Bby-T3yCo$rDFvulj zN2TVoGy|LdmhLqQb{&nrG51-7pX$a(6?dWYx_W4VOAE!x; zkzbUZ27MkMg3V(?Ea&NF2E8V_acW8Q|50@A4=uj`AHVON&xcxTowttbXdQGeTcy^~ zI_MyWt&%8Ngq*Td2c4`WN!XGkWO52&t0aUuhp-YtZ|3kJ-n{$n`w!ed-1q&uuGjT^ zJ)e&&s9C!BXaCYqFTD$>&ZGf{Hk7HP$ZGN6xv8Ce&fe*|?0=Q|Bk)h2h z2TjJFZ@u@UbjbM6qSHr~d3W07T=uYcwRel~we%2%8OQZseOc}mXHb_P20BT7>8cYa z6)uXGW#iw12Ow@Lh{ve6+ho}176^v0#mzr#(>jR9AHcqb4H`}kH4pB@sKH^erT_b3 zrW%7a!%n|KwW|L+r6#i8KS7t6jdIePa1s{xSTJ`UYxbY@w|i(b&-rsi9C?Lkm^ z2Ov)MQso-WgMqXK&qMt`1?5RK3!ou+k0sxvLB|JF&!ATyNc;xF4XqTD-E(AA8e(Z2 zqz>N`4!L)xTXopj?t7TscMYuu^uvdF=;qI%KX=#m2R8R+^3l&@xWU3tGuKSwI9X()fwrLcPD+}n3Gg6Sr?=>d7VR_Zso#ZPap4mxT*%1N~ertXvYDOL~U_q&P0 z2mghJ_zbvp_VPo)StyKbH(!Rj*OQkVTKZq_enGzsNi+|}HE3jLO33zE{|$dO?z9eB zSI2UHzGqGL_0nHIzMMXPa-S;h<)zF+IB=ELAuWbS*~g>|wqKYW zu0P;gf`RuZzqxfHdszOo|61+rfh&!Fc$?2`JVxor+`IJb`hTmE@0~kOtKYmZ`eAUL zezLOuYxqzl$&N+wC;*`~RkJ9Nt0jnsd#W>(Y#lh`= z-aA=u>>!s@H-6ewVU;TzJ9=o_)O$xJm#!S_Y;W8=zs^=iZ?6s0s}F_wbci6-%#_P- znsRtwPuuLAaxP1a3pF@olZ)5KQqC7_y4JLG*}ac8C0Ayu;W#hh2#dxtNOspr(i->; zKG(L=-RnUO{%(Zb?K2N}hoonpjFhc5ignZA&!=A;ci;D_N!+m~v2*y|-h%J{+`gRC z{_o+7%er?hH~xyNgU>d}uD>SqEw+4IX12t-2yV{xaxTYY0vSKa0roV|+-#Bts-Z?D zsSun!k1d9vd4Ti=Uj%?K`_Aw%w%&h`z#fwy!g&tqCaUKIx*6;d=XH*}x}?R4jZ{}g z?p|TdmunWeeJk6^k+i3YJLgY#!tO9?eUeBHbN3$J>vX7ZSB&eav4&W24JjGxKeF=Z z!E#x%;I`yUa~APTit_ZG?cbH}tk!sZIGwOP$@ZaT;i|r<`x|=_%c$uk6P0djct;0~ zVyht$M|u8M4+vdc_p?=m(14+)%vDZNYv+AzM>ZvG{xxZwv^M08$;7f#u=Gs%1^C`e z2@I+=v$U5n3&VB!O=nCqo@*dz>*oSAt$Rt^j@1|7?q`It;qGVG-JUBW%-{oH4eOuY zzHPR;wA%6Ia+wBBDn%jsHV@#YSWxj}^5}YBPIZ#Z$z&pcwn_cKY7s2lv<)?XZWXyE zOC_Nd?T9tDWzjt!D(AtuB1m`IWynz>+gH9Yo+cn|ts zxDX#P`nL3t_SKs2*J^UMYH8|U2;s| zH5TH1X7A2bT*SB6CbOYI>A!Xs=5eqT!2_$G>|-HcixNk8U3N|5PA`7lv-ngQ6>9#A zkgTn;b~$>($%R4TQkENu6o$2)3`t%(XS9$PeY%;*Vu3(mP|uL|D1 z;Sn`*3MBCjGvFaPg3JDlkcp{3T9-E)(u1%&RRFeeugqR{68)@dfWZn!u4*aAZ{oko zKX>$Yq4iHvWACy{C5G_x%x81;ule9XV_xov@uf!>>YR&<($ZBBD#C*3$`e;5)<}%o zX=SX799*F=oF-#mbNHa%@%!)p5ObxX?H*lWu*DQL%U%SKW=ToViehAdK}P$)N90k* zD>6~{s0z{pOP+Y8?>6|H&DXH|jqEJFyrO*1J+8F+r!y+F3lkYvbT&R1jBQEZM|+hz zl(0COB%wq1jHbg_@dEO6dS%*G1zdgV#`TiH2zv1s!VL$H;@I4eimcterDM>}FS?5K zPxtCJ4%@o_(7FbB+)Lx8K$3TjPNFvJcPzKZ5f|lD*qssXNc>YpInU2ozNH7Zu-(C= zU9o({^9f{S-Z*xpYQjNbI`XJrlp!yz$=<+zPD-akUd2Liwmh-DN^pL?&fTh?)IHu^ zzW8fUH^cVShhInYFSL>(*KIMzzn{8w;jZ&gcWu#<+3BnmmoCyjZ~V2Rda0tH+L}J! zb&;l8fEzG>qZ$hAsjo>v4Q%LTpTyA_<&IoYo7q`FH2d!|)b|wt!kjIhA801;VQUJR zGHXI2(yx-!AN4vcPOSZGlQX)~BDbEoxCpbtE!+5|zAT_mfNX0kA%|ijew{5SR0Z>usT&u6vGCw)0942EUk*9$j?K*Yv3{2~xGdo?!mdX!yw=HPno*ykbioMB zX9Ryg$ZVczXrlt2{gGSG80L*#rn4=%)(s45hjN6wB80|q?jS%5Jg9NU$sV9dsAfim znj?H;%-7J0Id(I{1})OcL(;U?A+7422~9(^2916zh?8t=2JEx!=-IYwp1mSW3vjN+ z8Rnw%{I3wn#-K;}Sj(N~v!wVz_*~V|xpn#9zVe83=NQ>D2qebiNHMjrc6)2}{yYu& zg91IpH|ZBxH86ho3XFZkR4ttnDNwixo*uYuRxtjwPWiK3X)-9byeTlteQ)GjPNoZf zIVuV26S?UC#G@OE>r*g)>@KaB zli&T3a72^{1o=Q6$CEXCs@||#;fq?Yc}A-7>~VCd4tZ1WX`j8N{|IC$VECU}~1Bk;LTOMjTU_kDFJD z?a`bgy&d_?6iV@%kcAr4mmKTKacf1y)ESM%1m|cWr)0w_^WS{f>>oZEHEv=KVizcl zW_092a5K(u#MEJJvSBDCw-_{=Exd0K@hI6_Tol;HYOE^hAxU}uV#DIf{C)jvzuoLH zxoH%8>nk~{)|kf$Y|Y=_tRY(>j3jF8xs^t;@m1gNQ*s#B+t^h0IBBucBvtHr9yAjz zuzCp2bScdjD{0#C?X3a|NY_-4)*znn49ll!v9)^#56Hw%@TQb-ww-VslDDbK_N^WTc?gKXJg9&d`z89Y8Y+yif)aqZCpwn&V^CUW>|k`OtF2Yn#5E+ zorF>@NXp_3XIT$}=AmM%mmE9bjrF9a{?9JTk0DDM;~r|<=)apu_v1c6q~)ABS&Rwih|QiUtrYFnYu_d4Wz>Sh8~*6bS~oInfgXB7T z?ZXb^XG7^nCN1yf5xaL~kcC33+$I5H-d}~>%tth*q4c86|DBp{ci99tqNt{(7G>G6 zZLJ@JRSinYh+vV)ih0iG=6w;7dX*LmG3h=X@1-G|bC_-#JESXRvBqfg8_L$fk`nlw zDr8z7!@?!C>)~$e$ruw4hPKqf*aIY-0Wc_Wso6MU5Wo$xE9A=M8D@|MF%;Crw&+8W)V4cPPm|YVumP!(4z+ z!iQ9`p(P68J`v2w55c7))m`{udh~zlXf?-L4a%Vz)M0?=d!G1*jvo_+SEF@O8% z$he=>cIAdjF-^iTpdTzLE6qB|~pbjf; z{W!h!IU`8VCh9=*x8v0N>Rpx${3M-I3)#MM!2JrJy!D#9IdxhxZWUV0_@=R};aIT6 zlu!*-(nh?(M;I)fSpZJOLblQog=}R8VEqH)d4=R`utwYSAqa3ZZhS?t!t0X1$Ip7%FI2K4{2#F!p+yZMc<4o+etLU- ze{{B8smsns34w)azn`vBQVEP)7Z-@V5>02c&aSnik(iz9#p^5?#v=1eGd-7To^i7@ zc$~&a$T0m{OtTk1wHMIpG)Jxv2*!5MdKGnh`G_n-_>hfF6(Oql&_EqP*Fm%`uw42r z`~>PaFyzC4QyASEkan|g#7`OMxABj^eZ(NUat4oT0R|rLv~s*)>SkuXb|I~Uv7uH& zD>!S>Dj>(XS#04|qtZ==)z!WX%k4_DPn@ooh}!qaHqC)Hg+;ZD`iD+17n|gP6zQ5bQcF`N zDkP6XTP48W{|()0_HGN`AZQ|Tb->L)M7sLz$5V)MQS5z3crb^2v#(n`er<&Rr-X?g z+uGll`zm*pYIT?Cxt9(5L36jgcejB(j7$F|94DEJ?Y}b()f%v_z-Wu<{eTIph)h!X zPjsCQwTc}#i|eQBMBu-Iv$K&WF0>%)jQ_C$i*U}?Z49$J*5)%K38}XB%%-e;;}$vK zxiXFATaArENorD(xEzAHl1VA%qi-3l;!p~dWQoHjk;Cq|@6I`TRgkeD1_eg*Tv ztK(KpvTRBgGjRcNNjbjs=;$7jE?zNgwCcznou-3FtTIv~JnW27%QsZ^NWc z^6`oPbrv4J|2W~`m2JO1{qvEEO>y=LM{Emoc zqp(>NO~&WIjO^ti2$`u6K_w&iN8EaP?@0+k(hdnUeNfoWr#2 z5iiueFs$3rtqmAv7YZ_L_n2lp>~wszr@rwlWdP&eshUW0eoC?3;d(Nst=73iStN!d zTeSmt_Y^+IC}VQ4VZo(z#zUS&#~(29jVOW>{QCsZl;lJQq-nZ|25!nLd1PV|usHc~ z#^v_Ish)R9uW>$iDa`b}1xIP!{xO^a0UtS##5~mB&t%N3&iWH(n6>QI&n?>JaKRig9`Lb>^Bs z+Hbc5KQ^x$E4q2ZsM79o)vY>@GK1;WP9)R}+wUwkt#TMALvOp+w(fbk+3WPgosi#W zcHzCBj@j+^ynxFp+kU?C=S@*kjUFo5HpPsxSv#CqVM+SW`>sP%ToMC;NvDIAR+3Q> zvBxL5%{jZWNLuZhr5dc_jO5u_2?`RgGq!!FA?qU}?^o5I&?+O~aXq@2#Y*UdDC1o$REWj#qNhs+|}3_s7h-^;!;KJdTgt ziE%6x_Q!Z!@$bQSouo|Ey0{iA%AjaBA%wz{^LKRw)T?C+R*P0O(;r_IAdqW>tcNBG zf|b{gEpJbZAZH3e7$vir6qy!ZbJlaw{o`*8c3N)sbkA`4gWEoLK3p@mo>U+giKJE% z@eV~^ENP84!dH<^-B8d^c@vm+F-0X=zdjOMU4on!F@SeOF_w8YbJnLPqc=}y+q7kj zV{Qv@izpJ(;BeGD^W3Jby;A;k$#uW2GXuH&xa{07Q9*rR)q-9SBNDaHK4`5zcTSt^ znL_w*1qad;QPp0T42F_>gbfkd#$C)Z7wsT!*`GH0S>pw>4lhShk-=?b88CQXF@&=I zC0Mnvx|NVllAKsy8;+ilL#$bq832@ank2I`7=%q%GhwSU?-5!^=UIaqVsKaZ%kM*e zcK4JJ6DAuqL8{13e@*N5kF;D>RKt7NW_sw-HKr}{f=5vn<@7+SC&marcXvNgppbex zd7@*vh`nclG7K<|id9Ic$7%36WP{FG2BY?B@7Q6!7nLwlk@p{i!^^{FE@VnBmaw7bdWCnM zuwvftabh7GTxQ`PAN*IoCo*Ni!uLVNyaT_9+xzS+>{kxDPpuDsHDhP}C&VM{5|WILWWY=$d^=xmmQfqe&dYgRMgSlrISuY| z5sk`!1~I*+Yh_i5F$?Z!&~JHV2^;%G=wh8QyAs5?0Z@k=2HJw(Z%P%EIr%_575XDP z{-SyQaffk*y;U^aDs6Y~9AqGOXlV3{b_MsLSs)eh-w!|2JW|t~3z~sttVB#Y8)}@F zHy~i&lOwPAbmXd`)>;IW%0QrDwywWv0=>7 zFYTIuJn)CJnPq3*BfmDs(hC)g8pmo!ks;IxR7lDMGAqx=q>YQt%dxdD(}tTV6v(K) z*$K+YydB1^0Nn9A|6vHJzcaoz*-`h=;Y-2)(4l(JXt)Jtr!_PoA&}6(38OcckbV_LbxaY1dgI$%>;I`O$yaBVpgI^36a>?EK(ops7{jS!c3&Oh9J_O9O3M`TH0yelJX zR}I#00WryxHhjX%aEG?(`_~73NF{mDrnBm9v*t)t2*)rOV7~Qk+~ky7E?w^eVtm{O zERDS@#`iG7ugC}P%pVL2c{W}hKiqHHg&HLD{=&2R254P8H)k~usjXH9wF!sZanDg* zY^99Hx@gnPl3F(Ed`|m`(YgFB#*O@+4wW1v|L>OcHT)T~yiEu%g&4P(|I5_>%F0dK zZn?`uaOSL<{l$zCO8O|yk%V-N>> zO}XGqm{GAD=5Wpv_nJ-E#UlLR6DHNfZ(8EN!dd(*0$u-2)UL)L@1-i(n4LUikQ`P( zLK2)1+&8Ft6{dm@%Jr_7MYwA`+^`mVhlIPQ$3N8Sp@k_apK=AOJ1gb|c`&2%>lKO{%*evLaQ#O%?bcBGnaGJYEjKs1uCA$8+gDK&oQf zZ9X(W5A`sD81Voou${^(Eo*1QlaT90R$2T~v~IDT8d9o;56bVoFl?6`_Qf87j8`_z;Q8(Y_1%Nn0&Zp4xJptqzX4M|~j#@eT;}`UKV9^UwRV{!Y zAQL}p3Ezdpo$qp=@=F5jq_6b&NH)}!Z*DJy9MPbvRpz_(m}Nr9)eERf7P?dj-3B16 z6d+ayER#daM2IqA$Mep#(WCn<)N9A~Zhh4Yn5lq%)P8~vm{)lKuLtnzsNL%PJ#0)n zfZl$FLC-q4)Yw+6#p%>sskR`H4h>ZA{I7Q>jK|#-;Wu<`7LMToHqCii@|BZ3Y!SVF z7aJX`E_}?#eiRYM*@SUD?w5#oM@1Y5&<@T44ts;F!%@R$Ru`$^>jByZz2`1EdL7I9 z4i6XDb*NW_rE4%qB)U`$iDlPQqLGhy7;_TTo(~eW_82)BBZqqGfw;~2en;RrN8FF- z5&M8L{CDJk_NXYmA)tpyD=C{(&SR4hVKY#l)NDWBdE~>{Kf~P?R_qyP;R~jaz@X_K zHTJLw&EJR-^V#v0=nic~Wd>$-#q!MZIY&-Gyyca@)L{<*c+kD}c=P;4`h7cf2lnzX zRgX}c70A_k)4il984ve~6f8c4d%>EuI@oMc7K3dTAvb6d%YZGxx-Cy>&=AF{WkSSe z9n47%`qAMl=*Ut%bSE9T@FIv+fHv~3WEFtZx0))zu~qrwF5Rzg0$6_c+xNg=-huZ| z0gMp%yr^Ivin!C0xMnc_3mUy%Eni{>mbU}T)&aIU>BTI6Ew5D5!nJ&jYXA#F)gfD!;YkI>tpJ>0SjmSN{ z`w(U`9oabCo@VHCY}_^dq3(59vlZAwyeP9?Xp90DD~CnKAkXR$ zFZ>}EUZrH#EW}R;^`wK8jrp+e#wFaWeY`BkA@%}3Je!V88>O$h(DdnnN!FLL;#EiP zveqwW;!1Xu58p?X>JIEj(YUFdD;^@2{>teHCnl$ETAh}BD*fnD1}vG5|3)JIVB_XS zL7v1wo;E|T?r1m?$Xf{@H?vWlRbA!qiVL3M$Dd!^%nDy}{^GHZ$CjU~jbB9%&?0xU zTlu5~Mmi*$he%KxFXNfx0f-eFeEamol*?u9rtSx>m*3s!o<}>W$Jl<0nR{;%b%=CO zCO_$?T~r>yMaluV0;%9-9-w0v$gzI<0)`Oy>%Z+!?^z?&vP_|0B@ao~!#}YJ%{TGS z7sA`z~u@Yh*{Z!E%FIq`v-s8_(IRfM&y)6Ty|223e0S-t=|_ih(* zB^@pT;P204&WSMI!2_qD27DB9xz;uofQHmC%t(+JwYXBTo2H)ow+gh=wg+f|mo0}w zJ>iR67D#xQC*KgwY_ljKY++*YI#&cw6q>?bgmpNQu!5@B;ZACi+kfxt{DADbbn(Q$ zo^f(Sp%z)lXBSi;yR_Ib-Gre{kh111!qdxhw2EGS~_ ziSxPnp8VFu$cn|L*GmCpsTP@!Yb}Sj*65H&kKYvO%Zp&Go9`i2ezRNLOuIMl27Qkp z`(67yh2T6kq&}(6Ne;Eq0&Y)gOH{QJt479SZoS~%dVO*0xwj|Yu?)Jhff=Z=H8Kme};U?0(ms(vRHgydR^rbGW3WEk-f85;OTDC#!`F)hUYrV~d* zXeS}|kybna#473NDG{MjO`!ILT~-nEEbn>8-UIiX&e9?~F~gUhAr|Uj{lkzH7BYnm z&(uTx^w6y1uq!5zP#l+`g}AdI?sE7hz5Vg!pu6^dz-`EvVp&4)@z5{E@#Pgq*k+Hj zLxB0PHJQbJD?@wln}l%}WfeijRi1Bo=zbN-;QxoN5Mgs3LrXVdsuioed8@h{aeL?+ zGksBCNWmSV<#~#Al>$tj#If-dGF1qR1U4Q`giu(}pyoNbk0Gx&pD>l17BZub-@753 zdo$sI&)u$@vcorz_Mt=y)9n{cOLefG&a_vXK^z-$$}#``$kwT@%Xm3xBLtS|(RDmj zwr>9o)9&G)PhV7S9XzIE~Z1td|sdgB_M&udUS{aBc;P+a`ZVqe!U8F zEC>Hwk9w}c$MbNLipn1>{J+2~{+pWkR*$OTqj%E#v#;7s|KAs3>JWOUk+#o_$ z)GsLi65_#zWoxgUm4u>qyRLm!ymlq^g%DbP89bOjYR<;UNCH`9LMRXFN=FHWm?sis zv%>x5SHdrmBe%o7aGytu1}eD>ddd^5Snv9(5AU_?Cdfy3|MRY~)++yal&tJ&(}}15 zu7A4a)Us0E;kOZ&9~}p8nby3&aNvDLfhP}zCDmF8L2uIKTc!sF4NmL88Z+MQH_>%! ztD1Kg4$zHiURcaBbeCc$GNVerK*ud#JdEG{Dg^8i68^kLr}5xELdcjqh^uD2-UxNl z12TPtaVaWA0odzMJIhYAn-d=MQM6O|DHZ;#3f~Q&zo`gHkf^8U>eYljynEhQ)X`}K zI~4Ue+aO{>|H0T&N%z-FQQP>~8WHBD!uzQnn?H!VMZ&FBquReixV#CACRn-%zEp)M zP$4peh4-7f(JogU5_YN$EzQA1s^8^sq^ALa-L1^{epr6)+&qgxLT%*cqd%Zep zn!R}E01X$;-DMeHytS_=+x+TwhYKsULV*~H$NI2@qz4)a99Qu2On?}KA8<)|SQ3`I zlg`-}xGn$4-DT06KO2QIlEN!V#`Ij#lxlpS9M6nae8>ENq({~;;}j9 zk%eOygnx%G-=dNfXSSMt`Dd4Oum)}F;a{Q!il9Rn3ad%0{xXTMY2JEUenBI~5=pm; zh3RL;wTk%baU;E7vTrnu?`}=IL3WC&i>$SMQ>mp#nI&+!ayCZ{4k9h*=-)gE5Z=zg z-z=8EvAAo-aeH{WC`8H_P;@l;`p#B5+MYYZ%Rx|P>9YQRs=RTF+>0Bv8P5@Sm!8`8 zqvOrGiq_1W(fo$X1XvC!2tyvkwT-X^VpP9;Qod-j2EHdtA$HumyzQ66U`7l2)ZV;{ zjPfeSPA&w2lQi2m&UF!i<*0_cGia@wtoGbFbyKp`8$p%_1kvR{#DgrKQ`4 z&h{pkXqyeb0sRb{ymYa|j5!?Rsf1NcpHBmst1s(ZX9qk~Y7ib8j`z8nW#rz0F!Fv34jIM9iHFno zO`qMKwQkVpIal+K5t}Y1R2nW1QUI^}P0ov;zB6!3q3G8@B|d@1L0~IgMP(!-=BIKm zuNkmU|AA*nHQEXvL#S@egDtE@0lE9uY6Ypj9x}L)uV(1rRFw^(X1;oVOV#qyr;_P7(J`10(L6g*0W~VsM0-dDrvq|=`gs| zD$;A$K0!!6|FAEShrcuHZ>ASX_J3#>p}Y=^LK~HF_u6;mPA1-r+xBc_hp~5EC#Ni8 z#gsy7M6U(i?0FKwZLF=9Pd?3>pWkq?aF)`2e)4PM&+{)^Wc5*D^-|aptID%y)2)Kk zohFV+_+G-%x;*@sG37=vC1bNLE)D?^eqe2TEiJ(+Hmo0)+o^#xYGu&|%!0cdL|Y1Qxh!bJ zZFZJ-@oag-GB>HkPC1AhRhQeVG^Bd}2-_)kMSxaJtZWW9O4mY+`g8_#8N~SEFpOCl zk4TPuKaX08YqLb{7z2%$~&h3rH7iS$& zOoPS}+D%8FFV(k}d+`35dTQhQ1?Ec8Kphk!#1!mklvyMcuUiQ9Az@-zZ5u8gyY)#J zy@&VWP0CecYrCAEs92wVVmw`gO6oE1kB$Uo`7eJdHj0q6A@4`)YW~-C-ObM`KfO!2 z&@c1#$lHKq@cq72hsP`S#h&?WBxB0#_)4UeOda@ZT^v08HTEqqV60$j@Hr&Ntii|+ zK)GxbizkAO>0m-8tYngOz@1NrFbsJDS3M+Bc8JX2;e0Og9fw8!Yn0( zdUZdcQ|RC~GoB-6hS7&vV#J^r&N1Y~BUuvS6eQwmx-F~GAG_adz~X#mxN(DAcIdW- z6u;%!gHd@!kbM?@)l}F{zFbBdROH9$Kw?Ld%=RH0JGWCqnhcC`)sgWF?uVNU@yg~< zlqXF=33{y@T4?_@?rzpgpF^g-&e|MEDz9~aIU5m-nrN8+G{*`2-_G0XKM~iIKpju0 z#DwDwySv90!UDgEM)x};pBq@RWRhiiRb56_mJHh6x9y7rX4{At+_835e$-F#9eYQ% zbOfx~ErQaBTaJ!fpQbwBS#!>@^(FM3_o4T+mDh6j|8ooG%+;XSJ`={rMg3?Ny%oZw zgRpA#CTkUBStpiuTBSi0vm{U#oxj0+0Y}h5oIjg*OP^NKqC1Z2^MhFI9`I$7cVt_> zCJ%YmS%~<@EvGoR$|>o41+UzPl*L)dg<9rm_u8k^VHKkwB9srwh_Ksno0GM!ImWh- z4JC2%`i&N`<{!JyAQudONPQ=)2=>XqbJ<}=J!+Zr$$Df634)iYq35U?1lzv@l(nd&42q5c&Ka%`Ud~A4W{a+1H2?y431nC4N!+Kx%z( zMX*}{IsQ(#?L}?b+~eY#b3V^%aOaMvTF>xZGCM%Lt~c$9xfsDq*I-7oA;dpHNJoE- zm+!4w)bKArwV@qKqx!L2+(>#^Jr^McK*x8aWC-26ve{h-rO)|1qceBk))<-r4% z)mwD2@n5@L6Y}<-^n4rf>9{u9JwKyu+h`cv#Z80a=GYovAd2bbOViKSdn4qcSBBW=l6O1eZjh6Bbtu8o3byN5iQG}9agS0T0B}FdQ z!%S;9@Bkf1n%xY*js10(8I{n1kE9P-{u9iY6Ekys1*_lD22AgCLhC;Enoda?V_}ZT zUJXHP$Dj+1nHSu666afxZlxM?Ms3Dyu>I0AM=v&+0?8zh2tW)#O!5>!ngI*bFQO#} z*4787oi@3~4caHa;6ksOH{h1=`yyLeaR==lkuSa20`b>M#5&M#3Nsh9S-1;WdJ4dI z!qP|w&ZWa*N@QQApijpyrCg{E)%S-Q^dmXMtWs>%AhtvqdHMuvcJ0xY9LTJ%d9yh< zvp)Fs7sro919#VTJkkcQZ87=yHTWMd5BQWv)-mdXbxvb+L;S!gRRm9;fzV3;OqXJ2 zwgew|5JnO~DnYQPa=TaoQ;Db|@%v0@#ArFMvu@fL z>dD6;6#()JnyB?=41>WmSg;D}BZM;LlKDDlU=ZF9TdZnLNO4JQD6{_!&rL^U z0Z=pAA$x!Iu8&;oZ(fWGsn-9D$=|(>*SB0uw*w9G%EzaM8#w3o6x2kz+*)>Q_n>XW zDE-|1b+ANQSuAPJ7YQt@8oq=nqtTjY0*R0Tz)B|$lfyf*y7EdSIAG7F@VeMI1$h{l zHwxLlL+XwKA$)Nfs?3cm;gO-65Bbd#NtP)AR~5vIYl&w<*b3A<5^Ny}#$%R+F=de? zcpwTA!h-XdvRDPY{llPr3tTtZzKm7AQU$Ne25D-@$^P<)W@siG)@^&iA^ZZDD~kY* zd9WdLmt&j$By4U6kp2LSA7>h|VApICV8zp1*%bQE+KX=!gO(Rr89-iDt)R7`MIDuL z)b^ZC%l6(1FXtWglpqct)#MiDFO25N5!rGlR50_U5UNSA3(wA(7vl^-7j79?8MfeC0e78QHL|h> zvk1SgDENfzZh-VIC(iAffpH{*#j2Vv4Av&1=A`t-Mj0@|Gm!s!Le!0*v07UBac{yX z%#cY!(-*8|03aQ}$;D(kLEbihB%S>_S}+qt3;nxYL3{YgqiH=mhJxPoRl%KdxY3j`eoJ)ZS(CGFK*qLK4G;Ct?1N z{pMaH4`16_54o@d>QM;|T;A!8DvMOWwi>Q6+#+)Xf`gg^O%41?7R?b|6z~m#qVYZXosI8(ki|m7eu}72Ai!U6mya1t) zyt%uIh9Mb~yG>O9jfL~RD0+OV-dfq?9SnW@Mk;1KnWeyz^}9fm8(RRR<$ut)FrVOb z!%@Y^Cr_5lDqB%fp2UR5<-tN!(f0QqGAZyxp3{%B%aTf7#g>$92!x0DLjw$e4xZ!) z>`4PW!%-0v>Mz|`y25!T-H8-i?&iGtM(D0p-E;VOJBQ|I`&f+2!B1vWp~n?Z$Wt?3 z_qQ5Nool5!pM`N1c-L!5?F+}}Pu`Dfb^^cFTC1-54+%J(5}X3)?E*1CX1Uh_+YKjQ z>(7BC5lL?0F)DGa6oHi@NUvzmthK>WC=H`Y-CJb-!vI1k4x__NG8URmUB{0?s+jU{ zwv5*cTgZLD5$5vbx0AH1cqI|(iZVW_{B*O-epJlvCfkd^PZ5%cgh{983nLxX)|(nn z0@dBTOL)Z+!l^*Mvyt=v(HCq>-c2 z7!qurciBAsF8Lqib_G&6QR`TF+z3`~YTo!ELOfNhZeXk(Z zseoD*DTJq$z+ZfjW+d2k<-82^=WqBS-AHZlmf!3w5PyxvnQqlh42R+_iD=BJ3{6I! z%dP3(eWHZe$=Qo06@*1??u+#ONr&S@QfTn3?6SpL!}kHr0EkyQ!gA;(Qz*sx1IuKt zChYe*CSWLjm-3a(R1r*_IPd~uCKthv_`&@dc7~yIB{X0v%ccZE(%U%^paXD-kw54$ zTD`zxZ@4Zf4i1Zb1ciYzT^7vcpUiOokEdF?rn2)Ntj~AKys%r^6SlMb(@(f0{&LwIIAVmsTEWwmbbbS8YMTKe5#-JHcT%r#h6Cv1T$HsuB-LSz;( ztApA+t#{r9d0Y0WXsOJbWW=KF^cE#LSAuBP!C||)vD@!n=UG>~iM@nU%i->|&uTgj zDWIY`>~^}C`ZB}wV8%V0w_$6XO`bhv`4*g-`guj>d>EdMDxWhfcIh4WPlbn+h=dGF z3=gzX0K|0BztNAc5CDhrwOGTt?X}oSE=p-X@52HEIiQzbY#785g$D8_=$8i#qk%5k zpN{J1hNdr^?PWj#PuEBzSg<)?+x(d`{yM1mZks;~CjBh2PnT3(hs-JQa$_x-Bm79O z@Or;1H0;xz!2^wrdHs$l?vnqb=-%U*`u{k9?`C$xHq16+bHCs3QQO=lMhH=Jjgs6+ z)He6~C3n*1PAWtw)h2{g6p~bkF1k@Fx_tfi`)~j5JRawB&UwAx@8`Sgr3*9xxE&9b z0_=gUz3Pqj-YWhQ8?Lsiv8Kpl&PkZ{WHSzEr zGTUBz(%&WgOkK%%cl$A@qZj~VI3;PcU`cuSplrdZE}$H~4a9vrqx?3^{Cn|_jF9)H zwUR#Pnvxt+BAe1FsNsP3>XJ!lu+(#wRqLi*{{x44kU9gb z*;@SQ;>ZW_-Td9(|9!m=y6gzi;cP4QC+6J;X>La)EIuOZtV+$RD%eF=znn|GOkz?f zj3o*X0wGx^qL%@<{Wo|1s6;JR8J#Rq{Gcx!n5(&`xTn8$wLoH@@=mQoc1XoV%haE| z#p@1-T0)jqUp{^2^4cWwq47UVPv#^?EpX{mHRw2|?od-w*-)CDSgk?W_7;`cTB?5f zZvE{e&|EJi*D~LWmbr7`O^5P-mpXuL5#qXxN1T~&O)g3_kDX!qkP06tB&Arypn@hU z^^QfGdUf(x86qlP!Rif+?{9}N5)#@SBpUe9C6fwczuy$dbS*VuUlG7?Z}xX0b>iX+ zL3CPS8oWy^Qxk7@Z}sZBIWy*}?2}%XTG9)DoCTS?B4^sk1R=y^l{M|@jK4!^ZHte;nr^hyrl-gLH1X zE~C;vWA7&bc~8s~YZ`mBb2**p)mogHqw#h+Jy+W;l$KKGJk2>R*B7N%T|8f zqabFvwWv^Nu{8O_fgVy61tA1Db8QroB!&*SH_dnD%BCcf?;lNCigHkE-j;u$vwPR@ zUbFfT!!5hHI!As&?NVLzcuN(!K2vrlthl{BkX|MyAt@;Q$Z2Z2jmqb4FWa?6=<+B~ z@$gQ*uo9!$4%#*z&pQE2e7g`@Z}!J09x(|$a{c+kQD^J#=z3|z@{PB!(^bAS8TEJF zAY@2Up1!?i$9wWHDKVB*6DO2)n3*h|$OH+Y=tl$-%_v44AD$NpM(;0*1SBiyQmDeH z8D^%Kgy9scEploqbx#3>#V41l;vH2B0U&!Bp|{I6dAc*L+)3TY)?sXnB28FY!S=n) z1I_kUC{{=G6n9!OAQXr)TOaFz?DL^hi{LQtUWyGih;EA2Gt0EuJ-Ro{wJh*bl z6rUo{^Q8wNpb6z}>xJ>Xcay)17>rJ_$JMIYNeH!;Xq7A}zE3X^5^ z0HJV^%#L;bFdDxwkx}3%*TaYGEki5+n1_AW-~tVruoB>AZON^}>gh zBZ43lYJf@?_T*he4-ZQ?y33J&Gg+2pNrGajNylBw&G5v6jk~Su*LVscFE(qNJ6)u zT*O|1ttZ_tdgr%;ZZJHO3ApzR0HaT(DNd0s`*#;8p z;u@5Z7PF`vx9h}1nTBW`EFe$(OrT9itnl@!O;MHSC**ts*$`j<%b&?2gBKf zhoPf73qd(CogN1T^XG&GN}4e~Ldu8YNY>`I(b87vflH}!!`4~$?L!hZW6-93!Z)3_ z1H^9vgj5+(xh`AsxZPo00anQsNg56$6zPweBroR%Z?mtrt3t#Aic+6+gjm3Mhe6E4 z08%7bAkOo^%76}$P#(|>jV3>dWQXBm8Iudmx0^j~Pf3t!r=law9=F|zrLj})5T2>t zJbBffB#i5X74*lt!bkuz_?P(-P?*kyLP|l%P|E)6%{+X_g?)^ zK#B7kyF%|(%lcxNsm|$xAo((ouwkA*Ccn!{2{B!6+keoNaZ^z?^fD z9&HLisFo*UMuJGxGNyi^oo;*z)`{sd(mHJSYZl(A9e*9E9rbVYVx#WisFgNtx2y+s zsbkcnz}xGap(+6q0I}W>q{sI~#@&d>dm;jl8@@#nvGii?xuXkJkO)98%cd%9F*B&O z05GBzli|M}p*d(6q9&r35kHl-M;nMd$+#y&?+GyKpMOd9SP=@^9wx|HEV~D)&+QT) zz0s{3&O529FP9e{q*yb2AlcsCYa~cm|1%ZczHOxvLVc(C#~OEj3R3-ZD#P5FE0T*I za*dzPTB}639tT{gjOUK~4Lz5-xIG$J#f2ZLtnbc0V58$~CUUyy=bk1TLxXPr_fMOR z@wZ7fa)3>tPyU78k0OB2ACnr*J2~*{!TE*SQ=RU|h4)48H-33I1@LX=-)L`@rVkaIv7tugtYN*u_bawv#J zbEl*mGHIIm>AI2SCc0L$!Ks>wOYb38r1wC)Fa0FLwFr_eu|+L_jd!T>5A6{M^cYAe z1?j~Ehl?2vNVWgtEDHIzcM-e0o&gs9V#&*ZPkw#dFC!pzr}Jog^M{tlT`b1MJ4M)U zmVrs$(x8E7y#9*rprdb3WhBxM0x7ewEUIrQUkm^YQaymttlWhjq>|AzF^f#;B^K1X zMo9D67ydkn`0%TU2)5Q9t4hV;Ut<-4s91iEP{4Py*Wbx}p_#F*=cFQw=};LNh^FtX zg(MZ0M!~01l>ooa92@BhC@K~Vl*xFduqx*m%Z(G9y>#1tj(e(lwx% z;i&c!U!Kl>;Z-8DWK*99SB?~_n;xDTr`2ZTR3S8-a0O)sNpB0JUCK7J7*QsqnpofC zYNd{`XgUWeU_hZrL;z0U(s?k2=zOw3TeK*{`4@{i7mM2n)`vXC-Vvt3$;piiVzT~c zpZfs~x#Dka$zHVhAETdQD-=F0Bsh@#GZ|H{|{=cwlMpoGQR1R_;QwTv7TZjfh!AQq|#JSH}&i zQlhVtKoT5em4<3fhbckl6DREkiSU=SwACmoCYAB5FM&g1_FDm~@g;@e%fVlo6MBlq!);tCa^@ zGkvbEIC#nU$`1YF%a@F=Xbw>odZ-EJc;3G^{E*1cW0sgXyauCU3SFZi%JqhHqla1kwF&4 z$F&)wxauJir{Y7EqLn&QtbFwLqTZ95NEiOHt3%BetmjF-N{IGQt{&xr`MSiZ+@^=hKy=yRiQao-~0Ub zIs)}Bc3t#*7@AiH@!Dhs^7v|t@3mm;x1ns!pnFbPCDjtm^iO>G9-xe=EwElhW{i5_ zC*R|f%tFwJw&~DgwQ{}AS{>3wwMZf5WLiZXEo^};ATrn8*~d;H);ESUHirCfvv=)! zcoDV$xistAFUlQ79TpMw?ZF~ci5aS~3dgvG1LB_5U%mmLyH=so5UM@E zWNY4(4%A>DllPq+4x4>5sw&TXtvLDqc_Sovy-BMbRQSYN`*(fyCv12>HvW5arHy-W;6x&)xM<#B@}J> z;sJFAdu4>Cy*d=s`+yV<(sBo)eJP;97HT%xu|WK~z#!x>Te^5y)3k(eirAQx1f2?N zT?NfB#UzGU)f7OAeFowI|xJ;&@kj*; zc0_1Jd|XQ;?7qs_!{DkLf9+# zbX?=G-+XXIo`xfHoDekfpONz$=Fo0UT(i2hjqM)~1&;H&uV%FtNMX@YRdYz&eMnnI zU*{7@i8SQ&*icRp_`J(N@xfFCqJ>zpqI6PDxvygp6B)gyF|O+C4sA%m6r`Z5-rxH5 zilw@`faQRl`VX4gP)3XW3zA)Bq7)l>t>imS4|W&*ptTg;uS}r?z!uX^ypu1I%!Ie{ zgeoXt62eJANyK zjC<{sl%h(~Yt|C4cl^}jo@$(Y*nHvJC)-;?pL&s6G ze{?DNC;w$a)F{w2t4TP%fbnbWBPRt5Anwr#|dZLgrC zP&y#@CMWt0;+ty2ZpXj?J_Bcj-7NCEBpe;mDTd~ywAQ;#l&?MVb8XV5&gpWO|Z%)Mu& zydXVRXM0@s5`l}vqR1aPkwF*2gU|k1%An*Qzft)5y3OkLD*H7NutOM_ChD^MR)BJf zk7R3&tC^s|xl4b5k7Vb8QaUub!CQWw){a3yd}SIgdEDm0IM3Y1Zv4F5__LUa{SkWhxyUvb4D zZU(do^pI*{bVShc_^L4FL6>FB{lE4nQiQF9+Cf9aR6#cp8XM{2@(Q@Dj}~mL=;T2{ z0q|ia;YE><1)z0b*^6&+ojRACf1viHQPDg=j^a;3)%Nwhx4Jdrdt*#{j{V8*Va{~) z-}sZV_d4kw;WsyvCps2$V||<8HyiSrAF}_;@slUZ1dRb>w+0o`G4t}uoY{$oY2@H8 zy8Vc@s=!;K;_UeZlsB*8^$s^*Zj8m;0?HZ+-kPx9Mvv5zXC5kDvo~Sa90Jws{!vW) zyQ@eV(${WSh#V{#dH?2ts-WZ2vgYr_`>M#;VKJ{GlOHR&V(03AZD?H*w|M_|2TQB} znH>MhX8@3S_2Pr(+~b;wNxF)u>d7Eg{5{G?Dzl+F8V*03O{Sm)Z=@4A9fZ8%_yu8j z2?9=1rT~D{5rpK?pqc*Sz|jmpO1x_W^nr}A$_M)MV#Vz0y(hn{Mh#@VwJ$yqde!x* z&GCmur1M{_K?*}Q4R*zz%+AsPn-&)hEQ#)azcAvz|AP12fA^?%@39#6?F(6&&-Nx` zHQr1S{aVa_!+i4eG3ufqkkL+9OZ1C>HuIF^y`&+V*uI+hz0ysKS~3CZ7G z9goKS_;4L5Ms{k^Ed!;f7b#fe!?fCGvM>scWw?=o&ngD>Hpu}mzP!2rSlhZ3y{CTo z9o?rl=&8Kj(ZNJ{t4xm7rJh!loZ30!OQz3~S^@;i&8RRxXK|}z0|1n7Ja=1xRz#$- z1^TMe?~3;^6Nc*IZBDKF4(XDff~d5@H+DL>iosB`k)#^K(^w!?MFB0_SU=T<5=Ji# zfpzT}0GMtPt1X)zlrvo5l?=?5x=8^w7KaWGAxq!G8nVkuc=F9gxZi3j7b7OJTk6g^ zu8b9FGD$#enWMU6lWIFw9b{app0cph};_602p{+XkVeu0p|DL6-TW&ta z67SvkbTZ(clfnM&`6e;zaI3fya~0}r|LTmp_?6Yl13?v5%2fp=Ht{JV<$h<*t_ru+ zBOZGN=nd;yf#&%L%O3#ND#rd*!`#A-DSxi`z=m{ssVg1+>jIFPosNU#dyh)_Kz6Lr z-o~yRCQ_>heJ_VZ1Ka~@u2y)pboic-Z`M8$)lf*oIy4t|j=fPdem~|4m%YFYo4gi@ z)qkUKVX;l9F5Xc-m#dz|P|IpH%o#4LNorqf8AXy|vV$`x@~wAAeZk1wuaO^Ct{44L zhnhWO)ayT3Rh1OkyP>M7>txJd6`{U*pWf*RDhrfSew5Ym-lmB$)OCNcx}oO#Nc>2w`meBtK()#xKpiN%~Rwz-PgR1|%d;Vkf+_fSaNv*MXd$r;5zQ0>< z#CSk&Ryr?6(8x^iaX-^ZIF!WE^`7;pfLVO&9M&IH7gFvY#$oD;M~Soj#iCiyVSy`} zrDH?)Yme7w2XYqsKBy3=Nf3|m^Q^-rVz!8`jA&DR68AXTo;af zG$~=&+u3%|=FkD+Oti5n`f3=9mqz%x0rg<6hzz13%0D@oB12TkmTq_w#6;xfus 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

H^o`-pKE$-|f(-VpTjRrmh8^KIcL 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

1gFNAJb}3JD8$7VkwK6TZ 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

vi0S`N_2#Ztkgogwoc91wXGHypN8#Bd@sT}pI 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

diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 3bf33baa..de13a746 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -10,6 +10,18 @@ "config": { "cameras": { "camera_entity": "Camera Entity", + "cast": { + "dashboard": { + "dashboard_path": "Dashboard path", + "view_path": "View path" + }, + "editor_label": "Cast Options", + "method": "Cast method", + "methods": { + "standard": "Standard", + "dashboard": "Dashboard" + } + }, "dependencies": { "all_cameras": "Show events for all cameras with this camera", "cameras": "Show events for specific cameras with this camera", @@ -522,4 +534,4 @@ }, "select_date": "Choose date" } -} \ No newline at end of file +} diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 3d66105a..cbefd91d 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -10,6 +10,18 @@ "config": { "cameras": { "camera_entity": "Entità della telecamera", + "cast": { + "dashboard": { + "dashboard_path": "", + "view_path": "" + }, + "editor_label": "", + "method": "", + "methods": { + "standard": "", + "dashboard": "" + } + }, "dependencies": { "all_cameras": "Mostra eventi per tutte le telecamere con questa telecamera", "cameras": "Mostra eventi per telecamere specifiche con questa telecamera", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 394ce8a4..aa8ecc21 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -10,6 +10,18 @@ "config": { "cameras": { "camera_entity": "Entidade da Câmera", + "cast": { + "dashboard": { + "dashboard_path": "", + "view_path": "" + }, + "editor_label": "", + "method": "", + "methods": { + "standard": "", + "dashboard": "" + } + }, "dependencies": { "all_cameras": "Mostrar eventos para todas as câmeras nesta câmera", "cameras": "Mostrar eventos para câmeras específicas nesta câmera", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 438bfb40..df256cee 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -10,6 +10,18 @@ "config": { "cameras": { "camera_entity": "Entidade da Câmera", + "cast": { + "dashboard": { + "dashboard_path": "", + "view_path": "" + }, + "editor_label": "", + "method": "", + "methods": { + "standard": "", + "dashboard": "" + } + }, "dependencies": { "all_cameras": "Mostrar eventos para todas as câmeras nesta câmera", "cameras": "Mostrar eventos para câmeras específicas nesta câmera", From e12912fa85a082c45f131829e812e6120844e1bc Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 29 Oct 2023 14:10:41 -0700 Subject: [PATCH 066/189] Add out-of-the-box Frigate PTZ support. --- README.md | 176 ++++--- src/action-handler-directive.ts | 9 +- .../browse-media/engine-browse-media.ts | 34 +- src/camera-manager/camera.ts | 44 ++ src/camera-manager/engine.ts | 46 +- src/camera-manager/error.ts | 1 + src/camera-manager/frigate/engine-frigate.ts | 205 +++++--- src/camera-manager/frigate/requests.ts | 19 + src/camera-manager/frigate/types.ts | 7 + src/camera-manager/generic/engine-generic.ts | 70 +-- src/camera-manager/manager.ts | 131 ++--- .../motioneye/engine-motioneye.ts | 32 +- src/camera-manager/store.ts | 120 +++-- src/camera-manager/types.ts | 22 +- src/card-controller/actions-manager.ts | 16 + src/card-controller/initialization-manager.ts | 17 +- src/card-controller/media-player-manager.ts | 6 +- src/card-controller/microphone-manager.ts | 8 +- src/card-controller/query-string-manager.ts | 7 +- src/card-controller/triggers-manager.ts | 10 +- src/card-controller/view-manager.ts | 7 +- src/card.ts | 12 + src/components-lib/menu-controller.ts | 177 +++---- src/components-lib/ptz-controller.ts | 170 +++++++ src/components/carousel.ts | 9 +- src/components/elements.ts | 136 +----- src/components/live/live.ts | 86 ++-- src/components/media-filter.ts | 16 +- src/components/menu.ts | 2 +- src/components/ptz.ts | 131 +++++ src/components/surround.ts | 4 +- src/components/thumbnail-carousel.ts | 2 + src/components/views.ts | 77 +-- src/config-mgmt.ts | 70 ++- src/config/types.ts | 176 ++++--- src/const.ts | 20 +- src/editor.ts | 89 ++++ src/localize/languages/en.json | 27 +- src/localize/languages/it.json | 29 +- src/localize/languages/pt-BR.json | 27 +- src/localize/languages/pt-PT.json | 27 +- src/localize/localize.ts | 3 +- src/patches/ha-hls-player.ts | 5 +- src/scss/live-image.scss | 3 +- src/scss/{elements-ptz.scss => ptz.scss} | 17 +- src/utils/action.ts | 133 ++--- src/utils/camera.ts | 46 -- src/utils/initializer/initializer.ts | 9 +- src/utils/media-to-view.ts | 5 +- src/utils/ptz.ts | 14 + src/view/view.ts | 3 +- tests/camera-manager/camera.test.ts | 57 +++ .../frigate/engine-frigate.test.ts | 99 ++++ tests/camera-manager/frigate/requests.test.ts | 218 +++++++++ .../generic/engine-generic.test.ts | 92 ++-- tests/camera-manager/store.test.ts | 185 +++++-- tests/card-controller/actions-manager.test.ts | 57 ++- tests/card-controller/hass-manager.test.ts | 43 +- .../initialization-manager.test.ts | 44 +- .../media-player-manager.test.ts | 169 ++++--- .../microphone-manager.test.ts | 2 +- .../card-controller/triggers-manager.test.ts | 33 +- tests/card-controller/view-manager.test.ts | 454 ++++++++++++------ tests/components-lib/menu-controller.test.ts | 305 ++++++++---- tests/components-lib/ptz-controller.test.ts | 316 ++++++++++++ tests/config-mgmt.test.ts | 429 +++++++++++++++++ tests/config/types.test.ts | 20 +- tests/test-utils.ts | 112 +++-- tests/utils/action.test.ts | 103 ++-- tests/utils/camera.test.ts | 58 +-- tests/utils/diagnostics.test.ts | 1 - tests/utils/download.test.ts | 10 +- tests/utils/media-to-view.test.ts | 140 ++++-- tests/utils/ptz.test.ts | 36 ++ 74 files changed, 3981 insertions(+), 1514 deletions(-) create mode 100644 src/camera-manager/camera.ts create mode 100644 src/components-lib/ptz-controller.ts create mode 100644 src/components/ptz.ts rename src/scss/{elements-ptz.scss => ptz.scss} (91%) create mode 100644 src/utils/ptz.ts create mode 100644 tests/camera-manager/camera.test.ts create mode 100644 tests/camera-manager/frigate/requests.test.ts create mode 100644 tests/components-lib/ptz-controller.test.ts create mode 100644 tests/utils/ptz.test.ts diff --git a/README.md b/README.md index 21f905d4..ec370777 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ That's it! ### Manual Resource Management -For most users, HACS should automatically add the necessary resources. Should this auto-registration does not work, you will need to complete one additional step. +For most users, HACS should automatically add the necessary resources. Should this auto-registration not work you will need to complete one additional step. #### Lovelace in "Storage mode" (default) @@ -167,11 +167,11 @@ See the [fully expanded cameras configuration example](#config-expanded-cameras) ##### Engine Capabilities -|Engine|Live|Supports clips|Supports Snapshots|Supports Recordings|Supports Timeline|Favorite events|Favorite recordings| -| - | - | - | - | - | - | - | - | -|`frigate`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | -|`generic`| :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | -|`motioneye`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | +|Engine|Live|Supports clips|Supports Snapshots|Supports Recordings|Supports Timeline|Supports PTZ out of the box|Supports manually configured PTZ|Favorite events|Favorite recordings| +| - | - | - | - | - | - | - | - | - | - | +|`frigate`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | +|`generic`| :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | +|`motioneye`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | ##### Live providers supported per Engine @@ -485,6 +485,7 @@ menu: | `timeline` | :white_check_mark: | The `timeline` menu button: show the event timeline. | | `media_player` | :white_check_mark: | The `media_player` menu button: sends the visible media to a remote media player. Supports Frigate clips, snapshots and live camera (only for cameras that specify a `camera_entity` and only using the default HA stream (equivalent to the `ha` live provider). `jsmpeg` or `webrtc-card` are not supported, although live can still be played as long as `camera_entity` is specified. In the player list, a `tap` will send the media to the player, a `hold` will stop the media on the player. | | `microphone` | :white_check_mark: | The `microphone` button allows usage of 2-way audio in certain configurations. See [Using 2-way audio](#using-2-way-audio). | +| `show_ptz` | :white_check_mark: | The `show_ptz` button shows or hide the PTZ controls. | ##### Configuration on each button @@ -628,6 +629,30 @@ live: See [Using 2-way audio](#using-2-way-audio) for more information about the very particular requirements that must be followed for 2-way audio to work. + + +#### Live: PTZ + +Controls a PTZ (Pan Tilt Zoom) controller overlay. All configuration is under: + +```yaml +live: + ptz: +``` + +| Option | Default | Overridable | Description | +| - | - | - | - | +| `mode` | `on` | :white_check_mark: | When `on` will show a PTZ control if so configured (manually, or by the camera engine), if `off` will not show any control. | +| `position` | `bottom-right` | :white_check_mark: | Whether to position the control on the `top-left`, `top-right`, `bottom-left` or `bottom-right`. This may be overridden by using the `style` parameter to precisely control placement. | +| `actions_left`, `actions_right`, `actions_up`, `actions_down`, `actions_zoom_in`, `actions_zoom_out`, `actions_home` | Default is set by camera engine of the selected camera | :white_check_mark: | The [Home Assistant actions](https://www.home-assistant.io/dashboards/actions/) to call when this icon is interacted with. | +| `orientation` | `horizontal` | :white_check_mark: | Whether to show a `vertical` or `horizontal` PTZ control. | +| `hide_pan_tilt` | `false` | :white_check_mark: | When `true` the Pan & Tilt buttons of the control is hidden | +| `hide_zoom` | `false` | :white_check_mark: | When `true` the Zoom button of the control is hidden | +| `hide_home` | `false` | :white_check_mark: | When `true` the Home button of the control is hidden | +| `data_left`, `data_right`, `data_up`, `data_down`, `data_zoom_in`, `data_zoom_out`, `data_home` | | :white_check_mark: | Shorthand for a `tap_action` that calls the `service` with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[button]`. If both `actions_X` and `data_X` are specified, `actions_X` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). | +| `service` | | :white_check_mark: | An optional Home Assistant service to call when the `data_` parameters are used. | +| `style` | | :white_check_mark: | Optionally position and style the element using CSS. Similar to [Picture Element styling](https://www.home-assistant.io/dashboards/picture-elements/#how-to-use-the-style-object), except without any default, e.g. `left: 42%` | + #### Live: Display @@ -1315,8 +1340,6 @@ elements to add special Frigate card functionality. | `custom:frigate-card-menu-submenu` | Add a configurable submenu dropdown. See [configuration below](#frigate-card-menu-submenu).| | `custom:frigate-card-menu-submenu-select` | Add a submenu based on a `select` or `input_select`. See [configuration below](#frigate-card-submenu-select).| | `custom:frigate-card-conditional` | Restrict a set of elements to only render when the card is showing particular a particular [view](#views). See [configuration below](#frigate-card-conditional).| -| `custom:frigate-card-ptz` | Add a PTZ (Pan Tilt Zoom) controller overlay. See [configuration below](#frigate-card-ptz).| - **Note**: ℹ️ Manual positioning of custom menu icons or submenus via the `style` parameter is not supported as the menu buttons displayed are context sensitive @@ -1377,19 +1400,6 @@ Parameters for the `custom:frigate-card-conditional` element: `elements` | The elements to render. Can be any supported element, include additional condition or custom elements. | | `conditions` | A set of conditions that must evaluate to true in order for the elements to be rendered. See [Frigate Card Conditions](#frigate-card-conditions). | -#### `custom:frigate-card-ptz` - -Parameters for the `custom:frigate-card-ptz` element: - -| Parameter | Default | Description | -| ------------- | - | -------------------------------------------- | -| `type` | | Must be `custom:frigate-card-ptz`. | -| `style` | `translate(-50%, -50%)` | Position and style the element using CSS. See [Picture Element styling](https://www.home-assistant.io/dashboards/picture-elements/#how-to-use-the-style-object). | -| `orientation` | `vertical` | Whether to show a `vertical` or `horizontal` PTZ control. | -| `actions_left`, `actions_right`, `actions_up`, `actions_down`, `actions_zoom_in`, `actions_zoom_out`, `actions_home` | The [Home Assistant actions](https://www.home-assistant.io/dashboards/actions/) to call when this icon is interacted with. | -| `data_left`, `data_right`, `data_up`, `data_down`, `data_zoom_in`, `data_zoom_out`, `data_home` | Shorthand for a `tap_action` that calls the `service` with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[button]`. If both `actions_X` and `data_X` are specified, `actions_X` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). | -| `service` | | An optional Home Assistant service to call when the `data_` parameters are used. | - ### Special Actions @@ -1399,7 +1409,7 @@ Parameters for the `custom:frigate-card-ptz` element: | Parameter | Description | | - | - | | `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Call a Frigate Card action. Acceptable values are `default`, `clip`, `clips`, `image`, `live`, `recording`, `recordings`, `snapshot`, `snapshots`, `download`, `timeline`, `camera_ui`, `fullscreen`, `camera_select`, `menu_toggle`, `media_player`, `live_substream_on`, `live_substream_off`, `live_substream_select`, `expand`, `microphone_mute`, `microphone_unmute`, `mute`, `unmute`, `play`, `pause`, `screenshot`| +| `frigate_card_action` | Call a Frigate Card action. Acceptable values are `default`, `clip`, `clips`, `image`, `live`, `recording`, `recordings`, `snapshot`, `snapshots`, `download`, `timeline`, `camera_ui`, `fullscreen`, `camera_select`, `menu_toggle`, `media_player`, `live_substream_on`, `live_substream_off`, `live_substream_select`, `expand`, `microphone_mute`, `microphone_unmute`, `mute`, `unmute`, `play`, `pause`, `screenshot`, `show_ptz`, `ptz`| @@ -1421,6 +1431,8 @@ Parameters for the `custom:frigate-card-ptz` element: |`mute`, `unmute`| Mute or unmute the loaded media. | |`play`, `pause`| Play or pause the loaded media. | |`screenshot`| Take a screenshot of the loaded media (e.g. a still from a video). | +|`show_ptz`| Show or hide the PTZ controls. Takes a `show_ptz` boolean parameter to indicate whether the controls show be shown or not. | +|`ptz`| Execute a native PTZ action (only for native out-of-the-box PTZ camera engines, e.g. Frigate). Takes a required `ptz_action` parameter that is one of `left`, `right`, `up`, `down`, `zoom_in`, `zoom_out` or `preset`. Takes an optional `ptz_phase` parameter that is one of `start` or `stop` to start or stop the movement discretely. Takes an optional `ptz_preset` parameter as the preset to execute when the `ptz_action` parameter is `preset`. | @@ -1438,6 +1450,7 @@ This card supports several different views: |`recordings`|Shows a gallery of recent (last day) recordings for this camera and its dependents.| |`recording`|Shows a viewer for the most recent recording for this camera. Can also be accessed by holding down the `recordings` menu icon.| |`image`|Shows a static image specified by the `image` parameter, can be used as a discrete default view or a screensaver (via `view.timeout_seconds`).| +|`timeline`|Shows an event timeline.| ### Navigating From A Snapshot To A Clip @@ -2012,6 +2025,11 @@ menu: enabled: false alignment: matching icon: mdi:play + show_ptz: + priority: 50 + enabled: false + alignment: matching + icon: mdi:pan button_size: 40 ``` @@ -2066,6 +2084,29 @@ live: microphone: always_connected: false disconnect_seconds: 60 + ptz: + mode: on + position: bottom-right + orientation: horizontal + hide_pan_tilt: false + hide_zoom: false + hide_home: false + style: + # Optionally override the default style. + right: 5% + # Manually specifying actions. + actions_left: + tap_action: + action: call-service + service: sonoff.send_command + service_data: + device: '048123' + cmd: left + # Equivalent short form PTZ actions (only right button shown) + service: sonoff.send_command + data_right: + device: '048123' + cmd: right display: mode: single grid_selected_width_factor: 2 @@ -2432,31 +2473,6 @@ elements: state: on state_not: off media_loaded: true - # Full form PTZ actions (only left button shown). - - type: custom:frigate-card-ptz - orientation: vertical - style: - transform: none - right: 5% - top: 50% - actions_left: - tap_action: - action: call-service - service: sonoff.send_command - service_data: - device: '048123' - cmd: left - # Equivalent short form PTZ actions (only left button shown) - - type: custom:frigate-card-ptz - orientation: vertical - style: - transform: none - right: 20px - top: 180px - service: sonoff.send_command - data_left: - device: '048123' - cmd: left ``` @@ -2562,6 +2578,21 @@ elements: tap_action: action: custom:frigate-card-action frigate_card_action: screenshot + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-p-circle + title: Show PTZ + tap_action: + action: custom:frigate-card-action + frigate_card_action: show_ptz + show_ptz: true + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-q-circle + title: Native PTZ Preset + tap_action: + action: custom:frigate-card-action + frigate_card_action: ptz + ptz_action: preset + ptz_preset: 'doorway ``` @@ -3416,44 +3447,33 @@ elements: ``` -### Using a PTZ picture element +### Using a PTZ control -The card supports a custom PTZ element (`custom:frigate-card-ptz`) to conveniently control pan, tilt and zoom for cameras. +The card supports using PTZ controls to conveniently control pan, tilt and zoom for cameras.
- Expand: Using the native PTZ picture element + Expand: Using the PTZ controls -This example shows the native PTZ element when the `live` or `image` view is displayed and the stream (media) has loaded. +This example shows the PTZ controls of the `live` view. Note that if your camera engine supports it (e.g. `frigate`) this will just work out of the box with no configuration at all. ```yaml [...] -elements: - - type: custom:frigate-card-conditional - conditions: - media_loaded: true - view: - - live - - image - elements: - - type: custom:frigate-card-ptz - orientation: horizontal - style: - transform: none - right: 20px - top: 180px - service: sonoff.send_command - data_left: - device: '048123' - cmd: left - data_right: - device: '048123' - cmd: right - data_up: - device: '048123' - cmd: up - data_down: - device: '048123' - cmd: down +live: + ptz: + orientation: horizontal + service: sonoff.send_command + data_left: + device: '048123' + cmd: left + data_right: + device: '048123' + cmd: right + data_up: + device: '048123' + cmd: up + data_down: + device: '048123' + cmd: down ```
diff --git a/src/action-handler-directive.ts b/src/action-handler-directive.ts index 73fe78ab..c61f028e 100644 --- a/src/action-handler-directive.ts +++ b/src/action-handler-directive.ts @@ -32,6 +32,7 @@ class ActionHandler extends HTMLElement implements ActionHandler { protected doubleClickTimer = new Timer(); protected held = false; + protected started = false; public connectedCallback(): void { [ @@ -83,7 +84,12 @@ class ActionHandler extends HTMLElement implements ActionHandler { this.held = true; }); - fireEvent(element, 'action', { action: 'start_tap' }); + // Without this check we get double start_tap events from touchstart and + // mousedown events (on Android). + if (!this.started) { + this.started = true; + fireEvent(element, 'action', { action: 'start_tap' }); + } }; const end = (ev: Event): void => { @@ -105,6 +111,7 @@ class ActionHandler extends HTMLElement implements ActionHandler { this.holdTimer.stop(); + this.started = false; fireEvent(element, 'action', { action: 'end_tap' }); if (options?.hasHold && this.held) { diff --git a/src/camera-manager/browse-media/engine-browse-media.ts b/src/camera-manager/browse-media/engine-browse-media.ts index f6eea202..22c41b9b 100644 --- a/src/camera-manager/browse-media/engine-browse-media.ts +++ b/src/camera-manager/browse-media/engine-browse-media.ts @@ -15,14 +15,14 @@ import { Entity } from '../../utils/ha/entity-registry/types'; import { ResolvedMediaCache, resolveMedia } from '../../utils/ha/resolved-media'; import { ViewMedia } from '../../view/media'; import { RequestCache } from '../cache'; +import { Camera } from '../camera'; import { CameraManagerEngine } from '../engine'; import { CameraInitializationError } from '../error'; import { GenericCameraManagerEngine } from '../generic/engine-generic'; import { rangesOverlap } from '../range'; +import { CameraManagerReadOnlyConfigStore } from '../store'; import { - CameraConfigs, CameraEndpoint, - CameraManagerCameraCapabilities, CameraManagerMediaCapabilities, DataQuery, EventQuery, @@ -141,7 +141,7 @@ export class BrowseMediaCameraManagerEngine hass: HomeAssistant, entityRegistryManager: EntityRegistryManager, cameraConfig: CameraConfig, - ): Promise { + ): Promise { const entity = cameraConfig.camera_entity ? await entityRegistryManager.getEntity(hass, cameraConfig.camera_entity) : null; @@ -152,11 +152,20 @@ export class BrowseMediaCameraManagerEngine ); } this._cameraEntities.set(cameraConfig.camera_entity, entity); - return cameraConfig; + + return new Camera(cameraConfig, this, { + canFavoriteEvents: false, + canFavoriteRecordings: false, + canSeek: false, + supportsClips: true, + supportsRecordings: false, + supportsSnapshots: true, + supportsTimeline: true, + }); } public generateDefaultEventQuery( - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, cameraIDs: Set, query: PartialEventQuery, ): EventQuery[] | null { @@ -191,21 +200,6 @@ export class BrowseMediaCameraManagerEngine return null; } - public getCameraCapabilities( - cameraConfig: CameraConfig, - ): CameraManagerCameraCapabilities | null { - const parentCapabilities = super.getCameraCapabilities(cameraConfig); - if (!parentCapabilities) { - return null; - } - return { - ...parentCapabilities, - supportsClips: true, - supportsSnapshots: true, - supportsTimeline: true, - }; - } - // eslint-disable-next-line @typescript-eslint/no-unused-vars public getMediaCapabilities(_media: ViewMedia): CameraManagerMediaCapabilities { return { diff --git a/src/camera-manager/camera.ts b/src/camera-manager/camera.ts new file mode 100644 index 00000000..dd6990ee --- /dev/null +++ b/src/camera-manager/camera.ts @@ -0,0 +1,44 @@ +import { CameraConfig } from '../config/types'; +import { localize } from '../localize/localize'; +import { CameraManagerEngine } from './engine'; +import { CameraNoIDError } from './error'; +import { CameraManagerCameraCapabilities } from './types'; + +export class Camera { + protected _config: CameraConfig; + protected _engine: CameraManagerEngine; + protected _capabilities: CameraManagerCameraCapabilities; + + constructor( + config: CameraConfig, + engine: CameraManagerEngine, + capabilities: CameraManagerCameraCapabilities, + ) { + this._config = config; + this._engine = engine; + this._capabilities = capabilities; + } + + public getConfig(): CameraConfig { + return this._config; + } + + public setID(cameraID: string): void { + this._config.id = cameraID; + } + + public getID(): string { + if (this._config.id) { + return this._config.id; + } + throw new CameraNoIDError(localize('error.no_camera_id')); + } + + public getEngine(): CameraManagerEngine { + return this._engine; + } + + public getCapabilities(): CameraManagerCameraCapabilities { + return this._capabilities; + } +} diff --git a/src/camera-manager/engine.ts b/src/camera-manager/engine.ts index c2d8710c..8f013cbc 100644 --- a/src/camera-manager/engine.ts +++ b/src/camera-manager/engine.ts @@ -1,14 +1,18 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { CameraConfig } from '../config/types'; +import { + CameraConfig, + PTZAction, + PTZPhase, +} from '../config/types'; import { ExtendedHomeAssistant } from '../types'; import { EntityRegistryManager } from '../utils/ha/entity-registry'; import { ViewMedia } from '../view/media'; +import { Camera } from './camera'; +import { CameraManagerReadOnlyConfigStore } from './store'; import { - CameraConfigs, CameraEndpoint, CameraEndpoints, CameraEndpointsContext, - CameraManagerCameraCapabilities, CameraManagerCameraMetadata, CameraManagerMediaCapabilities, DataQuery, @@ -37,57 +41,57 @@ export interface CameraManagerEngine { hass: HomeAssistant, entityRegistryManager: EntityRegistryManager, cameraConfig: CameraConfig, - ): Promise; + ): Promise; generateDefaultEventQuery( - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, cameraIDs: Set, query: PartialEventQuery, ): EventQuery[] | null; generateDefaultRecordingQuery( - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, cameraIDs: Set, query: PartialRecordingQuery, ): RecordingQuery[] | null; generateDefaultRecordingSegmentsQuery( - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, cameraIDs: Set, query: PartialRecordingSegmentsQuery, ): RecordingSegmentsQuery[] | null; getEvents( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: EventQuery, engineOptions?: EngineOptions, ): Promise; getRecordings( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: RecordingQuery, engineOptions?: EngineOptions, ): Promise; getRecordingSegments( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: RecordingSegmentsQuery, engineOptions?: EngineOptions, ): Promise; generateMediaFromEvents( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: EventQuery, results: QueryReturnType, ): ViewMedia[] | null; generateMediaFromRecordings( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: RecordingQuery, results: QueryReturnType, ): ViewMedia[] | null; @@ -109,7 +113,7 @@ export interface CameraManagerEngine { getMediaSeekTime( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, media: ViewMedia, target: Date, engineOptions?: EngineOptions, @@ -117,7 +121,7 @@ export interface CameraManagerEngine { getMediaMetadata( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: MediaMetadataQuery, engineOptions?: EngineOptions, ): Promise; @@ -127,14 +131,20 @@ export interface CameraManagerEngine { cameraConfig: CameraConfig, ): CameraManagerCameraMetadata; - getCameraCapabilities( - cameraConfig: CameraConfig, - ): CameraManagerCameraCapabilities | null; - getMediaCapabilities(media: ViewMedia): CameraManagerMediaCapabilities | null; getCameraEndpoints( cameraConfig: CameraConfig, context?: CameraEndpointsContext, ): CameraEndpoints | null; + + executePTZAction( + hass: HomeAssistant, + cameraConfig: CameraConfig, + action: PTZAction, + options?: { + phase?: PTZPhase, + preset?: string, + } + ): Promise; } diff --git a/src/camera-manager/error.ts b/src/camera-manager/error.ts index 61f9e7e5..38cb3561 100644 --- a/src/camera-manager/error.ts +++ b/src/camera-manager/error.ts @@ -1,3 +1,4 @@ import { FrigateCardError } from '../types.js'; export class CameraInitializationError extends FrigateCardError {} +export class CameraNoIDError extends FrigateCardError {} diff --git a/src/camera-manager/frigate/engine-frigate.ts b/src/camera-manager/frigate/engine-frigate.ts index 0a4dd6ea..f7936f3d 100644 --- a/src/camera-manager/frigate/engine-frigate.ts +++ b/src/camera-manager/frigate/engine-frigate.ts @@ -9,11 +9,12 @@ import orderBy from 'lodash-es/orderBy'; import throttle from 'lodash-es/throttle'; import uniq from 'lodash-es/uniq'; import uniqWith from 'lodash-es/uniqWith'; -import { CameraConfig } from '../../config/types'; +import { CameraConfig, PTZAction, PTZPhase } from '../../config/types'; import { localize } from '../../localize/localize'; import { ExtendedHomeAssistant } from '../../types'; import { allPromises, + errorToConsole, formatDate, prettifyTitle, runWhenIdleIfSupported, @@ -24,6 +25,7 @@ import { Entity } from '../../utils/ha/entity-registry/types'; import { ViewMedia } from '../../view/media'; import { ViewMediaClassifier } from '../../view/media-classifier'; import { RecordingSegmentsCache, RequestCache } from '../cache'; +import { Camera } from '../camera'; import { CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT, CameraManagerEngine, @@ -31,12 +33,11 @@ import { import { CameraInitializationError } from '../error'; import { GenericCameraManagerEngine } from '../generic/engine-generic'; import { DateRange } from '../range'; +import { CameraManagerReadOnlyConfigStore } from '../store'; import { - CameraConfigs, CameraEndpoint, CameraEndpoints, CameraEndpointsContext, - CameraManagerCameraCapabilities, CameraManagerCameraMetadata, CameraManagerMediaCapabilities, DataQuery, @@ -51,6 +52,8 @@ import { PartialEventQuery, PartialRecordingQuery, PartialRecordingSegmentsQuery, + PTZCapabilities, + PTZMovementType, QueryResults, QueryResultsType, QueryReturnType, @@ -74,12 +77,14 @@ import { getRecordingSegments, getRecordingsSummary, retainEvent, + getPTZInfo, } from './requests'; import { FrigateEventQueryResults, FrigateRecording, FrigateRecordingQueryResults, FrigateRecordingSegmentsQueryResults, + PTZInfo, } from './types'; const EVENT_REQUEST_CACHE_MAX_AGE_SECONDS = 60; @@ -144,7 +149,7 @@ export class FrigateCameraManagerEngine hass: HomeAssistant, entityRegistryManager: EntityRegistryManager, cameraConfig: CameraConfig, - ): Promise { + ): Promise { const hasCameraName = !!cameraConfig.frigate?.camera_name; const hasAutoTriggers = cameraConfig.triggers.motion || cameraConfig.triggers.occupancy; @@ -207,7 +212,64 @@ export class FrigateCameraManagerEngine cameraConfig.triggers.entities = uniq(cameraConfig.triggers.entities); } - return cameraConfig; + const ptz = await this._getPTZCapabilities(hass, cameraConfig); + + const isBirdseye = this._isBirdseye(cameraConfig); + return new Camera(cameraConfig, this, { + canFavoriteEvents: !isBirdseye, + canFavoriteRecordings: !isBirdseye, + canSeek: true, + supportsClips: !isBirdseye, + supportsSnapshots: !isBirdseye, + supportsRecordings: !isBirdseye, + supportsTimeline: !isBirdseye, + + ...(ptz && { ptz: ptz }), + }); + } + + protected async _getPTZCapabilities( + hass: HomeAssistant, + cameraConfig: CameraConfig, + ): Promise { + if (!cameraConfig.frigate.camera_name) { + return null; + } + + let ptzInfo: PTZInfo | null = null; + try { + ptzInfo = await getPTZInfo( + hass, + cameraConfig.frigate.client_id, + cameraConfig.frigate.camera_name, + ); + } catch (e) { + errorToConsole(e as Error); + return null; + } + + const panTilt: PTZMovementType[] = [ + ...(ptzInfo.features?.includes('pt') ? ['continuous' as const] : []), + ...(ptzInfo.features?.includes('pt-r') ? ['relative' as const] : []), + ]; + const zoom: PTZMovementType[] = [ + ...(ptzInfo.features?.includes('zoom') ? ['continuous' as const] : []), + ...(ptzInfo.features?.includes('zoom-r') ? ['relative' as const] : []), + ]; + const presets = ptzInfo.presets; + + if (panTilt.length || zoom.length || presets?.length) { + return { + ...(panTilt && { panTilt: panTilt }), + ...(zoom && { zoom: zoom }), + ...(presets && { presets: presets }), + }; + } + return null; + } + + protected _isBirdseye(cameraConfig: CameraConfig): boolean { + return cameraConfig.frigate.camera_name === CAMERA_BIRDSEYE; } /** @@ -330,13 +392,11 @@ export class FrigateCameraManagerEngine } public generateDefaultEventQuery( - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, cameraIDs: Set, query?: PartialEventQuery, ): EventQuery[] | null { - const relevantCameraConfigs = Array.from(cameraIDs).map((cameraID) => - cameras.get(cameraID), - ); + const relevantCameraConfigs = [...store.getCameraConfigs(cameraIDs)]; // If all cameras specify exactly the same zones or labels (incl. none), we // can use a single batch query which will be better performance wise, @@ -365,7 +425,7 @@ export class FrigateCameraManagerEngine const output: EventQuery[] = []; for (const cameraID of cameraIDs) { - const cameraConfig = cameras.get(cameraID); + const cameraConfig = store.getCameraConfig(cameraID); if (cameraConfig) { output.push({ type: QueryType.Event, @@ -384,7 +444,7 @@ export class FrigateCameraManagerEngine } public generateDefaultRecordingQuery( - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, cameraIDs: Set, query?: PartialRecordingQuery, ): RecordingQuery[] { @@ -398,7 +458,7 @@ export class FrigateCameraManagerEngine } public generateDefaultRecordingSegmentsQuery( - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, cameraIDs: Set, query: PartialRecordingSegmentsQuery, ): RecordingSegmentsQuery[] | null { @@ -431,12 +491,12 @@ export class FrigateCameraManagerEngine } protected _buildInstanceToCameraIDMapFromQuery( - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, cameraIDs: Set, ): Map> { const output: Map> = new Map(); for (const cameraID of cameraIDs) { - const cameraConfig = this._getQueryableCameraConfig(cameras, cameraID); + const cameraConfig = this._getQueryableCameraConfig(store, cameraID); const clientID = cameraConfig?.frigate.client_id; if (clientID) { if (!output.has(clientID)) { @@ -449,12 +509,12 @@ export class FrigateCameraManagerEngine } protected _getFrigateCameraNamesForCameraIDs( - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, cameraIDs: Set, ): Set { const output = new Set(); for (const cameraID of cameraIDs) { - const cameraConfig = this._getQueryableCameraConfig(cameras, cameraID); + const cameraConfig = this._getQueryableCameraConfig(store, cameraID); if (cameraConfig?.frigate.camera_name) { output.add(cameraConfig.frigate.camera_name); } @@ -464,7 +524,7 @@ export class FrigateCameraManagerEngine public async getEvents( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: EventQuery, engineOptions?: EngineOptions, ): Promise { @@ -487,7 +547,7 @@ export class FrigateCameraManagerEngine const nativeQuery: NativeFrigateEventQuery = { instance_id: instanceID, - cameras: Array.from(this._getFrigateCameraNamesForCameraIDs(cameras, cameraIDs)), + cameras: Array.from(this._getFrigateCameraNamesForCameraIDs(store, cameraIDs)), ...(query.what && { labels: Array.from(query.what) }), ...(query.where && { zones: Array.from(query.where) }), ...(query.tags && { sub_labels: Array.from(query.tags) }), @@ -518,10 +578,7 @@ export class FrigateCameraManagerEngine // Frigate allows multiple cameras to be searched for events in a single // query. Break them down into groups of cameras per Frigate instance, then // query once per instance for all cameras in that instance. - const instances = this._buildInstanceToCameraIDMapFromQuery( - cameras, - query.cameraIDs, - ); + const instances = this._buildInstanceToCameraIDMapFromQuery(store, query.cameraIDs); await Promise.all( Array.from(instances.keys()).map((instanceID) => @@ -533,7 +590,7 @@ export class FrigateCameraManagerEngine public async getRecordings( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: RecordingQuery, engineOptions?: EngineOptions, ): Promise { @@ -551,7 +608,7 @@ export class FrigateCameraManagerEngine return; } - const cameraConfig = this._getQueryableCameraConfig(cameras, cameraID); + const cameraConfig = this._getQueryableCameraConfig(store, cameraID); if (!cameraConfig || !cameraConfig.frigate.camera_name) { return; } @@ -619,7 +676,7 @@ export class FrigateCameraManagerEngine public async getRecordingSegments( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: RecordingSegmentsQuery, engineOptions?: EngineOptions, ): Promise { @@ -630,7 +687,7 @@ export class FrigateCameraManagerEngine cameraID: string, ): Promise => { const query = { ...baseQuery, cameraIDs: new Set([cameraID]) }; - const cameraConfig = this._getQueryableCameraConfig(cameras, cameraID); + const cameraConfig = this._getQueryableCameraConfig(store, cameraID); if (!cameraConfig || !cameraConfig.frigate.camera_name) { return; } @@ -687,12 +744,12 @@ export class FrigateCameraManagerEngine Array.from(query.cameraIDs).map((cameraID) => processQuery(query, cameraID)), ); - runWhenIdleIfSupported(() => this._throttledSegmentGarbageCollector(hass, cameras)); + runWhenIdleIfSupported(() => this._throttledSegmentGarbageCollector(hass, store)); return output.size ? output : null; } protected _getCameraIDMatch( - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: DataQuery, instanceID: string, cameraName: string, @@ -704,7 +761,7 @@ export class FrigateCameraManagerEngine if (query.cameraIDs.size === 1) { return [...query.cameraIDs][0]; } - for (const [cameraID, cameraConfig] of cameras.entries()) { + for (const [cameraID, cameraConfig] of store.getCameraConfigEntries()) { if ( cameraConfig.frigate.client_id === instanceID && cameraConfig.frigate.camera_name === cameraName @@ -717,7 +774,7 @@ export class FrigateCameraManagerEngine public generateMediaFromEvents( _hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: EventQuery, results: QueryReturnType, ): ViewMedia[] | null { @@ -728,7 +785,7 @@ export class FrigateCameraManagerEngine const output: ViewMedia[] = []; for (const event of results.events) { const cameraID = this._getCameraIDMatch( - cameras, + store, query, results.instanceID, event.camera, @@ -736,7 +793,7 @@ export class FrigateCameraManagerEngine if (!cameraID) { continue; } - const cameraConfig = this._getQueryableCameraConfig(cameras, cameraID); + const cameraConfig = this._getQueryableCameraConfig(store, cameraID); if (!cameraConfig) { continue; } @@ -771,7 +828,7 @@ export class FrigateCameraManagerEngine public generateMediaFromRecordings( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, _query: RecordingQuery, results: QueryReturnType, ): ViewMedia[] | null { @@ -781,7 +838,7 @@ export class FrigateCameraManagerEngine const output: ViewMedia[] = []; for (const recording of results.recordings) { - const cameraConfig = this._getQueryableCameraConfig(cameras, recording.cameraID); + const cameraConfig = this._getQueryableCameraConfig(store, recording.cameraID); if (!cameraConfig) { continue; } @@ -809,7 +866,7 @@ export class FrigateCameraManagerEngine public async getMediaSeekTime( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, media: ViewMedia, target: Date, engineOptions?: EngineOptions, @@ -828,7 +885,7 @@ export class FrigateCameraManagerEngine type: QueryType.RecordingSegments, }; - const results = await this.getRecordingSegments(hass, cameras, query, engineOptions); + const results = await this.getRecordingSegments(hass, store, query, engineOptions); if (results) { return this._getSeekTimeInSegments( @@ -843,11 +900,11 @@ export class FrigateCameraManagerEngine } protected _getQueryableCameraConfig( - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, cameraID: string, ): CameraConfig | null { - const cameraConfig = cameras.get(cameraID); - if (!cameraConfig || cameraConfig.frigate.camera_name == CAMERA_BIRDSEYE) { + const cameraConfig = store.getCameraConfig(cameraID); + if (!cameraConfig || this._isBirdseye(cameraConfig)) { return null; } return cameraConfig; @@ -865,7 +922,7 @@ export class FrigateCameraManagerEngine public async getMediaMetadata( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: MediaMetadataQuery, engineOptions?: EngineOptions, ): Promise { @@ -885,16 +942,13 @@ export class FrigateCameraManagerEngine const days: Set = new Set(); const tags: Set = new Set(); - const instances = this._buildInstanceToCameraIDMapFromQuery( - cameras, - query.cameraIDs, - ); + const instances = this._buildInstanceToCameraIDMapFromQuery(store, query.cameraIDs); const processEventSummary = async ( instanceID: string, cameraIDs: Set, ): Promise => { - const cameraNames = this._getFrigateCameraNamesForCameraIDs(cameras, cameraIDs); + const cameraNames = this._getFrigateCameraNamesForCameraIDs(store, cameraIDs); for (const entry of await getEventSummary(hass, instanceID)) { if (!cameraNames.has(entry.camera)) { // If this entry applies to a camera that *is* in this Frigate @@ -919,7 +973,7 @@ export class FrigateCameraManagerEngine const processRecordings = async (cameraIDs: Set): Promise => { const recordings = await this.getRecordings( hass, - cameras, + store, { type: QueryType.Recording, cameraIDs: cameraIDs, @@ -977,7 +1031,7 @@ export class FrigateCameraManagerEngine */ protected async _garbageCollectSegments( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, ): Promise { const cameraIDs = this._recordingSegmentsCache.getCameraIDs(); const recordingQuery: RecordingQuery = { @@ -992,7 +1046,7 @@ export class FrigateCameraManagerEngine return `${cameraID}/${startTime.getDate()}/${startTime.getHours()}`; }; - const results = await this.getRecordings(hass, cameras, recordingQuery); + const results = await this.getRecordings(hass, store, recordingQuery); if (!results) { return; } @@ -1053,21 +1107,6 @@ export class FrigateCameraManagerEngine return seekMilliseconds / 1000; } - public getCameraCapabilities( - cameraConfig: CameraConfig, - ): CameraManagerCameraCapabilities { - const isBirdseye = cameraConfig.frigate.camera_name === CAMERA_BIRDSEYE; - return { - canFavoriteEvents: !isBirdseye, - canFavoriteRecordings: !isBirdseye, - canSeek: true, - supportsClips: !isBirdseye, - supportsSnapshots: !isBirdseye, - supportsRecordings: !isBirdseye, - supportsTimeline: !isBirdseye, - }; - } - public getMediaCapabilities(media: ViewMedia): CameraManagerMediaCapabilities { return { canFavorite: ViewMediaClassifier.isEvent(media), @@ -1189,4 +1228,44 @@ export class FrigateCameraManagerEngine ...(webrtcCard && { webrtcCard: webrtcCard }), }; } + + public async executePTZAction( + hass: HomeAssistant, + cameraConfig: CameraConfig, + action: PTZAction, + options?: { + phase?: PTZPhase; + preset?: string; + }, + ): Promise { + const cameraEntity = cameraConfig.camera_entity; + + if (action === 'preset' && !options?.preset) { + return; + } + + // Awkward translation between card action and service parameters: + // https://github.com/blakeblackshear/frigate-hass-integration/blob/dev/custom_components/frigate/services.yaml + await hass.callService('frigate', 'ptz', { + entity_id: cameraEntity, + action: + options?.phase === 'stop' + ? 'stop' + : action === 'zoom_in' || action === 'zoom_out' + ? 'zoom' + : action === 'preset' + ? 'preset' + : 'move', + ...(options?.phase !== 'stop' && { + argument: + action === 'zoom_in' + ? 'in' + : action === 'zoom_out' + ? 'out' + : action === 'preset' + ? options?.preset + : action, + }), + }); + } } diff --git a/src/camera-manager/frigate/requests.ts b/src/camera-manager/frigate/requests.ts index 6bb5fc8b..c019f934 100644 --- a/src/camera-manager/frigate/requests.ts +++ b/src/camera-manager/frigate/requests.ts @@ -8,6 +8,8 @@ import { eventSummarySchema, FrigateEvent, frigateEventsSchema, + PTZInfo, + ptzInfoSchema, recordingSegmentsSchema, RecordingSummary, recordingSummarySchema, @@ -151,3 +153,20 @@ export const getEventSummary = async ( true, ); }; + +export const getPTZInfo = async ( + hass: HomeAssistant, + clientID: string, + cameraName: string, +): Promise => { + return await homeAssistantWSRequest( + hass, + ptzInfoSchema, + { + type: 'frigate/ptz/info', + instance_id: clientID, + camera: cameraName, + }, + true, + ); +}; diff --git a/src/camera-manager/frigate/types.ts b/src/camera-manager/frigate/types.ts index 8c923401..1d3bf95d 100644 --- a/src/camera-manager/frigate/types.ts +++ b/src/camera-manager/frigate/types.ts @@ -76,6 +76,13 @@ export const eventSummarySchema = z .array(); export type EventSummary = z.infer; +export const ptzInfoSchema = z.object({ + name: z.string().optional(), + features: z.string().array().optional(), + presets: z.string().array().optional(), +}); +export type PTZInfo = z.infer; + // ============================== // Frigate concrete query results // ============================== diff --git a/src/camera-manager/generic/engine-generic.ts b/src/camera-manager/generic/engine-generic.ts index 3a5fe04e..ed8986a4 100644 --- a/src/camera-manager/generic/engine-generic.ts +++ b/src/camera-manager/generic/engine-generic.ts @@ -1,18 +1,22 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { CameraConfig } from '../../config/types'; +import { + CameraConfig, + PTZAction, + PTZPhase +} from '../../config/types'; import { ExtendedHomeAssistant } from '../../types'; import { getEntityIcon, getEntityTitle } from '../../utils/ha'; import { EntityRegistryManager } from '../../utils/ha/entity-registry'; import { ViewMedia } from '../../view/media'; +import { Camera } from '../camera'; import { CameraManagerEngine } from '../engine'; +import { CameraManagerReadOnlyConfigStore } from '../store'; import { - CameraConfigs, CameraEndpoint, CameraEndpoints, CameraEndpointsContext, - CameraManagerCameraCapabilities, CameraManagerCameraMetadata, CameraManagerMediaCapabilities, DataQuery, @@ -29,7 +33,7 @@ import { RecordingQuery, RecordingQueryResultsMap, RecordingSegmentsQuery, - RecordingSegmentsQueryResultsMap, + RecordingSegmentsQueryResultsMap } from '../types'; import { getCameraEntityFromConfig, getDefaultGo2RTCEndpoint } from '../utils.js'; @@ -42,12 +46,20 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { _hass: HomeAssistant, _entityRegistryManager: EntityRegistryManager, cameraConfig: CameraConfig, - ): Promise { - return cameraConfig; + ): Promise { + return new Camera(cameraConfig, this, { + canFavoriteEvents: false, + canFavoriteRecordings: false, + canSeek: false, + supportsClips: false, + supportsRecordings: false, + supportsSnapshots: false, + supportsTimeline: false, + }); } public generateDefaultEventQuery( - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, _cameraIDs: Set, _query: PartialEventQuery, ): EventQuery[] | null { @@ -55,7 +67,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { } public generateDefaultRecordingQuery( - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, _cameraIDs: Set, _query: PartialRecordingQuery, ): RecordingQuery[] | null { @@ -63,7 +75,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { } public generateDefaultRecordingSegmentsQuery( - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, _cameraIDs: Set, _query: PartialRecordingSegmentsQuery, ): RecordingSegmentsQuery[] | null { @@ -72,7 +84,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { public async getEvents( _hass: HomeAssistant, - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, _query: EventQuery, _engineOptions?: EngineOptions, ): Promise { @@ -81,7 +93,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { public async getRecordings( _hass: HomeAssistant, - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, _query: RecordingQuery, _engineOptions?: EngineOptions, ): Promise { @@ -90,7 +102,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { public async getRecordingSegments( _hass: HomeAssistant, - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, _query: RecordingSegmentsQuery, _engineOptions?: EngineOptions, ): Promise { @@ -99,7 +111,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { public generateMediaFromEvents( _hass: HomeAssistant, - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, _query: EventQuery, _results: QueryReturnType, ): ViewMedia[] | null { @@ -108,7 +120,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { public generateMediaFromRecordings( _hass: HomeAssistant, - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, _query: RecordingQuery, _results: QueryReturnType, ): ViewMedia[] | null { @@ -138,7 +150,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { public async getMediaSeekTime( _hass: HomeAssistant, - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, _media: ViewMedia, _target: Date, _engineOptions?: EngineOptions, @@ -148,7 +160,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { public async getMediaMetadata( _hass: HomeAssistant, - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, _query: MediaMetadataQuery, _engineOptions?: EngineOptions, ): Promise { @@ -173,20 +185,6 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { }; } - public getCameraCapabilities( - _cameraConfig: CameraConfig, - ): CameraManagerCameraCapabilities | null { - return { - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, - supportsClips: false, - supportsRecordings: false, - supportsSnapshots: false, - supportsTimeline: false, - }; - } - public getMediaCapabilities(_media: ViewMedia): CameraManagerMediaCapabilities | null { return null; } @@ -202,4 +200,16 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { } : null; } + + public async executePTZAction( + _hass: HomeAssistant, + _cameraConfig: CameraConfig, + _action: PTZAction, + _options?: { + phase?: PTZPhase; + preset?: string; + }, + ): Promise { + // Pass. + } } diff --git a/src/camera-manager/manager.ts b/src/camera-manager/manager.ts index 5ca659e8..efcefd4f 100644 --- a/src/camera-manager/manager.ts +++ b/src/camera-manager/manager.ts @@ -1,16 +1,14 @@ -import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import add from 'date-fns/add'; import cloneDeep from 'lodash-es/cloneDeep'; import merge from 'lodash-es/merge.js'; import sum from 'lodash-es/sum'; import { CardCameraAPI } from '../card-controller/types.js'; -import { CameraConfig, CamerasConfig } from '../config/types.js'; +import { CameraConfig, CamerasConfig, PTZAction, PTZPhase } from '../config/types.js'; import { MEDIA_CHUNK_SIZE_DEFAULT } from '../const.js'; import { localize } from '../localize/localize.js'; import { allPromises, arrayify, setify } from '../utils/basic.js'; import { getCameraID } from '../utils/camera.js'; import { log } from '../utils/debug.js'; -import { EntityRegistryManager } from '../utils/ha/entity-registry/index.js'; import { ViewMedia } from '../view/media.js'; import { CameraManagerEngineFactory } from './engine-factory.js'; import { CameraManagerEngine } from './engine.js'; @@ -49,7 +47,7 @@ import { RecordingSegmentsQuery, RecordingSegmentsQueryResults, RecordingSegmentsQueryResultsMap, - ResultsMap, + ResultsMap } from './types.js'; import { sortMedia } from './utils.js'; @@ -102,31 +100,26 @@ export interface ExtendedMediaQueryResult { results: ViewMedia[]; } -interface InitializedCamera { - inputConfig: CameraConfig; - initializedConfig: CameraConfig; - engine: CameraManagerEngine; -} - export class CameraManager { protected _api: CardCameraAPI; protected _engineFactory: CameraManagerEngineFactory; - protected _store = new CameraManagerStore(); + protected _store: CameraManagerStore; - constructor(api: CardCameraAPI) { + constructor(api: CardCameraAPI, store?: CameraManagerStore) { this._api = api; this._engineFactory = new CameraManagerEngineFactory( this._api.getEntityRegistryManager(), this._api.getResolvedMediaCache(), ); + this._store = store ?? new CameraManagerStore(); } - public async initializeCamerasFromConfig(): Promise { + public async initializeCamerasFromConfig(): Promise { const config = this._api.getConfigManager().getConfig(); const hass = this._api.getHASSManager().getHASS(); if (!config || !hass) { - return; + return false; } this._store.reset(); @@ -143,7 +136,9 @@ export class CameraManager { await this._initializeCameras(cameras); } catch (e: unknown) { this._api.getMessageManager().setErrorIfHigherPriority(e); + return false; } + return true; } protected async _getEnginesForCameras( @@ -172,7 +167,9 @@ export class CameraManager { if (!engine || !engineType) { throw new CameraInitializationError( localize('error.no_camera_engine'), - cameraConfig, + // Camera initialization may modify the configuration. Keep the + // original config unchanged. + cloneDeep(cameraConfig), ); } engines.set(engineType, engine); @@ -181,27 +178,6 @@ export class CameraManager { return output; } - protected async _initializeCamera( - hass: HomeAssistant, - engine: CameraManagerEngine, - entityRegistryManager: EntityRegistryManager, - inputCameraConfig: CameraConfig, - ): Promise { - const initializedConfig = await engine.initializeCamera( - hass, - entityRegistryManager, - // Camera initialization may modify the configuration. Keep the original - // for display in error messages to avoid user confusion. - cloneDeep(inputCameraConfig), - ); - - return { - inputConfig: inputCameraConfig, - initializedConfig: initializedConfig, - engine: engine, - }; - } - protected async _initializeCameras(camerasConfig: CamerasConfig): Promise { const initializationStartTime = new Date(); const hass = this._api.getHASSManager().getHASS(); @@ -229,12 +205,11 @@ export class CameraManager { const engineByConfig = await this._getEnginesForCameras(camerasConfig); // Configuration is initialized in parallel. - const results = await allPromises( + const cameras = await allPromises( engineByConfig.entries(), async ([cameraConfig, engine]) => - await this._initializeCamera( + await engine.initializeCamera( hass, - engine, this._api.getEntityRegistryManager(), cameraConfig, ), @@ -242,27 +217,26 @@ export class CameraManager { // Do the additions based off the result-order, to ensure the map order is // preserved. - results.forEach((result) => { - const id = getCameraID(result.initializedConfig); + cameras.forEach((camera) => { + const cameraID = getCameraID(camera.getConfig()); - if (!id) { + if (!cameraID) { throw new CameraInitializationError( localize('error.no_camera_id'), - result.inputConfig, + camera.getConfig(), ); } - if (this._store.hasCameraID(id)) { + if (this._store.hasCameraID(cameraID)) { throw new CameraInitializationError( localize('error.duplicate_camera_id'), - result.inputConfig, + camera.getConfig(), ); } // Always ensure the actual ID used in the card is in the configuration itself. - result.initializedConfig.id = id; - - this._store.addCamera(id, result.initializedConfig, result.engine); + camera.setID(cameraID); + this._store.addCamera(camera); }); if (!this._store.getVisibleCameraCount()) { @@ -372,20 +346,16 @@ export class CameraManager { for (const [engine, cameraIDs] of engines) { let queries: DataQuery[] | null = null; if (QueryClassifier.isEventQuery(partialQuery)) { - queries = engine.generateDefaultEventQuery( - this._store.getVisibleCameras(), - cameraIDs, - partialQuery, - ); + queries = engine.generateDefaultEventQuery(this._store, cameraIDs, partialQuery); } else if (QueryClassifier.isRecordingQuery(partialQuery)) { queries = engine.generateDefaultRecordingQuery( - this._store.getVisibleCameras(), + this._store, cameraIDs, partialQuery, ); } else if (QueryClassifier.isRecordingSegmentsQuery(partialQuery)) { queries = engine.generateDefaultRecordingSegmentsQuery( - this._store.getVisibleCameras(), + this._store, cameraIDs, partialQuery, ); @@ -596,7 +566,7 @@ export class CameraManager { return null; } - return await engine.getMediaSeekTime(hass, this._store.getCameras(), media, target); + return await engine.getMediaSeekTime(hass, this._store, media, target); } protected async _handleQuery( @@ -624,28 +594,28 @@ export class CameraManager { if (QueryClassifier.isEventQuery(query)) { engineResult = (await engine.getEvents( hass, - this._store.getCameras(), + this._store, query, engineOptions, )) as Map> | null; } else if (QueryClassifier.isRecordingQuery(query)) { engineResult = (await engine.getRecordings( hass, - this._store.getCameras(), + this._store, query, engineOptions, )) as Map> | null; } else if (QueryClassifier.isRecordingSegmentsQuery(query)) { engineResult = (await engine.getRecordingSegments( hass, - this._store.getCameras(), + this._store, query, engineOptions, )) as Map> | null; } else if (QueryClassifier.isMediaMetadataQuery(query)) { engineResult = (await engine.getMediaMetadata( hass, - this._store.getCameras(), + this._store, query, engineOptions, )) as Map> | null; @@ -710,22 +680,12 @@ export class CameraManager { QueryClassifier.isEventQuery(query) && QueryResultClassifier.isEventQueryResult(result) ) { - media = engine.generateMediaFromEvents( - hass, - this._store.getCameras(), - query, - result, - ); + media = engine.generateMediaFromEvents(hass, this._store, query, result); } else if ( QueryClassifier.isRecordingQuery(query) && QueryResultClassifier.isRecordingQuery(result) ) { - media = engine.generateMediaFromRecordings( - hass, - this._store.getCameras(), - query, - result, - ); + media = engine.generateMediaFromRecordings(hass, this._store, query, result); } if (media) { mediaArray.push(...media); @@ -761,12 +721,7 @@ export class CameraManager { public getCameraCapabilities( cameraID: string, ): CameraManagerCameraCapabilities | null { - const cameraConfig = this._store.getCameraConfig(cameraID); - const engine = this._store.getEngineForCameraID(cameraID); - if (!cameraConfig || !engine) { - return null; - } - return engine.getCameraCapabilities(cameraConfig); + return this._store.getCamera(cameraID)?.getCapabilities() ?? null; } public getAggregateCameraCapabilities( @@ -787,6 +742,26 @@ export class CameraManager { supportsRecordings: perCameraCapabilities.some((cap) => cap?.supportsRecordings), supportsSnapshots: perCameraCapabilities.some((cap) => cap?.supportsSnapshots), supportsTimeline: perCameraCapabilities.some((cap) => cap?.supportsTimeline), + + supportsPTZ: perCameraCapabilities.some((cap) => !!cap?.ptz), }; } + + public async executePTZAction( + cameraID: string, + action: PTZAction, + options: { + phase?: PTZPhase; + preset?: string; + }, + ): Promise { + const hass = this._api.getHASSManager().getHASS(); + const engine = this._store.getEngineForCameraID(cameraID); + const cameraConfig = this._store.getCameraConfig(cameraID); + + if (!engine || !cameraConfig || !hass) { + return; + } + return engine.executePTZAction(hass, cameraConfig, action, options); + } } diff --git a/src/camera-manager/motioneye/engine-motioneye.ts b/src/camera-manager/motioneye/engine-motioneye.ts index c7116239..f326b08f 100644 --- a/src/camera-manager/motioneye/engine-motioneye.ts +++ b/src/camera-manager/motioneye/engine-motioneye.ts @@ -8,25 +8,23 @@ import { CameraConfig } from '../../config/types'; import { allPromises, formatDate, isValidDate } from '../../utils/basic'; import { BrowseMediaStep, - BrowseMediaTarget, + BrowseMediaTarget } from '../../utils/ha/browse-media/browse-media-manager'; import { - BROWSE_MEDIA_CACHE_SECONDS, - BrowseMedia, - MEDIA_CLASS_IMAGE, + BrowseMedia, BROWSE_MEDIA_CACHE_SECONDS, MEDIA_CLASS_IMAGE, MEDIA_CLASS_VIDEO, - RichBrowseMedia, + RichBrowseMedia } from '../../utils/ha/browse-media/types'; import { ViewMedia } from '../../view/media'; import { BrowseMediaCameraManagerEngine, getViewMediaFromBrowseMediaArray, - isMediaWithinDates, + isMediaWithinDates } from '../browse-media/engine-browse-media'; import { BrowseMediaMetadata } from '../browse-media/types'; import { CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT } from '../engine'; +import { CameraManagerReadOnlyConfigStore } from '../store'; import { - CameraConfigs, CameraEndpoint, CameraEndpoints, CameraEndpointsContext, @@ -41,7 +39,7 @@ import { MediaMetadataQueryResultsMap, QueryResults, QueryResultsType, - QueryReturnType, + QueryReturnType } from '../types'; import motioneyeLogo from './assets/motioneye-logo.svg'; import { MotionEyeEventQueryResults } from './types'; @@ -126,7 +124,7 @@ export class MotionEyeCameraManagerEngine extends BrowseMediaCameraManagerEngine // Get media directories that match a given criteria. protected async _getMatchingDirectories( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, cameraID: string, matchOptions?: { start?: Date; @@ -136,11 +134,11 @@ export class MotionEyeCameraManagerEngine extends BrowseMediaCameraManagerEngine } | null, engineOptions?: EngineOptions, ): Promise[] | null> { - const cameraEntityID = cameras.get(cameraID)?.camera_entity; + const cameraConfig = store.getCameraConfig(cameraID); + const cameraEntityID = cameraConfig?.camera_entity; const entity = cameraEntityID ? this._cameraEntities.get(cameraEntityID) : null; const configID = entity?.config_entry_id; const deviceID = entity?.device_id; - const cameraConfig = cameras.get(cameraID); if (!configID || !deviceID || !cameraConfig) { return null; @@ -206,7 +204,7 @@ export class MotionEyeCameraManagerEngine extends BrowseMediaCameraManagerEngine public async getEvents( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: EventQuery, engineOptions?: EngineOptions, ): Promise { @@ -225,14 +223,14 @@ export class MotionEyeCameraManagerEngine extends BrowseMediaCameraManagerEngine return; } - const cameraConfig = cameras.get(cameraID); + const cameraConfig = store.getCameraConfig(cameraID); if (!cameraConfig) { return; } const directories = await this._getMatchingDirectories( hass, - cameras, + store, cameraID, perCameraQuery, engineOptions, @@ -309,7 +307,7 @@ export class MotionEyeCameraManagerEngine extends BrowseMediaCameraManagerEngine public generateMediaFromEvents( _hass: HomeAssistant, - _cameras: CameraConfigs, + _store: CameraManagerReadOnlyConfigStore, _query: EventQuery, results: QueryReturnType, ): ViewMedia[] | null { @@ -321,7 +319,7 @@ export class MotionEyeCameraManagerEngine extends BrowseMediaCameraManagerEngine public async getMediaMetadata( hass: HomeAssistant, - cameras: CameraConfigs, + store: CameraManagerReadOnlyConfigStore, query: MediaMetadataQuery, engineOptions?: EngineOptions, ): Promise { @@ -340,7 +338,7 @@ export class MotionEyeCameraManagerEngine extends BrowseMediaCameraManagerEngine const getDaysForCamera = async (cameraID: string): Promise => { const directories = await this._getMatchingDirectories( hass, - cameras, + store, cameraID, null, engineOptions, diff --git a/src/camera-manager/store.ts b/src/camera-manager/store.ts index b5ec864e..752a6aaf 100644 --- a/src/camera-manager/store.ts +++ b/src/camera-manager/store.ts @@ -1,7 +1,8 @@ import { CameraConfig } from '../config/types'; import { ViewMedia } from '../view/media'; +import { Camera } from './camera'; import { CameraManagerEngine } from './engine'; -import { CameraConfigs, Engine } from './types'; +import { Engine } from './types'; type CameraManagerEngineCameraIDMap = Map>; @@ -10,74 +11,82 @@ export interface CameraManagerReadOnlyConfigStore { getCameraConfigForMedia(media: ViewMedia): CameraConfig | null; hasCameraID(cameraID: string): boolean; - hasVisibleCameraID(cameraID: string): boolean; + getCamera(cameraID: string): Camera | null; getCameraCount(): number; getVisibleCameraCount(): number; - getCameras(): CameraConfigs; - getVisibleCameras(): CameraConfigs; + getCameraConfigs(cameraIDs?: Iterable): IterableIterator; + getCameraConfigEntries( + cameraIDs?: Iterable, + ): IterableIterator<[string, CameraConfig]>; getCameraIDs(): Set; getVisibleCameraIDs(): Set; + + getAllDependentCameras(cameraID: string): Set; } export class CameraManagerStore implements CameraManagerReadOnlyConfigStore { - protected _allConfigs: Map = new Map(); - protected _visibleConfigs: Map = new Map(); - protected _enginesByCamera: Map = new Map(); + protected _cameras: Map = new Map(); protected _enginesByType: Map = new Map(); - public addCamera( - cameraID: string, - cameraConfig: CameraConfig, - engine: CameraManagerEngine, - ): void { - if (!cameraConfig.hide) { - this._visibleConfigs.set(cameraID, cameraConfig); - } - this._allConfigs.set(cameraID, cameraConfig); - this._enginesByCamera.set(cameraID, engine); - this._enginesByType.set(engine.getEngineType(), engine); + public addCamera(camera: Camera): void { + this._cameras.set(camera.getID(), camera); + this._enginesByType.set(camera.getEngine().getEngineType(), camera.getEngine()); } - public reset(): void { - this._allConfigs.clear(); - this._visibleConfigs.clear(); - this._enginesByCamera.clear(); + this._cameras.clear(); this._enginesByType.clear(); } + public getCamera(cameraID: string): Camera | null { + return this._cameras.get(cameraID) ?? null; + } public getCameraConfig(cameraID: string): CameraConfig | null { - return this._allConfigs.get(cameraID) ?? null; + return this._cameras.get(cameraID)?.getConfig() ?? null; } public hasCameraID(cameraID: string): boolean { - return this._allConfigs.has(cameraID); - } - public hasVisibleCameraID(cameraID: string): boolean { - return this._visibleConfigs.has(cameraID); + return this._cameras.has(cameraID); } public getCameraCount(): number { - return this._allConfigs.size; + return this._cameras.size; } public getVisibleCameraCount(): number { - return this._visibleConfigs.size; + return this.getVisibleCameraIDs().size; } - public getCameras(): CameraConfigs { - return this._allConfigs; + public getCameras(): Map { + return this._cameras; } - public getVisibleCameras(): CameraConfigs { - return this._visibleConfigs; + + public *getCameraConfigs( + cameraIDs?: Iterable, + ): IterableIterator { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + for (const [_cameraID, config] of this.getCameraConfigEntries(cameraIDs)) { + yield config; + } + } + public *getCameraConfigEntries( + cameraIDs?: Iterable, + ): IterableIterator<[string, CameraConfig]> { + for (const cameraID of cameraIDs ?? this._cameras.keys()) { + const config = this.getCameraConfig(cameraID); + + if (config) { + yield [cameraID, config]; + } + } } public getCameraIDs(): Set { - return new Set(this._allConfigs.keys()); + return new Set(this._cameras.keys()); } public getVisibleCameraIDs(): Set { - return new Set(this._visibleConfigs.keys()); + return this._getMatchingCameraIDs((camera) => !camera.getConfig().hide); } public getCameraConfigForMedia(media: ViewMedia): CameraConfig | null { @@ -89,7 +98,7 @@ export class CameraManagerStore implements CameraManagerReadOnlyConfigStore { } public getEngineForCameraID(cameraID: string): CameraManagerEngine | null { - return this._enginesByCamera.get(cameraID) ?? null; + return this._cameras.get(cameraID)?.getEngine() ?? null; } public getEnginesForCameraIDs( @@ -114,7 +123,42 @@ export class CameraManagerStore implements CameraManagerReadOnlyConfigStore { return this.getEngineForCameraID(media.getCameraID()); } - public getAllEngines(): CameraManagerEngine[] { - return [...this._enginesByType.values()]; + /** + * Get all cameras that depend on a given camera. + * @param cameraManager The camera manager. + * @param cameraID ID of the target camera. + * @returns A set of dependent cameraIDs or null (since JS sets guarantee order, + * the first item in the set is guaranteed to be the cameraID itself). + */ + public getAllDependentCameras(cameraID: string): Set { + const cameraIDs: Set = new Set(); + const getDependentCameras = (cameraID: string): void => { + const cameraConfig = this.getCameraConfig(cameraID); + if (cameraConfig) { + cameraIDs.add(cameraID); + const dependentCameras: Set = new Set(); + cameraConfig.dependencies.cameras.forEach((item) => dependentCameras.add(item)); + if (cameraConfig.dependencies.all_cameras) { + this.getCameraIDs().forEach((cameraID) => dependentCameras.add(cameraID)); + } + for (const eventCameraID of dependentCameras) { + if (!cameraIDs.has(eventCameraID)) { + getDependentCameras(eventCameraID); + } + } + } + }; + getDependentCameras(cameraID); + return cameraIDs; + } + + protected _getMatchingCameraIDs(func: (camera: Camera) => boolean): Set { + const output = new Set(); + for (const [cameraID, camera] of this._cameras.entries()) { + if (func(camera)) { + output.add(cameraID); + } + } + return output; } } diff --git a/src/camera-manager/types.ts b/src/camera-manager/types.ts index a9c6906e..9f4353bd 100644 --- a/src/camera-manager/types.ts +++ b/src/camera-manager/types.ts @@ -1,4 +1,4 @@ -import { CameraConfig, FrigateCardView } from '../config/types'; +import { FrigateCardView } from '../config/types'; import { ViewMedia } from '../view/media'; // ==== @@ -91,6 +91,14 @@ export interface MediaMetadata { what?: Set; } +export type PTZMovementType = 'relative' | 'continuous'; + +export interface PTZCapabilities { + panTilt?: PTZMovementType[]; + zoom?: PTZMovementType[]; + presets?: string[]; +} + interface BaseCapabilities { canFavoriteEvents: boolean; canFavoriteRecordings: boolean; @@ -102,8 +110,14 @@ interface BaseCapabilities { supportsTimeline: boolean; } -export type CameraManagerCapabilities = BaseCapabilities; -export type CameraManagerCameraCapabilities = BaseCapabilities; +export interface CameraManagerCapabilities extends BaseCapabilities { + supportsPTZ: boolean; +} + +export interface CameraManagerCameraCapabilities extends BaseCapabilities { + ptz?: PTZCapabilities; +} + export interface CameraManagerMediaCapabilities { canFavorite: boolean; canDownload: boolean; @@ -132,8 +146,6 @@ export interface CameraEndpoints { webrtcCard?: CameraEndpoint; } -export type CameraConfigs = Map; - export interface EngineOptions { useCache?: boolean; } diff --git a/src/card-controller/actions-manager.ts b/src/card-controller/actions-manager.ts index 37d50b5a..68a0572f 100644 --- a/src/card-controller/actions-manager.ts +++ b/src/card-controller/actions-manager.ts @@ -216,6 +216,22 @@ export class ActionsManager { .getViewManager() .setViewWithNewDisplayMode(frigateCardAction.display_mode); break; + case 'ptz': + const cameraID = this._api.getViewManager().getView()?.camera; + if (cameraID) { + this._api + .getCameraManager() + .executePTZAction(cameraID, frigateCardAction.ptz_action, { + phase: frigateCardAction.ptz_phase, + preset: frigateCardAction.ptz_preset, + }); + } + break; + case 'show_ptz': + this._api + .getViewManager() + .setViewWithNewContext({ live: { ptzVisible: frigateCardAction.show_ptz } }); + break; default: console.warn(`Frigate card received unknown card action: ${action}`); } diff --git a/src/card-controller/initialization-manager.ts b/src/card-controller/initialization-manager.ts index c6fa07da..1b630fc3 100644 --- a/src/card-controller/initialization-manager.ts +++ b/src/card-controller/initialization-manager.ts @@ -13,7 +13,7 @@ export enum InitializationAspect { export class InitializationManager { protected _api: CardInitializerAPI; - protected _initializer; + protected _initializer: Initializer; constructor(api: CardInitializerAPI, initializer?: Initializer) { this._api = api; @@ -21,11 +21,15 @@ export class InitializationManager { } public isInitializedMandatory(): boolean { - return this._initializer.isInitializedMultiple([ - InitializationAspect.LANGUAGES, - InitializationAspect.SIDE_LOAD_ELEMENTS, - InitializationAspect.CAMERAS, - ]); + return ( + this._initializer.isInitializedMultiple([ + InitializationAspect.LANGUAGES, + InitializationAspect.SIDE_LOAD_ELEMENTS, + InitializationAspect.CAMERAS, + ]) && + // If there's no view, re-initialize (e.g. config changes). + this._api.getViewManager().hasView() + ); } /** @@ -80,7 +84,6 @@ export class InitializationManager { } } - this._api.getCardElementManager().update(); return true; } diff --git a/src/card-controller/media-player-manager.ts b/src/card-controller/media-player-manager.ts index e6af01bc..2cda70be 100644 --- a/src/card-controller/media-player-manager.ts +++ b/src/card-controller/media-player-manager.ts @@ -25,10 +25,10 @@ export class MediaPlayerManager { return this._mediaPlayers.length > 0; } - public async initialize(): Promise { + public async initialize(): Promise { const hass = this._api.getHASSManager().getHASS(); if (!hass) { - return; + return false; } const isValidMediaPlayer = (entityID: string): boolean => { @@ -66,6 +66,8 @@ export class MediaPlayerManager { const entity = mediaPlayerEntities?.get(entityID); return !entity || !entity.hidden_by; }); + + return true; } public async stop(mediaPlayer: string): Promise { diff --git a/src/card-controller/microphone-manager.ts b/src/card-controller/microphone-manager.ts index d2d878b0..303a79c6 100644 --- a/src/card-controller/microphone-manager.ts +++ b/src/card-controller/microphone-manager.ts @@ -16,7 +16,7 @@ export class MicrophoneManager { this._api = api; } - public async connect(): Promise { + public async connect(): Promise { try { this._stream = await navigator.mediaDevices.getUserMedia({ audio: true, @@ -24,15 +24,19 @@ export class MicrophoneManager { }); } catch (e: unknown) { errorToConsole(e as Error); + this._stream = null; + this._api.getCardElementManager().update(); + return false; } this._setMute(); + return true; } public async disconnect(): Promise { this._stream?.getTracks().forEach((track) => track.stop()); - this._stream = undefined; + this._stream = undefined; this._api.getCardElementManager().update(); } diff --git a/src/card-controller/query-string-manager.ts b/src/card-controller/query-string-manager.ts index faf1f813..41840f84 100644 --- a/src/card-controller/query-string-manager.ts +++ b/src/card-controller/query-string-manager.ts @@ -1,5 +1,5 @@ import { FrigateCardCustomAction, FrigateCardViewAction } from '../config/types'; -import { createFrigateCardCustomAction } from '../utils/action.js'; +import { createFrigateCardCameraAction, createFrigateCardSimpleAction } from '../utils/action.js'; import { CardQueryStringAPI } from './types'; import { ViewManagerSetViewParameters } from './view-manager'; @@ -139,8 +139,7 @@ export class QueryStringManager { case 'camera_select': case 'live_substream_select': if (value) { - customAction = createFrigateCardCustomAction(action, { - camera: value, + customAction = createFrigateCardCameraAction(action, value, { cardID: cardID, }); } @@ -160,7 +159,7 @@ export class QueryStringManager { case 'snapshot': case 'snapshots': case 'timeline': - customAction = createFrigateCardCustomAction(action, { + customAction = createFrigateCardSimpleAction(action, { cardID: cardID, }); break; diff --git a/src/card-controller/triggers-manager.ts b/src/card-controller/triggers-manager.ts index 4850b01e..9e9ab222 100644 --- a/src/card-controller/triggers-manager.ts +++ b/src/card-controller/triggers-manager.ts @@ -28,8 +28,14 @@ export class TriggersManager { const now = new Date(); let triggerChanges = false; - const cameras = this._api.getCameraManager().getStore().getVisibleCameras(); - for (const [cameraID, config] of cameras?.entries()) { + const visibleCameraIDs = this._api + .getCameraManager() + .getStore() + .getVisibleCameraIDs(); + for (const [cameraID, config] of this._api + .getCameraManager() + .getStore() + .getCameraConfigEntries(visibleCameraIDs)) { const triggerEntities = config.triggers.entities; const diffs = getHassDifferences(hass, oldHass, triggerEntities, { stateOnly: true, diff --git a/src/card-controller/view-manager.ts b/src/card-controller/view-manager.ts index 39c95702..569cb323 100644 --- a/src/card-controller/view-manager.ts +++ b/src/card-controller/view-manager.ts @@ -1,7 +1,6 @@ import { ViewContext } from 'view'; import { FrigateCardConfig, FrigateCardView, ViewDisplayMode } from '../config/types'; import { View } from '../view/view'; -import { getAllDependentCameras } from '../utils/camera'; import { log } from '../utils/debug'; import { executeMediaQueryForView } from '../utils/media-to-view'; import { CardViewAPI } from './types'; @@ -28,6 +27,10 @@ export class ViewManager { return this._view; } + public hasView(): boolean { + return !!this.getView(); + } + public setView(view: View): void { this._setView(view); } @@ -255,7 +258,7 @@ export class ViewManager { protected _createViewWithNextStream(baseView: View): View { const dependencies = [ - ...getAllDependentCameras(this._api.getCameraManager(), baseView.camera), + ...this._api.getCameraManager().getStore().getAllDependentCameras(baseView.camera), ]; if (dependencies.length <= 1) { return baseView.clone(); diff --git a/src/card.ts b/src/card.ts index a759833d..527b710a 100644 --- a/src/card.ts +++ b/src/card.ts @@ -163,6 +163,12 @@ class FrigateCard extends LitElement { } protected shouldUpdate(): boolean { + // Always allow messages to render, as a message may be generated during + // initialization. + if (this._controller.getMessageManager().hasMessage()) { + return true; + } + if (!this._controller.getInitializationManager().isInitializedMandatory()) { this._controller.getInitializationManager().initializeMandatory(); return false; @@ -295,6 +301,12 @@ class FrigateCard extends LitElement { .view=${this._controller.getViewManager().getView()} .cameraManager=${cameraManager} .resolvedMediaCache=${this._controller.getResolvedMediaCache()} + .nonOverriddenConfig=${this._controller + .getConfigManager() + .getNonOverriddenConfig()} + .overriddenConfig=${this._controller.getConfigManager().getConfig()} + .cardWideConfig=${this._controller.getConfigManager().getCardWideConfig()} + .rawConfig=${this._controller.getConfigManager().getRawConfig()} .configManager=${this._controller.getConfigManager()} .conditionsManagerEpoch=${this._controller .getConditionsManager() diff --git a/src/components-lib/menu-controller.ts b/src/components-lib/menu-controller.ts index ac561641..56639fb6 100644 --- a/src/components-lib/menu-controller.ts +++ b/src/components-lib/menu-controller.ts @@ -1,24 +1,29 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import { StyleInfo } from 'lit/directives/style-map'; import { CameraManager } from '../camera-manager/manager'; +import { MediaPlayerManager } from '../card-controller/media-player-manager'; +import { MicrophoneManager } from '../card-controller/microphone-manager'; import { - FRIGATE_CARD_VIEWS_USER_SPECIFIED, FrigateCardConfig, FrigateCardCustomAction, - MenuItem + FRIGATE_CARD_VIEWS_USER_SPECIFIED, + MenuItem, } from '../config/types'; import { FRIGATE_BUTTON_MENU_ICON } from '../const'; import { localize } from '../localize/localize.js'; +import { MediaLoadedInfo } from '../types'; import { - MediaLoadedInfo, -} from '../types'; -import { View } from '../view/view'; -import { createFrigateCardCustomAction } from '../utils/action'; -import { getAllDependentCameras } from '../utils/camera'; -import { MediaPlayerManager } from '../card-controller/media-player-manager'; -import { MicrophoneManager } from '../card-controller/microphone-manager'; + createFrigateCardCameraAction, + createFrigateCardDisplayModeAction, + createFrigateCardMediaPlayerAction, + createFrigateCardShowPTZAction, + createFrigateCardSimpleAction, +} from '../utils/action'; import { getEntityIcon, getEntityTitle } from '../utils/ha'; +import { hasUsablePTZ } from '../utils/ptz'; import { hasSubstream } from '../utils/substream'; +import { View } from '../view/view'; + export interface MenuButtonControllerOptions { currentMediaLoadedInfo?: MediaLoadedInfo | null; showCameraUIButton?: boolean; @@ -55,15 +60,19 @@ export class MenuButtonController { view: View, options?: MenuButtonControllerOptions, ): MenuItem[] { - const visibleCameras = cameraManager.getStore().getVisibleCameras(); + const visibleCameraIDs = cameraManager.getStore().getVisibleCameraIDs(); const selectedCameraID = view.camera; const selectedCameraConfig = cameraManager .getStore() .getCameraConfig(selectedCameraID); - const allSelectedCameraIDs = getAllDependentCameras(cameraManager, selectedCameraID); + const allSelectedCameraIDs = cameraManager + .getStore() + .getAllDependentCameras(selectedCameraID); const selectedMedia = view.queryResults?.getSelectedResult(); - const cameraCapabilities = + const selectedCameraCapabilities = + cameraManager.getCameraCapabilities(selectedCameraID); + const aggregateCapabilities = cameraManager.getAggregateCameraCapabilities(allSelectedCameraIDs); const mediaCapabilities = selectedMedia ? cameraManager?.getMediaCapabilities(selectedMedia) @@ -79,30 +88,31 @@ export class MenuButtonController { title: localize('config.menu.buttons.frigate'), tap_action: config.menu?.style === 'hidden' - ? (createFrigateCardCustomAction('menu_toggle') as FrigateCardCustomAction) - : (createFrigateCardCustomAction('default') as FrigateCardCustomAction), - hold_action: createFrigateCardCustomAction( + ? (createFrigateCardSimpleAction('menu_toggle') as FrigateCardCustomAction) + : (createFrigateCardSimpleAction('default') as FrigateCardCustomAction), + hold_action: createFrigateCardSimpleAction( 'diagnostics', ) as FrigateCardCustomAction, }); - if (visibleCameras.size) { - const menuItems = Array.from(visibleCameras, ([cameraID, config]) => { - const action = createFrigateCardCustomAction('camera_select', { - camera: cameraID, - }); - const metadata = cameraManager.getCameraMetadata(cameraID); + if (visibleCameraIDs.size) { + const menuItems = Array.from( + cameraManager.getStore().getCameraConfigEntries(visibleCameraIDs), + ([cameraID, config]) => { + const action = createFrigateCardCameraAction('camera_select', cameraID); + const metadata = cameraManager.getCameraMetadata(cameraID); - return { - enabled: true, - icon: metadata?.icon, - entity: config.camera_entity, - state_color: true, - title: metadata?.title, - selected: selectedCameraID === cameraID, - ...(action && { tap_action: action }), - }; - }); + return { + enabled: true, + icon: metadata?.icon, + entity: config.camera_entity, + state_color: true, + title: metadata?.title, + selected: selectedCameraID === cameraID, + ...(action && { tap_action: action }), + }; + }, + ); buttons.push({ icon: 'mdi:video-switch', @@ -127,15 +137,16 @@ export class MenuButtonController { title: localize('config.menu.buttons.substreams'), ...config.menu.buttons.substreams, type: 'custom:frigate-card-menu-icon', - tap_action: createFrigateCardCustomAction( + tap_action: createFrigateCardSimpleAction( hasSubstream(view) ? 'live_substream_off' : 'live_substream_on', ) as FrigateCardCustomAction, }); } else if (dependencies.length > 2) { const menuItems = Array.from(dependencies, (cameraID) => { - const action = createFrigateCardCustomAction('live_substream_select', { - camera: cameraID, - }); + const action = createFrigateCardCameraAction( + 'live_substream_select', + cameraID, + ); const metadata = cameraManager.getCameraMetadata(cameraID) ?? undefined; const cameraConfig = cameraManager.getStore().getCameraConfig(cameraID); return { @@ -169,48 +180,48 @@ export class MenuButtonController { type: 'custom:frigate-card-menu-icon', title: localize('config.view.views.live'), style: view.is('live') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardCustomAction('live') as FrigateCardCustomAction, + tap_action: createFrigateCardSimpleAction('live') as FrigateCardCustomAction, }); - if (cameraCapabilities?.supportsClips) { + if (aggregateCapabilities?.supportsClips) { buttons.push({ icon: 'mdi:filmstrip', ...config.menu.buttons.clips, type: 'custom:frigate-card-menu-icon', title: localize('config.view.views.clips'), style: view?.is('clips') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardCustomAction('clips') as FrigateCardCustomAction, - hold_action: createFrigateCardCustomAction('clip') as FrigateCardCustomAction, + tap_action: createFrigateCardSimpleAction('clips') as FrigateCardCustomAction, + hold_action: createFrigateCardSimpleAction('clip') as FrigateCardCustomAction, }); } - if (cameraCapabilities?.supportsSnapshots) { + if (aggregateCapabilities?.supportsSnapshots) { buttons.push({ icon: 'mdi:camera', ...config.menu.buttons.snapshots, type: 'custom:frigate-card-menu-icon', title: localize('config.view.views.snapshots'), style: view?.is('snapshots') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardCustomAction( + tap_action: createFrigateCardSimpleAction( 'snapshots', ) as FrigateCardCustomAction, - hold_action: createFrigateCardCustomAction( + hold_action: createFrigateCardSimpleAction( 'snapshot', ) as FrigateCardCustomAction, }); } - if (cameraCapabilities?.supportsRecordings) { + if (aggregateCapabilities?.supportsRecordings) { buttons.push({ icon: 'mdi:album', ...config.menu.buttons.recordings, type: 'custom:frigate-card-menu-icon', title: localize('config.view.views.recordings'), style: view.is('recordings') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardCustomAction( + tap_action: createFrigateCardSimpleAction( 'recordings', ) as FrigateCardCustomAction, - hold_action: createFrigateCardCustomAction( + hold_action: createFrigateCardSimpleAction( 'recording', ) as FrigateCardCustomAction, }); @@ -222,19 +233,19 @@ export class MenuButtonController { type: 'custom:frigate-card-menu-icon', title: localize('config.view.views.image'), style: view?.is('image') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardCustomAction('image') as FrigateCardCustomAction, + tap_action: createFrigateCardSimpleAction('image') as FrigateCardCustomAction, }); // Don't show the timeline button unless there's at least one non-birdseye // camera with a Frigate camera name. - if (cameraCapabilities?.supportsTimeline) { + if (aggregateCapabilities?.supportsTimeline) { buttons.push({ icon: 'mdi:chart-gantt', ...config.menu.buttons.timeline, type: 'custom:frigate-card-menu-icon', title: localize('config.view.views.timeline'), style: view.is('timeline') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardCustomAction('timeline') as FrigateCardCustomAction, + tap_action: createFrigateCardSimpleAction('timeline') as FrigateCardCustomAction, }); } @@ -244,7 +255,7 @@ export class MenuButtonController { ...config.menu.buttons.download, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.download'), - tap_action: createFrigateCardCustomAction('download') as FrigateCardCustomAction, + tap_action: createFrigateCardSimpleAction('download') as FrigateCardCustomAction, }); } @@ -254,7 +265,7 @@ export class MenuButtonController { ...config.menu.buttons.camera_ui, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.camera_ui'), - tap_action: createFrigateCardCustomAction( + tap_action: createFrigateCardSimpleAction( 'camera_ui', ) as FrigateCardCustomAction, }); @@ -279,16 +290,16 @@ export class MenuButtonController { style: forbidden || muted ? {} : this._getEmphasizedStyle(true), ...(!forbidden && buttonType === 'momentary' && { - start_tap_action: createFrigateCardCustomAction( + start_tap_action: createFrigateCardSimpleAction( 'microphone_unmute', ) as FrigateCardCustomAction, - end_tap_action: createFrigateCardCustomAction( + end_tap_action: createFrigateCardSimpleAction( 'microphone_mute', ) as FrigateCardCustomAction, }), ...(!forbidden && buttonType === 'toggle' && { - tap_action: createFrigateCardCustomAction( + tap_action: createFrigateCardSimpleAction( options.microphoneManager.isMuted() ? 'microphone_unmute' : 'microphone_mute', @@ -303,7 +314,7 @@ export class MenuButtonController { ...config.menu.buttons.fullscreen, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.fullscreen'), - tap_action: createFrigateCardCustomAction( + tap_action: createFrigateCardSimpleAction( 'fullscreen', ) as FrigateCardCustomAction, style: options?.inFullscreenMode ? this._getEmphasizedStyle() : {}, @@ -315,7 +326,7 @@ export class MenuButtonController { ...config.menu.buttons.expand, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.expand'), - tap_action: createFrigateCardCustomAction('expand') as FrigateCardCustomAction, + tap_action: createFrigateCardSimpleAction('expand') as FrigateCardCustomAction, style: options?.inExpandedMode ? this._getEmphasizedStyle() : {}, }); @@ -328,14 +339,8 @@ export class MenuButtonController { .map((playerEntityID) => { const title = getEntityTitle(hass, playerEntityID) || playerEntityID; const state = hass.states[playerEntityID]; - const playAction = createFrigateCardCustomAction('media_player', { - media_player: playerEntityID, - media_player_action: 'play', - }); - const stopAction = createFrigateCardCustomAction('media_player', { - media_player: playerEntityID, - media_player_action: 'stop', - }); + const playAction = createFrigateCardMediaPlayerAction(playerEntityID, 'play'); + const stopAction = createFrigateCardMediaPlayerAction(playerEntityID, 'stop'); const disabled = !state || state.state === 'unavailable'; return { @@ -368,7 +373,7 @@ export class MenuButtonController { ...config.menu.buttons.play, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.play'), - tap_action: createFrigateCardCustomAction( + tap_action: createFrigateCardSimpleAction( paused ? 'play' : 'pause', ) as FrigateCardCustomAction, }); @@ -381,7 +386,7 @@ export class MenuButtonController { ...config.menu.buttons.mute, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.mute'), - tap_action: createFrigateCardCustomAction( + tap_action: createFrigateCardSimpleAction( muted ? 'unmute' : 'mute', ) as FrigateCardCustomAction, }); @@ -394,29 +399,39 @@ export class MenuButtonController { ...config.menu.buttons.screenshot, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.screenshot'), - tap_action: createFrigateCardCustomAction( + tap_action: createFrigateCardSimpleAction( 'screenshot', ) as FrigateCardCustomAction, }); } - if (view.supportsMultipleDisplayModes() && visibleCameras.size > 1) { + if (view.supportsMultipleDisplayModes() && visibleCameraIDs.size > 1) { const isGrid = view.isGrid(); - const action = createFrigateCardCustomAction('display_mode_select', { - display_mode: isGrid ? 'single' : 'grid', + buttons.push({ + icon: isGrid ? 'mdi:grid-off' : 'mdi:grid', + ...config.menu.buttons.display_mode, + style: isGrid ? this._getEmphasizedStyle() : {}, + type: 'custom:frigate-card-menu-icon', + title: isGrid + ? localize('display_modes.single') + : localize('display_modes.grid'), + tap_action: createFrigateCardDisplayModeAction(isGrid ? 'single' : 'grid'), + }); + } + + if (hasUsablePTZ(selectedCameraCapabilities, config.live.controls.ptz)) { + const isOn = + view.context?.live?.ptzVisible === false + ? false + : config.live.controls.ptz.mode === 'on'; + buttons.push({ + icon: 'mdi:pan', + ...config.menu.buttons.ptz, + style: isOn ? this._getEmphasizedStyle() : {}, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.ptz'), + tap_action: createFrigateCardShowPTZAction(!isOn), }); - /* istanbul ignore else: the else path cannot be reached -- @preserve */ - if (action) { - buttons.push({ - icon: isGrid ? 'mdi:grid-off' : 'mdi:grid', - ...config.menu.buttons.display_mode, - type: 'custom:frigate-card-menu-icon', - title: isGrid - ? localize('display_modes.single') - : localize('display_modes.grid'), - tap_action: action, - }); - } } const styledDynamicButtons = this._dynamicMenuButtons.map((button) => ({ diff --git a/src/components-lib/ptz-controller.ts b/src/components-lib/ptz-controller.ts new file mode 100644 index 00000000..1db58905 --- /dev/null +++ b/src/components-lib/ptz-controller.ts @@ -0,0 +1,170 @@ +import { HASSDomEvent, HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { CameraManager } from '../camera-manager/manager'; +import { + Actions, + ActionsConfig, + FrigateCardPTZAction, + FrigateCardPTZActions, + FrigateCardPTZConfig, + PTZAction, + PTZControlAction, + PTZ_CONTROL_ACTIONS, +} from '../config/types'; +import { + frigateCardHandleActionConfig, + getActionConfigGivenAction, +} from '../utils/action'; + +export class PTZController { + private _host: HTMLElement; + + private _config: FrigateCardPTZConfig | null = null; + private _hass: HomeAssistant | null = null; + private _cameraManager: CameraManager | null = null; + private _cameraID: string | null = null; + private _actions: FrigateCardPTZActions | null = null; + private _forceVisibility?: boolean; + + constructor(host: HTMLElement) { + this._host = host; + } + + public setConfig(config?: FrigateCardPTZConfig) { + this._config = config ?? null; + + this._host.setAttribute('data-orientation', config?.orientation ?? 'horizontal'); + this._host.setAttribute('data-position', config?.position ?? 'bottom-right'); + this._host.setAttribute( + 'style', + Object.entries(config?.style ?? {}) + .map(([k, v]) => `${k}:${v}`) + .join(';'), + ); + } + + public getConfig(): FrigateCardPTZConfig | null { + return this._config; + } + + public setHASS(hass?: HomeAssistant) { + this._hass = hass ?? null; + } + + public setCamera(cameraManager?: CameraManager, cameraID?: string) { + this._cameraManager = cameraManager ?? null; + this._cameraID = cameraID ?? null; + + this._calculateActions(); + } + + public setForceVisibility(forceVisibility?: boolean): void { + this._forceVisibility = forceVisibility; + } + + public handleAction( + ev: HASSDomEvent<{ action: string }>, + config?: ActionsConfig | null, + ): void { + // Nothing else has the configuration for this action, so don't let it + // propagate further. + ev.stopPropagation(); + + const interaction: string = ev.detail.action; + const action = getActionConfigGivenAction(interaction, config); + if (config && action && this._hass) { + frigateCardHandleActionConfig(this._host, this._hass, config, interaction, action); + } + } + + public getPTZActions(actionName: PTZControlAction): Actions | null { + const propertyName = 'actions_' + actionName; + return this._config?.[propertyName] ?? this._actions?.[propertyName] ?? null; + } + + private _hasAnyAction(): boolean { + for (const actionName of PTZ_CONTROL_ACTIONS) { + if ('actions_' + actionName in (this._actions ?? {})) { + return true; + } + } + return false; + } + + public shouldDisplay(): boolean { + return this._forceVisibility === false + ? false + : this._config?.mode === 'on' && this._hasAnyAction(); + } + + private _calculateActions(): void { + const getDefaultAction = ( + ptzAction: PTZAction, + options?: { + phase?: 'start' | 'stop'; + preset?: string; + }, + ): FrigateCardPTZAction => ({ + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: ptzAction, + ...(options?.phase && { ptz_phase: options.phase }), + ...(options?.preset && { ptz_preset: options.preset }), + }); + + const getDefaultActions = ( + ptzAction: PTZAction, + continuous: boolean, + preset?: string, + ): Actions => + continuous + ? { + start_tap_action: getDefaultAction(ptzAction, { + phase: 'start', + preset: preset, + }), + end_tap_action: getDefaultAction(ptzAction, { + phase: 'stop', + preset: preset, + }), + } + : { + tap_action: getDefaultAction(ptzAction, { preset: preset }), + }; + + if (!this._cameraManager || !this._cameraID) { + return; + } + + const ptzCapabilities = this._cameraManager.getCameraCapabilities( + this._cameraID, + )?.ptz; + + const defaultActions: FrigateCardPTZActions = {}; + const panTilt = ptzCapabilities?.panTilt; + const zoom = ptzCapabilities?.zoom; + const presets = ptzCapabilities?.presets; + + if (panTilt?.length) { + const continuous = panTilt.includes('continuous'); + defaultActions.actions_up = getDefaultActions('up', continuous); + defaultActions.actions_down = getDefaultActions('down', continuous); + defaultActions.actions_left = getDefaultActions('left', continuous); + defaultActions.actions_right = getDefaultActions('right', continuous); + } + + if (zoom?.length) { + const continuous = zoom.includes('continuous'); + defaultActions.actions_zoom_in = getDefaultActions('zoom_in', continuous); + defaultActions.actions_zoom_out = getDefaultActions('zoom_out', continuous); + } + + if (presets?.length) { + defaultActions.actions_home = getDefaultActions('preset', false, presets[0]); + } + + this._actions = { + ...defaultActions, + ...this._config, + }; + } +} diff --git a/src/components/carousel.ts b/src/components/carousel.ts index 453db5d1..6b223fad 100644 --- a/src/components/carousel.ts +++ b/src/components/carousel.ts @@ -69,7 +69,14 @@ export class FrigateCardCarousel extends LitElement { this.setAttribute('direction', this.direction); } - const destroyProperties = ['direction', 'dragFree', 'transitionEffect'] as const; + const destroyProperties = [ + 'direction', + 'dragEnabled', + 'dragFree', + 'loop', + 'plugins', + 'transitionEffect', + ] as const; if (destroyProperties.some((prop) => changedProps.has(prop))) { this._carousel?.destroy(); this._carousel = null; diff --git a/src/components/elements.ts b/src/components/elements.ts index 06d63dc7..d8d7b563 100644 --- a/src/components/elements.ts +++ b/src/components/elements.ts @@ -1,19 +1,18 @@ -import { HASSDomEvent, HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import { CSSResultGroup, + html, LitElement, PropertyValues, TemplateResult, - html, unsafeCSS, } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import { classMap } from 'lit/directives/class-map.js'; -import { actionHandler } from '../action-handler-directive.js'; import { - Actions, - ActionsConfig, - FrigateCardPTZConfig, + ConditionsManagerEpoch, + evaluateConditionViaEvent, +} from '../card-controller/conditions-manager.js'; +import { FrigateConditional, MenuIcon, MenuItem, @@ -23,19 +22,9 @@ import { PictureElements, } from '../config/types.js'; import { localize } from '../localize/localize.js'; -import ptzStyle from '../scss/elements-ptz.scss'; import elementsStyle from '../scss/elements.scss'; import { FrigateCardError } from '../types.js'; -import { - frigateCardHandleActionConfig, - frigateCardHasAction, - getActionConfigGivenAction, -} from '../utils/action.js'; -import { dispatchFrigateCardEvent } from '../utils/basic.js'; -import { - ConditionsManagerEpoch, - evaluateConditionViaEvent, -} from '../card-controller/conditions-manager.js'; +import { dispatchFrigateCardEvent, errorToConsole } from '../utils/basic.js'; import { dispatchFrigateCardErrorEvent } from './message.js'; /* A note on picture element rendering: @@ -122,7 +111,7 @@ export class FrigateCardElementsCore extends LitElement { try { element.setConfig(config); } catch (e) { - console.error(e); + errorToConsole(e as Error, console.error); throw new FrigateCardError(localize('error.invalid_elements_config')); } return element; @@ -342,114 +331,6 @@ export class FrigateCardElementsMenuSubmenu extends FrigateCardElementsBaseMenuI @customElement('frigate-card-menu-submenu-select') export class FrigateCardElementsMenuSubmenuSelect extends FrigateCardElementsBaseMenuIcon {} -@customElement('frigate-card-ptz') -export class FrigateCardPTZ extends LitElement { - @property({ attribute: false }) - public hass?: HomeAssistant; - - @state() - protected _config: FrigateCardPTZConfig | null = null; - - /** - * Set the card config. - * @param config The configuration. - */ - public setConfig(config: FrigateCardPTZConfig): void { - this._config = config; - } - - /** - * Called before each update. - */ - protected willUpdate(changedProps: PropertyValues): void { - if (changedProps.has('_config')) { - this.setAttribute('data-orientation', this._config?.orientation ?? 'vertical'); - } - } - - /** - * Handle a PTZ action. - * @param ev The actionHandler event. - * @param config The action configuration. - */ - protected _actionHandler( - ev: HASSDomEvent<{ action: string }>, - config?: ActionsConfig, - ): void { - // Nothing else has the configuration for this action, so don't let it - // propagate further. - ev.stopPropagation(); - - const interaction: string = ev.detail.action; - const action = getActionConfigGivenAction(interaction, config); - if (config && action && this.hass) { - frigateCardHandleActionConfig(this, this.hass, config, interaction, action); - } - } - - /** - * Render the elements. - * @returns A rendered template or void. - */ - protected render(): TemplateResult | void { - if (!this._config) { - return; - } - const renderIcon = ( - name: string, - icon: string, - actions?: Actions, - ): TemplateResult => { - const hasHold = frigateCardHasAction(actions?.hold_action); - const hasDoubleClick = frigateCardHasAction(actions?.double_tap_action); - const classes = { - [name]: true, - disabled: !actions, - }; - - return html` this._actionHandler(ev, actions)} - >`; - }; - - return html`
-
- ${renderIcon('right', 'mdi:arrow-right', this._config.actions_right)} - ${renderIcon('left', 'mdi:arrow-left', this._config.actions_left)} - ${renderIcon('up', 'mdi:arrow-up', this._config.actions_up)} - ${renderIcon('down', 'mdi:arrow-down', this._config.actions_down)} -
- ${this._config.actions_zoom_in || this._config.actions_zoom_out - ? html`
- ${renderIcon('zoom_in', 'mdi:plus', this._config.actions_zoom_in)} - ${renderIcon('zoom_out', 'mdi:minus', this._config.actions_zoom_out)} -
` - : html``} - ${this._config.actions_home - ? html` -
- ${renderIcon('home', 'mdi:home', this._config.actions_home)} -
- ` - : html``} -
`; - } - - /** - * Return compiled CSS styles. - */ - static get styles(): CSSResultGroup { - return unsafeCSS(ptzStyle); - } -} - declare global { interface HTMLElementTagNameMap { 'frigate-card-conditional': FrigateCardElementsConditional; @@ -459,6 +340,5 @@ declare global { 'frigate-card-menu-state-icon': FrigateCardElementsMenuStateIcon; 'frigate-card-menu-icon': FrigateCardElementsMenuIcon; 'frigate-card-elements-core': FrigateCardElementsCore; - 'frigate-card-ptz': FrigateCardPTZ; } } diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 1056387b..23d58d7c 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -13,7 +13,7 @@ import { ifDefined } from 'lit/directives/if-defined.js'; import { keyed } from 'lit/directives/keyed.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js'; import { CameraManager } from '../../camera-manager/manager.js'; -import { CameraConfigs, CameraEndpoints } from '../../camera-manager/types.js'; +import { CameraEndpoints } from '../../camera-manager/types.js'; import { ConditionsManagerEpoch, getOverriddenConfig, @@ -45,6 +45,7 @@ import { AutoLazyLoad } from '../../utils/embla/plugins/auto-lazy-load/auto-lazy import { AutoMediaActions } from '../../utils/embla/plugins/auto-media-actions/auto-media-actions.js'; import AutoMediaLoadedInfo from '../../utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.js'; import AutoSize from '../../utils/embla/plugins/auto-size/auto-size.js'; +import { getStateObjOrDispatchError } from '../../utils/get-state-obj.js'; import { dispatchExistingMediaLoadedInfoAsEvent, dispatchMediaUnloadedEvent, @@ -55,18 +56,20 @@ import { dispatchViewContextChangeEvent, View } from '../../view/view.js'; import { EmblaCarouselPlugins } from '../carousel.js'; import { renderMessage } from '../message.js'; import '../next-prev-control.js'; +import '../ptz.js'; +import { FrigateCardPTZ } from '../ptz.js'; import '../surround.js'; import '../title-control.js'; import { FrigateCardTitleControl, getDefaultTitleConfigForView, } from '../title-control.js'; -import { getStateObjOrDispatchError } from '../../utils/get-state-obj.js'; interface LiveViewContext { // A cameraID override (used for dependencies/substreams to force a different // camera to be live rather than the camera selected in the view). overrides?: Map; + ptzVisible?: boolean; } declare module 'view' { @@ -387,6 +390,10 @@ export class FrigateCardLiveCarousel extends LitElement { // Index between camera name and slide number. protected _cameraToSlide: Record = {}; protected _refTitleControl: Ref = createRef(); + protected _refPTZControl: Ref = createRef(); + + @state() + protected _mediaHasLoaded = false; protected _getTransitionEffect(): TransitionEffect { return ( @@ -449,25 +456,20 @@ export class FrigateCardLiveCarousel extends LitElement { } protected _getSlides(): [TemplateResult[], Record] { - let cameras: CameraConfigs | null = null; - if (this.viewFilterCameraID) { - const config = this.cameraManager - ?.getStore() - .getCameraConfig(this.viewFilterCameraID); - if (config) { - cameras = new Map([[this.viewFilterCameraID, config]]); - } - } else { - cameras = this.cameraManager?.getStore().getVisibleCameras() ?? null; - } - if (!cameras) { + if (!this.cameraManager) { return [[], {}]; } + const cameraIDs = this.viewFilterCameraID + ? new Set([this.viewFilterCameraID]) + : this.cameraManager.getStore().getVisibleCameraIDs(); + const slides: TemplateResult[] = []; const cameraToSlide: Record = {}; - for (const [cameraID, cameraConfig] of cameras) { + for (const [cameraID, cameraConfig] of this.cameraManager + .getStore() + .getCameraConfigEntries(cameraIDs)) { const liveCameraID = this.view?.context?.live?.overrides?.get(cameraID) ?? cameraID; const liveCameraConfig = @@ -487,9 +489,9 @@ export class FrigateCardLiveCarousel extends LitElement { } protected _setViewHandler(ev: CustomEvent): void { - const cameras = this.cameraManager?.getStore().getVisibleCameras(); - if (cameras && ev.detail.index !== this._getSelectedCameraIndex()) { - this._setViewCameraID(Array.from(cameras.keys())[ev.detail.index]); + const cameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); + if (cameraIDs && ev.detail.index !== this._getSelectedCameraIndex()) { + this._setViewCameraID([...cameraIDs][ev.detail.index]); } } @@ -575,22 +577,23 @@ export class FrigateCardLiveCarousel extends LitElement { } protected _getCameraIDsOfNeighbors(): [string | null, string | null] { - const cameras = this.cameraManager?.getStore().getVisibleCameras(); - if (this.viewFilterCameraID || !cameras || !this.view || !this.hass) { + const cameraIDs = this.cameraManager + ? [...this.cameraManager.getStore().getVisibleCameraIDs()] + : []; + if (this.viewFilterCameraID || cameraIDs.length <= 1 || !this.view || !this.hass) { return [null, null]; } const cameraID = this.viewFilterCameraID ?? this.view.camera; - const keys = Array.from(cameras.keys()); - const currentIndex = keys.indexOf(cameraID); + const currentIndex = cameraIDs.indexOf(cameraID); - if (currentIndex < 0 || cameras.size <= 1) { + if (currentIndex < 0) { return [null, null]; } return [ - keys[currentIndex > 0 ? currentIndex - 1 : cameras.size - 1], - keys[currentIndex + 1 < cameras.size ? currentIndex + 1 : 0], + cameraIDs[currentIndex > 0 ? currentIndex - 1 : cameraIDs.length - 1], + cameraIDs[currentIndex + 1 < cameraIDs.length ? currentIndex + 1 : 0], ]; } @@ -608,18 +611,19 @@ export class FrigateCardLiveCarousel extends LitElement { const hasMultipleCameras = slides.length > 1; const [prevID, nextID] = this._getCameraIDsOfNeighbors(); - const overrideCameraID = (cameraID: string): string => { + const getOverrideCameraID = (cameraID: string): string => { return this.view?.context?.live?.overrides?.get(cameraID) ?? cameraID; }; const cameraMetadataPrevious = prevID - ? this.cameraManager.getCameraMetadata(overrideCameraID(prevID)) + ? this.cameraManager.getCameraMetadata(getOverrideCameraID(prevID)) : null; + const cameraID = this.viewFilterCameraID ?? this.view.camera; const cameraMetadataCurrent = this.cameraManager.getCameraMetadata( - overrideCameraID(this.viewFilterCameraID ?? this.view.camera), + getOverrideCameraID(cameraID), ); const cameraMetadataNext = nextID - ? this.cameraManager.getCameraMetadata(overrideCameraID(nextID)) + ? this.cameraManager.getCameraMetadata(getOverrideCameraID(nextID)) : null; const titleConfig = getDefaultTitleConfigForView( @@ -656,6 +660,10 @@ export class FrigateCardLiveCarousel extends LitElement { if (this._refTitleControl.value) { this._refTitleControl.value.show(); } + this._mediaHasLoaded = true; + }} + @frigate-card:media:unloaded=${() => { + this._mediaHasLoaded = false; }} > + + ${cameraMetadataCurrent && titleConfig ? html`, ): Promise { - const cameras = this.cameraManager?.getStore().getVisibleCameras(); - if (!this.hass || !cameras || !this.cameraManager || !this.view) { + const visibleCameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); + if (!this.hass || !visibleCameraIDs || !this.cameraManager || !this.view) { return; } @@ -182,7 +182,7 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) { }; const cameraIDs = - getArrayValueAsSet(this._refCamera.value?.value) ?? new Set(cameras.keys()); + getArrayValueAsSet(this._refCamera.value?.value) ?? visibleCameraIDs; const mediaType = this._refMediaType.value?.value as | MediaFilterMediaType | undefined; @@ -268,9 +268,9 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) { protected willUpdate(changedProps: PropertyValues): void { if (changedProps.has('cameraManager')) { - const cameras = this.cameraManager?.getStore().getVisibleCameras(); + const cameras = this.cameraManager?.getStore().getVisibleCameraIDs(); if (cameras) { - this._cameraOptions = Array.from(cameras.keys()).map((cameraID) => ({ + this._cameraOptions = [...cameras].map((cameraID) => ({ value: cameraID, label: this.hass ? this.cameraManager?.getCameraMetadata(cameraID)?.title ?? '' @@ -319,8 +319,8 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) { protected _getDefaultsFromView(): MediaFilterCoreDefaults | null { const queries = this.view?.query?.getQueries(); - const cameras = this.cameraManager?.getStore().getVisibleCameras(); - if (!this.view || !queries || !cameras) { + const visibleCameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); + if (!this.view || !queries || !visibleCameraIDs) { return null; } @@ -337,7 +337,7 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) { ); // Special note: If all visible cameras are selected, this is the same as no // selector at all. - if (cameraIDSets.length === 1 && !isEqual(queries[0].cameraIDs, cameras)) { + if (cameraIDSets.length === 1 && !isEqual(queries[0].cameraIDs, visibleCameraIDs)) { cameraIDs = [...queries[0].cameraIDs]; } diff --git a/src/components/menu.ts b/src/components/menu.ts index c791fd07..bc19712b 100644 --- a/src/components/menu.ts +++ b/src/components/menu.ts @@ -97,7 +97,7 @@ export class FrigateCardMenu extends LitElement { * @param action The action to check. * @returns `true` if the action toggles the menu, `false` otherwise. */ - protected _isMenuToggleAction(action: ActionType | undefined): boolean { + protected _isMenuToggleAction(action: ActionType | null): boolean { // Determine if this action is a Frigate card action, if so handle it // internally. if (!action) { diff --git a/src/components/ptz.ts b/src/components/ptz.ts new file mode 100644 index 00000000..eed0d6e2 --- /dev/null +++ b/src/components/ptz.ts @@ -0,0 +1,131 @@ +import { HASSDomEvent, HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { + CSSResultGroup, + html, + LitElement, + PropertyValues, + TemplateResult, + unsafeCSS +} from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; +import { actionHandler } from '../action-handler-directive.js'; +import { CameraManager } from '../camera-manager/manager.js'; +import { PTZController } from '../components-lib/ptz-controller.js'; +import { Actions, FrigateCardPTZConfig } from '../config/types.js'; +import { localize } from '../localize/localize.js'; +import ptzStyle from '../scss/ptz.scss'; +import { frigateCardHasAction } from '../utils/action.js'; + +@customElement('frigate-card-ptz') +export class FrigateCardPTZ extends LitElement { + @property({ attribute: false }) + public hass?: HomeAssistant; + + @property({ attribute: false }) + public config?: FrigateCardPTZConfig; + + @property({ attribute: false }) + public cameraManager?: CameraManager; + + @property({ attribute: false }) + public cameraID?: string; + + @property({ attribute: false }) + public forceVisibility?: boolean; + + protected _controller = new PTZController(this); + + protected willUpdate(changedProps: PropertyValues): void { + if (changedProps.has('config')) { + this._controller.setConfig(this.config); + } + if (changedProps.has('hass')) { + this._controller.setHASS(this.hass); + } + if (changedProps.has('cameraManager') || changedProps.has('cameraID')) { + this._controller.setCamera(this.cameraManager, this.cameraID); + } + if (changedProps.has('forceVisibility')) { + this._controller.setForceVisibility(this.forceVisibility); + } + } + + protected render(): TemplateResult | void { + if (!this._controller.shouldDisplay()) { + return; + } + + const renderIcon = ( + name: string, + icon: string, + actions: Actions | null, + ): TemplateResult => { + const classes = { + [name]: true, + disabled: !actions, + }; + + return html`) => + this._controller.handleAction(ev, actions)} + >`; + }; + + const config = this._controller.getConfig(); + const actionsZoomIn = this._controller.getPTZActions('zoom_in'); + const actionsZoomOut = this._controller.getPTZActions('zoom_out'); + const actionsHome = this._controller.getPTZActions('home'); + + return html`
+ ${!config?.hide_pan_tilt + ? html`
+ ${renderIcon( + 'right', + 'mdi:arrow-right', + this._controller.getPTZActions('right'), + )} + ${renderIcon( + 'left', + 'mdi:arrow-left', + this._controller.getPTZActions('left'), + )} + ${renderIcon('up', 'mdi:arrow-up', this._controller.getPTZActions('up'))} + ${renderIcon( + 'down', + 'mdi:arrow-down', + this._controller.getPTZActions('down'), + )} +
` + : ''} + ${!config?.hide_zoom && (actionsZoomIn || actionsZoomOut) + ? html`
+ ${renderIcon('zoom_in', 'mdi:plus', actionsZoomIn)} + ${renderIcon('zoom_out', 'mdi:minus', actionsZoomOut)} +
` + : html``} + ${!config?.hide_home && actionsHome + ? html` +
${renderIcon('home', 'mdi:home', actionsHome)}
+ ` + : html``} +
`; + } + + static get styles(): CSSResultGroup { + return unsafeCSS(ptzStyle); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'frigate-card-ptz': FrigateCardPTZ; + } +} diff --git a/src/components/surround.ts b/src/components/surround.ts index e2efa85f..853f1a92 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -16,7 +16,6 @@ import { import basicBlockStyle from '../scss/basic-block.scss'; import { ClipsOrSnapshotsOrAll, ExtendedHomeAssistant } from '../types.js'; import { contentsChanged, dispatchFrigateCardEvent } from '../utils/basic.js'; -import { getAllDependentCameras } from '../utils/camera.js'; import { changeViewToRecentEventsForCameraAndDependents } from '../utils/media-to-view'; import { View } from '../view/view.js'; import './surround-basic.js'; @@ -140,7 +139,8 @@ export class FrigateCardSurround extends LitElement { if (this.view?.is('live')) { return this.view.isGrid() ? this.cameraManager?.getStore().getVisibleCameraIDs() ?? null - : getAllDependentCameras(this.cameraManager, this.view.camera); + : this.cameraManager?.getStore().getAllDependentCameras(this.view.camera) ?? + null; } if (this.view.isViewerView()) { return this.view.query?.getQueryCameraIDs() ?? null; diff --git a/src/components/thumbnail-carousel.ts b/src/components/thumbnail-carousel.ts index 6ab71228..3237464e 100644 --- a/src/components/thumbnail-carousel.ts +++ b/src/components/thumbnail-carousel.ts @@ -15,6 +15,7 @@ import { ExtendedHomeAssistant } from '../types.js'; import { stopEventFromActivatingCardWideActions } from '../utils/action.js'; import { dispatchFrigateCardEvent } from '../utils/basic.js'; import { CarouselDirection } from '../utils/embla/carousel-controller.js'; +import AutoSize from '../utils/embla/plugins/auto-size/auto-size.js'; import { MediaQueriesResults } from '../view/media-queries-results'; import { View } from '../view/view.js'; import './carousel.js'; @@ -136,6 +137,7 @@ export class FrigateCardThumbnailCarousel extends LitElement { return html` diff --git a/src/components/views.ts b/src/components/views.ts index da524511..8fbf9af8 100644 --- a/src/components/views.ts +++ b/src/components/views.ts @@ -9,10 +9,17 @@ import { import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { CameraManager } from '../camera-manager/manager.js'; -import { ConditionsManagerEpoch, getOverridesByKey } from '../card-controller/conditions-manager.js'; +import { + ConditionsManagerEpoch, + getOverridesByKey, +} from '../card-controller/conditions-manager.js'; +import { + CardWideConfig, + FrigateCardConfig, + RawFrigateCardConfig, +} from '../config/types.js'; import viewsStyle from '../scss/views.scss'; import { ExtendedHomeAssistant } from '../types.js'; -import { ConfigManager } from '../card-controller/config-manager.js'; import { ResolvedMediaCache } from '../utils/ha/resolved-media.js'; import { View } from '../view/view.js'; import './surround.js'; @@ -32,7 +39,16 @@ export class FrigateCardViews extends LitElement { public cameraManager?: CameraManager; @property({ attribute: false }) - public configManager?: ConfigManager; + public nonOverriddenConfig?: FrigateCardConfig; + + @property({ attribute: false }) + public overriddenConfig?: FrigateCardConfig; + + @property({ attribute: false }) + public cardWideConfig?: CardWideConfig; + + @property({ attribute: false }) + public rawConfig?: RawFrigateCardConfig; @property({ attribute: false }) public resolvedMediaCache?: ResolvedMediaCache; @@ -94,21 +110,21 @@ export class FrigateCardViews extends LitElement { return ( // Special case: Never preload for diagnostics -- we want that to be as // minimal as possible. - !!this.configManager?.getConfig()?.live.preload && !this.view?.is('diagnostics') + !!this.overriddenConfig?.live.preload && !this.view?.is('diagnostics') ); } protected render(): TemplateResult | void { - const config = this.configManager?.getConfig(); - const nonOverriddenConfig = this.configManager?.getNonOverriddenConfig(); - const cardWideConfig = this.configManager?.getCardWideConfig(); - const rawConfig = this.configManager?.getRawConfig(); - // Only essential items should be added to the below list, since we want the // overall views pane to render in ~almost all cases (e.g. for a camera // initialization error to display, `view` and `cameraConfig` may both be // undefined, but we still want to render). - if (!this.hass || !config || !nonOverriddenConfig || !cardWideConfig) { + if ( + !this.hass || + !this.overriddenConfig || + !this.nonOverriddenConfig || + !this.cardWideConfig + ) { return html``; } @@ -122,17 +138,17 @@ export class FrigateCardViews extends LitElement { }; const thumbnailConfig = this.view?.is('live') - ? config.live.controls.thumbnails + ? this.overriddenConfig.live.controls.thumbnails : this.view?.isViewerView() - ? config.media_viewer.controls.thumbnails + ? this.overriddenConfig.media_viewer.controls.thumbnails : this.view?.is('timeline') - ? config.timeline.controls.thumbnails + ? this.overriddenConfig.timeline.controls.thumbnails : undefined; const miniTimelineConfig = this.view?.is('live') - ? config.live.controls.timeline + ? this.overriddenConfig.live.controls.timeline : this.view?.isViewerView() - ? config.media_viewer.controls.timeline + ? this.overriddenConfig.media_viewer.controls.timeline : undefined; const cameraConfig = this.view @@ -144,16 +160,16 @@ export class FrigateCardViews extends LitElement { .hass=${this.hass} .view=${this.view} .fetchMedia=${this.view?.is('live') - ? config.live.controls.thumbnails.media + ? this.overriddenConfig.live.controls.thumbnails.media : undefined} .thumbnailConfig=${!this.hide ? thumbnailConfig : undefined} .timelineConfig=${!this.hide ? miniTimelineConfig : undefined} .cameraManager=${this.cameraManager} - .cardWideConfig=${cardWideConfig} + .cardWideConfig=${this.cardWideConfig} > ${!this.hide && this.view?.is('image') && cameraConfig ? html` ` : ``} @@ -176,10 +192,10 @@ export class FrigateCardViews extends LitElement { ` @@ -188,16 +204,16 @@ export class FrigateCardViews extends LitElement { ? html` ` : ``} ${!this.hide && this.view?.is('diagnostics') ? html` ` : ``} @@ -213,12 +229,15 @@ export class FrigateCardViews extends LitElement { diff --git a/src/config-mgmt.ts b/src/config-mgmt.ts index 7d484646..fc81696a 100644 --- a/src/config-mgmt.ts +++ b/src/config-mgmt.ts @@ -3,7 +3,7 @@ import get from 'lodash-es/get'; import isEqual from 'lodash-es/isEqual'; import set from 'lodash-es/set'; import unset from 'lodash-es/unset'; -import { RawFrigateCardConfig } from './config/types'; +import { RawFrigateCardConfig, RawFrigateCardConfigArray } from './config/types'; import { CONF_CAMERAS, CONF_CAMERAS_GLOBAL_IMAGE, @@ -303,7 +303,7 @@ export const deleteTransform = function (_value: unknown): number | null | undef }; // ************************************************************************* -// Upgrade Related Functions: Specific Transforms +// Upgrade Related Functions: Specific Transforms / Upgraders // ************************************************************************* /** @@ -360,6 +360,71 @@ const frigateUIActionTransform = (data: unknown): boolean => { return false; }; +/** + * Transform element PTZ to native live PTZ. + * @param data Input data. + * @returns `true` if the configuration was modified. + */ +const upgradePTZElementsToLive = function (): (data: unknown) => boolean { + return function (data: unknown): boolean { + if ( + typeof data !== 'object' || + !data || + !(CONF_ELEMENTS in data) || + !Array.isArray(data[CONF_ELEMENTS]) + ) { + return false; + } + + let foundPTZ = false; + const movePTZ = (element: RawFrigateCardConfig): void => { + if (!foundPTZ) { + if (!get(data, 'live.controls.ptz')) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const { type: _, ...newPTZ } = element; + set(data, 'live.controls.ptz', newPTZ); + } + foundPTZ = true; + } + }; + + const processElements = ( + elements: RawFrigateCardConfigArray, + ): RawFrigateCardConfigArray => { + const newElements: RawFrigateCardConfigArray = []; + for (const element of elements) { + if (element['type'] === 'custom:frigate-card-ptz') { + movePTZ(element); + } else if ( + (element['type'] === 'conditional' || + element['type'] === 'custom:frigate-card-conditional') && + Array.isArray(element['elements']) + ) { + const newConditionalElements = processElements(element['elements']); + if (newConditionalElements.length) { + element['elements'] = newConditionalElements; + newElements.push(element); + } + } else { + newElements.push(element); + } + } + return newElements; + }; + + const newElements = processElements(data[CONF_ELEMENTS]); + + if (foundPTZ) { + if (newElements.length) { + data[CONF_ELEMENTS] = newElements; + } else { + delete data[CONF_ELEMENTS]; + } + } + return foundPTZ; + }; +}; + const UPGRADES = [ // v4.0.0 -> v4.1.0 upgradeArrayOfObjects( @@ -408,4 +473,5 @@ const UPGRADES = [ typeof data === 'object' && data ? data : {}, ); }, + upgradePTZElementsToLive(), ]; diff --git a/src/config/types.ts b/src/config/types.ts index a6140877..a8aceed8 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -65,6 +65,19 @@ const MEDIA_ACTION_POSITIVE_CONDITIONS = [ export type AutoUnmuteCondition = (typeof MEDIA_ACTION_POSITIVE_CONDITIONS)[number]; export type AutoPlayCondition = (typeof MEDIA_ACTION_POSITIVE_CONDITIONS)[number]; +const PTZ_BASE_ACTIONS = ['left', 'right', 'up', 'down', 'zoom_in', 'zoom_out'] as const; + +// PTZ actions as used by the PTZ control (includes a 'home' button). +export const PTZ_CONTROL_ACTIONS = [...PTZ_BASE_ACTIONS, 'home'] as const; +export type PTZControlAction = (typeof PTZ_CONTROL_ACTIONS)[number]; + +// PTZ actions as used by the camera manager (includes generic presets). +const PTZ_ACTIONS = [...PTZ_BASE_ACTIONS, 'preset'] as const; +export type PTZAction = (typeof PTZ_ACTIONS)[number]; + +const PTZ_PHASES = ['start', 'stop'] as const; +export type PTZPhase = (typeof PTZ_PHASES)[number]; + // ************************************************************************* // View Display Mode // ************************************************************************* @@ -201,32 +214,22 @@ const FRIGATE_CARD_GENERAL_ACTIONS = [ 'camera_ui', 'default', 'diagnostics', - 'expand', 'download', + 'expand', 'fullscreen', - 'menu_toggle', - 'mute', - 'live_substream_on', 'live_substream_off', + 'live_substream_on', + 'menu_toggle', 'microphone_mute', 'microphone_unmute', - 'play', + 'mute', 'pause', + 'play', 'screenshot', 'unmute', ] as const; export type FrigateCardGeneralAction = (typeof FRIGATE_CARD_GENERAL_ACTIONS)[number]; -const FRIGATE_CARD_ACTIONS = [ - ...FRIGATE_CARD_VIEWS_USER_SPECIFIED, - ...FRIGATE_CARD_GENERAL_ACTIONS, - 'camera_select', - 'live_substream_select', - 'media_player', - 'display_mode_select', -] as const; -export type FrigateCardAction = (typeof FRIGATE_CARD_ACTIONS)[number]; - const frigateCardViewActionSchema = frigateCardCustomActionsBaseSchema.extend({ frigate_card_action: z.enum(FRIGATE_CARD_VIEWS_USER_SPECIFIED), }); @@ -240,9 +243,6 @@ const frigateCardCameraSelectActionSchema = frigateCardCustomActionsBaseSchema.e frigate_card_action: z.literal('camera_select'), camera: z.string(), }); -export type FrigateCardCameraSelectAction = z.infer< - typeof frigateCardCameraSelectActionSchema ->; const frigateCardLiveDependencySelectActionSchema = frigateCardCustomActionsBaseSchema.extend({ @@ -263,6 +263,19 @@ const frigateCardViewDisplayModeActionSchema = frigateCardCustomActionsBaseSchem }, ); +const frigateCardPTZActionSchema = frigateCardCustomActionsBaseSchema.extend({ + frigate_card_action: z.literal('ptz'), + ptz_action: z.enum(PTZ_ACTIONS), + ptz_phase: z.enum(PTZ_PHASES).optional(), + ptz_preset: z.string().optional(), +}); +export type FrigateCardPTZAction = z.infer; + +const frigateCardShowPTZActionSchema = frigateCardCustomActionsBaseSchema.extend({ + frigate_card_action: z.literal('show_ptz'), + show_ptz: z.boolean(), +}); + export const frigateCardCustomActionSchema = z.union([ frigateCardViewActionSchema, frigateCardGeneralActionSchema, @@ -270,6 +283,8 @@ export const frigateCardCustomActionSchema = z.union([ frigateCardLiveDependencySelectActionSchema, frigateCardMediaPlayerActionSchema, frigateCardViewDisplayModeActionSchema, + frigateCardPTZActionSchema, + frigateCardShowPTZActionSchema, ]); export type FrigateCardCustomAction = z.infer; @@ -481,53 +496,8 @@ export const frigateConditionalSchema = z.object({ conditions: frigateCardConditionSchema, elements: z.lazy(() => pictureElementsSchema), }); - export type FrigateConditional = z.infer; -// ************************************************************************* -// Custom Element Configuration: PTZ -// ************************************************************************* - -export const frigateCardPTZSchema = z.preprocess( - // To avoid lots of YAML duplication, provide an easy way to just specify the - // service data as actions for each PTZ icon, and it will be preprocessed into - // the full form. This also provides compatability with the AlexIT/WebRTC PTZ - // configuration. - (data) => { - if (!data || typeof data !== 'object' || !data['service']) { - return data; - } - const out = { ...data }; - ['left', 'right', 'up', 'down', 'zoom_in', 'zoom_out', 'home'].forEach((name) => { - if (`data_${name}` in data && !(`actions_${name}` in data)) { - out[`actions_${name}`] = { - tap_action: { - action: 'call-service', - service: data['service'], - data: data[`data_${name}`], - }, - }; - delete out[`data_${name}`]; - } - }); - return out; - }, - z.object({ - type: z.literal('custom:frigate-card-ptz'), - style: z.object({}).passthrough().optional(), - orientation: z.enum(['vertical', 'horizontal']).default('vertical').optional(), - service: z.string().optional(), - actions_left: actionsBaseSchema.optional(), - actions_right: actionsBaseSchema.optional(), - actions_up: actionsBaseSchema.optional(), - actions_down: actionsBaseSchema.optional(), - actions_zoom_in: actionsBaseSchema.optional(), - actions_zoom_out: actionsBaseSchema.optional(), - actions_home: actionsBaseSchema.optional(), - }), -); -export type FrigateCardPTZConfig = z.infer; - // ************************************************************************* // Custom Element Configuration: Stock Picture Elements + Custom // ************************************************************************* @@ -540,7 +510,6 @@ const pictureElementSchema = z.union([ menuSubmenuSchema, menuSubmenuSelectSchema, frigateConditionalSchema, - frigateCardPTZSchema, stateBadgeIconSchema, stateIconSchema, stateLabelSchema, @@ -818,6 +787,73 @@ const jsmpegConfigSchema = z.object({ .optional(), }); +const frigateCardPTZActions = z.object({ + actions_left: actionsBaseSchema.optional(), + actions_right: actionsBaseSchema.optional(), + actions_up: actionsBaseSchema.optional(), + actions_down: actionsBaseSchema.optional(), + actions_zoom_in: actionsBaseSchema.optional(), + actions_zoom_out: actionsBaseSchema.optional(), + actions_home: actionsBaseSchema.optional(), +}); +export type FrigateCardPTZActions = z.infer; + +const livePTZControlsDefaults = { + orientation: 'horizontal' as const, + mode: 'on' as const, + hide_pan_tilt: false, + hide_zoom: false, + hide_home: false, + position: 'bottom-right' as const, +}; + +export const frigateCardPTZSchema = z.preprocess( + // To avoid lots of YAML duplication, provide an easy way to just specify the + // service data as actions for each PTZ icon, and it will be preprocessed into + // the full form. This also provides compatability with the AlexIT/WebRTC PTZ + // configuration. + (data) => { + if (!data || typeof data !== 'object' || !data['service']) { + return data; + } + const out = { ...data }; + PTZ_CONTROL_ACTIONS.forEach((name) => { + if (`data_${name}` in data && !(`actions_${name}` in data)) { + out[`actions_${name}`] = { + tap_action: { + action: 'call-service', + service: data['service'], + data: data[`data_${name}`], + }, + }; + delete out[`data_${name}`]; + } + }); + return out; + }, + frigateCardPTZActions.extend({ + // TODO strip from config update + // type: z.literal('custom:frigate-card-ptz'), + + mode: z.enum(['off', 'on']).default(livePTZControlsDefaults.mode), + position: z + .enum(['top-left', 'top-right', 'bottom-left', 'bottom-right']) + .default(livePTZControlsDefaults.position), + + orientation: z + .enum(['vertical', 'horizontal']) + .default(livePTZControlsDefaults.orientation), + + hide_pan_tilt: z.boolean().default(livePTZControlsDefaults.hide_pan_tilt), + hide_zoom: z.boolean().default(livePTZControlsDefaults.hide_zoom), + hide_home: z.boolean().default(livePTZControlsDefaults.hide_home), + + service: z.string().optional(), + style: z.object({}).passthrough().optional(), + }), +); +export type FrigateCardPTZConfig = z.infer; + const liveThumbnailControlsDefaults = { ...thumbnailControlsDefaults, media: 'all' as const, @@ -842,6 +878,7 @@ const liveConfigDefault = { size: 48, style: 'chevrons' as const, }, + ptz: livePTZControlsDefaults, thumbnails: liveThumbnailControlsDefaults, timeline: miniTimelineConfigDefault, }, @@ -872,6 +909,7 @@ const liveOverridableConfigSchema = z ), }) .default(liveConfigDefault.controls.next_previous), + ptz: frigateCardPTZSchema.default(liveConfigDefault.controls.ptz), thumbnails: livethumbnailsControlSchema.default( liveConfigDefault.controls.thumbnails, ), @@ -934,7 +972,7 @@ const castConfigDefault = { method: 'standard' as const, }; -export const castSchema = z.object({ +const castSchema = z.object({ method: z.enum(['standard', 'dashboard']).default(castConfigDefault.method).optional(), dashboard: z .object({ @@ -1170,6 +1208,7 @@ const menuConfigDefault = { recordings: hiddenButtonDefault, screenshot: hiddenButtonDefault, display_mode: visibleButtonDefault, + ptz: hiddenButtonDefault, }, button_size: 40, }; @@ -1220,6 +1259,7 @@ const menuConfigSchema = z display_mode: visibleButtonSchema.default( menuConfigDefault.buttons.display_mode, ), + ptz: hiddenButtonSchema.default(menuConfigDefault.buttons.ptz), }) .default(menuConfigDefault.buttons), button_size: z.number().min(BUTTON_SIZE_MIN).default(menuConfigDefault.button_size), @@ -1411,13 +1451,13 @@ const overridesSchema = z // Automation Configuration // ************************************************************************* -const automationActionSchema = actionSchema.array().optional(); +const automationActionSchema = actionSchema.array(); export type AutomationActions = z.infer; const automationSchema = z.object({ conditions: frigateCardConditionSchema, - actions: automationActionSchema, - actions_not: automationActionSchema, + actions: automationActionSchema.optional(), + actions_not: automationActionSchema.optional(), }); export type Automation = z.infer; diff --git a/src/const.ts b/src/const.ts index 98097196..d2a2a41b 100644 --- a/src/const.ts +++ b/src/const.ts @@ -98,7 +98,7 @@ export const CONF_MEDIA_GALLERY_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL = export const CONF_MEDIA_GALLERY_CONTROLS_THUMBNAILS_SIZE = `${CONF_MEDIA_GALLERY}.controls.thumbnails.size` as const; -export const CONF_MEDIA_VIEWER = 'media_viewer' as const; +const CONF_MEDIA_VIEWER = 'media_viewer' as const; export const CONF_MEDIA_VIEWER_AUTO_PLAY = `${CONF_MEDIA_VIEWER}.auto_play` as const; export const CONF_MEDIA_VIEWER_AUTO_PAUSE = `${CONF_MEDIA_VIEWER}.auto_pause` as const; export const CONF_MEDIA_VIEWER_AUTO_MUTE = `${CONF_MEDIA_VIEWER}.auto_mute` as const; @@ -169,6 +169,17 @@ export const CONF_LIVE_CONTROLS_NEXT_PREVIOUS_STYLE = `${CONF_LIVE}.controls.next_previous.style` as const; export const CONF_LIVE_CONTROLS_NEXT_PREVIOUS_SIZE = `${CONF_LIVE}.controls.next_previous.size` as const; +export const CONF_LIVE_CONTROLS_PTZ_HIDE_HOME = + `${CONF_LIVE}.controls.ptz.hide_home` as const; +export const CONF_LIVE_CONTROLS_PTZ_HIDE_PAN_TILT = + `${CONF_LIVE}.controls.ptz.hide_pan_tilt` as const; +export const CONF_LIVE_CONTROLS_PTZ_HIDE_ZOOM = + `${CONF_LIVE}.controls.ptz.hide_zoom` as const; +export const CONF_LIVE_CONTROLS_PTZ_MODE = `${CONF_LIVE}.controls.ptz.mode` as const; +export const CONF_LIVE_CONTROLS_PTZ_ORIENTATION = + `${CONF_LIVE}.controls.ptz.orientation` as const; +export const CONF_LIVE_CONTROLS_PTZ_POSITION = + `${CONF_LIVE}.controls.ptz.position` as const; export const CONF_LIVE_CONTROLS_THUMBNAILS_MEDIA = `${CONF_LIVE}.controls.thumbnails.media` as const; export const CONF_LIVE_CONTROLS_THUMBNAILS_MODE = @@ -257,17 +268,10 @@ export const CONF_MENU_STYLE = `${CONF_MENU}.style` as const; export const CONF_MENU_BUTTON_SIZE = `${CONF_MENU}.button_size` as const; export const CONF_MENU_BUTTONS = `${CONF_MENU}.buttons` as const; -export const CONF_MENU_BUTTONS_CAMERAS = `${CONF_MENU}.buttons.cameras` as const; -export const CONF_MENU_BUTTONS_CLIPS = `${CONF_MENU}.buttons.clips` as const; -export const CONF_MENU_BUTTONS_DOWNLOAD = `${CONF_MENU}.buttons.download` as const; export const CONF_MENU_BUTTONS_FRIGATE = `${CONF_MENU}.buttons.frigate` as const; export const CONF_MENU_BUTTONS_CAMERA_UI = `${CONF_MENU}.buttons.camera_ui` as const; -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; const CONF_DIMENSIONS = 'dimensions' as const; diff --git a/src/editor.ts b/src/editor.ts index 294b0dd3..d981a550 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -80,6 +80,12 @@ import { CONF_LIVE_CONTROLS_BUILTIN, CONF_LIVE_CONTROLS_NEXT_PREVIOUS_SIZE, CONF_LIVE_CONTROLS_NEXT_PREVIOUS_STYLE, + CONF_LIVE_CONTROLS_PTZ_HIDE_HOME, + CONF_LIVE_CONTROLS_PTZ_HIDE_PAN_TILT, + CONF_LIVE_CONTROLS_PTZ_HIDE_ZOOM, + CONF_LIVE_CONTROLS_PTZ_MODE, + CONF_LIVE_CONTROLS_PTZ_ORIENTATION, + CONF_LIVE_CONTROLS_PTZ_POSITION, CONF_LIVE_CONTROLS_THUMBNAILS_MEDIA, CONF_LIVE_CONTROLS_THUMBNAILS_MODE, CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DETAILS, @@ -211,6 +217,7 @@ const MENU_CAMERAS_WEBRTC_CARD = 'cameras.webrtc_card'; const MENU_IMAGE_LAYOUT = 'image.layout'; const MENU_LIVE_CONTROLS = 'live.controls'; const MENU_LIVE_CONTROLS_NEXT_PREVIOUS = 'live.controls.next_previous'; +const MENU_LIVE_CONTROLS_PTZ = 'live.controls.ptz'; const MENU_LIVE_CONTROLS_THUMBNAILS = 'live.controls.thumbnails'; const MENU_LIVE_CONTROLS_TIMELINE = 'live.controls.timeline'; const MENU_LIVE_CONTROLS_TITLE = 'live.controls.title'; @@ -575,6 +582,45 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor { value: 'dashboard', label: localize('config.cameras.cast.methods.dashboard') }, ]; + protected _ptzModes: EditorSelectOption[] = [ + { value: '', label: '' }, + { value: 'on', label: localize('config.live.controls.ptz.modes.on') }, + { value: 'off', label: localize('config.live.controls.ptz.modes.off') }, + { value: 'auto', label: localize('config.live.controls.ptz.modes.auto') }, + ]; + + protected _ptzOrientations: EditorSelectOption[] = [ + { value: '', label: '' }, + { + value: 'vertical', + label: localize('config.live.controls.ptz.orientations.vertical'), + }, + { + value: 'horizontal', + label: localize('config.live.controls.ptz.orientations.horizontal'), + }, + ]; + + protected _ptzPositions: EditorSelectOption[] = [ + { value: '', label: '' }, + { + value: 'top-left', + label: localize('config.live.controls.ptz.positions.top-left'), + }, + { + value: 'top-right', + label: localize('config.live.controls.ptz.positions.top-right'), + }, + { + value: 'bottom-left', + label: localize('config.live.controls.ptz.positions.bottom-left'), + }, + { + value: 'bottom-right', + label: localize('config.live.controls.ptz.positions.bottom-right'), + }, + ]; + public setConfig(config: RawFrigateCardConfig): void { // Note: This does not use Zod to parse the configuration, so it may be // partially or completely invalid. It's more useful to have a partially @@ -1886,6 +1932,8 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderMenuButton('play') /* */} ${this._renderMenuButton('mute') /* */} ${this._renderMenuButton('screenshot')} + ${this._renderMenuButton('display_mode')} + ${this._renderMenuButton('ptz')}
` : ''} @@ -1981,6 +2029,47 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS, this._defaults.live.controls.timeline.show_recordings, )} + ${this._putInSubmenu( + MENU_LIVE_CONTROLS_PTZ, + true, + 'config.live.controls.ptz.editor_label', + { name: 'mdi:pan' }, + html` + ${this._renderOptionSelector( + CONF_LIVE_CONTROLS_PTZ_MODE, + this._ptzModes, + )} + ${this._renderOptionSelector( + CONF_LIVE_CONTROLS_PTZ_POSITION, + this._ptzPositions, + )} + ${this._renderOptionSelector( + CONF_LIVE_CONTROLS_PTZ_ORIENTATION, + this._ptzOrientations, + )} + ${this._renderSwitch( + CONF_LIVE_CONTROLS_PTZ_HIDE_PAN_TILT, + this._defaults.live.controls.ptz.hide_pan_tilt, + { + label: localize('config.live.controls.ptz.hide_pan_tilt'), + }, + )} + ${this._renderSwitch( + CONF_LIVE_CONTROLS_PTZ_HIDE_ZOOM, + this._defaults.live.controls.ptz.hide_pan_tilt, + { + label: localize('config.live.controls.ptz.hide_zoom'), + }, + )} + ${this._renderSwitch( + CONF_LIVE_CONTROLS_PTZ_HIDE_HOME, + this._defaults.live.controls.ptz.hide_home, + { + label: localize('config.live.controls.ptz.hide_home'), + }, + )} + `, + )} `, )} ${this._renderMediaLayout( diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index de13a746..64b2c503 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -233,7 +233,31 @@ "auto_play": "Automatically play live cameras", "auto_unmute": "Automatically unmute live cameras", "controls": { - "editor_label": "Live Controls" + "editor_label": "Live Controls", + "ptz": { + "editor_label": "PTZ", + "mode": "Mode", + "modes": { + "on": "On", + "off": "Off", + "auto": "Automatic" + }, + "orientation": "Orientation", + "orientations": { + "vertical": "Vertical", + "horizontal": "Horizontal" + }, + "position": "Position", + "positions": { + "top-left": "Top left", + "top-right": "Top right", + "bottom-left": "Bottom left", + "bottom-right": "Bottom right" + }, + "hide_zoom": "Hide zoom control", + "hide_pan_tilt": "Hide pan & tilt control", + "hide_home": "Hide home control" + } }, "draggable": "Live cameras view can be dragged/swiped", "layout": "Live Layout", @@ -301,6 +325,7 @@ "mute": "Mute / Unmute", "play": "Play / Pause", "priority": "Priority", + "ptz": "Show PTZ controls", "recordings": "Recordings", "screenshot": "Screenshot", "snapshots": "Snapshots", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index cbefd91d..e4af3d0f 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -233,7 +233,31 @@ "auto_play": "Gioca automaticamente le telecamere dal vivo", "auto_unmute": "Riattiva automaticamente l'audio delle telecamere live", "controls": { - "editor_label": "Controlli dal vivo" + "editor_label": "Controlli dal vivo", + "ptz": { + "editor_label": "", + "mode": "", + "modes": { + "on": "", + "off": "", + "auto": "" + }, + "orientation": "", + "orientations": { + "vertical": "", + "horizontal": "" + }, + "position": "", + "positions": { + "top-left": "", + "top-right": "", + "bottom-left": "", + "bottom-right": "" + }, + "hide_zoom": "", + "hide_pan_tilt": "", + "hide_home": "" + } }, "draggable": "Il Visualizzatore eventi può essere trascinato oppure puoi scorrere", "layout": "Disposizione dal vivo", @@ -299,6 +323,7 @@ "mute": "", "play": "", "priority": "Priorità", + "ptz": "", "screenshot": "", "snapshots": "Istantanee", "substreams": "Flusso/i secondario/i", @@ -523,4 +548,4 @@ }, "select_date": "Scegli la data" } -} \ No newline at end of file +} diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index aa8ecc21..4028931f 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -233,7 +233,31 @@ "auto_play": "Reproduzir câmeras ao vivo automaticamente", "auto_unmute": "Ativar automaticamente o som das câmeras ao vivo", "controls": { - "editor_label": "Controles da visualização ao vivo" + "editor_label": "Controles da visualização ao vivo", + "ptz": { + "editor_label": "", + "mode": "", + "modes": { + "on": "", + "off": "", + "auto": "" + }, + "orientation": "", + "orientations": { + "vertical": "", + "horizontal": "" + }, + "position": "", + "positions": { + "top-left": "", + "top-right": "", + "bottom-left": "", + "bottom-right": "" + }, + "hide_zoom": "", + "hide_pan_tilt": "", + "hide_home": "" + } }, "draggable": "A visualização ao vivo das câmeras pode ser arrastada/deslizada", "layout": "Layout dinâmico", @@ -300,6 +324,7 @@ "mute": "", "play": "", "priority": "Prioridade", + "ptz": "", "recordings": "Gravações", "screenshot": "", "snapshots": "Instantâneos", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index df256cee..daebd3ed 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -226,7 +226,31 @@ "auto_play": "Reproduzir câmeras ao vivo automaticamente", "auto_unmute": "Ativar automaticamente o som das câmeras ao vivo", "controls": { - "editor_label": "Controles da visualização ao vivo" + "editor_label": "Controles da visualização ao vivo", + "ptz": { + "editor_label": "", + "mode": "", + "modes": { + "on": "", + "off": "", + "auto": "" + }, + "orientation": "", + "orientations": { + "vertical": "", + "horizontal": "" + }, + "position": "", + "positions": { + "top-left": "", + "top-right": "", + "bottom-left": "", + "bottom-right": "" + }, + "hide_zoom": "", + "hide_pan_tilt": "", + "hide_home": "" + } }, "draggable": "A visualização ao vivo das câmeras pode ser arrastada/deslizada", "layout": "layout", @@ -292,6 +316,7 @@ "mute": "", "play": "", "priority": "Prioridade", + "ptz": "", "screenshot": "", "snapshots": "Instantâneos", "substreams": "substreams", diff --git a/src/localize/localize.ts b/src/localize/localize.ts index 2ecac5dd..76e67a72 100644 --- a/src/localize/localize.ts +++ b/src/localize/localize.ts @@ -52,7 +52,7 @@ export function getLanguage(hass?: HomeAssistant): string { /** * Load required languages. */ -export const loadLanguages = async (hass: HomeAssistant): Promise => { +export const loadLanguages = async (hass: HomeAssistant): Promise => { const lang = getLanguage(hass); if (lang === 'it') { languages[lang] = await import('./languages/it.json'); @@ -65,6 +65,7 @@ export const loadLanguages = async (hass: HomeAssistant): Promise => { if (lang) { frigateCardLanguage = lang; } + return true; }; /** diff --git a/src/patches/ha-hls-player.ts b/src/patches/ha-hls-player.ts index 56f12e7f..89c6920f 100644 --- a/src/patches/ha-hls-player.ts +++ b/src/patches/ha-hls-player.ts @@ -12,11 +12,11 @@ import { css, CSSResultGroup, html, TemplateResult, unsafeCSS } from 'lit'; import { customElement } from 'lit/decorators.js'; import { query } from 'lit/decorators/query.js'; -import { screenshotMedia } from '../utils/screenshot.js'; import { dispatchErrorMessageEvent } from '../components/message.js'; import liveHAComponentsStyle from '../scss/live-ha-components.scss'; import { FrigateCardMediaPlayer } from '../types.js'; import { mayHaveAudio } from '../utils/audio.js'; +import { errorToConsole } from '../utils/basic.js'; import { dispatchMediaLoadedEvent, dispatchMediaPauseEvent, @@ -26,6 +26,7 @@ import { import { hideMediaControlsTemporarily, MEDIA_LOAD_CONTROLS_HIDE_SECONDS, setControlsOnVideo } from '../utils/media.js'; +import { screenshotMedia } from '../utils/screenshot.js'; customElements.whenDefined('ha-hls-player').then(() => { @customElement('frigate-card-ha-hls-player') @@ -97,7 +98,7 @@ customElements.whenDefined('ha-hls-player').then(() => { // Use native Frigate card error handling for fatal errors. return dispatchErrorMessageEvent(this, this._error); } else { - console.error(this._error); + errorToConsole(this._error, console.error); } } return html` diff --git a/src/scss/live-image.scss b/src/scss/live-image.scss index cec0abb6..e3950e11 100644 --- a/src/scss/live-image.scss +++ b/src/scss/live-image.scss @@ -9,6 +9,5 @@ ha-icon { position: absolute; top: 10px; right: 10px; - opacity: 50%; - color: white; + color: var(--primary-color); } diff --git a/src/scss/elements-ptz.scss b/src/scss/ptz.scss similarity index 91% rename from src/scss/elements-ptz.scss rename to src/scss/ptz.scss index 34bfbb4a..b21e62bb 100644 --- a/src/scss/elements-ptz.scss +++ b/src/scss/ptz.scss @@ -1,7 +1,7 @@ -// Modified from / inspired by: +// Inspired by: // https://github.com/AlexxIT/WebRTC/blob/master/custom_components/webrtc/www/webrtc-camera.js :host { - position: relative; + position: absolute; width: fit-content; height: fit-content; @@ -9,6 +9,19 @@ --frigate-card-ptz-icon-size: 24px; } +:host([data-position$='-left']) { + left: 5%; +} +:host([data-position$='-right']) { + right: 5%; +} +:host([data-position^='top-']) { + top: 5%; +} +:host([data-position^='bottom-']) { + bottom: 5%; +} + /***************** * Main Containers *****************/ diff --git a/src/utils/action.ts b/src/utils/action.ts index 8b0e60d4..27bb17c6 100644 --- a/src/utils/action.ts +++ b/src/utils/action.ts @@ -7,10 +7,10 @@ import { import { Actions, ActionType, - FrigateCardAction, FrigateCardCustomAction, frigateCardCustomActionSchema, - ViewDisplayMode, + FrigateCardGeneralAction, + FrigateCardUserSpecifiedView, } from '../config/types.js'; /** @@ -30,59 +30,75 @@ export function convertActionToFrigateCardCustomAction( return parseResult.success ? parseResult.data : null; } -/** - * Create a Frigate card custom action. - * @param action The Frigate card action string (e.g. 'fullscreen') - * @returns A FrigateCardCustomAction for that action string or null. - */ -export function createFrigateCardCustomAction( - action: FrigateCardAction, - args?: { +export function createFrigateCardSimpleAction( + action: FrigateCardGeneralAction | FrigateCardUserSpecifiedView, + options?: { cardID?: string; - camera?: string; - media_player?: string; - media_player_action?: 'play' | 'stop'; - display_mode?: ViewDisplayMode; }, ): FrigateCardCustomAction | null { - if (action === 'camera_select' || action === 'live_substream_select') { - if (!args?.camera) { - return null; - } - return { - action: 'fire-dom-event', - frigate_card_action: action, - camera: args.camera as string, - ...(args.cardID && { card_id: args.cardID }), - }; - } - if (action === 'media_player') { - if (!args?.media_player || !args.media_player_action) { - return null; - } - return { - action: 'fire-dom-event', - frigate_card_action: action, - media_player: args.media_player, - media_player_action: args.media_player_action, - ...(args.cardID && { card_id: args.cardID }), - }; - } - if (action === 'display_mode_select') { - if (!args?.display_mode) { - return null; - } - return { - action: 'fire-dom-event', - frigate_card_action: action, - display_mode: args?.display_mode, - ...(args.cardID && { card_id: args.cardID }), - }; - } return { action: 'fire-dom-event', frigate_card_action: action, - ...(args?.cardID && { card_id: args.cardID }), + ...(options?.cardID && { card_id: options.cardID }), + }; +} + +export function createFrigateCardCameraAction( + action: 'camera_select' | 'live_substream_select', + camera: string, + options?: { + cardID?: string; + }, +): FrigateCardCustomAction { + return { + action: 'fire-dom-event', + frigate_card_action: action, + camera: camera, + ...(options?.cardID && { card_id: options.cardID }), + }; +} + +export function createFrigateCardMediaPlayerAction( + mediaPlayer: string, + mediaPlayerAction: 'play' | 'stop', + options?: { + cardID?: string; + }, +): FrigateCardCustomAction { + return { + action: 'fire-dom-event', + frigate_card_action: 'media_player', + media_player: mediaPlayer, + media_player_action: mediaPlayerAction, + ...(options?.cardID && { card_id: options.cardID }), + }; +} + +export function createFrigateCardDisplayModeAction( + displayMode: 'single' | 'grid', + options?: { + cardID?: string; + }, +): FrigateCardCustomAction { + return { + action: 'fire-dom-event', + frigate_card_action: 'display_mode_select', + display_mode: displayMode, + ...(options?.cardID && { card_id: options.cardID }), + }; +} + +export function createFrigateCardShowPTZAction( + showPTZ: boolean, + options?: { + cardID?: string; + }, +): FrigateCardCustomAction { + return { + action: 'fire-dom-event', + frigate_card_action: 'show_ptz', + show_ptz: showPTZ, + ...(options?.cardID && { card_id: options.cardID }), }; } @@ -94,10 +110,10 @@ export function createFrigateCardCustomAction( */ export function getActionConfigGivenAction( interaction?: string, - config?: Actions, -): ActionType | ActionType[] | undefined { + config?: Actions | null, +): ActionType | ActionType[] | null { if (!interaction || !config) { - return undefined; + return null; } if (interaction == 'tap' && config.tap_action) { return config.tap_action; @@ -110,7 +126,7 @@ export function getActionConfigGivenAction( } else if (interaction == 'start_tap' && config.start_tap_action) { return config.start_tap_action; } - return undefined; + return null; } /** @@ -132,7 +148,7 @@ export const frigateCardHandleActionConfig = ( entity?: string; }, action: string, - actionConfig?: ActionType | ActionType[], + actionConfig?: ActionType | ActionType[] | null, ): boolean => { // Only allow a tap action to use a default non-config (the more-info config). if (actionConfig || action == 'tap') { @@ -149,7 +165,7 @@ export const frigateCardHandleAction = ( camera_image?: string; entity?: string; }, - actionConfig: ActionType | ActionType[] | undefined, + actionConfig?: ActionType | ActionType[] | null, ): void => { // ActionConfig vs ActionType: // * There is a slight typing (but not functional) difference between @@ -161,7 +177,12 @@ export const frigateCardHandleAction = ( handleActionConfig(node, hass, config, action as ActionConfig | undefined), ); } else { - handleActionConfig(node, hass, config, actionConfig as ActionConfig | undefined); + handleActionConfig( + node, + hass, + config, + (actionConfig ?? undefined) as ActionConfig | undefined, + ); } }; diff --git a/src/utils/camera.ts b/src/utils/camera.ts index a72a507a..0a561890 100644 --- a/src/utils/camera.ts +++ b/src/utils/camera.ts @@ -1,4 +1,3 @@ -import { CameraManager } from '../camera-manager/manager.js'; import { CameraConfig, RawFrigateCardConfig } from '../config/types.js'; /** @@ -30,48 +29,3 @@ export function getCameraID( '' ); } - -/** - * Get all cameras that depend on a given camera. - * @param cameraManager The camera manager. - * @param cameraID ID of the target camera. - * @returns A set of dependent cameraIDs or null (since JS sets guarantee order, - * the first item in the set is guaranteed to be the cameraID itself). - */ -export function getAllDependentCameras( - cameraManager: CameraManager, - cameraID: string, -): Set; -export function getAllDependentCameras( - cameraManager?: CameraManager, - cameraID?: string, -): Set | null; -export function getAllDependentCameras( - cameraManager?: CameraManager, - cameraID?: string, -): Set | null { - if (!cameraManager || !cameraID) { - return null; - } - const cameras = cameraManager.getStore().getCameras(); - - const cameraIDs: Set = new Set(); - const getDependentCameras = (cameraID: string): void => { - const cameraConfig = cameras.get(cameraID); - if (cameraConfig) { - cameraIDs.add(cameraID); - const dependentCameras: Set = new Set(); - cameraConfig.dependencies.cameras.forEach((item) => dependentCameras.add(item)); - if (cameraConfig.dependencies.all_cameras) { - cameras.forEach((_, key) => dependentCameras.add(key)); - } - for (const eventCameraID of dependentCameras) { - if (!cameraIDs.has(eventCameraID)) { - getDependentCameras(eventCameraID); - } - } - } - }; - getDependentCameras(cameraID); - return cameraIDs; -} diff --git a/src/utils/initializer/initializer.ts b/src/utils/initializer/initializer.ts index a8033865..ef3ea8b7 100644 --- a/src/utils/initializer/initializer.ts +++ b/src/utils/initializer/initializer.ts @@ -5,7 +5,7 @@ enum InitializationState { INITIALIZED = 'initialized', } -type InitializationCallback = () => Promise; +type InitializationCallback = () => Promise; /** * Manages initialization state & calling initializers. @@ -43,8 +43,11 @@ export class Initializer { if (state !== InitializationState.INITIALIZING) { if (initializer) { this._state.set(aspect, InitializationState.INITIALIZING); - await initializer(); - this._state.set(aspect, InitializationState.INITIALIZED); + if (await initializer()) { + this._state.set(aspect, InitializationState.INITIALIZED); + } else { + this.uninitialize(aspect); + } } else { this._state.set(aspect, InitializationState.INITIALIZED); } diff --git a/src/utils/media-to-view.ts b/src/utils/media-to-view.ts index ac3bc44c..bfd58328 100644 --- a/src/utils/media-to-view.ts +++ b/src/utils/media-to-view.ts @@ -14,7 +14,6 @@ import { import { MediaQueriesResults } from '../view/media-queries-results'; import { View } from '../view/view'; import { errorToConsole } from './basic'; -import { getAllDependentCameras } from './camera.js'; type ResultSelectType = 'latest' | 'time' | 'none'; @@ -32,7 +31,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( ): Promise => { const cameraIDs = options?.allCameras ? cameraManager.getStore().getVisibleCameraIDs() - : getAllDependentCameras(cameraManager, view.camera); + : cameraManager.getStore().getAllDependentCameras(view.camera); if (!cameraIDs.size) { return; } @@ -98,7 +97,7 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( ): Promise => { const cameraIDs = options?.allCameras ? cameraManager.getStore().getVisibleCameraIDs() - : getAllDependentCameras(cameraManager, view.camera); + : cameraManager.getStore().getAllDependentCameras(view.camera); if (!cameraIDs.size) { return; } diff --git a/src/utils/ptz.ts b/src/utils/ptz.ts new file mode 100644 index 00000000..6d31e8a2 --- /dev/null +++ b/src/utils/ptz.ts @@ -0,0 +1,14 @@ +import { CameraManagerCameraCapabilities } from '../camera-manager/types'; +import { FrigateCardPTZConfig, PTZ_CONTROL_ACTIONS } from '../config/types'; + +export const hasUsablePTZ = ( + capabilities: CameraManagerCameraCapabilities | null, + config: FrigateCardPTZConfig, +): boolean => { + for (const actionName of PTZ_CONTROL_ACTIONS) { + if ('actions_' + actionName in config) { + return true; + } + } + return !!capabilities?.ptz; +}; diff --git a/src/view/view.ts b/src/view/view.ts index e2a1de01..a402b3ad 100644 --- a/src/view/view.ts +++ b/src/view/view.ts @@ -5,6 +5,7 @@ import { dispatchFrigateCardEvent } from '../utils/basic.js'; import { MediaQueries } from './media-queries'; import { MediaQueriesClassifier } from './media-queries-classifier.js'; import { MediaQueriesResults } from './media-queries-results'; +import merge from 'lodash-es/merge'; interface ViewEvolveParameters { view?: FrigateCardView; @@ -177,7 +178,7 @@ export class View { * @returns This view. */ public mergeInContext(context?: ViewContext): View { - this.context = { ...this.context, ...context }; + this.context = merge(this.context ?? {}, this.context, context); return this; } diff --git a/tests/camera-manager/camera.test.ts b/tests/camera-manager/camera.test.ts new file mode 100644 index 00000000..358203d8 --- /dev/null +++ b/tests/camera-manager/camera.test.ts @@ -0,0 +1,57 @@ +import { describe, expect, it } from 'vitest'; +import { Camera } from '../../src/camera-manager/camera.js'; +import { GenericCameraManagerEngine } from '../../src/camera-manager/generic/engine-generic.js'; +import { createCameraCapabilities, createCameraConfig } from '../test-utils.js'; + +describe('Camera', () => { + it('should get config', async () => { + const config = createCameraConfig(); + const camera = new Camera( + config, + new GenericCameraManagerEngine(), + createCameraCapabilities(), + ); + expect(camera.getConfig()).toBe(config); + }); + + it('should get capabilities', async () => { + const capabilities = createCameraCapabilities(); + const camera = new Camera( + createCameraConfig(), + new GenericCameraManagerEngine(), + capabilities, + ); + expect(camera.getCapabilities()).toBe(capabilities); + }); + + it('should get engine', async () => { + const engine = new GenericCameraManagerEngine(); + const camera = new Camera(createCameraConfig(), engine, createCameraCapabilities()); + expect(camera.getEngine()).toBe(engine); + }); + + it('should set and get id', async () => { + const config = createCameraConfig(); + const camera = new Camera( + config, + new GenericCameraManagerEngine(), + createCameraCapabilities(), + ); + camera.setID('foo'); + expect(camera.getID()).toBe('foo'); + expect(camera.getConfig().id).toBe('foo'); + }); + + it('should throw without id', async () => { + const config = createCameraConfig(); + const camera = new Camera( + config, + new GenericCameraManagerEngine(), + createCameraCapabilities(), + ); + expect(() => camera.getID()).toThrowError( + 'Could not determine camera id for the following ' + + "camera, may need to set 'id' parameter manually", + ); + }); +}); diff --git a/tests/camera-manager/frigate/engine-frigate.test.ts b/tests/camera-manager/frigate/engine-frigate.test.ts index 81f7ebd1..61acff83 100644 --- a/tests/camera-manager/frigate/engine-frigate.test.ts +++ b/tests/camera-manager/frigate/engine-frigate.test.ts @@ -9,6 +9,7 @@ import { FrigateEvent, eventSchema } from '../../../src/camera-manager/frigate/t import { CameraConfig, FrigateCardView, + PTZAction, RawFrigateCardConfig, } from '../../../src/config/types'; import { ViewMedia } from '../../../src/view/media'; @@ -392,3 +393,101 @@ describe('getCameraEndpoints', () => { }); }); }); + +describe('executePTZAction', () => { + describe('preset', () => { + it('should reject without preset argument', () => { + const hass = createHASS(); + const cameraConfig = createCameraConfig({ camera_entity: 'camera.office' }); + + createEngine().executePTZAction(hass, cameraConfig, 'preset'); + + expect(hass.callService).not.toBeCalled(); + }); + + it('should succeed', () => { + const hass = createHASS(); + const cameraConfig = createCameraConfig({ camera_entity: 'camera.office' }); + + createEngine().executePTZAction(hass, cameraConfig, 'preset', { + preset: 'preset-foo', + }); + + expect(hass.callService).toBeCalledWith('frigate', 'ptz', { + entity_id: 'camera.office', + action: 'preset', + argument: 'preset-foo', + }); + }); + }); + + describe('zoom', () => { + describe.each([['zoom_in' as const], ['zoom_out' as const]])( + '%s', + (actionName: PTZAction) => { + it('start', () => { + const hass = createHASS(); + const cameraConfig = createCameraConfig({ camera_entity: 'camera.office' }); + + createEngine().executePTZAction(hass, cameraConfig, actionName); + + expect(hass.callService).toBeCalledWith('frigate', 'ptz', { + entity_id: 'camera.office', + action: 'zoom', + argument: actionName === 'zoom_in' ? 'in' : 'out', + }); + }); + + it('stop', () => { + const hass = createHASS(); + const cameraConfig = createCameraConfig({ camera_entity: 'camera.office' }); + + createEngine().executePTZAction(hass, cameraConfig, actionName, { + phase: 'stop', + }); + + expect(hass.callService).toBeCalledWith('frigate', 'ptz', { + entity_id: 'camera.office', + action: 'stop', + }); + }); + }, + ); + }); + + describe('move', () => { + describe.each([ + ['left' as const], + ['right' as const], + ['up' as const], + ['down' as const], + ])('%s', (actionName: PTZAction) => { + it('start', () => { + const hass = createHASS(); + const cameraConfig = createCameraConfig({ camera_entity: 'camera.office' }); + + createEngine().executePTZAction(hass, cameraConfig, actionName); + + expect(hass.callService).toBeCalledWith('frigate', 'ptz', { + entity_id: 'camera.office', + action: 'move', + argument: actionName, + }); + }); + + it('stop', () => { + const hass = createHASS(); + const cameraConfig = createCameraConfig({ camera_entity: 'camera.office' }); + + createEngine().executePTZAction(hass, cameraConfig, actionName, { + phase: 'stop', + }); + + expect(hass.callService).toBeCalledWith('frigate', 'ptz', { + entity_id: 'camera.office', + action: 'stop', + }); + }); + }); + }); +}); diff --git a/tests/camera-manager/frigate/requests.test.ts b/tests/camera-manager/frigate/requests.test.ts new file mode 100644 index 00000000..461c1df2 --- /dev/null +++ b/tests/camera-manager/frigate/requests.test.ts @@ -0,0 +1,218 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { + getEvents, + getEventSummary, + getPTZInfo, + getRecordingSegments, + getRecordingsSummary, + retainEvent, +} from '../../../src/camera-manager/frigate/requests'; +import { + EventSummary, + eventSummarySchema, + FrigateEvent, + frigateEventsSchema, + ptzInfoSchema, + recordingSegmentsSchema, + recordingSummarySchema, + retainResultSchema, +} from '../../../src/camera-manager/frigate/types'; +import { RecordingSegment } from '../../../src/camera-manager/types'; +import { homeAssistantWSRequest } from '../../../src/utils/ha'; +import { createFrigateEvent, createHASS } from '../../test-utils'; + +vi.mock('../../../src/utils/ha'); + +describe('frigate requests', () => { + afterEach(() => { + vi.resetAllMocks(); + }); + it('should get recordings summary', async () => { + const recordingSummary = { + events: 0, + hours: [], + day: new Date(), + }; + const hass = createHASS(); + vi.mocked(homeAssistantWSRequest).mockResolvedValue(recordingSummary); + expect(await getRecordingsSummary(hass, 'clientID', 'camera.office')).toBe( + recordingSummary, + ); + expect(homeAssistantWSRequest).toBeCalledWith( + hass, + recordingSummarySchema, + expect.objectContaining({ + type: 'frigate/recordings/summary', + instance_id: 'clientID', + camera: 'camera.office', + timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + }), + true, + ); + }); + + it('should get recordings segments', async () => { + const recordingSegments: RecordingSegment[] = [ + { + start_time: 0, + end_time: 1, + id: 'foo', + }, + ]; + const hass = createHASS(); + vi.mocked(homeAssistantWSRequest).mockResolvedValue(recordingSegments); + expect( + await getRecordingSegments(hass, { + instance_id: 'clientID', + camera: 'camera.office', + after: 1, + before: 0, + }), + ).toBe(recordingSegments); + expect(homeAssistantWSRequest).toBeCalledWith( + hass, + recordingSegmentsSchema, + expect.objectContaining({ + type: 'frigate/recordings/get', + instance_id: 'clientID', + camera: 'camera.office', + after: 1, + before: 0, + }), + true, + ); + }); + + describe('should retain event', async () => { + it('successfully', async () => { + vi.mocked(homeAssistantWSRequest).mockResolvedValue({ + success: true, + message: 'success', + }); + + const hass = createHASS(); + retainEvent(hass, 'clientID', 'eventID', true); + + expect(homeAssistantWSRequest).toBeCalledWith( + hass, + retainResultSchema, + expect.objectContaining({ + type: 'frigate/event/retain', + instance_id: 'clientID', + event_id: 'eventID', + retain: true, + }), + true, + ); + }); + + it('unsuccessfully', async () => { + vi.mocked(homeAssistantWSRequest).mockResolvedValue({ + success: false, + message: 'failed', + }); + + const hass = createHASS(); + await expect(retainEvent(hass, 'clientID', 'eventID', true)).rejects.toThrowError( + /Could not retain event/, + ); + expect(homeAssistantWSRequest).toBeCalledWith( + hass, + retainResultSchema, + expect.objectContaining({ + type: 'frigate/event/retain', + instance_id: 'clientID', + event_id: 'eventID', + retain: true, + }), + true, + ); + }); + }); + + it('should get events', async () => { + const events: FrigateEvent[] = [createFrigateEvent()]; + const hass = createHASS(); + vi.mocked(homeAssistantWSRequest).mockResolvedValue(events); + expect( + await getEvents(hass, { + instance_id: 'clientID', + cameras: ['camera.office'], + labels: ['person'], + zones: ['zone'], + after: 0, + before: 1, + limit: 10, + has_clip: true, + has_snapshot: true, + favorites: true, + }), + ).toBe(events); + expect(homeAssistantWSRequest).toBeCalledWith( + hass, + frigateEventsSchema, + expect.objectContaining({ + type: 'frigate/events/get', + instance_id: 'clientID', + cameras: ['camera.office'], + labels: ['person'], + zones: ['zone'], + after: 0, + before: 1, + limit: 10, + has_clip: true, + has_snapshot: true, + favorites: true, + }), + true, + ); + }); + + it('should get event summary', async () => { + const eventSummary: EventSummary = [ + { + camera: 'camera.office', + day: '2023-10-29', + label: 'person', + sub_label: null, + zones: ['door'], + }, + ]; + const hass = createHASS(); + vi.mocked(homeAssistantWSRequest).mockResolvedValue(eventSummary); + expect(await getEventSummary(hass, 'clientID')).toBe(eventSummary); + expect(homeAssistantWSRequest).toBeCalledWith( + hass, + eventSummarySchema, + expect.objectContaining({ + type: 'frigate/events/summary', + instance_id: 'clientID', + timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + }), + true, + ); + }); + + it('should get PTZ info', async () => { + const ptzInfo = [ + { + name: 'camera.office', + features: ['zoom', 'zoom-r'], + presets: ['preset01', 'preset02'], + }, + ]; + const hass = createHASS(); + vi.mocked(homeAssistantWSRequest).mockResolvedValue(ptzInfo); + expect(await getPTZInfo(hass, 'clientID', 'camera.office')).toBe(ptzInfo); + expect(homeAssistantWSRequest).toBeCalledWith( + hass, + ptzInfoSchema, + expect.objectContaining({ + type: 'frigate/ptz/info', + instance_id: 'clientID', + camera: 'camera.office', + }), + true, + ); + }); +}); diff --git a/tests/camera-manager/generic/engine-generic.test.ts b/tests/camera-manager/generic/engine-generic.test.ts index 3ee4b706..c023c808 100644 --- a/tests/camera-manager/generic/engine-generic.test.ts +++ b/tests/camera-manager/generic/engine-generic.test.ts @@ -9,6 +9,7 @@ import { createCameraConfig, createHASS, createStateEntity, + createStore, } from '../../test-utils'; const createEngine = (): GenericCameraManagerEngine => { @@ -26,19 +27,29 @@ describe('GenericCameraManagerEngine', () => { it('should initialize camera', async () => { const config = createGenericCameraConfig(); - expect( - await createEngine().initializeCamera( - createHASS(), - mock(), - config, - ), - ).toEqual(config); + const camera = await createEngine().initializeCamera( + createHASS(), + mock(), + config, + ); + + expect(camera.getConfig()).toEqual(config); + expect(camera.getCapabilities()).toEqual({ + canFavoriteEvents: false, + canFavoriteRecordings: false, + canSeek: false, + supportsClips: false, + supportsRecordings: false, + supportsSnapshots: false, + supportsTimeline: false, + }); }); it('should generate default event query', () => { + const engine = createEngine(); expect( - createEngine().generateDefaultEventQuery( - new Map([['camera-1', createGenericCameraConfig()]]), + engine.generateDefaultEventQuery( + createStore([{ cameraID: 'camera-1', engine: engine }]), new Set(['camera-1']), {}, ), @@ -46,9 +57,10 @@ describe('GenericCameraManagerEngine', () => { }); it('should generate default recording query', () => { + const engine = createEngine(); expect( - createEngine().generateDefaultRecordingQuery( - new Map([['camera-1', createGenericCameraConfig()]]), + engine.generateDefaultRecordingQuery( + createStore([{ cameraID: 'camera-1', engine: engine }]), new Set(['camera-1']), {}, ), @@ -56,9 +68,10 @@ describe('GenericCameraManagerEngine', () => { }); it('should generate default recording segments query', () => { + const engine = createEngine(); expect( - createEngine().generateDefaultRecordingSegmentsQuery( - new Map([['camera-1', createGenericCameraConfig()]]), + engine.generateDefaultRecordingSegmentsQuery( + createStore([{ cameraID: 'camera-1', engine: engine }]), new Set(['camera-1']), {}, ), @@ -66,30 +79,33 @@ describe('GenericCameraManagerEngine', () => { }); it('should get events', async () => { + const engine = createEngine(); expect( - await createEngine().getEvents( + await engine.getEvents( createHASS(), - new Map([['camera-1', createGenericCameraConfig()]]), + createStore([{ cameraID: 'camera-1', engine: engine }]), { type: QueryType.Event, cameraIDs: new Set(['camera-1']) }, ), ).toBeNull(); }); it('should get recordings', async () => { + const engine = createEngine(); expect( - await createEngine().getRecordings( + await engine.getRecordings( createHASS(), - new Map([['camera-1', createGenericCameraConfig()]]), + createStore([{ cameraID: 'camera-1', engine: engine }]), { type: QueryType.Recording, cameraIDs: new Set(['camera-1']) }, ), ).toBeNull(); }); it('should get recording segments', async () => { + const engine = createEngine(); expect( - await createEngine().getRecordingSegments( + await engine.getRecordingSegments( createHASS(), - new Map([['camera-1', createGenericCameraConfig()]]), + createStore([{ cameraID: 'camera-1', engine: engine }]), { type: QueryType.RecordingSegments, cameraIDs: new Set(['camera-1']), @@ -101,10 +117,11 @@ describe('GenericCameraManagerEngine', () => { }); it('should generate media from events', async () => { + const engine = createEngine(); expect( - createEngine().generateMediaFromEvents( + engine.generateMediaFromEvents( createHASS(), - new Map([['camera-1', createGenericCameraConfig()]]), + createStore([{ cameraID: 'camera-1', engine: engine }]), { type: QueryType.Event, cameraIDs: new Set(['camera-1']), @@ -118,10 +135,11 @@ describe('GenericCameraManagerEngine', () => { }); it('should generate media from recordings', async () => { + const engine = createEngine(); expect( - createEngine().generateMediaFromRecordings( + engine.generateMediaFromRecordings( createHASS(), - new Map([['camera-1', createGenericCameraConfig()]]), + createStore([{ cameraID: 'camera-1', engine: engine }]), { type: QueryType.Recording, cameraIDs: new Set(['camera-1']), @@ -167,10 +185,11 @@ describe('GenericCameraManagerEngine', () => { }); it('should get media seek time', async () => { + const engine = createEngine(); expect( - await createEngine().getMediaSeekTime( + await engine.getMediaSeekTime( createHASS(), - new Map([['camera-1', createGenericCameraConfig()]]), + createStore([{ cameraID: 'camera-1', engine: engine }]), new TestViewMedia(), new Date(), ), @@ -178,10 +197,11 @@ describe('GenericCameraManagerEngine', () => { }); it('should get media metadata', async () => { + const engine = createEngine(); expect( - await createEngine().getMediaMetadata( + await engine.getMediaMetadata( createHASS(), - new Map([['camera-1', createGenericCameraConfig()]]), + createStore([{ cameraID: 'camera-1', engine: engine }]), { type: QueryType.MediaMetadata, cameraIDs: new Set(['camera-1']) }, ), ).toBeNull(); @@ -264,18 +284,6 @@ describe('GenericCameraManagerEngine', () => { }); }); - it('should get camera capabilities metadata', async () => { - expect(createEngine().getCameraCapabilities(createGenericCameraConfig())).toEqual({ - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, - supportsClips: false, - supportsRecordings: false, - supportsSnapshots: false, - supportsTimeline: false, - }); - }); - it('should get media capabilities', () => { expect(createEngine().getMediaCapabilities(new TestViewMedia())).toBeNull(); }); @@ -303,4 +311,10 @@ describe('GenericCameraManagerEngine', () => { }); }); }); + + it('should execute PTZ action', () => { + const hass = createHASS(); + createEngine().executePTZAction(hass, createCameraConfig(), 'left'); + expect(hass.callService).not.toBeCalled(); + }); }); diff --git a/tests/camera-manager/store.test.ts b/tests/camera-manager/store.test.ts index bd66f082..384f43e7 100644 --- a/tests/camera-manager/store.test.ts +++ b/tests/camera-manager/store.test.ts @@ -1,15 +1,23 @@ import { describe, expect, it } from 'vitest'; import { mock } from 'vitest-mock-extended'; +import { Camera } from '../../src/camera-manager/camera.js'; import { CameraManagerEngineFactory } from '../../src/camera-manager/engine-factory.js'; import { CameraManagerStore } from '../../src/camera-manager/store.js'; import { Engine } from '../../src/camera-manager/types.js'; import { EntityRegistryManager } from '../../src/utils/ha/entity-registry/index.js'; import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media.js'; -import { TestViewMedia, createCameraConfig } from '../test-utils.js'; +import { + TestViewMedia, + createCameraCapabilities, + createCameraConfig, +} from '../test-utils.js'; describe('CameraManagerStore', async () => { - const config_visible = createCameraConfig(); - const config_hidden = createCameraConfig({ + const configVisible = createCameraConfig({ + id: 'camera-visible', + }); + const configHidden = createCameraConfig({ + id: 'camera-hidden', hide: true, }); @@ -21,71 +29,100 @@ describe('CameraManagerStore', async () => { const engineGeneric = await engineFactory.createEngine(Engine.Generic); const engineFrigate = await engineFactory.createEngine(Engine.Frigate); - const setupStore = async (): Promise => { + const setupStore = (): CameraManagerStore => { const store = new CameraManagerStore(); - store.addCamera('camera-visible', config_visible, engineGeneric); - store.addCamera('camera-hidden', config_hidden, engineFrigate); + store.addCamera( + new Camera(configVisible, engineGeneric, createCameraCapabilities()), + ); + store.addCamera(new Camera(configHidden, engineFrigate, createCameraCapabilities())); return store; }; it('getCameraConfig', async () => { - const store = await setupStore(); - expect(store.getCameraConfig('camera-visible')).toBe(config_visible); - expect(store.getCameraConfig('camera-hidden')).toBe(config_hidden); + const store = setupStore(); + expect(store.getCameraConfig('camera-visible')).toBe(configVisible); + expect(store.getCameraConfig('camera-hidden')).toBe(configHidden); expect(store.getCameraConfig('camera-not-exist')).toBeNull(); }); it('hasCameraID', async () => { - const store = await setupStore(); + const store = setupStore(); expect(store.hasCameraID('camera-visible')).toBeTruthy(); expect(store.hasCameraID('camera-hidden')).toBeTruthy(); }); - it('hasVisibleCameraID', async () => { - const store = await setupStore(); - expect(store.hasVisibleCameraID('camera-visible')).toBeTruthy(); - expect(store.hasVisibleCameraID('camera-hidden')).toBeFalsy(); - }); - it('getCameraCount', async () => { - const store = await setupStore(); + const store = setupStore(); expect(store.getCameraCount()).toBe(2); }); it('getVisibleCameraCount', async () => { - const store = await setupStore(); + const store = setupStore(); expect(store.getVisibleCameraCount()).toBe(1); }); - it('getCameras', async () => { - const store = await setupStore(); - expect(store.getCameras()).toEqual( - new Map([ - ['camera-visible', config_visible], - ['camera-hidden', config_hidden], - ]), - ); + describe('getCamera', async () => { + it('present', async () => { + const store = setupStore(); + expect(store.getCamera('camera-visible')?.getConfig()).toEqual(configVisible); + }); + + it('absent', async () => { + const store = setupStore(); + expect(store.getCamera('not-a-camera')).toBeNull(); + }); }); - it('getVisibleCameras', async () => { - const store = await setupStore(); - expect(store.getVisibleCameras()).toEqual( - new Map([['camera-visible', config_visible]]), - ); + describe('getCameraConfigs', async () => { + it('all', async () => { + const store = setupStore(); + expect([...store.getCameraConfigs()]).toEqual([configVisible, configHidden]); + }); + + it('named', async () => { + const store = setupStore(); + expect([...store.getCameraConfigs(['camera-visible', 'not-a-camera'])]).toEqual([ + configVisible, + ]); + }); + }); + + describe('getCameraConfigEntries', async () => { + it('all', async () => { + const store = setupStore(); + expect([...store.getCameraConfigEntries()]).toEqual([ + ['camera-visible', configVisible], + ['camera-hidden', configHidden], + ]); + }); + + it('named', async () => { + const store = setupStore(); + expect([ + ...store.getCameraConfigEntries(['camera-visible', 'not-a-camera']), + ]).toEqual([['camera-visible', configVisible]]); + }); + }); + + it('getCameras', async () => { + const store = setupStore(); + expect([...store.getCameras().keys()]).toEqual(['camera-visible', 'camera-hidden']); + expect(store.getCameras().get('camera-visible')?.getConfig()).toEqual(configVisible); + expect(store.getCameras().get('camera-hidden')?.getConfig()).toEqual(configHidden); }); it('getCameraIDs', async () => { - const store = await setupStore(); + const store = setupStore(); expect(store.getCameraIDs()).toEqual(new Set(['camera-visible', 'camera-hidden'])); }); it('getVisibleCameraIDs', async () => { - const store = await setupStore(); + const store = setupStore(); expect(store.getVisibleCameraIDs()).toEqual(new Set(['camera-visible'])); }); it('reset', async () => { - const store = await setupStore(); + const store = setupStore(); store.reset(); @@ -94,24 +131,24 @@ describe('CameraManagerStore', async () => { }); it('getCameraConfigForMedia', async () => { - const store = await setupStore(); + const store = setupStore(); const media_1 = new TestViewMedia({ cameraID: 'camera-visible' }); - expect(store.getCameraConfigForMedia(media_1)).toBe(config_visible); + expect(store.getCameraConfigForMedia(media_1)).toBe(configVisible); const media_2 = new TestViewMedia({ cameraID: 'camera-not-exist' }); expect(store.getCameraConfigForMedia(media_2)).toBeNull(); }); it('getEngineOfType', async () => { - const store = await setupStore(); + const store = setupStore(); expect(store.getEngineOfType(Engine.Generic)).toBe(engineGeneric); expect(store.getEngineOfType(Engine.Frigate)).toBe(engineFrigate); expect(store.getEngineOfType(Engine.MotionEye)).toBeNull(); }); it('getEngineForCameraID', async () => { - const store = await setupStore(); + const store = setupStore(); expect(store.getEngineForCameraID('camera-visible')).toBe(engineGeneric); expect(store.getEngineForCameraID('camera-hidden')).toBe(engineFrigate); expect(store.getEngineForCameraID('camera-not-exist')).toBeNull(); @@ -119,13 +156,23 @@ describe('CameraManagerStore', async () => { describe('getEnginesForCameraIDs', async () => { it('empty input', async () => { - const store = await setupStore(); + const store = setupStore(); expect(store.getEnginesForCameraIDs(new Set())).toBeNull(); }); it('multiple cameras', async () => { - const store = await setupStore(); - store.addCamera('camera-visible2', config_visible, engineGeneric); + const store = setupStore(); + store.addCamera( + new Camera( + { + ...configVisible, + id: 'camera-visible2', + }, + engineGeneric, + createCameraCapabilities(), + ), + ); + expect( store.getEnginesForCameraIDs( new Set([ @@ -145,13 +192,61 @@ describe('CameraManagerStore', async () => { }); it('getEngineForMedia', async () => { - const store = await setupStore(); + const store = setupStore(); const media = new TestViewMedia({ cameraID: 'camera-visible' }); expect(store.getEngineForMedia(media)).toBe(engineGeneric); }); - it('getAllEngines', async () => { - const store = await setupStore(); - expect(store.getAllEngines()).toEqual([engineGeneric, engineFrigate]); + describe('getAllDependentCameras', () => { + it('should return dependent cameras', () => { + const store = new CameraManagerStore(); + store.addCamera( + new Camera( + createCameraConfig({ + id: 'one', + dependencies: { + cameras: ['two', 'three'], + }, + }), + engineGeneric, + createCameraCapabilities(), + ), + ); + store.addCamera( + new Camera( + createCameraConfig({ + id: 'two', + }), + engineGeneric, + createCameraCapabilities(), + ), + ); + expect(store.getAllDependentCameras('one')).toEqual(new Set(['one', 'two'])); + }); + it('should return all cameras', () => { + const store = new CameraManagerStore(); + store.addCamera( + new Camera( + createCameraConfig({ + id: 'one', + dependencies: { + all_cameras: true, + }, + }), + engineGeneric, + createCameraCapabilities(), + ), + ); + store.addCamera( + new Camera( + createCameraConfig({ + id: 'two', + }), + engineGeneric, + createCameraCapabilities(), + ), + ); + expect(store.getAllDependentCameras('one')).toEqual(new Set(['one', 'two'])); + }); }); }); diff --git a/tests/card-controller/actions-manager.test.ts b/tests/card-controller/actions-manager.test.ts index 8496f4f0..52c794f1 100644 --- a/tests/card-controller/actions-manager.test.ts +++ b/tests/card-controller/actions-manager.test.ts @@ -23,7 +23,6 @@ import { } from '../test-utils'; vi.mock('../../src/utils/action.js'); -vi.mock('../../src/camera-manager/manager.js'); const createAction = ( action: Record, @@ -708,6 +707,62 @@ describe('ActionsManager.executeAction', () => { expect(api.getViewManager().setViewWithNewDisplayMode).toBeCalledWith('grid'); }); + describe('should handle ptz action', () => { + it('with selected camera', async () => { + const api = createCardAPI(); + const manager = new ActionsManager(api); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ camera: 'camera.office' }), + ); + + await manager.executeAction( + createAction({ + frigate_card_action: 'ptz', + ptz_action: 'left', + })!, + ); + + expect(api.getCameraManager().executePTZAction).toBeCalledWith( + 'camera.office', + 'left', + { + phase: undefined, + preset: undefined, + }, + ); + }); + + it('without selected camera', async () => { + const api = createCardAPI(); + const manager = new ActionsManager(api); + + await manager.executeAction( + createAction({ + frigate_card_action: 'ptz', + ptz_action: 'left', + })!, + ); + + expect(api.getCameraManager().executePTZAction).not.toBeCalled(); + }); + }); + + it('should handle show_ptz action', async () => { + const api = createCardAPI(); + const manager = new ActionsManager(api); + + await manager.executeAction( + createAction({ + frigate_card_action: 'show_ptz', + show_ptz: true, + })!, + ); + + expect(api.getViewManager().setViewWithNewContext).toBeCalledWith( + expect.objectContaining({ live: { ptzVisible: true } }), + ); + }); + it('should handle unknown action', async () => { const manager = new ActionsManager(createCardAPI()); diff --git a/tests/card-controller/hass-manager.test.ts b/tests/card-controller/hass-manager.test.ts index cb10b2ae..0fbe2b97 100644 --- a/tests/card-controller/hass-manager.test.ts +++ b/tests/card-controller/hass-manager.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { CardController } from '../../src/card-controller/controller'; import { HASSManager } from '../../src/card-controller/hass-manager'; -import { CardHASSAPI } from '../../src/card-controller/types'; import { createCameraConfig, createCameraManager, @@ -8,12 +8,11 @@ import { createConfig, createHASS, createStateEntity, + createStore, createView, } from '../test-utils'; -vi.mock('../../src/camera-manager/manager.js'); - -const createAPIWithoutMediaPlayers = (): CardHASSAPI => { +const createAPIWithoutMediaPlayers = (): CardController => { const api = createCardAPI(); vi.mocked(api.getMediaPlayerManager().getMediaPlayers).mockReturnValue([]); return api; @@ -158,20 +157,20 @@ describe('HASSManager', () => { describe('should set default view when', () => { it('selected camera trigger entity changes', () => { - const cameraManager = createCameraManager({ - configs: new Map([ - [ - 'camera.foo', - createCameraConfig({ + const api = createAPIWithoutMediaPlayers(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.foo', + config: createCameraConfig({ triggers: { entities: ['binary_sensor.motion'], }, }), - ], + }, ]), - }); - const api = createAPIWithoutMediaPlayers(); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); + ); vi.mocked(api.getViewManager().getView).mockReturnValue( createView({ camera: 'camera.foo', @@ -189,20 +188,20 @@ describe('HASSManager', () => { }); it('selected camera is unknown', () => { - const cameraManager = createCameraManager({ - configs: new Map([ - [ - 'camera.foo', - createCameraConfig({ + const api = createAPIWithoutMediaPlayers(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.foo', + config: createCameraConfig({ triggers: { entities: ['binary_sensor.motion'], }, }), - ], + }, ]), - }); - const api = createAPIWithoutMediaPlayers(); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); + ); vi.mocked(api.getViewManager().getView).mockReturnValue( createView({ camera: 'camera.UNKNOWN', diff --git a/tests/card-controller/initialization-manager.test.ts b/tests/card-controller/initialization-manager.test.ts index c9f05c32..7ee8bd0b 100644 --- a/tests/card-controller/initialization-manager.test.ts +++ b/tests/card-controller/initialization-manager.test.ts @@ -18,9 +18,37 @@ describe('InitializationManager', () => { vi.resetAllMocks(); }); - it('should not be initialized', () => { - const manager = new InitializationManager(createCardAPI()); - expect(manager.isInitializedMandatory()).toBeFalsy(); + describe('should correctly determine when mandatory initialization is required', () => { + it('without aspects', () => { + const api = createCardAPI(); + const initializer = mock(); + const manager = new InitializationManager(api, initializer); + + initializer.isInitializedMultiple.mockReturnValue(false); + + expect(manager.isInitializedMandatory()).toBeFalsy(); + }); + + it('without view', () => { + const api = createCardAPI(); + const initializer = mock(); + const manager = new InitializationManager(api, initializer); + + initializer.isInitializedMultiple.mockReturnValue(true); + + expect(manager.isInitializedMandatory()).toBeFalsy(); + }); + + it('with aspects and view', () => { + const api = createCardAPI(); + const initializer = mock(); + const manager = new InitializationManager(api, initializer); + + initializer.isInitializedMultiple.mockReturnValue(true); + vi.mocked(api.getViewManager().hasView).mockReturnValue(true); + + expect(manager.isInitializedMandatory()).toBeTruthy(); + }); }); describe('should initialize mandatory', () => { @@ -41,7 +69,9 @@ describe('InitializationManager', () => { vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); vi.mocked(api.getConfigManager().hasConfig).mockReturnValue(true); vi.mocked(api.getMessageManager().hasMessage).mockReturnValue(false); - vi.mocked(api.getQueryStringManager().hasViewRelatedActions).mockReturnValue(false); + vi.mocked(api.getQueryStringManager().hasViewRelatedActions).mockReturnValue( + false, + ); const manager = new InitializationManager(api); expect(await manager.initializeMandatory()).toBeTruthy(); @@ -50,7 +80,6 @@ describe('InitializationManager', () => { expect(sideLoadHomeAssistantElements).toBeCalled(); expect(api.getCameraManager().initializeCamerasFromConfig).toBeCalled(); expect(api.getViewManager().setViewDefault).toBeCalled(); - expect(api.getCardElementManager().update).toBeCalled(); }); it('successfully with querystring view', async () => { @@ -71,7 +100,9 @@ describe('InitializationManager', () => { vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); vi.mocked(api.getConfigManager().hasConfig).mockReturnValue(true); vi.mocked(api.getMessageManager().hasMessage).mockReturnValue(true); - vi.mocked(api.getQueryStringManager().hasViewRelatedActions).mockReturnValue(false); + vi.mocked(api.getQueryStringManager().hasViewRelatedActions).mockReturnValue( + false, + ); const manager = new InitializationManager(api); expect(await manager.initializeMandatory()).toBeTruthy(); @@ -134,7 +165,6 @@ describe('InitializationManager', () => { expect(await manager.initializeBackgroundIfNecessary()).toBeTruthy(); expect(api.getMediaPlayerManager().initialize).not.toBeCalled(); expect(api.getMicrophoneManager().connect).not.toBeCalled(); - expect(api.getCardElementManager().update).not.toBeCalled(); }); it('successfully with all inititalizers', async () => { diff --git a/tests/card-controller/media-player-manager.test.ts b/tests/card-controller/media-player-manager.test.ts index 411cd046..836f544e 100644 --- a/tests/card-controller/media-player-manager.test.ts +++ b/tests/card-controller/media-player-manager.test.ts @@ -1,20 +1,19 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { MediaPlayerManager } from '../../src/card-controller/media-player-manager'; +import { MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA } from '../../src/const'; +import { ExtendedHomeAssistant } from '../../src/types'; +import { EntityRegistryManager } from '../../src/utils/ha/entity-registry'; import { - TestViewMedia, createCameraConfig, createCameraManager, createCardAPI, createHASS, createRegistryEntity, createStateEntity, + createStore, + TestViewMedia, } from '../test-utils'; -import { MediaPlayerManager } from '../../src/card-controller/media-player-manager'; -import { ExtendedHomeAssistant } from '../../src/types'; -import { MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA } from '../../src/const'; -import { EntityRegistryManager } from '../../src/utils/ha/entity-registry'; -import { mock } from 'vitest-mock-extended'; - -vi.mock('../../src/camera-manager/manager.js'); const createHASSWithMediaPlayers = (): ExtendedHomeAssistant => { const attributesSupported = { @@ -145,9 +144,7 @@ describe('MediaPlayerManager', () => { describe('live', () => { it('without camera config', async () => { const api = createCardAPI(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getCameraConfig).mockReturnValue(null); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); const manager = new MediaPlayerManager(api); @@ -159,28 +156,33 @@ describe('MediaPlayerManager', () => { describe('using standard method', () => { it('successfully', async () => { const api = createCardAPI(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getCameraConfig).mockReturnValue( - createCameraConfig({ - camera_entity: 'camera.foo', - }), + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.foo', + config: createCameraConfig({ + camera_entity: 'camera.foo', + }), + }, + ]), ); - vi.mocked(cameraManager.getCameraMetadata).mockReturnValue({ + vi.mocked(api.getCameraManager().getCameraMetadata).mockReturnValue({ title: 'camera title', icon: 'icon', }); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); - const hass = createHASS({ - 'camera.foo': createStateEntity({ - attributes: { - entity_picture: 'http://thumbnail', - }, + vi.mocked(api.getHASSManager().getHASS).mockReturnValue( + createHASS({ + 'camera.foo': createStateEntity({ + attributes: { + entity_picture: 'http://thumbnail', + }, + }), }), - }); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + ); const manager = new MediaPlayerManager(api); - await manager.playLive('media_player.foo', 'camera'); + await manager.playLive('media_player.foo', 'camera.foo'); expect(api.getHASSManager().getHASS()?.callService).toBeCalledWith( 'media_player', @@ -199,32 +201,41 @@ describe('MediaPlayerManager', () => { it('without camera_entity', async () => { const api = createCardAPI(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getCameraConfig).mockReturnValue( - createCameraConfig({}), + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.foo', + config: createCameraConfig(), + }, + ]), ); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); const manager = new MediaPlayerManager(api); - await manager.playLive('media_player.foo', 'camera'); + await manager.playLive('media_player.foo', 'camera.foo'); expect(api.getHASSManager().getHASS()?.callService).not.toBeCalled(); }); it('without title and thumbnail', async () => { const api = createCardAPI(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getCameraConfig).mockReturnValue( - createCameraConfig({ - camera_entity: 'camera.foo', - }), + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.foo', + config: createCameraConfig({ + camera_entity: 'camera.foo', + }), + }, + ]), ); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); const manager = new MediaPlayerManager(api); - await manager.playLive('media_player.foo', 'camera'); + await manager.playLive('media_player.foo', 'camera.foo'); expect(api.getHASSManager().getHASS()?.callService).toBeCalledWith( 'media_player', @@ -242,25 +253,29 @@ describe('MediaPlayerManager', () => { describe('using dashboard method', () => { it('successfully', async () => { const api = createCardAPI(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getCameraConfig).mockReturnValue( - createCameraConfig({ - camera_entity: 'camera.foo', - cast: { - method: 'dashboard', - dashboard: { - dashboard_path: 'dashboard_path', - view_path: 'view_path', - }, + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.foo', + config: createCameraConfig({ + camera_entity: 'camera.foo', + cast: { + method: 'dashboard', + dashboard: { + dashboard_path: 'dashboard_path', + view_path: 'view_path', + }, + }, + }), }, - }), + ]), ); vi.mocked(api.getQueryStringManager().generateQueryString).mockReturnValue(''); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); const manager = new MediaPlayerManager(api); - await manager.playLive('media_player.foo', 'camera'); + await manager.playLive('media_player.foo', 'camera.foo'); expect(api.getHASSManager().getHASS()?.callService).toBeCalledWith( 'cast', @@ -275,24 +290,28 @@ describe('MediaPlayerManager', () => { it('without hass', async () => { const api = createCardAPI(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getCameraConfig).mockReturnValue( - createCameraConfig({ - camera_entity: 'camera.foo', - cast: { - method: 'dashboard', - dashboard: { - dashboard_path: 'dashboard_path', - view_path: 'view_path', - }, + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.foo', + config: createCameraConfig({ + camera_entity: 'camera.foo', + cast: { + method: 'dashboard', + dashboard: { + dashboard_path: 'dashboard_path', + view_path: 'view_path', + }, + }, + }), }, - }), + ]), ); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(null); const manager = new MediaPlayerManager(api); - await manager.playLive('media_player.foo', 'camera'); + await manager.playLive('media_player.foo', 'camera.foo'); // No actual test can be performed here as nothing observable happens. // This test serves only as code-coverage long-tail. @@ -301,21 +320,25 @@ describe('MediaPlayerManager', () => { it('without required configuration', async () => { const api = createCardAPI(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getCameraConfig).mockReturnValue( - createCameraConfig({ - camera_entity: 'camera.foo', - cast: { - method: 'dashboard', + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.foo', + config: createCameraConfig({ + camera_entity: 'camera.foo', + cast: { + method: 'dashboard', + }, + }), }, - }), + ]), ); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); const manager = new MediaPlayerManager(api); - await manager.playLive('media_player.foo', 'camera'); + await manager.playLive('media_player.foo', 'camera.foo'); expect( vi.mocked(api.getMessageManager().setMessageIfHigherPriority), diff --git a/tests/card-controller/microphone-manager.test.ts b/tests/card-controller/microphone-manager.test.ts index 9f6b4f78..fe8355e8 100644 --- a/tests/card-controller/microphone-manager.test.ts +++ b/tests/card-controller/microphone-manager.test.ts @@ -63,7 +63,7 @@ describe('MicrophoneManager', () => { const manager = new MicrophoneManager(api); navigatorMock.mediaDevices.getUserMedia.mockRejectedValue(new Error()); - await manager.connect(); + expect(await manager.connect()).toBeFalsy(); expect(manager.isConnected()).toBeFalsy(); expect(manager.isForbidden()).toBeTruthy(); diff --git a/tests/card-controller/triggers-manager.test.ts b/tests/card-controller/triggers-manager.test.ts index 7379f69e..d14d2f7a 100644 --- a/tests/card-controller/triggers-manager.test.ts +++ b/tests/card-controller/triggers-manager.test.ts @@ -1,8 +1,9 @@ import add from 'date-fns/add'; import { HassEntities } from 'home-assistant-js-websocket'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { ScanOptions } from '../../src/config/types'; +import { CardController } from '../../src/card-controller/controller'; import { TriggersManager } from '../../src/card-controller/triggers-manager'; +import { ScanOptions } from '../../src/config/types'; import { createCameraConfig, createCameraManager, @@ -10,18 +11,17 @@ import { createConfig, createHASS, createStateEntity, + createStore, createView, } from '../test-utils'; -vi.mock('../../src/camera-manager/manager.js'); - // Creating and mocking a trigger API is a lot of boilerplate, this convenience // function reduces it. const createTriggerAPI = (options?: { config?: Partial; hassStates?: HassEntities; interaction?: boolean; -}) => { +}): CardController => { const api = createCardAPI(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ @@ -37,19 +37,18 @@ const createTriggerAPI = (options?: { vi.mocked(api.getHASSManager().getHASS).mockReturnValue( createHASS(options?.hassStates), ); - vi.mocked(api.getCameraManager).mockReturnValue( - createCameraManager({ - configs: new Map([ - [ - 'camera_1', - createCameraConfig({ - triggers: { - entities: ['binary_sensor.motion'], - }, - }), - ], - ]), - }), + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera_1', + config: createCameraConfig({ + triggers: { + entities: ['binary_sensor.motion'], + }, + }), + }, + ]), ); vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue( options?.interaction ?? false, diff --git a/tests/card-controller/view-manager.test.ts b/tests/card-controller/view-manager.test.ts index 516a2ec3..07844a7a 100644 --- a/tests/card-controller/view-manager.test.ts +++ b/tests/card-controller/view-manager.test.ts @@ -1,20 +1,24 @@ import { describe, expect, it, vi } from 'vitest'; import { QueryType } from '../../src/camera-manager/types'; -import { FrigateCardView } from '../../src/config/types'; -import { getAllDependentCameras } from '../../src/utils/camera'; import { ViewManager } from '../../src/card-controller/view-manager'; +import { FrigateCardView } from '../../src/config/types'; +import { executeMediaQueryForView } from '../../src/utils/media-to-view'; import { EventMediaQueries } from '../../src/view/media-queries'; +import { MediaQueriesResults } from '../../src/view/media-queries-results'; +import { View } from '../../src/view/view'; import { + createCameraCapabilities, + createCameraConfig, createCameraManager, createCardAPI, createConfig, createHASS, + createStore, createView, - generateViewMediaArray, + generateViewMediaArray } from '../test-utils'; -vi.mock('../../src/camera-manager/manager.js'); -vi.mock('../../src/utils/camera'); +vi.mock('../../src/utils/media-to-view'); describe('ViewManager.setView', () => { it('should set view', () => { @@ -29,6 +33,7 @@ describe('ViewManager.setView', () => { manager.setView(view); expect(manager.getView()).toBe(view); + expect(manager.hasView()).toBeTruthy(); expect(api.getMediaLoadedInfoManager().clear).toBeCalled(); expect(api.getCardElementManager().scrollReset).toBeCalled(); expect(api.getMessageManager().reset).toBeCalled(); @@ -101,6 +106,7 @@ describe('ViewManager.reset', () => { manager.reset(); expect(manager.getView()).toBeNull(); + expect(manager.hasView()).toBeFalsy(); }); }); @@ -109,6 +115,13 @@ describe('ViewManager.setViewDefault', () => { const api = createCardAPI(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera', + }, + ]), + ); const manager = new ViewManager(api); manager.setViewDefault(); @@ -130,12 +143,18 @@ describe('ViewManager.setViewDefault', () => { }); it('should cycle camera when configured', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getVisibleCameraIDs).mockReturnValue( - new Set(['camera_1', 'camera_2']), - ); const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera_1', + }, + { + cameraID: 'camera_2', + }, + ]), + ); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { @@ -160,13 +179,19 @@ describe('ViewManager.setViewDefault', () => { }); it('should respect parameters', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getVisibleCameraIDs).mockReturnValue( - new Set(['camera.kitchen', 'camera.office']), - ); const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + }, + { + cameraID: 'camera.office', + }, + ]), + ); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); const manager = new ViewManager(api); manager.setViewDefault({ @@ -186,60 +211,84 @@ describe('ViewManager.setViewByParameters', () => { const api = createCardAPI(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + }, + ]), + ); + vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue( + createCameraCapabilities({ + supportsClips: true, + }), + ); const manager = new ViewManager(api); manager.setViewByParameters({ - cameraID: 'camera', + cameraID: 'camera.kitchen', viewName: 'clips', }); expect(manager.getView()?.view).toBe('clips'); - expect(manager.getView()?.camera).toBe('camera'); + expect(manager.getView()?.camera).toBe('camera.kitchen'); }); it('should set view by parameters using existing view if unspecified', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getVisibleCameraIDs).mockReturnValue( - new Set(['camera_1', 'camera_2']), - ); - const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + }, + { + cameraID: 'camera.office', + }, + ]), + ); + vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue( + createCameraCapabilities({ + supportsClips: true, + }), + ); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); const manager = new ViewManager(api); manager.setViewByParameters({ - cameraID: 'camera_1', + cameraID: 'camera.kitchen', viewName: 'clips', }); manager.setViewByParameters({ - cameraID: 'camera_2', + cameraID: 'camera.office', }); expect(manager.getView()?.view).toBe('clips'); - expect(manager.getView()?.camera).toBe('camera_2'); + expect(manager.getView()?.camera).toBe('camera.office'); }); it('should set view by parameters using config as fallback', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getVisibleCameraIDs).mockReturnValue( - new Set(['camera_1', 'camera_2']), - ); - const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + }, + ]), + ); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); const manager = new ViewManager(api); manager.setViewByParameters({ - cameraID: 'camera_1', + cameraID: 'camera.kitchen', // No prior view, and no specified view. This could happen during query // string based initialization. }); expect(manager.getView()?.view).toBe('live'); - expect(manager.getView()?.camera).toBe('camera_1'); + expect(manager.getView()?.camera).toBe('camera.kitchen'); }); it('should not set view by parameters without config', () => { @@ -253,12 +302,19 @@ describe('ViewManager.setViewByParameters', () => { }); it('should not set view by parameters without visible cameras', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getVisibleCameraIDs).mockReturnValue(new Set()); - const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + config: createCameraConfig({ + hide: true, + }), + }, + ]), + ); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); const manager = new ViewManager(api); manager.setViewByParameters({ @@ -278,6 +334,21 @@ describe('ViewManager.setViewByParameters', () => { ])('%s', (viewName: FrigateCardView) => { const api = createCardAPI(); vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + }, + ]), + ); + vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue( + createCameraCapabilities({ + supportsClips: true, + supportsRecordings: true, + supportsSnapshots: true, + }), + ); + vi.mocked(api.getConfigManager()).getConfig.mockReturnValue( createConfig({ media_viewer: { @@ -295,7 +366,7 @@ describe('ViewManager.setViewByParameters', () => { const manager = new ViewManager(api); manager.setViewByParameters({ - cameraID: 'camera', + cameraID: 'camera.kitchen', viewName: viewName, }); @@ -314,43 +385,31 @@ describe('ViewManager.setViewByParameters', () => { const api = createCardAPI(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + }, + ]), + ); + vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue( + createCameraCapabilities({ + supportsClips: true, + supportsRecordings: true, + supportsSnapshots: true, + }), + ); + const manager = new ViewManager(api); manager.setViewByParameters({ - cameraID: 'camera', + cameraID: 'camera.kitchen', viewName: viewName, }); expect(manager.getView()?.displayMode).toBe('single'); }); }); - - it('should set view by parameters using config as fallback', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getVisibleCameraIDs).mockReturnValue( - new Set(['camera_1', 'camera_2']), - ); - - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); - vi.mocked(getAllDependentCameras).mockReturnValue( - new Set(['camera_1', 'camera_1_hd']), - ); - - const manager = new ViewManager(api); - manager.setViewByParameters({ - cameraID: 'camera_1', - viewName: 'live', - substream: 'camera_1_hd', - }); - - expect(manager.getView()?.view).toBe('live'); - expect(manager.getView()?.camera).toBe('camera_1'); - expect(manager.getView()?.context?.live?.overrides).toEqual( - new Map([['camera_1', 'camera_1_hd']]), - ); - }); }); // @vitest-environment jsdom @@ -360,6 +419,7 @@ describe('ViewManager.setViewWithNewDisplayMode', () => { vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + const manager = new ViewManager(api); manager.setView(createView()); @@ -380,20 +440,40 @@ describe('ViewManager.setViewWithNewDisplayMode', () => { }); it('should set display mode to grid and create new query', async () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getVisibleCameraCount).mockReturnValue(2); - vi.mocked(cameraManager.getStore().getVisibleCameraIDs).mockReturnValue( - new Set(['camera_1', 'camera_2']), - ); - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: createCameraCapabilities({ + supportsClips: true, + supportsRecordings: true, + supportsSnapshots: true, + }), + }, + { + cameraID: 'camera.office', + capabilities: createCameraCapabilities({ + supportsClips: true, + supportsRecordings: true, + supportsSnapshots: true, + }), + }, + ]), + ); const hass = createHASS(); vi.mocked(api.getHASSManager()).getHASS.mockReturnValue(hass); - const media = generateViewMediaArray({ count: 5 }); - vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(media); + const mediaArray = generateViewMediaArray({ count: 5 }); + vi.mocked(executeMediaQueryForView).mockResolvedValue( + new View({ + view: 'clip', + camera: 'camera.kitchen', + queryResults: new MediaQueriesResults({ results: mediaArray }), + }), + ); const manager = new ViewManager(api); const query = new EventMediaQueries([ @@ -410,39 +490,50 @@ describe('ViewManager.setViewWithNewDisplayMode', () => { await manager.setViewWithNewDisplayMode('grid'); - expect(manager.getView()?.queryResults?.getResults()).toBe(media); - expect(cameraManager.executeMediaQueries).toBeCalledWith( - expect.arrayContaining([ - expect.objectContaining({ - type: 'event-query', - cameraIDs: new Set(['camera_1', 'camera_2']), - hasClip: true, - }), - ]), - ); + expect(manager.getView()?.queryResults?.getResults()).toBe(mediaArray); }); it('should set display mode to single and create new query', async () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getVisibleCameraCount).mockReturnValue(2); - vi.mocked(cameraManager.getStore().getVisibleCameraIDs).mockReturnValue( - new Set(['camera_1', 'camera_2']), - ); - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: createCameraCapabilities({ + supportsClips: true, + supportsRecordings: true, + supportsSnapshots: true, + }), + }, + { + cameraID: 'camera.office', + capabilities: createCameraCapabilities({ + supportsClips: true, + supportsRecordings: true, + supportsSnapshots: true, + }), + }, + ]), + ); const hass = createHASS(); vi.mocked(api.getHASSManager()).getHASS.mockReturnValue(hass); - const media = generateViewMediaArray({ count: 5 }); - vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(media); + const mediaArray = generateViewMediaArray({ count: 5 }); + vi.mocked(executeMediaQueryForView).mockResolvedValue( + new View({ + view: 'clip', + camera: 'camera.kitchen', + queryResults: new MediaQueriesResults({ results: mediaArray }), + }), + ); const manager = new ViewManager(api); const query = new EventMediaQueries([ { type: QueryType.Event, - cameraIDs: new Set(['camera_1', 'camera_2']), + cameraIDs: new Set(['camera.kitchen', 'camera.office']), hasClip: true, }, ]); @@ -450,53 +541,58 @@ describe('ViewManager.setViewWithNewDisplayMode', () => { manager.setView( createView({ view: 'clip', - camera: 'camera_2', + camera: 'camera.office', query: query, }), ); await manager.setViewWithNewDisplayMode('single'); - expect(manager.getView()?.queryResults?.getResults()).toBe(media); - expect(cameraManager.executeMediaQueries).toBeCalledWith( - expect.arrayContaining([ - expect.objectContaining({ - type: 'event-query', - cameraIDs: new Set(['camera_2']), - hasClip: true, - }), - ]), - ); + expect(manager.getView()?.queryResults?.getResults()).toBe(mediaArray); }); it('should set display mode to single and handle failed new query', async () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getVisibleCameraCount).mockReturnValue(2); - vi.mocked(cameraManager.getStore().getVisibleCameraIDs).mockReturnValue( - new Set(['camera_1', 'camera_2']), - ); - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: createCameraCapabilities({ + supportsClips: true, + supportsRecordings: true, + supportsSnapshots: true, + }), + }, + { + cameraID: 'camera.office', + capabilities: createCameraCapabilities({ + supportsClips: true, + supportsRecordings: true, + supportsSnapshots: true, + }), + }, + ]), + ); const manager = new ViewManager(api); const query = new EventMediaQueries([ { type: QueryType.Event, - cameraIDs: new Set(['camera_1', 'camera_2']), + cameraIDs: new Set(['camera.kitchen', 'camera.office']), hasClip: true, }, ]); const originalView = createView({ view: 'clip', - camera: 'camera_2', + camera: 'camera.office', query: query, }); manager.setView(originalView); // Query execution fails / returns null. - vi.mocked(cameraManager.executeMediaQueries).mockRejectedValue(null); + vi.mocked(executeMediaQueryForView).mockRejectedValue(null); await manager.setViewWithNewDisplayMode('single'); @@ -504,14 +600,28 @@ describe('ViewManager.setViewWithNewDisplayMode', () => { }); it('should set display mode and handle empty new query results', async () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore().getVisibleCameraCount).mockReturnValue(2); - vi.mocked(cameraManager.getStore().getVisibleCameraIDs).mockReturnValue( - new Set(['camera_1', 'camera_2']), - ); - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: createCameraCapabilities({ + supportsClips: true, + supportsRecordings: true, + supportsSnapshots: true, + }), + }, + { + cameraID: 'camera.office', + capabilities: createCameraCapabilities({ + supportsClips: true, + supportsRecordings: true, + supportsSnapshots: true, + }), + }, + ]), + ); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); const manager = new ViewManager(api); @@ -519,20 +629,20 @@ describe('ViewManager.setViewWithNewDisplayMode', () => { const query = new EventMediaQueries([ { type: QueryType.Event, - cameraIDs: new Set(['camera_1']), + cameraIDs: new Set(['camera.kitchen']), hasClip: true, }, ]); const originalView = createView({ view: 'clip', - camera: 'camera_2', + camera: 'camera.office', query: query, }); manager.setView(originalView); await manager.setViewWithNewDisplayMode('grid'); - vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(null); + vi.mocked(executeMediaQueryForView).mockResolvedValue(null); // Empty queries will not be executed, so view will not be changed. expect(manager.getView()?.displayMode).toBeNull(); @@ -541,13 +651,21 @@ describe('ViewManager.setViewWithNewDisplayMode', () => { describe('ViewManager.setViewWithSubstream', () => { it('should set new equal view with no dependencies', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + }, + ]), + ); + const manager = new ViewManager(api); const view = createView({ view: 'live', camera: 'camera', }); - vi.mocked(getAllDependentCameras).mockReturnValue(new Set(['camera'])); - const manager = new ViewManager(createCardAPI()); manager.setView(view); manager.setViewWithSubstream(); @@ -557,39 +675,71 @@ describe('ViewManager.setViewWithSubstream', () => { }); it('should set new view with next substream', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + config: createCameraConfig({ + dependencies: { + cameras: ['camera.kitchen_hd'], + }, + }), + }, + { + cameraID: 'camera.kitchen_hd', + }, + ]), + ); + const manager = new ViewManager(api); const view = createView({ view: 'live', - camera: 'camera', + camera: 'camera.kitchen', }); - vi.mocked(getAllDependentCameras).mockReturnValue(new Set(['camera', 'camera2'])); - const manager = new ViewManager(createCardAPI()); manager.setView(view); manager.setViewWithSubstream(); expect(manager.getView()?.context?.live?.overrides).toEqual( - new Map([['camera', 'camera2']]), + new Map([['camera.kitchen', 'camera.kitchen_hd']]), ); }); it('should set new view with next substream when view has invalid substream', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + config: createCameraConfig({ + dependencies: { + cameras: ['camera.kitchen_hd'], + }, + }), + }, + { + cameraID: 'camera.kitchen_hd', + }, + ]), + ); + const manager = new ViewManager(api); const view = createView({ view: 'live', - camera: 'camera', + camera: 'camera.kitchen', context: { live: { - overrides: new Map([['camera', 'camera-that-does-not-exist']]), + overrides: new Map([['camera.kitchen', 'camera-that-does-not-exist']]), }, }, }); - vi.mocked(getAllDependentCameras).mockReturnValue(new Set(['camera', 'camera2'])); - const manager = new ViewManager(createCardAPI()); manager.setView(view); manager.setViewWithSubstream(); expect(manager.getView()?.context?.live?.overrides).toEqual( - new Map([['camera', 'camera']]), + new Map([['camera.kitchen', 'camera.kitchen']]), ); }); @@ -680,17 +830,23 @@ describe('ViewManager.isViewSupportedByCamera', () => { ['media' as const, false], ])('%s', (viewName: FrigateCardView, expected: boolean) => { const api = createCardAPI(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue({ - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, - supportsClips: false, - supportsRecordings: false, - supportsSnapshots: false, - supportsTimeline: false, - }); - vi.mocked(api.getCameraManager).mockReturnValue(cameraManager); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: { + canFavoriteEvents: false, + canFavoriteRecordings: false, + canSeek: false, + supportsClips: false, + supportsRecordings: false, + supportsSnapshots: false, + supportsTimeline: false, + }, + }, + ]), + ); const manager = new ViewManager(api); expect(manager.isViewSupportedByCamera('camera', viewName)).toBe(expected); diff --git a/tests/components-lib/menu-controller.test.ts b/tests/components-lib/menu-controller.test.ts index 590e27ac..b5de796b 100644 --- a/tests/components-lib/menu-controller.test.ts +++ b/tests/components-lib/menu-controller.test.ts @@ -12,11 +12,12 @@ import { } from '../../src/components-lib/menu-controller'; import { FrigateCardConfig, MenuItem, ViewDisplayMode } from '../../src/config/types'; import { FrigateCardMediaPlayer } from '../../src/types'; -import { createFrigateCardCustomAction } from '../../src/utils/action'; +import { createFrigateCardSimpleAction } from '../../src/utils/action'; import { ViewMedia } from '../../src/view/media'; import { MediaQueriesResults } from '../../src/view/media-queries-results'; import { View } from '../../src/view/view'; import { + createAggregateCameraCapabilities, createCameraCapabilities, createCameraConfig, createCameraManager, @@ -26,10 +27,10 @@ import { createMediaCapabilities, createMediaLoadedInfo, createStateEntity, + createStore, createView, } from '../test-utils'; -vi.mock('../../src/camera-manager/manager.js'); vi.mock('../../src/utils/media-player-controller.js'); vi.mock('../../src/card-controller/microphone-manager.js'); @@ -42,16 +43,15 @@ const calculateButtons = ( view?: View; }, ): MenuItem[] => { + let cameraManager: CameraManager | null = options?.cameraManager ?? null; + if (!cameraManager) { + cameraManager = createCameraManager(); + } + return controller.calculateButtons( options?.hass ?? createHASS(), options?.config ?? createConfig(), - options?.cameraManager ?? - createCameraManager({ - configs: new Map([ - ['camera-1', createCameraConfig()], - ['camera-2', createCameraConfig()], - ]), - }), + cameraManager, options?.view ?? createView({ camera: 'camera-1' }), options, ); @@ -79,8 +79,8 @@ describe('MenuButtonController', () => { priority: 50, type: 'custom:frigate-card-menu-icon', title: 'Frigate menu / Default view', - tap_action: createFrigateCardCustomAction('menu_toggle'), - hold_action: createFrigateCardCustomAction('diagnostics'), + tap_action: createFrigateCardSimpleAction('menu_toggle'), + hold_action: createFrigateCardSimpleAction('diagnostics'), }); }); @@ -94,19 +94,17 @@ describe('MenuButtonController', () => { priority: 50, type: 'custom:frigate-card-menu-icon', title: 'Frigate menu / Default view', - tap_action: createFrigateCardCustomAction('default'), - hold_action: createFrigateCardCustomAction('diagnostics'), + tap_action: createFrigateCardSimpleAction('default'), + hold_action: createFrigateCardSimpleAction('diagnostics'), }); }); it('should have cameras menu', () => { - const cameraManager = createCameraManager({ - configs: new Map([ - ['camera-1', createCameraConfig()], - ['camera-2', createCameraConfig()], - ]), - }); - mock(cameraManager).getCameraMetadata.mockReturnValue({ + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([{ cameraID: 'camera-1' }, { cameraID: 'camera-2' }]), + ); + vi.mocked(cameraManager).getCameraMetadata.mockReturnValue({ title: 'title', icon: 'icon', }); @@ -150,14 +148,12 @@ describe('MenuButtonController', () => { }); it('should not have a cameras menu without a visible camera', () => { - const cameraManager = createCameraManager({ - configs: new Map([ - ['camera-1', createCameraConfig()], - ['camera-2', createCameraConfig()], + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { cameraID: 'camera-1', config: createCameraConfig({ hide: true }) }, ]), - }); - - vi.mocked(cameraManager.getStore()).getVisibleCameras.mockReturnValue(new Map()); + ); const buttons = calculateButtons(controller, { cameraManager: cameraManager }); expect(buttons).not.toEqual( @@ -170,12 +166,16 @@ describe('MenuButtonController', () => { }); it('should have substream button with single dependency', () => { - const cameraManager = createCameraManager({ - configs: new Map([ - ['camera-1', createCameraConfig({ dependencies: { cameras: ['camera-2'] } })], - ['camera-2', createCameraConfig()], + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), + }, + { cameraID: 'camera-2' }, ]), - }); + ); const buttons = calculateButtons(controller, { cameraManager: cameraManager }); expect(buttons).toContainEqual({ @@ -193,12 +193,17 @@ describe('MenuButtonController', () => { }); it('should have substream button selected with single dependency', () => { - const cameraManager = createCameraManager({ - configs: new Map([ - ['camera-1', createCameraConfig({ dependencies: { cameras: ['camera-2'] } })], - ['camera-2', createCameraConfig()], + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), + }, + { cameraID: 'camera-2' }, ]), - }); + ); + const view = createView({ camera: 'camera-1', context: { @@ -227,29 +232,31 @@ describe('MenuButtonController', () => { }); it('should have substream menu without substream on with multiple dependencies', () => { - const cameraManager = createCameraManager({ - configs: new Map([ - [ - 'camera-1', - createCameraConfig({ + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ camera_entity: 'camera.1', dependencies: { cameras: ['camera-2', 'camera-3'] }, }), - ], - [ - 'camera-2', - createCameraConfig({ + }, + { + cameraID: 'camera-2', + config: createCameraConfig({ camera_entity: 'camera.2', }), - ], - [ - 'camera-3', - createCameraConfig({ + }, + { + cameraID: 'camera-3', + config: createCameraConfig({ camera_entity: 'camera.3', }), - ], + }, ]), - }); + ); + // Return different metadata depending on the camera to test multiple code // paths. mock(cameraManager).getCameraMetadata.mockImplementation( @@ -316,29 +323,30 @@ describe('MenuButtonController', () => { }); it('should have substream menu with substream on with multiple dependencies', () => { - const cameraManager = createCameraManager({ - configs: new Map([ - [ - 'camera-1', - createCameraConfig({ + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ camera_entity: 'camera.1', dependencies: { cameras: ['camera-2', 'camera-3'] }, }), - ], - [ - 'camera-2', - createCameraConfig({ + }, + { + cameraID: 'camera-2', + config: createCameraConfig({ camera_entity: 'camera.2', }), - ], - [ - 'camera-3', - createCameraConfig({ + }, + { + cameraID: 'camera-3', + config: createCameraConfig({ camera_entity: 'camera.3', }), - ], + }, ]), - }); + ); const view = createView({ camera: 'camera-1', @@ -436,8 +444,8 @@ describe('MenuButtonController', () => { it('should have styled clips menu button in clips view', () => { const cameraManager = createCameraManager(); - mock(cameraManager).getAggregateCameraCapabilities.mockReturnValue( - createCameraCapabilities({ supportsClips: true }), + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsClips: true }), ); const buttons = calculateButtons(controller, { cameraManager: cameraManager, @@ -457,8 +465,8 @@ describe('MenuButtonController', () => { it('should have unstyled clips menu button in non-clips view', () => { const cameraManager = createCameraManager(); - mock(cameraManager).getAggregateCameraCapabilities.mockReturnValue( - createCameraCapabilities({ supportsClips: true }), + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsClips: true }), ); const buttons = calculateButtons(controller, { cameraManager: cameraManager }); expect(buttons).toContainEqual({ @@ -475,8 +483,8 @@ describe('MenuButtonController', () => { it('should have styled snapshots menu button in snapshots view', () => { const cameraManager = createCameraManager(); - mock(cameraManager).getAggregateCameraCapabilities.mockReturnValue( - createCameraCapabilities({ supportsSnapshots: true }), + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsSnapshots: true }), ); const buttons = calculateButtons(controller, { cameraManager: cameraManager, @@ -496,8 +504,8 @@ describe('MenuButtonController', () => { it('should have unstyled snapshots menu button in non-snapshots view', () => { const cameraManager = createCameraManager(); - mock(cameraManager).getAggregateCameraCapabilities.mockReturnValue( - createCameraCapabilities({ supportsSnapshots: true }), + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsSnapshots: true }), ); const buttons = calculateButtons(controller, { cameraManager: cameraManager }); expect(buttons).toContainEqual({ @@ -514,8 +522,8 @@ describe('MenuButtonController', () => { it('should have styled recordings menu button in recordings view', () => { const cameraManager = createCameraManager(); - mock(cameraManager).getAggregateCameraCapabilities.mockReturnValue( - createCameraCapabilities({ supportsRecordings: true }), + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsRecordings: true }), ); const buttons = calculateButtons(controller, { cameraManager: cameraManager, @@ -535,8 +543,8 @@ describe('MenuButtonController', () => { it('should have unstyled recordings menu button in non-recordings view', () => { const cameraManager = createCameraManager(); - mock(cameraManager).getAggregateCameraCapabilities.mockReturnValue( - createCameraCapabilities({ supportsRecordings: true }), + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsRecordings: true }), ); const buttons = calculateButtons(controller, { cameraManager: cameraManager }); expect(buttons).toContainEqual({ @@ -581,8 +589,8 @@ describe('MenuButtonController', () => { it('should have styled timeline menu button in timeline view', () => { const cameraManager = createCameraManager(); - mock(cameraManager).getAggregateCameraCapabilities.mockReturnValue( - createCameraCapabilities({ supportsTimeline: true }), + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsTimeline: true }), ); const buttons = calculateButtons(controller, { cameraManager: cameraManager, @@ -601,8 +609,8 @@ describe('MenuButtonController', () => { it('should have unstyled timeline menu button in non-timeline view', () => { const cameraManager = createCameraManager(); - mock(cameraManager).getAggregateCameraCapabilities.mockReturnValue( - createCameraCapabilities({ supportsTimeline: true }), + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsTimeline: true }), ); const buttons = calculateButtons(controller, { cameraManager: cameraManager, @@ -622,15 +630,15 @@ describe('MenuButtonController', () => { vi.stubGlobal('navigator', { userAgent: 'foo' }); const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getMediaCapabilities).mockReturnValue( + createMediaCapabilities({ canDownload: true }), + ); const view = createView({ queryResults: new MediaQueriesResults({ results: [new ViewMedia('clip', 'camera-1')], selectedIndex: 0, }), }); - mock(cameraManager).getMediaCapabilities.mockReturnValue( - createMediaCapabilities({ canDownload: true }), - ); const buttons = calculateButtons(controller, { cameraManager: cameraManager, view: view, @@ -653,15 +661,15 @@ describe('MenuButtonController', () => { }); const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getMediaCapabilities).mockReturnValue( + createMediaCapabilities({ canDownload: true }), + ); const view = createView({ queryResults: new MediaQueriesResults({ results: [new ViewMedia('clip', 'camera-1')], selectedIndex: 0, }), }); - mock(cameraManager).getMediaCapabilities.mockReturnValue( - createMediaCapabilities({ canDownload: true }), - ); const buttons = calculateButtons(controller, { cameraManager: cameraManager, view: view, @@ -906,16 +914,18 @@ describe('MenuButtonController', () => { }); it('should have media players button', () => { - const cameraManager = createCameraManager({ - configs: new Map([ - [ - 'camera-1', - createCameraConfig({ + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ camera_entity: 'camera.1', }), - ], + }, ]), - }); + ); + const mediaPlayerController = mock(); mediaPlayerController.hasMediaPlayers.mockReturnValue(true); mediaPlayerController.getMediaPlayers.mockReturnValue(['media_player.tv']); @@ -961,16 +971,17 @@ describe('MenuButtonController', () => { }); it('should disable media players button when entity not found', () => { - const cameraManager = createCameraManager({ - configs: new Map([ - [ - 'camera-1', - createCameraConfig({ + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ camera_entity: 'camera.1', }), - ], + }, ]), - }); + ); const mediaPlayerController = mock(); mediaPlayerController.hasMediaPlayers.mockReturnValue(true); mediaPlayerController.getMediaPlayers.mockReturnValue(['not_a_real_player']); @@ -1109,7 +1120,13 @@ describe('MenuButtonController', () => { '%s', (displayMode: ViewDisplayMode) => { const view = createView({ view: 'live', displayMode: displayMode }); - expect(calculateButtons(controller, { view: view })).toContainEqual({ + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([{ cameraID: 'camera-1' }, { cameraID: 'camera-2' }]), + ); + expect( + calculateButtons(controller, { cameraManager: cameraManager, view: view }), + ).toContainEqual({ icon: displayMode === 'single' ? 'mdi:grid' : 'mdi:grid-off', enabled: true, priority: 50, @@ -1118,6 +1135,7 @@ describe('MenuButtonController', () => { displayMode === 'grid' ? 'Show single media viewer' : 'Show media viewer for each camera in a grid', + style: displayMode === 'grid' ? { color: 'var(--primary-color, white)' } : {}, tap_action: { action: 'fire-dom-event', frigate_card_action: 'display_mode_select', @@ -1128,6 +1146,85 @@ describe('MenuButtonController', () => { ); }); + describe('should have show ptz button', () => { + it('when the selected camera is not PTZ enabled', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( + createCameraCapabilities(), + ); + + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).not.toContainEqual({ + enabled: false, + icon: 'mdi:pan', + priority: 50, + style: { + color: 'var(--primary-color, white)', + }, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'show_ptz', + show_ptz: false, + }, + title: 'Show PTZ controls', + type: 'custom:frigate-card-menu-icon', + }); + }); + + it('when the selected camera is PTZ enabled', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( + createCameraCapabilities({ ptz: {} }), + ); + + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).toContainEqual({ + enabled: false, + icon: 'mdi:pan', + priority: 50, + style: { + color: 'var(--primary-color, white)', + }, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'show_ptz', + show_ptz: false, + }, + title: 'Show PTZ controls', + type: 'custom:frigate-card-menu-icon', + }); + }); + + it('when the context has PTZ visiblity turned off', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( + createCameraCapabilities({ ptz: {} }), + ); + const view = createView({ + camera: 'camera-1', + context: { live: { ptzVisible: false } }, + }); + + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); + expect(buttons).toContainEqual({ + enabled: false, + icon: 'mdi:pan', + priority: 50, + style: {}, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'show_ptz', + show_ptz: true, + }, + title: 'Show PTZ controls', + type: 'custom:frigate-card-menu-icon', + }); + }); + }); + it('should handle dynamic buttons', () => { const button: MenuItem = { ...dynamicButton, diff --git a/tests/components-lib/ptz-controller.test.ts b/tests/components-lib/ptz-controller.test.ts new file mode 100644 index 00000000..11f047a4 --- /dev/null +++ b/tests/components-lib/ptz-controller.test.ts @@ -0,0 +1,316 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { PTZController } from '../../src/components-lib/ptz-controller'; +import { + FrigateCardPTZConfig, + frigateCardPTZSchema, + PTZControlAction, +} from '../../src/config/types'; +import { + frigateCardHandleActionConfig, + getActionConfigGivenAction, +} from '../../src/utils/action.js'; +import { + createCameraCapabilities, + createCameraManager, + createHASS, +} from '../test-utils'; + +vi.mock('../../src/utils/action.js'); + +const createConfig = (config?: Partial): FrigateCardPTZConfig => { + return frigateCardPTZSchema.parse({ + ...config, + }); +}; + +// @vitest-environment jsdom +describe('PTZController', () => { + beforeEach(() => { + vi.resetAllMocks(); + }); + + it('should be creatable', () => { + const controller = new PTZController(document.createElement('div')); + expect(controller).toBeTruthy(); + }); + + it('should get config creatable', () => { + const controller = new PTZController(document.createElement('div')); + const config = createConfig(); + controller.setConfig(config); + expect(controller.getConfig()).toBe(config); + }); + + describe('should set element attributes', () => { + describe('orientation', () => { + describe('with config', () => { + it.each([['horizontal' as const], ['vertical' as const]])( + '%s', + (orientation: 'horizontal' | 'vertical') => { + const element = document.createElement('div'); + const controller = new PTZController(element); + controller.setConfig(createConfig({ orientation: orientation })); + expect(element.getAttribute('data-orientation')).toBe(orientation); + }, + ); + }); + it('without config', () => { + const element = document.createElement('div'); + const controller = new PTZController(element); + controller.setConfig(); + expect(element.getAttribute('data-orientation')).toBe('horizontal'); + }); + }); + describe('position', () => { + describe('with config', () => { + it.each([ + ['top-left' as const], + ['top-right' as const], + ['bottom-left' as const], + ['bottom-right' as const], + ])( + '%s', + (position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right') => { + const element = document.createElement('div'); + const controller = new PTZController(element); + controller.setConfig(createConfig({ position: position })); + expect(element.getAttribute('data-position')).toBe(position); + }, + ); + }); + it('without config', () => { + const element = document.createElement('div'); + const controller = new PTZController(element); + controller.setConfig(); + expect(element.getAttribute('data-position')).toBe('bottom-right'); + }); + }); + it('with style in config', () => { + const element = document.createElement('div'); + const controller = new PTZController(element); + controller.setConfig(createConfig({ style: { transform: 'none', left: '50%' } })); + expect(element.getAttribute('style')).toBe('transform:none;left:50%'); + }); + }); + + describe('should respect mode', () => { + it('off', () => { + const controller = new PTZController(document.createElement('div')); + expect(controller.shouldDisplay()).toBeFalsy(); + }); + it('off but forced on', () => { + const controller = new PTZController(document.createElement('div')); + controller.setForceVisibility(true); + // No actions, no rendering, no matter what. + expect(controller.shouldDisplay()).toBeFalsy(); + }); + it('on without actions', () => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig(createConfig({ mode: 'on' })); + expect(controller.shouldDisplay()).toBeFalsy(); + }); + it('on with actions', () => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig(createConfig({ mode: 'on', actions_left: {} })); + controller.setCamera(createCameraManager(), 'camera.office'); + expect(controller.shouldDisplay()).toBeTruthy(); + }); + it('on with actions but forced off', () => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig(createConfig({ mode: 'on', actions_left: {} })); + controller.setCamera(createCameraManager(), 'camera.office'); + controller.setForceVisibility(false); + expect(controller.shouldDisplay()).toBeFalsy(); + }); + }); + + describe('should get PTZ actions', () => { + it('without config', () => { + const controller = new PTZController(document.createElement('div')); + expect(controller.getPTZActions('left')).toBeNull(); + }); + + describe('using defaults', () => { + describe('with continous PTZ', () => { + it.each([ + ['left' as const], + ['right' as const], + ['up' as const], + ['down' as const], + ['zoom_in' as const], + ['zoom_out' as const], + ])('%s', (actionName: PTZControlAction) => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig(createConfig()); + + const cameraManager = createCameraManager(); + vi.mocked(cameraManager).getCameraCapabilities.mockReturnValue( + createCameraCapabilities({ + ptz: { + panTilt: ['continuous'], + zoom: ['continuous'], + }, + }), + ); + controller.setCamera(cameraManager, 'camera.office'); + + expect(controller.getPTZActions(actionName)).toEqual({ + start_tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: actionName, + ptz_phase: 'start', + }, + end_tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: actionName, + ptz_phase: 'stop', + }, + }); + }); + }); + + describe('with relative PTZ', () => { + it.each([ + ['left' as const], + ['right' as const], + ['up' as const], + ['down' as const], + ['zoom_in' as const], + ['zoom_out' as const], + ])('%s', (actionName: PTZControlAction) => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig(createConfig()); + + const cameraManager = createCameraManager(); + vi.mocked(cameraManager).getCameraCapabilities.mockReturnValue( + createCameraCapabilities({ + ptz: { + panTilt: ['relative'], + zoom: ['relative'], + }, + }), + ); + controller.setCamera(cameraManager, 'camera.office'); + + expect(controller.getPTZActions(actionName)).toEqual({ + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: actionName, + }, + }); + }); + }); + + it('home', () => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig(createConfig()); + + const cameraManager = createCameraManager(); + vi.mocked(cameraManager).getCameraCapabilities.mockReturnValue( + createCameraCapabilities({ + ptz: { + presets: ['preset-foo'], + }, + }), + ); + controller.setCamera(cameraManager, 'camera.office'); + + expect(controller.getPTZActions('home')).toEqual({ + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'preset', + ptz_preset: 'preset-foo', + }, + }); + }); + }); + + describe('using config', () => { + it.each([ + ['left' as const], + ['right' as const], + ['up' as const], + ['down' as const], + ['zoom_in' as const], + ['zoom_out' as const], + ])('%s', (actionName: PTZControlAction) => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig( + createConfig({ + [`actions_${actionName}`]: { + argument: actionName, + }, + }), + ); + controller.setCamera(createCameraManager(), 'camera.office'); + + expect(controller.getPTZActions(actionName)).toEqual({ + argument: actionName, + }); + }); + + it('home', () => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig( + createConfig({ + actions_home: { + argument: 'home', + }, + }), + ); + controller.setCamera(createCameraManager(), 'camera.office'); + + expect(controller.getPTZActions('home')).toEqual({ + argument: 'home', + }); + }); + }); + }); + + describe('should handle action', () => { + it('without hass or action', () => { + const controller = new PTZController(document.createElement('div')); + controller.setHASS(); + controller.setCamera(); + controller.handleAction( + new CustomEvent<{ action: string }>('@action', { detail: { action: 'tap' } }), + ); + expect(frigateCardHandleActionConfig).not.toBeCalled(); + }); + + it('with action', () => { + const element = document.createElement('div'); + const controller = new PTZController(element); + const hass = createHASS(); + controller.setHASS(hass); + controller.setConfig( + createConfig({ + [`actions_left`]: {}, + }), + ); + const tapAction = { + action: 'none' as const, + }; + const actionsConfig = { + tap_action: tapAction, + }; + vi.mocked(getActionConfigGivenAction).mockReturnValue(tapAction); + + controller.handleAction( + new CustomEvent<{ action: string }>('@action', { detail: { action: 'tap' } }), + actionsConfig, + ); + expect(frigateCardHandleActionConfig).toBeCalledWith( + element, + hass, + actionsConfig, + 'tap', + actionsConfig.tap_action, + ); + }); + }); +}); diff --git a/tests/config-mgmt.test.ts b/tests/config-mgmt.test.ts index 4ca5eb32..cb51a12c 100644 --- a/tests/config-mgmt.test.ts +++ b/tests/config-mgmt.test.ts @@ -739,4 +739,433 @@ describe('should handle version specific upgrades', () => { }); }); }); + + describe('should move PTZ elements to live', () => { + it('case with 1 element', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, + actions_up: { + tap_action: { + action: 'call-service', + service: 'notify.persistent_notification', + service_data: { + message: 'Hello 1', + }, + }, + }, + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + cameras: [{ camera_entity: 'camera.office' }], + live: { + controls: { + ptz: { + actions_up: { + tap_action: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + orientation: 'vertical', + style: { + color: 'white', + right: '20px', + top: '20px', + }, + }, + }, + }, + type: 'custom:frigate-card', + }); + }); + + it('case with >1 element', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, + actions_up: { + tap_action: { + action: 'call-service', + service: 'notify.persistent_notification', + service_data: { + message: 'Hello 1', + }, + }, + }, + }, + { + type: 'service-button', + title: 'title', + service: 'service', + service_data: { + message: "It's a trick", + }, + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + service: 'service', + service_data: { + message: "It's a trick", + }, + title: 'title', + type: 'service-button', + }, + ], + live: { + controls: { + ptz: { + actions_up: { + tap_action: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + orientation: 'vertical', + style: { + color: 'white', + right: '20px', + top: '20px', + }, + }, + }, + }, + type: 'custom:frigate-card', + }); + }); + + it('case with custom conditional element with 2 PTZ but nothing else', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + type: 'custom:frigate-card-conditional', + conditions: { + fullscreen: true, + media_loaded: true, + }, + elements: [ + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, + actions_up: { + tap_action: { + action: 'call-service', + service: 'notify.persistent_notification', + service_data: { + message: 'Hello 1', + }, + }, + }, + }, + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, + actions_up: { + tap_action: { + action: 'call-service', + service: 'notify.persistent_notification', + service_data: { + message: 'Hello 2', + }, + }, + }, + }, + ], + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + cameras: [{ camera_entity: 'camera.office' }], + live: { + controls: { + ptz: { + actions_up: { + tap_action: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + orientation: 'vertical', + style: { + color: 'white', + right: '20px', + top: '20px', + }, + }, + }, + }, + type: 'custom:frigate-card', + }); + }); + + it('case with custom conditional element with 1 PTZ and another element', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + type: 'custom:frigate-card-conditional', + conditions: { + fullscreen: true, + media_loaded: true, + }, + elements: [ + { + type: 'service-button', + title: 'title', + service: 'service', + service_data: { + message: "It's a trick", + }, + }, + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, + actions_up: { + tap_action: { + action: 'call-service', + service: 'notify.persistent_notification', + service_data: { + message: 'Hello 1', + }, + }, + }, + }, + ], + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + cameras: [{ camera_entity: 'camera.office' }], + live: { + controls: { + ptz: { + actions_up: { + tap_action: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + orientation: 'vertical', + style: { + color: 'white', + right: '20px', + top: '20px', + }, + }, + }, + }, + elements: [ + { + type: 'custom:frigate-card-conditional', + conditions: { + fullscreen: true, + media_loaded: true, + }, + elements: [ + { + type: 'service-button', + title: 'title', + service: 'service', + service_data: { + message: "It's a trick", + }, + }, + ], + }, + ], + type: 'custom:frigate-card', + }); + }); + + it('case with stock conditional element with 1 PTZ', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + type: 'conditional', + conditions: [{ entity: 'light.office', state: 'on' }], + elements: [ + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, + actions_up: { + tap_action: { + action: 'call-service', + service: 'notify.persistent_notification', + service_data: { + message: 'Hello 1', + }, + }, + }, + }, + ], + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + cameras: [{ camera_entity: 'camera.office' }], + live: { + controls: { + ptz: { + actions_up: { + tap_action: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + orientation: 'vertical', + style: { + color: 'white', + right: '20px', + top: '20px', + }, + }, + }, + }, + type: 'custom:frigate-card', + }); + }); + + it('case when live.controls.ptz already exists', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + live: { + controls: { + ptz: { + actions_up: { + tap_action: { + action: 'call-service', + data: { + message: 'Original', + }, + service: 'notify.persistent_notification', + }, + }, + orientation: 'vertical', + style: { + color: 'white', + right: '20px', + top: '20px', + }, + }, + }, + }, + elements: [ + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, + actions_up: { + tap_action: { + action: 'call-service', + service: 'notify.persistent_notification', + service_data: { + message: 'Replacement that should be ignored', + }, + }, + }, + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + cameras: [{ camera_entity: 'camera.office' }], + live: { + controls: { + ptz: { + actions_up: { + tap_action: { + action: 'call-service', + data: { + message: 'Original', + }, + service: 'notify.persistent_notification', + }, + }, + orientation: 'vertical', + style: { + color: 'white', + right: '20px', + top: '20px', + }, + }, + }, + }, + type: 'custom:frigate-card', + }); + }); + + }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 6d762c68..0dbd69c3 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -68,6 +68,14 @@ describe('config defaults', () => { size: 48, style: 'chevrons', }, + ptz: { + hide_home: false, + hide_pan_tilt: false, + hide_zoom: false, + mode: 'on', + orientation: 'horizontal', + position: 'bottom-right', + }, thumbnails: { media: 'all', mode: 'right', @@ -208,6 +216,10 @@ describe('config defaults', () => { enabled: false, priority: 50, }, + ptz: { + enabled: false, + priority: 50, + }, recordings: { enabled: false, priority: 50, @@ -343,7 +355,13 @@ describe('should convert webrtc card PTZ to Frigate card PTZ', () => { }, }, service: 'foo', - type: 'custom:frigate-card-ptz', + + hide_home: false, + hide_pan_tilt: false, + hide_zoom: false, + mode: 'on', + orientation: 'horizontal', + position: 'bottom-right', }); }); }); diff --git a/tests/test-utils.ts b/tests/test-utils.ts index 7458701c..8c134c6d 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -1,27 +1,17 @@ import { HassEntities, HassEntity } from 'home-assistant-js-websocket'; import { vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; +import { Camera } from '../src/camera-manager/camera'; +import { CameraManagerEngine } from '../src/camera-manager/engine'; import { FrigateEvent, FrigateRecording } from '../src/camera-manager/frigate/types'; +import { GenericCameraManagerEngine } from '../src/camera-manager/generic/engine-generic'; import { CameraManager } from '../src/camera-manager/manager'; import { CameraManagerStore } from '../src/camera-manager/store'; import { - CameraConfigs, CameraManagerCameraCapabilities, + CameraManagerCapabilities, CameraManagerMediaCapabilities, - QueryType, } from '../src/camera-manager/types'; -import { - CameraConfig, - FrigateCardCondition, - FrigateCardConfig, - PerformanceConfig, - RawFrigateCardConfig, - cameraConfigSchema, - frigateCardConditionSchema, - frigateCardConfigSchema, - performanceConfigSchema, -} from '../src/config/types'; -import { ExtendedHomeAssistant, MediaLoadedInfo } from '../src/types'; import { ActionsManager } from '../src/card-controller/actions-manager'; import { AutoUpdateManager } from '../src/card-controller/auto-update-manager'; import { AutomationsManager } from '../src/card-controller/automations-manager'; @@ -44,6 +34,18 @@ import { QueryStringManager } from '../src/card-controller/query-string-manager' import { StyleManager } from '../src/card-controller/style-manager'; import { TriggersManager } from '../src/card-controller/triggers-manager'; import { ViewManager } from '../src/card-controller/view-manager'; +import { + CameraConfig, + cameraConfigSchema, + FrigateCardCondition, + frigateCardConditionSchema, + FrigateCardConfig, + frigateCardConfigSchema, + PerformanceConfig, + performanceConfigSchema, + RawFrigateCardConfig, +} from '../src/config/types'; +import { ExtendedHomeAssistant, MediaLoadedInfo } from '../src/types'; import { Entity } from '../src/utils/ha/entity-registry/types'; import { ViewMedia, ViewMediaType } from '../src/view/media'; import { MediaQueriesResults } from '../src/view/media-queries-results'; @@ -150,55 +152,51 @@ export const createViewWithMedia = (options?: Partial): View => }); }; -export const createCameraManager = (options?: { - store?: CameraManagerStore; - configs?: CameraConfigs; -}): CameraManager => { - const cameraManager = new CameraManager(createCardAPI()); - let store: CameraManagerStore | undefined = options?.store; - if (!store) { - store = mock(); - const configs = options?.configs ?? new Map([['camera', createCameraConfig()]]); - vi.mocked(store.getCameras).mockReturnValue(configs); - vi.mocked(store.getVisibleCameras).mockReturnValue(configs); - vi.mocked(store.getVisibleCameraIDs).mockReturnValue(new Set(configs.keys())); - vi.mocked(store.hasVisibleCameraID).mockImplementation((cameraID: string) => - [...configs.keys()].includes(cameraID), - ); - vi.mocked(store.getCameraConfig).mockImplementation( - (cameraID): CameraConfig | null => { - return configs.get(cameraID) ?? null; - }, +export const createStore = ( + cameras?: { + cameraID: string; + engine?: CameraManagerEngine; + config?: CameraConfig; + capabilities?: CameraManagerCameraCapabilities; + }[], +): CameraManagerStore => { + const store = new CameraManagerStore(); + for (const cameraProps of cameras ?? []) { + const camera = new Camera( + cameraProps.config ?? createCameraConfig(), + cameraProps.engine ?? new GenericCameraManagerEngine(), + cameraProps.capabilities ?? createCameraCapabilities(), ); + camera.setID(cameraProps.cameraID); + store.addCamera(camera); } - vi.mocked(cameraManager.getStore).mockReturnValue(store); - vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue([ - { - cameraIDs: new Set(['camera']), - type: QueryType.Event, - }, - ]); - vi.mocked(cameraManager.generateDefaultRecordingQueries).mockReturnValue([ - { - cameraIDs: new Set(['camera']), - type: QueryType.Recording, - }, - ]); - vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue({ - canFavoriteEvents: true, - canFavoriteRecordings: true, - canSeek: true, - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, - supportsTimeline: true, - }); + return store; +}; +export const createCameraManager = (): CameraManager => { + const cameraManager = mock(); + vi.mocked(cameraManager.getStore).mockReturnValue(createStore()); return cameraManager; }; +export const createAggregateCameraCapabilities = ( + capabilities?: Partial, +): CameraManagerCapabilities => { + return { + canFavoriteEvents: false, + canFavoriteRecordings: false, + canSeek: false, + supportsClips: false, + supportsRecordings: false, + supportsSnapshots: false, + supportsTimeline: false, + supportsPTZ: false, + ...capabilities, + }; +}; + export const createCameraCapabilities = ( - options?: Partial, + capabilities?: Partial, ): CameraManagerCameraCapabilities => { return { canFavoriteEvents: false, @@ -208,7 +206,7 @@ export const createCameraCapabilities = ( supportsRecordings: false, supportsSnapshots: false, supportsTimeline: false, - ...options, + ...capabilities, }; }; diff --git a/tests/utils/action.test.ts b/tests/utils/action.test.ts index 1a8c3e69..d75389b6 100644 --- a/tests/utils/action.test.ts +++ b/tests/utils/action.test.ts @@ -4,7 +4,11 @@ import { mock } from 'vitest-mock-extended'; import { actionSchema } from '../../src/config/types'; import { convertActionToFrigateCardCustomAction, - createFrigateCardCustomAction, + createFrigateCardCameraAction, + createFrigateCardDisplayModeAction, + createFrigateCardMediaPlayerAction, + createFrigateCardShowPTZAction, + createFrigateCardSimpleAction, frigateCardHandleAction, frigateCardHandleActionConfig, frigateCardHasAction, @@ -37,13 +41,24 @@ describe('convertActionToFrigateCardCustomAction', () => { }); }); -describe('createFrigateCardCustomAction', () => { - it('should create camera_select', () => { +describe('createFrigateCardSimpleAction', () => { + it('should create general action', () => { expect( - createFrigateCardCustomAction('camera_select', { - camera: 'camera', + createFrigateCardSimpleAction('clips', { cardID: 'card_id', }), + ).toEqual({ + action: 'fire-dom-event', + frigate_card_action: 'clips', + card_id: 'card_id', + }); + }); +}); + +describe('createFrigateCardCameraAction', () => { + it('should create camera_select', () => { + expect( + createFrigateCardCameraAction('camera_select', 'camera', { cardID: 'card_id' }), ).toEqual({ action: 'fire-dom-event', camera: 'camera', @@ -51,16 +66,12 @@ describe('createFrigateCardCustomAction', () => { card_id: 'card_id', }); }); +}); - it('should not create camera_select without camera', () => { - expect(createFrigateCardCustomAction('camera_select')).toBeNull(); - }); - +describe('createFrigateCardMediaPlayerAction', () => { it('should create media_player', () => { expect( - createFrigateCardCustomAction('media_player', { - media_player: 'device', - media_player_action: 'play', + createFrigateCardMediaPlayerAction('device', 'play', { cardID: 'card_id', }), ).toEqual({ @@ -71,37 +82,12 @@ describe('createFrigateCardCustomAction', () => { card_id: 'card_id', }); }); +}); - it('should not create media_player without player or action', () => { - expect( - createFrigateCardCustomAction('media_player', { - media_player_action: 'play', - }), - ).toBeNull(); - - expect( - createFrigateCardCustomAction('media_player', { - media_player: 'device', - }), - ).toBeNull(); - }); - - it('should create general action', () => { - expect( - createFrigateCardCustomAction('clips', { - cardID: 'card_id', - }), - ).toEqual({ - action: 'fire-dom-event', - frigate_card_action: 'clips', - card_id: 'card_id', - }); - }); - +describe('createFrigateCardDisplayModeAction', () => { it('should create display mode action', () => { expect( - createFrigateCardCustomAction('display_mode_select', { - display_mode: 'grid', + createFrigateCardDisplayModeAction('grid', { cardID: 'card_id', }), ).toEqual({ @@ -111,9 +97,20 @@ describe('createFrigateCardCustomAction', () => { card_id: 'card_id', }); }); +}); - it('should not create display mode action without display mode', () => { - expect(createFrigateCardCustomAction('display_mode_select')).toBeNull(); +describe('createFrigateCardShowPTZAction', () => { + it('should create show PTZ action', () => { + expect( + createFrigateCardShowPTZAction(true, { + cardID: 'card_id', + }), + ).toEqual({ + action: 'fire-dom-event', + frigate_card_action: 'show_ptz', + show_ptz: true, + card_id: 'card_id', + }); }); }); @@ -124,13 +121,13 @@ describe('getActionConfigGivenAction', () => { }); it('should not handle undefined arguments', () => { - expect(getActionConfigGivenAction()).toBeUndefined(); + expect(getActionConfigGivenAction()).toBeNull(); }); it('should not handle unknown interactions', () => { expect( getActionConfigGivenAction('triple_poke', { triple_poke_action: action }), - ).toBeUndefined(); + ).toBeNull(); }); it('should handle tap actions', () => { @@ -178,17 +175,23 @@ describe('frigateCardHandleActionConfig', () => { }); it('should handle simple case', () => { - frigateCardHandleActionConfig(element, createHASS(), {}, 'tap', action); + const hass = createHASS(); + frigateCardHandleActionConfig(element, hass, {}, 'tap', action); expect(handleActionConfig).toBeCalled(); + expect(handleActionConfig).toBeCalledWith(element, hass, {}, action); }); it('should handle array case', () => { - frigateCardHandleActionConfig(element, createHASS(), {}, 'tap', [ - action, - action, - action, - ]); + const hass = createHASS(); + frigateCardHandleActionConfig(element, hass, {}, 'tap', [action, action, action]); expect(handleActionConfig).toBeCalledTimes(3); + expect(handleActionConfig).toBeCalledWith(element, hass, {}, action); + }); + + it('should handle null case', () => { + const hass = createHASS(); + frigateCardHandleActionConfig(element, hass, {}, 'tap', null); + expect(handleActionConfig).toBeCalledWith(element, hass, {}, undefined); }); }); diff --git a/tests/utils/camera.test.ts b/tests/utils/camera.test.ts index a69f5432..c84b2d15 100644 --- a/tests/utils/camera.test.ts +++ b/tests/utils/camera.test.ts @@ -1,11 +1,6 @@ import { describe, expect, it, vi } from 'vitest'; -import { mock } from 'vitest-mock-extended'; -import { CameraManager } from '../../src/camera-manager/manager.js'; -import { CameraConfigs } from '../../src/camera-manager/types.js'; -import { getAllDependentCameras, getCameraID } from '../../src/utils/camera.js'; -import { createCameraConfig, createCameraManager } from '../test-utils.js'; - -vi.mock('../../src/camera-manager/manager.js'); +import { getCameraID } from '../../src/utils/camera.js'; +import { createCameraConfig } from '../test-utils.js'; describe('getCameraID', () => { it('should get camera id with id', () => { @@ -25,7 +20,9 @@ describe('getCameraID', () => { expect(getCameraID(config)).toBe('foo'); }); it('should get camera id with go2rtc url and stream', () => { - const config = createCameraConfig({ go2rtc: { url: 'https://foo', stream: 'office' } }); + const config = createCameraConfig({ + go2rtc: { url: 'https://foo', stream: 'office' }, + }); expect(getCameraID(config)).toBe('https://foo#office'); }); it('should get camera id with frigate camera_name', () => { @@ -39,48 +36,3 @@ describe('getCameraID', () => { expect(getCameraID(config)).toBe(''); }); }); - -describe('getAllDependentCameras', () => { - it('should return null without cameraManager', () => { - expect(getAllDependentCameras()).toBeNull(); - }); - it('should return null without cameraID', () => { - expect(getAllDependentCameras(mock())).toBeNull(); - }); - it('should return dependent cameras', () => { - const cameraConfigs: CameraConfigs = new Map([ - [ - 'one', - createCameraConfig({ - dependencies: { - cameras: ['two', 'three'], - }, - }), - ], - ['two', createCameraConfig({})], - ]); - - const cameraManager = createCameraManager({ configs: cameraConfigs }); - expect(getAllDependentCameras(cameraManager, 'one')).toEqual( - new Set(['one', 'two']), - ); - }); - it('should return all cameras', () => { - const cameraConfigs: CameraConfigs = new Map([ - [ - 'one', - createCameraConfig({ - dependencies: { - all_cameras: true, - }, - }), - ], - ['two', createCameraConfig({})], - ]); - - const cameraManager = createCameraManager({ configs: cameraConfigs }); - expect(getAllDependentCameras(cameraManager, 'one')).toEqual( - new Set(['one', 'two']), - ); - }); -}); diff --git a/tests/utils/diagnostics.test.ts b/tests/utils/diagnostics.test.ts index d56a6080..a68c627e 100644 --- a/tests/utils/diagnostics.test.ts +++ b/tests/utils/diagnostics.test.ts @@ -13,7 +13,6 @@ vi.mock('../../package.json', () => ({ gitDate: 'Wed, 6 Sep 2023 21:27:28 -0700', }, })); -vi.mock('../../src/camera-manager/manager.js'); vi.mock('../../src/utils/ha'); vi.mock('../../src/localize/localize.js'); vi.mock('../../src/utils/ha/device-registry'); diff --git a/tests/utils/download.test.ts b/tests/utils/download.test.ts index c5c9ac0b..dd4ecca9 100644 --- a/tests/utils/download.test.ts +++ b/tests/utils/download.test.ts @@ -1,12 +1,10 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; -import { CameraManager } from '../../src/camera-manager/manager.js'; import { downloadMedia, downloadURL } from '../../src/utils/download'; import { homeAssistantSignPath } from '../../src/utils/ha'; import { ViewMedia } from '../../src/view/media'; import { createCameraManager, createHASS } from '../test-utils'; -vi.mock('../../src/camera-manager/manager.js'); vi.mock('../../src/utils/ha'); const media = new ViewMedia('clip', 'camera-1'); @@ -73,7 +71,7 @@ describe('downloadMedia', () => { it('should throw error when no media', () => { const cameraManager = createCameraManager(); - mock(cameraManager).getMediaDownloadPath.mockResolvedValue(null); + vi.mocked(cameraManager.getMediaDownloadPath).mockResolvedValue(null); expect(downloadMedia(createHASS(), cameraManager, media)).rejects.toThrow( /No media to download/, @@ -84,7 +82,7 @@ describe('downloadMedia', () => { vi.spyOn(global.console, 'warn').mockReturnValue(undefined); const cameraManager = createCameraManager(); - mock(cameraManager).getMediaDownloadPath.mockResolvedValue({ + vi.mocked(cameraManager).getMediaDownloadPath.mockResolvedValue({ sign: true, endpoint: 'foo', }); @@ -98,7 +96,7 @@ describe('downloadMedia', () => { it('should download media', async () => { const cameraManager = createCameraManager(); - mock(cameraManager).getMediaDownloadPath.mockResolvedValue({ + vi.mocked(cameraManager).getMediaDownloadPath.mockResolvedValue({ sign: true, endpoint: 'foo', }); @@ -111,7 +109,7 @@ describe('downloadMedia', () => { it('should download media without signing', async () => { const cameraManager = createCameraManager(); - mock(cameraManager).getMediaDownloadPath.mockResolvedValue({ + vi.mocked(cameraManager).getMediaDownloadPath.mockResolvedValue({ sign: false, endpoint: 'https://foo/', }); diff --git a/tests/utils/media-to-view.test.ts b/tests/utils/media-to-view.test.ts index 579c594b..9cb614be 100644 --- a/tests/utils/media-to-view.test.ts +++ b/tests/utils/media-to-view.test.ts @@ -1,7 +1,7 @@ import add from 'date-fns/add'; import sub from 'date-fns/sub'; import { beforeEach, describe, expect, it, Mock, vi } from 'vitest'; -import { CameraConfigs } from '../../src/camera-manager/types'; +import { QueryType } from '../../src/camera-manager/types'; import { changeViewToRecentEventsForCameraAndDependents, changeViewToRecentRecordingForCameraAndDependents, @@ -14,12 +14,11 @@ import { EventMediaQueries } from '../../src/view/media-queries'; import { createCameraManager, createPerformanceConfig, + createStore, createView, TestViewMedia, } from '../test-utils'; -vi.mock('../../src/camera-manager/manager.js'); - const createElementListenForView = (): { element: HTMLElement; viewHandler: Mock; @@ -66,11 +65,10 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { it('should do nothing without camera config for selected camera', async () => { const elementHandler = createElementListenForView(); - const cameraManager = createCameraManager({ configs: new Map() }); await changeViewToRecentEventsForCameraAndDependents( elementHandler.element, - cameraManager, + createCameraManager(), {}, createView(), ); @@ -79,11 +77,10 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { it('should do nothing without camera configs for all cameras', async () => { const elementHandler = createElementListenForView(); - const cameraManager = createCameraManager({ configs: new Map() }); await changeViewToRecentEventsForCameraAndDependents( elementHandler.element, - cameraManager, + createCameraManager(), {}, createView(), { @@ -113,6 +110,19 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { it('should dispatch new view on success', async () => { const elementHandler = createElementListenForView(); const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera', + }, + ]), + ); + vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera']), + }, + ]); const mediaArray = [new ViewMedia('clip', 'camera')]; vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(mediaArray); @@ -136,6 +146,19 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { const elementHandler = createElementListenForView(); const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera', + }, + ]), + ); + vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera']), + }, + ]); vi.mocked(cameraManager.executeMediaQueries).mockRejectedValue(new Error()); await changeViewToRecentEventsForCameraAndDependents( @@ -150,6 +173,13 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { it('should respect media chunk size', async () => { const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera', + }, + ]), + ); await changeViewToRecentEventsForCameraAndDependents( createElementListenForView().element, @@ -178,6 +208,13 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { ['clips' as const, 'hasClip'], ])('%s', async (mediaType, queryParameter) => { const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera', + }, + ]), + ); await changeViewToRecentEventsForCameraAndDependents( createElementListenForView().element, @@ -206,12 +243,9 @@ describe('executeMediaQueryForView', () => { }); it('should not execute empty queries', async () => { - const cameraConfigs: CameraConfigs = new Map(); - const cameraManager = createCameraManager({ configs: cameraConfigs }); - expect( await executeMediaQueryForView( - cameraManager, + createCameraManager(), createView(), new EventMediaQueries(), ), @@ -219,24 +253,25 @@ describe('executeMediaQueryForView', () => { }); it('should throw on failure', async () => { - const cameraConfigs: CameraConfigs = new Map(); - const cameraManager = createCameraManager({ configs: cameraConfigs }); + const cameraManager = createCameraManager(); vi.mocked(cameraManager.executeMediaQueries).mockRejectedValue(new Error()); await expect( executeMediaQueryForView( cameraManager, createView(), - new EventMediaQueries( - cameraManager.generateDefaultEventQueries('camera') ?? undefined, - ), + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set('camera'), + }, + ]), ), ).rejects.toThrowError(); }); it('should select time-based result', async () => { - const cameraConfigs: CameraConfigs = new Map(); - const cameraManager = createCameraManager({ configs: cameraConfigs }); + const cameraManager = createCameraManager(); const now = new Date(); const mediaArray = [ @@ -249,9 +284,12 @@ describe('executeMediaQueryForView', () => { const view = await executeMediaQueryForView( cameraManager, createView(), - new EventMediaQueries( - cameraManager.generateDefaultEventQueries('camera') ?? undefined, - ), + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set('camera'), + }, + ]), { select: 'time', targetTime: add(now, { seconds: 30 }), @@ -264,8 +302,7 @@ describe('executeMediaQueryForView', () => { }); it('should select nothing when time-based selection does not match', async () => { - const cameraConfigs: CameraConfigs = new Map(); - const cameraManager = createCameraManager({ configs: cameraConfigs }); + const cameraManager = createCameraManager(); const now = new Date(); const mediaArray = [ @@ -279,9 +316,12 @@ describe('executeMediaQueryForView', () => { const view = await executeMediaQueryForView( cameraManager, createView(), - new EventMediaQueries( - cameraManager.generateDefaultEventQueries('camera') ?? undefined, - ), + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set('camera'), + }, + ]), { select: 'time', targetTime: sub(now, { seconds: 30 }), @@ -292,6 +332,24 @@ describe('executeMediaQueryForView', () => { expect(view?.queryResults?.getSelectedIndex()).toBe(2); expect(view?.queryResults?.getResults()).toBe(mediaArray); }); + + it('should select nothing when query returns null', async () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(null); + + expect( + await executeMediaQueryForView( + cameraManager, + createView(), + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set('camera'), + }, + ]), + ), + ).toBeNull(); + }); }); // @vitest-environment jsdom @@ -302,11 +360,10 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => { it('should do nothing without camera config for selected camera', async () => { const elementHandler = createElementListenForView(); - const cameraManager = createCameraManager({ configs: new Map() }); await changeViewToRecentRecordingForCameraAndDependents( elementHandler.element, - cameraManager, + createCameraManager(), {}, createView(), ); @@ -315,11 +372,10 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => { it('should do nothing without camera configs for all cameras', async () => { const elementHandler = createElementListenForView(); - const cameraManager = createCameraManager({ configs: new Map() }); await changeViewToRecentRecordingForCameraAndDependents( elementHandler.element, - cameraManager, + createCameraManager(), {}, createView(), { @@ -346,9 +402,22 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => { it('should dispatch new view on success', async () => { const elementHandler = createElementListenForView(); const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera', + }, + ]), + ); const mediaArray = [new ViewMedia('recording', 'camera')]; vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(mediaArray); + vi.mocked(cameraManager.generateDefaultRecordingQueries).mockReturnValue([ + { + type: QueryType.Recording, + cameraIDs: new Set(['camera']), + }, + ]); await changeViewToRecentRecordingForCameraAndDependents( elementHandler.element, @@ -366,6 +435,13 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => { it('should respect media chunk size', async () => { const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera', + }, + ]), + ); await changeViewToRecentRecordingForCameraAndDependents( createElementListenForView().element, @@ -402,9 +478,7 @@ describe('executeMediaQueryForViewWithErrorDispatching', () => { elementHandler.element, cameraManager, createView(), - new EventMediaQueries( - cameraManager.generateDefaultEventQueries('camera') ?? undefined, - ), + new EventMediaQueries([{ type: QueryType.Event, cameraIDs: new Set(['camera']) }]), ); expect(elementHandler.viewHandler).not.toBeCalled(); diff --git a/tests/utils/ptz.test.ts b/tests/utils/ptz.test.ts new file mode 100644 index 00000000..3aefcf1d --- /dev/null +++ b/tests/utils/ptz.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, it } from 'vitest'; +import { FrigateCardPTZConfig, frigateCardPTZSchema } from '../../src/config/types'; +import { hasUsablePTZ } from '../../src/utils/ptz'; +import { createCameraCapabilities } from '../test-utils'; + +const createPTZConfig = ( + config?: Partial, +): FrigateCardPTZConfig => { + return frigateCardPTZSchema.parse(config ?? {}); +}; + +describe('hasUsablePTZ', () => { + it('should return true with manual actions', () => { + expect( + hasUsablePTZ( + createCameraCapabilities(), + createPTZConfig({ + actions_left: {}, + }), + ), + ).toBeTruthy(); + }); + it('should return true with capabilities', () => { + expect( + hasUsablePTZ( + createCameraCapabilities({ + ptz: {}, + }), + createPTZConfig(), + ), + ).toBeTruthy(); + }); + it('should return false with manual actions or capabilities', () => { + expect(hasUsablePTZ(createCameraCapabilities(), createPTZConfig())).toBeFalsy(); + }); +}); From 984e60f626c01ca5a8a3616607e5f37dab55e190 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 30 Oct 2023 01:59:01 -0700 Subject: [PATCH 067/189] Remove old TODO. --- src/config/types.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/config/types.ts b/src/config/types.ts index a8aceed8..3b7d12e6 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -832,9 +832,6 @@ export const frigateCardPTZSchema = z.preprocess( return out; }, frigateCardPTZActions.extend({ - // TODO strip from config update - // type: z.literal('custom:frigate-card-ptz'), - mode: z.enum(['off', 'on']).default(livePTZControlsDefaults.mode), position: z .enum(['top-left', 'top-right', 'bottom-left', 'bottom-right']) From f67511c6c1470fa6c1230306172814e9b6a67225 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 31 Oct 2023 14:06:10 -0700 Subject: [PATCH 068/189] Enforce coverage %. --- .github/workflows/build.yml | 24 ++++++++++++++++-------- .gitignore | 2 +- rollup.config.js | 5 ++++- vite.config.ts | 8 ++++++++ 4 files changed, 29 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 344bdf89..4ed0f679 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ on: - dev pull_request: schedule: - - cron: "17 6 * * *" + - cron: '17 6 * * *' workflow_dispatch: jobs: @@ -25,23 +25,31 @@ jobs: - name: Install dependencies run: yarn install --immutable + - name: Test & Coverage + run: yarn run coverage + - name: Build run: yarn run build - - name: Test - run: yarn run test - - name: HACS build validation - uses: "hacs/action@21.12.1" + uses: 'hacs/action@21.12.1' with: - category: "plugin" + category: 'plugin' # Don't attempt to load into HACS (as it loads the release, not the # build). - ignore: "hacs" + ignore: 'hacs' - - name: Upload artifact + - name: Upload javascript uses: actions/upload-artifact@v3 with: name: frigate-hass-card path: dist/*.js + + # When this issue is fixed, it would be useful to upload visualizations: + # https://github.com/actions/upload-artifact/issues/14 + # - name: Upload visualizations + # uses: actions/upload-artifact@v3 + # with: + # name: frigate-hass-card + # path: visualizations/*.html diff --git a/.gitignore b/.gitignore index 13e1d646..6e919754 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ package-lock.json .env .envrc -stats.html +/visualizations/ /coverage/ # https://yarnpkg.com/getting-started/qa#which-files-should-be-gitignored diff --git a/rollup.config.js b/rollup.config.js index 821de314..9ebfe496 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -58,7 +58,10 @@ const plugins = [ }), watch && serve(serveopts), !dev && terser(), - visualizer(), + visualizer({ + filename: 'visualizations/treemap.html', + template: 'treemap', + }), ]; /** diff --git a/vite.config.ts b/vite.config.ts index c5d2f145..aeacea4f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -6,6 +6,14 @@ export default defineConfig({ coverage: { // Favor istanbul for coverage over v8 due to better accuracy. provider: 'istanbul', + + // Thresholds will automatically be updated as coverage improves to avoid + // back-sliding. + thresholdAutoUpdate: true, + statements: 71.65, + branches: 60.62, + functions: 72.78, + lines: 71.54, }, }, }); From 278f4f372d8ebc1014cd2c2c2794a86528726733 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 17 Jan 2024 22:07:30 -0800 Subject: [PATCH 069/189] Initial version of more advanced scan mode control. --- README.md | 35 ++- src/card-controller/actions-manager.ts | 34 +- src/card-controller/hass-manager.ts | 2 +- src/card-controller/interaction-manager.ts | 3 - src/card-controller/query-string-manager.ts | 44 +-- src/card-controller/triggers-manager.ts | 162 ++++++---- src/card-controller/types.ts | 30 +- src/card-controller/view-manager.ts | 2 + src/card.ts | 2 +- src/config/types.ts | 82 ++++- src/const.ts | 6 +- src/editor.ts | 13 +- src/localize/languages/en.json | 2 +- src/localize/languages/it.json | 2 +- src/localize/languages/pt-BR.json | 2 +- src/localize/languages/pt-PT.json | 2 +- tests/card-controller/actions-manager.test.ts | 138 ++++++-- tests/card-controller/hass-manager.test.ts | 4 +- .../interaction-manager.test.ts | 1 - .../media-player-manager.test.ts | 1 - .../query-string-manager.test.ts | 88 +----- .../card-controller/triggers-manager.test.ts | 294 ++++++++++++++---- tests/config/types.test.ts | 20 +- vite.config.ts | 6 +- 24 files changed, 648 insertions(+), 327 deletions(-) diff --git a/README.md b/README.md index ec370777..218f38ec 100644 --- a/README.md +++ b/README.md @@ -421,20 +421,43 @@ view: scan: ``` -Scan mode allows the card to automatically "follow the action". In this mode the card will automatically select a camera in the `live` view when an entity changes to an active state (specifically `on` or `open`). The entities considered are defined by your camera configuration (see `triggers` parameters). An untrigger is defined as the state for all the configured entities returning to inactive (i.e. not `on` or `open`), with an optional number of seconds to wait prior to the untriggering (see `untrigger_seconds`). +Scan mode allows the card to automatically "follow the action". In this mode the card will automatically execute an action (defined by `trigger_action`) when a camera is 'triggered', by default selecting that camera in the `live` view . The trigger entities considered are defined by your camera configuration (see `triggers` parameters). An untrigger is defined as the state for all the configured entities returning to inactive (i.e. not `on` or `open`), with an optional number of seconds to wait prior to the untriggering (see `untrigger_seconds`). -When the camera untriggers, the view will either remain as-is (if `untrigger_reset` is `false`) and the card return to normal operation, or reset to the default view (if `untrigger_reset` is `true` -- the default). +When the camera untriggers, a different action (defined by `untrigger_action`) is automatically executed, by default returning the card to the default view and camera. -Triggering is only allowed when there is no ongoing human interaction with the card -- interaction will automatically untrigger and further triggering will not occur until after the card has been unattended for `view.timeout_seconds`. +By default, triggering is only allowed when there is no ongoing human interaction with the card. This behavior can be controlled by the `interaction_mode` parameter. Scan mode tracks Home Assistant state *changes* -- when the card is first started, it takes an active change in state to trigger (i.e. an already occupied room will not trigger it, but a newly occupied room will). | Option | Default | Overridable | Description | | - | - | - | - | | `enabled` | `false` | :white_check_mark: | Whether to enable scan mode. | -| `show_trigger_status` | `true` | :white_check_mark: | Whether or not the card should show a visual indication that it is triggered (a pulsing border around the card edge). | +| `interaction_mode` | `inactive` | :white_check_mark: | Whether actions should be taken when the card is being interacted with. If `all`, actions will always be taken regardless. If `inactive` actions will only be taken if the card has *not* had human interaction recently (as defined by `view.timeout_seconds`). If `active` actions will only be taken if the card *has* had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `trigger_show_status` is true) but rather just prevents the actions being performed.| +| `trigger_filter_camera` | `all` | :white_check_mark: | If set to `all` the camera will be triggered regardless of which camera is currently selected, if set to `selected` the camera will only trigger if that camera is already selected.| +| `trigger_show_status` | `true` | :white_check_mark: | Whether or not the card should show a visual indication that it is triggered (a pulsing border around the card edge). | +| `trigger_action` | Selects triggered camera in `live` view (see below) | :white_check_mark: | An action or list of actions that are executed when a camera is triggered. May be set to `null` for no action.| | `untrigger_reset` | `true` | :white_check_mark: | Whether or not to reset the view to the default after untriggering. | | `untrigger_seconds` | `0` | :white_check_mark: | The number of seconds to wait after all entities are inactive before untriggering. | +| `untrigger_action` | Selects default view and camera (see below) | :white_check_mark: | An action or list of actions that are executed when a camera is triggered. May bet to `null` for no action.| + +##### View: Scan Mode default actions + +The default `trigger_action` is: + +```yaml + - action: custom:frigate-card-action + frigate_card_action: camera_select + triggered: true + - action: custom:frigate-card-action + frigate_card_action: live +``` + +The default `untrigger_action` is: + +```yaml + - action: custom:frigate-card-action + frigate_card_action: default +``` ### Menu Options @@ -1422,7 +1445,7 @@ Parameters for the `custom:frigate-card-conditional` element: |`download`|Download the displayed media.| |`camera_ui`|Open the Frigate UI at the configured URL.| |`fullscreen`|Toggle fullscreen.| -|`camera_select`|Select a given camera. Takes a single additional `camera` parameter with the [camera ID](#camera-ids) of the camera to select. Respects the value of `view.camera_select` to choose the appropriate view on the new camera.| +|`camera_select`|Select a given camera. Takes an additional `camera` parameter with the [camera ID](#camera-ids) of the camera to select. Respects the value of `view.camera_select` to choose the appropriate view on the new camera. If a `triggered` parameter is set to `true` instead of `camera` being specified then a triggered camera (if any) is selected instead. | |`menu_toggle` | Show/hide the menu (for the `hidden` mode style). | |`media_player`| Perform a media player action. Takes a `media_player` parameter with the entity ID of the media_player on which to perform the action, and a `media_player_action` parameter which should be either `play` or `stop` to play or stop the media in question. | |`live_substream_select`| Perform a media player action. Takes a `camera` parameter with the [camera ID](#camera-ids) of the substream camera. | @@ -1912,7 +1935,7 @@ view: dark_mode: 'off' scan: enabled: false - show_trigger_status: true + trigger_show_status: true untrigger_reset: true untrigger_seconds: 0 actions: diff --git a/src/card-controller/actions-manager.ts b/src/card-controller/actions-manager.ts index 68a0572f..a40ab535 100644 --- a/src/card-controller/actions-manager.ts +++ b/src/card-controller/actions-manager.ts @@ -1,11 +1,13 @@ import { Actions, ActionsConfig, + ActionType, FrigateCardCustomAction, FRIGATE_CARD_VIEW_DEFAULT, } from '../config/types.js'; import { convertActionToFrigateCardCustomAction, + frigateCardHandleAction, frigateCardHandleActionConfig, getActionConfigGivenAction, } from '../utils/action.js'; @@ -81,16 +83,36 @@ export class ActionsManager { const frigateCardAction = convertActionToFrigateCardCustomAction(ev.detail); if (frigateCardAction) { - this.executeAction(frigateCardAction); + this.executeFrigateAction(frigateCardAction); } }; + /** + * Small convenience method to call frigateCardHandleAction without the caller + * needing hass or the element. + */ + public executeActions(actions: ActionType | ActionType[]): void { + const hass = this._api.getHASSManager().getHASS(); + if (!hass) { + return; + } + + frigateCardHandleAction( + this._api.getCardElementManager().getElement(), + hass, + {}, + actions, + ); + } + /** * Execute a card action. * @param frigateCardAction * @returns `true` if an action is executed. */ - public async executeAction(frigateCardAction: FrigateCardCustomAction): Promise { + public async executeFrigateAction( + frigateCardAction: FrigateCardCustomAction, + ): Promise { const config = this._api.getConfigManager().getConfig(); const mediaLoadedInfoManager = this._api.getMediaLoadedInfoManager(); @@ -146,8 +168,12 @@ export class ActionsManager { this._api.getCardElementManager().toggleMenu(); break; case 'camera_select': - const selectCameraID = frigateCardAction.camera; - if (view) { + const selectCameraID = + frigateCardAction.camera ?? + (frigateCardAction.triggered + ? this._api.getTriggersManager().getMostRecentlyTriggeredCameraID() + : null); + if (selectCameraID && view) { const viewOnCameraSelect = config?.view.camera_select ?? 'current'; const targetViewName = viewOnCameraSelect === 'current' ? view.view : viewOnCameraSelect; diff --git a/src/card-controller/hass-manager.ts b/src/card-controller/hass-manager.ts index 35134171..4c697165 100644 --- a/src/card-controller/hass-manager.ts +++ b/src/card-controller/hass-manager.ts @@ -74,7 +74,7 @@ export class HASSManager { this._api.getCardElementManager().update(); } - this._api.getTriggersManager().updateTriggeredCameras(oldHass); + this._api.getTriggersManager().updateTriggerHAState(oldHass); if (this._api.getConditionsManager().hasHAStateConditions()) { this._api.getConditionsManager().setState({ state: this._hass.states }); diff --git a/src/card-controller/interaction-manager.ts b/src/card-controller/interaction-manager.ts index 24a473b8..af04cc81 100644 --- a/src/card-controller/interaction-manager.ts +++ b/src/card-controller/interaction-manager.ts @@ -27,9 +27,6 @@ export class InteractionManager { protected _reportInteraction(): void { this._timer.stop(); - // Interactions reset the trigger state. - this._api.getTriggersManager().untrigger(); - const timeoutSeconds = this._api.getConfigManager().getConfig() ?.view.timeout_seconds; diff --git a/src/card-controller/query-string-manager.ts b/src/card-controller/query-string-manager.ts index 41840f84..f118f3be 100644 --- a/src/card-controller/query-string-manager.ts +++ b/src/card-controller/query-string-manager.ts @@ -1,5 +1,8 @@ import { FrigateCardCustomAction, FrigateCardViewAction } from '../config/types'; -import { createFrigateCardCameraAction, createFrigateCardSimpleAction } from '../utils/action.js'; +import { + createFrigateCardCameraAction, + createFrigateCardSimpleAction +} from '../utils/action.js'; import { CardQueryStringAPI } from './types'; import { ViewManagerSetViewParameters } from './view-manager'; @@ -35,43 +38,6 @@ export class QueryStringManager { this._executeNonViewRelated(intent); }; - public generateQueryString(action: FrigateCardCustomAction): string | null { - const baseKey = - 'frigate-card-action.' + (action.card_id ? `${action.card_id}.` : ''); - - switch (action.frigate_card_action) { - case 'camera_select': - case 'live_substream_select': - return new URLSearchParams([ - [baseKey + action.frigate_card_action, action.camera], - ]).toString(); - case 'camera_ui': - case 'clip': - case 'clips': - case 'default': - case 'diagnostics': - case 'download': - case 'expand': - case 'image': - case 'live': - case 'menu_toggle': - case 'recording': - case 'recordings': - case 'snapshot': - case 'snapshots': - case 'timeline': - return new URLSearchParams([ - [baseKey + action.frigate_card_action, ''], - ]).toString(); - default: - console.warn( - `Frigate card cannot convert unsupported action to query string:`, - action, - ); - } - return null; - } - protected _executeViewRelated(intent: QueryStringViewIntent): void { if (intent.view) { if (intent.view.default) { @@ -96,7 +62,7 @@ export class QueryStringManager { } intent.other?.forEach((action) => - this._api.getActionsManager().executeAction(action), + this._api.getActionsManager().executeFrigateAction(action), ); } diff --git a/src/card-controller/triggers-manager.ts b/src/card-controller/triggers-manager.ts index 9e9ab222..78ff1295 100644 --- a/src/card-controller/triggers-manager.ts +++ b/src/card-controller/triggers-manager.ts @@ -2,30 +2,44 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import orderBy from 'lodash-es/orderBy'; import { getHassDifferences, isTriggeredState } from '../utils/ha'; import { Timer } from '../utils/timer'; +import { View } from '../view/view'; import { CardTriggersAPI } from './types'; export class TriggersManager { protected _api: CardTriggersAPI; - protected _triggers: Map = new Map(); - protected _untriggerTimer = new Timer(); + protected _triggeredCameras: Map = new Map(); + protected _triggeredCameraTimers: Map = new Map(); + protected _triggeredState: Set = new Set(); constructor(api: CardTriggersAPI) { this._api = api; } - public isTriggered(): boolean { - return !!this._triggers.size || this._untriggerTimer.isRunning(); + public getTriggeredCameraIDs(): Set { + return new Set(this._triggeredCameras.keys()); } - public updateTriggeredCameras(oldHass?: HomeAssistant | null): boolean { - if (!this._shouldTrackTriggers()) { - return false; + public isTriggered(): boolean { + return !!this._triggeredCameras.size; + } + + public getMostRecentlyTriggeredCameraID(): string | null { + const sorted = orderBy( + [...this._triggeredCameras.entries()], + (entry) => entry[1].getTime(), + 'desc', + ); + return sorted.length ? sorted[0][0] : null; + } + + public updateTriggerHAState(oldHass?: HomeAssistant | null): void { + const scanConfig = this._api.getConfigManager().getConfig()?.view.scan; + if (!scanConfig || !scanConfig.enabled) { + return; } const hass = this._api.getHASSManager().getHASS(); - - const now = new Date(); let triggerChanges = false; const visibleCameraIDs = this._api @@ -45,88 +59,108 @@ export class TriggersManager { (entity) => !isTriggeredState(hass?.states[entity]), ); if (shouldTrigger) { - this._triggers.set(cameraID, now); + this._triggeredState.add(cameraID); triggerChanges = true; - } else if (shouldUntrigger && this._triggers.has(cameraID)) { - this._triggers.delete(cameraID); + } else if (shouldUntrigger && this._triggeredState.has(cameraID)) { + this._triggeredState.delete(cameraID); triggerChanges = true; } } if (triggerChanges) { - const targetCameraID = this._getMostRecentTrigger(); - if (targetCameraID) { - this._triggerAction(targetCameraID); - return true; - } else { - this._startUntriggerTimer(); + this._evaluateTriggers(); + } + } + + public updateView(oldView?: View | null): void { + if (oldView?.camera !== this._api.getViewManager().getView()?.camera) { + // If the view changes, a new camera may have been selected, which may + // mean a trigger is required (in the case that `trigger_filter_camera` + // has been set to `selected`). + this._evaluateTriggers(); + } + } + + protected _evaluateTriggers(): void { + const scanConfig = this._api.getConfigManager().getConfig()?.view.scan; + if (!scanConfig) { + return; + } + + const now = new Date(); + for (const cameraID of this._triggeredState.keys()) { + if ( + !this._triggeredCameras.has(cameraID) && + (scanConfig.trigger_filter_camera === 'all' || + (scanConfig.trigger_filter_camera === 'selected' && + cameraID === this._api.getViewManager().getView()?.camera)) + ) { + this._triggeredCameras.set(cameraID, now); + this._triggerAction(); } } - return false; - } - public untrigger(): void { - const wasTriggered = this.isTriggered(); - this._triggers.clear(); - this._untriggerTimer.stop(); - - if (wasTriggered) { - this._untriggerAction(); + for (const cameraID of this._triggeredCameras.keys()) { + if (!this._triggeredState.has(cameraID)) { + this._startUntriggerTimer(cameraID); + } } } - protected _triggerAction(cameraID: string): void { - const view = this._api.getViewManager().getView(); - if ( - this._isAutomatedViewUpdateAllowed() && - (view?.camera !== cameraID || !view?.is('live')) - ) { - this._api.getViewManager().setViewByParameters({ - viewName: 'live', - cameraID: cameraID, - }); - } - } + protected _hasAllowableInteractionState(): boolean { + const scanConfig = this._api.getConfigManager().getConfig()?.view.scan; + const hasInteraction = this._api.getInteractionManager().hasInteraction(); - protected _untriggerAction(): void { - if ( - !this.isTriggered() && - this._isAutomatedViewUpdateAllowed() && - this._api.getConfigManager().getConfig()?.view.scan.untrigger_reset - ) { - this._api.getViewManager().setViewDefault(); - } - } - - protected _isAutomatedViewUpdateAllowed(): boolean { return ( - this._api.getConfigManager().getConfig()?.view.update_force || - !this._api.getInteractionManager().hasInteraction() + !!scanConfig && + (scanConfig.interaction_mode === 'all' || + (scanConfig.interaction_mode === 'active' && hasInteraction) || + (scanConfig.interaction_mode === 'inactive' && !hasInteraction)) ); } - protected _shouldTrackTriggers(): boolean { - return !!this._api.getConfigManager().getConfig()?.view.scan.enabled; + protected _triggerAction(): void { + const action = this._api.getConfigManager().getConfig()?.view.scan.trigger_action; + + if (action && this._hasAllowableInteractionState()) { + this._api.getActionsManager().executeActions(action); + } + + // Must update master element to add border pulsing. + this._api.getCardElementManager().update(); } - protected _startUntriggerTimer(): void { - this._untriggerTimer.start( + protected _untriggerAction(cameraID: string): void { + const action = this._api.getConfigManager().getConfig()?.view.scan.untrigger_action; + + if (action && this._hasAllowableInteractionState()) { + this._api.getActionsManager().executeActions(action); + } + this._triggeredCameras.delete(cameraID); + this._deleteTimer(cameraID); + + // Must update master element to remove border pulsing. + this._api.getCardElementManager().update(); + } + + protected _startUntriggerTimer(cameraID: string): void { + this._deleteTimer(cameraID); + + const timer = new Timer(); + this._triggeredCameraTimers.set(cameraID, timer); + timer.start( /* istanbul ignore next: the case of config being null here cannot be reached, as there's no way to have the untrigger call happen without a config. -- @preserve */ this._api.getConfigManager().getConfig()?.view.scan.untrigger_seconds ?? 0, () => { - this._untriggerAction(); + this._untriggerAction(cameraID); }, ); } - protected _getMostRecentTrigger(): string | null { - const sorted = orderBy( - [...this._triggers.entries()], - (entry) => entry[1].getTime(), - 'desc', - ); - return sorted.length ? sorted[0][0] : null; + protected _deleteTimer(cameraID: string): void { + this._triggeredCameraTimers.get(cameraID)?.stop(); + this._triggeredCameraTimers.delete(cameraID); } } diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index 95776b50..a962d08a 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -41,8 +41,9 @@ export interface CardActionsManagerAPI { getMediaLoadedInfoManager(): MediaLoadedInfoManager; getMediaPlayerManager(): MediaPlayerManager; getMessageManager(): MessageManager; - getViewManager(): ViewManager; getMicrophoneManager(): MicrophoneManager; + getTriggersManager(): TriggersManager; + getViewManager(): ViewManager; } export interface CardAutomationsAPI { @@ -55,17 +56,17 @@ export interface CardAutomationsAPI { export interface CardAutoRefreshAPI { getConfigManager(): ConfigManager; - getViewManager(): ViewManager; - getTriggersManager(): TriggersManager; getInteractionManager(): InteractionManager; + getTriggersManager(): TriggersManager; + getViewManager(): ViewManager; } export interface CardCameraAPI { getConfigManager(): ConfigManager; getEntityRegistryManager(): EntityRegistryManager; - getResolvedMediaCache(): ResolvedMediaCache; getHASSManager(): HASSManager; getMessageManager(): MessageManager; + getResolvedMediaCache(): ResolvedMediaCache; } export interface CardCameraURLAPI { @@ -106,15 +107,15 @@ export interface CardElementAPI { } export interface CardExpandAPI { - getFullscreenManager(): FullscreenManager; - getConditionsManager(): ConditionsManager; getCardElementManager(): CardElementManager; + getConditionsManager(): ConditionsManager; + getFullscreenManager(): FullscreenManager; } export interface CardFullscreenAPI { getCardElementManager(): CardElementManager; - getExpandManager(): ExpandManager; getConditionsManager(): ConditionsManager; + getExpandManager(): ExpandManager; getMediaPlayerManager(): MediaPlayerManager; } @@ -153,23 +154,23 @@ export interface CardInteractionAPI { } export interface CardMediaLoadedAPI { + getCardElementManager(): CardElementManager; getConditionsManager(): ConditionsManager; getConfigManager(): ConfigManager; - getCardElementManager(): CardElementManager; getStyleManager(): StyleManager; } export interface CardMediaPlayerAPI { - getHASSManager(): HASSManager; getCameraManager(): CameraManager; getEntityRegistryManager(): EntityRegistryManager; + getHASSManager(): HASSManager; getMessageManager(): MessageManager; getQueryStringManager(): QueryStringManager; } export interface CardMessageAPI { - getConditionsManager(): ConditionsManager; getCardElementManager(): CardElementManager; + getConditionsManager(): ConditionsManager; getMediaLoadedInfoManager(): MediaLoadedInfoManager; } @@ -179,9 +180,9 @@ export interface CardMicrophoneAPI { } export interface CardQueryStringAPI { + getActionsManager(): ActionsManager; getCardElementManager(): CardElementManager; getViewManager(): ViewManager; - getActionsManager(): ActionsManager; } export interface CardStyleAPI { @@ -196,7 +197,9 @@ export interface CardStyleAPI { } export interface CardTriggersAPI { + getActionsManager(): ActionsManager; getCameraManager(): CameraManager; + getCardElementManager(): CardElementManager; getConfigManager(): ConfigManager; getHASSManager(): HASSManager; getInteractionManager(): InteractionManager; @@ -206,11 +209,12 @@ export interface CardTriggersAPI { export interface CardViewAPI { getAutoUpdateManager(): AutoUpdateManager; getCameraManager(): CameraManager; + getCardElementManager(): CardElementManager; + getConditionsManager(): ConditionsManager; getConfigManager(): ConfigManager; getHASSManager(): HASSManager; getMediaLoadedInfoManager(): MediaLoadedInfoManager; getMessageManager(): MessageManager; getStyleManager(): StyleManager; - getConditionsManager(): ConditionsManager; - getCardElementManager(): CardElementManager; + getTriggersManager(): TriggersManager; } diff --git a/src/card-controller/view-manager.ts b/src/card-controller/view-manager.ts index 569cb323..71940719 100644 --- a/src/card-controller/view-manager.ts +++ b/src/card-controller/view-manager.ts @@ -244,6 +244,8 @@ export class ViewManager { camera: view.camera, displayMode: view.displayMode ?? undefined, }); + + this._api.getTriggersManager().updateView(oldView); this._api.getCardElementManager().update(); } diff --git a/src/card.ts b/src/card.ts index 527b710a..1f50e2b4 100644 --- a/src/card.ts +++ b/src/card.ts @@ -241,7 +241,7 @@ class FrigateCard extends LitElement { const cardClasses = { triggered: !!this._controller.getTriggersManager().isTriggered() && - !!this._config?.view.scan.show_trigger_status, + !!this._config?.view.scan.trigger_show_status, }; const mainClasses = { main: true, diff --git a/src/config/types.ts b/src/config/types.ts index 3b7d12e6..f618ea74 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -1,3 +1,43 @@ +// TODO: Config migration +// TODO: Editor support for scan mode changes +// TODO: Consider this: + +/* +// NOW ===> +view: + scan: + enabled: true + trigger_show_status: true, + trigger_action: + - action: custom:frigate-card-action + frigate_card_action: camera_select + triggered: true + - action: custom:frigate-card-action + frigate_card_action: live + untrigger_action: + - action: custom:frigate-card-action + interaction_mode: inactive + trigger_filter_camera: all + untrigger_seconds: 0 + +view: + scan: + enabled: true + +// TO + +view: + scan: + enabled: true + trigger_show_status: true + actions: + live | live-reset | none + interaction: inactive | active | all + trigger_filter_camera: all + untrigger_seconds: 0 +automations: +*/ + import { CallServiceActionConfig, ConfirmationRestrictionConfig, @@ -241,7 +281,8 @@ const frigateCardGeneralActionSchema = frigateCardCustomActionsBaseSchema.extend const frigateCardCameraSelectActionSchema = frigateCardCustomActionsBaseSchema.extend({ frigate_card_action: z.literal('camera_select'), - camera: z.string(), + camera: z.string().optional(), + triggered: z.boolean().optional(), }); const frigateCardLiveDependencySelectActionSchema = @@ -1119,17 +1160,48 @@ const viewConfigDefault = { dark_mode: 'off' as const, scan: { enabled: false, - show_trigger_status: true, + trigger_show_status: true, + trigger_action: [ + { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'camera_select' as const, + triggered: true, + }, + { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live' as const, + }, + ], + untrigger_action: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'default' as const, + }, + interaction_mode: 'inactive' as const, + trigger_filter_camera: 'all' as const, untrigger_seconds: 0, - untrigger_reset: true, }, }; const scanSchema = z.object({ enabled: z.boolean().default(viewConfigDefault.scan.enabled), - show_trigger_status: z.boolean().default(viewConfigDefault.scan.show_trigger_status), + + interaction_mode: z + .enum(['all', 'inactive', 'active']) + .default(viewConfigDefault.scan.interaction_mode), + trigger_filter_camera: z + .enum(['all', 'selected']) + .default(viewConfigDefault.scan.trigger_filter_camera), + trigger_show_status: z.boolean().default(viewConfigDefault.scan.trigger_show_status), + trigger_action: actionSchema + .or(actionSchema.array()) + .nullable() + .default(viewConfigDefault.scan.trigger_action), + + untrigger_action: actionSchema + .or(actionSchema.array()) + .nullable() + .default(viewConfigDefault.scan.untrigger_action), untrigger_seconds: z.number().default(viewConfigDefault.scan.untrigger_seconds), - untrigger_reset: z.boolean().default(viewConfigDefault.scan.untrigger_reset), }); export type ScanOptions = z.infer; diff --git a/src/const.ts b/src/const.ts index d2a2a41b..1d6c4c62 100644 --- a/src/const.ts +++ b/src/const.ts @@ -77,10 +77,8 @@ export const CONF_VIEW_UPDATE_FORCE = `${CONF_VIEW}.update_force` as const; export const CONF_VIEW_UPDATE_SECONDS = `${CONF_VIEW}.update_seconds` as const; export const CONF_VIEW_SCAN = `${CONF_VIEW}.scan` as const; export const CONF_VIEW_SCAN_ENABLED = `${CONF_VIEW_SCAN}.enabled` as const; -export const CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS = - `${CONF_VIEW_SCAN}.show_trigger_status` as const; -export const CONF_VIEW_SCAN_UNTRIGGER_RESET = - `${CONF_VIEW_SCAN}.untrigger_reset` as const; +export const CONF_VIEW_SCAN_TRIGGER_SHOW_STATUS = + `${CONF_VIEW_SCAN}.trigger_show_status` as const; export const CONF_VIEW_SCAN_UNTRIGGER_SECONDS = `${CONF_VIEW_SCAN}.untrigger_seconds` as const; diff --git a/src/editor.ts b/src/editor.ts index d981a550..64ab9401 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -182,8 +182,7 @@ import { CONF_VIEW_DEFAULT, CONF_VIEW_SCAN, CONF_VIEW_SCAN_ENABLED, - CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS, - CONF_VIEW_SCAN_UNTRIGGER_RESET, + CONF_VIEW_SCAN_TRIGGER_SHOW_STATUS, CONF_VIEW_SCAN_UNTRIGGER_SECONDS, CONF_VIEW_TIMEOUT_SECONDS, CONF_VIEW_UPDATE_CYCLE_CAMERA, @@ -902,16 +901,12 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor }, )} ${this._renderSwitch( - CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS, - this._defaults.view.scan.show_trigger_status, + CONF_VIEW_SCAN_TRIGGER_SHOW_STATUS, + this._defaults.view.scan.trigger_show_status, { - label: localize(`config.${CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS}`), + label: localize(`config.${CONF_VIEW_SCAN_TRIGGER_SHOW_STATUS}`), }, )} - ${this._renderSwitch( - CONF_VIEW_SCAN_UNTRIGGER_RESET, - this._defaults.view.scan.untrigger_reset, - )} ${this._renderNumberInput(CONF_VIEW_SCAN_UNTRIGGER_SECONDS, { default: this._defaults.view.scan.untrigger_seconds, })} diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 64b2c503..6d93d174 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -387,7 +387,7 @@ "scan": { "enabled": "Scan mode enabled", "scan_mode": "Scan mode", - "show_trigger_status": "Show pulsing border when triggered", + "trigger_show_status": "Show pulsing border when triggered", "untrigger_reset": "Reset the view to default after untrigger", "untrigger_seconds": "Seconds after inactive state change to untrigger" }, diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index e4af3d0f..363c00c4 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -383,7 +383,7 @@ "scan": { "enabled": "Modalità di scansione abilitata", "scan_mode": "Modalità di scansione", - "show_trigger_status": "Mostra bordo pulsante quando attivato", + "trigger_show_status": "Mostra bordo pulsante quando attivato", "untrigger_reset": "Reset the view to default after untrigger", "untrigger_seconds": "Reimposta la vista ai valori predefiniti dopo aver annullato l'attivazione" }, diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 4028931f..58c5c7ad 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -386,7 +386,7 @@ "scan": { "enabled": "Modo scan ativado", "scan_mode": "Modo scan", - "show_trigger_status": "Pulsar borda quando acionado", + "trigger_show_status": "Pulsar borda quando acionado", "untrigger_reset": "Redefinir a visualização para o padrão após desacionar", "untrigger_seconds": "Segundos após a mudar para o estado inativo para desacionar" }, diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index daebd3ed..702913ce 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -376,7 +376,7 @@ "scan": { "enabled": "Modo scan ativado", "scan_mode": "Modo scan", - "show_trigger_status": "Exibir estado do gatilho", + "trigger_show_status": "Exibir estado do gatilho", "untrigger_reset": "Redefinir a visualização para o padrão após desacionar", "untrigger_seconds": "Segundos após a mudar para o estado inativo para desacionar" }, diff --git a/tests/card-controller/actions-manager.test.ts b/tests/card-controller/actions-manager.test.ts index 52c794f1..f864302c 100644 --- a/tests/card-controller/actions-manager.test.ts +++ b/tests/card-controller/actions-manager.test.ts @@ -9,6 +9,7 @@ import { import { FrigateCardMediaPlayer } from '../../src/types'; import { convertActionToFrigateCardCustomAction, + frigateCardHandleAction, frigateCardHandleActionConfig, getActionConfigGivenAction, } from '../../src/utils/action.js'; @@ -245,7 +246,7 @@ describe('ActionsManager.executeAction', () => { const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ card_id: 'NOT_foo', frigate_card_action: 'default', @@ -259,7 +260,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'default', })!, @@ -283,7 +284,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: viewName, })!, @@ -301,7 +302,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'download', })!, @@ -314,7 +315,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'camera_ui', })!, @@ -327,7 +328,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'expand', })!, @@ -340,7 +341,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'fullscreen', })!, @@ -353,7 +354,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'menu_toggle', })!, @@ -370,7 +371,7 @@ describe('ActionsManager.executeAction', () => { vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'camera_select', camera: 'camera', @@ -397,7 +398,7 @@ describe('ActionsManager.executeAction', () => { ); vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'camera_select', camera: 'camera', @@ -430,7 +431,7 @@ describe('ActionsManager.executeAction', () => { vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'camera_select', camera: 'camera', @@ -445,11 +446,55 @@ describe('ActionsManager.executeAction', () => { ); }); + it('with triggered camera', async () => { + const api = createCardAPI(); + const manager = new ActionsManager(api); + + vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); + vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); + vi.mocked( + api.getTriggersManager().getMostRecentlyTriggeredCameraID, + ).mockReturnValue('camera'); + + await manager.executeFrigateAction( + createAction({ + frigate_card_action: 'camera_select', + triggered: true, + })!, + ); + + expect(api.getViewManager().setViewByParameters).toBeCalledWith( + expect.objectContaining({ + viewName: 'live', + cameraID: 'camera', + }), + ); + }); + + it('without camera or triggered camera', async () => { + const api = createCardAPI(); + const manager = new ActionsManager(api); + + vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); + vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); + vi.mocked( + api.getTriggersManager().getMostRecentlyTriggeredCameraID, + ).mockReturnValue('camera'); + + await manager.executeFrigateAction( + createAction({ + frigate_card_action: 'camera_select', + })!, + ); + + expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + }); + it('without a current view', async () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'camera_select', camera: 'camera', @@ -469,7 +514,7 @@ describe('ActionsManager.executeAction', () => { }), ); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'camera_select', camera: 'camera', @@ -490,7 +535,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'live_substream_select', camera: 'substream', @@ -504,7 +549,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'live_substream_off', })!, @@ -517,7 +562,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'live_substream_on', })!, @@ -531,7 +576,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'media_player', media_player_action: 'stop', @@ -552,7 +597,7 @@ describe('ActionsManager.executeAction', () => { ); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'media_player', media_player_action: 'play', @@ -576,7 +621,7 @@ describe('ActionsManager.executeAction', () => { vi.mocked(api.getViewManager().getView).mockReturnValue(view); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'media_player', media_player_action: 'play', @@ -599,7 +644,7 @@ describe('ActionsManager.executeAction', () => { ); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'media_player', media_player_action: 'play', @@ -615,7 +660,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'diagnostics', })!, @@ -632,7 +677,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'microphone_mute', })!, @@ -645,7 +690,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'microphone_unmute', })!, @@ -670,7 +715,7 @@ describe('ActionsManager.executeAction', () => { ); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: action, })!, @@ -684,7 +729,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'screenshot', })!, @@ -697,7 +742,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'display_mode_select', display_mode: 'grid', @@ -715,7 +760,7 @@ describe('ActionsManager.executeAction', () => { createView({ camera: 'camera.office' }), ); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'ptz', ptz_action: 'left', @@ -736,7 +781,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'ptz', ptz_action: 'left', @@ -751,7 +796,7 @@ describe('ActionsManager.executeAction', () => { const api = createCardAPI(); const manager = new ActionsManager(api); - await manager.executeAction( + await manager.executeFrigateAction( createAction({ frigate_card_action: 'show_ptz', show_ptz: true, @@ -768,7 +813,7 @@ describe('ActionsManager.executeAction', () => { const spy = vi.spyOn(global.console, 'warn').mockImplementation(() => true); - await manager.executeAction( + await manager.executeFrigateAction( // Have to manually create the action (vs using `createAction()`) since // it's malformed. { @@ -781,3 +826,36 @@ describe('ActionsManager.executeAction', () => { ); }); }); + +describe('ActionsManager.executeActions', () => { + it('should execute actions', async () => { + const api = createCardAPI(); + const hass = createHASS(); + const element = document.createElement('div'); + + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const manager = new ActionsManager(api); + const action = createAction({ + frigate_card_action: 'default', + })!; + manager.executeActions(action); + + expect(frigateCardHandleAction).toBeCalledWith(element, hass, {}, action); + }); + + it('should not execute actions without hass', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(null); + + const manager = new ActionsManager(api); + manager.executeActions( + createAction({ + frigate_card_action: 'default', + })!, + ); + + expect(api.getViewManager().setViewDefault).not.toBeCalled(); + }); +}); diff --git a/tests/card-controller/hass-manager.test.ts b/tests/card-controller/hass-manager.test.ts index 0fbe2b97..51f64728 100644 --- a/tests/card-controller/hass-manager.test.ts +++ b/tests/card-controller/hass-manager.test.ts @@ -72,10 +72,10 @@ describe('HASSManager', () => { const originalHASS = createHASS(); manager.setHASS(originalHASS); - expect(api.getTriggersManager().updateTriggeredCameras).toBeCalledWith(null); + expect(api.getTriggersManager().updateTriggerHAState).toBeCalledWith(null); manager.setHASS(createHASS()); - expect(api.getTriggersManager().updateTriggeredCameras).toBeCalledWith(originalHASS); + expect(api.getTriggersManager().updateTriggerHAState).toBeCalledWith(originalHASS); }); describe('should handle connection state change when', () => { diff --git a/tests/card-controller/interaction-manager.test.ts b/tests/card-controller/interaction-manager.test.ts index 1f024dbf..be6534d5 100644 --- a/tests/card-controller/interaction-manager.test.ts +++ b/tests/card-controller/interaction-manager.test.ts @@ -30,7 +30,6 @@ describe('InteractionManager', () => { manager.reportInteraction(); - expect(api.getTriggersManager().untrigger).toBeCalled(); expect(manager.hasInteraction()).toBeTruthy(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); diff --git a/tests/card-controller/media-player-manager.test.ts b/tests/card-controller/media-player-manager.test.ts index 836f544e..9e4cb610 100644 --- a/tests/card-controller/media-player-manager.test.ts +++ b/tests/card-controller/media-player-manager.test.ts @@ -271,7 +271,6 @@ describe('MediaPlayerManager', () => { }, ]), ); - vi.mocked(api.getQueryStringManager().generateQueryString).mockReturnValue(''); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); const manager = new MediaPlayerManager(api); diff --git a/tests/card-controller/query-string-manager.test.ts b/tests/card-controller/query-string-manager.test.ts index d453b518..eb9ee80c 100644 --- a/tests/card-controller/query-string-manager.test.ts +++ b/tests/card-controller/query-string-manager.test.ts @@ -28,7 +28,7 @@ describe('QueryStringManager', () => { manager.executeAll(); expect(manager.hasViewRelatedActions()).toBeFalsy(); - expect(api.getActionsManager().executeAction).not.toBeCalled(); + expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); expect(api.getViewManager().setViewByParameters).not.toBeCalled(); }); @@ -76,7 +76,7 @@ describe('QueryStringManager', () => { manager.executeAll(); expect(manager.hasViewRelatedActions()).toBeFalsy(); - expect(api.getActionsManager().executeAction).toBeCalledWith({ + expect(api.getActionsManager().executeFrigateAction).toBeCalledWith({ action: 'fire-dom-event', card_id: 'id', frigate_card_action: action, @@ -97,7 +97,7 @@ describe('QueryStringManager', () => { expect(api.getViewManager().setViewDefault).toBeCalled(); expect(manager.hasViewRelatedActions()).toBeTruthy(); - expect(api.getActionsManager().executeAction).not.toBeCalled(); + expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); expect(api.getViewManager().setViewByParameters).not.toBeCalled(); }); @@ -114,7 +114,7 @@ describe('QueryStringManager', () => { }); expect(manager.hasViewRelatedActions()).toBeTruthy(); - expect(api.getActionsManager().executeAction).not.toBeCalled(); + expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); }); @@ -131,7 +131,7 @@ describe('QueryStringManager', () => { }); expect(manager.hasViewRelatedActions()).toBeTruthy(); - expect(api.getActionsManager().executeAction).not.toBeCalled(); + expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); }); @@ -147,7 +147,7 @@ describe('QueryStringManager', () => { manager.executeAll(); expect(manager.hasViewRelatedActions()).toBeFalsy(); - expect(api.getActionsManager().executeAction).not.toBeCalled(); + expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); expect(api.getViewManager().setViewByParameters).not.toBeCalled(); }, @@ -165,7 +165,7 @@ describe('QueryStringManager', () => { manager.executeAll(); expect(manager.hasViewRelatedActions()).toBeFalsy(); - expect(api.getActionsManager().executeAction).not.toBeCalled(); + expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); expect(api.getViewManager().setViewByParameters).not.toBeCalled(); expect(consoleSpy).toBeCalled(); @@ -212,7 +212,7 @@ describe('QueryStringManager', () => { manager.executeAll(); - expect(api.getActionsManager().executeAction).not.toBeCalled(); + expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); expect(api.getViewManager().setViewByParameters).not.toBeCalled(); }); @@ -296,77 +296,7 @@ describe('QueryStringManager', () => { manager.executeViewRelated(); - expect(api.getActionsManager().executeAction).not.toBeCalled(); - }); - }); - - describe('should generate query string', () => { - describe('that require no arguments', () => { - it.each([ - ['camera_ui' as const], - ['clip' as const], - ['clips' as const], - ['default' as const], - ['diagnostics' as const], - ['download' as const], - ['expand' as const], - ['image' as const], - ['live' as const], - ['menu_toggle' as const], - ['recording' as const], - ['recordings' as const], - ['snapshot' as const], - ['snapshots' as const], - ['timeline' as const], - ])('%s', (actionName: FrigateCardGeneralAction | FrigateCardUserSpecifiedView) => { - const manager = new QueryStringManager(createCardAPI()); - expect( - manager.generateQueryString({ - action: 'fire-dom-event', - frigate_card_action: actionName, - }), - ).toBe(`frigate-card-action.${actionName}=`); - }); - }); - - describe('that require camera argument', () => { - it.each([['camera_select' as const], ['live_substream_select' as const]])( - '%s', - (actionName: 'camera_select' | 'live_substream_select') => { - const manager = new QueryStringManager(createCardAPI()); - expect( - manager.generateQueryString({ - action: 'fire-dom-event', - frigate_card_action: actionName, - camera: 'camera', - }), - ).toBe(`frigate-card-action.${actionName}=camera`); - }, - ); - }); - - it('that include a card_id', () => { - const manager = new QueryStringManager(createCardAPI()); - expect( - manager.generateQueryString({ - action: 'fire-dom-event', - frigate_card_action: 'clips', - card_id: 'card-id', - }), - ).toBe(`frigate-card-action.card-id.clips=`); - }); - - it('that include an unsupported action', () => { - const spy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined); - const manager = new QueryStringManager(createCardAPI()); - - expect( - manager.generateQueryString({ - action: 'fire-dom-event', - frigate_card_action: 'microphone_unmute', - }), - ).toBeNull(); - expect(spy).toBeCalled(); + expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); }); }); }); diff --git a/tests/card-controller/triggers-manager.test.ts b/tests/card-controller/triggers-manager.test.ts index d14d2f7a..7fc1688a 100644 --- a/tests/card-controller/triggers-manager.test.ts +++ b/tests/card-controller/triggers-manager.test.ts @@ -15,6 +15,28 @@ import { createView, } from '../test-utils'; +const baseScanConfig: Partial = { + enabled: true, + untrigger_seconds: 10, + interaction_mode: 'inactive' as const, + trigger_filter_camera: 'all' as const, + trigger_action: [ + { + action: 'fire-dom-event' as const, + frigate_card_action: 'camera_select' as const, + triggered: true, + }, + { + action: 'fire-dom-event' as const, + frigate_card_action: 'live' as const, + }, + ], + untrigger_action: { + action: 'fire-dom-event' as const, + frigate_card_action: 'default' as const, + }, +}; + // Creating and mocking a trigger API is a lot of boilerplate, this convenience // function reduces it. const createTriggerAPI = (options?: { @@ -26,11 +48,7 @@ const createTriggerAPI = (options?: { vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { - scan: options?.config ?? { - enabled: true, - untrigger_reset: true, - untrigger_seconds: 10, - }, + scan: options?.config ?? baseScanConfig, }, }), ); @@ -83,11 +101,28 @@ describe('TriggersManager', () => { }); const manager = new TriggersManager(api); - manager.updateTriggeredCameras(null); + manager.updateTriggerHAState(null); expect(manager.isTriggered()).toBeFalsy(); }); + it('should not trigger without a scan config', () => { + const api = createTriggerAPI({ + hassStates: hassActiveState, + }); + + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + camera: 'camera_1' as const, + }), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(null); + + const manager = new TriggersManager(api); + manager.updateView(null); + expect(manager.isTriggered()).toBeFalsy(); + }); + it('should trigger and untrigger based on entity state', () => { const start = new Date('2023-10-01T17:14'); vi.setSystemTime(start); @@ -96,22 +131,29 @@ describe('TriggersManager', () => { }); const manager = new TriggersManager(api); - manager.updateTriggeredCameras(createHASS(hassInactiveState)); + manager.updateTriggerHAState(createHASS(hassInactiveState)); expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setViewByParameters).toBeCalledWith({ - viewName: 'live', - cameraID: 'camera_1', - }); + expect(api.getActionsManager().executeActions).toBeCalledWith([ + { + action: 'fire-dom-event' as const, + frigate_card_action: 'camera_select' as const, + triggered: true, + }, + { + action: 'fire-dom-event' as const, + frigate_card_action: 'live' as const, + }, + ]); vi.mocked(api.getHASSManager().getHASS).mockReturnValue( createHASS(hassInactiveState), ); - manager.updateTriggeredCameras(createHASS(hassActiveState)); + manager.updateTriggerHAState(createHASS(hassActiveState)); // Intentional state update with no change. - manager.updateTriggeredCameras(createHASS(hassActiveState)); + manager.updateTriggerHAState(createHASS(hassActiveState)); // Will still be triggered, but untrigger timer will be running. expect(manager.isTriggered()).toBeTruthy(); @@ -120,26 +162,10 @@ describe('TriggersManager', () => { vi.runOnlyPendingTimers(); expect(manager.isTriggered()).toBeFalsy(); - expect(api.getViewManager().setViewDefault).toBeCalled(); - }); - it('should trigger and set view if current view is wrong', () => { - const api = createTriggerAPI({ - hassStates: hassActiveState, - }); - vi.mocked(api.getViewManager().getView).mockReturnValue( - createView({ - // Correct camera, but wrong view. - view: 'clips', - camera: 'camera_1', - }), - ); - const manager = new TriggersManager(api); - manager.updateTriggeredCameras(null); - - expect(api.getViewManager().setViewByParameters).toBeCalledWith({ - viewName: 'live', - cameraID: 'camera_1', + expect(api.getActionsManager().executeActions).toBeCalledWith({ + action: 'fire-dom-event' as const, + frigate_card_action: 'default' as const, }); }); @@ -150,40 +176,196 @@ describe('TriggersManager', () => { const manager = new TriggersManager(api); expect(manager.isTriggered()).toBeFalsy(); - manager.updateTriggeredCameras(null); + manager.updateTriggerHAState(null); expect(manager.isTriggered()).toBeTruthy(); }); - it('should untrigger manually', () => { - const api = createTriggerAPI({ - hassStates: hassActiveState, - }); - const manager = new TriggersManager(api); - - // Untriggering when not triggered. - manager.untrigger(); - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - - manager.updateTriggeredCameras(null); - expect(manager.isTriggered()).toBeTruthy(); - - manager.untrigger(); - expect(manager.isTriggered()).toBeFalsy(); - expect(api.getViewManager().setViewDefault).toBeCalled(); - }); - - it('should take no actions when automated actions are not allowed', () => { + it('should take no actions with human interactions', () => { + const start = new Date('2023-10-01T17:14'); const api = createTriggerAPI({ hassStates: hassActiveState, // Interaction present. interaction: true, }); const manager = new TriggersManager(api); - manager.updateTriggeredCameras(null); + manager.updateTriggerHAState(createHASS(hassInactiveState)); expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); - manager.untrigger(); - expect(api.getViewManager().setViewDefault).not.toBeCalled(); + expect(api.getActionsManager().executeActions).not.toBeCalled(); + + vi.mocked(api.getHASSManager().getHASS).mockReturnValue( + createHASS(hassInactiveState), + ); + manager.updateTriggerHAState(createHASS(hassActiveState)); + + vi.setSystemTime(add(start, { seconds: 10 })); + vi.runOnlyPendingTimers(); + + expect(manager.isTriggered()).toBeFalsy(); + + expect(api.getActionsManager().executeActions).not.toBeCalled(); + }); + + it('should take actions with human interactions when interaction mode is active', () => { + const start = new Date('2023-10-01T17:14'); + const api = createTriggerAPI({ + hassStates: hassActiveState, + // Interaction present. + interaction: true, + config: { + ...baseScanConfig, + interaction_mode: 'active', + }, + }); + const manager = new TriggersManager(api); + manager.updateTriggerHAState(createHASS(hassInactiveState)); + expect(manager.isTriggered()).toBeTruthy(); + + expect(api.getActionsManager().executeActions).toBeCalledTimes(1); + + vi.mocked(api.getHASSManager().getHASS).mockReturnValue( + createHASS(hassInactiveState), + ); + manager.updateTriggerHAState(createHASS(hassActiveState)); + + vi.setSystemTime(add(start, { seconds: 10 })); + vi.runOnlyPendingTimers(); + + expect(manager.isTriggered()).toBeFalsy(); + + expect(api.getActionsManager().executeActions).toBeCalledTimes(2); + }); + + it('should report multiple triggered cameras', () => { + const start = new Date('2023-10-01T17:14'); + const bothOnState = { + 'binary_sensor.one': createStateEntity({ state: 'on' }), + 'binary_sensor.two': createStateEntity({ state: 'on' }), + }; + const api = createTriggerAPI({ + hassStates: bothOnState, + }); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera_1', + config: createCameraConfig({ + triggers: { + entities: ['binary_sensor.one'], + }, + }), + }, + { + cameraID: 'camera_2', + config: createCameraConfig({ + triggers: { + entities: ['binary_sensor.two'], + }, + }), + }, + ]), + ); + + const manager = new TriggersManager(api); + + expect(manager.isTriggered()).toBeFalsy(); + expect(manager.getMostRecentlyTriggeredCameraID()).toBeNull(); + expect(manager.getTriggeredCameraIDs()).toEqual(new Set()); + + manager.updateTriggerHAState(null); + expect(manager.isTriggered()).toBeTruthy(); + expect(manager.getTriggeredCameraIDs()).toEqual(new Set(['camera_1', 'camera_2'])); + + // Either is the most recently triggered. + expect(['camera_1', 'camera_2']).toContain( + manager.getMostRecentlyTriggeredCameraID(), + ); + + vi.mocked(api.getHASSManager().getHASS).mockReturnValue( + createHASS({ + 'binary_sensor.one': createStateEntity({ state: 'off' }), + 'binary_sensor.two': createStateEntity({ state: 'on' }), + }), + ); + + manager.updateTriggerHAState(createHASS(bothOnState)); + + vi.setSystemTime(add(start, { seconds: 10 })); + vi.runOnlyPendingTimers(); + + expect(manager.getTriggeredCameraIDs()).toEqual(new Set(['camera_2'])); + expect(manager.getMostRecentlyTriggeredCameraID()).toBe('camera_2'); + }); + + it('should filter triggers by camera', () => { + const start = new Date('2023-10-01T17:14'); + const api = createTriggerAPI({ + config: { + ...baseScanConfig, + // Filter triggers to selected camera only. + trigger_filter_camera: 'selected' as const, + }, + hassStates: hassActiveState, + }); + const manager = new TriggersManager(api); + manager.updateTriggerHAState(createHASS(hassInactiveState)); + expect(manager.isTriggered()).toBeFalsy(); + + const otherCameraSelected = createView({ + camera: 'camera_SOME_OTHER_CAMERA' as const, + }); + + vi.mocked(api.getViewManager().getView).mockReturnValue(otherCameraSelected); + manager.updateView(null); + expect(manager.isTriggered()).toBeFalsy(); + + const thisCameraSelected = createView({ + camera: 'camera_1' as const, + }); + + vi.mocked(api.getViewManager().getView).mockReturnValue(thisCameraSelected); + manager.updateView(otherCameraSelected); + expect(manager.isTriggered()).toBeTruthy(); + + // Ensure a view change to the same camera stays triggered. + vi.mocked(api.getViewManager().getView).mockReturnValue(thisCameraSelected); + manager.updateView(thisCameraSelected); + expect(manager.isTriggered()).toBeTruthy(); + }); + + it('should not untrigger triggers by camera', () => { + const start = new Date('2023-10-01T17:14'); + const api = createTriggerAPI({ + config: { + ...baseScanConfig, + // Filter triggers to selected camera only. + trigger_filter_camera: 'selected' as const, + }, + hassStates: hassActiveState, + }); + const manager = new TriggersManager(api); + manager.updateTriggerHAState(createHASS(hassInactiveState)); + expect(manager.isTriggered()).toBeFalsy(); + + const otherCameraSelected = createView({ + camera: 'camera_SOME_OTHER_CAMERA' as const, + }); + + vi.mocked(api.getViewManager().getView).mockReturnValue(otherCameraSelected); + manager.updateView(null); + expect(manager.isTriggered()).toBeFalsy(); + + const thisCameraSelected = createView({ + camera: 'camera_1' as const, + }); + + vi.mocked(api.getViewManager().getView).mockReturnValue(thisCameraSelected); + manager.updateView(otherCameraSelected); + expect(manager.isTriggered()).toBeTruthy(); + + // Ensure a view change to the same camera stays triggered. + vi.mocked(api.getViewManager().getView).mockReturnValue(thisCameraSelected); + manager.updateView(thisCameraSelected); + expect(manager.isTriggered()).toBeTruthy(); }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 0dbd69c3..7758c2bf 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -279,9 +279,25 @@ describe('config defaults', () => { default: 'live', scan: { enabled: false, - show_trigger_status: true, - untrigger_reset: true, + interaction_mode: 'inactive', + trigger_show_status: true, untrigger_seconds: 0, + trigger_action: [ + { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + triggered: true, + }, + { + action: 'fire-dom-event', + frigate_card_action: 'live', + }, + ], + trigger_filter_camera: 'all', + untrigger_action: { + action: 'fire-dom-event', + frigate_card_action: 'default', + }, }, timeout_seconds: 300, update_cycle_camera: false, diff --git a/vite.config.ts b/vite.config.ts index aeacea4f..ff62e3a5 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,10 +10,10 @@ export default defineConfig({ // Thresholds will automatically be updated as coverage improves to avoid // back-sliding. thresholdAutoUpdate: true, - statements: 71.65, + statements: 71.74, branches: 60.62, - functions: 72.78, - lines: 71.54, + functions: 72.84, + lines: 71.63, }, }, }); From 64a909ead09670c5839787f865bb8a2e7529a333 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 21 Jan 2024 11:30:23 -0800 Subject: [PATCH 070/189] Add editor and migration support. --- README.md | 38 ++--- src/card-controller/triggers-manager.ts | 36 +++-- src/card-controller/types.ts | 1 - src/card.ts | 2 +- src/config-mgmt.ts | 9 ++ src/config/types.ts | 94 +++-------- src/const.ts | 13 +- src/editor.ts | 148 +++++++++++++----- src/localize/languages/en.json | 25 ++- src/localize/languages/it.json | 25 ++- src/localize/languages/pt-BR.json | 25 ++- src/localize/languages/pt-PT.json | 25 ++- .../card-controller/triggers-manager.test.ts | 98 +++++++----- tests/config-mgmt.test.ts | 45 ++++++ tests/config/types.test.ts | 23 +-- vite.config.ts | 8 +- 16 files changed, 385 insertions(+), 230 deletions(-) diff --git a/README.md b/README.md index 218f38ec..8891b1d3 100644 --- a/README.md +++ b/README.md @@ -432,32 +432,16 @@ Scan mode tracks Home Assistant state *changes* -- when the card is first starte | Option | Default | Overridable | Description | | - | - | - | - | | `enabled` | `false` | :white_check_mark: | Whether to enable scan mode. | -| `interaction_mode` | `inactive` | :white_check_mark: | Whether actions should be taken when the card is being interacted with. If `all`, actions will always be taken regardless. If `inactive` actions will only be taken if the card has *not* had human interaction recently (as defined by `view.timeout_seconds`). If `active` actions will only be taken if the card *has* had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `trigger_show_status` is true) but rather just prevents the actions being performed.| -| `trigger_filter_camera` | `all` | :white_check_mark: | If set to `all` the camera will be triggered regardless of which camera is currently selected, if set to `selected` the camera will only trigger if that camera is already selected.| -| `trigger_show_status` | `true` | :white_check_mark: | Whether or not the card should show a visual indication that it is triggered (a pulsing border around the card edge). | -| `trigger_action` | Selects triggered camera in `live` view (see below) | :white_check_mark: | An action or list of actions that are executed when a camera is triggered. May be set to `null` for no action.| -| `untrigger_reset` | `true` | :white_check_mark: | Whether or not to reset the view to the default after untriggering. | +| `filter_selected_camera` | `false` | :white_check_mark: | If set to `true` will only trigger on the currently selected camera.| +| `show_trigger_status` | `true` | :white_check_mark: | Whether or not the card should show a visual indication that it is triggered (a pulsing border around the card edge). | | `untrigger_seconds` | `0` | :white_check_mark: | The number of seconds to wait after all entities are inactive before untriggering. | -| `untrigger_action` | Selects default view and camera (see below) | :white_check_mark: | An action or list of actions that are executed when a camera is triggered. May bet to `null` for no action.| +| `actions` | | :white_check_mark: | The actions to take when scan mode triggers (see below). | -##### View: Scan Mode default actions +#### View: Scan Mode Actions configuration -The default `trigger_action` is: - -```yaml - - action: custom:frigate-card-action - frigate_card_action: camera_select - triggered: true - - action: custom:frigate-card-action - frigate_card_action: live -``` - -The default `untrigger_action` is: - -```yaml - - action: custom:frigate-card-action - frigate_card_action: default -``` +| `trigger` | `live` | :white_check_mark | When `live` the trigger will select the triggered camera in `live` view, when `none` will take no action. | +| `untrigger` | `default` | :white_check_mark | When `default` the untrigger will return to the default view and camera, when `none` will take no action. | +| `interaction_mode` | `inactive` | :white_check_mark: | Whether actions should be taken when the card is being interacted with. If `all`, actions will always be taken regardless. If `inactive` actions will only be taken if the card has *not* had human interaction recently (as defined by `view.timeout_seconds`). If `active` actions will only be taken if the card *has* had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed.| ### Menu Options @@ -1935,9 +1919,13 @@ view: dark_mode: 'off' scan: enabled: false - trigger_show_status: true - untrigger_reset: true + show_trigger_status: true + filter_selected_camera: false untrigger_seconds: 0 + actions: + interaction_mode: 'inactive' as const, + trigger: 'live' as const, + untrigger: 'default' as const, actions: entity: light.office_main_lights tap_action: diff --git a/src/card-controller/triggers-manager.ts b/src/card-controller/triggers-manager.ts index 78ff1295..dbd17869 100644 --- a/src/card-controller/triggers-manager.ts +++ b/src/card-controller/triggers-manager.ts @@ -75,8 +75,8 @@ export class TriggersManager { public updateView(oldView?: View | null): void { if (oldView?.camera !== this._api.getViewManager().getView()?.camera) { // If the view changes, a new camera may have been selected, which may - // mean a trigger is required (in the case that `trigger_filter_camera` - // has been set to `selected`). + // mean a trigger is required (in the case that `filter_selected_camera` + // is true). this._evaluateTriggers(); } } @@ -91,12 +91,11 @@ export class TriggersManager { for (const cameraID of this._triggeredState.keys()) { if ( !this._triggeredCameras.has(cameraID) && - (scanConfig.trigger_filter_camera === 'all' || - (scanConfig.trigger_filter_camera === 'selected' && - cameraID === this._api.getViewManager().getView()?.camera)) + (!scanConfig.filter_selected_camera || + cameraID === this._api.getViewManager().getView()?.camera) ) { this._triggeredCameras.set(cameraID, now); - this._triggerAction(); + this._triggerAction(cameraID); } } @@ -107,23 +106,26 @@ export class TriggersManager { } } - protected _hasAllowableInteractionState(): boolean { + protected _hasAllowableInteractionStateForAction(): boolean { const scanConfig = this._api.getConfigManager().getConfig()?.view.scan; const hasInteraction = this._api.getInteractionManager().hasInteraction(); return ( !!scanConfig && - (scanConfig.interaction_mode === 'all' || - (scanConfig.interaction_mode === 'active' && hasInteraction) || - (scanConfig.interaction_mode === 'inactive' && !hasInteraction)) + (scanConfig.actions.interaction_mode === 'all' || + (scanConfig.actions.interaction_mode === 'active' && hasInteraction) || + (scanConfig.actions.interaction_mode === 'inactive' && !hasInteraction)) ); } - protected _triggerAction(): void { - const action = this._api.getConfigManager().getConfig()?.view.scan.trigger_action; + protected _triggerAction(cameraID: string): void { + const action = this._api.getConfigManager().getConfig()?.view.scan.actions.trigger; - if (action && this._hasAllowableInteractionState()) { - this._api.getActionsManager().executeActions(action); + if (action === 'live' && this._hasAllowableInteractionStateForAction()) { + this._api.getViewManager().setViewByParameters({ + viewName: 'live', + cameraID: cameraID, + }); } // Must update master element to add border pulsing. @@ -131,10 +133,10 @@ export class TriggersManager { } protected _untriggerAction(cameraID: string): void { - const action = this._api.getConfigManager().getConfig()?.view.scan.untrigger_action; + const action = this._api.getConfigManager().getConfig()?.view.scan.actions.untrigger; - if (action && this._hasAllowableInteractionState()) { - this._api.getActionsManager().executeActions(action); + if (action === 'default' && this._hasAllowableInteractionStateForAction()) { + this._api.getViewManager().setViewDefault(); } this._triggeredCameras.delete(cameraID); this._deleteTimer(cameraID); diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index a962d08a..068439ee 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -197,7 +197,6 @@ export interface CardStyleAPI { } export interface CardTriggersAPI { - getActionsManager(): ActionsManager; getCameraManager(): CameraManager; getCardElementManager(): CardElementManager; getConfigManager(): ConfigManager; diff --git a/src/card.ts b/src/card.ts index 1f50e2b4..527b710a 100644 --- a/src/card.ts +++ b/src/card.ts @@ -241,7 +241,7 @@ class FrigateCard extends LitElement { const cardClasses = { triggered: !!this._controller.getTriggersManager().isTriggered() && - !!this._config?.view.scan.trigger_show_status, + !!this._config?.view.scan.show_trigger_status, }; const mainClasses = { main: true, diff --git a/src/config-mgmt.ts b/src/config-mgmt.ts index fc81696a..8a9a8234 100644 --- a/src/config-mgmt.ts +++ b/src/config-mgmt.ts @@ -13,6 +13,7 @@ import { CONF_MEDIA_GALLERY, CONF_MENU_BUTTONS_CAMERA_UI, CONF_OVERRIDES, + CONF_VIEW_SCAN_ACTIONS_UNTRIGGER, } from './const'; import { arrayify } from './utils/basic'; @@ -474,4 +475,12 @@ const UPGRADES = [ ); }, upgradePTZElementsToLive(), + upgradeMoveToWithOverrides( + 'view.scan.untrigger_reset', + CONF_VIEW_SCAN_ACTIONS_UNTRIGGER, + { + // Delete the value if it's set to the default. + transform: (val) => (val ? 'default' : null), + }, + ), ]; diff --git a/src/config/types.ts b/src/config/types.ts index f618ea74..3c70cf38 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -1,42 +1,3 @@ -// TODO: Config migration -// TODO: Editor support for scan mode changes -// TODO: Consider this: - -/* -// NOW ===> -view: - scan: - enabled: true - trigger_show_status: true, - trigger_action: - - action: custom:frigate-card-action - frigate_card_action: camera_select - triggered: true - - action: custom:frigate-card-action - frigate_card_action: live - untrigger_action: - - action: custom:frigate-card-action - interaction_mode: inactive - trigger_filter_camera: all - untrigger_seconds: 0 - -view: - scan: - enabled: true - -// TO - -view: - scan: - enabled: true - trigger_show_status: true - actions: - live | live-reset | none - interaction: inactive | active | all - trigger_filter_camera: all - untrigger_seconds: 0 -automations: -*/ import { CallServiceActionConfig, @@ -1160,47 +1121,36 @@ const viewConfigDefault = { dark_mode: 'off' as const, scan: { enabled: false, - trigger_show_status: true, - trigger_action: [ - { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'camera_select' as const, - triggered: true, - }, - { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live' as const, - }, - ], - untrigger_action: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'default' as const, + show_trigger_status: true, + filter_selected_camera: false, + actions: { + interaction_mode: 'inactive' as const, + trigger: 'live' as const, + untrigger: 'default' as const, }, - interaction_mode: 'inactive' as const, - trigger_filter_camera: 'all' as const, untrigger_seconds: 0, }, }; -const scanSchema = z.object({ +export const scanSchema = z.object({ enabled: z.boolean().default(viewConfigDefault.scan.enabled), - interaction_mode: z - .enum(['all', 'inactive', 'active']) - .default(viewConfigDefault.scan.interaction_mode), - trigger_filter_camera: z - .enum(['all', 'selected']) - .default(viewConfigDefault.scan.trigger_filter_camera), - trigger_show_status: z.boolean().default(viewConfigDefault.scan.trigger_show_status), - trigger_action: actionSchema - .or(actionSchema.array()) - .nullable() - .default(viewConfigDefault.scan.trigger_action), + filter_selected_camera: z + .boolean() + .default(viewConfigDefault.scan.filter_selected_camera), + show_trigger_status: z.boolean().default(viewConfigDefault.scan.show_trigger_status), - untrigger_action: actionSchema - .or(actionSchema.array()) - .nullable() - .default(viewConfigDefault.scan.untrigger_action), + actions: z + .object({ + interaction_mode: z + .enum(['all', 'inactive', 'active']) + .default(viewConfigDefault.scan.actions.interaction_mode), + trigger: z.enum(['live', 'none']).default(viewConfigDefault.scan.actions.trigger), + untrigger: z + .enum(['default', 'none']) + .default(viewConfigDefault.scan.actions.untrigger), + }) + .default(viewConfigDefault.scan.actions), untrigger_seconds: z.number().default(viewConfigDefault.scan.untrigger_seconds), }); export type ScanOptions = z.infer; diff --git a/src/const.ts b/src/const.ts index 1d6c4c62..16f16147 100644 --- a/src/const.ts +++ b/src/const.ts @@ -77,10 +77,19 @@ export const CONF_VIEW_UPDATE_FORCE = `${CONF_VIEW}.update_force` as const; export const CONF_VIEW_UPDATE_SECONDS = `${CONF_VIEW}.update_seconds` as const; export const CONF_VIEW_SCAN = `${CONF_VIEW}.scan` as const; export const CONF_VIEW_SCAN_ENABLED = `${CONF_VIEW_SCAN}.enabled` as const; -export const CONF_VIEW_SCAN_TRIGGER_SHOW_STATUS = - `${CONF_VIEW_SCAN}.trigger_show_status` as const; +export const CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS = + `${CONF_VIEW_SCAN}.show_trigger_status` as const; +export const CONF_VIEW_SCAN_FILTER_SELECTED_CAMERA = + `${CONF_VIEW_SCAN}.filter_selected_camera` as const; export const CONF_VIEW_SCAN_UNTRIGGER_SECONDS = `${CONF_VIEW_SCAN}.untrigger_seconds` as const; +export const CONF_VIEW_SCAN_ACTIONS = `${CONF_VIEW_SCAN}.actions` as const; +export const CONF_VIEW_SCAN_ACTIONS_TRIGGER = + `${CONF_VIEW_SCAN_ACTIONS}.trigger` as const; +export const CONF_VIEW_SCAN_ACTIONS_UNTRIGGER = + `${CONF_VIEW_SCAN_ACTIONS}.untrigger` as const; +export const CONF_VIEW_SCAN_ACTIONS_INTERACTION_MODE = + `${CONF_VIEW_SCAN_ACTIONS}.interaction_mode` as const; export const CONF_MEDIA_GALLERY = 'media_gallery' as const; export const CONF_MEDIA_GALLERY_CONTROLS_FILTER_MODE = diff --git a/src/editor.ts b/src/editor.ts index 64ab9401..d3be3939 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -181,8 +181,13 @@ import { CONF_VIEW_DARK_MODE, CONF_VIEW_DEFAULT, CONF_VIEW_SCAN, + CONF_VIEW_SCAN_ACTIONS, + CONF_VIEW_SCAN_ACTIONS_INTERACTION_MODE, + CONF_VIEW_SCAN_ACTIONS_TRIGGER, + CONF_VIEW_SCAN_ACTIONS_UNTRIGGER, CONF_VIEW_SCAN_ENABLED, - CONF_VIEW_SCAN_TRIGGER_SHOW_STATUS, + CONF_VIEW_SCAN_FILTER_SELECTED_CAMERA, + CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS, CONF_VIEW_SCAN_UNTRIGGER_SECONDS, CONF_VIEW_TIMEOUT_SECONDS, CONF_VIEW_UPDATE_CYCLE_CAMERA, @@ -237,6 +242,7 @@ const MENU_PERFORMANCE_FEATURES = 'performance.features'; const MENU_PERFORMANCE_STYLE = 'performance.style'; const MENU_TIMELINE_CONTROLS_THUMBNAILS = 'timeline.controls.thumbnails'; const MENU_VIEW_SCAN = 'scan'; +const MENU_VIEW_SCAN_ACTIONS = 'scan.actions'; interface EditorOptionsSet { icon: string; @@ -620,6 +626,46 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor }, ]; + protected _scanActionsInteractionModes: EditorSelectOption[] = [ + { value: '', label: '' }, + { + value: 'all', + label: localize('config.view.scan.actions.interaction_modes.all'), + }, + { + value: 'inactive', + label: localize('config.view.scan.actions.interaction_modes.inactive'), + }, + { + value: 'active', + label: localize('config.view.scan.actions.interaction_modes.active'), + }, + ]; + + protected _scanActionsTrigger: EditorSelectOption[] = [ + { value: '', label: '' }, + { + value: 'live', + label: localize('config.view.scan.actions.triggers.live'), + }, + { + value: 'none', + label: localize('config.view.scan.actions.triggers.none'), + }, + ]; + + protected _scanActionsUntrigger: EditorSelectOption[] = [ + { value: '', label: '' }, + { + value: 'default', + label: localize('config.view.scan.actions.untriggers.default'), + }, + { + value: 'none', + label: localize('config.view.scan.actions.untriggers.none'), + }, + ]; + public setConfig(config: RawFrigateCardConfig): void { // Note: This does not use Zod to parse the configuration, so it may be // partially or completely invalid. It's more useful to have a partially @@ -876,44 +922,68 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor } protected _renderViewScanMenu(): TemplateResult { - const submenuClasses = { - submenu: true, - selected: !!this._expandedMenus[MENU_VIEW_SCAN], - }; - return html` -
- - ${this._expandedMenus[MENU_VIEW_SCAN] - ? html`
- ${this._renderSwitch( - CONF_VIEW_SCAN_ENABLED, - this._defaults.view.scan.enabled, - { - label: localize(`config.${CONF_VIEW_SCAN_ENABLED}`), - }, - )} - ${this._renderSwitch( - CONF_VIEW_SCAN_TRIGGER_SHOW_STATUS, - this._defaults.view.scan.trigger_show_status, - { - label: localize(`config.${CONF_VIEW_SCAN_TRIGGER_SHOW_STATUS}`), - }, - )} - ${this._renderNumberInput(CONF_VIEW_SCAN_UNTRIGGER_SECONDS, { - default: this._defaults.view.scan.untrigger_seconds, - })} -
` - : ''} -
- `; + return this._putInSubmenu( + MENU_VIEW_SCAN, + true, + `config.${CONF_VIEW_SCAN}.editor_label`, + { name: 'mdi:target-account' }, + html` + ${this._renderSwitch(CONF_VIEW_SCAN_ENABLED, this._defaults.view.scan.enabled, { + label: localize(`config.${CONF_VIEW_SCAN_ENABLED}`), + })} + ${this._renderSwitch( + CONF_VIEW_SCAN_FILTER_SELECTED_CAMERA, + this._defaults.view.scan.filter_selected_camera, + { + label: localize(`config.${CONF_VIEW_SCAN_FILTER_SELECTED_CAMERA}`), + }, + )} + ${this._renderSwitch( + CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS, + this._defaults.view.scan.show_trigger_status, + { + label: localize(`config.${CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS}`), + }, + )} + ${this._renderNumberInput(CONF_VIEW_SCAN_UNTRIGGER_SECONDS, { + default: this._defaults.view.scan.untrigger_seconds, + })} + ${this._renderOptionSelector( + CONF_VIEW_SCAN_ACTIONS_TRIGGER, + this._scanActionsTrigger, + { + label: localize('config.view.scan.actions.trigger'), + }, + )} + ${this._putInSubmenu( + MENU_VIEW_SCAN_ACTIONS, + true, + `config.${CONF_VIEW_SCAN_ACTIONS}.editor_label`, + { name: 'mdi:cogs' }, + html` ${this._renderOptionSelector( + CONF_VIEW_SCAN_ACTIONS_TRIGGER, + this._scanActionsTrigger, + { + label: localize('config.view.scan.actions.trigger'), + }, + )} + ${this._renderOptionSelector( + CONF_VIEW_SCAN_ACTIONS_UNTRIGGER, + this._scanActionsUntrigger, + { + label: localize('config.view.scan.actions.untrigger'), + }, + )} + ${this._renderOptionSelector( + CONF_VIEW_SCAN_ACTIONS_INTERACTION_MODE, + this._scanActionsInteractionModes, + { + label: localize('config.view.scan.actions.interaction_mode'), + }, + )}`, + )} + `, + ); } /** diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 6d93d174..d4f7fd10 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -385,10 +385,29 @@ }, "default": "Default view", "scan": { + "actions": { + "editor_label": "Scan mode actions", + "interaction_mode": "How to handle actions when the card has human interaction", + "interaction_modes": { + "active": "Only trigger actions when card has human interaction", + "all": "Trigger actions regardless of human interaction", + "inactive": "Only trigger actions when card has no human interaction" + }, + "trigger": "Trigger action", + "triggers": { + "live": "Change to live", + "none": "Take no action" + }, + "untrigger": "Untrigger action", + "untriggers": { + "default": "Change to default view/camera", + "none": "Take no action" + } + }, + "editor_label": "Scan mode", + "filter_selected_camera": "Only trigger on selected camera", "enabled": "Scan mode enabled", - "scan_mode": "Scan mode", - "trigger_show_status": "Show pulsing border when triggered", - "untrigger_reset": "Reset the view to default after untrigger", + "show_trigger_status": "Show pulsing border when triggered", "untrigger_seconds": "Seconds after inactive state change to untrigger" }, "timeout_seconds": "Reset to default view X seconds after user action (0=never)", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 363c00c4..b5940789 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -381,10 +381,29 @@ }, "default": "Visualizzazione predefinita", "scan": { + "actions": { + "editor_label": "", + "interaction_mode": "", + "interaction_modes": { + "active": "", + "all": "", + "inactive": "" + }, + "trigger": "", + "triggers": { + "live": "", + "none": "" + }, + "untrigger": "", + "untriggers": { + "default": "", + "none": "" + } + }, + "editor_label": "Modalità di scansione", "enabled": "Modalità di scansione abilitata", - "scan_mode": "Modalità di scansione", - "trigger_show_status": "Mostra bordo pulsante quando attivato", - "untrigger_reset": "Reset the view to default after untrigger", + "filter_selected_camera": "", + "show_trigger_status": "Mostra bordo pulsante quando attivato", "untrigger_seconds": "Reimposta la vista ai valori predefiniti dopo aver annullato l'attivazione" }, "timeout_seconds": "Ripristina la vista predefinita x secondi dopo l'azione dell'utente (0 = mai)", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 58c5c7ad..8c6db881 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -384,10 +384,29 @@ }, "default": "Visualização padrão", "scan": { + "actions": { + "editor_label": "", + "interaction_mode": "", + "interaction_modes": { + "active": "", + "all": "", + "inactive": "" + }, + "trigger": "", + "triggers": { + "live": "", + "none": "" + }, + "untrigger": "", + "untriggers": { + "default": "", + "none": "" + } + }, + "editor_label": "Modo scan", "enabled": "Modo scan ativado", - "scan_mode": "Modo scan", - "trigger_show_status": "Pulsar borda quando acionado", - "untrigger_reset": "Redefinir a visualização para o padrão após desacionar", + "filter_selected_camera": "", + "show_trigger_status": "Pulsar borda quando acionado", "untrigger_seconds": "Segundos após a mudar para o estado inativo para desacionar" }, "timeout_seconds": "Redefinir para a visualização padrão X segundos após a ação do usuário (0 = nunca)", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 702913ce..b164abc4 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -374,10 +374,29 @@ }, "default": "Visualização padrão", "scan": { + "actions": { + "editor_label": "", + "interaction_mode": "", + "interaction_modes": { + "active": "", + "all": "", + "inactive": "" + }, + "trigger": "", + "triggers": { + "live": "", + "none": "" + }, + "untrigger": "", + "untriggers": { + "default": "", + "none": "" + } + }, + "editor_label": "Modo scan", "enabled": "Modo scan ativado", - "scan_mode": "Modo scan", - "trigger_show_status": "Exibir estado do gatilho", - "untrigger_reset": "Redefinir a visualização para o padrão após desacionar", + "filter_selected_camera": "", + "show_trigger_status": "Exibir estado do gatilho", "untrigger_seconds": "Segundos após a mudar para o estado inativo para desacionar" }, "timeout_seconds": "Redefinir para a visualização padrão X segundos após a ação do usuário (0 = nunca)", diff --git a/tests/card-controller/triggers-manager.test.ts b/tests/card-controller/triggers-manager.test.ts index 7fc1688a..d6ae6b4d 100644 --- a/tests/card-controller/triggers-manager.test.ts +++ b/tests/card-controller/triggers-manager.test.ts @@ -3,7 +3,7 @@ import { HassEntities } from 'home-assistant-js-websocket'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { CardController } from '../../src/card-controller/controller'; import { TriggersManager } from '../../src/card-controller/triggers-manager'; -import { ScanOptions } from '../../src/config/types'; +import { ScanOptions, scanSchema } from '../../src/config/types'; import { createCameraConfig, createCameraManager, @@ -18,22 +18,11 @@ import { const baseScanConfig: Partial = { enabled: true, untrigger_seconds: 10, - interaction_mode: 'inactive' as const, - trigger_filter_camera: 'all' as const, - trigger_action: [ - { - action: 'fire-dom-event' as const, - frigate_card_action: 'camera_select' as const, - triggered: true, - }, - { - action: 'fire-dom-event' as const, - frigate_card_action: 'live' as const, - }, - ], - untrigger_action: { - action: 'fire-dom-event' as const, - frigate_card_action: 'default' as const, + filter_selected_camera: false, + actions: { + trigger: 'live' as const, + untrigger: 'default' as const, + interaction_mode: 'inactive' as const, }, }; @@ -48,7 +37,7 @@ const createTriggerAPI = (options?: { vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { - scan: options?.config ?? baseScanConfig, + scan: options?.config ? scanSchema.parse(options.config) : baseScanConfig, }, }), ); @@ -134,17 +123,10 @@ describe('TriggersManager', () => { manager.updateTriggerHAState(createHASS(hassInactiveState)); expect(manager.isTriggered()).toBeTruthy(); - expect(api.getActionsManager().executeActions).toBeCalledWith([ - { - action: 'fire-dom-event' as const, - frigate_card_action: 'camera_select' as const, - triggered: true, - }, - { - action: 'fire-dom-event' as const, - frigate_card_action: 'live' as const, - }, - ]); + expect(api.getViewManager().setViewByParameters).toBeCalledWith({ + viewName: 'live' as const, + cameraID: 'camera_1' as const, + }); vi.mocked(api.getHASSManager().getHASS).mockReturnValue( createHASS(hassInactiveState), @@ -163,10 +145,7 @@ describe('TriggersManager', () => { expect(manager.isTriggered()).toBeFalsy(); - expect(api.getActionsManager().executeActions).toBeCalledWith({ - action: 'fire-dom-event' as const, - frigate_card_action: 'default' as const, - }); + expect(api.getViewManager().setViewDefault).toBeCalled(); }); it('should trigger when entity state is active on startup', () => { @@ -191,7 +170,7 @@ describe('TriggersManager', () => { manager.updateTriggerHAState(createHASS(hassInactiveState)); expect(manager.isTriggered()).toBeTruthy(); - expect(api.getActionsManager().executeActions).not.toBeCalled(); + expect(api.getViewManager().setViewByParameters).not.toBeCalled(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue( createHASS(hassInactiveState), @@ -203,7 +182,39 @@ describe('TriggersManager', () => { expect(manager.isTriggered()).toBeFalsy(); - expect(api.getActionsManager().executeActions).not.toBeCalled(); + expect(api.getViewManager().setViewDefault).not.toBeCalled(); + }); + + it('should take no actions when actions are set to none', () => { + const start = new Date('2023-10-01T17:14'); + const api = createTriggerAPI({ + hassStates: hassActiveState, + config: { + enabled: true, + actions: { + interaction_mode: 'all', + trigger: 'none', + untrigger: 'none', + }, + }, + }); + const manager = new TriggersManager(api); + manager.updateTriggerHAState(createHASS(hassInactiveState)); + expect(manager.isTriggered()).toBeTruthy(); + + expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + + vi.mocked(api.getHASSManager().getHASS).mockReturnValue( + createHASS(hassInactiveState), + ); + manager.updateTriggerHAState(createHASS(hassActiveState)); + + vi.setSystemTime(add(start, { seconds: 10 })); + vi.runOnlyPendingTimers(); + + expect(manager.isTriggered()).toBeFalsy(); + + expect(api.getViewManager().setViewDefault).not.toBeCalled(); }); it('should take actions with human interactions when interaction mode is active', () => { @@ -214,14 +225,21 @@ describe('TriggersManager', () => { interaction: true, config: { ...baseScanConfig, - interaction_mode: 'active', + actions: { + trigger: 'live' as const, + untrigger: 'default' as const, + interaction_mode: 'active', + }, }, }); const manager = new TriggersManager(api); manager.updateTriggerHAState(createHASS(hassInactiveState)); expect(manager.isTriggered()).toBeTruthy(); - expect(api.getActionsManager().executeActions).toBeCalledTimes(1); + expect(api.getViewManager().setViewByParameters).toBeCalledWith({ + viewName: 'live' as const, + cameraID: 'camera_1' as const, + }); vi.mocked(api.getHASSManager().getHASS).mockReturnValue( createHASS(hassInactiveState), @@ -233,7 +251,7 @@ describe('TriggersManager', () => { expect(manager.isTriggered()).toBeFalsy(); - expect(api.getActionsManager().executeActions).toBeCalledTimes(2); + expect(api.getViewManager().setViewDefault).toBeCalled(); }); it('should report multiple triggered cameras', () => { @@ -303,7 +321,7 @@ describe('TriggersManager', () => { config: { ...baseScanConfig, // Filter triggers to selected camera only. - trigger_filter_camera: 'selected' as const, + filter_selected_camera: true, }, hassStates: hassActiveState, }); @@ -339,7 +357,7 @@ describe('TriggersManager', () => { config: { ...baseScanConfig, // Filter triggers to selected camera only. - trigger_filter_camera: 'selected' as const, + filter_selected_camera: true, }, hassStates: hassActiveState, }); diff --git a/tests/config-mgmt.test.ts b/tests/config-mgmt.test.ts index cb51a12c..d90c099f 100644 --- a/tests/config-mgmt.test.ts +++ b/tests/config-mgmt.test.ts @@ -1166,6 +1166,51 @@ describe('should handle version specific upgrades', () => { type: 'custom:frigate-card', }); }); + }); + describe('should move and transform untrigger_reset', () => { + it('when true', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + scan: { + untrigger_reset: true, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + scan: { + actions: { + untrigger: 'default', + }, + }, + }, + }); + }); + + it('when false', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + scan: { + untrigger_reset: false, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + scan: {}, + }, + }); + }); }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 7758c2bf..9bd1fe41 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -279,25 +279,14 @@ describe('config defaults', () => { default: 'live', scan: { enabled: false, - interaction_mode: 'inactive', - trigger_show_status: true, + show_trigger_status: true, untrigger_seconds: 0, - trigger_action: [ - { - action: 'fire-dom-event', - frigate_card_action: 'camera_select', - triggered: true, - }, - { - action: 'fire-dom-event', - frigate_card_action: 'live', - }, - ], - trigger_filter_camera: 'all', - untrigger_action: { - action: 'fire-dom-event', - frigate_card_action: 'default', + actions: { + trigger: 'live', + untrigger: 'default', + interaction_mode: 'inactive', }, + filter_selected_camera: false, }, timeout_seconds: 300, update_cycle_camera: false, diff --git a/vite.config.ts b/vite.config.ts index ff62e3a5..699b52b7 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,10 +10,10 @@ export default defineConfig({ // Thresholds will automatically be updated as coverage improves to avoid // back-sliding. thresholdAutoUpdate: true, - statements: 71.74, - branches: 60.62, - functions: 72.84, - lines: 71.63, + statements: 71.82, + branches: 60.67, + functions: 72.86, + lines: 71.71, }, }, }); From 06f2151bab3c99fa380743255576eccb58feb0c9 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 23 Jan 2024 20:56:30 -0800 Subject: [PATCH 071/189] Allow per-camera trigger borders. --- README.md | 2 +- src/card.ts | 9 +++------ src/components/live/live.ts | 14 +++++++++++++- src/components/thumbnail-carousel.ts | 3 ++- src/components/views.ts | 4 ++++ src/scss/card.scss | 20 +------------------- src/scss/live-carousel.scss | 1 + src/scss/live-grid.scss | 20 ++++++++++++++++++++ 8 files changed, 45 insertions(+), 28 deletions(-) create mode 100644 src/scss/live-grid.scss diff --git a/README.md b/README.md index 8891b1d3..f5d2a47d 100644 --- a/README.md +++ b/README.md @@ -433,7 +433,7 @@ Scan mode tracks Home Assistant state *changes* -- when the card is first starte | - | - | - | - | | `enabled` | `false` | :white_check_mark: | Whether to enable scan mode. | | `filter_selected_camera` | `false` | :white_check_mark: | If set to `true` will only trigger on the currently selected camera.| -| `show_trigger_status` | `true` | :white_check_mark: | Whether or not the card should show a visual indication that it is triggered (a pulsing border around the card edge). | +| `show_trigger_status` | `true` | :white_check_mark: | Whether or not the `live` view should show a visual indication that it is triggered (a pulsing border around the camera edge). | | `untrigger_seconds` | `0` | :white_check_mark: | The number of seconds to wait after all entities are inactive before untriggering. | | `actions` | | :white_check_mark: | The actions to take when scan mode triggers (see below). | diff --git a/src/card.ts b/src/card.ts index 527b710a..550067c8 100644 --- a/src/card.ts +++ b/src/card.ts @@ -238,11 +238,6 @@ class FrigateCard extends LitElement { const cardStyle = { 'aspect-ratio': this._controller.getStyleManager().getAspectRatioStyle(), }; - const cardClasses = { - triggered: - !!this._controller.getTriggersManager().isTriggered() && - !!this._config?.view.scan.show_trigger_status, - }; const mainClasses = { main: true, 'curve-top': @@ -264,7 +259,6 @@ class FrigateCard extends LitElement { hasHold: frigateCardHasAction(actions.hold_action), hasDoubleClick: frigateCardHasAction(actions.double_tap_action), })} - class="${classMap(cardClasses)}" style="${styleMap(cardStyle)}" @frigate-card:message=${(ev: CustomEvent) => this._controller.getMessageManager().setMessageIfHigherPriority(ev.detail)} @@ -313,6 +307,9 @@ class FrigateCard extends LitElement { ?.getEpoch()} .hide=${!!this._controller.getMessageManager().hasMessage()} .microphoneStream=${this._controller.getMicrophoneManager()?.getStream()} + .triggeredCameraIDs=${this._config?.view.scan.show_trigger_status + ? this._controller.getTriggersManager().getTriggeredCameraIDs() + : undefined} >`} ${ // Keep message rendering to last to show messages that may have been diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 23d58d7c..f69a04aa 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -31,6 +31,7 @@ import { import { localize } from '../../localize/localize.js'; import basicBlockStyle from '../../scss/basic-block.scss'; import liveCarouselStyle from '../../scss/live-carousel.scss'; +import liveGridStyle from '../../scss/live-grid.scss'; import liveProviderStyle from '../../scss/live-provider.scss'; import { ExtendedHomeAssistant, @@ -114,6 +115,9 @@ export class FrigateCardLive extends LitElement { @property({ attribute: false }) public microphoneStream?: MediaStream; + @property({ attribute: false }) + public triggeredCameraIDs?: Set; + // Whether or not the live view is currently in the background (i.e. preloaded // but not visible) @state() @@ -219,6 +223,7 @@ export class FrigateCardLive extends LitElement { .cardWideConfig=${this.cardWideConfig} .cameraManager=${this.cameraManager} .microphoneStream=${this.microphoneStream} + .triggeredCameraIDs=${this.triggeredCameraIDs} @frigate-card:message=${(ev: CustomEvent) => { this._renderKey++; this._messageReceivedPostRender = true; @@ -283,7 +288,12 @@ export class FrigateCardLiveGrid extends LitElement { @property({ attribute: false }) public microphoneStream?: MediaStream; + @property({ attribute: false }) + public triggeredCameraIDs?: Set; + protected _renderCarousel(cameraID?: string): TemplateResult { + const triggeredCameraID = cameraID ?? this.view?.camera; + return html` `; @@ -351,7 +363,7 @@ export class FrigateCardLiveGrid extends LitElement { } static get styles(): CSSResultGroup { - return unsafeCSS(basicBlockStyle); + return unsafeCSS(liveGridStyle); } } diff --git a/src/components/thumbnail-carousel.ts b/src/components/thumbnail-carousel.ts index 3237464e..52e81acd 100644 --- a/src/components/thumbnail-carousel.ts +++ b/src/components/thumbnail-carousel.ts @@ -43,6 +43,7 @@ export class FrigateCardThumbnailCarousel extends LitElement { public fadeThumbnails = false; protected _thumbnailSlides: TemplateResult[] = []; + protected _plugins = [AutoSize()]; protected willUpdate(changedProps: PropertyValues): void { if (changedProps.has('config')) { @@ -137,7 +138,7 @@ export class FrigateCardThumbnailCarousel extends LitElement { return html` diff --git a/src/components/views.ts b/src/components/views.ts index 8fbf9af8..de9bb490 100644 --- a/src/components/views.ts +++ b/src/components/views.ts @@ -62,6 +62,9 @@ export class FrigateCardViews extends LitElement { @property({ attribute: false }) public microphoneStream?: MediaStream; + @property({ attribute: false }) + public triggeredCameraIDs?: Set; + protected willUpdate(changedProps: PropertyValues): void { if (changedProps.has('view') || changedProps.has('config')) { if (this.view?.is('live') || this._shouldLivePreload()) { @@ -239,6 +242,7 @@ export class FrigateCardViews extends LitElement { .cameraManager=${this.cameraManager} .cardWideConfig=${this.cardWideConfig} .microphoneStream=${this.microphoneStream} + .triggeredCameraIDs=${this.triggeredCameraIDs} class="${classMap(liveClasses)}" > diff --git a/src/scss/card.scss b/src/scss/card.scss index 7a489571..0ed212a9 100644 --- a/src/scss/card.scss +++ b/src/scss/card.scss @@ -21,7 +21,7 @@ // The standard HA header is 56 pixels tall, so that much off the top (header) // and bottom (to maintain center), before doing the calculation of // max-height. This matters on small mobile devices in landscape orientation. - --frigate-card-expand-max-height: calc( ( 100vh - (2 * 56px) ) * 0.85 ); + --frigate-card-expand-max-height: calc((100vh - (2 * 56px)) * 0.85); --frigate-card-expand-max-width: 85vw; --frigate-card-expand-width: none; --frigate-card-expand-height: none; @@ -52,10 +52,6 @@ div.main { // Necessary to get Safari to show border-radius correctly. transform: translateZ(0); - // Include the borders in the sizing (to keep the triggered warning pulse - // visible in fullscreen). - box-sizing: border-box; - // Hide scrollbar: Firefox scrollbar-width: none; // Hide scrollbar: IE and Edge @@ -112,20 +108,6 @@ ha-card { position: static; color: var(--secondary-text-color, white); } -ha-card.triggered { - @keyframes warning-pulse { - 0% { - border: solid 2px rgba(0, 0, 0, 0); - } - 50% { - border: solid 2px var(--warning-color); - } - 100% { - border: solid 2px rgba(0, 0, 0, 0); - } - } - animation: warning-pulse 5s infinite; -} /************ * Fullscreen diff --git a/src/scss/live-carousel.scss b/src/scss/live-carousel.scss index 81c26c13..79c460f2 100644 --- a/src/scss/live-carousel.scss +++ b/src/scss/live-carousel.scss @@ -1,4 +1,5 @@ :host { + display: block; --video-max-height: none; } diff --git a/src/scss/live-grid.scss b/src/scss/live-grid.scss new file mode 100644 index 00000000..8e860304 --- /dev/null +++ b/src/scss/live-grid.scss @@ -0,0 +1,20 @@ +@use 'basic-block.scss'; + +@keyframes warning-pulse { + 0% { + border: solid 2px var(--frigate-card-triggered-color-1, rgba(0, 0, 0, 0)); + } + 50% { + border: solid 2px var(--frigate-card-triggered-color-2, var(--warning-color)); + } + 100% { + border: solid 2px var(--frigate-card-triggered-color-1, rgba(0, 0, 0, 0)); + } +} + +frigate-card-live-carousel[triggered] { + animation: warning-pulse 5s infinite; +} +frigate-card-live-carousel[selected] { + --frigate-card-triggered-color-1: var(--primary-color); +} From 5e72070c96491159d459657cbdef57fe92fe0ea4 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Thu, 25 Jan 2024 22:06:21 -0800 Subject: [PATCH 072/189] Add interaction and triggered conditions. --- README.md | 90 +++++++++++++++++-- src/card-controller/card-element-manager.ts | 7 ++ src/card-controller/conditions-manager.ts | 15 +++- src/card-controller/expand-manager.ts | 14 ++- src/card-controller/fullscreen-manager.ts | 14 ++- src/card-controller/interaction-manager.ts | 23 +++-- src/card-controller/media-info-manager.ts | 4 + src/card-controller/triggers-manager.ts | 10 +++ src/card-controller/types.ts | 3 + src/config-mgmt.ts | 2 + src/config/types.ts | 11 ++- src/const.ts | 3 +- src/editor.ts | 13 ++- src/localize/languages/en.json | 3 +- src/localize/languages/it.json | 33 +++---- src/localize/languages/pt-BR.json | 31 +++---- src/localize/languages/pt-PT.json | 31 +++---- .../card-element-manager.test.ts | 5 ++ .../conditions-manager.test.ts | 22 +++++ tests/card-controller/expand-manager.test.ts | 8 ++ .../fullscreen-manager.test.ts | 11 +++ .../interaction-manager.test.ts | 72 ++++++++++++++- .../media-info-manager.test.ts | 8 ++ .../card-controller/triggers-manager.test.ts | 7 ++ tests/config-mgmt.test.ts | 18 ++++ tests/config/types.test.ts | 3 +- vite.config.ts | 8 +- 27 files changed, 379 insertions(+), 90 deletions(-) diff --git a/README.md b/README.md index f5d2a47d..3cec8618 100644 --- a/README.md +++ b/README.md @@ -400,8 +400,9 @@ See the [fully expanded view configuration example](#config-expanded-view) for h | - | - | - | - | | `default` | `live` | :white_check_mark: | The view to show in the card by default. The default camera is the first one listed. See [views](#views) below.| | `camera_select` | `current` | :white_check_mark: | The view to show when a new camera is selected (e.g. in the camera menu). If `current` the view is unchanged when a new camera is selected. Other acceptable values may be seen at [views](#views) below.| -| `dark_mode` | `off` | :white_check_mark: | Whether or not to turn dark mode `on`, `off` or `auto` to automatically turn on if the card `timeout_seconds` has expired (i.e. card has been left unattended for that period of time) or if dark mode is enabled in the HA profile theme setting. Dark mode dims the brightness by `25%`.| -| `timeout_seconds` | `300` | :white_check_mark: | A numbers of seconds of inactivity after user interaction, after which the card will reset to the default configured view (i.e. 'screensaver' functionality). Inactivity is defined as lack of mouse/touch interaction with the Frigate card. If the default view occurs sooner (e.g. via `update_seconds` or manually) the timer will be stopped. `0` means disable this functionality. | +| `dark_mode` | `off` | :white_check_mark: | Whether or not to turn dark mode `on`, `off` or `auto` to automatically turn on if the card `interaction_seconds` has expired (i.e. card has been left unattended for that period of time) or if dark mode is enabled in the HA profile theme setting. Dark mode dims the brightness by `25%`.| +| `interaction_seconds` | `300` | :white_check_mark: | After a mouse/touch interaction with the Frigate card, it will be considered "interacted with" until this number of seconds elapses without further interaction. May be used in conditions with the `interaction` parameter of a [Frigate card condition](#frigate-card-condition) or with `reset_after_interaction` (below). `0` means no interactions are reported / acted upon. | +| `reset_after_interaction` | `true` | :white_check_mark: | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | | `update_seconds` | `0` | :white_check_mark: | A number of seconds after which to automatically update/refresh the default view. See [card updates](#card-updates) below for behavior and usecases. If the default view occurs sooner (e.g. manually) the timer will start over. `0` disables this functionality.| | `update_force` | `false` | :white_check_mark: | Whether automated card updates/refreshes should ignore user interaction. See [card updates](#card-updates) below for behavior and usecases.| | `update_entities` | | :white_check_mark: | **YAML only**: A card-wide list of entities that should cause the view to reset to the default (if the entity only pertains to a particular camera use `triggers` for the selected camera instead, see [Trigger Configuration](#camera-triggers-configuration)). See [card updates](#card-updates) below for behavior and usecases.| @@ -441,7 +442,7 @@ Scan mode tracks Home Assistant state *changes* -- when the card is first starte | `trigger` | `live` | :white_check_mark | When `live` the trigger will select the triggered camera in `live` view, when `none` will take no action. | | `untrigger` | `default` | :white_check_mark | When `default` the untrigger will return to the default view and camera, when `none` will take no action. | -| `interaction_mode` | `inactive` | :white_check_mark: | Whether actions should be taken when the card is being interacted with. If `all`, actions will always be taken regardless. If `inactive` actions will only be taken if the card has *not* had human interaction recently (as defined by `view.timeout_seconds`). If `active` actions will only be taken if the card *has* had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed.| +| `interaction_mode` | `inactive` | :white_check_mark: | Whether actions should be taken when the card is being interacted with. If `all`, actions will always be taken regardless. If `inactive` actions will only be taken if the card has *not* had human interaction recently (as defined by `view.interaction_seconds`). If `active` actions will only be taken if the card *has* had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed.| ### Menu Options @@ -1283,12 +1284,14 @@ All variables listed are under a `conditions:` section. | Condition | Description | | ------------- | --------------------------------------------- | | `view` | A list of [views](#views) in which this condition is satified (e.g. `clips`) | -| `camera` | A list of camera ids in which this condition is satisfied. See [camera IDs](#camera-ids).| +| `camera` | A list of camera IDs in which this condition is satisfied. See [camera IDs](#camera-ids).| | `fullscreen` | If `true` the condition is satisfied if the card is in fullscreen mode. If `false` the condition is satisfied if the card is **NOT** in fullscreen mode.| | `expand` | If `true` the condition is satisfied if the card is in expanded mode (in a dialog/popup). If `false` the condition is satisfied if the card is **NOT** in expanded mode (in a dialog/popup).| | `state` | A list of state conditions to compare with Home Assistant state. See below. | | `media_loaded` | If `true` the condition is satisfied if there is media load**ED** (not load**ING**) in the card (e.g. a clip, snapshot or live view). This may be used to hide controls during media loading or when a message (not media) is being displayed. Note that if `true` this condition will never be satisfied for views that do not themselves load media directly (e.g. gallery).| | `media_query` | Any valid [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries) string. Media queries must start and end with parentheses. This may be used to alter card configuration based on device/media properties (e.g. viewport width, orientation). Please note that `width` and `height` refer to the entire viewport not just the card. See the [media query example](#media-query-example).| +| `interacted` | If `true` the condition is satisfied if the card has had human interaction within `view.interaction_seconds` elapsed seconds. If `false` the condition is satisfied if the card has **NOT** had human interaction in that time. | +| `triggered` | A list of camera IDs which, if triggered in [scan mode](#scan-mode), satisfy the condition.| See the [example below](#frigate-card-conditional-example) for a real-world example of how these conditions can be used. @@ -1456,7 +1459,7 @@ This card supports several different views: |`clip`|Shows a viewer for the most recent clip for this camera. Can also be accessed by holding down the `clips` menu icon.| |`recordings`|Shows a gallery of recent (last day) recordings for this camera and its dependents.| |`recording`|Shows a viewer for the most recent recording for this camera. Can also be accessed by holding down the `recordings` menu icon.| -|`image`|Shows a static image specified by the `image` parameter, can be used as a discrete default view or a screensaver (via `view.timeout_seconds`).| +|`image`|Shows a static image specified by the `image` parameter, can be used as a discrete default view or a screensaver (via `view.interaction_seconds`).| |`timeline`|Shows an event timeline.| ### Navigating From A Snapshot To A Clip @@ -1908,7 +1911,7 @@ Reference: [View Options](#view-options). view: default: live camera_select: current - timeout_seconds: 300 + interaction_seconds: 300 update_seconds: 0 update_force: false update_cycle_camera: false @@ -2860,7 +2863,7 @@ overrides: view: default: live camera_select: current - timeout_seconds: 300 + interaction_seconds: 300 update_seconds: 0 update_force: false update_cycle_camera: false @@ -3663,6 +3666,37 @@ view: ``` +
+ Expand: Showing an alarm menu button when a camera is triggered + +This example adds a menu button to optionally activate a siren when the camera is triggered. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: custom:frigate-card-conditional + elements: + - type: custom:frigate-card-menu-icon + icon: mdi:alarm-bell + title: Activate alarm + style: + color: red + tap_action: + action: call-service + service: homeassistant.toggle + data: + entity_id: siren.siren + conditions: + triggered: + - camera.office +view: + scan: + enabled: true +``` +
+ ### Changing the Media Layout @@ -4051,6 +4085,44 @@ views: +### Interaction conditions + +The card can automatically execute actions when the card is interacted with (mouse or touch). + +
+ Expand: Automatically show a high-bandwidth stream on interaction + +This example will automatically use a HD live substream when the mouse cursor interacts with the card. + +```yaml +type: custom:frigate-card +cameras: + - live_provider: go2rtc + camera_entity: camera.office + triggers: + entities: + - switch.office_detect + dependencies: + cameras: + - camera.office_hd + - camera_entity: camera.office_hd + live_provider: go2rtc + hide: true +automations: + - actions: + - action: custom:frigate-card-action + frigate_card_action: live_substream_on + actions_not: + - action: custom:frigate-card-action + frigate_card_action: live_substream_off + conditions: + interaction: true +view: + scan: + enabled: true +``` +
+ ## Card Refreshes @@ -4066,7 +4138,7 @@ Note that no (other) automated updates are permitted when [scan mode](#scan-mode In the below "Trigger Entities" refers to the combination of `view.update_entities` and the `triggers.entities` for the currently selected camera (which in turn will also include the occupancy and motion sensor entities for Frigate cameras if `triggers.occupancy` and `triggers.motion` options are enabled, see [Trigger Configuration](#camera-triggers-configuration)). -| `view . update_seconds` | `view . timeout_seconds` | `view . update_force` | Trigger Entities | Behavior | +| `view . update_seconds` | `view . interaction_seconds` | `view . update_force` | Trigger Entities | Behavior | | :-: | :-: | :-: | :-: | - | | `0` | `0` | *(Any value)* | Unset | Card will not automatically refresh. | | `0` | `0` | *(Any value)* | *(Any entity)* | Card will reload default view & camera when entity state changes. | @@ -4108,7 +4180,7 @@ view: ```yaml view: default: clip - timeout_seconds: 30 + interaction_seconds: 30 ``` diff --git a/src/card-controller/card-element-manager.ts b/src/card-controller/card-element-manager.ts index 1df6edef..e984cb48 100644 --- a/src/card-controller/card-element-manager.ts +++ b/src/card-controller/card-element-manager.ts @@ -54,6 +54,13 @@ export class CardElementManager { } public elementConnected(): void { + // Set initial condition state. Must be done after the element is connected to + // allow callbacks to interact with the card. + this._api.getInteractionManager().initialize(); + this._api.getFullscreenManager().initialize(); + this._api.getExpandManager().initialize(); + this._api.getMediaLoadedInfoManager().initialize(); + // Whether or not the card is in panel mode on the dashboard. setOrRemoveAttribute(this._element, isCardInPanel(this._element), 'panel'); diff --git a/src/card-controller/conditions-manager.ts b/src/card-controller/conditions-manager.ts index deba399f..7a726f71 100644 --- a/src/card-controller/conditions-manager.ts +++ b/src/card-controller/conditions-manager.ts @@ -6,7 +6,7 @@ import { frigateConditionalSchema, OverrideConfigurationKey, RawFrigateCardConfig, - ViewDisplayMode + ViewDisplayMode, } from '../config/types'; import { CardConditionAPI } from './types'; @@ -18,6 +18,8 @@ interface ConditionState { state?: HassEntities; media_loaded?: boolean; displayMode?: ViewDisplayMode; + triggered?: Set; + interaction?: boolean; } export class ConditionEvaluateRequestEvent extends Event { @@ -133,7 +135,7 @@ export class ConditionsManager { this._listeners = [ () => this._api.getConfigManager().computeOverrideConfig(), () => this._api.getAutomationsManager().execute(), - ...(listener ? [listener] : []) + ...(listener ? [listener] : []), ]; } @@ -243,6 +245,15 @@ export class ConditionsManager { if (condition.display_mode) { result &&= !!state.displayMode && condition.display_mode === state.displayMode; } + if (condition.triggered?.length) { + result &&= condition.triggered.some((triggeredCameraID) => + state.triggered?.has(triggeredCameraID), + ); + } + if (condition.interaction !== undefined) { + result &&= + state.interaction !== undefined && condition.interaction === state.interaction; + } return result; } diff --git a/src/card-controller/expand-manager.ts b/src/card-controller/expand-manager.ts index 9516a9f0..2a112136 100644 --- a/src/card-controller/expand-manager.ts +++ b/src/card-controller/expand-manager.ts @@ -8,6 +8,10 @@ export class ExpandManager { this._api = api; } + public initialize(): void { + this._setConditionState(); + } + public isExpanded(): boolean { return this._expanded; } @@ -23,9 +27,13 @@ export class ExpandManager { } this._expanded = expanded; - this._api.getConditionsManager()?.setState({ - expand: expanded, - }); + this._setConditionState(); this._api.getCardElementManager().update(); } + + protected _setConditionState(): void { + this._api.getConditionsManager()?.setState({ + expand: this._expanded, + }); + } } diff --git a/src/card-controller/fullscreen-manager.ts b/src/card-controller/fullscreen-manager.ts index 418bf72f..a60d5dfe 100644 --- a/src/card-controller/fullscreen-manager.ts +++ b/src/card-controller/fullscreen-manager.ts @@ -8,6 +8,10 @@ export class FullscreenManager { this._api = api; } + public initialize(): void { + this._setConditionState(); + } + public connect(): void { if (screenfull.isEnabled) { screenfull.on('change', this._fullscreenHandler); @@ -32,12 +36,16 @@ export class FullscreenManager { screenfull.exit(); } - protected _fullscreenHandler = (): void => { - this._api.getExpandManager().setExpanded(false); - + protected _setConditionState(): void { this._api.getConditionsManager()?.setState({ fullscreen: this.isInFullscreen(), }); + } + + protected _fullscreenHandler = (): void => { + this._api.getExpandManager().setExpanded(false); + + this._setConditionState(); // Re-render after a change to fullscreen mode to take advantage of // the expanded screen real-estate (vs staying in aspect-ratio locked diff --git a/src/card-controller/interaction-manager.ts b/src/card-controller/interaction-manager.ts index af04cc81..64a43912 100644 --- a/src/card-controller/interaction-manager.ts +++ b/src/card-controller/interaction-manager.ts @@ -16,32 +16,37 @@ export class InteractionManager { this._reportInteraction(); }, 1 * 1000); + public initialize(): void { + this._api.getConditionsManager().setState({ interaction: false }); + } + public hasInteraction(): boolean { return this._timer.isRunning(); } /** * Start the user interaction ('screensaver') timer to reset the view to - * default `view.timeout_seconds` after user interaction. + * default `view.interaction_seconds` after user interaction. */ protected _reportInteraction(): void { this._timer.stop(); const timeoutSeconds = this._api.getConfigManager().getConfig() - ?.view.timeout_seconds; + ?.view.interaction_seconds; if (timeoutSeconds) { + this._api.getConditionsManager().setState({ interaction: true }); + this._timer.start(timeoutSeconds, () => { - if (this._isAutomatedUpdateAllowed()) { - this._api.getViewManager().setViewDefault(); + this._api.getConditionsManager().setState({ interaction: false }); + + if (!this._api.getTriggersManager().isTriggered()) { + if (this._api.getConfigManager().getConfig()?.view.reset_after_interaction) { + this._api.getViewManager().setViewDefault(); + } this._api.getStyleManager().setLightOrDarkMode(); } }); } - this._api.getStyleManager().setLightOrDarkMode(); - } - - protected _isAutomatedUpdateAllowed(): boolean { - return !this._api.getTriggersManager().isTriggered(); } } diff --git a/src/card-controller/media-info-manager.ts b/src/card-controller/media-info-manager.ts index 88dde87a..78878996 100644 --- a/src/card-controller/media-info-manager.ts +++ b/src/card-controller/media-info-manager.ts @@ -12,6 +12,10 @@ export class MediaLoadedInfoManager { this._api = api; } + public initialize(): void { + this.clear(); + } + public set(mediaInfo: MediaLoadedInfo): void { if (!isValidMediaLoadedInfo(mediaInfo)) { return; diff --git a/src/card-controller/triggers-manager.ts b/src/card-controller/triggers-manager.ts index dbd17869..ff4362ff 100644 --- a/src/card-controller/triggers-manager.ts +++ b/src/card-controller/triggers-manager.ts @@ -95,6 +95,7 @@ export class TriggersManager { cameraID === this._api.getViewManager().getView()?.camera) ) { this._triggeredCameras.set(cameraID, now); + this._setConditionState(); this._triggerAction(cameraID); } } @@ -132,6 +133,14 @@ export class TriggersManager { this._api.getCardElementManager().update(); } + protected _setConditionState(): void { + this._api.getConditionsManager().setState({ + triggered: this._triggeredCameras.size + ? new Set(this._triggeredCameras.keys()) + : undefined, + }); + } + protected _untriggerAction(cameraID: string): void { const action = this._api.getConfigManager().getConfig()?.view.scan.actions.untrigger; @@ -140,6 +149,7 @@ export class TriggersManager { } this._triggeredCameras.delete(cameraID); this._deleteTimer(cameraID); + this._setConditionState(); // Must update master element to remove border pulsing. this._api.getCardElementManager().update(); diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index 068439ee..7cc92bba 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -100,6 +100,7 @@ export interface CardDownloadAPI { export interface CardElementAPI { getActionsManager(): ActionsManager; + getExpandManager(): ExpandManager; getFullscreenManager(): FullscreenManager; getInteractionManager(): InteractionManager; getMediaLoadedInfoManager(): MediaLoadedInfoManager; @@ -147,6 +148,7 @@ export interface CardInitializerAPI { } export interface CardInteractionAPI { + getConditionsManager(): ConditionsManager; getConfigManager(): ConfigManager; getStyleManager(): StyleManager; getTriggersManager(): TriggersManager; @@ -198,6 +200,7 @@ export interface CardStyleAPI { export interface CardTriggersAPI { getCameraManager(): CameraManager; + getConditionsManager(): ConditionsManager; getCardElementManager(): CardElementManager; getConfigManager(): ConfigManager; getHASSManager(): HASSManager; diff --git a/src/config-mgmt.ts b/src/config-mgmt.ts index 8a9a8234..d6f5eb61 100644 --- a/src/config-mgmt.ts +++ b/src/config-mgmt.ts @@ -13,6 +13,7 @@ import { CONF_MEDIA_GALLERY, CONF_MENU_BUTTONS_CAMERA_UI, CONF_OVERRIDES, + CONF_VIEW_INTERACTION_SECONDS, CONF_VIEW_SCAN_ACTIONS_UNTRIGGER, } from './const'; import { arrayify } from './utils/basic'; @@ -483,4 +484,5 @@ const UPGRADES = [ transform: (val) => (val ? 'default' : null), }, ), + upgradeMoveToWithOverrides('view.timeout_seconds', CONF_VIEW_INTERACTION_SECONDS), ]; diff --git a/src/config/types.ts b/src/config/types.ts index 3c70cf38..2da6551a 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -1,4 +1,3 @@ - import { CallServiceActionConfig, ConfirmationRestrictionConfig, @@ -490,6 +489,8 @@ export const frigateCardConditionSchema = z.object({ state: stateConditions.optional(), media_query: z.string().optional(), display_mode: viewDisplayModeSchema.optional(), + triggered: z.string().array().optional(), + interaction: z.boolean().optional(), }); export type FrigateCardCondition = z.infer; @@ -1114,7 +1115,8 @@ export type CamerasConfig = z.infer; const viewConfigDefault = { default: FRIGATE_CARD_VIEW_DEFAULT, camera_select: 'current' as const, - timeout_seconds: 300, + interaction_seconds: 300, + reset_after_interaction: true, update_seconds: 0, update_force: false, update_cycle_camera: false, @@ -1163,7 +1165,10 @@ const viewConfigSchema = z camera_select: z .enum([...FRIGATE_CARD_VIEWS_USER_SPECIFIED, 'current']) .default(viewConfigDefault.camera_select), - timeout_seconds: z.number().default(viewConfigDefault.timeout_seconds), + interaction_seconds: z.number().default(viewConfigDefault.interaction_seconds), + reset_after_interaction: z + .boolean() + .default(viewConfigDefault.reset_after_interaction), update_seconds: z.number().default(viewConfigDefault.update_seconds), update_force: z.boolean().default(viewConfigDefault.update_force), update_cycle_camera: z.boolean().default(viewConfigDefault.update_cycle_camera), diff --git a/src/const.ts b/src/const.ts index 16f16147..d0fddf23 100644 --- a/src/const.ts +++ b/src/const.ts @@ -71,10 +71,11 @@ const CONF_VIEW = 'view' as const; export const CONF_VIEW_CAMERA_SELECT = `${CONF_VIEW}.camera_select` as const; export const CONF_VIEW_DARK_MODE = `${CONF_VIEW}.dark_mode` as const; export const CONF_VIEW_DEFAULT = `${CONF_VIEW}.default` as const; -export const CONF_VIEW_TIMEOUT_SECONDS = `${CONF_VIEW}.timeout_seconds` as const; +export const CONF_VIEW_INTERACTION_SECONDS = `${CONF_VIEW}.interaction_seconds` as const; export const CONF_VIEW_UPDATE_CYCLE_CAMERA = `${CONF_VIEW}.update_cycle_camera` as const; export const CONF_VIEW_UPDATE_FORCE = `${CONF_VIEW}.update_force` as const; export const CONF_VIEW_UPDATE_SECONDS = `${CONF_VIEW}.update_seconds` as const; +export const CONF_VIEW_RESET_AFTER_INTERACTION = `${CONF_VIEW}.reset_after_interaction` as const; export const CONF_VIEW_SCAN = `${CONF_VIEW}.scan` as const; export const CONF_VIEW_SCAN_ENABLED = `${CONF_VIEW_SCAN}.enabled` as const; export const CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS = diff --git a/src/editor.ts b/src/editor.ts index d3be3939..00ddc989 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -22,9 +22,9 @@ import { } from './config-mgmt.js'; import { BUTTON_SIZE_MIN, - FRIGATE_MENU_PRIORITY_MAX, FrigateCardConfig, frigateCardConfigDefaults, + FRIGATE_MENU_PRIORITY_MAX, RawFrigateCardConfig, RawFrigateCardConfigArray, THUMBNAIL_WIDTH_MAX, @@ -157,8 +157,8 @@ import { CONF_MEDIA_VIEWER_TRANSITION_EFFECT, CONF_MEDIA_VIEWER_ZOOMABLE, CONF_MENU_ALIGNMENT, - CONF_MENU_BUTTON_SIZE, CONF_MENU_BUTTONS, + CONF_MENU_BUTTON_SIZE, CONF_MENU_POSITION, CONF_MENU_STYLE, CONF_PERFORMANCE_FEATURES_ANIMATED_PROGRESS_INDICATOR, @@ -180,6 +180,8 @@ import { CONF_VIEW_CAMERA_SELECT, CONF_VIEW_DARK_MODE, CONF_VIEW_DEFAULT, + CONF_VIEW_INTERACTION_SECONDS, + CONF_VIEW_RESET_AFTER_INTERACTION, CONF_VIEW_SCAN, CONF_VIEW_SCAN_ACTIONS, CONF_VIEW_SCAN_ACTIONS_INTERACTION_MODE, @@ -189,7 +191,6 @@ import { CONF_VIEW_SCAN_FILTER_SELECTED_CAMERA, CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS, CONF_VIEW_SCAN_UNTRIGGER_SECONDS, - CONF_VIEW_TIMEOUT_SECONDS, CONF_VIEW_UPDATE_CYCLE_CAMERA, CONF_VIEW_UPDATE_FORCE, CONF_VIEW_UPDATE_SECONDS, @@ -1948,7 +1949,11 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor this._cameraSelectViewModes, )} ${this._renderOptionSelector(CONF_VIEW_DARK_MODE, this._darkModes)} - ${this._renderNumberInput(CONF_VIEW_TIMEOUT_SECONDS)} + ${this._renderNumberInput(CONF_VIEW_INTERACTION_SECONDS)} + ${this._renderSwitch( + CONF_VIEW_RESET_AFTER_INTERACTION, + this._defaults.view.reset_after_interaction, + )} ${this._renderNumberInput(CONF_VIEW_UPDATE_SECONDS)} ${this._renderSwitch( CONF_VIEW_UPDATE_FORCE, diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index d4f7fd10..1c61c77a 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -410,7 +410,8 @@ "show_trigger_status": "Show pulsing border when triggered", "untrigger_seconds": "Seconds after inactive state change to untrigger" }, - "timeout_seconds": "Reset to default view X seconds after user action (0=never)", + "interaction_seconds": "Seconds after user action to remain interacted with (0=never)", + "reset_after_interaction": "Reset to the default view after user interaction", "update_cycle_camera": "Cycle through cameras when default view updates", "update_force": "Force card updates (ignore user interaction)", "update_seconds": "Refresh default view every X seconds (0=never)", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index b5940789..0d174950 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -18,8 +18,8 @@ "editor_label": "", "method": "", "methods": { - "standard": "", - "dashboard": "" + "dashboard": "", + "standard": "" } }, "dependencies": { @@ -236,27 +236,27 @@ "editor_label": "Controlli dal vivo", "ptz": { "editor_label": "", + "hide_home": "", + "hide_pan_tilt": "", + "hide_zoom": "", "mode": "", "modes": { - "on": "", + "auto": "", "off": "", - "auto": "" + "on": "" }, "orientation": "", "orientations": { - "vertical": "", - "horizontal": "" + "horizontal": "", + "vertical": "" }, "position": "", "positions": { - "top-left": "", - "top-right": "", "bottom-left": "", - "bottom-right": "" - }, - "hide_zoom": "", - "hide_pan_tilt": "", - "hide_home": "" + "bottom-right": "", + "top-left": "", + "top-right": "" + } } }, "draggable": "Il Visualizzatore eventi può essere trascinato oppure puoi scorrere", @@ -380,6 +380,8 @@ "on": "On" }, "default": "Visualizzazione predefinita", + "interaction_seconds": "", + "reset_after_interaction": "", "scan": { "actions": { "editor_label": "", @@ -406,7 +408,6 @@ "show_trigger_status": "Mostra bordo pulsante quando attivato", "untrigger_seconds": "Reimposta la vista ai valori predefiniti dopo aver annullato l'attivazione" }, - "timeout_seconds": "Ripristina la vista predefinita x secondi dopo l'azione dell'utente (0 = mai)", "update_cycle_camera": "Scorri le telecamere quando si aggiorna la visualizzazione predefinita", "update_force": "Aggiornamenti della scheda forza (ignora l'interazione dell'utente)", "update_seconds": "Aggiorna la visualizzazione predefinita ogni x secondi (0 = mai)", @@ -497,8 +498,8 @@ "no_visible_cameras": "Nessuna telecamera visibile trovata, è necessario configurare almeno una telecamera non nascosta", "reconnecting": "Riconnessione", "timeline_no_cameras": "Nessuna telecamera damostrare in Frigate nella timeline", - "troubleshooting": "Controllare la risoluzione dei problemi", "too_many_automations": "", + "troubleshooting": "Controllare la risoluzione dei problemi", "unknown": "Errore sconosciuto", "upgrade_available": "È disponibile un aggiornamento di configurazione della scheda automatizzato, visitare l'editor di schede visive", "webrtc_card_reported_error": "La scheda WebRTC ha riportato un errore", @@ -567,4 +568,4 @@ }, "select_date": "Scegli la data" } -} +} \ No newline at end of file diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 8c6db881..eb91e704 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -18,8 +18,8 @@ "editor_label": "", "method": "", "methods": { - "standard": "", - "dashboard": "" + "dashboard": "", + "standard": "" } }, "dependencies": { @@ -236,27 +236,27 @@ "editor_label": "Controles da visualização ao vivo", "ptz": { "editor_label": "", + "hide_home": "", + "hide_pan_tilt": "", + "hide_zoom": "", "mode": "", "modes": { - "on": "", + "auto": "", "off": "", - "auto": "" + "on": "" }, "orientation": "", "orientations": { - "vertical": "", - "horizontal": "" + "horizontal": "", + "vertical": "" }, "position": "", "positions": { - "top-left": "", - "top-right": "", "bottom-left": "", - "bottom-right": "" - }, - "hide_zoom": "", - "hide_pan_tilt": "", - "hide_home": "" + "bottom-right": "", + "top-left": "", + "top-right": "" + } } }, "draggable": "A visualização ao vivo das câmeras pode ser arrastada/deslizada", @@ -383,6 +383,8 @@ "on": "Ligado" }, "default": "Visualização padrão", + "interaction_seconds": "", + "reset_after_interaction": "", "scan": { "actions": { "editor_label": "", @@ -409,7 +411,6 @@ "show_trigger_status": "Pulsar borda quando acionado", "untrigger_seconds": "Segundos após a mudar para o estado inativo para desacionar" }, - "timeout_seconds": "Redefinir para a visualização padrão X segundos após a ação do usuário (0 = nunca)", "update_cycle_camera": "Percorrer as câmeras quando a visualização padrão for atualizada", "update_force": "Forçar atualizações do cartão (ignore a interação do usuário)", "update_seconds": "Atualize a visualização padrão a cada X segundos (0 = nunca)", @@ -577,4 +578,4 @@ }, "select_date": "Escolha a data" } -} +} \ No newline at end of file diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index b164abc4..1e744d30 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -18,8 +18,8 @@ "editor_label": "", "method": "", "methods": { - "standard": "", - "dashboard": "" + "dashboard": "", + "standard": "" } }, "dependencies": { @@ -229,27 +229,27 @@ "editor_label": "Controles da visualização ao vivo", "ptz": { "editor_label": "", + "hide_home": "", + "hide_pan_tilt": "", + "hide_zoom": "", "mode": "", "modes": { - "on": "", + "auto": "", "off": "", - "auto": "" + "on": "" }, "orientation": "", "orientations": { - "vertical": "", - "horizontal": "" + "horizontal": "", + "vertical": "" }, "position": "", "positions": { - "top-left": "", - "top-right": "", "bottom-left": "", - "bottom-right": "" - }, - "hide_zoom": "", - "hide_pan_tilt": "", - "hide_home": "" + "bottom-right": "", + "top-left": "", + "top-right": "" + } } }, "draggable": "A visualização ao vivo das câmeras pode ser arrastada/deslizada", @@ -373,6 +373,8 @@ "on": "Ligado" }, "default": "Visualização padrão", + "interaction_seconds": "", + "reset_after_interaction": "", "scan": { "actions": { "editor_label": "", @@ -399,7 +401,6 @@ "show_trigger_status": "Exibir estado do gatilho", "untrigger_seconds": "Segundos após a mudar para o estado inativo para desacionar" }, - "timeout_seconds": "Redefinir para a visualização padrão X segundos após a ação do usuário (0 = nunca)", "update_cycle_camera": "Percorrer as câmeras quando a visualização padrão for atualizada", "update_force": "Forçar atualizações do cartão (ignore a interação do Utilizador)", "update_seconds": "Atualize a visualização padrão a cada X segundos (0 = nunca)", @@ -490,8 +491,8 @@ "no_visible_cameras": "Sem camaras visiveis", "reconnecting": "A voltar a ligar", "timeline_no_cameras": "Nenhuma câmera do Frigate para mostrar na linha do tempo", - "troubleshooting": "Verifique a solução de problemas", "too_many_automations": "", + "troubleshooting": "Verifique a solução de problemas", "unknown": "Erro desconhecido", "upgrade_available": "Uma atualização automatizada da configuração do cartão está disponível, visite o editor visual do cartão", "webrtc_card_reported_error": "O cartão WebRTC relatou um erro", diff --git a/tests/card-controller/card-element-manager.test.ts b/tests/card-controller/card-element-manager.test.ts index a9eb5f40..1f9877a1 100644 --- a/tests/card-controller/card-element-manager.test.ts +++ b/tests/card-controller/card-element-manager.test.ts @@ -136,6 +136,11 @@ describe('CardElementManager', () => { ); expect(windowAddEventListener).toBeCalledWith('location-changed', expect.anything()); expect(windowAddEventListener).toBeCalledWith('popstate', expect.anything()); + + expect(api.getInteractionManager().initialize).toBeCalled(); + expect(api.getFullscreenManager().initialize).toBeCalled(); + expect(api.getExpandManager().initialize).toBeCalled(); + expect(api.getMediaLoadedInfoManager().initialize).toBeCalled(); }); it('should disconnect', () => { diff --git a/tests/card-controller/conditions-manager.test.ts b/tests/card-controller/conditions-manager.test.ts index 148c0dda..f1c321ec 100644 --- a/tests/card-controller/conditions-manager.test.ts +++ b/tests/card-controller/conditions-manager.test.ts @@ -360,4 +360,26 @@ describe('ConditionsManager', () => { manager.setState({ displayMode: 'single' }); expect(manager.evaluateCondition(condition)).toBeFalsy(); }); + + it('should evaluate conditions with triggers', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { triggered: ['camera_1', 'camera_2'] }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ triggered: new Set(['camera_1']) }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ triggered: new Set(['camera_2', 'camera_1', 'camera_3']) }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ triggered: new Set(['camera_3']) }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + it('should evaluate conditions with interaction', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { interaction: true }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ interaction: true }) + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ interaction: false }) + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); }); diff --git a/tests/card-controller/expand-manager.test.ts b/tests/card-controller/expand-manager.test.ts index cfbc514e..1417c064 100644 --- a/tests/card-controller/expand-manager.test.ts +++ b/tests/card-controller/expand-manager.test.ts @@ -9,6 +9,14 @@ describe('ExpandManager', () => { expect(manager.isExpanded()).toBeFalsy(); }); + it('should initialize', () => { + const api = createCardAPI(); + const manager = new ExpandManager(api); + + manager.initialize(); + expect(api.getConditionsManager().setState).toBeCalledWith({ expand: false }); + }); + it('should set expanded', () => { const api = createCardAPI(); vi.mocked(api.getFullscreenManager().isInFullscreen).mockReturnValue(true); diff --git a/tests/card-controller/fullscreen-manager.test.ts b/tests/card-controller/fullscreen-manager.test.ts index 7599ae62..ba0d3f6c 100644 --- a/tests/card-controller/fullscreen-manager.test.ts +++ b/tests/card-controller/fullscreen-manager.test.ts @@ -29,6 +29,17 @@ describe('FullscreenManager', () => { vi.clearAllMocks(); }); + it('should initialize', () => { + const api = createCardAPI(); + const manager = new FullscreenManager(api); + + setScreenfulEnabled(true); + setScreenfulFullscreen(false); + + manager.initialize(); + expect(api.getConditionsManager().setState).toBeCalledWith({ fullscreen: false }); + }); + it('should correctly determine whether in fullscreen', () => { const manager = new FullscreenManager(createCardAPI()); diff --git a/tests/card-controller/interaction-manager.test.ts b/tests/card-controller/interaction-manager.test.ts index be6534d5..8e363948 100644 --- a/tests/card-controller/interaction-manager.test.ts +++ b/tests/card-controller/interaction-manager.test.ts @@ -15,12 +15,20 @@ describe('InteractionManager', () => { vi.useRealTimers(); }); + it('should initialize', () => { + const api = createCardAPI(); + const manager = new InteractionManager(api); + + manager.initialize(); + expect(api.getConditionsManager().setState).toBeCalledWith({ interaction: false }); + }); + it('should take action when interaction is reported', () => { const api = createCardAPI(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { - timeout_seconds: 10, + interaction_seconds: 10, }, }), ); @@ -45,7 +53,7 @@ describe('InteractionManager', () => { vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { - timeout_seconds: 10, + interaction_seconds: 10, }, }), ); @@ -64,12 +72,12 @@ describe('InteractionManager', () => { expect(api.getViewManager().setViewDefault).not.toBeCalled(); }); - it('should not take action when not configured', () => { + it('should not take action without an interaction timeout', () => { const api = createCardAPI(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { - timeout_seconds: 0, + interaction_seconds: 0, }, }), ); @@ -81,4 +89,60 @@ describe('InteractionManager', () => { // true but the default view will not have been set. expect(api.getViewManager().setViewDefault).not.toBeCalled(); }); + + it('should not take action without reset_after_interaction', () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + reset_after_interaction: false, + interaction_seconds: 10, + }, + }), + ); + const manager = new InteractionManager(api); + vi.useFakeTimers(); + vi.setSystemTime(start); + + manager.reportInteraction(); + + vi.setSystemTime(add(start, { seconds: 10 })); + vi.runOnlyPendingTimers(); + + // First call is blocked by triggers (above), so interaction will report + // true but the default view will not have been set. + expect(api.getViewManager().setViewDefault).not.toBeCalled(); + }); + + it('should set condition state', () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + interaction_seconds: 10, + }, + }), + ); + const manager = new InteractionManager(api); + vi.useFakeTimers(); + vi.setSystemTime(start); + + expect(api.getConditionsManager().setState).not.toBeCalled(); + + manager.reportInteraction(); + expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith( + expect.objectContaining({ + interaction: true, + }), + ); + + vi.setSystemTime(add(start, { seconds: 10 })); + vi.runOnlyPendingTimers(); + + expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith( + expect.objectContaining({ + interaction: false, + }), + ); + }); }); diff --git a/tests/card-controller/media-info-manager.test.ts b/tests/card-controller/media-info-manager.test.ts index fc0e1c9f..3f2969d3 100644 --- a/tests/card-controller/media-info-manager.test.ts +++ b/tests/card-controller/media-info-manager.test.ts @@ -3,6 +3,14 @@ import { MediaLoadedInfoManager } from '../../src/card-controller/media-info-man import { createCardAPI, createMediaLoadedInfo } from '../test-utils.js'; describe('MediaLoadedInfoManager', () => { + it('should initialize', () => { + const api = createCardAPI(); + const manager = new MediaLoadedInfoManager(api); + + manager.initialize(); + expect(api.getConditionsManager().setState).toBeCalledWith({ media_loaded: false }); + }); + it('should set', () => { const api = createCardAPI(); const manager = new MediaLoadedInfoManager(api); diff --git a/tests/card-controller/triggers-manager.test.ts b/tests/card-controller/triggers-manager.test.ts index d6ae6b4d..90bcedd7 100644 --- a/tests/card-controller/triggers-manager.test.ts +++ b/tests/card-controller/triggers-manager.test.ts @@ -123,6 +123,10 @@ describe('TriggersManager', () => { manager.updateTriggerHAState(createHASS(hassInactiveState)); expect(manager.isTriggered()).toBeTruthy(); + expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({ + triggered: new Set(['camera_1']), + }); + expect(api.getViewManager().setViewByParameters).toBeCalledWith({ viewName: 'live' as const, cameraID: 'camera_1' as const, @@ -144,6 +148,9 @@ describe('TriggersManager', () => { vi.runOnlyPendingTimers(); expect(manager.isTriggered()).toBeFalsy(); + expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({ + triggered: undefined, + }); expect(api.getViewManager().setViewDefault).toBeCalled(); }); diff --git a/tests/config-mgmt.test.ts b/tests/config-mgmt.test.ts index d90c099f..834928de 100644 --- a/tests/config-mgmt.test.ts +++ b/tests/config-mgmt.test.ts @@ -1213,4 +1213,22 @@ describe('should handle version specific upgrades', () => { }); }); }); + + it('should move view.timeout_seconds', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + timeout_seconds: 200, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + interaction_seconds: 200, + }, + }); + }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 9bd1fe41..95de1a00 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -288,7 +288,8 @@ describe('config defaults', () => { }, filter_selected_camera: false, }, - timeout_seconds: 300, + interaction_seconds: 300, + reset_after_interaction: true, update_cycle_camera: false, update_force: false, update_seconds: 0, diff --git a/vite.config.ts b/vite.config.ts index 699b52b7..8647cf09 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,10 +10,10 @@ export default defineConfig({ // Thresholds will automatically be updated as coverage improves to avoid // back-sliding. thresholdAutoUpdate: true, - statements: 71.82, - branches: 60.67, - functions: 72.86, - lines: 71.71, + statements: 71.95, + branches: 60.8, + functions: 73.04, + lines: 71.84, }, }, }); From 2d3817100be0593afd60f8ef1f3ebc0577ad0b2a Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Thu, 25 Jan 2024 22:28:05 -0800 Subject: [PATCH 073/189] Add warning message for loading stream. --- src/components/live/live-image.ts | 10 ++++++++-- src/localize/languages/en.json | 1 + src/localize/languages/it.json | 1 + src/localize/languages/pt-BR.json | 1 + src/localize/languages/pt-PT.json | 1 + 5 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/live/live-image.ts b/src/components/live/live-image.ts index eb6a24d4..91a5351d 100644 --- a/src/components/live/live-image.ts +++ b/src/components/live/live-image.ts @@ -3,10 +3,11 @@ import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit import { customElement, property } from 'lit/decorators.js'; import { createRef, ref, Ref } from 'lit/directives/ref.js'; import { CameraConfig } from '../../config/types'; +import { localize } from '../../localize/localize'; import liveImageStyle from '../../scss/live-image.scss'; import { FrigateCardMediaPlayer } from '../../types.js'; -import '../image.js'; import { getStateObjOrDispatchError } from '../../utils/get-state-obj'; +import '../image.js'; @customElement('frigate-card-live-image') export class FrigateCardLiveImage extends LitElement implements FrigateCardMediaPlayer { @@ -79,7 +80,12 @@ export class FrigateCardLiveImage extends LitElement implements FrigateCardMedia .cameraConfig=${this.cameraConfig} > - ${this.watermark ? html`` : ''} + ${this.watermark + ? html`` + : ''} `; } diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 1c61c77a..79bffa5b 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -477,6 +477,7 @@ } }, "error": { + "awaiting_live": "Waiting for live stream to load ...", "could_not_render_elements": "Could not render picture elements", "could_not_resolve": "Could not resolve media URL", "diagnostics": "Card diagnostics. Please review for confidential information prior to sharing", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 0d174950..7cf37f87 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -469,6 +469,7 @@ } }, "error": { + "awaiting_live": "", "could_not_render_elements": "Impossibile renderizzare gli elementi dell'immagine", "could_not_resolve": "Impossibile risolvere l'URL dei media", "diagnostics": "Diagnostica delle carte.Si prega di rivedere per informazioni riservate prima di condividere", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index eb91e704..73ed9a70 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -476,6 +476,7 @@ } }, "error": { + "awaiting_live": "", "could_not_render_elements": "Não foi possível renderizar os elementos da imagem", "could_not_resolve": "Não foi possível resolver o URL de mídia", "diagnostics": "Diagnósticos do cartão. Revise as informações confidenciais antes de compartilhar", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 1e744d30..25140dd8 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -462,6 +462,7 @@ } }, "error": { + "awaiting_live": "", "could_not_render_elements": "Não foi possível renderizar os elementos da imagem", "could_not_resolve": "Não foi possível resolver o URL de mídia", "diagnostics": "Diagnósticos do cartão. Reveja as informações confidenciais antes de partilhar", From 53fa1e06596de5b4c0a1fae0ac288126251e8fd2 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Thu, 25 Jan 2024 22:40:29 -0800 Subject: [PATCH 074/189] Minor fixes. --- src/editor.ts | 7 ------- src/localize/languages/en.json | 4 ++-- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/editor.ts b/src/editor.ts index 00ddc989..442afa1c 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -949,13 +949,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderNumberInput(CONF_VIEW_SCAN_UNTRIGGER_SECONDS, { default: this._defaults.view.scan.untrigger_seconds, })} - ${this._renderOptionSelector( - CONF_VIEW_SCAN_ACTIONS_TRIGGER, - this._scanActionsTrigger, - { - label: localize('config.view.scan.actions.trigger'), - }, - )} ${this._putInSubmenu( MENU_VIEW_SCAN_ACTIONS, true, diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 79bffa5b..94d05c5c 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -396,12 +396,12 @@ "trigger": "Trigger action", "triggers": { "live": "Change to live", - "none": "Take no action" + "none": "No action" }, "untrigger": "Untrigger action", "untriggers": { "default": "Change to default view/camera", - "none": "Take no action" + "none": "No action" } }, "editor_label": "Scan mode", From b99628d5eeb7cc5bf057a0bcdd48508c1550e581 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 27 Jan 2024 17:39:47 -0800 Subject: [PATCH 075/189] Fix minor seeking issue in unreleased code. --- src/view/view.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view/view.ts b/src/view/view.ts index a402b3ad..6d395a9b 100644 --- a/src/view/view.ts +++ b/src/view/view.ts @@ -178,7 +178,7 @@ export class View { * @returns This view. */ public mergeInContext(context?: ViewContext): View { - this.context = merge(this.context ?? {}, this.context, context); + this.context = merge({}, this.context, context); return this; } From 1f70866ce65b952e14e0ab3db4c31e31f8701028 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 27 Jan 2024 17:43:00 -0800 Subject: [PATCH 076/189] Add test. --- tests/view/view.test.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/view/view.test.ts b/tests/view/view.test.ts index 0703f226..bea28a03 100644 --- a/tests/view/view.test.ts +++ b/tests/view/view.test.ts @@ -113,6 +113,12 @@ describe('View Basics', () => { view.mergeInContext({ timeline: timelineContext }); expect(view.context?.live).toEqual(liveContext); expect(view.context?.timeline).toEqual(timelineContext); + + // Verify that merging context creates a new context object, as some + // downstream users may check for context equality. + const oldContext = view.context; + view.mergeInContext({ live: liveContext }); + expect(view.context).not.toBe(oldContext); }); it('should remove context', () => { From 94ade5beb573211c702a33dcb33fed4633e4fc93 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 27 Jan 2024 17:57:41 -0800 Subject: [PATCH 077/189] Adjust branch coverage. --- vite.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vite.config.ts b/vite.config.ts index 8647cf09..c788fc81 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -11,7 +11,7 @@ export default defineConfig({ // back-sliding. thresholdAutoUpdate: true, statements: 71.95, - branches: 60.8, + branches: 60.78, functions: 73.04, lines: 71.84, }, From d3260d516c19bfd530dc8d795acb9a72e74c4f0a Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 28 Jan 2024 20:30:09 -0800 Subject: [PATCH 078/189] Allow the inbound audio to unmute when the microphone is unmuted. --- README.md | 55 +- src/card-controller/microphone-manager.ts | 60 +- src/card.ts | 2 +- src/components/live/live.ts | 31 +- src/components/viewer.ts | 8 +- src/components/views.ts | 5 +- src/config-mgmt.ts | 31 + src/config/types.ts | 67 +- src/const.ts | 5 +- src/editor.ts | 57 +- src/localize/languages/en.json | 5 +- src/localize/languages/it.json | 5 +- src/localize/languages/pt-BR.json | 5 +- src/localize/languages/pt-PT.json | 5 +- .../plugins/auto-lazy-load/auto-lazy-load.ts | 8 +- .../auto-media-actions/auto-media-actions.ts | 119 +- .../microphone-manager.test.ts | 31 + tests/config-mgmt.test.ts | 1182 +++++++++++------ tests/config/types.test.ts | 30 +- .../auto-lazy-load/auto-lazy-load.test.ts | 9 +- .../auto-media-actions.test.ts | 167 ++- vite.config.ts | 8 +- 22 files changed, 1313 insertions(+), 582 deletions(-) diff --git a/README.md b/README.md index 3cec8618..6c1ba897 100644 --- a/README.md +++ b/README.md @@ -517,12 +517,12 @@ See the [fully expanded live configuration example](#config-expanded-live) for h | Option | Default | Overridable | Description | | - | - | - | - | | `preload` | `false` | :heavy_multiplication_x: | Whether or not to preload the live view. Preloading causes the live view to render in the background regardless of what view is actually shown, so it's instantly available when requested. This consumes additional network/CPU resources continually. | -| `auto_play` | `all` | :heavy_multiplication_x: | Whether to automatically play live camera feeds. `never` will never automatically play, `selected` will automatically play when a camera is selected in the carousel, `visible` will automatically play when the browser/tab becomes visible or `all` on any opportunity to automatically play (i.e. either case). Some live providers (e.g. `webrtc-card`, `jsmpeg`) do not support the prevention of automatic play on initial load, but should still respect the value of this flag on play-after-pause.| -| `auto_pause` | `never` | :heavy_multiplication_x: | Whether to automatically pause live camera feeds. `never` will never automatically pause, `unselected` will automatically pause when a camera is unselected in the carousel, `hidden` will automatically pause when the browser/tab becomes hidden or `all` on any opportunity to automatically pause (i.e. either case). **Caution**: Some live providers (e.g. `jsmpeg`) may not offer human-accessible means to resume play if it is paused, unless the `auto_play` option (above) is used.| -| `auto_mute` | `all` | :heavy_multiplication_x: | Whether to automatically mute live camera feeds. `never` will never automatically mute, `unselected` will automatically mute when a camera is unselected in the carousel, `hidden` will automatically mute when the browser/tab becomes hidden or `all` on any opportunity to automatically mute (i.e. either case). Note that if `auto_play` is enabled, the stream may mute itself automatically in order to honor the `auto_play` setting, as some browsers will not auto play media that is unmuted -- that is to say, where necessary, the `auto_play` parameter will take priority over the `auto_mute` parameter.| -| `auto_unmute` | `never` | :heavy_multiplication_x: | Whether to automatically unmute live camera feeds. `never` will never automatically unmute, `selected` will automatically unmute when a camera is unselected in the carousel, `visible` will automatically unmute when the browser/tab becomes visible or `all` on any opportunity to automatically unmute (i.e. either case).| +| `auto_play` | `[selected, visible]` | :heavy_multiplication_x: | An array of conditions in which live camera feeds are automatically played.`selected` will automatically play when a camera is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play. Some live providers (e.g. `webrtc-card`, `jsmpeg`) do not support the prevention of automatic play on initial load, but should still respect the value of this flag on play-after-pause.| +| `auto_pause` | `[]` | :heavy_multiplication_x: | An array of conditions in which live camera feeds are automatically paused. `unselected` will automatically pause when a camera is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause. **Caution**: Some live providers (e.g. `jsmpeg`) may not offer human-accessible means to resume play if it is paused, unless the `auto_play` option (above) is used.| +| `auto_mute` | `[unselected, hidden, microphone]` | :heavy_multiplication_x: | An array of conditions in which live camera feeds are muted. `unselected` will automatically mute when a camera is unselected in the carousel, `hidden` will automatically mute when the browser/tab becomes hidden or `microphone` will automatically mute after the microphone is muted as long as the camera stays selected (see the `live.microphone.mute_after_microphone_mute_seconds` to control how long after). Use an empty list (`[]`) to never automatically mute. Note that if `auto_play` is enabled, the stream may mute itself automatically in order to honor the `auto_play` setting, as some browsers will not auto play media that is unmuted -- that is to say, where necessary, the `auto_play` parameter will take priority over the `auto_mute` parameter.| +| `auto_unmute` | `[microphone]` | :heavy_multiplication_x: | An array of conditions in which live camera feeds are unmuted. `selected` will automatically unmute when a camera is unselected in the carousel, `visible` will automatically unmute when the browser/tab becomes visible or `microphone` will automatically unmute after the microphone is unmuted. Use an empty list (`[]`) to never automatically unmute.| | `lazy_load` | `true` | :heavy_multiplication_x: | Whether or not to lazily load cameras in the camera carousel. Setting this will `false` will cause all cameras to load simultaneously when the `live` carousel is opened (or cause all cameras to load continually if both `lazy_load` and `preload` are `true`). This will result in a smoother carousel experience at a cost of (potentially) a substantial amount of continually streamed data. | -| `lazy_unload` | `never` | :heavy_multiplication_x: | When to lazily **un**load lazyily-loaded cameras. `never` will never lazily-unload, `unselected` will lazy-unload a camera when it is unselected in the carousel, `hidden` will lazy-unload all cameras when the browser/tab becomes hidden or `all` on any opportunity to lazily unload (i.e. either case). This will cause a reloading delay on revisiting that camera in the carousel but will save the streaming network resources that are otherwise consumed. This option has no effect if `lazy_load` is false. Some live providers (e.g. `webrtc-card`) implement their own lazy unloading independently which may occur regardless of the value of this setting.| +| `lazy_unload` | `[]` | :heavy_multiplication_x: | An array of conditions in which live camera feeds are unloaded. `unselected` will lazy-unload a camera when it is unselected in the carousel and `hidden` will lazy-unload all cameras when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically unload. This will cause a reloading delay on revisiting that camera in the carousel but will save the streaming network resources that are otherwise consumed. This option has no effect if `lazy_load` is false. Some live providers (e.g. `webrtc-card`) implement their own lazy unloading independently which may occur regardless of the value of this setting.| | `draggable` | `true` | :heavy_multiplication_x: | Whether or not the live carousel can be dragged left or right, via touch/swipe and mouse dragging. | | `zoomable` | `true` | :white_check_mark: | Whether or not the live carousel can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | | `transition_effect` | `slide` | :heavy_multiplication_x: | Effect to apply as a transition between live cameras. Accepted values: `slide` or `none`. | @@ -633,7 +633,8 @@ live: | Option | Default | Overridable | Description | | - | - | - | - | | `always_connected` | `false` | :white_check_mark: | Whether or not to keep the microphone stream continually connected while the card is running, or only when microphone is used (default). In the latter case there'll be a connection reset when the microphone is first used -- using this option can avoid that reset.| -| `disconnect_seconds` | `60` | :white_check_mark: | The number of seconds after microphone usage to disconnect the microphone from the stream. `0` implies never. Not relevant if `always_connected` is `true`.| +| `disconnect_seconds` | `90` | :white_check_mark: | The number of seconds after microphone usage to disconnect the microphone from the stream. `0` implies never. Not relevant if `always_connected` is `true`.| +| `mute_after_microphone_mute_seconds` | `60` | :white_check_mark: | The number of seconds after the microphone mutes to automatically mute the inbound audio when `live.auto_mute` includes `microphone`.| See [Using 2-way audio](#using-2-way-audio) for more information about the very particular requirements that must be followed for 2-way audio to work. @@ -704,10 +705,10 @@ See the [fully expanded Media viewer configuration example](#config-expanded-med | Option | Default | Overridable | Description | | - | - | - | - | -| `auto_play` | `all` | :heavy_multiplication_x: | Whether to automatically play events. `never` will never automatically play, `selected` will automatically play when an event is selected in the carousel, `visible` will automatically play when the browser/tab becomes visible or `all` on any opportunity to automatically play (i.e. either case).| -| `auto_pause` | `all` | :heavy_multiplication_x: | Whether to automatically pause events. `never` will never automatically pause, `unselected` will automatically pause when an event is unselected in the carousel, `hidden` will automatically pause when the browser/tab becomes hidden or `all` on any opportunity to automatically pause (i.e. either case).| -| `auto_mute` | `all` | :heavy_multiplication_x: | Whether to automatically mute events. `never` will never automatically mute, `unselected` will automatically mute when an event is unselected in the carousel, `hidden` will automatically mute when the browser/tab becomes hidden or `all` on any opportunity to automatically mute (i.e. either case).| -| `auto_unmute` | `never` | :heavy_multiplication_x: | Whether to automatically unmute events. `never` will never automatically unmute, `selected` will automatically unmute when an event is selected in the carousel, `visible` will automatically unmute when the browser/tab becomes visible or `all` on any opportunity to automatically unmute (i.e. either case). Note that some browsers will not allow automated unmute until the user has interacted with the page in some way -- if the user has not then the browser may pause the media instead.| +| `auto_play` | `[selected, visible]` | :heavy_multiplication_x: | An array of conditions in which media items are automatically played.`selected` will automatically play when a media item is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play.| +| `auto_pause` | `[unselected, hidden]` | :heavy_multiplication_x: | An array of conditions in which media items are automatically paused. `unselected` will automatically pause when a media item is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause.| +| `auto_mute` | `[unselected, hidden]` | :heavy_multiplication_x: | An array of conditions in which media items are muted. `unselected` will automatically mute when a media item is unselected in the carousel and `hidden` will automatically mute when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically mute.| +| `auto_unmute` | `[]` | :heavy_multiplication_x: | An array of conditions in which media items are unmuted. `selected` will automatically unmute when a media item is unselected in the carousel and `visible` will automatically unmute when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically unmute. Note that some browsers will not allow automated unmute until the user has interacted with the page in some way -- if the user has not then the browser may pause the media instead.| | `lazy_load` | `true` | :heavy_multiplication_x: | Whether or not to lazily load media in the Media viewer carousel. Setting this will false will fetch all media immediately which may make the carousel experience smoother at a cost of (potentially) a substantial number of simultaneous media fetches on load. | | `draggable` | `true` | :heavy_multiplication_x: | Whether or not the Media viewer carousel can be dragged left or right, via touch/swipe and mouse dragging. | | `zoomable` | `true` | :heavy_multiplication_x: | Whether or not the Media Viewer can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | @@ -2057,13 +2058,18 @@ Reference: [Live Options](#live-options). ```yaml live: - auto_play: all - auto_pause: never - auto_mute: all - auto_unmute: never + auto_play: + - selected + - visible + auto_pause: [] + auto_mute: + - unselected + - hidden + auto_unmute: + - microphone preload: false lazy_load: true - lazy_unload: never + lazy_unload: [] draggable: true zoomable: true transition_effect: slide @@ -2097,7 +2103,8 @@ live: y: 50 microphone: always_connected: false - disconnect_seconds: 60 + disconnect_seconds: 90 + mute_after_microphone_mute_seconds: 60 ptz: mode: on position: bottom-right @@ -2150,10 +2157,16 @@ Reference: [Media Viewer Options](#event-viewer-options). ```yaml media_viewer: - auto_play: all - auto_pause: all - auto_mute: all - auto_unmute: never + auto_play: + - selected + - visible + auto_pause: + - unselected + - hidden + auto_mute: + - unselected + - hidden + auto_unmute: [] lazy_load: true draggable: true zoomable: true @@ -4346,7 +4359,7 @@ Your browser will not allow a page/script (like this card) to pass credentials t ### Chrome autoplays when a tab becomes visible again -Even if `live.auto_play` or `media_viewer.auto_play` is set to `never`, Chrome itself will still auto play a video that was previously playing prior to the tab being hidden, once that tab is visible again. This behavior cannot be influenced by the card. Other browsers (e.g. Firefox, Safari) do not exhibit this behavior. +Even if `live.auto_play` or `media_viewer.auto_play` is set to `[]`, Chrome itself will still auto play a video that was previously playing prior to the tab being hidden, once that tab is visible again. This behavior cannot be influenced by the card. Other browsers (e.g. Firefox, Safari) do not exhibit this behavior. ### The `live` view just shows a blank white image during loading diff --git a/src/card-controller/microphone-manager.ts b/src/card-controller/microphone-manager.ts index 303a79c6..8aed6315 100644 --- a/src/card-controller/microphone-manager.ts +++ b/src/card-controller/microphone-manager.ts @@ -2,10 +2,23 @@ import { errorToConsole } from '../utils/basic'; import { Timer } from '../utils/timer'; import { CardMicrophoneAPI } from './types'; -export class MicrophoneManager { +export type MicrophoneManagerListenerChange = 'muted' | 'unmuted'; +type MicrophoneManagerListener = (change: MicrophoneManagerListenerChange) => void; + +export interface ReadonlyMicrophoneManager { + getStream(): MediaStream | undefined; + addListener(listener: MicrophoneManagerListener): void; + removeListener(listener: MicrophoneManagerListener): void; + isConnected(): boolean; + isForbidden(): boolean; + isMuted(): boolean; +} + +export class MicrophoneManager implements ReadonlyMicrophoneManager { protected _api: CardMicrophoneAPI; protected _stream?: MediaStream | null; protected _timer = new Timer(); + protected _listeners: MicrophoneManagerListener[] = []; // We keep mute state separate from the stream state so that mute/unmute can // be expressed before the stream is created -- and when it's create it will @@ -44,21 +57,20 @@ export class MicrophoneManager { return this._stream ?? undefined; } - protected _setMute(): void { - this._stream?.getTracks().forEach((track) => { - track.enabled = !this._mute; - }); - this._startTimer(); - - this._api.getCardElementManager().update(); - } - public mute(): void { + const wasMuted = this.isMuted(); + this._mute = true; this._setMute(); + + if (!wasMuted) { + this._callListeners('muted'); + } } public async unmute(): Promise { + const wasUnmuted = !this.isMuted(); + const unmute = (): void => { this._mute = false; this._setMute(); @@ -76,6 +88,10 @@ export class MicrophoneManager { } else if (this.isConnected()) { unmute(); } + + if (!wasUnmuted) { + this._callListeners('unmuted'); + } } public isConnected(): boolean { @@ -92,9 +108,29 @@ export class MicrophoneManager { return !this._stream || this._stream.getTracks().every((track) => !track.enabled); } + public addListener(listener: MicrophoneManagerListener): void { + this._listeners.push(listener); + } + + public removeListener(listener: MicrophoneManagerListener): void { + this._listeners = this._listeners.filter((l) => l !== listener); + } + + protected _callListeners(change: MicrophoneManagerListenerChange): void { + this._listeners.forEach((listener) => listener(change)); + } + + protected _setMute(): void { + this._stream?.getTracks().forEach((track) => { + track.enabled = !this._mute; + }); + + this._startTimer(); + this._api.getCardElementManager().update(); + } + protected _startTimer(): void { - const microphoneConfig = this._api.getConfigManager().getConfig() - ?.live.microphone; + const microphoneConfig = this._api.getConfigManager().getConfig()?.live.microphone; if (microphoneConfig?.always_connected) { return; diff --git a/src/card.ts b/src/card.ts index 550067c8..7fb158aa 100644 --- a/src/card.ts +++ b/src/card.ts @@ -306,7 +306,7 @@ class FrigateCard extends LitElement { .getConditionsManager() ?.getEpoch()} .hide=${!!this._controller.getMessageManager().hasMessage()} - .microphoneStream=${this._controller.getMicrophoneManager()?.getStream()} + .microphoneManager=${this._controller.getMicrophoneManager()} .triggeredCameraIDs=${this._config?.view.scan.show_trigger_status ? this._controller.getTriggersManager().getTriggeredCameraIDs() : undefined} diff --git a/src/components/live/live.ts b/src/components/live/live.ts index f69a04aa..4f01c22e 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -18,6 +18,7 @@ import { ConditionsManagerEpoch, getOverriddenConfig, } from '../../card-controller/conditions-manager.js'; +import { ReadonlyMicrophoneManager } from '../../card-controller/microphone-manager.js'; import { MediaGridSelected } from '../../components-lib/media-grid-controller.js'; import { CameraConfig, @@ -113,7 +114,7 @@ export class FrigateCardLive extends LitElement { public cardWideConfig?: CardWideConfig; @property({ attribute: false }) - public microphoneStream?: MediaStream; + public microphoneManager?: ReadonlyMicrophoneManager; @property({ attribute: false }) public triggeredCameraIDs?: Set; @@ -222,7 +223,7 @@ export class FrigateCardLive extends LitElement { .liveOverrides=${this.liveOverrides} .cardWideConfig=${this.cardWideConfig} .cameraManager=${this.cameraManager} - .microphoneStream=${this.microphoneStream} + .microphoneManager=${this.microphoneManager} .triggeredCameraIDs=${this.triggeredCameraIDs} @frigate-card:message=${(ev: CustomEvent) => { this._renderKey++; @@ -286,7 +287,7 @@ export class FrigateCardLiveGrid extends LitElement { public cameraManager?: CameraManager; @property({ attribute: false }) - public microphoneStream?: MediaStream; + public microphoneManager?: ReadonlyMicrophoneManager; @property({ attribute: false }) public triggeredCameraIDs?: Set; @@ -306,7 +307,7 @@ export class FrigateCardLiveGrid extends LitElement { .liveOverrides=${this.liveOverrides} .cardWideConfig=${this.cardWideConfig} .cameraManager=${this.cameraManager} - .microphoneStream=${this.microphoneStream} + .microphoneManager=${this.microphoneManager} ?triggered=${triggeredCameraID && !!this.triggeredCameraIDs?.has(triggeredCameraID)} > @@ -394,7 +395,7 @@ export class FrigateCardLiveCarousel extends LitElement { public cameraManager?: CameraManager; @property({ attribute: false }) - public microphoneStream?: MediaStream; + public microphoneManager?: ReadonlyMicrophoneManager; @property({ attribute: false }) public viewFilterCameraID?: string; @@ -431,7 +432,7 @@ export class FrigateCardLiveCarousel extends LitElement { lazyLoadCallback: (index, slide) => this._lazyloadOrUnloadSlide('load', index, slide), }), - lazyUnloadCondition: this.overriddenLiveConfig?.lazy_unload, + lazyUnloadConditions: this.overriddenLiveConfig?.lazy_unload, lazyUnloadCallback: (index, slide) => this._lazyloadOrUnloadSlide('unload', index, slide), }), @@ -439,16 +440,22 @@ export class FrigateCardLiveCarousel extends LitElement { AutoMediaActions({ playerSelector: FRIGATE_CARD_LIVE_PROVIDER, ...(this.overriddenLiveConfig?.auto_play && { - autoPlayCondition: this.overriddenLiveConfig.auto_play, + autoPlayConditions: this.overriddenLiveConfig.auto_play, }), ...(this.overriddenLiveConfig?.auto_pause && { - autoPauseCondition: this.overriddenLiveConfig.auto_pause, + autoPauseConditions: this.overriddenLiveConfig.auto_pause, }), ...(this.overriddenLiveConfig?.auto_mute && { - autoMuteCondition: this.overriddenLiveConfig.auto_mute, + autoMuteConditions: this.overriddenLiveConfig.auto_mute, }), ...(this.overriddenLiveConfig?.auto_unmute && { - autoUnmuteCondition: this.overriddenLiveConfig.auto_unmute, + autoUnmuteConditions: this.overriddenLiveConfig.auto_unmute, + }), + ...((this.overriddenLiveConfig?.auto_unmute || + this.overriddenLiveConfig?.auto_mute) && { + microphoneManager: this.microphoneManager, + microphoneMuteSeconds: + this.overriddenLiveConfig.microphone.mute_after_microphone_mute_seconds, }), }), AutoSize(), @@ -571,7 +578,7 @@ export class FrigateCardLiveCarousel extends LitElement { ; @@ -241,7 +242,7 @@ export class FrigateCardViews extends LitElement { )} .cameraManager=${this.cameraManager} .cardWideConfig=${this.cardWideConfig} - .microphoneStream=${this.microphoneStream} + .microphoneManager=${this.microphoneManager} .triggeredCameraIDs=${this.triggeredCameraIDs} class="${classMap(liveClasses)}" > diff --git a/src/config-mgmt.ts b/src/config-mgmt.ts index d6f5eb61..9fe304ad 100644 --- a/src/config-mgmt.ts +++ b/src/config-mgmt.ts @@ -485,4 +485,35 @@ const UPGRADES = [ }, ), upgradeMoveToWithOverrides('view.timeout_seconds', CONF_VIEW_INTERACTION_SECONDS), + upgradeWithOverrides('live.lazy_unload', (data) => + data === 'all' ? ['unselected', 'hidden'] : data === 'never' ? null : arrayify(data), + ), + upgradeWithOverrides('live.auto_play', (data) => + data === 'all' ? null : data === 'never' ? [] : arrayify(data), + ), + upgradeWithOverrides('live.auto_pause', (data) => + data === 'all' ? ['unselected', 'hidden'] : data === 'never' ? null : arrayify(data), + ), + upgradeWithOverrides('live.auto_mute', (data) => + data === 'all' ? null : data === 'never' ? [] : arrayify(data), + ), + upgradeWithOverrides('live.auto_unmute', (data) => + data === 'all' + ? ['selected', 'visible', 'microphone'] + : data === 'never' + ? null + : arrayify(data), + ), + upgradeWithOverrides('media_viewer.auto_play', (data) => + data === 'all' ? null : data === 'never' ? [] : arrayify(data), + ), + upgradeWithOverrides('media_viewer.auto_pause', (data) => + data === 'all' ? null : data === 'never' ? [] : arrayify(data), + ), + upgradeWithOverrides('media_viewer.auto_mute', (data) => + data === 'all' ? null : data === 'never' ? [] : arrayify(data), + ), + upgradeWithOverrides('media_viewer.auto_unmute', (data) => + data === 'all' ? ['selected', 'visible'] : data === 'never' ? null : arrayify(data), + ), ]; diff --git a/src/config/types.ts b/src/config/types.ts index 2da6551a..514b90ff 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -46,24 +46,23 @@ const FRIGATE_CARD_VIEWS = [ export type FrigateCardView = (typeof FRIGATE_CARD_VIEWS)[number]; export const FRIGATE_CARD_VIEW_DEFAULT = 'live' as const; -const MEDIA_ACTION_NEGATIVE_CONDITIONS = [ - 'all', - 'unselected', - 'hidden', - 'never', -] as const; +export const MEDIA_ACTION_NEGATIVE_CONDITIONS = ['unselected', 'hidden'] as const; export type LazyUnloadCondition = (typeof MEDIA_ACTION_NEGATIVE_CONDITIONS)[number]; -export type AutoMuteCondition = (typeof MEDIA_ACTION_NEGATIVE_CONDITIONS)[number]; export type AutoPauseCondition = (typeof MEDIA_ACTION_NEGATIVE_CONDITIONS)[number]; -const MEDIA_ACTION_POSITIVE_CONDITIONS = [ - 'all', - 'selected', - 'visible', - 'never', -] as const; -export type AutoUnmuteCondition = (typeof MEDIA_ACTION_POSITIVE_CONDITIONS)[number]; +export const MEDIA_ACTION_POSITIVE_CONDITIONS = ['selected', 'visible'] as const; export type AutoPlayCondition = (typeof MEDIA_ACTION_POSITIVE_CONDITIONS)[number]; +export const MEDIA_UNMUTE_CONDITIONS = [ + ...MEDIA_ACTION_POSITIVE_CONDITIONS, + 'microphone', +] as const; +export type AutoUnmuteCondition = (typeof MEDIA_UNMUTE_CONDITIONS)[number]; + +export const MEDIA_MUTE_CONDITIONS = [ + ...MEDIA_ACTION_NEGATIVE_CONDITIONS, + 'microphone', +] as const; +export type AutoMuteCondition = (typeof MEDIA_MUTE_CONDITIONS)[number]; const PTZ_BASE_ACTIONS = ['left', 'right', 'up', 'down', 'zoom_in', 'zoom_out'] as const; @@ -738,6 +737,7 @@ export type LiveProvider = (typeof LIVE_PROVIDERS)[number]; const microphoneConfigDefault = { always_connected: false, disconnect_seconds: 60, + mute_after_microphone_mute_seconds: 60, }; const microphoneConfigSchema = z @@ -747,6 +747,10 @@ const microphoneConfigSchema = z .number() .min(0) .default(microphoneConfigDefault.disconnect_seconds), + mute_after_microphone_mute_seconds: z + .number() + .min(0) + .default(microphoneConfigDefault.mute_after_microphone_mute_seconds), }) .default(microphoneConfigDefault); export type MicrophoneConfig = z.infer; @@ -860,13 +864,13 @@ const liveThumbnailControlsDefaults = { }; const liveConfigDefault = { - auto_play: 'all' as const, - auto_pause: 'never' as const, - auto_mute: 'all' as const, - auto_unmute: 'never' as const, + auto_play: [...MEDIA_ACTION_POSITIVE_CONDITIONS], + auto_pause: [], + auto_mute: [...MEDIA_MUTE_CONDITIONS], + auto_unmute: ['microphone' as const], preload: false, lazy_load: true, - lazy_unload: 'never' as const, + lazy_unload: [], draggable: true, zoomable: true, transition_effect: 'slide' as const, @@ -929,23 +933,27 @@ const liveOverridableConfigSchema = z const liveConfigSchema = liveOverridableConfigSchema .extend({ - // Non-overrideable parameters. auto_play: z .enum(MEDIA_ACTION_POSITIVE_CONDITIONS) + .array() .default(liveConfigDefault.auto_play), auto_pause: z .enum(MEDIA_ACTION_NEGATIVE_CONDITIONS) + .array() .default(liveConfigDefault.auto_pause), auto_mute: z - .enum(MEDIA_ACTION_NEGATIVE_CONDITIONS) + .enum(MEDIA_MUTE_CONDITIONS) + .array() .default(liveConfigDefault.auto_mute), auto_unmute: z - .enum(MEDIA_ACTION_POSITIVE_CONDITIONS) + .enum(MEDIA_UNMUTE_CONDITIONS) + .array() .default(liveConfigDefault.auto_unmute), preload: z.boolean().default(liveConfigDefault.preload), lazy_load: z.boolean().default(liveConfigDefault.lazy_load), lazy_unload: z .enum(MEDIA_ACTION_NEGATIVE_CONDITIONS) + .array() .default(liveConfigDefault.lazy_unload), draggable: z.boolean().default(liveConfigDefault.draggable), transition_effect: transitionEffectConfigSchema.default( @@ -1296,10 +1304,10 @@ export type MenuConfig = z.infer; // ************************************************************************* const viewerConfigDefault = { - auto_play: 'all' as const, - auto_pause: 'all' as const, - auto_mute: 'all' as const, - auto_unmute: 'never' as const, + auto_play: [...MEDIA_ACTION_POSITIVE_CONDITIONS], + auto_pause: [...MEDIA_ACTION_NEGATIVE_CONDITIONS], + auto_mute: [...MEDIA_ACTION_NEGATIVE_CONDITIONS], + auto_unmute: [], lazy_load: true, draggable: true, zoomable: true, @@ -1330,15 +1338,22 @@ const viewerConfigSchema = z .object({ auto_play: z .enum(MEDIA_ACTION_POSITIVE_CONDITIONS) + .array() .default(viewerConfigDefault.auto_play), auto_pause: z .enum(MEDIA_ACTION_NEGATIVE_CONDITIONS) + .array() .default(viewerConfigDefault.auto_pause), + + // Don't use MEDIA_UNMUTE_CONDITIONS and MEDIA_MUTE_CONDITIONS here, since + // it includes 'microphone' which doesn't make sense for viewer media. auto_mute: z .enum(MEDIA_ACTION_NEGATIVE_CONDITIONS) + .array() .default(viewerConfigDefault.auto_mute), auto_unmute: z .enum(MEDIA_ACTION_POSITIVE_CONDITIONS) + .array() .default(viewerConfigDefault.auto_unmute), lazy_load: z.boolean().default(viewerConfigDefault.lazy_load), draggable: z.boolean().default(viewerConfigDefault.draggable), diff --git a/src/const.ts b/src/const.ts index d0fddf23..92dc8064 100644 --- a/src/const.ts +++ b/src/const.ts @@ -75,7 +75,8 @@ export const CONF_VIEW_INTERACTION_SECONDS = `${CONF_VIEW}.interaction_seconds` export const CONF_VIEW_UPDATE_CYCLE_CAMERA = `${CONF_VIEW}.update_cycle_camera` as const; export const CONF_VIEW_UPDATE_FORCE = `${CONF_VIEW}.update_force` as const; export const CONF_VIEW_UPDATE_SECONDS = `${CONF_VIEW}.update_seconds` as const; -export const CONF_VIEW_RESET_AFTER_INTERACTION = `${CONF_VIEW}.reset_after_interaction` as const; +export const CONF_VIEW_RESET_AFTER_INTERACTION = + `${CONF_VIEW}.reset_after_interaction` as const; export const CONF_VIEW_SCAN = `${CONF_VIEW}.scan` as const; export const CONF_VIEW_SCAN_ENABLED = `${CONF_VIEW_SCAN}.enabled` as const; export const CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS = @@ -236,6 +237,8 @@ export const CONF_LIVE_SHOW_IMAGE_DURING_LOAD = `${CONF_LIVE}.show_image_during_load` as const; export const CONF_LIVE_MICROPHONE_DISCONNECT_SECONDS = `${CONF_LIVE}.microphone.disconnect_seconds` as const; +export const CONF_LIVE_MICROPHONE_MUTE_AFTER_MICROPHONE_MUTE_SECONDS = + `${CONF_LIVE}.microphone.mute_after_microphone_mute_seconds` as const; export const CONF_LIVE_MICROPHONE_ALWAYS_CONNECTED = `${CONF_LIVE}.microphone.always_connected` as const; export const CONF_LIVE_ZOOMABLE = `${CONF_LIVE}.zoomable` as const; diff --git a/src/editor.ts b/src/editor.ts index 442afa1c..997820e5 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -1,3 +1,5 @@ +// TODO: menu in hover mode, hold down microphone, should be momentary, appears to stick on? + import { fireEvent, HomeAssistant, @@ -113,6 +115,7 @@ import { CONF_LIVE_LAZY_UNLOAD, CONF_LIVE_MICROPHONE_ALWAYS_CONNECTED, CONF_LIVE_MICROPHONE_DISCONNECT_SECONDS, + CONF_LIVE_MICROPHONE_MUTE_AFTER_MICROPHONE_MUTE_SECONDS, CONF_LIVE_PRELOAD, CONF_LIVE_SHOW_IMAGE_DURING_LOAD, CONF_LIVE_TRANSITION_EFFECT, @@ -519,18 +522,15 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor protected _mediaActionNegativeConditions: EditorSelectOption[] = [ { value: '', label: '' }, - { value: 'all', label: localize('config.common.media_action_conditions.all') }, { value: 'unselected', label: localize('config.common.media_action_conditions.unselected'), }, { value: 'hidden', label: localize('config.common.media_action_conditions.hidden') }, - { value: 'never', label: localize('config.common.media_action_conditions.never') }, ]; protected _mediaActionPositiveConditions: EditorSelectOption[] = [ { value: '', label: '' }, - { value: 'all', label: localize('config.common.media_action_conditions.all') }, { value: 'selected', label: localize('config.common.media_action_conditions.selected'), @@ -539,7 +539,22 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor value: 'visible', label: localize('config.common.media_action_conditions.visible'), }, - { value: 'never', label: localize('config.common.media_action_conditions.never') }, + ]; + + protected _mediaLiveUnmuteConditions: EditorSelectOption[] = [ + ...this._mediaActionPositiveConditions, + { + value: 'microphone', + label: localize('config.common.media_action_conditions.microphone_unmute'), + }, + ]; + + protected _mediaLiveMuteConditions: EditorSelectOption[] = [ + ...this._mediaActionNegativeConditions, + { + value: 'microphone', + label: localize('config.common.media_action_conditions.microphone_mute'), + }, ]; protected _layoutFits: EditorSelectOption[] = [ @@ -2011,22 +2026,37 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderOptionSelector( CONF_LIVE_LAZY_UNLOAD, this._mediaActionNegativeConditions, + { + multiple: true, + }, )} ${this._renderOptionSelector( CONF_LIVE_AUTO_PLAY, this._mediaActionPositiveConditions, + { + multiple: true, + }, )} ${this._renderOptionSelector( CONF_LIVE_AUTO_PAUSE, this._mediaActionNegativeConditions, + { + multiple: true, + }, )} ${this._renderOptionSelector( CONF_LIVE_AUTO_MUTE, - this._mediaActionNegativeConditions, + this._mediaLiveMuteConditions, + { + multiple: true, + }, )} ${this._renderOptionSelector( CONF_LIVE_AUTO_UNMUTE, - this._mediaActionPositiveConditions, + this._mediaLiveUnmuteConditions, + { + multiple: true, + }, )} ${this._renderOptionSelector( CONF_LIVE_TRANSITION_EFFECT, @@ -2153,6 +2183,9 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor CONF_LIVE_MICROPHONE_ALWAYS_CONNECTED, this._defaults.live.microphone.always_connected, )} + ${this._renderNumberInput( + CONF_LIVE_MICROPHONE_MUTE_AFTER_MICROPHONE_MUTE_SECONDS, + )} `, )} @@ -2182,18 +2215,30 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderOptionSelector( CONF_MEDIA_VIEWER_AUTO_PLAY, this._mediaActionPositiveConditions, + { + multiple: true, + }, )} ${this._renderOptionSelector( CONF_MEDIA_VIEWER_AUTO_PAUSE, this._mediaActionNegativeConditions, + { + multiple: true, + }, )} ${this._renderOptionSelector( CONF_MEDIA_VIEWER_AUTO_MUTE, this._mediaActionNegativeConditions, + { + multiple: true, + }, )} ${this._renderOptionSelector( CONF_MEDIA_VIEWER_AUTO_UNMUTE, this._mediaActionPositiveConditions, + { + multiple: true, + }, )} ${this._renderSwitch( CONF_MEDIA_VIEWER_DRAGGABLE, diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 94d05c5c..bb246156 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -182,6 +182,8 @@ "media_action_conditions": { "all": "All opportunities", "hidden": "On browser/tab hiding", + "microphone_mute": "On microphone mute", + "microphone_unmute": "On microphone unmute", "never": "Never", "selected": "On selection", "unselected": "On unselection", @@ -267,7 +269,8 @@ "always_connected": "Always keep the microphone connected", "disconnect_seconds": "Seconds after which to disconnect microphone (0=never)", "editor_label": "Microphone", - "enabled": "Microphone enabled" + "enabled": "Microphone enabled", + "mute_after_microphone_mute_seconds": "Seconds after microphone mute to mute inbound audio" }, "preload": "Preload live view in the background", "show_image_during_load": "Show still image while the live stream is loading", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 7cf37f87..570d1dc4 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -182,6 +182,8 @@ "media_action_conditions": { "all": "Tutte le opportunità", "hidden": "Sul browser/nascondere le schede", + "microphone_mute": "", + "microphone_unmute": "", "never": "Mai", "selected": "Sulla selezione", "unselected": "Sulla non selezione", @@ -267,7 +269,8 @@ "always_connected": "", "disconnect_seconds": "", "editor_label": "", - "enabled": "" + "enabled": "", + "mute_after_microphone_mute_seconds": "" }, "preload": "Precarica Live View in background", "show_image_during_load": "Mostra un'immagine fissa durante il caricamento del live streaming", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 73ed9a70..2909b41b 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -182,6 +182,8 @@ "media_action_conditions": { "all": "Todas as oportunidades", "hidden": "Ao ocultar o navegador/aba", + "microphone_mute": "", + "microphone_unmute": "", "never": "Nunca", "selected": "Ao selecionar", "unselected": "Ao desselecionar", @@ -267,7 +269,8 @@ "always_connected": "", "disconnect_seconds": "", "editor_label": "", - "enabled": "" + "enabled": "", + "mute_after_microphone_mute_seconds": "" }, "preload": "Pré-carregar a visualização ao vivo em segundo plano", "show_image_during_load": "Mostrar imagem estática enquanto a transmissão ao vivo está carregando", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 25140dd8..e224ccf0 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -182,6 +182,8 @@ "media_action_conditions": { "all": "Todas as oportunidades", "hidden": "Ao ocultar o navegador/aba", + "microphone_mute": "", + "microphone_unmute": "", "never": "Nunca", "selected": "Ao selecionar", "unselected": "Ao desselecionar", @@ -260,7 +262,8 @@ "always_connected": "", "disconnect_seconds": "", "editor_label": "", - "enabled": "" + "enabled": "", + "mute_after_microphone_mute_seconds": "" }, "preload": "Pré-carregar a visualização ao vivo em segundo plano", "show_image_during_load": "Mostar imagem durante o carregamento", diff --git a/src/utils/embla/plugins/auto-lazy-load/auto-lazy-load.ts b/src/utils/embla/plugins/auto-lazy-load/auto-lazy-load.ts index efd4f2f4..c35b825d 100644 --- a/src/utils/embla/plugins/auto-lazy-load/auto-lazy-load.ts +++ b/src/utils/embla/plugins/auto-lazy-load/auto-lazy-load.ts @@ -14,7 +14,7 @@ type OptionsType = CreateOptionsType<{ // Number of slides to lazyload left/right of selected (0 == only selected // slide). lazyLoadCount: number; - lazyUnloadCondition?: LazyUnloadCondition; + lazyUnloadConditions?: readonly LazyUnloadCondition[]; lazyLoadCallback?: (index: number, slide: HTMLElement) => void; lazyUnloadCallback?: (index: number, slide: HTMLElement) => void; @@ -55,8 +55,7 @@ export function AutoLazyLoad( } if ( options.lazyUnloadCallback && - options.lazyUnloadCondition && - ['all', 'unselected'].includes(options.lazyUnloadCondition) + options.lazyUnloadConditions?.includes('unselected') ) { unloadEvents.forEach((evt) => emblaApi.on(evt, lazyUnloadPreviousHandler)); } @@ -76,8 +75,7 @@ export function AutoLazyLoad( function visibilityHandler(): void { if ( document.visibilityState === 'hidden' && - options.lazyUnloadCondition && - ['all', 'hidden'].includes(options.lazyUnloadCondition) + options.lazyUnloadConditions?.includes('hidden') ) { lazyUnloadAllHandler(); } else if (document.visibilityState === 'visible' && options.lazyLoadCallback) { diff --git a/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts b/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts index cb47af69..e31b10db 100644 --- a/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts +++ b/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts @@ -2,6 +2,10 @@ import { EmblaCarouselType } from 'embla-carousel'; import { CreateOptionsType } from 'embla-carousel/components/Options.js'; import { OptionsHandlerType } from 'embla-carousel/components/OptionsHandler.js'; import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins.js'; +import { + MicrophoneManagerListenerChange, + ReadonlyMicrophoneManager, +} from '../../../../card-controller/microphone-manager.js'; import { AutoMuteCondition, AutoPauseCondition, @@ -9,6 +13,7 @@ import { AutoUnmuteCondition, } from '../../../../config/types.js'; import { FrigateCardMediaPlayer } from '../../../../types.js'; +import { Timer } from '../../../timer.js'; declare module 'embla-carousel/components/Plugins' { interface EmblaPluginsType { @@ -19,10 +24,13 @@ declare module 'embla-carousel/components/Plugins' { type OptionsType = CreateOptionsType<{ playerSelector?: string; - autoPlayCondition?: AutoPlayCondition; - autoUnmuteCondition?: AutoUnmuteCondition; - autoPauseCondition?: AutoPauseCondition; - autoMuteCondition?: AutoMuteCondition; + autoPlayConditions?: readonly AutoPlayCondition[]; + autoUnmuteConditions?: readonly AutoUnmuteCondition[]; + autoPauseConditions?: readonly AutoPauseCondition[]; + autoMuteConditions?: readonly AutoMuteCondition[]; + + microphoneManager?: ReadonlyMicrophoneManager; + microphoneMuteSeconds?: number; }>; export type AutoMediaActionsOptionsType = Partial; @@ -43,6 +51,7 @@ export function AutoMediaActions( let emblaApi: EmblaCarouselType; let slides: HTMLElement[]; let hadInitialIntersectionCall: boolean | null = false; + const microphoneMuteTimer = new Timer(); const intersectionObserver: IntersectionObserver = new IntersectionObserver( intersectionHandler, @@ -59,35 +68,23 @@ export function AutoMediaActions( slides = emblaApi.slideNodes(); - if ( - options.autoPlayCondition && - ['all', 'selected'].includes(options.autoPlayCondition) - ) { + if (options.autoPlayConditions?.includes('selected')) { // Auto play when the media loads not necessarily when the slide is // selected (to allow for lazyloading). emblaApi.containerNode().addEventListener('frigate-card:media:loaded', play); } - if ( - options.autoUnmuteCondition && - ['all', 'selected'].includes(options.autoUnmuteCondition) - ) { + if (options.autoUnmuteConditions?.includes('selected')) { // Auto unmute when the media loads not necessarily when the slide is // selected (to allow for lazyloading). emblaApi.containerNode().addEventListener('frigate-card:media:loaded', unmute); } - if ( - options.autoPauseCondition && - ['all', 'unselected'].includes(options.autoPauseCondition) - ) { + if (options.autoPauseConditions?.includes('unselected')) { emblaApi.on('select', pausePrevious); } - if ( - options.autoMuteCondition && - ['all', 'unselected'].includes(options.autoMuteCondition) - ) { + if (options.autoMuteConditions?.includes('unselected')) { emblaApi.on('select', mutePrevious); } @@ -96,34 +93,54 @@ export function AutoMediaActions( document.addEventListener('visibilitychange', visibilityHandler); intersectionObserver.observe(emblaApi.containerNode()); + + if ( + options.autoUnmuteConditions?.includes('microphone') || + options.autoMuteConditions?.includes('microphone') + ) { + // For some reason mergeOptions() appears to break mock objects passed in, + // so unittesting doesn't work when using options (vs userOptions where it + // does). + userOptions.microphoneManager?.addListener(microphoneChangeHandler); + + // Stop the microphone mute timer if the media changes. + emblaApi + .containerNode() + .addEventListener('frigate-card:media:loaded', stopMicrophoneTimer); + } + } + + function stopMicrophoneTimer(): void { + microphoneMuteTimer.stop(); + } + + function microphoneChangeHandler(change: MicrophoneManagerListenerChange): void { + if (change === 'unmuted' && options.autoUnmuteConditions?.includes('microphone')) { + unmute(); + } else if ( + change === 'muted' && + options.autoMuteConditions?.includes('microphone') + ) { + microphoneMuteTimer.start(options.microphoneMuteSeconds ?? 60, () => { + mute(); + }); + } } function destroy(): void { - if ( - options.autoPlayCondition && - ['all', 'selected'].includes(options.autoPlayCondition) - ) { + if (options.autoPlayConditions?.includes('selected')) { emblaApi.containerNode().removeEventListener('frigate-card:media:loaded', play); } - if ( - options.autoUnmuteCondition && - ['all', 'selected'].includes(options.autoUnmuteCondition) - ) { + if (options.autoUnmuteConditions?.includes('selected')) { emblaApi.containerNode().removeEventListener('frigate-card:media:loaded', unmute); } - if ( - options.autoPauseCondition && - ['all', 'unselected'].includes(options.autoPauseCondition) - ) { + if (options.autoPauseConditions?.includes('unselected')) { emblaApi.off('select', pausePrevious); } - if ( - options.autoMuteCondition && - ['all', 'unselected'].includes(options.autoMuteCondition) - ) { + if (options.autoMuteConditions?.includes('unselected')) { emblaApi.off('select', mutePrevious); } @@ -132,33 +149,31 @@ export function AutoMediaActions( document.removeEventListener('visibilitychange', visibilityHandler); intersectionObserver.disconnect(); + + if ( + options.autoUnmuteConditions?.includes('microphone') || + options.autoMuteConditions?.includes('microphone') + ) { + userOptions.microphoneManager?.removeListener(microphoneChangeHandler); + emblaApi + .containerNode() + .removeEventListener('frigate-card:media:loaded', stopMicrophoneTimer); + } } function actOnVisibilityChange(visible: boolean): void { if (visible) { - if ( - options.autoPlayCondition && - ['all', 'visible'].includes(options.autoPlayCondition) - ) { + if (options.autoPlayConditions?.includes('visible')) { play(); } - if ( - options.autoUnmuteCondition && - ['all', 'visible'].includes(options.autoUnmuteCondition) - ) { + if (options.autoUnmuteConditions?.includes('visible')) { unmute(); } } else { - if ( - options.autoPauseCondition && - ['all', 'hidden'].includes(options.autoPauseCondition) - ) { + if (options.autoPauseConditions?.includes('hidden')) { pauseAll(); } - if ( - options.autoMuteCondition && - ['all', 'hidden'].includes(options.autoMuteCondition) - ) { + if (options.autoMuteConditions?.includes('hidden')) { muteAll(); } } diff --git a/tests/card-controller/microphone-manager.test.ts b/tests/card-controller/microphone-manager.test.ts index fe8355e8..df9d6408 100644 --- a/tests/card-controller/microphone-manager.test.ts +++ b/tests/card-controller/microphone-manager.test.ts @@ -190,4 +190,35 @@ describe('MicrophoneManager', () => { expect(manager.isConnected()).toBeTruthy(); expect(api.getCardElementManager().update).toBeCalledTimes(1); }); + + it('should respect listeners', async () => { + const api = createCardAPI(); + const manager = new MicrophoneManager(api); + navigatorMock.mediaDevices.getUserMedia.mockReturnValue(createMockStream()); + + const listener = vi.fn(); + manager.addListener(listener); + + await manager.connect(); + expect(listener).not.toHaveBeenCalled(); + + await manager.mute(); + expect(listener).not.toHaveBeenCalled(); + + await manager.unmute(); + expect(listener).toHaveBeenCalledTimes(1); + expect(listener).toHaveBeenLastCalledWith('unmuted'); + + await manager.unmute(); + expect(listener).toHaveBeenCalledTimes(1); + + await manager.mute(); + expect(listener).toHaveBeenCalledTimes(2); + expect(listener).toHaveBeenLastCalledWith('muted'); + + manager.removeListener(listener); + + await manager.unmute(); + expect(listener).toHaveBeenCalledTimes(2); + }); }); diff --git a/tests/config-mgmt.test.ts b/tests/config-mgmt.test.ts index 834928de..bba0efc3 100644 --- a/tests/config-mgmt.test.ts +++ b/tests/config-mgmt.test.ts @@ -617,7 +617,7 @@ describe('should handle version specific upgrades', () => { }); }); - describe('v5.2.0', () => { + describe('v5.2.0 -> v6.0.0', () => { describe('should rename service_data to data', () => { it('positive case', () => { const config = { @@ -738,445 +738,487 @@ describe('should handle version specific upgrades', () => { }); }); }); - }); - describe('should move PTZ elements to live', () => { - it('case with 1 element', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - type: 'custom:frigate-card-ptz', - orientation: 'vertical', - style: { - right: '20px', - top: '20px', - color: 'white', - }, - actions_up: { - tap_action: { - action: 'call-service', - service: 'notify.persistent_notification', - service_data: { - message: 'Hello 1', - }, + describe('should move PTZ elements to live', () => { + it('case with 1 element', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', }, - }, - }, - ], - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - cameras: [{ camera_entity: 'camera.office' }], - live: { - controls: { - ptz: { actions_up: { tap_action: { action: 'call-service', - data: { + service: 'notify.persistent_notification', + service_data: { message: 'Hello 1', }, - service: 'notify.persistent_notification', - }, - }, - orientation: 'vertical', - style: { - color: 'white', - right: '20px', - top: '20px', - }, - }, - }, - }, - type: 'custom:frigate-card', - }); - }); - - it('case with >1 element', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - type: 'custom:frigate-card-ptz', - orientation: 'vertical', - style: { - right: '20px', - top: '20px', - color: 'white', - }, - actions_up: { - tap_action: { - action: 'call-service', - service: 'notify.persistent_notification', - service_data: { - message: 'Hello 1', }, }, }, - }, - { - type: 'service-button', - title: 'title', - service: 'service', - service_data: { - message: "It's a trick", - }, - }, - ], - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - service: 'service', - service_data: { - message: "It's a trick", - }, - title: 'title', - type: 'service-button', - }, - ], - live: { - controls: { - ptz: { - actions_up: { - tap_action: { - action: 'call-service', - data: { - message: 'Hello 1', - }, - service: 'notify.persistent_notification', - }, - }, - orientation: 'vertical', - style: { - color: 'white', - right: '20px', - top: '20px', - }, - }, - }, - }, - type: 'custom:frigate-card', - }); - }); - - it('case with custom conditional element with 2 PTZ but nothing else', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - type: 'custom:frigate-card-conditional', - conditions: { - fullscreen: true, - media_loaded: true, - }, - elements: [ - { - type: 'custom:frigate-card-ptz', - orientation: 'vertical', - style: { - right: '20px', - top: '20px', - color: 'white', - }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + cameras: [{ camera_entity: 'camera.office' }], + live: { + controls: { + ptz: { actions_up: { tap_action: { action: 'call-service', - service: 'notify.persistent_notification', - service_data: { + data: { message: 'Hello 1', }, + service: 'notify.persistent_notification', }, }, - }, - { - type: 'custom:frigate-card-ptz', orientation: 'vertical', style: { + color: 'white', right: '20px', top: '20px', - color: 'white', - }, - actions_up: { - tap_action: { - action: 'call-service', - service: 'notify.persistent_notification', - service_data: { - message: 'Hello 2', - }, - }, }, }, - ], + }, }, - ], - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - cameras: [{ camera_entity: 'camera.office' }], - live: { - controls: { - ptz: { + type: 'custom:frigate-card', + }); + }); + + it('case with >1 element', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, actions_up: { tap_action: { action: 'call-service', - data: { + service: 'notify.persistent_notification', + service_data: { message: 'Hello 1', }, - service: 'notify.persistent_notification', }, }, - orientation: 'vertical', - style: { - color: 'white', - right: '20px', - top: '20px', - }, }, - }, - }, - type: 'custom:frigate-card', - }); - }); - - it('case with custom conditional element with 1 PTZ and another element', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - type: 'custom:frigate-card-conditional', - conditions: { - fullscreen: true, - media_loaded: true, - }, - elements: [ - { - type: 'service-button', - title: 'title', - service: 'service', - service_data: { - message: "It's a trick", - }, + { + type: 'service-button', + title: 'title', + service: 'service', + service_data: { + message: "It's a trick", }, - { - type: 'custom:frigate-card-ptz', - orientation: 'vertical', - style: { - right: '20px', - top: '20px', - color: 'white', - }, + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + service: 'service', + service_data: { + message: "It's a trick", + }, + title: 'title', + type: 'service-button', + }, + ], + live: { + controls: { + ptz: { actions_up: { tap_action: { action: 'call-service', - service: 'notify.persistent_notification', - service_data: { + data: { message: 'Hello 1', }, + service: 'notify.persistent_notification', }, }, - }, - ], - }, - ], - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - cameras: [{ camera_entity: 'camera.office' }], - live: { - controls: { - ptz: { - actions_up: { - tap_action: { - action: 'call-service', - data: { - message: 'Hello 1', - }, - service: 'notify.persistent_notification', - }, - }, - orientation: 'vertical', - style: { - color: 'white', - right: '20px', - top: '20px', - }, - }, - }, - }, - elements: [ - { - type: 'custom:frigate-card-conditional', - conditions: { - fullscreen: true, - media_loaded: true, - }, - elements: [ - { - type: 'service-button', - title: 'title', - service: 'service', - service_data: { - message: "It's a trick", - }, - }, - ], - }, - ], - type: 'custom:frigate-card', - }); - }); - - it('case with stock conditional element with 1 PTZ', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - type: 'conditional', - conditions: [{ entity: 'light.office', state: 'on' }], - elements: [ - { - type: 'custom:frigate-card-ptz', orientation: 'vertical', style: { + color: 'white', right: '20px', top: '20px', - color: 'white', }, - actions_up: { - tap_action: { - action: 'call-service', - service: 'notify.persistent_notification', - service_data: { - message: 'Hello 1', + }, + }, + }, + type: 'custom:frigate-card', + }); + }); + + it('case with custom conditional element with 2 PTZ but nothing else', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + type: 'custom:frigate-card-conditional', + conditions: { + fullscreen: true, + media_loaded: true, + }, + elements: [ + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, + actions_up: { + tap_action: { + action: 'call-service', + service: 'notify.persistent_notification', + service_data: { + message: 'Hello 1', + }, }, }, }, - }, - ], - }, - ], - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - cameras: [{ camera_entity: 'camera.office' }], - live: { - controls: { - ptz: { - actions_up: { - tap_action: { - action: 'call-service', - data: { - message: 'Hello 1', + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, + actions_up: { + tap_action: { + action: 'call-service', + service: 'notify.persistent_notification', + service_data: { + message: 'Hello 2', + }, + }, }, - service: 'notify.persistent_notification', }, - }, - orientation: 'vertical', - style: { - color: 'white', - right: '20px', - top: '20px', + ], + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + cameras: [{ camera_entity: 'camera.office' }], + live: { + controls: { + ptz: { + actions_up: { + tap_action: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + orientation: 'vertical', + style: { + color: 'white', + right: '20px', + top: '20px', + }, }, }, }, - }, - type: 'custom:frigate-card', + type: 'custom:frigate-card', + }); + }); + + it('case with custom conditional element with 1 PTZ and another element', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + type: 'custom:frigate-card-conditional', + conditions: { + fullscreen: true, + media_loaded: true, + }, + elements: [ + { + type: 'service-button', + title: 'title', + service: 'service', + service_data: { + message: "It's a trick", + }, + }, + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, + actions_up: { + tap_action: { + action: 'call-service', + service: 'notify.persistent_notification', + service_data: { + message: 'Hello 1', + }, + }, + }, + }, + ], + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + cameras: [{ camera_entity: 'camera.office' }], + live: { + controls: { + ptz: { + actions_up: { + tap_action: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + orientation: 'vertical', + style: { + color: 'white', + right: '20px', + top: '20px', + }, + }, + }, + }, + elements: [ + { + type: 'custom:frigate-card-conditional', + conditions: { + fullscreen: true, + media_loaded: true, + }, + elements: [ + { + type: 'service-button', + title: 'title', + service: 'service', + service_data: { + message: "It's a trick", + }, + }, + ], + }, + ], + type: 'custom:frigate-card', + }); + }); + + it('case with stock conditional element with 1 PTZ', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + type: 'conditional', + conditions: [{ entity: 'light.office', state: 'on' }], + elements: [ + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, + actions_up: { + tap_action: { + action: 'call-service', + service: 'notify.persistent_notification', + service_data: { + message: 'Hello 1', + }, + }, + }, + }, + ], + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + cameras: [{ camera_entity: 'camera.office' }], + live: { + controls: { + ptz: { + actions_up: { + tap_action: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + orientation: 'vertical', + style: { + color: 'white', + right: '20px', + top: '20px', + }, + }, + }, + }, + type: 'custom:frigate-card', + }); + }); + + it('case when live.controls.ptz already exists', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + live: { + controls: { + ptz: { + actions_up: { + tap_action: { + action: 'call-service', + data: { + message: 'Original', + }, + service: 'notify.persistent_notification', + }, + }, + orientation: 'vertical', + style: { + color: 'white', + right: '20px', + top: '20px', + }, + }, + }, + }, + elements: [ + { + type: 'custom:frigate-card-ptz', + orientation: 'vertical', + style: { + right: '20px', + top: '20px', + color: 'white', + }, + actions_up: { + tap_action: { + action: 'call-service', + service: 'notify.persistent_notification', + service_data: { + message: 'Replacement that should be ignored', + }, + }, + }, + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + cameras: [{ camera_entity: 'camera.office' }], + live: { + controls: { + ptz: { + actions_up: { + tap_action: { + action: 'call-service', + data: { + message: 'Original', + }, + service: 'notify.persistent_notification', + }, + }, + orientation: 'vertical', + style: { + color: 'white', + right: '20px', + top: '20px', + }, + }, + }, + }, + type: 'custom:frigate-card', + }); }); }); - it('case when live.controls.ptz already exists', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - live: { - controls: { - ptz: { - actions_up: { - tap_action: { - action: 'call-service', - data: { - message: 'Original', - }, - service: 'notify.persistent_notification', - }, - }, - orientation: 'vertical', - style: { - color: 'white', - right: '20px', - top: '20px', + describe('should move and transform untrigger_reset', () => { + it('when true', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + scan: { + untrigger_reset: true, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + scan: { + actions: { + untrigger: 'default', }, }, }, - }, - elements: [ - { - type: 'custom:frigate-card-ptz', - orientation: 'vertical', - style: { - right: '20px', - top: '20px', - color: 'white', - }, - actions_up: { - tap_action: { - action: 'call-service', - service: 'notify.persistent_notification', - service_data: { - message: 'Replacement that should be ignored', - }, - }, + }); + }); + + it('when false', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + scan: { + untrigger_reset: false, }, }, - ], - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - cameras: [{ camera_entity: 'camera.office' }], - live: { - controls: { - ptz: { - actions_up: { - tap_action: { - action: 'call-service', - data: { - message: 'Original', - }, - service: 'notify.persistent_notification', - }, - }, - orientation: 'vertical', - style: { - color: 'white', - right: '20px', - top: '20px', - }, - }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + scan: {}, }, - }, - type: 'custom:frigate-card', + }); }); }); - }); - describe('should move and transform untrigger_reset', () => { - it('when true', () => { + it('should move view.timeout_seconds', () => { const config = { type: 'custom:frigate-card', cameras: [{ camera_entity: 'camera.office' }], view: { - scan: { - untrigger_reset: true, - }, + timeout_seconds: 200, }, }; expect(upgradeConfig(config)).toBeTruthy(); @@ -1184,51 +1226,369 @@ describe('should handle version specific upgrades', () => { type: 'custom:frigate-card', cameras: [{ camera_entity: 'camera.office' }], view: { - scan: { - actions: { - untrigger: 'default', - }, - }, + interaction_seconds: 200, }, }); }); - it('when false', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - view: { - scan: { - untrigger_reset: false, - }, - }, - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - view: { - scan: {}, - }, - }); - }); - }); + describe('should handle all and never action conditions', () => { + describe('live', () => { + describe('lazy_unload', () => { + it('all', () => { + const config = { + live: { + lazy_unload: 'all', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: { + lazy_unload: ['unselected', 'hidden'], + }, + }); + }); + it('never', () => { + const config = { + live: { + lazy_unload: 'never', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: {}, + }); + }); + it('other value', () => { + const config = { + live: { + lazy_unload: 'unselected', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: { + lazy_unload: ['unselected'], + }, + }); + }); + }); - it('should move view.timeout_seconds', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - view: { - timeout_seconds: 200, - }, - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - view: { - interaction_seconds: 200, - }, + describe('auto_play', () => { + it('all', () => { + const config = { + live: { + auto_play: 'all', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: {}, + }); + }); + it('never', () => { + const config = { + live: { + auto_play: 'never', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: { + auto_play: [], + }, + }); + }); + it('other value', () => { + const config = { + live: { + auto_play: 'selected', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: { + auto_play: ['selected'], + }, + }); + }); + }); + describe('auto_pause', () => { + it('all', () => { + const config = { + live: { + auto_pause: 'all', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: { + auto_pause: ['unselected', 'hidden'], + }, + }); + }); + it('never', () => { + const config = { + live: { + auto_pause: 'never', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: {}, + }); + }); + it('other value', () => { + const config = { + live: { + auto_pause: 'unselected', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: { + auto_pause: ['unselected'], + }, + }); + }); + }); + describe('auto_mute', () => { + it('all', () => { + const config = { + live: { + auto_mute: 'all', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: {}, + }); + }); + it('never', () => { + const config = { + live: { + auto_mute: 'never', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: { + auto_mute: [], + }, + }); + }); + it('other value', () => { + const config = { + live: { + auto_mute: 'unselected', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: { + auto_mute: ['unselected'], + }, + }); + }); + }); + describe('auto_unmute', () => { + it('all', () => { + const config = { + live: { + auto_unmute: 'all', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: { + auto_unmute: ['selected', 'visible', 'microphone'], + }, + }); + }); + it('never', () => { + const config = { + live: { + auto_unmute: 'never', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: {}, + }); + }); + it('other value', () => { + const config = { + live: { + auto_unmute: 'selected', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: { + auto_unmute: ['selected'], + }, + }); + }); + }); + }); + + describe('media_viewer', () => { + describe('auto_play', () => { + it('all', () => { + const config = { + media_viewer: { + auto_play: 'all', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: {}, + }); + }); + it('never', () => { + const config = { + media_viewer: { + auto_play: 'never', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: { + auto_play: [], + }, + }); + }); + it('other value', () => { + const config = { + media_viewer: { + auto_play: 'selected', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: { + auto_play: ['selected'], + }, + }); + }); + }); + describe('auto_pause', () => { + it('all', () => { + const config = { + media_viewer: { + auto_pause: 'all', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: {}, + }); + }); + it('never', () => { + const config = { + media_viewer: { + auto_pause: 'never', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: { + auto_pause: [], + }, + }); + }); + it('other value', () => { + const config = { + media_viewer: { + auto_pause: 'unselected', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: { + auto_pause: ['unselected'], + }, + }); + }); + }); + describe('auto_mute', () => { + it('all', () => { + const config = { + media_viewer: { + auto_mute: 'all', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: {}, + }); + }); + it('never', () => { + const config = { + media_viewer: { + auto_mute: 'never', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: { + auto_mute: [], + }, + }); + }); + it('other value', () => { + const config = { + media_viewer: { + auto_mute: 'unselected', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: { + auto_mute: ['unselected'], + }, + }); + }); + }); + describe('auto_unmute', () => { + it('all', () => { + const config = { + media_viewer: { + auto_unmute: 'all', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: { + auto_unmute: ['selected', 'visible'], + }, + }); + }); + it('never', () => { + const config = { + media_viewer: { + auto_unmute: 'never', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: {}, + }); + }); + it('other value', () => { + const config = { + media_viewer: { + auto_unmute: 'selected', + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: { + auto_unmute: ['selected'], + }, + }); + }); + }); + }); }); }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 95de1a00..aa41d7b8 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -58,10 +58,10 @@ describe('config defaults', () => { zoomable: true, }, live: { - auto_mute: 'all', - auto_pause: 'never', - auto_play: 'all', - auto_unmute: 'never', + auto_mute: ['unselected', 'hidden', 'microphone'], + auto_pause: [], + auto_play: ['selected', 'visible'], + auto_unmute: ['microphone'], controls: { builtin: true, next_previous: { @@ -96,10 +96,11 @@ describe('config defaults', () => { }, draggable: true, lazy_load: true, - lazy_unload: 'never', + lazy_unload: [], microphone: { always_connected: false, disconnect_seconds: 60, + mute_after_microphone_mute_seconds: 60, }, preload: false, show_image_during_load: true, @@ -122,10 +123,10 @@ describe('config defaults', () => { }, }, media_viewer: { - auto_mute: 'all', - auto_pause: 'all', - auto_play: 'all', - auto_unmute: 'never', + auto_mute: ['unselected', 'hidden'], + auto_pause: ['unselected', 'hidden'], + auto_play: ['selected', 'visible'], + auto_unmute: [], controls: { builtin: true, next_previous: { @@ -473,3 +474,14 @@ it('should strip trailing slashes from go2rtc url', () => { expect(config).toBeTruthy(); expect(config.cameras[0].go2rtc.url).toBe('https://my-custom-go2rtc'); }); + +it('media viewer should not support microphone based conditions', () => { + expect(() => + createConfig({ + cameras: [], + media_viewer: { + auto_unmute: 'microphone' as const, + }, + }), + ).toThrowError(); +}); diff --git a/tests/utils/embla/plugins/auto-lazy-load/auto-lazy-load.test.ts b/tests/utils/embla/plugins/auto-lazy-load/auto-lazy-load.test.ts index d2ec3916..3282dc57 100644 --- a/tests/utils/embla/plugins/auto-lazy-load/auto-lazy-load.test.ts +++ b/tests/utils/embla/plugins/auto-lazy-load/auto-lazy-load.test.ts @@ -1,4 +1,5 @@ import { describe, expect, it, vi } from 'vitest'; +import { MEDIA_ACTION_NEGATIVE_CONDITIONS } from '../../../../../src/config/types'; import { AutoLazyLoad } from '../../../../../src/utils/embla/plugins/auto-lazy-load/auto-lazy-load'; import { callEmblaHandler, @@ -91,7 +92,7 @@ describe('AutoLazyLoad', () => { lazyLoadCallback: vi.fn(), lazyLoadCount: 3, lazyUnloadCallback: lazyUnloadCallback, - lazyUnloadCondition: 'all', + lazyUnloadConditions: MEDIA_ACTION_NEGATIVE_CONDITIONS, }); const children = createTestSlideNodes(); @@ -143,7 +144,7 @@ describe('AutoLazyLoad', () => { const plugin = AutoLazyLoad({ lazyLoadCallback: vi.fn(), lazyUnloadCallback: lazyUnloadCallback, - lazyUnloadCondition: 'all', + lazyUnloadConditions: MEDIA_ACTION_NEGATIVE_CONDITIONS, }); const children = createTestSlideNodes(); @@ -172,7 +173,7 @@ describe('AutoLazyLoad', () => { const lazyLoadCallback = vi.fn(); const plugin = AutoLazyLoad({ lazyLoadCallback: lazyLoadCallback, - lazyUnloadCondition: 'all', + lazyUnloadConditions: MEDIA_ACTION_NEGATIVE_CONDITIONS, // No lazy unload callback. }); const children = createTestSlideNodes(); @@ -200,7 +201,7 @@ describe('AutoLazyLoad', () => { vi.spyOn(global.document, 'addEventListener'); const plugin = AutoLazyLoad({ - lazyUnloadCondition: 'all', + lazyUnloadConditions: MEDIA_ACTION_NEGATIVE_CONDITIONS, // No callbacks provided. }); diff --git a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts index 9e8b7092..d941d2c4 100644 --- a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts +++ b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts @@ -1,4 +1,16 @@ -import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import add from 'date-fns/add'; +import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { + MicrophoneManagerListenerChange, + ReadonlyMicrophoneManager, +} from '../../../../../src/card-controller/microphone-manager'; +import { + MEDIA_ACTION_NEGATIVE_CONDITIONS, + MEDIA_ACTION_POSITIVE_CONDITIONS, + MEDIA_MUTE_CONDITIONS, + MEDIA_UNMUTE_CONDITIONS, +} from '../../../../../src/config/types'; import { FrigateCardMediaPlayer } from '../../../../../src/types'; import { AutoMediaActions, @@ -50,18 +62,33 @@ const createPlayerSlideNodes = (n = 10): HTMLElement[] => { const createPlugin = (options?: AutoMediaActionsOptionsType): AutoMediaActionsType => { return AutoMediaActions({ playerSelector: 'video', - autoPlayCondition: 'all', - autoUnmuteCondition: 'all', - autoPauseCondition: 'all', - autoMuteCondition: 'all', + autoPlayConditions: MEDIA_ACTION_POSITIVE_CONDITIONS, + autoUnmuteConditions: MEDIA_UNMUTE_CONDITIONS, + autoPauseConditions: MEDIA_ACTION_NEGATIVE_CONDITIONS, + autoMuteConditions: MEDIA_MUTE_CONDITIONS, + microphoneManager: mock(), ...options, }); }; +export const callMicrophoneListener = ( + microphoneManager: ReadonlyMicrophoneManager, + action: MicrophoneManagerListenerChange, + n = 0, +): void => { + const mock = vi.mocked(microphoneManager.addListener).mock; + mock.calls[n][0](action); +}; + // @vitest-environment jsdom describe('AutoMediaActions', () => { beforeAll(() => { vi.stubGlobal('IntersectionObserver', IntersectionObserverMock); + vi.useFakeTimers(); + }); + + afterAll(() => { + vi.useRealTimers(); }); beforeEach(() => { @@ -74,8 +101,14 @@ describe('AutoMediaActions', () => { }); it('should init without any conditions', () => { - const plugin = AutoMediaActions(); - + const microphoneManager = mock(); + const plugin = createPlugin({ + autoPlayConditions: [], + autoUnmuteConditions: [], + autoPauseConditions: [], + autoMuteConditions: [], + microphoneManager: microphoneManager, + }); const parent = createParent(); const addEventListener = vi.fn(); parent.addEventListener = addEventListener; @@ -86,6 +119,7 @@ describe('AutoMediaActions', () => { expect(emblaApi.on).toBeCalledWith('destroy', expect.anything()); expect(emblaApi.on).not.toBeCalledWith('select', expect.anything()); expect(addEventListener).not.toBeCalled(); + expect(microphoneManager.addListener).not.toBeCalled(); }); it('should destroy', () => { @@ -105,7 +139,14 @@ describe('AutoMediaActions', () => { }); it('should destroy without any conditions', () => { - const plugin = AutoMediaActions(); + const microphoneManager = mock(); + const plugin = createPlugin({ + autoPlayConditions: [], + autoUnmuteConditions: [], + autoPauseConditions: [], + autoMuteConditions: [], + microphoneManager: microphoneManager, + }); const parent = createParent(); const removeEventListener = vi.fn(); parent.removeEventListener = removeEventListener; @@ -118,6 +159,7 @@ describe('AutoMediaActions', () => { expect(emblaApi.off).toBeCalledWith('destroy', expect.anything()); expect(emblaApi.off).not.toBeCalledWith('select', expect.anything()); expect(removeEventListener).not.toBeCalled(); + expect(microphoneManager.removeListener).not.toBeCalled(); }); it('should mute and pause on destroy', () => { @@ -301,4 +343,113 @@ describe('AutoMediaActions', () => { expect(getPlayer(child, 'video')?.mute).toBeCalled(); } }); + + describe('should handle microphone triggers', () => { + it('should unmute on microphone unmute', () => { + const microphoneManager = mock(); + const plugin = createPlugin({ microphoneManager: microphoneManager }); + const children = createPlayerSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + selectedScrollSnap: 5, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + callMicrophoneListener(microphoneManager, 'unmuted'); + + expect(getPlayer(children[5], 'video')?.unmute).toBeCalled(); + }); + + it('should not unmute on microphone unmute when not configured', () => { + const microphoneManager = mock(); + const plugin = createPlugin({ + microphoneManager: microphoneManager, + autoUnmuteConditions: [], + }); + const children = createPlayerSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + selectedScrollSnap: 5, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + callMicrophoneListener(microphoneManager, 'unmuted'); + + expect(getPlayer(children[5], 'video')?.unmute).not.toBeCalled(); + }); + + it('should mute on microphone mute after default delay', () => { + const start = new Date('2024-01-28T14:42'); + + const microphoneManager = mock(); + const plugin = createPlugin({ microphoneManager: microphoneManager }); + const children = createPlayerSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + selectedScrollSnap: 5, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + vi.setSystemTime(start); + callMicrophoneListener(microphoneManager, 'muted'); + + expect(getPlayer(children[5], 'video')?.mute).not.toBeCalled(); + vi.setSystemTime(add(start, { seconds: 60 })); + vi.runOnlyPendingTimers(); + expect(getPlayer(children[5], 'video')?.mute).toBeCalled(); + }); + + it('should mute on microphone mute after configured delay', () => { + const start = new Date('2024-01-28T14:42'); + + const microphoneManager = mock(); + const plugin = createPlugin({ + microphoneManager: microphoneManager, + microphoneMuteSeconds: 30, + }); + const children = createPlayerSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + selectedScrollSnap: 5, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + vi.setSystemTime(start); + callMicrophoneListener(microphoneManager, 'muted'); + + expect(getPlayer(children[5], 'video')?.mute).not.toBeCalled(); + vi.setSystemTime(add(start, { seconds: 30 })); + vi.runOnlyPendingTimers(); + expect(getPlayer(children[5], 'video')?.mute).toBeCalled(); + }); + + it('should not mute on microphone mute after delay when not configured', () => { + const start = new Date('2024-01-28T14:42'); + + const microphoneManager = mock(); + const plugin = createPlugin({ + microphoneManager: microphoneManager, + autoMuteConditions: [], + }); + const children = createPlayerSlideNodes(); + const emblaApi = createEmblaApiInstance({ + slideNodes: children, + selectedScrollSnap: 5, + }); + + plugin.init(emblaApi, createTestEmblaOptionHandler()); + + vi.setSystemTime(start); + callMicrophoneListener(microphoneManager, 'muted'); + + expect(getPlayer(children[5], 'video')?.mute).not.toBeCalled(); + vi.setSystemTime(add(start, { seconds: 60 })); + vi.runOnlyPendingTimers(); + expect(getPlayer(children[5], 'video')?.mute).not.toBeCalled(); + }); + }); }); diff --git a/vite.config.ts b/vite.config.ts index c788fc81..5f1aa02a 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,10 +10,10 @@ export default defineConfig({ // Thresholds will automatically be updated as coverage improves to avoid // back-sliding. thresholdAutoUpdate: true, - statements: 71.95, - branches: 60.78, - functions: 73.04, - lines: 71.84, + statements: 72.2, + branches: 61.18, + functions: 73.47, + lines: 72.09, }, }, }); From dd01c0089ed67354069861146b8650f50eec2ef6 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 28 Jan 2024 20:53:04 -0800 Subject: [PATCH 079/189] Minor fixes. --- src/editor.ts | 2 -- .../embla/plugins/auto-media-actions/auto-media-actions.test.ts | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/editor.ts b/src/editor.ts index 997820e5..d0db698f 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -1,5 +1,3 @@ -// TODO: menu in hover mode, hold down microphone, should be momentary, appears to stick on? - import { fireEvent, HomeAssistant, diff --git a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts index d941d2c4..8ebb42f7 100644 --- a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts +++ b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts @@ -71,7 +71,7 @@ const createPlugin = (options?: AutoMediaActionsOptionsType): AutoMediaActionsTy }); }; -export const callMicrophoneListener = ( +const callMicrophoneListener = ( microphoneManager: ReadonlyMicrophoneManager, action: MicrophoneManagerListenerChange, n = 0, From 7ddafa086fa39e063f55fb1ca3d5acff8bc8b2d3 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 28 Jan 2024 21:41:04 -0800 Subject: [PATCH 080/189] Fix issue with menu closing too early on microphone unmute. --- src/components/menu.ts | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/components/menu.ts b/src/components/menu.ts index bc19712b..59e729c1 100644 --- a/src/components/menu.ts +++ b/src/components/menu.ts @@ -180,7 +180,23 @@ export class FrigateCardMenu extends LitElement { if (menuToggle) { this.expanded = !this.expanded; } else if (tookAction) { - this.expanded = false; + // Don't close the menu if there is another action to come. + const holdAction = getActionConfigGivenAction('hold', config); + const doubleTapAction = getActionConfigGivenAction('double_tap', config); + const tapAction = getActionConfigGivenAction('tap', config); + const endTapAction = getActionConfigGivenAction('end_tap', config); + + if ( + interaction === 'end_tap' || + (interaction === 'start_tap' && + !holdAction && + !doubleTapAction && + !tapAction && + !endTapAction) || + (interaction !== 'end_tap' && !endTapAction) + ) { + this.expanded = false; + } } } } @@ -222,11 +238,6 @@ export class FrigateCardMenu extends LitElement { } } - /** - * Render a button. - * @param button The button configuration to render. - * @returns A rendered template or void. - */ protected _renderButton(button: MenuItem): TemplateResult | void { if (button.type === 'custom:frigate-card-menu-submenu') { return html` `; } - /** - * Render the menu. - * @returns A rendered template or void. - */ protected render(): TemplateResult | void { if (!this._menuConfig) { return; @@ -336,9 +343,6 @@ export class FrigateCardMenu extends LitElement { `; } - /** - * Get styles. - */ static get styles(): CSSResultGroup { return unsafeCSS(menuStyle); } From 8a6640a51226e661b1dc14a92039d2b3c7e08216 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Fri, 2 Feb 2024 18:12:03 -0800 Subject: [PATCH 081/189] Refactor menu code and add tests. --- src/card.ts | 2 +- src/components-lib/menu-button-controller.ts | 519 +++++ src/components-lib/menu-controller.ts | 680 ++----- src/components/menu.ts | 335 +-- src/config/types.ts | 4 +- src/utils/action.ts | 10 +- .../menu-button-controller.test.ts | 1351 +++++++++++++ tests/components-lib/menu-controller.test.ts | 1790 +++++------------ vite.config.ts | 8 +- 9 files changed, 2596 insertions(+), 2103 deletions(-) create mode 100644 src/components-lib/menu-button-controller.ts create mode 100644 tests/components-lib/menu-button-controller.test.ts diff --git a/src/card.ts b/src/card.ts index 7fb158aa..57633f66 100644 --- a/src/card.ts +++ b/src/card.ts @@ -10,7 +10,7 @@ import pkg from '../package.json'; import { actionHandler } from './action-handler-directive.js'; import { ConditionEvaluateRequestEvent } from './card-controller/conditions-manager.js'; import { CardController } from './card-controller/controller'; -import { MenuButtonController } from './components-lib/menu-controller'; +import { MenuButtonController } from './components-lib/menu-button-controller'; import './components/elements.js'; import { FrigateCardElements } from './components/elements.js'; import './components/menu.js'; diff --git a/src/components-lib/menu-button-controller.ts b/src/components-lib/menu-button-controller.ts new file mode 100644 index 00000000..56639fb6 --- /dev/null +++ b/src/components-lib/menu-button-controller.ts @@ -0,0 +1,519 @@ +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { StyleInfo } from 'lit/directives/style-map'; +import { CameraManager } from '../camera-manager/manager'; +import { MediaPlayerManager } from '../card-controller/media-player-manager'; +import { MicrophoneManager } from '../card-controller/microphone-manager'; +import { + FrigateCardConfig, + FrigateCardCustomAction, + FRIGATE_CARD_VIEWS_USER_SPECIFIED, + MenuItem, +} from '../config/types'; +import { FRIGATE_BUTTON_MENU_ICON } from '../const'; +import { localize } from '../localize/localize.js'; +import { MediaLoadedInfo } from '../types'; +import { + createFrigateCardCameraAction, + createFrigateCardDisplayModeAction, + createFrigateCardMediaPlayerAction, + createFrigateCardShowPTZAction, + createFrigateCardSimpleAction, +} from '../utils/action'; +import { getEntityIcon, getEntityTitle } from '../utils/ha'; +import { hasUsablePTZ } from '../utils/ptz'; +import { hasSubstream } from '../utils/substream'; +import { View } from '../view/view'; + +export interface MenuButtonControllerOptions { + currentMediaLoadedInfo?: MediaLoadedInfo | null; + showCameraUIButton?: boolean; + inFullscreenMode?: boolean; + inExpandedMode?: boolean; + microphoneManager?: MicrophoneManager | null; + mediaPlayerController?: MediaPlayerManager | null; +} + +export class MenuButtonController { + // Array of dynamic menu buttons to be added to menu. + protected _dynamicMenuButtons: MenuItem[] = []; + + public addDynamicMenuButton(button: MenuItem): void { + if (!this._dynamicMenuButtons.includes(button)) { + this._dynamicMenuButtons.push(button); + } + } + + public removeDynamicMenuButton(button: MenuItem): void { + this._dynamicMenuButtons = this._dynamicMenuButtons.filter( + (existingButton) => existingButton != button, + ); + } + + /** + * Get the menu buttons to display. + * @returns An array of menu buttons. + */ + public calculateButtons( + hass: HomeAssistant, + config: FrigateCardConfig, + cameraManager: CameraManager, + view: View, + options?: MenuButtonControllerOptions, + ): MenuItem[] { + const visibleCameraIDs = cameraManager.getStore().getVisibleCameraIDs(); + const selectedCameraID = view.camera; + const selectedCameraConfig = cameraManager + .getStore() + .getCameraConfig(selectedCameraID); + const allSelectedCameraIDs = cameraManager + .getStore() + .getAllDependentCameras(selectedCameraID); + const selectedMedia = view.queryResults?.getSelectedResult(); + + const selectedCameraCapabilities = + cameraManager.getCameraCapabilities(selectedCameraID); + const aggregateCapabilities = + cameraManager.getAggregateCameraCapabilities(allSelectedCameraIDs); + const mediaCapabilities = selectedMedia + ? cameraManager?.getMediaCapabilities(selectedMedia) + : null; + + const buttons: MenuItem[] = []; + buttons.push({ + // Use a magic icon value that the menu will use to render the custom + // Frigate icon. + icon: FRIGATE_BUTTON_MENU_ICON, + ...config.menu.buttons.frigate, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.frigate'), + tap_action: + config.menu?.style === 'hidden' + ? (createFrigateCardSimpleAction('menu_toggle') as FrigateCardCustomAction) + : (createFrigateCardSimpleAction('default') as FrigateCardCustomAction), + hold_action: createFrigateCardSimpleAction( + 'diagnostics', + ) as FrigateCardCustomAction, + }); + + if (visibleCameraIDs.size) { + const menuItems = Array.from( + cameraManager.getStore().getCameraConfigEntries(visibleCameraIDs), + ([cameraID, config]) => { + const action = createFrigateCardCameraAction('camera_select', cameraID); + const metadata = cameraManager.getCameraMetadata(cameraID); + + return { + enabled: true, + icon: metadata?.icon, + entity: config.camera_entity, + state_color: true, + title: metadata?.title, + selected: selectedCameraID === cameraID, + ...(action && { tap_action: action }), + }; + }, + ); + + buttons.push({ + icon: 'mdi:video-switch', + ...config.menu.buttons.cameras, + type: 'custom:frigate-card-menu-submenu', + title: localize('config.menu.buttons.cameras'), + items: menuItems, + }); + } + + if (selectedCameraID && allSelectedCameraIDs && view.is('live')) { + const dependencies = [...allSelectedCameraIDs]; + const override = view.context?.live?.overrides?.get(selectedCameraID); + + if (dependencies.length === 2) { + // If there are only two dependencies (the main camera, and 1 other) + // then use a button not a menu to toggle. + buttons.push({ + icon: 'mdi:video-input-component', + style: + override && override !== selectedCameraID ? this._getEmphasizedStyle() : {}, + title: localize('config.menu.buttons.substreams'), + ...config.menu.buttons.substreams, + type: 'custom:frigate-card-menu-icon', + tap_action: createFrigateCardSimpleAction( + hasSubstream(view) ? 'live_substream_off' : 'live_substream_on', + ) as FrigateCardCustomAction, + }); + } else if (dependencies.length > 2) { + const menuItems = Array.from(dependencies, (cameraID) => { + const action = createFrigateCardCameraAction( + 'live_substream_select', + cameraID, + ); + const metadata = cameraManager.getCameraMetadata(cameraID) ?? undefined; + const cameraConfig = cameraManager.getStore().getCameraConfig(cameraID); + return { + enabled: true, + icon: metadata?.icon, + entity: cameraConfig?.camera_entity, + state_color: true, + title: metadata?.title, + selected: + (view.context?.live?.overrides?.get(selectedCameraID) ?? + selectedCameraID) === cameraID, + ...(action && { tap_action: action }), + }; + }); + + buttons.push({ + icon: 'mdi:video-input-component', + title: localize('config.menu.buttons.substreams'), + style: + override && override !== selectedCameraID ? this._getEmphasizedStyle() : {}, + ...config.menu.buttons.substreams, + type: 'custom:frigate-card-menu-submenu', + items: menuItems, + }); + } + } + + buttons.push({ + icon: 'mdi:cctv', + ...config.menu.buttons.live, + type: 'custom:frigate-card-menu-icon', + title: localize('config.view.views.live'), + style: view.is('live') ? this._getEmphasizedStyle() : {}, + tap_action: createFrigateCardSimpleAction('live') as FrigateCardCustomAction, + }); + + if (aggregateCapabilities?.supportsClips) { + buttons.push({ + icon: 'mdi:filmstrip', + ...config.menu.buttons.clips, + type: 'custom:frigate-card-menu-icon', + title: localize('config.view.views.clips'), + style: view?.is('clips') ? this._getEmphasizedStyle() : {}, + tap_action: createFrigateCardSimpleAction('clips') as FrigateCardCustomAction, + hold_action: createFrigateCardSimpleAction('clip') as FrigateCardCustomAction, + }); + } + + if (aggregateCapabilities?.supportsSnapshots) { + buttons.push({ + icon: 'mdi:camera', + ...config.menu.buttons.snapshots, + type: 'custom:frigate-card-menu-icon', + title: localize('config.view.views.snapshots'), + style: view?.is('snapshots') ? this._getEmphasizedStyle() : {}, + tap_action: createFrigateCardSimpleAction( + 'snapshots', + ) as FrigateCardCustomAction, + hold_action: createFrigateCardSimpleAction( + 'snapshot', + ) as FrigateCardCustomAction, + }); + } + + if (aggregateCapabilities?.supportsRecordings) { + buttons.push({ + icon: 'mdi:album', + ...config.menu.buttons.recordings, + type: 'custom:frigate-card-menu-icon', + title: localize('config.view.views.recordings'), + style: view.is('recordings') ? this._getEmphasizedStyle() : {}, + tap_action: createFrigateCardSimpleAction( + 'recordings', + ) as FrigateCardCustomAction, + hold_action: createFrigateCardSimpleAction( + 'recording', + ) as FrigateCardCustomAction, + }); + } + + buttons.push({ + icon: 'mdi:image', + ...config.menu.buttons.image, + type: 'custom:frigate-card-menu-icon', + title: localize('config.view.views.image'), + style: view?.is('image') ? this._getEmphasizedStyle() : {}, + tap_action: createFrigateCardSimpleAction('image') as FrigateCardCustomAction, + }); + + // Don't show the timeline button unless there's at least one non-birdseye + // camera with a Frigate camera name. + if (aggregateCapabilities?.supportsTimeline) { + buttons.push({ + icon: 'mdi:chart-gantt', + ...config.menu.buttons.timeline, + type: 'custom:frigate-card-menu-icon', + title: localize('config.view.views.timeline'), + style: view.is('timeline') ? this._getEmphasizedStyle() : {}, + tap_action: createFrigateCardSimpleAction('timeline') as FrigateCardCustomAction, + }); + } + + if (mediaCapabilities?.canDownload && !this._isBeingCasted()) { + buttons.push({ + icon: 'mdi:download', + ...config.menu.buttons.download, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.download'), + tap_action: createFrigateCardSimpleAction('download') as FrigateCardCustomAction, + }); + } + + if (options?.showCameraUIButton) { + buttons.push({ + icon: 'mdi:web', + ...config.menu.buttons.camera_ui, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.camera_ui'), + tap_action: createFrigateCardSimpleAction( + 'camera_ui', + ) as FrigateCardCustomAction, + }); + } + + if ( + options?.microphoneManager && + options?.currentMediaLoadedInfo?.capabilities?.supports2WayAudio + ) { + const forbidden = options.microphoneManager.isForbidden(); + const muted = options.microphoneManager.isMuted(); + const buttonType = config.menu.buttons.microphone.type; + buttons.push({ + icon: forbidden + ? 'mdi:microphone-message-off' + : muted + ? 'mdi:microphone-off' + : 'mdi:microphone', + ...config.menu.buttons.microphone, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.microphone'), + style: forbidden || muted ? {} : this._getEmphasizedStyle(true), + ...(!forbidden && + buttonType === 'momentary' && { + start_tap_action: createFrigateCardSimpleAction( + 'microphone_unmute', + ) as FrigateCardCustomAction, + end_tap_action: createFrigateCardSimpleAction( + 'microphone_mute', + ) as FrigateCardCustomAction, + }), + ...(!forbidden && + buttonType === 'toggle' && { + tap_action: createFrigateCardSimpleAction( + options.microphoneManager.isMuted() + ? 'microphone_unmute' + : 'microphone_mute', + ) as FrigateCardCustomAction, + }), + }); + } + + if (!this._isBeingCasted()) { + buttons.push({ + icon: options?.inFullscreenMode ? 'mdi:fullscreen-exit' : 'mdi:fullscreen', + ...config.menu.buttons.fullscreen, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.fullscreen'), + tap_action: createFrigateCardSimpleAction( + 'fullscreen', + ) as FrigateCardCustomAction, + style: options?.inFullscreenMode ? this._getEmphasizedStyle() : {}, + }); + } + + buttons.push({ + icon: options?.inExpandedMode ? 'mdi:arrow-collapse-all' : 'mdi:arrow-expand-all', + ...config.menu.buttons.expand, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.expand'), + tap_action: createFrigateCardSimpleAction('expand') as FrigateCardCustomAction, + style: options?.inExpandedMode ? this._getEmphasizedStyle() : {}, + }); + + if ( + options?.mediaPlayerController?.hasMediaPlayers() && + (view?.isViewerView() || (view.is('live') && selectedCameraConfig?.camera_entity)) + ) { + const mediaPlayerItems = options.mediaPlayerController + .getMediaPlayers() + .map((playerEntityID) => { + const title = getEntityTitle(hass, playerEntityID) || playerEntityID; + const state = hass.states[playerEntityID]; + const playAction = createFrigateCardMediaPlayerAction(playerEntityID, 'play'); + const stopAction = createFrigateCardMediaPlayerAction(playerEntityID, 'stop'); + const disabled = !state || state.state === 'unavailable'; + + return { + enabled: true, + selected: false, + icon: getEntityIcon(hass, playerEntityID), + entity: playerEntityID, + state_color: false, + title: title, + disabled: disabled, + ...(!disabled && playAction && { tap_action: playAction }), + ...(!disabled && stopAction && { hold_action: stopAction }), + }; + }); + + buttons.push({ + icon: 'mdi:cast', + ...config.menu.buttons.media_player, + type: 'custom:frigate-card-menu-submenu', + title: localize('config.menu.buttons.media_player'), + items: mediaPlayerItems, + }); + } + + if (options?.currentMediaLoadedInfo && options.currentMediaLoadedInfo.player) { + if (options.currentMediaLoadedInfo.capabilities?.supportsPause) { + const paused = options.currentMediaLoadedInfo.player.isPaused(); + buttons.push({ + icon: paused ? 'mdi:play' : 'mdi:pause', + ...config.menu.buttons.play, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.play'), + tap_action: createFrigateCardSimpleAction( + paused ? 'play' : 'pause', + ) as FrigateCardCustomAction, + }); + } + + if (options.currentMediaLoadedInfo.capabilities?.hasAudio) { + const muted = options.currentMediaLoadedInfo.player.isMuted(); + buttons.push({ + icon: muted ? 'mdi:volume-off' : 'mdi:volume-high', + ...config.menu.buttons.mute, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.mute'), + tap_action: createFrigateCardSimpleAction( + muted ? 'unmute' : 'mute', + ) as FrigateCardCustomAction, + }); + } + } + + if (options?.currentMediaLoadedInfo && options.currentMediaLoadedInfo.player) { + buttons.push({ + icon: 'mdi:monitor-screenshot', + ...config.menu.buttons.screenshot, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.screenshot'), + tap_action: createFrigateCardSimpleAction( + 'screenshot', + ) as FrigateCardCustomAction, + }); + } + + if (view.supportsMultipleDisplayModes() && visibleCameraIDs.size > 1) { + const isGrid = view.isGrid(); + buttons.push({ + icon: isGrid ? 'mdi:grid-off' : 'mdi:grid', + ...config.menu.buttons.display_mode, + style: isGrid ? this._getEmphasizedStyle() : {}, + type: 'custom:frigate-card-menu-icon', + title: isGrid + ? localize('display_modes.single') + : localize('display_modes.grid'), + tap_action: createFrigateCardDisplayModeAction(isGrid ? 'single' : 'grid'), + }); + } + + if (hasUsablePTZ(selectedCameraCapabilities, config.live.controls.ptz)) { + const isOn = + view.context?.live?.ptzVisible === false + ? false + : config.live.controls.ptz.mode === 'on'; + buttons.push({ + icon: 'mdi:pan', + ...config.menu.buttons.ptz, + style: isOn ? this._getEmphasizedStyle() : {}, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.ptz'), + tap_action: createFrigateCardShowPTZAction(!isOn), + }); + } + + const styledDynamicButtons = this._dynamicMenuButtons.map((button) => ({ + style: this._getStyleFromActions(config, view, button, options), + ...button, + })); + + return buttons.concat(styledDynamicButtons); + } + + /** + * Get the style of emphasized menu items. + * @returns A StyleInfo. + */ + protected _getEmphasizedStyle(critical?: boolean): StyleInfo { + if (critical) { + return { + animation: 'pulse 3s infinite', + color: 'var(--error-color, white)', + }; + } + return { + color: 'var(--primary-color, white)', + }; + } + + /** + * Given a button determine if the style should be emphasized by examining all + * of the actions sequentially. + * @param button The button to examine. + * @returns A StyleInfo object. + */ + protected _getStyleFromActions( + config: FrigateCardConfig, + view: View, + button: MenuItem, + options?: MenuButtonControllerOptions, + ): StyleInfo { + for (const actionSet of [ + button.tap_action, + button.double_tap_action, + button.hold_action, + button.start_tap_action, + button.end_tap_action, + ]) { + const actions = Array.isArray(actionSet) ? actionSet : [actionSet]; + for (const action of actions) { + // All frigate card actions will have action of 'fire-dom-event' and + // styling only applies to those. + if ( + !action || + action.action !== 'fire-dom-event' || + !('frigate_card_action' in action) + ) { + continue; + } + const frigateCardAction = action as FrigateCardCustomAction; + if ( + FRIGATE_CARD_VIEWS_USER_SPECIFIED.some( + (viewName) => + viewName === frigateCardAction.frigate_card_action && + view?.is(frigateCardAction.frigate_card_action), + ) || + (frigateCardAction.frigate_card_action === 'default' && + view.is(config.view.default)) || + (frigateCardAction.frigate_card_action === 'fullscreen' && + !!options?.inFullscreenMode) || + (frigateCardAction.frigate_card_action === 'camera_select' && + view.camera === frigateCardAction.camera) + ) { + return this._getEmphasizedStyle(); + } + } + } + return {}; + } + + /** + * Determine if the card is currently being casted. + * @returns + */ + protected _isBeingCasted(): boolean { + return !!navigator.userAgent.match(/CrKey\//); + } +} diff --git a/src/components-lib/menu-controller.ts b/src/components-lib/menu-controller.ts index 56639fb6..0410a340 100644 --- a/src/components-lib/menu-controller.ts +++ b/src/components-lib/menu-controller.ts @@ -1,519 +1,215 @@ -import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { StyleInfo } from 'lit/directives/style-map'; -import { CameraManager } from '../camera-manager/manager'; -import { MediaPlayerManager } from '../card-controller/media-player-manager'; -import { MicrophoneManager } from '../card-controller/microphone-manager'; -import { - FrigateCardConfig, - FrigateCardCustomAction, - FRIGATE_CARD_VIEWS_USER_SPECIFIED, +import { HASSDomEvent, HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { LitElement } from 'lit'; +import { FRIGATE_ICON_SVG_PATH } from '../camera-manager/frigate/icon.js'; +import type { + ActionType, + ActionsConfig, + MenuConfig, MenuItem, -} from '../config/types'; -import { FRIGATE_BUTTON_MENU_ICON } from '../const'; -import { localize } from '../localize/localize.js'; -import { MediaLoadedInfo } from '../types'; +} from '../config/types.js'; +import { FRIGATE_BUTTON_MENU_ICON } from '../const.js'; +import { StateParameters } from '../types.js'; import { - createFrigateCardCameraAction, - createFrigateCardDisplayModeAction, - createFrigateCardMediaPlayerAction, - createFrigateCardShowPTZAction, - createFrigateCardSimpleAction, + convertActionToFrigateCardCustomAction, + frigateCardHandleActionConfig, + getActionConfigGivenAction, } from '../utils/action'; -import { getEntityIcon, getEntityTitle } from '../utils/ha'; -import { hasUsablePTZ } from '../utils/ptz'; -import { hasSubstream } from '../utils/substream'; -import { View } from '../view/view'; +import { arrayify, isTruthy } from '../utils/basic.js'; +import { refreshDynamicStateParameters } from '../utils/ha/index.js'; -export interface MenuButtonControllerOptions { - currentMediaLoadedInfo?: MediaLoadedInfo | null; - showCameraUIButton?: boolean; - inFullscreenMode?: boolean; - inExpandedMode?: boolean; - microphoneManager?: MicrophoneManager | null; - mediaPlayerController?: MediaPlayerManager | null; -} +export class MenuController { + protected _host: LitElement; + protected _config: MenuConfig | null = null; + protected _buttons: MenuItem[] = []; + protected _expanded = false; -export class MenuButtonController { - // Array of dynamic menu buttons to be added to menu. - protected _dynamicMenuButtons: MenuItem[] = []; - - public addDynamicMenuButton(button: MenuItem): void { - if (!this._dynamicMenuButtons.includes(button)) { - this._dynamicMenuButtons.push(button); - } + constructor(host: LitElement) { + this._host = host; } - public removeDynamicMenuButton(button: MenuItem): void { - this._dynamicMenuButtons = this._dynamicMenuButtons.filter( - (existingButton) => existingButton != button, + public setMenuConfig(config: MenuConfig): void { + this._config = config; + this._host.style.setProperty( + '--frigate-card-menu-button-size', + `${config.button_size}px`, + ); + + // Store the menu style, position and alignment as attributes (used for + // styling). + this._host.setAttribute('data-style', config.style); + this._host.setAttribute('data-position', config.position); + this._host.setAttribute('data-alignment', config.alignment); + + this._sortButtons(); + this._host.requestUpdate(); + } + + public getMenuConfig(): MenuConfig | null { + return this._config; + } + + public isExpanded(): boolean { + return this._expanded; + } + + public setButtons(buttons: MenuItem[]): void { + this._buttons = buttons; + this._sortButtons(); + this._host.requestUpdate(); + } + + public getButtons(alignment: 'matching' | 'opposing'): MenuItem[] { + const style = this._config?.style; + + const aligned = (button: MenuItem): boolean => { + return ( + button.alignment === alignment || (alignment === 'matching' && !button.alignment) + ); + }; + + const enabled = (button: MenuItem): boolean => { + return button.enabled !== false; + }; + + const suitableToShowIfHiddenMenu = (button: MenuItem): boolean => { + // If the hidden menu isn't expanded, only show the Frigate button. + return ( + style !== 'hidden' || this._expanded || button.icon === FRIGATE_BUTTON_MENU_ICON + ); + }; + + return this._buttons.filter( + (button) => + enabled(button) && aligned(button) && suitableToShowIfHiddenMenu(button), ); } - /** - * Get the menu buttons to display. - * @returns An array of menu buttons. - */ - public calculateButtons( + public setExpanded(expanded: boolean): void { + this._expanded = expanded; + this._host.setAttribute('expanded', ''); + this._host.requestUpdate(); + } + + public toggleExpanded(): void { + this.setExpanded(!this._expanded); + } + + public actionHandler( hass: HomeAssistant, - config: FrigateCardConfig, - cameraManager: CameraManager, - view: View, - options?: MenuButtonControllerOptions, - ): MenuItem[] { - const visibleCameraIDs = cameraManager.getStore().getVisibleCameraIDs(); - const selectedCameraID = view.camera; - const selectedCameraConfig = cameraManager - .getStore() - .getCameraConfig(selectedCameraID); - const allSelectedCameraIDs = cameraManager - .getStore() - .getAllDependentCameras(selectedCameraID); - const selectedMedia = view.queryResults?.getSelectedResult(); + ev: HASSDomEvent<{ action: string; config?: ActionsConfig }>, + config?: ActionsConfig, + ): void { + // These interactions should only be handled by the menu, as nothing + // upstream has the user-provided configuration. + ev.stopPropagation(); - const selectedCameraCapabilities = - cameraManager.getCameraCapabilities(selectedCameraID); - const aggregateCapabilities = - cameraManager.getAggregateCameraCapabilities(allSelectedCameraIDs); - const mediaCapabilities = selectedMedia - ? cameraManager?.getMediaCapabilities(selectedMedia) - : null; - - const buttons: MenuItem[] = []; - buttons.push({ - // Use a magic icon value that the menu will use to render the custom - // Frigate icon. - icon: FRIGATE_BUTTON_MENU_ICON, - ...config.menu.buttons.frigate, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.frigate'), - tap_action: - config.menu?.style === 'hidden' - ? (createFrigateCardSimpleAction('menu_toggle') as FrigateCardCustomAction) - : (createFrigateCardSimpleAction('default') as FrigateCardCustomAction), - hold_action: createFrigateCardSimpleAction( - 'diagnostics', - ) as FrigateCardCustomAction, - }); - - if (visibleCameraIDs.size) { - const menuItems = Array.from( - cameraManager.getStore().getCameraConfigEntries(visibleCameraIDs), - ([cameraID, config]) => { - const action = createFrigateCardCameraAction('camera_select', cameraID); - const metadata = cameraManager.getCameraMetadata(cameraID); - - return { - enabled: true, - icon: metadata?.icon, - entity: config.camera_entity, - state_color: true, - title: metadata?.title, - selected: selectedCameraID === cameraID, - ...(action && { tap_action: action }), - }; - }, - ); - - buttons.push({ - icon: 'mdi:video-switch', - ...config.menu.buttons.cameras, - type: 'custom:frigate-card-menu-submenu', - title: localize('config.menu.buttons.cameras'), - items: menuItems, - }); + // If the event itself contains a configuration then use that. This is + // useful in cases where the registration of the event handler does not have + // access to the actual desired configuration (e.g. action events generated + // by a submenu). + if (ev.detail.config) { + config = ev.detail.config; + } + if (!config) { + return; } - if (selectedCameraID && allSelectedCameraIDs && view.is('live')) { - const dependencies = [...allSelectedCameraIDs]; - const override = view.context?.live?.overrides?.get(selectedCameraID); + const interaction: string = ev.detail.action; + const action = getActionConfigGivenAction(interaction, config); + if (!action) { + return; + } + const actions = arrayify(action); - if (dependencies.length === 2) { - // If there are only two dependencies (the main camera, and 1 other) - // then use a button not a menu to toggle. - buttons.push({ - icon: 'mdi:video-input-component', - style: - override && override !== selectedCameraID ? this._getEmphasizedStyle() : {}, - title: localize('config.menu.buttons.substreams'), - ...config.menu.buttons.substreams, - type: 'custom:frigate-card-menu-icon', - tap_action: createFrigateCardSimpleAction( - hasSubstream(view) ? 'live_substream_off' : 'live_substream_on', - ) as FrigateCardCustomAction, - }); - } else if (dependencies.length > 2) { - const menuItems = Array.from(dependencies, (cameraID) => { - const action = createFrigateCardCameraAction( - 'live_substream_select', - cameraID, - ); - const metadata = cameraManager.getCameraMetadata(cameraID) ?? undefined; - const cameraConfig = cameraManager.getStore().getCameraConfig(cameraID); - return { - enabled: true, - icon: metadata?.icon, - entity: cameraConfig?.camera_entity, - state_color: true, - title: metadata?.title, - selected: - (view.context?.live?.overrides?.get(selectedCameraID) ?? - selectedCameraID) === cameraID, - ...(action && { tap_action: action }), - }; - }); + // A note on the complexity below: By default the menu should close when a + // user takes an action, an exception is if the user is specifically + // manipulating the menu in the actions themselves. + let menuToggle = false; - buttons.push({ - icon: 'mdi:video-input-component', - title: localize('config.menu.buttons.substreams'), - style: - override && override !== selectedCameraID ? this._getEmphasizedStyle() : {}, - ...config.menu.buttons.substreams, - type: 'custom:frigate-card-menu-submenu', - items: menuItems, - }); + const toggleLessActions = actions.filter( + (item) => isTruthy(item) && !this._isMenuToggleAction(item), + ); + if (toggleLessActions.length != actions.length) { + menuToggle = true; + } + + if (toggleLessActions.length) { + frigateCardHandleActionConfig(this._host, hass, config, interaction, actions); + } + + if (this._isHidingMenu()) { + if (menuToggle) { + this.setExpanded(!this._expanded); + } else { + // Don't close the menu if there is another action to come. + const holdAction = getActionConfigGivenAction('hold', config); + const doubleTapAction = getActionConfigGivenAction('double_tap', config); + const tapAction = getActionConfigGivenAction('tap', config); + const endTapAction = getActionConfigGivenAction('end_tap', config); + + if ( + interaction === 'end_tap' || + (interaction === 'start_tap' && + !holdAction && + !doubleTapAction && + !tapAction && + !endTapAction) || + (interaction !== 'end_tap' && !endTapAction) + ) { + this.setExpanded(false); + } } } - - buttons.push({ - icon: 'mdi:cctv', - ...config.menu.buttons.live, - type: 'custom:frigate-card-menu-icon', - title: localize('config.view.views.live'), - style: view.is('live') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction('live') as FrigateCardCustomAction, - }); - - if (aggregateCapabilities?.supportsClips) { - buttons.push({ - icon: 'mdi:filmstrip', - ...config.menu.buttons.clips, - type: 'custom:frigate-card-menu-icon', - title: localize('config.view.views.clips'), - style: view?.is('clips') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction('clips') as FrigateCardCustomAction, - hold_action: createFrigateCardSimpleAction('clip') as FrigateCardCustomAction, - }); - } - - if (aggregateCapabilities?.supportsSnapshots) { - buttons.push({ - icon: 'mdi:camera', - ...config.menu.buttons.snapshots, - type: 'custom:frigate-card-menu-icon', - title: localize('config.view.views.snapshots'), - style: view?.is('snapshots') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction( - 'snapshots', - ) as FrigateCardCustomAction, - hold_action: createFrigateCardSimpleAction( - 'snapshot', - ) as FrigateCardCustomAction, - }); - } - - if (aggregateCapabilities?.supportsRecordings) { - buttons.push({ - icon: 'mdi:album', - ...config.menu.buttons.recordings, - type: 'custom:frigate-card-menu-icon', - title: localize('config.view.views.recordings'), - style: view.is('recordings') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction( - 'recordings', - ) as FrigateCardCustomAction, - hold_action: createFrigateCardSimpleAction( - 'recording', - ) as FrigateCardCustomAction, - }); - } - - buttons.push({ - icon: 'mdi:image', - ...config.menu.buttons.image, - type: 'custom:frigate-card-menu-icon', - title: localize('config.view.views.image'), - style: view?.is('image') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction('image') as FrigateCardCustomAction, - }); - - // Don't show the timeline button unless there's at least one non-birdseye - // camera with a Frigate camera name. - if (aggregateCapabilities?.supportsTimeline) { - buttons.push({ - icon: 'mdi:chart-gantt', - ...config.menu.buttons.timeline, - type: 'custom:frigate-card-menu-icon', - title: localize('config.view.views.timeline'), - style: view.is('timeline') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction('timeline') as FrigateCardCustomAction, - }); - } - - if (mediaCapabilities?.canDownload && !this._isBeingCasted()) { - buttons.push({ - icon: 'mdi:download', - ...config.menu.buttons.download, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.download'), - tap_action: createFrigateCardSimpleAction('download') as FrigateCardCustomAction, - }); - } - - if (options?.showCameraUIButton) { - buttons.push({ - icon: 'mdi:web', - ...config.menu.buttons.camera_ui, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.camera_ui'), - tap_action: createFrigateCardSimpleAction( - 'camera_ui', - ) as FrigateCardCustomAction, - }); - } - - if ( - options?.microphoneManager && - options?.currentMediaLoadedInfo?.capabilities?.supports2WayAudio - ) { - const forbidden = options.microphoneManager.isForbidden(); - const muted = options.microphoneManager.isMuted(); - const buttonType = config.menu.buttons.microphone.type; - buttons.push({ - icon: forbidden - ? 'mdi:microphone-message-off' - : muted - ? 'mdi:microphone-off' - : 'mdi:microphone', - ...config.menu.buttons.microphone, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.microphone'), - style: forbidden || muted ? {} : this._getEmphasizedStyle(true), - ...(!forbidden && - buttonType === 'momentary' && { - start_tap_action: createFrigateCardSimpleAction( - 'microphone_unmute', - ) as FrigateCardCustomAction, - end_tap_action: createFrigateCardSimpleAction( - 'microphone_mute', - ) as FrigateCardCustomAction, - }), - ...(!forbidden && - buttonType === 'toggle' && { - tap_action: createFrigateCardSimpleAction( - options.microphoneManager.isMuted() - ? 'microphone_unmute' - : 'microphone_mute', - ) as FrigateCardCustomAction, - }), - }); - } - - if (!this._isBeingCasted()) { - buttons.push({ - icon: options?.inFullscreenMode ? 'mdi:fullscreen-exit' : 'mdi:fullscreen', - ...config.menu.buttons.fullscreen, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.fullscreen'), - tap_action: createFrigateCardSimpleAction( - 'fullscreen', - ) as FrigateCardCustomAction, - style: options?.inFullscreenMode ? this._getEmphasizedStyle() : {}, - }); - } - - buttons.push({ - icon: options?.inExpandedMode ? 'mdi:arrow-collapse-all' : 'mdi:arrow-expand-all', - ...config.menu.buttons.expand, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.expand'), - tap_action: createFrigateCardSimpleAction('expand') as FrigateCardCustomAction, - style: options?.inExpandedMode ? this._getEmphasizedStyle() : {}, - }); - - if ( - options?.mediaPlayerController?.hasMediaPlayers() && - (view?.isViewerView() || (view.is('live') && selectedCameraConfig?.camera_entity)) - ) { - const mediaPlayerItems = options.mediaPlayerController - .getMediaPlayers() - .map((playerEntityID) => { - const title = getEntityTitle(hass, playerEntityID) || playerEntityID; - const state = hass.states[playerEntityID]; - const playAction = createFrigateCardMediaPlayerAction(playerEntityID, 'play'); - const stopAction = createFrigateCardMediaPlayerAction(playerEntityID, 'stop'); - const disabled = !state || state.state === 'unavailable'; - - return { - enabled: true, - selected: false, - icon: getEntityIcon(hass, playerEntityID), - entity: playerEntityID, - state_color: false, - title: title, - disabled: disabled, - ...(!disabled && playAction && { tap_action: playAction }), - ...(!disabled && stopAction && { hold_action: stopAction }), - }; - }); - - buttons.push({ - icon: 'mdi:cast', - ...config.menu.buttons.media_player, - type: 'custom:frigate-card-menu-submenu', - title: localize('config.menu.buttons.media_player'), - items: mediaPlayerItems, - }); - } - - if (options?.currentMediaLoadedInfo && options.currentMediaLoadedInfo.player) { - if (options.currentMediaLoadedInfo.capabilities?.supportsPause) { - const paused = options.currentMediaLoadedInfo.player.isPaused(); - buttons.push({ - icon: paused ? 'mdi:play' : 'mdi:pause', - ...config.menu.buttons.play, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.play'), - tap_action: createFrigateCardSimpleAction( - paused ? 'play' : 'pause', - ) as FrigateCardCustomAction, - }); - } - - if (options.currentMediaLoadedInfo.capabilities?.hasAudio) { - const muted = options.currentMediaLoadedInfo.player.isMuted(); - buttons.push({ - icon: muted ? 'mdi:volume-off' : 'mdi:volume-high', - ...config.menu.buttons.mute, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.mute'), - tap_action: createFrigateCardSimpleAction( - muted ? 'unmute' : 'mute', - ) as FrigateCardCustomAction, - }); - } - } - - if (options?.currentMediaLoadedInfo && options.currentMediaLoadedInfo.player) { - buttons.push({ - icon: 'mdi:monitor-screenshot', - ...config.menu.buttons.screenshot, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.screenshot'), - tap_action: createFrigateCardSimpleAction( - 'screenshot', - ) as FrigateCardCustomAction, - }); - } - - if (view.supportsMultipleDisplayModes() && visibleCameraIDs.size > 1) { - const isGrid = view.isGrid(); - buttons.push({ - icon: isGrid ? 'mdi:grid-off' : 'mdi:grid', - ...config.menu.buttons.display_mode, - style: isGrid ? this._getEmphasizedStyle() : {}, - type: 'custom:frigate-card-menu-icon', - title: isGrid - ? localize('display_modes.single') - : localize('display_modes.grid'), - tap_action: createFrigateCardDisplayModeAction(isGrid ? 'single' : 'grid'), - }); - } - - if (hasUsablePTZ(selectedCameraCapabilities, config.live.controls.ptz)) { - const isOn = - view.context?.live?.ptzVisible === false - ? false - : config.live.controls.ptz.mode === 'on'; - buttons.push({ - icon: 'mdi:pan', - ...config.menu.buttons.ptz, - style: isOn ? this._getEmphasizedStyle() : {}, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.ptz'), - tap_action: createFrigateCardShowPTZAction(!isOn), - }); - } - - const styledDynamicButtons = this._dynamicMenuButtons.map((button) => ({ - style: this._getStyleFromActions(config, view, button, options), - ...button, - })); - - return buttons.concat(styledDynamicButtons); } - /** - * Get the style of emphasized menu items. - * @returns A StyleInfo. - */ - protected _getEmphasizedStyle(critical?: boolean): StyleInfo { - if (critical) { - return { - animation: 'pulse 3s infinite', - color: 'var(--error-color, white)', - }; - } - return { - color: 'var(--primary-color, white)', + public getFreshButtonState(hass: HomeAssistant, button: MenuItem): StateParameters { + const stateParameters = { ...button }; + return hass && button.type === 'custom:frigate-card-menu-state-icon' + ? refreshDynamicStateParameters(hass, stateParameters) + : stateParameters; + } + + public getSVGPath(button: MenuItem): string { + return button.icon === FRIGATE_BUTTON_MENU_ICON ? FRIGATE_ICON_SVG_PATH : ''; + } + + protected _sortButtons(): void { + const style = this._config?.style; + const sortButtons = (a: MenuItem, b: MenuItem): number => { + // If the menu is hidden, the Frigate button must come first. + if (style === 'hidden') { + if (a.icon === FRIGATE_BUTTON_MENU_ICON) { + return -1; + } else if (b.icon === FRIGATE_BUTTON_MENU_ICON) { + return 1; + } + } + + // Otherwise sort by priority. + if ( + a.priority === undefined || + (b.priority !== undefined && b.priority > a.priority) + ) { + return 1; + } + if ( + b.priority === undefined || + (a.priority !== undefined && b.priority < a.priority) + ) { + return -1; + } + return 0; }; + + this._buttons.sort(sortButtons); } - /** - * Given a button determine if the style should be emphasized by examining all - * of the actions sequentially. - * @param button The button to examine. - * @returns A StyleInfo object. - */ - protected _getStyleFromActions( - config: FrigateCardConfig, - view: View, - button: MenuItem, - options?: MenuButtonControllerOptions, - ): StyleInfo { - for (const actionSet of [ - button.tap_action, - button.double_tap_action, - button.hold_action, - button.start_tap_action, - button.end_tap_action, - ]) { - const actions = Array.isArray(actionSet) ? actionSet : [actionSet]; - for (const action of actions) { - // All frigate card actions will have action of 'fire-dom-event' and - // styling only applies to those. - if ( - !action || - action.action !== 'fire-dom-event' || - !('frigate_card_action' in action) - ) { - continue; - } - const frigateCardAction = action as FrigateCardCustomAction; - if ( - FRIGATE_CARD_VIEWS_USER_SPECIFIED.some( - (viewName) => - viewName === frigateCardAction.frigate_card_action && - view?.is(frigateCardAction.frigate_card_action), - ) || - (frigateCardAction.frigate_card_action === 'default' && - view.is(config.view.default)) || - (frigateCardAction.frigate_card_action === 'fullscreen' && - !!options?.inFullscreenMode) || - (frigateCardAction.frigate_card_action === 'camera_select' && - view.camera === frigateCardAction.camera) - ) { - return this._getEmphasizedStyle(); - } - } - } - return {}; + protected _isHidingMenu(): boolean { + return this._config?.style === 'hidden' ?? false; } - /** - * Determine if the card is currently being casted. - * @returns - */ - protected _isBeingCasted(): boolean { - return !!navigator.userAgent.match(/CrKey\//); + protected _isMenuToggleAction(action: ActionType): boolean { + const frigateCardAction = convertActionToFrigateCardCustomAction(action); + return !!frigateCardAction && frigateCardAction.frigate_card_action == 'menu_toggle'; } } diff --git a/src/components/menu.ts b/src/components/menu.ts index 59e729c1..1e92952a 100644 --- a/src/components/menu.ts +++ b/src/components/menu.ts @@ -1,249 +1,52 @@ -import { HASSDomEvent, HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { - CSSResultGroup, - LitElement, - PropertyValues, - TemplateResult, - html, - unsafeCSS, -} from 'lit'; -import { customElement, property, state } from 'lit/decorators.js'; -import { classMap } from 'lit/directives/class-map.js'; +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { styleMap } from 'lit/directives/style-map.js'; import { actionHandler } from '../action-handler-directive.js'; -import { FRIGATE_ICON_SVG_PATH } from '../camera-manager/frigate/icon.js'; -import type { - ActionType, - ActionsConfig, - MenuConfig, - MenuItem, -} from '../config/types.js'; -import { FRIGATE_BUTTON_MENU_ICON } from '../const.js'; +import { MenuController } from '../components-lib/menu-controller.js'; +import type { MenuConfig, MenuItem } from '../config/types.js'; import menuStyle from '../scss/menu.scss'; -import type { StateParameters } from '../types.js'; -import { - convertActionToFrigateCardCustomAction, - frigateCardHandleActionConfig, - frigateCardHasAction, - getActionConfigGivenAction, -} from '../utils/action.js'; -import { refreshDynamicStateParameters } from '../utils/ha'; +import { frigateCardHasAction } from '../utils/action.js'; import { EntityRegistryManager } from '../utils/ha/entity-registry/index.js'; import './submenu.js'; -/** - * A menu for the FrigateCard. - */ @customElement('frigate-card-menu') export class FrigateCardMenu extends LitElement { - @property({ attribute: false }) - public hass?: HomeAssistant; - - @property({ attribute: true, type: Boolean, reflect: true }) - public expanded = false; - - set menuConfig(menuConfig: MenuConfig) { - this._menuConfig = menuConfig; - if (menuConfig) { - this.style.setProperty( - '--frigate-card-menu-button-size', - `${menuConfig.button_size}px`, - ); - } - // Store the menu style, position and alignment as attributes (used for - // styling). - this.setAttribute('data-style', menuConfig.style); - this.setAttribute('data-position', menuConfig.position); - this.setAttribute('data-alignment', menuConfig.alignment); - } - @state() - protected _menuConfig?: MenuConfig; - - @property({ attribute: false }) - public buttons: MenuItem[] = []; + protected _controller = new MenuController(this); @property({ attribute: false }) public entityRegistryManager?: EntityRegistryManager; - /** - * Determine if a given menu configuration is a hiding menu. - * @param menuConfig The menu configuration. - * @returns `true` if the menu is hiding, `false` otherwise. - */ - static isHidingMenu(menuConfig: MenuConfig | undefined): boolean { - return menuConfig?.style === 'hidden' ?? false; + @property({ attribute: false }) + public hass?: HomeAssistant; + + set menuConfig(menuConfig: MenuConfig) { + this._controller.setMenuConfig(menuConfig); + } + + set buttons(buttons: MenuItem[]) { + this._controller.setButtons(buttons); + } + + set expanded(expanded: boolean) { + this._controller.setExpanded(expanded); } - /** - * Toggle the menu. Has no action if menu is not hiding/expandable. - */ public toggleMenu(): void { - if (this._isHidingMenu()) { - this.expanded = !this.expanded; - } - } - - /** - * Determine if a given menu configuration is a hiding menu (internal version). - * @returns `true` if the menu is hiding, `false` otherwise. - */ - protected _isHidingMenu(): boolean { - return FrigateCardMenu.isHidingMenu(this._menuConfig); - } - - /** - * Determine if a given action is intended to toggle the menu. - * @param action The action to check. - * @returns `true` if the action toggles the menu, `false` otherwise. - */ - protected _isMenuToggleAction(action: ActionType | null): boolean { - // Determine if this action is a Frigate card action, if so handle it - // internally. - if (!action) { - return false; - } - const frigateCardAction = convertActionToFrigateCardCustomAction(action); - return !!frigateCardAction && frigateCardAction.frigate_card_action == 'menu_toggle'; - } - - /** - * Handle an action on a menu button. - * @param ev The action event. - * @param button The button configuration. - */ - protected _actionHandler( - ev: HASSDomEvent<{ action: string; config?: ActionsConfig }>, - config?: ActionsConfig, - ): void { - if (!ev) { - return; - } - - // If the event itself contains a configuration then use that. This is - // useful in cases where the registration of the event handler does not have - // access to the actual desired configuration (e.g. action events generated - // by a submenu). - if (ev.detail.config) { - config = ev.detail.config; - } - - // These interactions should only be handled by the menu, as nothing - // upstream has the user-provided configuration. - ev.stopPropagation(); - - const interaction: string = ev.detail.action; - let action = getActionConfigGivenAction(interaction, config); - if (!config || !interaction) { - return; - } - - let tookAction = false; - let menuToggle = false; - - if (Array.isArray(action)) { - // Case 1: An array of actions. - // Strip out actions that toggle the menu. - const actionCount = action.length; - action = action.filter((item) => !this._isMenuToggleAction(item)); - if (action.length != actionCount) { - menuToggle = true; - } - - // If there are still actions left, handle them as usual. - if (action.length) { - tookAction = frigateCardHandleActionConfig( - this, - this.hass as HomeAssistant, - config, - interaction, - action, - ); - } - } else { - // Case 2: Either a specific action, or no action at all (i.e. default - // action for `tap`). - if (this._isMenuToggleAction(action)) { - menuToggle = true; - } else { - tookAction = frigateCardHandleActionConfig( - this, - this.hass as HomeAssistant, - config, - interaction, - action, - ); - } - } - - if (this._isHidingMenu()) { - if (menuToggle) { - this.expanded = !this.expanded; - } else if (tookAction) { - // Don't close the menu if there is another action to come. - const holdAction = getActionConfigGivenAction('hold', config); - const doubleTapAction = getActionConfigGivenAction('double_tap', config); - const tapAction = getActionConfigGivenAction('tap', config); - const endTapAction = getActionConfigGivenAction('end_tap', config); - - if ( - interaction === 'end_tap' || - (interaction === 'start_tap' && - !holdAction && - !doubleTapAction && - !tapAction && - !endTapAction) || - (interaction !== 'end_tap' && !endTapAction) - ) { - this.expanded = false; - } - } - } - } - - /** - * Ensure menu buttons are sorted before the render. - * @param changedProps The changed properties - */ - protected willUpdate(changedProps: PropertyValues): void { - const style = this._menuConfig?.style; - const sortButtons = (a: MenuItem, b: MenuItem): number => { - // If the menu is hidden, the Frigate button must come first. - if (style === 'hidden') { - if (a.icon === FRIGATE_BUTTON_MENU_ICON) { - return -1; - } else if (b.icon === FRIGATE_BUTTON_MENU_ICON) { - return 1; - } - } - - // Otherwise sort by priority. - if ( - a.priority === undefined || - (b.priority !== undefined && b.priority > a.priority) - ) { - return 1; - } - if ( - b.priority === undefined || - (a.priority !== undefined && b.priority < a.priority) - ) { - return -1; - } - return 0; - }; - - if (changedProps.has('_menuConfig') || changedProps.has('buttons')) { - this.buttons.sort(sortButtons); - } + this._controller.toggleExpanded(); } protected _renderButton(button: MenuItem): TemplateResult | void { + if (!this.hass) { + return; + } + if (button.type === 'custom:frigate-card-menu-submenu') { return html` this.hass && this._controller.actionHandler(this.hass, ev)} > `; } else if (button.type === 'custom:frigate-card-menu-submenu-select') { @@ -251,26 +54,11 @@ export class FrigateCardMenu extends LitElement { .hass=${this.hass} .submenuSelect=${button} .entityRegistryManager=${this.entityRegistryManager} - @action=${this._actionHandler.bind(this)} + @action=${(ev) => this.hass && this._controller.actionHandler(this.hass, ev)} > `; } - let stateParameters = { ...button } as StateParameters; - const svgPath = - stateParameters.icon === FRIGATE_BUTTON_MENU_ICON ? FRIGATE_ICON_SVG_PATH : ''; - - if (this.hass && button.type === 'custom:frigate-card-menu-state-icon') { - stateParameters = refreshDynamicStateParameters(this.hass, stateParameters); - } - - const hasHold = frigateCardHasAction(button.hold_action); - const hasDoubleClick = frigateCardHasAction(button.double_tap_action); - - const classes = { - button: true, - }; - // ===================================================================================== // For `data-domain` and `data-state`, see: See // https://github.com/home-assistant/frontend/blob/dev/src/components/entity/state-badge.ts#L54 @@ -283,62 +71,53 @@ export class FrigateCardMenu extends LitElement { // - Static styling based on domain (`data-domain`) and state // (`data-state`). This looks up a CSS style in `menu.scss`. + const buttonState = this._controller.getFreshButtonState(this.hass, button); + const svgPath = this._controller.getSVGPath(button); + return html` this._actionHandler(ev, button)} + .label=${buttonState.title || ''} + @action=${(ev) => + this.hass && this._controller.actionHandler(this.hass, ev, button)} > ${svgPath ? html`` : html``} `; } protected render(): TemplateResult | void { - if (!this._menuConfig) { - return; - } - const style = this._menuConfig.style; - if (style === 'none') { + const config = this._controller.getMenuConfig(); + const style = config?.style; + if (!config || style === 'none') { return; } + const matchingButtons = this._controller.getButtons('matching'); + const opposingButtons = this._controller.getButtons('opposing'); - // If the hidden menu isn't expanded, only show the Frigate button. - const matchingButtons = ( - style !== 'hidden' || this.expanded - ? this.buttons.filter( - (button) => !button.alignment || button.alignment === 'matching', - ) - : this.buttons.filter((button) => button.icon === FRIGATE_BUTTON_MENU_ICON) - ).filter((button) => button.enabled !== false); - - const opposingButtons = - style !== 'hidden' || this.expanded - ? this.buttons.filter( - (button) => button.alignment === 'opposing' && button.enabled !== false, - ) - : []; - - const matchingStyle = { - flex: String(matchingButtons.length), - }; - const opposingStyle = { - flex: String(opposingButtons.length), - }; - - return html`
+ return html`
${matchingButtons.map((button) => this._renderButton(button))}
-
+
${opposingButtons.map((button) => this._renderButton(button))}
`; } diff --git a/src/config/types.ts b/src/config/types.ts index 514b90ff..0fd907a4 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -326,7 +326,7 @@ const actionsSchema = z.object({ }); const elementsBaseSchema = actionsBaseSchema.extend({ - style: z.object({}).passthrough().optional(), + style: z.record(z.string().nullable()).optional(), title: z.string().nullable().optional(), }); @@ -1255,7 +1255,7 @@ const hiddenButtonSchema = menuBaseSchema.extend({ priority: menuBaseSchema.shape.priority.default(hiddenButtonDefault.priority), }); -const menuConfigSchema = z +export const menuConfigSchema = z .object({ style: z.enum(FRIGATE_MENU_STYLES).default(menuConfigDefault.style), position: z.enum(FRIGATE_MENU_POSITIONS).default(menuConfigDefault.position), diff --git a/src/utils/action.ts b/src/utils/action.ts index 27bb17c6..01b39f78 100644 --- a/src/utils/action.ts +++ b/src/utils/action.ts @@ -115,15 +115,15 @@ export function getActionConfigGivenAction( if (!interaction || !config) { return null; } - if (interaction == 'tap' && config.tap_action) { + if (interaction === 'tap' && config.tap_action) { return config.tap_action; - } else if (interaction == 'hold' && config.hold_action) { + } else if (interaction === 'hold' && config.hold_action) { return config.hold_action; - } else if (interaction == 'double_tap' && config.double_tap_action) { + } else if (interaction === 'double_tap' && config.double_tap_action) { return config.double_tap_action; - } else if (interaction == 'end_tap' && config.end_tap_action) { + } else if (interaction === 'end_tap' && config.end_tap_action) { return config.end_tap_action; - } else if (interaction == 'start_tap' && config.start_tap_action) { + } else if (interaction === 'start_tap' && config.start_tap_action) { return config.start_tap_action; } return null; diff --git a/tests/components-lib/menu-button-controller.test.ts b/tests/components-lib/menu-button-controller.test.ts new file mode 100644 index 00000000..87f2c9ba --- /dev/null +++ b/tests/components-lib/menu-button-controller.test.ts @@ -0,0 +1,1351 @@ +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import isEqual from 'lodash-es/isEqual'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { CameraManager } from '../../src/camera-manager/manager'; +import { CameraManagerCameraMetadata } from '../../src/camera-manager/types'; +import { MediaPlayerManager } from '../../src/card-controller/media-player-manager'; +import { MicrophoneManager } from '../../src/card-controller/microphone-manager'; +import { + MenuButtonController, + MenuButtonControllerOptions, +} from '../../src/components-lib/menu-button-controller'; +import { FrigateCardConfig, MenuItem, ViewDisplayMode } from '../../src/config/types'; +import { FrigateCardMediaPlayer } from '../../src/types'; +import { createFrigateCardSimpleAction } from '../../src/utils/action'; +import { ViewMedia } from '../../src/view/media'; +import { MediaQueriesResults } from '../../src/view/media-queries-results'; +import { View } from '../../src/view/view'; +import { + createAggregateCameraCapabilities, + createCameraCapabilities, + createCameraConfig, + createCameraManager, + createCardAPI, + createConfig, + createHASS, + createMediaCapabilities, + createMediaLoadedInfo, + createStateEntity, + createStore, + createView, +} from '../test-utils'; + +vi.mock('../../src/utils/media-player-controller.js'); +vi.mock('../../src/card-controller/microphone-manager.js'); + +const calculateButtons = ( + controller: MenuButtonController, + options?: MenuButtonControllerOptions & { + hass?: HomeAssistant; + config?: FrigateCardConfig; + cameraManager?: CameraManager; + view?: View; + }, +): MenuItem[] => { + let cameraManager: CameraManager | null = options?.cameraManager ?? null; + if (!cameraManager) { + cameraManager = createCameraManager(); + } + + return controller.calculateButtons( + options?.hass ?? createHASS(), + options?.config ?? createConfig(), + cameraManager, + options?.view ?? createView({ camera: 'camera-1' }), + options, + ); +}; + +// @vitest-environment jsdom +describe('MenuButtonController', () => { + let controller: MenuButtonController; + const dynamicButton: MenuItem = { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:alpha-a-circle', + title: 'Dynamic button', + }; + + beforeEach(() => { + vi.resetAllMocks(); + controller = new MenuButtonController(); + }); + + it('should have frigate menu button with hidden menu style', () => { + const buttons = calculateButtons(controller); + expect(buttons).toContainEqual({ + icon: 'frigate', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Frigate menu / Default view', + tap_action: createFrigateCardSimpleAction('menu_toggle'), + hold_action: createFrigateCardSimpleAction('diagnostics'), + }); + }); + + it('should have frigate menu button without hidden menu style', () => { + const buttons = calculateButtons(controller, { + config: createConfig({ menu: { style: 'overlay' } }), + }); + expect(buttons).toContainEqual({ + icon: 'frigate', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Frigate menu / Default view', + tap_action: createFrigateCardSimpleAction('default'), + hold_action: createFrigateCardSimpleAction('diagnostics'), + }); + }); + + it('should have cameras menu', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([{ cameraID: 'camera-1' }, { cameraID: 'camera-2' }]), + ); + vi.mocked(cameraManager).getCameraMetadata.mockReturnValue({ + title: 'title', + icon: 'icon', + }); + + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).toContainEqual({ + icon: 'mdi:video-switch', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-submenu', + title: 'Cameras', + items: [ + { + enabled: true, + icon: 'icon', + entity: undefined, + state_color: true, + title: 'title', + selected: true, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + camera: 'camera-1', + }, + }, + { + enabled: true, + icon: 'icon', + entity: undefined, + state_color: true, + title: 'title', + selected: false, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + camera: 'camera-2', + }, + }, + ], + }); + }); + + it('should not have a cameras menu without a visible camera', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { cameraID: 'camera-1', config: createCameraConfig({ hide: true }) }, + ]), + ); + + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ + title: 'Cameras', + }), + ]), + ); + }); + + it('should have substream button with single dependency', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), + }, + { cameraID: 'camera-2' }, + ]), + ); + + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).toContainEqual({ + icon: 'mdi:video-input-component', + style: {}, + title: 'Substream(s)', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_on', + }, + }); + }); + + it('should have substream button selected with single dependency', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), + }, + { cameraID: 'camera-2' }, + ]), + ); + + const view = createView({ + camera: 'camera-1', + context: { + live: { + overrides: new Map([['camera-1', 'camera-2']]), + }, + }, + }); + + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); + expect(buttons).toContainEqual({ + icon: 'mdi:video-input-component', + style: { color: 'var(--primary-color, white)' }, + title: 'Substream(s)', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_off', + }, + }); + }); + + it('should have substream menu without substream on with multiple dependencies', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ + camera_entity: 'camera.1', + dependencies: { cameras: ['camera-2', 'camera-3'] }, + }), + }, + { + cameraID: 'camera-2', + config: createCameraConfig({ + camera_entity: 'camera.2', + }), + }, + { + cameraID: 'camera-3', + config: createCameraConfig({ + camera_entity: 'camera.3', + }), + }, + ]), + ); + + // Return different metadata depending on the camera to test multiple code + // paths. + mock(cameraManager).getCameraMetadata.mockImplementation( + (cameraID: string): CameraManagerCameraMetadata | null => { + return cameraID === 'camera-1' + ? { + title: 'title', + icon: 'icon', + } + : null; + }, + ); + + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).toContainEqual({ + icon: 'mdi:video-input-component', + title: 'Substream(s)', + style: {}, + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-submenu', + items: [ + { + enabled: true, + icon: 'icon', + entity: 'camera.1', + state_color: true, + title: 'title', + selected: true, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'camera-1', + }, + }, + { + enabled: true, + icon: undefined, + entity: 'camera.2', + state_color: true, + title: undefined, + selected: false, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'camera-2', + }, + }, + { + enabled: true, + icon: undefined, + entity: 'camera.3', + state_color: true, + title: undefined, + selected: false, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'camera-3', + }, + }, + ], + }); + }); + + it('should have substream menu with substream on with multiple dependencies', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ + camera_entity: 'camera.1', + dependencies: { cameras: ['camera-2', 'camera-3'] }, + }), + }, + { + cameraID: 'camera-2', + config: createCameraConfig({ + camera_entity: 'camera.2', + }), + }, + { + cameraID: 'camera-3', + config: createCameraConfig({ + camera_entity: 'camera.3', + }), + }, + ]), + ); + + const view = createView({ + camera: 'camera-1', + context: { + live: { + overrides: new Map([['camera-1', 'camera-2']]), + }, + }, + }); + + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:video-input-component', + title: 'Substream(s)', + style: { color: 'var(--primary-color, white)' }, + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-submenu', + items: [ + { + enabled: true, + icon: undefined, + entity: 'camera.1', + state_color: true, + title: undefined, + selected: false, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'camera-1', + }, + }, + { + enabled: true, + icon: undefined, + entity: 'camera.2', + state_color: true, + title: undefined, + // camera-2 is selected in this test scenario because of the view + // override. + selected: true, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'camera-2', + }, + }, + { + enabled: true, + icon: undefined, + entity: 'camera.3', + state_color: true, + title: undefined, + selected: false, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'camera-3', + }, + }, + ], + }); + }); + + it('should have styled live menu button in live view', () => { + const buttons = calculateButtons(controller); + expect(buttons).toContainEqual({ + icon: 'mdi:cctv', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Live view', + style: { color: 'var(--primary-color, white)' }, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'live' }, + }); + }); + + it('should have unstyled live menu button in non-live views', () => { + const view = createView({ view: 'clips' }); + const buttons = calculateButtons(controller, { view: view }); + expect(buttons).toContainEqual({ + icon: 'mdi:cctv', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Live view', + style: {}, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'live' }, + }); + }); + + it('should have styled clips menu button in clips view', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsClips: true }), + ); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: createView({ view: 'clips' }), + }); + expect(buttons).toContainEqual({ + icon: 'mdi:filmstrip', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Clips gallery', + style: { color: 'var(--primary-color, white)' }, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' }, + hold_action: { action: 'fire-dom-event', frigate_card_action: 'clip' }, + }); + }); + + it('should have unstyled clips menu button in non-clips view', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsClips: true }), + ); + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).toContainEqual({ + icon: 'mdi:filmstrip', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Clips gallery', + style: {}, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' }, + hold_action: { action: 'fire-dom-event', frigate_card_action: 'clip' }, + }); + }); + + it('should have styled snapshots menu button in snapshots view', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsSnapshots: true }), + ); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: createView({ view: 'snapshots' }), + }); + expect(buttons).toContainEqual({ + icon: 'mdi:camera', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Snapshots gallery', + style: { color: 'var(--primary-color, white)' }, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'snapshots' }, + hold_action: { action: 'fire-dom-event', frigate_card_action: 'snapshot' }, + }); + }); + + it('should have unstyled snapshots menu button in non-snapshots view', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsSnapshots: true }), + ); + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).toContainEqual({ + icon: 'mdi:camera', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Snapshots gallery', + style: {}, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'snapshots' }, + hold_action: { action: 'fire-dom-event', frigate_card_action: 'snapshot' }, + }); + }); + + it('should have styled recordings menu button in recordings view', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsRecordings: true }), + ); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: createView({ view: 'recordings' }), + }); + expect(buttons).toContainEqual({ + icon: 'mdi:album', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Recordings gallery', + style: { color: 'var(--primary-color, white)' }, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'recordings' }, + hold_action: { action: 'fire-dom-event', frigate_card_action: 'recording' }, + }); + }); + + it('should have unstyled recordings menu button in non-recordings view', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsRecordings: true }), + ); + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).toContainEqual({ + icon: 'mdi:album', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Recordings gallery', + style: {}, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'recordings' }, + hold_action: { action: 'fire-dom-event', frigate_card_action: 'recording' }, + }); + }); + + it('should have styled image menu button in image view', () => { + const buttons = calculateButtons(controller, { + view: createView({ view: 'image' }), + }); + expect(buttons).toContainEqual({ + icon: 'mdi:image', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Static image', + style: { color: 'var(--primary-color, white)' }, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'image' }, + }); + }); + + it('should have unstyled image menu button in non-image view', () => { + const buttons = calculateButtons(controller); + expect(buttons).toContainEqual({ + icon: 'mdi:image', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Static image', + style: {}, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'image' }, + }); + }); + + it('should have styled timeline menu button in timeline view', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsTimeline: true }), + ); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: createView({ view: 'timeline' }), + }); + expect(buttons).toContainEqual({ + icon: 'mdi:chart-gantt', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Timeline view', + style: { color: 'var(--primary-color, white)' }, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'timeline' }, + }); + }); + + it('should have unstyled timeline menu button in non-timeline view', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsTimeline: true }), + ); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + }); + expect(buttons).toContainEqual({ + icon: 'mdi:chart-gantt', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Timeline view', + style: {}, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'timeline' }, + }); + }); + + it('should have download menu button', () => { + vi.stubGlobal('navigator', { userAgent: 'foo' }); + + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getMediaCapabilities).mockReturnValue( + createMediaCapabilities({ canDownload: true }), + ); + const view = createView({ + queryResults: new MediaQueriesResults({ + results: [new ViewMedia('clip', 'camera-1')], + selectedIndex: 0, + }), + }); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); + expect(buttons).toContainEqual({ + icon: 'mdi:download', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Download', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'download' }, + }); + }); + + it('should not have download menu button when being casted', () => { + vi.stubGlobal('navigator', { + userAgent: + 'Mozilla/5.0 (Fuchsia) AppleWebKit/537.36 (KHTML, like Gecko) ' + + 'Chrome/114.0.0.0 Safari/537.36 CrKey/1.56.500000', + }); + + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getMediaCapabilities).mockReturnValue( + createMediaCapabilities({ canDownload: true }), + ); + const view = createView({ + queryResults: new MediaQueriesResults({ + results: [new ViewMedia('clip', 'camera-1')], + selectedIndex: 0, + }), + }); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); + expect(buttons).not.toEqual( + expect.arrayContaining([expect.objectContaining({ title: 'Download' })]), + ); + }); + + it('should have camera UI button', () => { + const buttons = calculateButtons(controller, { + showCameraUIButton: true, + }); + expect(buttons).toContainEqual({ + icon: 'mdi:web', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Camera user interface', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'camera_ui' }, + }); + }); + + it('should have microphone button', () => { + const microphoneManager = new MicrophoneManager(createCardAPI()); + const buttons = calculateButtons(controller, { + microphoneManager: microphoneManager, + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supports2WayAudio: true, + }, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:microphone', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Microphone', + style: { + animation: 'pulse 3s infinite', + color: 'var(--error-color, white)', + }, + start_tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'microphone_unmute', + }, + end_tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'microphone_mute', + }, + }); + }); + + it('should not have microphone button when media does not support it', () => { + const microphoneManager = new MicrophoneManager(createCardAPI()); + const buttons = calculateButtons(controller, { + microphoneManager: microphoneManager, + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supports2WayAudio: false, + }, + }), + }); + + expect(buttons).not.toEqual( + expect.arrayContaining([expect.objectContaining({ title: 'Microphone' })]), + ); + }); + + it('should have microphone button when microphone forbidden', () => { + const microphoneManager = new MicrophoneManager(createCardAPI()); + mock(microphoneManager).isForbidden.mockReturnValue(true); + const buttons = calculateButtons(controller, { + microphoneManager: microphoneManager, + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supports2WayAudio: true, + }, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:microphone-message-off', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Microphone', + style: {}, + }); + }); + + it('should have microphone button when microphone muted', () => { + const microphoneManager = new MicrophoneManager(createCardAPI()); + mock(microphoneManager).isMuted.mockReturnValue(true); + const buttons = calculateButtons(controller, { + microphoneManager: microphoneManager, + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supports2WayAudio: true, + }, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:microphone-off', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Microphone', + style: {}, + start_tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'microphone_unmute', + }, + end_tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'microphone_mute', + }, + }); + }); + + it('should have microphone button when microphone muted with toggle type', () => { + const microphoneManager = new MicrophoneManager(createCardAPI()); + mock(microphoneManager).isMuted.mockReturnValue(true); + const buttons = calculateButtons(controller, { + microphoneManager: microphoneManager, + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supports2WayAudio: true, + }, + }), + config: createConfig({ + menu: { buttons: { microphone: { type: 'toggle' } } }, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:microphone-off', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Microphone', + style: {}, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'microphone_unmute', + }, + }); + }); + + it('should have microphone button when microphone unmuted with toggle type', () => { + const microphoneManager = new MicrophoneManager(createCardAPI()); + mock(microphoneManager).isMuted.mockReturnValue(false); + const buttons = calculateButtons(controller, { + microphoneManager: microphoneManager, + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supports2WayAudio: true, + }, + }), + config: createConfig({ + menu: { buttons: { microphone: { type: 'toggle' } } }, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:microphone', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Microphone', + style: { + animation: 'pulse 3s infinite', + color: 'var(--error-color, white)', + }, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'microphone_mute', + }, + }); + }); + + it('should have fullscreen button', () => { + // Need to write a readonly property. + vi.stubGlobal('navigator', { userAgent: 'foo' }); + const buttons = calculateButtons(controller, { inFullscreenMode: false }); + + expect(buttons).toContainEqual({ + icon: 'mdi:fullscreen', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Fullscreen', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' }, + style: {}, + }); + }); + + it('should have unfullscreen', () => { + vi.stubGlobal('navigator', { userAgent: 'foo' }); + const buttons = calculateButtons(controller, { inFullscreenMode: true }); + + expect(buttons).toContainEqual({ + icon: 'mdi:fullscreen-exit', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Fullscreen', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' }, + style: { color: 'var(--primary-color, white)' }, + }); + }); + + it('should have expand button', () => { + const buttons = calculateButtons(controller, { inExpandedMode: false }); + + expect(buttons).toContainEqual({ + icon: 'mdi:arrow-expand-all', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Expand', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'expand' }, + style: {}, + }); + }); + + it('should have unexpand button', () => { + const buttons = calculateButtons(controller, { inExpandedMode: true }); + + expect(buttons).toContainEqual({ + icon: 'mdi:arrow-collapse-all', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Expand', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'expand' }, + style: { color: 'var(--primary-color, white)' }, + }); + }); + + it('should have media players button', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ + camera_entity: 'camera.1', + }), + }, + ]), + ); + + const mediaPlayerController = mock(); + mediaPlayerController.hasMediaPlayers.mockReturnValue(true); + mediaPlayerController.getMediaPlayers.mockReturnValue(['media_player.tv']); + + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + mediaPlayerController: mediaPlayerController, + hass: createHASS({ + 'media_player.tv': createStateEntity({ entity_id: 'media_player.tv' }), + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:cast', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-submenu', + title: 'Send to media player', + items: [ + { + enabled: true, + selected: false, + icon: 'mdi:cast', + entity: 'media_player.tv', + state_color: false, + title: 'media_player.tv', + disabled: false, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'media_player', + media_player: 'media_player.tv', + media_player_action: 'play', + }, + hold_action: { + action: 'fire-dom-event', + frigate_card_action: 'media_player', + media_player: 'media_player.tv', + media_player_action: 'stop', + }, + }, + ], + }); + }); + + it('should disable media players button when entity not found', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ + camera_entity: 'camera.1', + }), + }, + ]), + ); + const mediaPlayerController = mock(); + mediaPlayerController.hasMediaPlayers.mockReturnValue(true); + mediaPlayerController.getMediaPlayers.mockReturnValue(['not_a_real_player']); + + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + mediaPlayerController: mediaPlayerController, + hass: createHASS(), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:cast', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-submenu', + title: 'Send to media player', + items: [ + { + enabled: true, + selected: false, + icon: 'mdi:bookmark', + entity: 'not_a_real_player', + state_color: false, + title: 'not_a_real_player', + disabled: true, + }, + ], + }); + }); + + it('should have pause button', () => { + const player = mock(); + const buttons = calculateButtons(controller, { + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supportsPause: true, + }, + player: player, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:pause', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Play / Pause', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'pause' }, + }); + }); + + it('should have play button', () => { + const player = mock(); + player.isPaused.mockReturnValue(true); + const buttons = calculateButtons(controller, { + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supportsPause: true, + }, + player: player, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:play', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Play / Pause', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'play' }, + }); + }); + + it('should have mute button', () => { + const player = mock(); + const buttons = calculateButtons(controller, { + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + hasAudio: true, + }, + player: player, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:volume-high', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Mute / Unmute', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'mute' }, + }); + }); + + it('should have unmute button', () => { + const player = mock(); + player.isMuted.mockReturnValue(true); + const buttons = calculateButtons(controller, { + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + hasAudio: true, + }, + player: player, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:volume-off', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Mute / Unmute', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'unmute' }, + }); + }); + + it('should have screenshot button', () => { + const buttons = calculateButtons(controller, { + currentMediaLoadedInfo: createMediaLoadedInfo({ + player: mock(), + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:monitor-screenshot', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Screenshot', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'screenshot' }, + }); + }); + + describe('should have grid button when display mode is', () => { + it.each([['single' as const], ['grid' as const]])( + '%s', + (displayMode: ViewDisplayMode) => { + const view = createView({ view: 'live', displayMode: displayMode }); + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([{ cameraID: 'camera-1' }, { cameraID: 'camera-2' }]), + ); + expect( + calculateButtons(controller, { cameraManager: cameraManager, view: view }), + ).toContainEqual({ + icon: displayMode === 'single' ? 'mdi:grid' : 'mdi:grid-off', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: + displayMode === 'grid' + ? 'Show single media viewer' + : 'Show media viewer for each camera in a grid', + style: displayMode === 'grid' ? { color: 'var(--primary-color, white)' } : {}, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'display_mode_select', + display_mode: displayMode === 'single' ? 'grid' : 'single', + }, + }); + }, + ); + }); + + describe('should have show ptz button', () => { + it('when the selected camera is not PTZ enabled', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( + createCameraCapabilities(), + ); + + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).not.toContainEqual({ + enabled: false, + icon: 'mdi:pan', + priority: 50, + style: { + color: 'var(--primary-color, white)', + }, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'show_ptz', + show_ptz: false, + }, + title: 'Show PTZ controls', + type: 'custom:frigate-card-menu-icon', + }); + }); + + it('when the selected camera is PTZ enabled', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( + createCameraCapabilities({ ptz: {} }), + ); + + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).toContainEqual({ + enabled: false, + icon: 'mdi:pan', + priority: 50, + style: { + color: 'var(--primary-color, white)', + }, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'show_ptz', + show_ptz: false, + }, + title: 'Show PTZ controls', + type: 'custom:frigate-card-menu-icon', + }); + }); + + it('when the context has PTZ visiblity turned off', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( + createCameraCapabilities({ ptz: {} }), + ); + const view = createView({ + camera: 'camera-1', + context: { live: { ptzVisible: false } }, + }); + + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); + expect(buttons).toContainEqual({ + enabled: false, + icon: 'mdi:pan', + priority: 50, + style: {}, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'show_ptz', + show_ptz: true, + }, + title: 'Show PTZ controls', + type: 'custom:frigate-card-menu-icon', + }); + }); + }); + + it('should handle dynamic buttons', () => { + const button: MenuItem = { + ...dynamicButton, + style: {}, + }; + controller.addDynamicMenuButton(button); + expect( + calculateButtons(controller).filter((menuButton) => isEqual(button, menuButton)) + .length, + ).toBe(1); + + // Adding it again will have no effect. + controller.addDynamicMenuButton(button); + expect( + calculateButtons(controller).filter((menuButton) => isEqual(button, menuButton)) + .length, + ).toBe(1); + + controller.removeDynamicMenuButton(button); + expect(calculateButtons(controller)).not.toContainEqual(button); + }); + + it('should not set style for dynamic button with stock action', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: { action: 'navigate', navigation_path: 'foo' }, + }; + controller.addDynamicMenuButton(button); + + expect(calculateButtons(controller)).toContainEqual({ + ...button, + style: {}, + }); + }); + + it('should not set style for dynamic button with non-Frigate fire-dom-event action', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: { action: 'fire-dom-event' }, + }; + controller.addDynamicMenuButton(button); + + controller.addDynamicMenuButton(dynamicButton); + expect(calculateButtons(controller)).toContainEqual({ + ...button, + style: {}, + }); + }); + + it('should set style for dynamic button with Frigate view action', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' }, + }; + + const view = createView({ view: 'clips' }); + controller.addDynamicMenuButton(button); + expect(calculateButtons(controller, { view: view })).toContainEqual({ + ...button, + style: { color: 'var(--primary-color, white)' }, + }); + }); + + it('should set style for dynamic button with Frigate default action', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'default' }, + }; + + controller.addDynamicMenuButton(button); + expect(calculateButtons(controller)).toContainEqual({ + ...button, + style: { color: 'var(--primary-color, white)' }, + }); + }); + + it('should set style for dynamic button with fullscreen action', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' }, + }; + + controller.addDynamicMenuButton(button); + expect(calculateButtons(controller, { inFullscreenMode: true })).toContainEqual({ + ...button, + style: { color: 'var(--primary-color, white)' }, + }); + }); + + it('should set style for dynamic button with camera_select action', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + camera: 'foo', + }, + }; + + const view = createView({ camera: 'foo' }); + controller.addDynamicMenuButton(button); + expect(calculateButtons(controller, { view: view })).toContainEqual({ + ...button, + style: { color: 'var(--primary-color, white)' }, + }); + }); + + it('should set style for dynamic button with array of actions', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: [ + { action: 'fire-dom-event' }, + { action: 'fire-dom-event', frigate_card_action: 'clips' }, + ], + }; + + const view = createView({ camera: 'clips' }); + controller.addDynamicMenuButton(button); + expect(calculateButtons(controller, { view: view })).toContainEqual({ + ...button, + style: {}, + }); + }); +}); diff --git a/tests/components-lib/menu-controller.test.ts b/tests/components-lib/menu-controller.test.ts index b5de796b..163e621b 100644 --- a/tests/components-lib/menu-controller.test.ts +++ b/tests/components-lib/menu-controller.test.ts @@ -1,1351 +1,499 @@ -import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import isEqual from 'lodash-es/isEqual'; +import { + HASSDomEvent, + handleActionConfig, +} from '@dermotduffy/custom-card-helpers'; +import { LitElement } from 'lit'; import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { mock } from 'vitest-mock-extended'; -import { CameraManager } from '../../src/camera-manager/manager'; -import { CameraManagerCameraMetadata } from '../../src/camera-manager/types'; -import { MediaPlayerManager } from '../../src/card-controller/media-player-manager'; -import { MicrophoneManager } from '../../src/card-controller/microphone-manager'; -import { - MenuButtonController, - MenuButtonControllerOptions, -} from '../../src/components-lib/menu-controller'; -import { FrigateCardConfig, MenuItem, ViewDisplayMode } from '../../src/config/types'; -import { FrigateCardMediaPlayer } from '../../src/types'; -import { createFrigateCardSimpleAction } from '../../src/utils/action'; -import { ViewMedia } from '../../src/view/media'; -import { MediaQueriesResults } from '../../src/view/media-queries-results'; -import { View } from '../../src/view/view'; -import { - createAggregateCameraCapabilities, - createCameraCapabilities, - createCameraConfig, - createCameraManager, - createCardAPI, - createConfig, - createHASS, - createMediaCapabilities, - createMediaLoadedInfo, - createStateEntity, - createStore, - createView, -} from '../test-utils'; +import { FRIGATE_ICON_SVG_PATH } from '../../src/camera-manager/frigate/icon'; +import { MenuController } from '../../src/components-lib/menu-controller'; +import { ActionsConfig, MenuConfig, menuConfigSchema } from '../../src/config/types'; +import { StateParameters } from '../../src/types'; +import { refreshDynamicStateParameters } from '../../src/utils/ha'; +import { createHASS } from '../test-utils'; -vi.mock('../../src/utils/media-player-controller.js'); -vi.mock('../../src/card-controller/microphone-manager.js'); +vi.mock('@dermotduffy/custom-card-helpers'); +vi.mock('../../src/utils/ha'); -const calculateButtons = ( - controller: MenuButtonController, - options?: MenuButtonControllerOptions & { - hass?: HomeAssistant; - config?: FrigateCardConfig; - cameraManager?: CameraManager; - view?: View; - }, -): MenuItem[] => { - let cameraManager: CameraManager | null = options?.cameraManager ?? null; - if (!cameraManager) { - cameraManager = createCameraManager(); - } +const createHost = (): LitElement => { + const host = document.createElement('div') as unknown as LitElement; + host.requestUpdate = vi.fn(); + return host; +}; - return controller.calculateButtons( - options?.hass ?? createHASS(), - options?.config ?? createConfig(), - cameraManager, - options?.view ?? createView({ camera: 'camera-1' }), - options, - ); +const createMenuConfig = (config: unknown): MenuConfig => { + return menuConfigSchema.parse(config); +}; + +const createEvent = ( + action: string, + config?: ActionsConfig, +): HASSDomEvent<{ action: string; config?: ActionsConfig }> => { + return new CustomEvent<{ action: string; config?: ActionsConfig }>('@action', { + detail: { + action: action, + config: config, + }, + }); }; // @vitest-environment jsdom -describe('MenuButtonController', () => { - let controller: MenuButtonController; - const dynamicButton: MenuItem = { - type: 'custom:frigate-card-menu-icon', - icon: 'mdi:alpha-a-circle', - title: 'Dynamic button', +describe('MenuController', () => { + const action = { + action: 'fire-dom-event' as const, + }; + const menuToggleAction = { + action: 'fire-dom-event' as const, + frigate_card_action: 'menu_toggle' as const, + }; + const tapActionConfig = { + camera_entity: 'foo', + tap_action: action, + }; + const tapActionConfigMulti = { + camera_entity: 'foo', + tap_action: [action, action, action], }; beforeEach(() => { - vi.resetAllMocks(); - controller = new MenuButtonController(); + vi.clearAllMocks(); }); - it('should have frigate menu button with hidden menu style', () => { - const buttons = calculateButtons(controller); - expect(buttons).toContainEqual({ - icon: 'frigate', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Frigate menu / Default view', - tap_action: createFrigateCardSimpleAction('menu_toggle'), - hold_action: createFrigateCardSimpleAction('diagnostics'), + it('should set and get menu config', () => { + const host = createHost(); + const controller = new MenuController(host); + + const config = createMenuConfig({ + button_size: 21, + style: 'hover', + position: 'left', + alignment: 'top', }); + controller.setMenuConfig(config); + expect(controller.getMenuConfig()).toBe(config); + + expect(host.style.getPropertyValue('--frigate-card-menu-button-size')).toBe('21px'); + expect(host.getAttribute('data-style')).toBe('hover'); + expect(host.getAttribute('data-position')).toBe('left'); + expect(host.getAttribute('data-alignment')).toBe('top'); }); - it('should have frigate menu button without hidden menu style', () => { - const buttons = calculateButtons(controller, { - config: createConfig({ menu: { style: 'overlay' } }), - }); - expect(buttons).toContainEqual({ - icon: 'frigate', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Frigate menu / Default view', - tap_action: createFrigateCardSimpleAction('default'), - hold_action: createFrigateCardSimpleAction('diagnostics'), - }); - }); - - it('should have cameras menu', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([{ cameraID: 'camera-1' }, { cameraID: 'camera-2' }]), - ); - vi.mocked(cameraManager).getCameraMetadata.mockReturnValue({ - title: 'title', - icon: 'icon', - }); - - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - icon: 'mdi:video-switch', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-submenu', - title: 'Cameras', - items: [ + describe('should set and sort buttons', () => { + it('by priority', () => { + const controller = new MenuController(createHost()); + controller.setButtons([ { - enabled: true, - icon: 'icon', - entity: undefined, - state_color: true, - title: 'title', - selected: true, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'camera_select', - camera: 'camera-1', - }, - }, - { - enabled: true, - icon: 'icon', - entity: undefined, - state_color: true, - title: 'title', - selected: false, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'camera_select', - camera: 'camera-2', - }, - }, - ], - }); - }); - - it('should not have a cameras menu without a visible camera', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { cameraID: 'camera-1', config: createCameraConfig({ hide: true }) }, - ]), - ); - - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ - title: 'Cameras', - }), - ]), - ); - }); - - it('should have substream button with single dependency', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), - }, - { cameraID: 'camera-2' }, - ]), - ); - - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - icon: 'mdi:video-input-component', - style: {}, - title: 'Substream(s)', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_on', - }, - }); - }); - - it('should have substream button selected with single dependency', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), - }, - { cameraID: 'camera-2' }, - ]), - ); - - const view = createView({ - camera: 'camera-1', - context: { - live: { - overrides: new Map([['camera-1', 'camera-2']]), - }, - }, - }); - - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: view, - }); - expect(buttons).toContainEqual({ - icon: 'mdi:video-input-component', - style: { color: 'var(--primary-color, white)' }, - title: 'Substream(s)', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_off', - }, - }); - }); - - it('should have substream menu without substream on with multiple dependencies', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ - camera_entity: 'camera.1', - dependencies: { cameras: ['camera-2', 'camera-3'] }, - }), - }, - { - cameraID: 'camera-2', - config: createCameraConfig({ - camera_entity: 'camera.2', - }), - }, - { - cameraID: 'camera-3', - config: createCameraConfig({ - camera_entity: 'camera.3', - }), - }, - ]), - ); - - // Return different metadata depending on the camera to test multiple code - // paths. - mock(cameraManager).getCameraMetadata.mockImplementation( - (cameraID: string): CameraManagerCameraMetadata | null => { - return cameraID === 'camera-1' - ? { - title: 'title', - icon: 'icon', - } - : null; - }, - ); - - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - icon: 'mdi:video-input-component', - title: 'Substream(s)', - style: {}, - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-submenu', - items: [ - { - enabled: true, - icon: 'icon', - entity: 'camera.1', - state_color: true, - title: 'title', - selected: true, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_select', - camera: 'camera-1', - }, - }, - { - enabled: true, - icon: undefined, - entity: 'camera.2', - state_color: true, - title: undefined, - selected: false, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_select', - camera: 'camera-2', - }, - }, - { - enabled: true, - icon: undefined, - entity: 'camera.3', - state_color: true, - title: undefined, - selected: false, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_select', - camera: 'camera-3', - }, - }, - ], - }); - }); - - it('should have substream menu with substream on with multiple dependencies', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ - camera_entity: 'camera.1', - dependencies: { cameras: ['camera-2', 'camera-3'] }, - }), - }, - { - cameraID: 'camera-2', - config: createCameraConfig({ - camera_entity: 'camera.2', - }), - }, - { - cameraID: 'camera-3', - config: createCameraConfig({ - camera_entity: 'camera.3', - }), - }, - ]), - ); - - const view = createView({ - camera: 'camera-1', - context: { - live: { - overrides: new Map([['camera-1', 'camera-2']]), - }, - }, - }); - - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: view, - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:video-input-component', - title: 'Substream(s)', - style: { color: 'var(--primary-color, white)' }, - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-submenu', - items: [ - { - enabled: true, - icon: undefined, - entity: 'camera.1', - state_color: true, - title: undefined, - selected: false, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_select', - camera: 'camera-1', - }, - }, - { - enabled: true, - icon: undefined, - entity: 'camera.2', - state_color: true, - title: undefined, - // camera-2 is selected in this test scenario because of the view - // override. - selected: true, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_select', - camera: 'camera-2', - }, - }, - { - enabled: true, - icon: undefined, - entity: 'camera.3', - state_color: true, - title: undefined, - selected: false, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_select', - camera: 'camera-3', - }, - }, - ], - }); - }); - - it('should have styled live menu button in live view', () => { - const buttons = calculateButtons(controller); - expect(buttons).toContainEqual({ - icon: 'mdi:cctv', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Live view', - style: { color: 'var(--primary-color, white)' }, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'live' }, - }); - }); - - it('should have unstyled live menu button in non-live views', () => { - const view = createView({ view: 'clips' }); - const buttons = calculateButtons(controller, { view: view }); - expect(buttons).toContainEqual({ - icon: 'mdi:cctv', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Live view', - style: {}, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'live' }, - }); - }); - - it('should have styled clips menu button in clips view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsClips: true }), - ); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: createView({ view: 'clips' }), - }); - expect(buttons).toContainEqual({ - icon: 'mdi:filmstrip', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Clips gallery', - style: { color: 'var(--primary-color, white)' }, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' }, - hold_action: { action: 'fire-dom-event', frigate_card_action: 'clip' }, - }); - }); - - it('should have unstyled clips menu button in non-clips view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsClips: true }), - ); - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - icon: 'mdi:filmstrip', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Clips gallery', - style: {}, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' }, - hold_action: { action: 'fire-dom-event', frigate_card_action: 'clip' }, - }); - }); - - it('should have styled snapshots menu button in snapshots view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsSnapshots: true }), - ); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: createView({ view: 'snapshots' }), - }); - expect(buttons).toContainEqual({ - icon: 'mdi:camera', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Snapshots gallery', - style: { color: 'var(--primary-color, white)' }, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'snapshots' }, - hold_action: { action: 'fire-dom-event', frigate_card_action: 'snapshot' }, - }); - }); - - it('should have unstyled snapshots menu button in non-snapshots view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsSnapshots: true }), - ); - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - icon: 'mdi:camera', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Snapshots gallery', - style: {}, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'snapshots' }, - hold_action: { action: 'fire-dom-event', frigate_card_action: 'snapshot' }, - }); - }); - - it('should have styled recordings menu button in recordings view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsRecordings: true }), - ); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: createView({ view: 'recordings' }), - }); - expect(buttons).toContainEqual({ - icon: 'mdi:album', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Recordings gallery', - style: { color: 'var(--primary-color, white)' }, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'recordings' }, - hold_action: { action: 'fire-dom-event', frigate_card_action: 'recording' }, - }); - }); - - it('should have unstyled recordings menu button in non-recordings view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsRecordings: true }), - ); - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - icon: 'mdi:album', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Recordings gallery', - style: {}, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'recordings' }, - hold_action: { action: 'fire-dom-event', frigate_card_action: 'recording' }, - }); - }); - - it('should have styled image menu button in image view', () => { - const buttons = calculateButtons(controller, { - view: createView({ view: 'image' }), - }); - expect(buttons).toContainEqual({ - icon: 'mdi:image', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Static image', - style: { color: 'var(--primary-color, white)' }, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'image' }, - }); - }); - - it('should have unstyled image menu button in non-image view', () => { - const buttons = calculateButtons(controller); - expect(buttons).toContainEqual({ - icon: 'mdi:image', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Static image', - style: {}, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'image' }, - }); - }); - - it('should have styled timeline menu button in timeline view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsTimeline: true }), - ); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: createView({ view: 'timeline' }), - }); - expect(buttons).toContainEqual({ - icon: 'mdi:chart-gantt', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Timeline view', - style: { color: 'var(--primary-color, white)' }, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'timeline' }, - }); - }); - - it('should have unstyled timeline menu button in non-timeline view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsTimeline: true }), - ); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - }); - expect(buttons).toContainEqual({ - icon: 'mdi:chart-gantt', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Timeline view', - style: {}, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'timeline' }, - }); - }); - - it('should have download menu button', () => { - vi.stubGlobal('navigator', { userAgent: 'foo' }); - - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getMediaCapabilities).mockReturnValue( - createMediaCapabilities({ canDownload: true }), - ); - const view = createView({ - queryResults: new MediaQueriesResults({ - results: [new ViewMedia('clip', 'camera-1')], - selectedIndex: 0, - }), - }); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: view, - }); - expect(buttons).toContainEqual({ - icon: 'mdi:download', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Download', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'download' }, - }); - }); - - it('should not have download menu button when being casted', () => { - vi.stubGlobal('navigator', { - userAgent: - 'Mozilla/5.0 (Fuchsia) AppleWebKit/537.36 (KHTML, like Gecko) ' + - 'Chrome/114.0.0.0 Safari/537.36 CrKey/1.56.500000', - }); - - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getMediaCapabilities).mockReturnValue( - createMediaCapabilities({ canDownload: true }), - ); - const view = createView({ - queryResults: new MediaQueriesResults({ - results: [new ViewMedia('clip', 'camera-1')], - selectedIndex: 0, - }), - }); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: view, - }); - expect(buttons).not.toEqual( - expect.arrayContaining([expect.objectContaining({ title: 'Download' })]), - ); - }); - - it('should have camera UI button', () => { - const buttons = calculateButtons(controller, { - showCameraUIButton: true, - }); - expect(buttons).toContainEqual({ - icon: 'mdi:web', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Camera user interface', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'camera_ui' }, - }); - }); - - it('should have microphone button', () => { - const microphoneManager = new MicrophoneManager(createCardAPI()); - const buttons = calculateButtons(controller, { - microphoneManager: microphoneManager, - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supports2WayAudio: true, - }, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:microphone', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Microphone', - style: { - animation: 'pulse 3s infinite', - color: 'var(--error-color, white)', - }, - start_tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'microphone_unmute', - }, - end_tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'microphone_mute', - }, - }); - }); - - it('should not have microphone button when media does not support it', () => { - const microphoneManager = new MicrophoneManager(createCardAPI()); - const buttons = calculateButtons(controller, { - microphoneManager: microphoneManager, - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supports2WayAudio: false, - }, - }), - }); - - expect(buttons).not.toEqual( - expect.arrayContaining([expect.objectContaining({ title: 'Microphone' })]), - ); - }); - - it('should have microphone button when microphone forbidden', () => { - const microphoneManager = new MicrophoneManager(createCardAPI()); - mock(microphoneManager).isForbidden.mockReturnValue(true); - const buttons = calculateButtons(controller, { - microphoneManager: microphoneManager, - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supports2WayAudio: true, - }, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:microphone-message-off', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Microphone', - style: {}, - }); - }); - - it('should have microphone button when microphone muted', () => { - const microphoneManager = new MicrophoneManager(createCardAPI()); - mock(microphoneManager).isMuted.mockReturnValue(true); - const buttons = calculateButtons(controller, { - microphoneManager: microphoneManager, - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supports2WayAudio: true, - }, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:microphone-off', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Microphone', - style: {}, - start_tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'microphone_unmute', - }, - end_tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'microphone_mute', - }, - }); - }); - - it('should have microphone button when microphone muted with toggle type', () => { - const microphoneManager = new MicrophoneManager(createCardAPI()); - mock(microphoneManager).isMuted.mockReturnValue(true); - const buttons = calculateButtons(controller, { - microphoneManager: microphoneManager, - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supports2WayAudio: true, - }, - }), - config: createConfig({ - menu: { buttons: { microphone: { type: 'toggle' } } }, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:microphone-off', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Microphone', - style: {}, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'microphone_unmute', - }, - }); - }); - - it('should have microphone button when microphone unmuted with toggle type', () => { - const microphoneManager = new MicrophoneManager(createCardAPI()); - mock(microphoneManager).isMuted.mockReturnValue(false); - const buttons = calculateButtons(controller, { - microphoneManager: microphoneManager, - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supports2WayAudio: true, - }, - }), - config: createConfig({ - menu: { buttons: { microphone: { type: 'toggle' } } }, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:microphone', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Microphone', - style: { - animation: 'pulse 3s infinite', - color: 'var(--error-color, white)', - }, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'microphone_mute', - }, - }); - }); - - it('should have fullscreen button', () => { - // Need to write a readonly property. - vi.stubGlobal('navigator', { userAgent: 'foo' }); - const buttons = calculateButtons(controller, { inFullscreenMode: false }); - - expect(buttons).toContainEqual({ - icon: 'mdi:fullscreen', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Fullscreen', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' }, - style: {}, - }); - }); - - it('should have unfullscreen', () => { - vi.stubGlobal('navigator', { userAgent: 'foo' }); - const buttons = calculateButtons(controller, { inFullscreenMode: true }); - - expect(buttons).toContainEqual({ - icon: 'mdi:fullscreen-exit', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Fullscreen', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' }, - style: { color: 'var(--primary-color, white)' }, - }); - }); - - it('should have expand button', () => { - const buttons = calculateButtons(controller, { inExpandedMode: false }); - - expect(buttons).toContainEqual({ - icon: 'mdi:arrow-expand-all', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Expand', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'expand' }, - style: {}, - }); - }); - - it('should have unexpand button', () => { - const buttons = calculateButtons(controller, { inExpandedMode: true }); - - expect(buttons).toContainEqual({ - icon: 'mdi:arrow-collapse-all', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Expand', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'expand' }, - style: { color: 'var(--primary-color, white)' }, - }); - }); - - it('should have media players button', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ - camera_entity: 'camera.1', - }), - }, - ]), - ); - - const mediaPlayerController = mock(); - mediaPlayerController.hasMediaPlayers.mockReturnValue(true); - mediaPlayerController.getMediaPlayers.mockReturnValue(['media_player.tv']); - - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - mediaPlayerController: mediaPlayerController, - hass: createHASS({ - 'media_player.tv': createStateEntity({ entity_id: 'media_player.tv' }), - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:cast', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-submenu', - title: 'Send to media player', - items: [ - { - enabled: true, - selected: false, - icon: 'mdi:cast', - entity: 'media_player.tv', - state_color: false, - title: 'media_player.tv', - disabled: false, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'media_player', - media_player: 'media_player.tv', - media_player_action: 'play', - }, - hold_action: { - action: 'fire-dom-event', - frigate_card_action: 'media_player', - media_player: 'media_player.tv', - media_player_action: 'stop', - }, - }, - ], - }); - }); - - it('should disable media players button when entity not found', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ - camera_entity: 'camera.1', - }), - }, - ]), - ); - const mediaPlayerController = mock(); - mediaPlayerController.hasMediaPlayers.mockReturnValue(true); - mediaPlayerController.getMediaPlayers.mockReturnValue(['not_a_real_player']); - - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - mediaPlayerController: mediaPlayerController, - hass: createHASS(), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:cast', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-submenu', - title: 'Send to media player', - items: [ - { - enabled: true, - selected: false, - icon: 'mdi:bookmark', - entity: 'not_a_real_player', - state_color: false, - title: 'not_a_real_player', - disabled: true, - }, - ], - }); - }); - - it('should have pause button', () => { - const player = mock(); - const buttons = calculateButtons(controller, { - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supportsPause: true, - }, - player: player, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:pause', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Play / Pause', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'pause' }, - }); - }); - - it('should have play button', () => { - const player = mock(); - player.isPaused.mockReturnValue(true); - const buttons = calculateButtons(controller, { - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supportsPause: true, - }, - player: player, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:play', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Play / Pause', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'play' }, - }); - }); - - it('should have mute button', () => { - const player = mock(); - const buttons = calculateButtons(controller, { - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - hasAudio: true, - }, - player: player, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:volume-high', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Mute / Unmute', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'mute' }, - }); - }); - - it('should have unmute button', () => { - const player = mock(); - player.isMuted.mockReturnValue(true); - const buttons = calculateButtons(controller, { - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - hasAudio: true, - }, - player: player, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:volume-off', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Mute / Unmute', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'unmute' }, - }); - }); - - it('should have screenshot button', () => { - const buttons = calculateButtons(controller, { - currentMediaLoadedInfo: createMediaLoadedInfo({ - player: mock(), - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:monitor-screenshot', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Screenshot', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'screenshot' }, - }); - }); - - describe('should have grid button when display mode is', () => { - it.each([['single' as const], ['grid' as const]])( - '%s', - (displayMode: ViewDisplayMode) => { - const view = createView({ view: 'live', displayMode: displayMode }); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([{ cameraID: 'camera-1' }, { cameraID: 'camera-2' }]), - ); - expect( - calculateButtons(controller, { cameraManager: cameraManager, view: view }), - ).toContainEqual({ - icon: displayMode === 'single' ? 'mdi:grid' : 'mdi:grid-off', - enabled: true, - priority: 50, type: 'custom:frigate-card-menu-icon', - title: - displayMode === 'grid' - ? 'Show single media viewer' - : 'Show media viewer for each camera in a grid', - style: displayMode === 'grid' ? { color: 'var(--primary-color, white)' } : {}, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'display_mode_select', - display_mode: displayMode === 'single' ? 'grid' : 'single', - }, + icon: 'mdi:cow', + priority: 20, + alignment: 'matching', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:goat', + alignment: 'matching', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:chicken', + priority: 40, + alignment: 'matching', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:horse', + priority: 40, + alignment: 'matching', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:sheep', + priority: 30, + alignment: 'matching', + }, + ]); + + expect(controller.getButtons('matching')).toEqual([ + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:chicken', + priority: 40, + alignment: 'matching', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:horse', + priority: 40, + alignment: 'matching', + }, + { + alignment: 'matching', + icon: 'mdi:sheep', + priority: 30, + type: 'custom:frigate-card-menu-icon', + }, + { + alignment: 'matching', + icon: 'mdi:cow', + priority: 20, + type: 'custom:frigate-card-menu-icon', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:goat', + alignment: 'matching', + }, + ]); + }); + + it('with frigate button first', () => { + const controller = new MenuController(createHost()); + controller.setMenuConfig( + createMenuConfig({ + style: 'hidden', + }), + ); + controller.setExpanded(true); + controller.setButtons([ + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:cow', + priority: 100, + alignment: 'matching', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'frigate', + alignment: 'matching', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:sheep', + priority: 100, + alignment: 'matching', + }, + ]); + + expect(controller.getButtons('matching')).toEqual([ + { + type: 'custom:frigate-card-menu-icon', + icon: 'frigate', + alignment: 'matching', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:cow', + priority: 100, + alignment: 'matching', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:sheep', + priority: 100, + alignment: 'matching', + }, + ]); + }); + }); + + describe('should get buttons', () => { + it('with matching alignment', () => { + const controller = new MenuController(createHost()); + controller.setButtons([ + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:cow', + alignment: 'opposing', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:sheep', + alignment: 'matching', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:cow', + }, + ]); + + expect(controller.getButtons('matching')).toEqual([ + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:sheep', + alignment: 'matching', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:cow', + }, + ]); + }); + + it('with disabled buttons', () => { + const controller = new MenuController(createHost()); + controller.setButtons([ + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:cow', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:sheep', + enabled: false, + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:goat', + enabled: true, + }, + ]); + + expect(controller.getButtons('matching')).toEqual([ + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:cow', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:goat', + enabled: true, + }, + ]); + }); + + it('with hidden non-expanded menu', () => { + const controller = new MenuController(createHost()); + controller.setMenuConfig( + createMenuConfig({ + style: 'hidden', + }), + ); + + controller.setButtons([ + { + type: 'custom:frigate-card-menu-icon', + icon: 'frigate', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:sheep', + }, + ]); + + expect(controller.getButtons('matching')).toEqual([ + { + type: 'custom:frigate-card-menu-icon', + icon: 'frigate', + }, + ]); + + controller.toggleExpanded(); + + expect(controller.getButtons('matching')).toEqual([ + { + type: 'custom:frigate-card-menu-icon', + icon: 'frigate', + }, + { + type: 'custom:frigate-card-menu-icon', + icon: 'mdi:sheep', + }, + ]); + }); + }); + + describe('should get fresh button state', () => { + it('on state icon', () => { + const controller = new MenuController(createHost()); + const stateButton = { + type: 'custom:frigate-card-menu-state-icon' as const, + icon: 'mdi:sheep', + entity: 'switch.foo', + state_color: true, + }; + + const stateParameters: StateParameters = {}; + vi.mocked(refreshDynamicStateParameters).mockReturnValue(stateParameters); + + expect(controller.getFreshButtonState(createHASS(), stateButton)).toBe( + stateParameters, + ); + + expect(vi.mocked(refreshDynamicStateParameters)).toBeCalled(); + }); + + it('on non state icon', () => { + const controller = new MenuController(createHost()); + const button = { + type: 'custom:frigate-card-menu-icon' as const, + icon: 'mdi:sheep', + }; + + expect(controller.getFreshButtonState(createHASS(), button)).toEqual(button); + expect(vi.mocked(refreshDynamicStateParameters)).not.toBeCalled(); + }); + }); + + describe('should get svg path', () => { + it('frigate icon', () => { + const controller = new MenuController(createHost()); + const button = { + type: 'custom:frigate-card-menu-icon' as const, + icon: 'frigate', + }; + expect(controller.getSVGPath(button)).toEqual(FRIGATE_ICON_SVG_PATH); + }); + + it('non-frigate icon', () => { + const controller = new MenuController(createHost()); + const button = { + type: 'custom:frigate-card-menu-icon' as const, + icon: 'mdi:cow', + }; + expect(controller.getSVGPath(button)).toBeFalsy(); + }); + }); + + describe('should handle actions', () => { + it('should bail without config', () => { + const controller = new MenuController(createHost()); + controller.actionHandler(createHASS(), createEvent('tap')); + expect(vi.mocked(handleActionConfig)).not.toBeCalled(); + }); + + it('should execute simple action in non-hidden menu', () => { + const host = createHost(); + const hass = createHASS(); + const controller = new MenuController(host); + + controller.actionHandler(hass, createEvent('tap'), tapActionConfig); + expect(vi.mocked(handleActionConfig)).toBeCalledWith( + host, + hass, + tapActionConfig, + action, + ); + + expect(controller.isExpanded()).toBeFalsy(); + }); + + it('should execute simple action in with config in event', () => { + const host = createHost(); + const hass = createHASS(); + const controller = new MenuController(host); + + controller.actionHandler(hass, createEvent('tap', tapActionConfig)); + expect(vi.mocked(handleActionConfig)).toBeCalledWith( + host, + hass, + tapActionConfig, + action, + ); + }); + + it('should execute simple array of actions in non-hidden menu', () => { + const host = createHost(); + const hass = createHASS(); + const controller = new MenuController(host); + + controller.actionHandler(hass, createEvent('tap'), tapActionConfigMulti); + expect(vi.mocked(handleActionConfig)).toBeCalledTimes(3); + }); + + describe('should close menu', () => { + it('tap', () => { + const host = createHost(); + const hass = createHASS(); + const controller = new MenuController(host); + controller.setMenuConfig( + createMenuConfig({ + style: 'hidden', + }), + ); + + controller.setExpanded(true); + expect(controller.isExpanded()).toBeTruthy(); + + controller.actionHandler(hass, createEvent('tap'), tapActionConfig); + expect(controller.isExpanded()).toBeFalsy(); + }); + + it('end_tap', () => { + const host = createHost(); + const hass = createHASS(); + const controller = new MenuController(host); + controller.setMenuConfig( + createMenuConfig({ + style: 'hidden', + }), + ); + + controller.setExpanded(true); + expect(controller.isExpanded()).toBeTruthy(); + + controller.actionHandler(hass, createEvent('end_tap'), { + end_tap_action: action, }); - }, - ); - }); - - describe('should have show ptz button', () => { - it('when the selected camera is not PTZ enabled', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( - createCameraCapabilities(), - ); - - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).not.toContainEqual({ - enabled: false, - icon: 'mdi:pan', - priority: 50, - style: { - color: 'var(--primary-color, white)', - }, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'show_ptz', - show_ptz: false, - }, - title: 'Show PTZ controls', - type: 'custom:frigate-card-menu-icon', + expect(controller.isExpanded()).toBeFalsy(); }); }); - it('when the selected camera is PTZ enabled', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( - createCameraCapabilities({ ptz: {} }), - ); + describe('should not close menu', () => { + it('start_tap with later action', () => { + const host = createHost(); + const hass = createHASS(); + const controller = new MenuController(host); + controller.setMenuConfig( + createMenuConfig({ + style: 'hidden', + }), + ); - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - enabled: false, - icon: 'mdi:pan', - priority: 50, - style: { - color: 'var(--primary-color, white)', - }, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'show_ptz', - show_ptz: false, - }, - title: 'Show PTZ controls', - type: 'custom:frigate-card-menu-icon', - }); - }); + controller.setExpanded(true); + expect(controller.isExpanded()).toBeTruthy(); - it('when the context has PTZ visiblity turned off', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( - createCameraCapabilities({ ptz: {} }), - ); - const view = createView({ - camera: 'camera-1', - context: { live: { ptzVisible: false } }, + controller.actionHandler(hass, createEvent('start_tap'), { + start_tap_action: action, + end_tap_action: action, + }); + expect(controller.isExpanded()).toBeTruthy(); }); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: view, + it('with a menu toggle action', () => { + const host = createHost(); + const hass = createHASS(); + const controller = new MenuController(host); + controller.setMenuConfig( + createMenuConfig({ + style: 'hidden', + }), + ); + + controller.setExpanded(false); + expect(controller.isExpanded()).toBeFalsy(); + + controller.actionHandler(hass, createEvent('tap'), { + camera_entity: 'foo', + tap_action: menuToggleAction, + }); + expect(controller.isExpanded()).toBeTruthy(); }); - expect(buttons).toContainEqual({ - enabled: false, - icon: 'mdi:pan', - priority: 50, - style: {}, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'show_ptz', - show_ptz: true, - }, - title: 'Show PTZ controls', - type: 'custom:frigate-card-menu-icon', + + it('when no action is actually taken', () => { + const host = createHost(); + const hass = createHASS(); + const controller = new MenuController(host); + controller.setMenuConfig( + createMenuConfig({ + style: 'hidden', + }), + ); + + controller.setExpanded(true); + expect(controller.isExpanded()).toBeTruthy(); + + controller.actionHandler(hass, createEvent('end_tap'), tapActionConfig); + expect(controller.isExpanded()).toBeTruthy(); }); }); }); - - it('should handle dynamic buttons', () => { - const button: MenuItem = { - ...dynamicButton, - style: {}, - }; - controller.addDynamicMenuButton(button); - expect( - calculateButtons(controller).filter((menuButton) => isEqual(button, menuButton)) - .length, - ).toBe(1); - - // Adding it again will have no effect. - controller.addDynamicMenuButton(button); - expect( - calculateButtons(controller).filter((menuButton) => isEqual(button, menuButton)) - .length, - ).toBe(1); - - controller.removeDynamicMenuButton(button); - expect(calculateButtons(controller)).not.toContainEqual(button); - }); - - it('should not set style for dynamic button with stock action', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: { action: 'navigate', navigation_path: 'foo' }, - }; - controller.addDynamicMenuButton(button); - - expect(calculateButtons(controller)).toContainEqual({ - ...button, - style: {}, - }); - }); - - it('should not set style for dynamic button with non-Frigate fire-dom-event action', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: { action: 'fire-dom-event' }, - }; - controller.addDynamicMenuButton(button); - - controller.addDynamicMenuButton(dynamicButton); - expect(calculateButtons(controller)).toContainEqual({ - ...button, - style: {}, - }); - }); - - it('should set style for dynamic button with Frigate view action', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' }, - }; - - const view = createView({ view: 'clips' }); - controller.addDynamicMenuButton(button); - expect(calculateButtons(controller, { view: view })).toContainEqual({ - ...button, - style: { color: 'var(--primary-color, white)' }, - }); - }); - - it('should set style for dynamic button with Frigate default action', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'default' }, - }; - - controller.addDynamicMenuButton(button); - expect(calculateButtons(controller)).toContainEqual({ - ...button, - style: { color: 'var(--primary-color, white)' }, - }); - }); - - it('should set style for dynamic button with fullscreen action', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' }, - }; - - controller.addDynamicMenuButton(button); - expect(calculateButtons(controller, { inFullscreenMode: true })).toContainEqual({ - ...button, - style: { color: 'var(--primary-color, white)' }, - }); - }); - - it('should set style for dynamic button with camera_select action', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'camera_select', - camera: 'foo', - }, - }; - - const view = createView({ camera: 'foo' }); - controller.addDynamicMenuButton(button); - expect(calculateButtons(controller, { view: view })).toContainEqual({ - ...button, - style: { color: 'var(--primary-color, white)' }, - }); - }); - - it('should set style for dynamic button with array of actions', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: [ - { action: 'fire-dom-event' }, - { action: 'fire-dom-event', frigate_card_action: 'clips' }, - ], - }; - - const view = createView({ camera: 'clips' }); - controller.addDynamicMenuButton(button); - expect(calculateButtons(controller, { view: view })).toContainEqual({ - ...button, - style: {}, - }); - }); }); diff --git a/vite.config.ts b/vite.config.ts index 5f1aa02a..197f27f1 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,10 +10,10 @@ export default defineConfig({ // Thresholds will automatically be updated as coverage improves to avoid // back-sliding. thresholdAutoUpdate: true, - statements: 72.2, - branches: 61.18, - functions: 73.47, - lines: 72.09, + statements: 72.66, + branches: 61.9, + functions: 73.96, + lines: 72.56, }, }, }); From 229530420d20b2656d7e485e39b29158d6b73460 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Fri, 2 Feb 2024 18:25:15 -0800 Subject: [PATCH 082/189] Fix StyleInfo typing. --- src/config/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config/types.ts b/src/config/types.ts index 0fd907a4..19b87484 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -326,7 +326,7 @@ const actionsSchema = z.object({ }); const elementsBaseSchema = actionsBaseSchema.extend({ - style: z.record(z.string().nullable()).optional(), + style: z.record(z.string().nullable().or(z.undefined())).optional(), title: z.string().nullable().optional(), }); From a4108b73c56ee0d4acd06e4739e708e2658f10bd Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Fri, 2 Feb 2024 20:32:53 -0800 Subject: [PATCH 083/189] Allow microphone state to be used in conditions. --- README.md | 13 ++++ src/card-controller/card-element-manager.ts | 1 + src/card-controller/conditions-manager.ts | 9 +++ src/card-controller/microphone-manager.ts | 19 ++++- src/card-controller/types.ts | 2 + src/config/types.ts | 9 ++- .../card-element-manager.test.ts | 1 + .../conditions-manager.test.ts | 76 ++++++++++++++++++- .../microphone-manager.test.ts | 64 +++++++++++++++- tests/config/types.test.ts | 2 +- vite.config.ts | 8 +- 11 files changed, 192 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 6c1ba897..8d1bc9e5 100644 --- a/README.md +++ b/README.md @@ -1293,6 +1293,7 @@ All variables listed are under a `conditions:` section. | `media_query` | Any valid [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries) string. Media queries must start and end with parentheses. This may be used to alter card configuration based on device/media properties (e.g. viewport width, orientation). Please note that `width` and `height` refer to the entire viewport not just the card. See the [media query example](#media-query-example).| | `interacted` | If `true` the condition is satisfied if the card has had human interaction within `view.interaction_seconds` elapsed seconds. If `false` the condition is satisfied if the card has **NOT** had human interaction in that time. | | `triggered` | A list of camera IDs which, if triggered in [scan mode](#scan-mode), satisfy the condition.| +| `microphone` | A object to include microphone state as part of the condition evaluation. See below.| See the [example below](#frigate-card-conditional-example) for a real-world example of how these conditions can be used. @@ -1316,6 +1317,18 @@ If multiple entries are provided, the results are `AND`ed. See the [Menu override example below](#frigate-card-menu-override-example) for an illustration. +### Microphone Conditions + +```yaml +- conditions: + microphone: +``` + +| Parameter | Description | +| - | - | +| `muted` | Optional: If `true` or `false` the condition is satisfied if the microphone is muted or unmuted respectively. | +| `connected` | Optional: If `true` or `false` the condition is satisfied if the microphone is connected or disconnected respectively. | + ## Picture Elements / Menu Customizations diff --git a/src/card-controller/card-element-manager.ts b/src/card-controller/card-element-manager.ts index e984cb48..cbbc6107 100644 --- a/src/card-controller/card-element-manager.ts +++ b/src/card-controller/card-element-manager.ts @@ -60,6 +60,7 @@ export class CardElementManager { this._api.getFullscreenManager().initialize(); this._api.getExpandManager().initialize(); this._api.getMediaLoadedInfoManager().initialize(); + this._api.getMicrophoneManager().initialize(); // Whether or not the card is in panel mode on the dashboard. setOrRemoveAttribute(this._element, isCardInPanel(this._element), 'panel'); diff --git a/src/card-controller/conditions-manager.ts b/src/card-controller/conditions-manager.ts index 7a726f71..7072323b 100644 --- a/src/card-controller/conditions-manager.ts +++ b/src/card-controller/conditions-manager.ts @@ -4,6 +4,7 @@ import { copyConfig } from '../config-mgmt'; import { FrigateCardCondition, frigateConditionalSchema, + MicrophoneConditionState, OverrideConfigurationKey, RawFrigateCardConfig, ViewDisplayMode, @@ -20,6 +21,7 @@ interface ConditionState { displayMode?: ViewDisplayMode; triggered?: Set; interaction?: boolean; + microphone?: MicrophoneConditionState; } export class ConditionEvaluateRequestEvent extends Event { @@ -254,6 +256,13 @@ export class ConditionsManager { result &&= state.interaction !== undefined && condition.interaction === state.interaction; } + if (condition.microphone) { + result &&= + (condition.microphone.connected === undefined || + state.microphone?.connected === condition.microphone.connected) && + (condition.microphone.muted === undefined || + state.microphone?.muted === condition.microphone.muted); + } return result; } diff --git a/src/card-controller/microphone-manager.ts b/src/card-controller/microphone-manager.ts index 8aed6315..19bc7c5f 100644 --- a/src/card-controller/microphone-manager.ts +++ b/src/card-controller/microphone-manager.ts @@ -29,6 +29,10 @@ export class MicrophoneManager implements ReadonlyMicrophoneManager { this._api = api; } + public initialize(): void { + this._setConditionState(); + } + public async connect(): Promise { try { this._stream = await navigator.mediaDevices.getUserMedia({ @@ -43,13 +47,15 @@ export class MicrophoneManager implements ReadonlyMicrophoneManager { return false; } this._setMute(); + this._setConditionState(); return true; } - public async disconnect(): Promise { + public disconnect(): void { this._stream?.getTracks().forEach((track) => track.stop()); this._stream = undefined; + this._setConditionState(); this._api.getCardElementManager().update(); } @@ -62,6 +68,7 @@ export class MicrophoneManager implements ReadonlyMicrophoneManager { this._mute = true; this._setMute(); + this._setConditionState(); if (!wasMuted) { this._callListeners('muted'); @@ -89,6 +96,7 @@ export class MicrophoneManager implements ReadonlyMicrophoneManager { unmute(); } + this._setConditionState(); if (!wasUnmuted) { this._callListeners('unmuted'); } @@ -144,4 +152,13 @@ export class MicrophoneManager implements ReadonlyMicrophoneManager { }); } } + + protected _setConditionState(): void { + this._api.getConditionsManager().setState({ + microphone: { + muted: this.isMuted(), + connected: this.isConnected(), + }, + }); + } } diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index 7cc92bba..89122b00 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -104,6 +104,7 @@ export interface CardElementAPI { getFullscreenManager(): FullscreenManager; getInteractionManager(): InteractionManager; getMediaLoadedInfoManager(): MediaLoadedInfoManager; + getMicrophoneManager(): MicrophoneManager; getQueryStringManager(): QueryStringManager; } @@ -178,6 +179,7 @@ export interface CardMessageAPI { export interface CardMicrophoneAPI { getCardElementManager(): CardElementManager; + getConditionsManager(): ConditionsManager; getConfigManager(): ConfigManager; } diff --git a/src/config/types.ts b/src/config/types.ts index 19b87484..bbd36b2e 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -479,6 +479,12 @@ export type MenuItem = MenuIcon | MenuStateIcon | MenuSubmenu | MenuSubmenuSelec // Custom Element Configuration: Conditions // ************************************************************************* +const microphoneConditionSchema = z.object({ + connected: z.boolean().optional(), + muted: z.boolean().optional(), +}); +export type MicrophoneConditionState = z.infer; + export const frigateCardConditionSchema = z.object({ view: z.string().array().optional(), fullscreen: z.boolean().optional(), @@ -490,6 +496,7 @@ export const frigateCardConditionSchema = z.object({ display_mode: viewDisplayModeSchema.optional(), triggered: z.string().array().optional(), interaction: z.boolean().optional(), + microphone: microphoneConditionSchema.optional(), }); export type FrigateCardCondition = z.infer; @@ -736,7 +743,7 @@ export type LiveProvider = (typeof LIVE_PROVIDERS)[number]; const microphoneConfigDefault = { always_connected: false, - disconnect_seconds: 60, + disconnect_seconds: 90, mute_after_microphone_mute_seconds: 60, }; diff --git a/tests/card-controller/card-element-manager.test.ts b/tests/card-controller/card-element-manager.test.ts index 1f9877a1..89a5e8e1 100644 --- a/tests/card-controller/card-element-manager.test.ts +++ b/tests/card-controller/card-element-manager.test.ts @@ -141,6 +141,7 @@ describe('CardElementManager', () => { expect(api.getFullscreenManager().initialize).toBeCalled(); expect(api.getExpandManager().initialize).toBeCalled(); expect(api.getMediaLoadedInfoManager().initialize).toBeCalled(); + expect(api.getMicrophoneManager().initialize).toBeCalled(); }); it('should disconnect', () => { diff --git a/tests/card-controller/conditions-manager.test.ts b/tests/card-controller/conditions-manager.test.ts index f1c321ec..08e71c67 100644 --- a/tests/card-controller/conditions-manager.test.ts +++ b/tests/card-controller/conditions-manager.test.ts @@ -377,9 +377,81 @@ describe('ConditionsManager', () => { const manager = new ConditionsManager(createCardAPI()); const condition: FrigateCardCondition = { interaction: true }; expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ interaction: true }) + manager.setState({ interaction: true }); expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ interaction: false }) + manager.setState({ interaction: false }); expect(manager.evaluateCondition(condition)).toBeFalsy(); }); + + describe('should evaluate conditions with microphone', () => { + it('empty', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { microphone: {} }; + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ microphone: { connected: true } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ microphone: { connected: false } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ microphone: { muted: true } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ microphone: { muted: false } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + }); + + it('connected is true', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { microphone: { connected: true } }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { connected: true } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ microphone: { connected: false } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + it('connected is false', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { microphone: { connected: false } }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { connected: true } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { connected: false } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + }); + + it('muted is true', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { microphone: { muted: true } }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { muted: true } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ microphone: { muted: false } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + it('muted is false', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { microphone: { muted: false } }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { muted: true } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { muted: false } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + }); + + it('connected and muted', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { + microphone: { muted: false, connected: true }, + }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { muted: true } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { muted: false } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { connected: false, muted: false } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { connected: true, muted: false } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + }); + }); }); diff --git a/tests/card-controller/microphone-manager.test.ts b/tests/card-controller/microphone-manager.test.ts index df9d6408..c3d521e5 100644 --- a/tests/card-controller/microphone-manager.test.ts +++ b/tests/card-controller/microphone-manager.test.ts @@ -128,7 +128,7 @@ describe('MicrophoneManager', () => { expect(manager.isConnected()).toBeTruthy(); expect(api.getCardElementManager().update).toBeCalledTimes(1); - await manager.disconnect(); + manager.disconnect(); expect(manager.isConnected()).toBeFalsy(); expect(api.getCardElementManager().update).toBeCalledTimes(2); }); @@ -202,7 +202,7 @@ describe('MicrophoneManager', () => { await manager.connect(); expect(listener).not.toHaveBeenCalled(); - await manager.mute(); + manager.mute(); expect(listener).not.toHaveBeenCalled(); await manager.unmute(); @@ -212,7 +212,7 @@ describe('MicrophoneManager', () => { await manager.unmute(); expect(listener).toHaveBeenCalledTimes(1); - await manager.mute(); + manager.mute(); expect(listener).toHaveBeenCalledTimes(2); expect(listener).toHaveBeenLastCalledWith('muted'); @@ -221,4 +221,62 @@ describe('MicrophoneManager', () => { await manager.unmute(); expect(listener).toHaveBeenCalledTimes(2); }); + + it('should initialize', () => { + const api = createCardAPI(); + const manager = new MicrophoneManager(api); + + manager.initialize(); + expect(api.getConditionsManager().setState).toBeCalledWith({ + microphone: { connected: false, muted: true }, + }); + }); + + it('should set condition state', async () => { + const api = createCardAPI(); + const manager = new MicrophoneManager(api); + navigatorMock.mediaDevices.getUserMedia.mockReturnValue(createMockStream()); + + expect(api.getConditionsManager().setState).not.toBeCalled(); + + await manager.connect(); + expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith( + expect.objectContaining({ + microphone: { + connected: true, + muted: true, + }, + }), + ); + + await manager.unmute(); + expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith( + expect.objectContaining({ + microphone: { + connected: true, + muted: false, + }, + }), + ); + + manager.mute(); + expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith( + expect.objectContaining({ + microphone: { + connected: true, + muted: true, + }, + }), + ); + + manager.disconnect(); + expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith( + expect.objectContaining({ + microphone: { + connected: false, + muted: true, + }, + }), + ); + }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index aa41d7b8..ef597865 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -99,7 +99,7 @@ describe('config defaults', () => { lazy_unload: [], microphone: { always_connected: false, - disconnect_seconds: 60, + disconnect_seconds: 90, mute_after_microphone_mute_seconds: 60, }, preload: false, diff --git a/vite.config.ts b/vite.config.ts index 197f27f1..c068a35d 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,10 +10,10 @@ export default defineConfig({ // Thresholds will automatically be updated as coverage improves to avoid // back-sliding. thresholdAutoUpdate: true, - statements: 72.66, - branches: 61.9, - functions: 73.96, - lines: 72.56, + statements: 72.72, + branches: 61.97, + functions: 74.01, + lines: 72.62, }, }, }); From 93a475c7f462eed2ebfabad125cd7ae4e7950804 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 3 Feb 2024 14:23:49 -0800 Subject: [PATCH 084/189] Allow live thumbnails to load recordings . --- README.md | 25 ++++--- src/components-lib/timeline-source.ts | 10 +-- src/components/gallery.ts | 4 +- src/components/surround.ts | 58 ++++++++++----- src/components/timeline-core.ts | 2 +- src/components/viewer.ts | 2 +- src/components/views.ts | 9 ++- src/config-mgmt.ts | 20 ++++++ src/config/types.ts | 25 ++++--- src/const.ts | 16 +++-- src/editor.ts | 78 +++++++++++++------- src/localize/languages/en.json | 15 ++-- src/types.ts | 1 + src/utils/media-to-view.ts | 12 ++-- tests/config-mgmt.test.ts | 100 ++++++++++++++++++++++++++ tests/config/types.test.ts | 9 +-- tests/utils/media-to-view.test.ts | 4 +- vite.config.ts | 6 +- 18 files changed, 295 insertions(+), 101 deletions(-) diff --git a/README.md b/README.md index 8d1bc9e5..3400d854 100644 --- a/README.md +++ b/README.md @@ -564,7 +564,8 @@ live: | `show_download_control` | `true` | :white_check_mark: | Whether to show the download control on each thumbnail.| | `show_favorite_control` | `true` | :white_check_mark: | Whether to show the favorite ('star') control on each thumbnail.| | `show_timeline_control` | `true` | :white_check_mark: | Whether to show the timeline ('target') control on each thumbnail.| -| `media` | `all` | :white_check_mark: | Whether to show `clips`, `snapshots` or `all` in the thumbnail carousel in the `live` view.| +| `media_type` | `events` | :white_check_mark: | Whether to load `events` or `recordings` media.| +| `events_media_type` | `all` | :white_check_mark: | Whether to show `clips`, `snapshots` or `all` in the thumbnail carousel in the `live` view. This setting is only relevant when the `media_type` parameter (above) is set to `events`.| #### Live Controls: Next / Previous @@ -597,7 +598,7 @@ live: | `style` | `ribbon` | :white_check_mark: | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold` (below). | | `window_seconds` | `3600` | :white_check_mark: | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | | `clustering_threshold` | `3` | :white_check_mark: | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | -| `media` | `all` | :white_check_mark: | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot.| +| `events_media_type` | `all` | :white_check_mark: | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot.| | `show_recordings` | `true` | :white_check_mark: | Whether to show recordings on the timeline (specifically: which hours have any recorded content).| **Caution**: 🚩 For optimal UX, keep the settings for the mini-timeline in the `live` and `media_viewer` identical. Dragging the timeline may cause the card to change between the `live` view and `media_viewer` based views as the user pans between the past and present -- if the settings are different the timeline must "reset". @@ -781,7 +782,7 @@ media_viewer: | `style` | `ribbon` | :heavy_multiplication_x: | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold` (below). | | `window_seconds` | `3600` | :heavy_multiplication_x: | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | | `clustering_threshold` | `3` | :heavy_multiplication_x: | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | -| `media` | `all` | :heavy_multiplication_x: | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot.| +| `events_media_type` | `all` | :heavy_multiplication_x: | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot. | | `show_recordings` | `true` | :heavy_multiplication_x: | Whether to show recordings on the timeline (specifically: which hours have any recorded content).| **Caution**: 🚩 For optimal UX, keep the settings for the mini-timeline in the `live` and `media_viewer` identical. Dragging the timeline may cause the card to change between the `live` view and `media_viewer` based views as the user pans between the past and present -- if the settings are different the timeline must "reset". @@ -911,7 +912,7 @@ See the [fully expanded timeline configuration example](#config-expanded-timelin | `style` | `stack` | :heavy_multiplication_x: | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold` (below). | | `window_seconds` | `3600` | :heavy_multiplication_x: | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | | `clustering_threshold` | `3` | :heavy_multiplication_x: | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | -| `media` | `all` | :heavy_multiplication_x: | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot.| +| `events_media_type` | `all` | :heavy_multiplication_x: | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot.| | `show_recordings` | `true` | :heavy_multiplication_x: | Whether to show recordings on the timeline (specifically: which hours have any recorded content).| | `controls` | | :heavy_multiplication_x: | Configuration for the timeline controls. See below.| @@ -2092,7 +2093,8 @@ live: style: chevrons size: 48 thumbnails: - media: clips + media_type: events + events_media_type: all size: 100 show_details: false show_download_control: true @@ -2103,7 +2105,7 @@ live: style: ribbon mode: none clustering_threshold: 3 - media: all + events_media_type: all show_recordings: true window_seconds: 3600 title: @@ -2201,7 +2203,7 @@ media_viewer: style: ribbon mode: none clustering_threshold: 3 - media: all + events_media_type: all show_recordings: true window_seconds: 3600 title: @@ -2663,7 +2665,7 @@ Reference: [Timeline Options](#timeline-options). timeline: style: stack clustering_threshold: 3 - media: all + events_media_type: all show_recordings: true window_seconds: 3600 controls: @@ -2755,8 +2757,8 @@ overrides: maxAudioLag: 10 videoBufferSize: 524288 audioBufferSize: 131072 - image: - refresh_seconds: 1 + image: + refresh_seconds: 1 live: webrtc_card: ui: true @@ -2779,7 +2781,8 @@ overrides: style: chevrons size: 48 thumbnails: - media: clips + media_type: events + events_media_type: all size: 100 show_details: false show_download_control: true diff --git a/src/components-lib/timeline-source.ts b/src/components-lib/timeline-source.ts index 3aac95b4..ad9eb210 100644 --- a/src/components-lib/timeline-source.ts +++ b/src/components-lib/timeline-source.ts @@ -47,18 +47,18 @@ export class TimelineDataSource { protected _eventRanges = new ExpiringMemoryRangeSet(); protected _cameraIDs: Set; - protected _mediaType: ClipsOrSnapshotsOrAll; + protected _eventsMediaType: ClipsOrSnapshotsOrAll; protected _showRecordings: boolean; constructor( cameraManager: CameraManager, cameraIDs: Set, - media: ClipsOrSnapshotsOrAll, + eventsMediaType: ClipsOrSnapshotsOrAll, showRecordings: boolean, ) { this._cameraManager = cameraManager; this._cameraIDs = cameraIDs; - this._mediaType = media; + this._eventsMediaType = eventsMediaType; this._showRecordings = showRecordings; } @@ -101,8 +101,8 @@ export class TimelineDataSource { return this._cameraManager.generateDefaultEventQueries(this._cameraIDs, { start: window.start, end: window.end, - ...(this._mediaType === 'clips' && { hasClip: true }), - ...(this._mediaType === 'snapshots' && { hasSnapshot: true }), + ...(this._eventsMediaType === 'clips' && { hasClip: true }), + ...(this._eventsMediaType === 'snapshots' && { hasSnapshot: true }), }); } diff --git a/src/components/gallery.ts b/src/components/gallery.ts index 0cc3fa73..b4f0f315 100644 --- a/src/components/gallery.ts +++ b/src/components/gallery.ts @@ -87,7 +87,7 @@ export class FrigateCardGallery extends LitElement { this.view, ); } else { - const mediaType = this.view.is('snapshots') + const eventsMediaType = this.view.is('snapshots') ? 'snapshots' : this.view.is('clips') ? 'clips' @@ -98,7 +98,7 @@ export class FrigateCardGallery extends LitElement { this.cardWideConfig, this.view, { - ...(mediaType && { mediaType: mediaType }), + ...(eventsMediaType && { eventsMediaType: eventsMediaType }), }, ); } diff --git a/src/components/surround.ts b/src/components/surround.ts index 853f1a92..ad89f4ec 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -14,9 +14,16 @@ import { ThumbnailsControlConfig, } from '../config/types.js'; import basicBlockStyle from '../scss/basic-block.scss'; -import { ClipsOrSnapshotsOrAll, ExtendedHomeAssistant } from '../types.js'; +import { + ClipsOrSnapshotsOrAll, + EventsOrRecordings, + ExtendedHomeAssistant, +} from '../types.js'; import { contentsChanged, dispatchFrigateCardEvent } from '../utils/basic.js'; -import { changeViewToRecentEventsForCameraAndDependents } from '../utils/media-to-view'; +import { + changeViewToRecentEventsForCameraAndDependents, + changeViewToRecentRecordingForCameraAndDependents, +} from '../utils/media-to-view'; import { View } from '../view/view.js'; import './surround-basic.js'; import { ThumbnailCarouselTap } from './thumbnail-carousel.js'; @@ -48,7 +55,10 @@ export class FrigateCardSurround extends LitElement { // If fetchMedia is not specified, no fetching is done. @property({ attribute: false, hasChanged: contentsChanged }) - public fetchMedia?: ClipsOrSnapshotsOrAll; + public fetchMediaType?: EventsOrRecordings; + + @property({ attribute: false, hasChanged: contentsChanged }) + public fetchEventsMediaType?: ClipsOrSnapshotsOrAll; @property({ attribute: false }) public cameraManager?: CameraManager; @@ -68,7 +78,8 @@ export class FrigateCardSurround extends LitElement { if ( !this.cameraManager || !this.cardWideConfig || - !this.fetchMedia || + !this.fetchMediaType || + !this.fetchEventsMediaType || !this.hass || !this.view || this.view.query || @@ -78,18 +89,33 @@ export class FrigateCardSurround extends LitElement { ) { return; } - await changeViewToRecentEventsForCameraAndDependents( - this, - this.cameraManager, - this.cardWideConfig, - this.view, - { - allCameras: this.view.isGrid(), - targetView: this.view.view, - mediaType: this.fetchMedia, - select: 'latest', - }, - ); + + if (this.fetchMediaType === 'events') { + await changeViewToRecentEventsForCameraAndDependents( + this, + this.cameraManager, + this.cardWideConfig, + this.view, + { + allCameras: this.view.isGrid(), + targetView: this.view.view, + eventsMediaType: this.fetchEventsMediaType, + select: 'latest', + }, + ); + } else if (this.fetchMediaType === 'recordings') { + await changeViewToRecentRecordingForCameraAndDependents( + this, + this.cameraManager, + this.cardWideConfig, + this.view, + { + allCameras: this.view.isGrid(), + targetView: this.view.view, + select: 'latest', + }, + ); + } } /** diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index b0d62eb8..4aee4deb 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -1161,7 +1161,7 @@ export class FrigateCardTimelineCore extends LitElement { this._timelineSource = new TimelineDataSource( this.cameraManager, cameraIDs, - this.timelineConfig.media, + this.timelineConfig.events_media_type, this.timelineConfig.show_recordings, ); } else { diff --git a/src/components/viewer.ts b/src/components/viewer.ts index e078b1b9..7310853d 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -168,7 +168,7 @@ export class FrigateCardViewer extends LitElement { { allCameras: this.view.isGrid(), targetView: 'media', - mediaType: mediaType, + eventsMediaType: mediaType, }, ); } diff --git a/src/components/views.ts b/src/components/views.ts index d07e57d6..352547b9 100644 --- a/src/components/views.ts +++ b/src/components/views.ts @@ -64,7 +64,7 @@ export class FrigateCardViews extends LitElement { public microphoneManager?: ReadonlyMicrophoneManager; @property({ attribute: false }) - public triggeredCameraIDs?: Set; + public triggeredCameraIDs?: Set; protected willUpdate(changedProps: PropertyValues): void { if (changedProps.has('view') || changedProps.has('config')) { @@ -163,8 +163,11 @@ export class FrigateCardViews extends LitElement { class="${classMap(overallClasses)}" .hass=${this.hass} .view=${this.view} - .fetchMedia=${this.view?.is('live') - ? this.overriddenConfig.live.controls.thumbnails.media + .fetchMediaType=${this.view?.is('live') + ? this.overriddenConfig.live.controls.thumbnails.media_type + : undefined} + .fetchEventsMediaType=${this.view?.is('live') + ? this.overriddenConfig.live.controls.thumbnails.events_media_type : undefined} .thumbnailConfig=${!this.hide ? thumbnailConfig : undefined} .timelineConfig=${!this.hide ? miniTimelineConfig : undefined} diff --git a/src/config-mgmt.ts b/src/config-mgmt.ts index 9fe304ad..fd0e0e20 100644 --- a/src/config-mgmt.ts +++ b/src/config-mgmt.ts @@ -10,9 +10,13 @@ import { CONF_CAMERAS_GLOBAL_JSMPEG, CONF_CAMERAS_GLOBAL_WEBRTC_CARD, CONF_ELEMENTS, + CONF_LIVE_CONTROLS_THUMBNAILS_EVENTS_MEDIA_TYPE, + CONF_LIVE_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, CONF_MEDIA_GALLERY, + CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, CONF_MENU_BUTTONS_CAMERA_UI, CONF_OVERRIDES, + CONF_TIMELINE_EVENTS_MEDIA_TYPE, CONF_VIEW_INTERACTION_SECONDS, CONF_VIEW_SCAN_ACTIONS_UNTRIGGER, } from './const'; @@ -516,4 +520,20 @@ const UPGRADES = [ upgradeWithOverrides('media_viewer.auto_unmute', (data) => data === 'all' ? ['selected', 'visible'] : data === 'never' ? null : arrayify(data), ), + upgradeMoveToWithOverrides( + 'live.controls.thumbnails.media', + CONF_LIVE_CONTROLS_THUMBNAILS_EVENTS_MEDIA_TYPE, + ), + upgradeMoveToWithOverrides( + 'timeline.media', + CONF_TIMELINE_EVENTS_MEDIA_TYPE, + ), + upgradeMoveToWithOverrides( + 'live.controls.timeline.media', + CONF_LIVE_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, + ), + upgradeMoveToWithOverrides( + 'media_viewer.controls.timeline.media', + CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, + ), ]; diff --git a/src/config/types.ts b/src/config/types.ts index bbd36b2e..1ab1941f 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -626,26 +626,31 @@ const thumbnailsControlSchema = thumbnailsControlBaseSchema.extend({ }); export type ThumbnailsControlConfig = z.infer; +// ************************************************************************* +// Event Media Type Configuration +// ************************************************************************* +const eventsMediaTypeSchema = z.enum(['all', 'clips', 'snapshots']); + // ************************************************************************* // Timeline Configuration // ************************************************************************* const timelineCoreConfigDefault = { clustering_threshold: 3, - media: 'all' as const, + events_media_type: 'all' as const, window_seconds: 60 * 60, show_recordings: true, style: 'stack' as const, }; -const timelineMediaSchema = z.enum(['all', 'clips', 'snapshots']); - const timelineCoreConfigSchema = z.object({ clustering_threshold: z .number() .optional() .default(timelineCoreConfigDefault.clustering_threshold), - media: timelineMediaSchema.optional().default(timelineCoreConfigDefault.media), + events_media_type: eventsMediaTypeSchema + .optional() + .default(timelineCoreConfigDefault.events_media_type), window_seconds: z .number() .min(1 * 60) @@ -867,7 +872,8 @@ export type FrigateCardPTZConfig = z.infer; const liveThumbnailControlsDefaults = { ...thumbnailControlsDefaults, - media: 'all' as const, + media_type: 'events' as const, + events_media_type: 'all' as const, }; const liveConfigDefault = { @@ -899,9 +905,12 @@ const liveConfigDefault = { }; const livethumbnailsControlSchema = thumbnailsControlSchema.extend({ - media: z - .enum(['all', 'clips', 'snapshots']) - .default(liveConfigDefault.controls.thumbnails.media), + media_type: z + .enum(['events', 'recordings']) + .default(liveConfigDefault.controls.thumbnails.media_type), + events_media_type: eventsMediaTypeSchema.default( + liveConfigDefault.controls.thumbnails.events_media_type, + ), }); const liveOverridableConfigSchema = z diff --git a/src/const.ts b/src/const.ts index 92dc8064..f3f3298b 100644 --- a/src/const.ts +++ b/src/const.ts @@ -146,8 +146,8 @@ export const CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SIZE = `${CONF_MEDIA_VIEWER}.controls.thumbnails.size` as const; export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_CLUSTERING_THRESHOLD = `${CONF_MEDIA_VIEWER}.controls.timeline.clustering_threshold` as const; -export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MEDIA = - `${CONF_MEDIA_VIEWER}.controls.timeline.media` as const; +export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE = + `${CONF_MEDIA_VIEWER}.controls.timeline.events_media_type` as const; export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MODE = `${CONF_MEDIA_VIEWER}.controls.timeline.mode` as const; export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_SHOW_RECORDINGS = @@ -189,8 +189,10 @@ export const CONF_LIVE_CONTROLS_PTZ_ORIENTATION = `${CONF_LIVE}.controls.ptz.orientation` as const; export const CONF_LIVE_CONTROLS_PTZ_POSITION = `${CONF_LIVE}.controls.ptz.position` as const; -export const CONF_LIVE_CONTROLS_THUMBNAILS_MEDIA = - `${CONF_LIVE}.controls.thumbnails.media` as const; +export const CONF_LIVE_CONTROLS_THUMBNAILS_MEDIA_TYPE = + `${CONF_LIVE}.controls.thumbnails.media_type` as const; +export const CONF_LIVE_CONTROLS_THUMBNAILS_EVENTS_MEDIA_TYPE = + `${CONF_LIVE}.controls.thumbnails.events_media_type` as const; export const CONF_LIVE_CONTROLS_THUMBNAILS_MODE = `${CONF_LIVE}.controls.thumbnails.mode` as const; export const CONF_LIVE_CONTROLS_THUMBNAILS_SIZE = @@ -205,8 +207,8 @@ export const CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL = `${CONF_LIVE}.controls.thumbnails.show_timeline_control` as const; export const CONF_LIVE_CONTROLS_TIMELINE_CLUSTERING_THRESHOLD = `${CONF_LIVE}.controls.timeline.clustering_threshold` as const; -export const CONF_LIVE_CONTROLS_TIMELINE_MEDIA = - `${CONF_LIVE}.controls.timeline.media` as const; +export const CONF_LIVE_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE = + `${CONF_LIVE}.controls.timeline.events_media_type` as const; export const CONF_LIVE_CONTROLS_TIMELINE_MODE = `${CONF_LIVE}.controls.timeline.mode` as const; export const CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS = @@ -256,7 +258,7 @@ const CONF_TIMELINE = 'timeline' as const; export const CONF_TIMELINE_WINDOW_SECONDS = `${CONF_TIMELINE}.window_seconds` as const; export const CONF_TIMELINE_CLUSTERING_THRESHOLD = `${CONF_TIMELINE}.clustering_threshold` as const; -export const CONF_TIMELINE_MEDIA = `${CONF_TIMELINE}.media` as const; +export const CONF_TIMELINE_EVENTS_MEDIA_TYPE = `${CONF_TIMELINE}.events_media_type` as const; export const CONF_TIMELINE_SHOW_RECORDINGS = `${CONF_TIMELINE}.show_recordings` as const; export const CONF_TIMELINE_STYLE = `${CONF_TIMELINE}.style` as const; export const CONF_TIMELINE_CONTROLS_THUMBNAILS_MODE = diff --git a/src/editor.ts b/src/editor.ts index d0db698f..fbd589a8 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -86,7 +86,8 @@ import { CONF_LIVE_CONTROLS_PTZ_MODE, CONF_LIVE_CONTROLS_PTZ_ORIENTATION, CONF_LIVE_CONTROLS_PTZ_POSITION, - CONF_LIVE_CONTROLS_THUMBNAILS_MEDIA, + CONF_LIVE_CONTROLS_THUMBNAILS_EVENTS_MEDIA_TYPE, + CONF_LIVE_CONTROLS_THUMBNAILS_MEDIA_TYPE, CONF_LIVE_CONTROLS_THUMBNAILS_MODE, CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DETAILS, CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DOWNLOAD_CONTROL, @@ -94,7 +95,7 @@ import { CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL, CONF_LIVE_CONTROLS_THUMBNAILS_SIZE, CONF_LIVE_CONTROLS_TIMELINE_CLUSTERING_THRESHOLD, - CONF_LIVE_CONTROLS_TIMELINE_MEDIA, + CONF_LIVE_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, CONF_LIVE_CONTROLS_TIMELINE_MODE, CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS, CONF_LIVE_CONTROLS_TIMELINE_STYLE, @@ -138,7 +139,7 @@ import { CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL, CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_SIZE, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_CLUSTERING_THRESHOLD, - CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MEDIA, + CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MODE, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_SHOW_RECORDINGS, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_STYLE, @@ -174,7 +175,7 @@ import { CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL, CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL, CONF_TIMELINE_CONTROLS_THUMBNAILS_SIZE, - CONF_TIMELINE_MEDIA, + CONF_TIMELINE_EVENTS_MEDIA_TYPE, CONF_TIMELINE_SHOW_RECORDINGS, CONF_TIMELINE_STYLE, CONF_TIMELINE_WINDOW_SECONDS, @@ -452,15 +453,27 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor }, ]; - protected _thumbnailMedias: EditorSelectOption[] = [ + protected _thumbnailMediaTypes: EditorSelectOption[] = [ + { value: '', label: '' }, + { + value: 'events', + label: localize('config.common.controls.thumbnails.media_types.events'), + }, + { + value: 'recordings', + label: localize('config.common.controls.thumbnails.media_types.recordings'), + }, + ]; + + protected _thumbnailEventsMediaTypes: EditorSelectOption[] = [ { value: '', label: '' }, { value: 'clips', - label: localize('config.common.controls.thumbnails.medias.clips'), + label: localize('config.common.controls.thumbnails.events_media_types.clips'), }, { value: 'snapshots', - label: localize('config.common.controls.thumbnails.medias.snapshots'), + label: localize('config.common.controls.thumbnails.events_media_types.snapshots'), }, ]; @@ -498,11 +511,11 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor { value: 'url', label: localize('config.image.modes.url') }, ]; - protected _timelineMediaTypes: EditorSelectOption[] = [ + protected _timelineEventsMediaTypes: EditorSelectOption[] = [ { value: '', label: '' }, - { value: 'all', label: localize('config.common.timeline.medias.all') }, - { value: 'clips', label: localize('config.common.timeline.medias.clips') }, - { value: 'snapshots', label: localize('config.common.timeline.medias.snapshots') }, + { value: 'all', label: localize('config.common.timeline.events_media_types.all') }, + { value: 'clips', label: localize('config.common.timeline.events_media_types.clips') }, + { value: 'snapshots', label: localize('config.common.timeline.events_media_types.snapshots') }, ]; protected _timelineStyleTypes: EditorSelectOption[] = [ @@ -1149,7 +1162,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor * @param configPathStyle Timeline style config path. * @param configPathWindowSeconds Timeline window config path. * @param configPathClusteringThreshold Clustering threshold config path. - * @param configPathTimelineMedia Timeline media config path. + * @param configPathTimelineEventsMediaType Timeline media config path. * @param configPathShowRecordings Show recordings config path. * @param defaultShowRecordings Default value of show_recordings. * @returns A rendered template. @@ -1158,7 +1171,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor configPathStyle: string, configPathWindowSeconds: string, configPathClusteringThreshold: string, - configPathTimelineMedia: string, + configPathTimelineEventsMediaType: string, configPathShowRecordings: string, defaultShowRecordings: boolean, ): TemplateResult { @@ -1175,8 +1188,8 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderNumberInput(configPathClusteringThreshold, { label: localize(`config.common.${CONF_TIMELINE_CLUSTERING_THRESHOLD}`), })} - ${this._renderOptionSelector(configPathTimelineMedia, this._timelineMediaTypes, { - label: localize(`config.common.${CONF_TIMELINE_MEDIA}`), + ${this._renderOptionSelector(configPathTimelineEventsMediaType, this._timelineEventsMediaTypes, { + label: localize(`config.common.${CONF_TIMELINE_EVENTS_MEDIA_TYPE}`), })} ${this._renderSwitch(configPathShowRecordings, defaultShowRecordings, { label: localize(`config.common.${CONF_TIMELINE_SHOW_RECORDINGS}`), @@ -1188,7 +1201,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor * @param domain The submenu domain. * @param configPathWindowSeconds Timeline window config path. * @param configPathClusteringThreshold Clustering threshold config path. - * @param configPathTimelineMedia Timeline media config path. + * @param configPathTimelineEventsMediaType Timeline media config path. * @param configPathShowRecordings Show recordings config path. * @returns A rendered template. */ @@ -1198,7 +1211,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor configPathStyle: string, configPathWindowSeconds: string, configPathClusteringThreshold: string, - configPathTimelineMedia: string, + configPathTimelineEventsMediaType: string, configPathShowRecordings: string, showRecordingsDefault: boolean, ): TemplateResult | void { @@ -1214,7 +1227,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor configPathStyle, configPathWindowSeconds, configPathClusteringThreshold, - configPathTimelineMedia, + configPathTimelineEventsMediaType, configPathShowRecordings, showRecordingsDefault, )}`, @@ -1330,7 +1343,8 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor show_download_control: boolean; }, options?: { - configPathMedia?: string; + configPathMediaType?: string; + configPathEventsMediaType?: string; configPathMode?: string; }, ): TemplateResult | void { @@ -1349,12 +1363,21 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor }, )}` : html``} - ${options?.configPathMedia + ${options?.configPathMediaType ? html`${this._renderOptionSelector( - options.configPathMedia, - this._thumbnailMedias, + options.configPathMediaType, + this._thumbnailMediaTypes, { - label: localize('config.common.controls.thumbnails.media'), + label: localize('config.common.controls.thumbnails.media_type'), + }, + )}` + : html``} + ${options?.configPathEventsMediaType + ? html`${this._renderOptionSelector( + options.configPathEventsMediaType, + this._thumbnailEventsMediaTypes, + { + label: localize('config.common.controls.thumbnails.events_media_type'), }, )}` : html``} @@ -2101,7 +2124,8 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DOWNLOAD_CONTROL, this._defaults.live.controls.thumbnails, { - configPathMedia: CONF_LIVE_CONTROLS_THUMBNAILS_MEDIA, + configPathMediaType: CONF_LIVE_CONTROLS_THUMBNAILS_MEDIA_TYPE, + configPathEventsMediaType: CONF_LIVE_CONTROLS_THUMBNAILS_EVENTS_MEDIA_TYPE, configPathMode: CONF_LIVE_CONTROLS_THUMBNAILS_MODE, }, )} @@ -2116,7 +2140,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor CONF_LIVE_CONTROLS_TIMELINE_STYLE, CONF_LIVE_CONTROLS_TIMELINE_WINDOW_SECONDS, CONF_LIVE_CONTROLS_TIMELINE_CLUSTERING_THRESHOLD, - CONF_LIVE_CONTROLS_TIMELINE_MEDIA, + CONF_LIVE_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS, this._defaults.live.controls.timeline.show_recordings, )} @@ -2309,7 +2333,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_STYLE, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_WINDOW_SECONDS, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_CLUSTERING_THRESHOLD, - CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MEDIA, + CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_SHOW_RECORDINGS, this._defaults.media_viewer.controls.timeline.show_recordings, )} @@ -2347,7 +2371,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor CONF_TIMELINE_STYLE, CONF_TIMELINE_WINDOW_SECONDS, CONF_TIMELINE_CLUSTERING_THRESHOLD, - CONF_TIMELINE_MEDIA, + CONF_TIMELINE_EVENTS_MEDIA_TYPE, CONF_TIMELINE_SHOW_RECORDINGS, this._defaults.timeline.show_recordings, )} diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index bb246156..2f3fdf84 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -119,8 +119,13 @@ }, "thumbnails": { "editor_label": "Thumbnails", - "media": "Whether to show thumbnails of clips or snapshots", - "medias": { + "media_type": "Whether to show thumnails of events or recordings", + "media_types": { + "events": "Events", + "recordings": "Recordings" + }, + "events_media_type": "Whether to show event thumbnails of clips or snapshots", + "events_media_types": { "clips": "Clip thumbnails", "snapshots": "Snapshot thumbnails" }, @@ -191,9 +196,9 @@ }, "timeline": { "clustering_threshold": "The count of events at which they are clustered (0=no clustering)", - "media": "The media the timeline displays", - "medias": { - "all": "All media types", + "events_media_type": "The events media the timeline displays", + "events_media_types": { + "all": "All event media types", "clips": "Clips", "snapshots": "Snapshots" }, diff --git a/src/types.ts b/src/types.ts index 80527d0c..d95880ed 100644 --- a/src/types.ts +++ b/src/types.ts @@ -4,6 +4,7 @@ import { z } from 'zod'; export type ClipsOrSnapshots = 'clips' | 'snapshots'; export type ClipsOrSnapshotsOrAll = 'clips' | 'snapshots' | 'all'; +export type EventsOrRecordings = 'events' | 'recordings'; export class FrigateCardError extends Error { context?: unknown; diff --git a/src/utils/media-to-view.ts b/src/utils/media-to-view.ts index bfd58328..4383b29c 100644 --- a/src/utils/media-to-view.ts +++ b/src/utils/media-to-view.ts @@ -24,7 +24,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( view: View, options?: { allCameras?: boolean; - mediaType?: ClipsOrSnapshotsOrAll; + eventsMediaType?: ClipsOrSnapshotsOrAll; targetView?: FrigateCardView; select?: ResultSelectType; }, @@ -37,7 +37,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( } const queries = createQueriesForEventsView(cameraManager, cardWideConfig, cameraIDs, { - mediaType: options?.mediaType, + eventsMediaType: options?.eventsMediaType, }); if (!queries) { return; @@ -62,15 +62,15 @@ const createQueriesForEventsView = ( cardWideConfig: CardWideConfig, cameraIDs: Set, options?: { - mediaType?: ClipsOrSnapshotsOrAll; + eventsMediaType?: ClipsOrSnapshotsOrAll; }, ): EventMediaQueries | null => { const limit = cardWideConfig.performance?.features.media_chunk_size ?? MEDIA_CHUNK_SIZE_DEFAULT; const eventQueries = cameraManager.generateDefaultEventQueries(cameraIDs, { limit: limit, - ...(options?.mediaType === 'clips' && { hasClip: true }), - ...(options?.mediaType === 'snapshots' && { hasSnapshot: true }), + ...(options?.eventsMediaType === 'clips' && { hasClip: true }), + ...(options?.eventsMediaType === 'snapshots' && { hasSnapshot: true }), }); return eventQueries ? new EventMediaQueries(eventQueries) : null; }; @@ -91,7 +91,7 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( view: View, options?: { allCameras?: boolean; - targetView?: 'recording' | 'recordings'; + targetView?: FrigateCardView; select?: ResultSelectType; }, ): Promise => { diff --git a/tests/config-mgmt.test.ts b/tests/config-mgmt.test.ts index bba0efc3..702a2637 100644 --- a/tests/config-mgmt.test.ts +++ b/tests/config-mgmt.test.ts @@ -1590,5 +1590,105 @@ describe('should handle version specific upgrades', () => { }); }); }); + + describe('should rename thumbnails.media to thumbnails.events_media_type', () => { + it.each([['all' as const], ['clips' as const], ['snapshots' as const]])( + '%s', + (mediaEventType: string) => { + const config = { + live: { + controls: { + thumbnails: { + media: mediaEventType, + }, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: { + controls: { + thumbnails: { + events_media_type: mediaEventType, + }, + }, + }, + }); + }, + ); + }); + + describe('should rename timeline.media to timeline.events_media_type', () => { + it.each([['all' as const], ['clips' as const], ['snapshots' as const]])( + '%s', + (mediaEventType: string) => { + const config = { + timeline: { + media: mediaEventType, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + timeline: { + events_media_type: mediaEventType, + }, + }); + }, + ); + }); + + describe('should rename live.controls.timeline.media to live.controls.timeline.events_media_type', () => { + it.each([['all' as const], ['clips' as const], ['snapshots' as const]])( + '%s', + (mediaEventType: string) => { + const config = { + live: { + controls: { + timeline: { + media: mediaEventType, + }, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: { + controls: { + timeline: { + events_media_type: mediaEventType, + }, + }, + }, + }); + }, + ); + }); + + describe('should rename media_viewer.controls.timeline.media to media_viewer.controls.timeline.events_media_type', () => { + it.each([['all' as const], ['clips' as const], ['snapshots' as const]])( + '%s', + (mediaEventType: string) => { + const config = { + media_viewer: { + controls: { + timeline: { + media: mediaEventType, + }, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + media_viewer: { + controls: { + timeline: { + events_media_type: mediaEventType, + }, + }, + }, + }); + }, + ); + }); }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index ef597865..d34b057f 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -77,7 +77,8 @@ describe('config defaults', () => { position: 'bottom-right', }, thumbnails: { - media: 'all', + media_type: 'events', + events_media_type: 'all', mode: 'right', show_details: true, show_download_control: true, @@ -87,7 +88,7 @@ describe('config defaults', () => { }, timeline: { clustering_threshold: 3, - media: 'all', + events_media_type: 'all', mode: 'none', show_recordings: true, style: 'ribbon', @@ -143,7 +144,7 @@ describe('config defaults', () => { }, timeline: { clustering_threshold: 3, - media: 'all', + events_media_type: 'all', mode: 'none', show_recordings: true, style: 'ribbon', @@ -268,7 +269,7 @@ describe('config defaults', () => { size: 100, }, }, - media: 'all', + events_media_type: 'all', show_recordings: true, style: 'stack', window_seconds: 3600, diff --git a/tests/utils/media-to-view.test.ts b/tests/utils/media-to-view.test.ts index 9cb614be..24ac2bf9 100644 --- a/tests/utils/media-to-view.test.ts +++ b/tests/utils/media-to-view.test.ts @@ -101,7 +101,7 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { {}, createView(), { - mediaType: 'clips', + eventsMediaType: 'clips', }, ); expect(elementHandler.viewHandler).not.toBeCalled(); @@ -222,7 +222,7 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { {}, createView(), { - mediaType: mediaType, + eventsMediaType: mediaType, }, ); diff --git a/vite.config.ts b/vite.config.ts index c068a35d..67ec51a5 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,10 +10,10 @@ export default defineConfig({ // Thresholds will automatically be updated as coverage improves to avoid // back-sliding. thresholdAutoUpdate: true, - statements: 72.72, - branches: 61.97, + statements: 72.73, + branches: 61.93, functions: 74.01, - lines: 72.62, + lines: 72.63, }, }, }); From e35a44933cf631751e68e157f67f5900724825fb Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 3 Feb 2024 14:37:22 -0800 Subject: [PATCH 085/189] Fix non-en languages. --- src/localize/languages/en.json | 56 +++++++++++++++---------------- src/localize/languages/it.json | 13 ++++--- src/localize/languages/pt-BR.json | 13 ++++--- src/localize/languages/pt-PT.json | 13 ++++--- 4 files changed, 55 insertions(+), 40 deletions(-) diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 2f3fdf84..241f4e4c 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -18,8 +18,8 @@ "editor_label": "Cast Options", "method": "Cast method", "methods": { - "standard": "Standard", - "dashboard": "Dashboard" + "dashboard": "Dashboard", + "standard": "Standard" } }, "dependencies": { @@ -119,16 +119,16 @@ }, "thumbnails": { "editor_label": "Thumbnails", - "media_type": "Whether to show thumnails of events or recordings", - "media_types": { - "events": "Events", - "recordings": "Recordings" - }, "events_media_type": "Whether to show event thumbnails of clips or snapshots", "events_media_types": { "clips": "Clip thumbnails", "snapshots": "Snapshot thumbnails" }, + "media_type": "Whether to show thumnails of events or recordings", + "media_types": { + "events": "Events", + "recordings": "Recordings" + }, "mode": "Thumbnails mode", "modes": { "above": "Thumbnails above", @@ -243,27 +243,27 @@ "editor_label": "Live Controls", "ptz": { "editor_label": "PTZ", + "hide_home": "Hide home control", + "hide_pan_tilt": "Hide pan & tilt control", + "hide_zoom": "Hide zoom control", "mode": "Mode", "modes": { - "on": "On", + "auto": "Automatic", "off": "Off", - "auto": "Automatic" + "on": "On" }, "orientation": "Orientation", "orientations": { - "vertical": "Vertical", - "horizontal": "Horizontal" + "horizontal": "Horizontal", + "vertical": "Vertical" }, "position": "Position", "positions": { - "top-left": "Top left", - "top-right": "Top right", "bottom-left": "Bottom left", - "bottom-right": "Bottom right" - }, - "hide_zoom": "Hide zoom control", - "hide_pan_tilt": "Hide pan & tilt control", - "hide_home": "Hide home control" + "bottom-right": "Bottom right", + "top-left": "Top left", + "top-right": "Top right" + } } }, "draggable": "Live cameras view can be dragged/swiped", @@ -319,8 +319,8 @@ "camera_ui": "Camera user interface", "cameras": "Cameras", "clips": "Clips", - "download": "Download", "display_mode": "Display mode", + "download": "Download", "enabled": "Button enabled", "expand": "Expand", "frigate": "Frigate menu / Default view", @@ -392,6 +392,8 @@ "on": "On" }, "default": "Default view", + "interaction_seconds": "Seconds after user action to remain interacted with (0=never)", + "reset_after_interaction": "Reset to the default view after user interaction", "scan": { "actions": { "editor_label": "Scan mode actions", @@ -413,13 +415,11 @@ } }, "editor_label": "Scan mode", - "filter_selected_camera": "Only trigger on selected camera", "enabled": "Scan mode enabled", + "filter_selected_camera": "Only trigger on selected camera", "show_trigger_status": "Show pulsing border when triggered", "untrigger_seconds": "Seconds after inactive state change to untrigger" }, - "interaction_seconds": "Seconds after user action to remain interacted with (0=never)", - "reset_after_interaction": "Reset to the default view after user interaction", "update_cycle_camera": "Cycle through cameras when default view updates", "update_force": "Force card updates (ignore user interaction)", "update_seconds": "Refresh default view every X seconds (0=never)", @@ -438,8 +438,8 @@ } }, "display_modes": { - "single": "Show single media viewer", - "grid": "Show media viewer for each camera in a grid" + "grid": "Show media viewer for each camera in a grid", + "single": "Show single media viewer" }, "editor": { "add_new_camera": "Add new camera", @@ -533,9 +533,6 @@ "what": "What", "where": "Where" }, - "media_viewer": { - "unseekable": "Seek time not found in media" - }, "media_filter": { "all": "All", "camera": "Camera", @@ -565,6 +562,9 @@ }, "where": "Where" }, + "media_viewer": { + "unseekable": "Seek time not found in media" + }, "recording": { "camera": "Camera", "duration": "Duration", @@ -588,4 +588,4 @@ }, "select_date": "Choose date" } -} +} \ No newline at end of file diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 570d1dc4..0a9b8e08 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -119,11 +119,16 @@ }, "thumbnails": { "editor_label": "Miniature", - "media": "Se mostrare miniature di clip o istantanee", - "medias": { + "events_media_type": "Se mostrare miniature di clip o istantanee", + "events_media_types": { "clips": "Miniature di clip", "snapshots": "Miniature istantanee" }, + "media_type": "", + "media_types": { + "events": "", + "recordings": "" + }, "mode": "Modalità miniatura", "modes": { "above": "Miniature sopra", @@ -191,8 +196,8 @@ }, "timeline": { "clustering_threshold": "Il conteggio degli eventi in cui sono raggruppati (0 = nessun clustering)", - "media": "I media vengono visualizzati la sequenza temporale", - "medias": { + "events_media_type": "I media vengono visualizzati la sequenza temporale", + "events_media_types": { "all": "Tutti i tipi di media", "clips": "Clip", "snapshots": "Istantanee" diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 2909b41b..7b91adc2 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -119,11 +119,16 @@ }, "thumbnails": { "editor_label": "Miniaturas", - "media": "Se deve mostrar miniaturas de clipes ou snapshots", - "medias": { + "events_media_type": "Se deve mostrar miniaturas de clipes ou snapshots", + "events_media_types": { "clips": "Miniaturas de clipes", "snapshots": "Miniaturas de Snapshots" }, + "media_type": "", + "media_types": { + "events": "", + "recordings": "" + }, "mode": "Modo de miniaturas", "modes": { "above": "Miniaturas acima da mídia", @@ -191,8 +196,8 @@ }, "timeline": { "clustering_threshold": "A contagem de eventos nos quais eles são agrupados (0 = sem agrupamento)", - "media": "A mídia que a linha do tempo exibe", - "medias": { + "events_media_type": "A mídia que a linha do tempo exibe", + "events_media_types": { "all": "Todos os tipos de mídia", "clips": "Clipes", "snapshots": "Instantâneos" diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index e224ccf0..c342ed09 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -119,11 +119,16 @@ }, "thumbnails": { "editor_label": "Editor de titulos", - "media": "Mostrar miniaturas de clipes ou snapshots", - "medias": { + "events_media_type": "Mostrar miniaturas de clipes ou snapshots", + "events_media_types": { "clips": "Miniaturas de clipes", "snapshots": "Miniaturas de Snapshots" }, + "media_type": "", + "media_types": { + "events": "", + "recordings": "" + }, "mode": "Modos", "modes": { "above": "Miniaturas acima da mídia", @@ -191,8 +196,8 @@ }, "timeline": { "clustering_threshold": "A contagem de eventos nos quais eles são agrupados (0 = sem agrupamento)", - "media": "A mídia que a linha do tempo exibe", - "medias": { + "events_media_type": "A mídia que a linha do tempo exibe", + "events_media_types": { "all": "Todos os tipos de mídia", "clips": "Clipes", "snapshots": "Instantâneos" From 220b4b99187918736ecc5f71f009ff976e107990 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 3 Feb 2024 15:18:40 -0800 Subject: [PATCH 086/189] Process range changes correctly when the date picker is used. --- src/components/timeline-core.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 4aee4deb..dadc0b3e 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -675,9 +675,6 @@ export class FrigateCardTimelineCore extends LitElement { byUser: boolean; event: Event & { additionalEvent: string }; }): Promise { - if (!properties.byUser) { - return; - } this._removeTargetBar(); if (!this._timeline || !this.view) { From 3ffcebfe6bc216288f629dcc9f551ec724416bb3 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 3 Feb 2024 16:36:07 -0800 Subject: [PATCH 087/189] Fix issues with 2-way audio for cameras that support only a single stream. --- src/card-controller/initialization-manager.ts | 35 +++++--- .../initialization-manager.test.ts | 82 +++++++++++++------ vite.config.ts | 6 +- 3 files changed, 84 insertions(+), 39 deletions(-) diff --git a/src/card-controller/initialization-manager.ts b/src/card-controller/initialization-manager.ts index 1b630fc3..aba58c22 100644 --- a/src/card-controller/initialization-manager.ts +++ b/src/card-controller/initialization-manager.ts @@ -21,11 +21,19 @@ export class InitializationManager { } public isInitializedMandatory(): boolean { + const config = this._api.getConfigManager().getConfig(); + if (!config) { + return false; + } + return ( this._initializer.isInitializedMultiple([ InitializationAspect.LANGUAGES, InitializationAspect.SIDE_LOAD_ELEMENTS, InitializationAspect.CAMERAS, + ...(config.live.microphone.always_connected + ? [InitializationAspect.MICROPHONE_CONNECT] + : []), ]) && // If there's no view, re-initialize (e.g. config changes). this._api.getViewManager().hasView() @@ -54,15 +62,25 @@ export class InitializationManager { return false; } - if (!this._api.getConfigManager().hasConfig()) { + const config = this._api.getConfigManager().getConfig(); + if (!config) { return false; } if ( - !(await this._initializer.initializeIfNecessary( - InitializationAspect.CAMERAS, - async () => await this._api.getCameraManager().initializeCamerasFromConfig(), - )) + !(await this._initializer.initializeMultipleIfNecessary({ + [InitializationAspect.CAMERAS]: async () => + await this._api.getCameraManager().initializeCamerasFromConfig(), + + // Connecting the microphone (if configured) is considered mandatory to + // avoid issues with some cameras that only allow 2-way audio on the + // first stream initialized. See: + // https://github.com/dermotduffy/frigate-hass-card/issues/1235 + ...(config.live.microphone.always_connected && { + [InitializationAspect.MICROPHONE_CONNECT]: async () => + await this._api.getMicrophoneManager().connect(), + }), + })) ) { return false; } @@ -104,9 +122,6 @@ export class InitializationManager { ...(config.menu.buttons.media_player.enabled ? [InitializationAspect.MEDIA_PLAYERS] : []), - ...(config.live.microphone.always_connected - ? [InitializationAspect.MICROPHONE_CONNECT] - : []), ]) ) { return true; @@ -118,10 +133,6 @@ export class InitializationManager { [InitializationAspect.MEDIA_PLAYERS]: async () => await this._api.getMediaPlayerManager().initialize(), }), - ...(config.live.microphone.always_connected && { - [InitializationAspect.MICROPHONE_CONNECT]: async () => - await this._api.getMicrophoneManager().connect(), - }), })) ) { return false; diff --git a/tests/card-controller/initialization-manager.test.ts b/tests/card-controller/initialization-manager.test.ts index 7ee8bd0b..7abc77b0 100644 --- a/tests/card-controller/initialization-manager.test.ts +++ b/tests/card-controller/initialization-manager.test.ts @@ -19,11 +19,20 @@ describe('InitializationManager', () => { }); describe('should correctly determine when mandatory initialization is required', () => { + it('without config', () => { + const api = createCardAPI(); + const initializer = mock(); + const manager = new InitializationManager(api, initializer); + + expect(manager.isInitializedMandatory()).toBeFalsy(); + }); + it('without aspects', () => { const api = createCardAPI(); const initializer = mock(); const manager = new InitializationManager(api, initializer); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); initializer.isInitializedMultiple.mockReturnValue(false); expect(manager.isInitializedMandatory()).toBeFalsy(); @@ -34,6 +43,7 @@ describe('InitializationManager', () => { const initializer = mock(); const manager = new InitializationManager(api, initializer); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); initializer.isInitializedMultiple.mockReturnValue(true); expect(manager.isInitializedMandatory()).toBeFalsy(); @@ -44,6 +54,27 @@ describe('InitializationManager', () => { const initializer = mock(); const manager = new InitializationManager(api, initializer); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + initializer.isInitializedMultiple.mockReturnValue(true); + vi.mocked(api.getViewManager().hasView).mockReturnValue(true); + + expect(manager.isInitializedMandatory()).toBeTruthy(); + }); + + it('with microphone if configured', () => { + const api = createCardAPI(); + const initializer = mock(); + const manager = new InitializationManager(api, initializer); + + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + live: { + microphone: { + always_connected: true, + }, + }, + }), + ); initializer.isInitializedMultiple.mockReturnValue(true); vi.mocked(api.getViewManager().hasView).mockReturnValue(true); @@ -67,7 +98,7 @@ describe('InitializationManager', () => { it('successfully', async () => { const api = createCardAPI(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); - vi.mocked(api.getConfigManager().hasConfig).mockReturnValue(true); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); vi.mocked(api.getMessageManager().hasMessage).mockReturnValue(false); vi.mocked(api.getQueryStringManager().hasViewRelatedActions).mockReturnValue( false, @@ -80,12 +111,31 @@ describe('InitializationManager', () => { expect(sideLoadHomeAssistantElements).toBeCalled(); expect(api.getCameraManager().initializeCamerasFromConfig).toBeCalled(); expect(api.getViewManager().setViewDefault).toBeCalled(); + expect(api.getMicrophoneManager().connect).not.toBeCalled(); + }); + + it('successfully with microphone if configured', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + live: { + microphone: { + always_connected: true, + }, + }, + }), + ); + const manager = new InitializationManager(api); + + expect(await manager.initializeMandatory()).toBeTruthy(); + expect(api.getMicrophoneManager().connect).toBeCalled(); }); it('successfully with querystring view', async () => { const api = createCardAPI(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); - vi.mocked(api.getConfigManager().hasConfig).mockReturnValue(true); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); vi.mocked(api.getMessageManager().hasMessage).mockReturnValue(false); vi.mocked(api.getQueryStringManager().hasViewRelatedActions).mockReturnValue(true); const manager = new InitializationManager(api); @@ -98,7 +148,7 @@ describe('InitializationManager', () => { it('with message set during initialization', async () => { const api = createCardAPI(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); - vi.mocked(api.getConfigManager().hasConfig).mockReturnValue(true); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); vi.mocked(api.getMessageManager().hasMessage).mockReturnValue(true); vi.mocked(api.getQueryStringManager().hasViewRelatedActions).mockReturnValue( false, @@ -124,12 +174,13 @@ describe('InitializationManager', () => { it('with cameras in progress', async () => { const api = createCardAPI(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); - vi.mocked(api.getConfigManager().hasConfig).mockReturnValue(true); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); const initializer = mock(); const manager = new InitializationManager(api, initializer); - initializer.initializeMultipleIfNecessary.mockResolvedValue(true); - initializer.initializeIfNecessary.mockResolvedValue(false); + initializer.initializeMultipleIfNecessary + .mockResolvedValueOnce(true) + .mockResolvedValueOnce(false); expect(await manager.initializeMandatory()).toBeFalsy(); }); @@ -154,17 +205,11 @@ describe('InitializationManager', () => { }, }, }, - live: { - microphone: { - always_connected: false, - }, - }, }), ); expect(await manager.initializeBackgroundIfNecessary()).toBeTruthy(); expect(api.getMediaPlayerManager().initialize).not.toBeCalled(); - expect(api.getMicrophoneManager().connect).not.toBeCalled(); }); it('successfully with all inititalizers', async () => { @@ -180,21 +225,15 @@ describe('InitializationManager', () => { }, }, }, - live: { - microphone: { - always_connected: true, - }, - }, }), ); expect(await manager.initializeBackgroundIfNecessary()).toBeTruthy(); expect(api.getMediaPlayerManager().initialize).toBeCalled(); - expect(api.getMicrophoneManager().connect).toBeCalled(); expect(api.getCardElementManager().update).toBeCalled(); }); - it('with media player and microphone connect in progress', async () => { + it('with media player in progress', async () => { const api = createCardAPI(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( @@ -206,11 +245,6 @@ describe('InitializationManager', () => { }, }, }, - live: { - microphone: { - always_connected: true, - }, - }, }), ); const initializer = mock(); diff --git a/vite.config.ts b/vite.config.ts index 67ec51a5..c9e5ca8e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,10 +10,10 @@ export default defineConfig({ // Thresholds will automatically be updated as coverage improves to avoid // back-sliding. thresholdAutoUpdate: true, - statements: 72.73, - branches: 61.93, + statements: 72.76, + branches: 61.95, functions: 74.01, - lines: 72.63, + lines: 72.66, }, }, }); From 2c8a41660cb9c2f3660b6182bcd7f81247e3ca3b Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 4 Feb 2024 12:31:00 -0800 Subject: [PATCH 088/189] Change datepicker library to fix iOS users. --- package.json | 1 - src/components/date-picker.ts | 45 +++++++++++++++----------- src/components/timeline-core.ts | 14 +-------- src/scss/date-picker.scss | 56 +++++++++++++++++++++++++++++---- src/scss/timeline-core.scss | 1 + yarn.lock | 21 +------------ 6 files changed, 80 insertions(+), 58 deletions(-) diff --git a/package.json b/package.json index 4c00c7ed..016203f5 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "home-assistant-js-websocket": "^8.0.0", "keycharm": "^0.4.0", "lit": "^2.3.1", - "lit-flatpickr": "^0.4.0", "lodash-es": "^4.17.21", "masonry-layout": "^4.2.2", "moment": "^2.29.4", diff --git a/src/components/date-picker.ts b/src/components/date-picker.ts index 36cdd277..42de9703 100644 --- a/src/components/date-picker.ts +++ b/src/components/date-picker.ts @@ -1,9 +1,9 @@ import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit'; -import 'lit-flatpickr'; -import { LitFlatpickr } from 'lit-flatpickr'; import { customElement } from 'lit/decorators.js'; import { createRef, ref, Ref } from 'lit/directives/ref.js'; +import { localize } from '../localize/localize'; import datePickerStyle from '../scss/date-picker.scss'; +import { stopEventFromActivatingCardWideActions } from '../utils/action'; import { dispatchFrigateCardEvent } from '../utils/basic'; export interface DatePickerEvent { @@ -12,24 +12,33 @@ export interface DatePickerEvent { @customElement('frigate-card-date-picker') export class FrigateCardDatePicker extends LitElement { - protected _refInput: Ref = createRef(); - - public open(): void { - this._refInput.value?.open(); - } + protected _refInput: Ref = createRef(); protected render(): TemplateResult { - return html` { - if (dates.length) { - // This is a single date picker, there should be only a single date. - dispatchFrigateCardEvent(this, 'date-picker:change', { - date: dates[0], - }); - } - }} - >`; + return html` { + const value = this._refInput.value?.value; + if (value) { + dispatchFrigateCardEvent(this, 'date-picker:change', { + date: new Date(value), + }); + } + }} + /> + { + stopEventFromActivatingCardWideActions(ev); + this._refInput.value?.showPicker(); + }} + > + `; } static get styles(): CSSResultGroup { diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index dadc0b3e..cb5b439a 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -334,22 +334,10 @@ export class FrigateCardTimelineCore extends LitElement { > ` : ''} - { - this._refDatePicker.value?.open(); - }} - > - ) => { - this._timeline?.setWindow( - startOfDay(ev.detail.date), - endOfDay(ev.detail.date), - ); + this._timeline?.moveTo(ev.detail.date); }} > diff --git a/src/scss/date-picker.scss b/src/scss/date-picker.scss index 4e336282..f29c3bae 100644 --- a/src/scss/date-picker.scss +++ b/src/scss/date-picker.scss @@ -1,7 +1,51 @@ -// The lit-flatpickr element itself is hidden as we only want the popup -// calender. -lit-flatpickr { - visibility: hidden; - width: 0px; - height: 0px; +:host { + display: inline-block; + position: relative; + width: var(--mdc-icon-size, 24px); + height: var(--mdc-icon-size, 24px); +} + +input { + display: block; + height: 100%; + width: 100%; + position: absolute; + + padding: 0px; + border: 0px; +} + +/** + * Hack warning: Safari on iOS does not support showPicker with + * datetime-local: + * https://caniuse.com/mdn-api_htmlinputelement_showpicker_datetime_local_input + * + * The hack is to render the input element in front of the icon, with an + * opacity of 0. This only works if the underlying input element accepts the + * click at the exact place the user happens to click. From trial and error, + * this seems to work better than expected / quite reliably, but had the user + * manually changed icon sizes with Safari iOS their experience may vary. + */ + +// webkit-touch-callout used to "detect" Safari on iOS. See: +// - https://stackoverflow.com/questions/30102792/css-media-query-to-target-only-ios-devices +@supports (-webkit-touch-callout: none) { + input { + // Need it to be in "front" but not visible to the naked eye. + opacity: 0; + z-index: 1; + } +} + +@supports not (-webkit-touch-callout: none) { + input { + visibility: hidden; + } +} + +ha-icon { + display: block; + height: 100%; + width: 100%; + position: absolute; } diff --git a/src/scss/timeline-core.scss b/src/scss/timeline-core.scss index 6d876cc9..e2bc517f 100644 --- a/src/scss/timeline-core.scss +++ b/src/scss/timeline-core.scss @@ -170,6 +170,7 @@ div.vis-tooltip { } .timeline-tools { + display: inline-flex; position: absolute; right: 2px; bottom: 2px; diff --git a/yarn.lock b/yarn.lock index e298d324..89af7f0d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3282,13 +3282,6 @@ __metadata: languageName: node linkType: hard -"flatpickr@npm:^4.6.13": - version: 4.6.13 - resolution: "flatpickr@npm:4.6.13" - checksum: 2cca1b8dc974e7673b51174ee3f0679ae3a6b79525a0c53bf49b87455ef358354e64acfd60b312e44cef208aab9750a1a48df32a0914046a53de6d9403742304 - languageName: node - linkType: hard - "flatted@npm:^3.1.0": version: 3.2.7 resolution: "flatted@npm:3.2.7" @@ -3357,7 +3350,6 @@ __metadata: jsdom: ^21.1.1 keycharm: ^0.4.0 lit: ^2.3.1 - lit-flatpickr: ^0.4.0 lodash-es: ^4.17.21 masonry-layout: ^4.2.2 moment: ^2.29.4 @@ -4384,17 +4376,6 @@ __metadata: languageName: node linkType: hard -"lit-flatpickr@npm:^0.4.0": - version: 0.4.0 - resolution: "lit-flatpickr@npm:0.4.0" - dependencies: - flatpickr: ^4.6.13 - lit: ^2.0.0 - tslib: ^1.11.0 - checksum: 2141902346bf3f2d291e1c3369317bb494641da48a3f69dabb891b7d065e2505b268c584cbc1859c36763374b9880399b17d93721539b2dc7d90c58988dba471 - languageName: node - linkType: hard - "lit-html@npm:^2.2.0, lit-html@npm:^2.6.0": version: 2.6.1 resolution: "lit-html@npm:2.6.1" @@ -6571,7 +6552,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^1.11.0, tslib@npm:^1.8.1": +"tslib@npm:^1.8.1": version: 1.14.1 resolution: "tslib@npm:1.14.1" checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd From cdf347ca7e080cec8671e036ef3b2e83172364d0 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 4 Feb 2024 15:49:48 -0800 Subject: [PATCH 089/189] Lint fixes. --- src/components/timeline-core.ts | 2 -- src/scss/date-picker.scss | 1 - 2 files changed, 3 deletions(-) diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index cb5b439a..17ae1d19 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -1,7 +1,5 @@ import add from 'date-fns/add'; import differenceInSeconds from 'date-fns/differenceInSeconds'; -import endOfDay from 'date-fns/endOfDay'; -import startOfDay from 'date-fns/startOfDay'; import sub from 'date-fns/sub'; import { CSSResultGroup, diff --git a/src/scss/date-picker.scss b/src/scss/date-picker.scss index f29c3bae..ae82974d 100644 --- a/src/scss/date-picker.scss +++ b/src/scss/date-picker.scss @@ -36,7 +36,6 @@ input { z-index: 1; } } - @supports not (-webkit-touch-callout: none) { input { visibility: hidden; From e21756887d32d3cc4353d39539c362439c92f9db Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 7 Feb 2024 22:06:21 -0800 Subject: [PATCH 090/189] Add custom date/time media filtering. --- src/camera-manager/range.ts | 1 + src/components-lib/media-filter-controller.ts | 509 ++++++++++ src/components/date-picker.ts | 37 +- src/components/media-filter.ts | 604 +++-------- src/components/select.ts | 24 +- src/components/timeline-core.ts | 4 +- src/localize/languages/en.json | 1 + src/localize/languages/it.json | 1 + src/localize/languages/pt-BR.json | 1 + src/localize/languages/pt-PT.json | 1 + src/scoped-elements/gr-select.js | 1 + src/scss/media-filter.scss | 23 + .../media-filter-controller.test.ts | 944 ++++++++++++++++++ vite.config.ts | 8 +- 14 files changed, 1667 insertions(+), 492 deletions(-) create mode 100644 src/components-lib/media-filter-controller.ts create mode 100644 tests/components-lib/media-filter-controller.test.ts diff --git a/src/camera-manager/range.ts b/src/camera-manager/range.ts index e680a5e1..789b4bbf 100644 --- a/src/camera-manager/range.ts +++ b/src/camera-manager/range.ts @@ -6,6 +6,7 @@ interface Range { } export type DateRange = Range; +export type PartialDateRange = Partial; interface MemoryRangeSetInterface { hasCoverage(range: T): boolean; diff --git a/src/components-lib/media-filter-controller.ts b/src/components-lib/media-filter-controller.ts new file mode 100644 index 00000000..ef5bfbd2 --- /dev/null +++ b/src/components-lib/media-filter-controller.ts @@ -0,0 +1,509 @@ +import endOfDay from 'date-fns/endOfDay'; +import endOfMonth from 'date-fns/endOfMonth'; +import endOfYesterday from 'date-fns/endOfYesterday'; +import endOfToday from 'date-fns/esm/endOfToday'; +import startOfToday from 'date-fns/esm/startOfToday'; +import format from 'date-fns/format'; +import parse from 'date-fns/parse'; +import startOfDay from 'date-fns/startOfDay'; +import startOfYesterday from 'date-fns/startOfYesterday'; +import sub from 'date-fns/sub'; +import { LitElement } from 'lit'; +import isEqual from 'lodash-es/isEqual'; +import orderBy from 'lodash-es/orderBy'; +import uniqWith from 'lodash-es/uniqWith'; +import { CameraManager } from '../camera-manager/manager'; +import { DateRange, PartialDateRange } from '../camera-manager/range'; +import { DataQuery, MediaMetadata, QueryType } from '../camera-manager/types'; +import { SelectOption, SelectValues } from '../components/select'; +import { CardWideConfig } from '../config/types'; +import { localize } from '../localize/localize'; +import { errorToConsole, formatDate, prettifyTitle } from '../utils/basic'; +import { executeMediaQueryForViewWithErrorDispatching } from '../utils/media-to-view'; +import { EventMediaQueries, RecordingMediaQueries } from '../view/media-queries'; +import { MediaQueriesClassifier } from '../view/media-queries-classifier'; +import { View } from '../view/view'; + +interface MediaFilterControls { + events: boolean; + recordings: boolean; + favorites: boolean; +} + +export interface MediaFilterCoreDefaults { + cameraIDs?: string[]; + favorite?: MediaFilterCoreFavoriteSelection; + mediaType?: MediaFilterMediaType; + what?: string[]; + when?: string; + where?: string[]; + tags?: string[]; +} + +export enum MediaFilterCoreFavoriteSelection { + Favorite = 'favorite', + NotFavorite = 'not-favorite', +} + +export enum MediaFilterCoreWhen { + Today = 'today', + Yesterday = 'yesterday', + PastWeek = 'past-week', + PastMonth = 'past-month', + Custom = 'custom', +} + +export enum MediaFilterMediaType { + Clips = 'clips', + Snapshots = 'snapshots', + Recordings = 'recordings', +} + +export class MediaFilterController { + protected _host: LitElement; + + protected _mediaTypeOptions: SelectOption[]; + protected _cameraOptions: SelectOption[] = []; + + protected _whenOptions: SelectOption[] = []; + protected _staticWhenOptions: SelectOption[]; + protected _metaDataWhenOptions: SelectOption[] = []; + + protected _whatOptions: SelectOption[] = []; + protected _whereOptions: SelectOption[] = []; + protected _tagsOptions: SelectOption[] = []; + protected _favoriteOptions: SelectOption[]; + + protected _defaults: MediaFilterCoreDefaults | null = null; + + constructor(host: LitElement) { + this._host = host; + + this._favoriteOptions = [ + { + value: MediaFilterCoreFavoriteSelection.Favorite, + label: localize('media_filter.favorite'), + }, + { + value: MediaFilterCoreFavoriteSelection.NotFavorite, + label: localize('media_filter.not_favorite'), + }, + ]; + this._mediaTypeOptions = [ + { + value: MediaFilterMediaType.Clips, + label: localize('media_filter.media_types.clips'), + }, + { + value: MediaFilterMediaType.Snapshots, + label: localize('media_filter.media_types.snapshots'), + }, + { + value: MediaFilterMediaType.Recordings, + label: localize('media_filter.media_types.recordings'), + }, + ]; + this._staticWhenOptions = [ + { + value: MediaFilterCoreWhen.Today, + label: localize('media_filter.whens.today'), + }, + { + value: MediaFilterCoreWhen.Yesterday, + label: localize('media_filter.whens.yesterday'), + }, + { + value: MediaFilterCoreWhen.PastWeek, + label: localize('media_filter.whens.past_week'), + }, + { + value: MediaFilterCoreWhen.PastMonth, + label: localize('media_filter.whens.past_month'), + }, + { + value: MediaFilterCoreWhen.Custom, + label: localize('media_filter.whens.custom'), + }, + ]; + this._computeWhenOptions(); + } + + public getMediaTypeOptions(): SelectOption[] { + return this._mediaTypeOptions; + } + public getCameraOptions(): SelectOption[] { + return this._cameraOptions; + } + public getWhenOptions(): SelectOption[] { + return this._whenOptions; + } + public getWhatOptions(): SelectOption[] { + return this._whatOptions; + } + public getWhereOptions(): SelectOption[] { + return this._whereOptions; + } + public getTagsOptions(): SelectOption[] { + return this._tagsOptions; + } + public getFavoriteOptions(): SelectOption[] { + return this._favoriteOptions; + } + public getDefaults(): MediaFilterCoreDefaults | null { + return this._defaults; + } + + public async valueChangeHandler( + cameraManager: CameraManager, + view: View, + cardWideConfig: CardWideConfig, + values: { + camera?: string | string[]; + mediaType?: MediaFilterMediaType; + when: { + selected?: string | string[]; + from?: Date | null; + to?: Date | null; + }; + favorite?: MediaFilterCoreFavoriteSelection; + where?: string | string[]; + what?: string | string[]; + tags?: string | string[]; + }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _ev?: unknown, + ): Promise { + const getArrayValueAsSet = (val?: SelectValues): Set | null => { + // The reported value may be '' if the field is clearable (i.e. the user + // can click 'x'). + if (val && Array.isArray(val) && val.length && !val.includes('')) { + return new Set([...val]); + } + return null; + }; + + const visibleCameraIDs = cameraManager.getStore().getVisibleCameraIDs(); + if (!visibleCameraIDs.size || !values.mediaType) { + return; + } + const cameraIDs = getArrayValueAsSet(values.camera) ?? visibleCameraIDs; + + const when = this._getWhen(values.when); + const favorite = values.favorite + ? values.favorite === MediaFilterCoreFavoriteSelection.Favorite + : null; + + // A note on views: + // - In the below, if the user selects a camera to view media for, the main + // view camera is also set to that value (e.g. a user browsing the + // gallery, chooses a different camera in the media filter, then + // subsequently chooses the live button -- they would expect the live view + // for that filtered camera not the prior camera). + // - Similarly, if the user chooses clips or snapshots, set the actual view + // to 'clips' or 'snapshots' in order to ensure the right icon is shown as + // selected in the menu. + const limit = cardWideConfig.performance?.features.media_chunk_size; + + if ( + values.mediaType === MediaFilterMediaType.Clips || + values.mediaType === MediaFilterMediaType.Snapshots + ) { + const where = getArrayValueAsSet(values.where); + const what = getArrayValueAsSet(values.what); + const tags = getArrayValueAsSet(values.tags); + + const queries = new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: cameraIDs, + ...(tags && { tags: tags }), + ...(what && { what: what }), + ...(where && { where: where }), + ...(favorite !== null && { favorite: favorite }), + ...(when && { + ...(when.start && { start: when.start }), + ...(when.end && { end: when.end }), + }), + ...(limit && { limit: limit }), + ...(values.mediaType === MediaFilterMediaType.Clips && { hasClip: true }), + ...(values.mediaType === MediaFilterMediaType.Snapshots && { + hasSnapshot: true, + }), + }, + ]); + + ( + await executeMediaQueryForViewWithErrorDispatching( + this._host, + cameraManager, + view, + queries, + { + // See 'A note on views' above for these two arguments. + ...(cameraIDs.size === 1 && { targetCameraID: [...cameraIDs][0] }), + targetView: + values.mediaType === MediaFilterMediaType.Clips ? 'clips' : 'snapshots', + }, + ) + )?.dispatchChangeEvent(this._host); + } else { + const queries = new RecordingMediaQueries([ + { + type: QueryType.Recording, + cameraIDs: cameraIDs, + ...(limit && { limit: limit }), + ...(when && { + ...(when.start && { start: when.start }), + ...(when.end && { end: when.end }), + }), + ...(favorite !== null && { favorite: favorite }), + }, + ]); + + ( + await executeMediaQueryForViewWithErrorDispatching( + this._host, + cameraManager, + view, + queries, + { + // See 'A note on views' above for these two arguments. + ...(cameraIDs.size === 1 && { targetCameraID: [...cameraIDs][0] }), + targetView: 'recordings', + }, + ) + )?.dispatchChangeEvent(this._host); + } + + // Need to ensure we update the element as the date-picker selections may + // have changed, and we need to un/set the selected class. + this._host.requestUpdate(); + } + + public computeInitialDefaultsFromView(cameraManager: CameraManager, view: View): void { + const queries = view.query?.getQueries(); + const visibleCameraIDs = cameraManager.getStore().getVisibleCameraIDs(); + if (!queries || !visibleCameraIDs.size) { + return; + } + + let mediaType: MediaFilterMediaType | undefined; + let cameraIDs: string[] | undefined; + let what: string[] | undefined; + let where: string[] | undefined; + let favorite: MediaFilterCoreFavoriteSelection | undefined; + let tags: string[] | undefined; + + const cameraIDSets = uniqWith( + queries.map((query: DataQuery) => query.cameraIDs), + isEqual, + ); + // Special note: If all visible cameras are selected, this is the same as no + // selector at all. + if (cameraIDSets.length === 1 && !isEqual(queries[0].cameraIDs, visibleCameraIDs)) { + cameraIDs = [...queries[0].cameraIDs]; + } + + const favoriteValues = uniqWith( + queries.map((query) => query.favorite), + isEqual, + ); + if (favoriteValues.length === 1 && queries[0].favorite !== undefined) { + favorite = queries[0].favorite + ? MediaFilterCoreFavoriteSelection.Favorite + : MediaFilterCoreFavoriteSelection.NotFavorite; + } + + /* istanbul ignore else: the else path cannot be reached -- @preserve */ + if (MediaQueriesClassifier.areEventQueries(view.query)) { + const queries = view.query.getQueries(); + + /* istanbul ignore if: the if path cannot be reached -- @preserve */ + if (!queries) { + return; + } + + const hasClips = uniqWith( + queries.map((query) => query.hasClip), + isEqual, + ); + const hasSnapshots = uniqWith( + queries.map((query) => query.hasSnapshot), + isEqual, + ); + if (hasClips.length === 1 && hasSnapshots.length === 1) { + mediaType = !!hasClips[0] + ? MediaFilterMediaType.Clips + : !!hasSnapshots[0] + ? MediaFilterMediaType.Snapshots + : undefined; + } + + const whatSets = uniqWith( + queries.map((query) => query.what), + isEqual, + ); + if (whatSets.length === 1 && queries[0].what?.size) { + what = [...queries[0].what]; + } + const whereSets = uniqWith( + queries.map((query) => query.where), + isEqual, + ); + if (whereSets.length === 1 && queries[0].where?.size) { + where = [...queries[0].where]; + } + const tagsSets = uniqWith( + queries.map((query) => query.tags), + isEqual, + ); + if (tagsSets.length === 1 && queries[0].tags?.size) { + tags = [...queries[0].tags]; + } + } else if (MediaQueriesClassifier.areRecordingQueries(view.query)) { + mediaType = MediaFilterMediaType.Recordings; + } + + this._defaults = { + ...(mediaType && { mediaType: mediaType }), + ...(cameraIDs && { cameraIDs: cameraIDs }), + ...(what && { what: what }), + ...(where && { where: where }), + ...(favorite !== undefined && { favorite: favorite }), + ...(tags && { tags: tags }), + }; + } + + public computeCameraOptions(cameraManager: CameraManager): void { + const cameras = cameraManager.getStore().getVisibleCameraIDs(); + this._cameraOptions = [...cameras].map((cameraID) => ({ + value: cameraID, + label: cameraManager.getCameraMetadata(cameraID)?.title ?? cameraID, + })); + } + + public async computeMetadataOptions(cameraManager: CameraManager): Promise { + let metadata: MediaMetadata | null = null; + try { + metadata = await cameraManager.getMediaMetadata(); + } catch (e) { + errorToConsole(e as Error); + } + if (!metadata) { + return; + } + + if (metadata.what) { + this._whatOptions = [...metadata.what] + .sort() + .map((what) => ({ value: what, label: prettifyTitle(what) })); + } + if (metadata.where) { + this._whereOptions = [...metadata.where] + .sort() + .map((where) => ({ value: where, label: prettifyTitle(where) })); + } + if (metadata.tags) { + this._tagsOptions = [...metadata.tags] + .sort() + .map((tag) => ({ value: tag, label: prettifyTitle(tag) })); + } + if (metadata.days) { + const yearMonths: Set = new Set(); + [...metadata.days].forEach((day) => { + // An efficient conversion: "2023-01-26" -> "2023-01" + yearMonths.add(day.substring(0, 7)); + }); + + const monthStarts: Date[] = []; + yearMonths.forEach((yearMonth) => { + monthStarts.push(parse(yearMonth, 'yyyy-MM', new Date())); + }); + + this._metaDataWhenOptions = orderBy( + monthStarts, + (date) => date.getTime(), + 'desc', + ).map((monthStart) => ({ + label: format(monthStart, 'MMMM yyyy'), + value: this._dateRangeToString({ + start: monthStart, + end: endOfMonth(monthStart), + }), + })); + this._computeWhenOptions(); + } + + this._host.requestUpdate(); + } + + public getControlsToShow( + cameraManager: CameraManager, + view: View, + ): MediaFilterControls { + const events = !!(view.query && MediaQueriesClassifier.areEventQueries(view.query)); + const recordings = !!( + view.query && MediaQueriesClassifier.areRecordingQueries(view.query) + ); + const managerCapabilities = cameraManager.getAggregateCameraCapabilities(); + + return { + events: events, + recordings: recordings, + favorites: events + ? !!managerCapabilities?.canFavoriteEvents + : recordings + ? !!managerCapabilities?.canFavoriteRecordings + : false, + }; + } + + protected _computeWhenOptions(): void { + this._whenOptions = [...this._staticWhenOptions, ...this._metaDataWhenOptions]; + } + + protected _dateRangeToString(when: DateRange): string { + return `${formatDate(when.start)},${formatDate(when.end)}`; + } + + protected _stringToDateRange(input: string): DateRange { + const dates = input.split(','); + return { + start: parse(dates[0], 'yyyy-MM-dd', new Date()), + end: endOfDay(parse(dates[1], 'yyyy-MM-dd', new Date())), + }; + } + + protected _getWhen(values: { + selected?: string | string[]; + from?: Date | null; + to?: Date | null; + }): PartialDateRange | null { + if (values.from || values.to) { + return { + ...(values.from && { start: values.from }), + ...(values.to && { end: values.to }), + }; + } + + if (!values.selected || Array.isArray(values.selected)) { + return null; + } + + const now = new Date(); + switch (values.selected) { + case MediaFilterCoreWhen.Custom: + return null; + case MediaFilterCoreWhen.Today: + return { start: startOfToday(), end: endOfToday() }; + case MediaFilterCoreWhen.Yesterday: + return { start: startOfYesterday(), end: endOfYesterday() }; + case MediaFilterCoreWhen.PastWeek: + return { start: startOfDay(sub(now, { days: 7 })), end: endOfDay(now) }; + case MediaFilterCoreWhen.PastMonth: + return { start: startOfDay(sub(now, { months: 1 })), end: endOfDay(now) }; + default: + return this._stringToDateRange(values.selected); + } + } +} diff --git a/src/components/date-picker.ts b/src/components/date-picker.ts index 42de9703..bf171ee4 100644 --- a/src/components/date-picker.ts +++ b/src/components/date-picker.ts @@ -1,5 +1,5 @@ import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit'; -import { customElement } from 'lit/decorators.js'; +import { customElement, property } from 'lit/decorators.js'; import { createRef, ref, Ref } from 'lit/directives/ref.js'; import { localize } from '../localize/localize'; import datePickerStyle from '../scss/date-picker.scss'; @@ -7,32 +7,47 @@ import { stopEventFromActivatingCardWideActions } from '../utils/action'; import { dispatchFrigateCardEvent } from '../utils/basic'; export interface DatePickerEvent { - date: Date; + date: Date | null; } @customElement('frigate-card-date-picker') export class FrigateCardDatePicker extends LitElement { + @property({ attribute: false }) + public icon?: string; + protected _refInput: Ref = createRef(); + get value(): Date | null { + return this._refInput.value?.value ? new Date(this._refInput.value.value) : null; + } + + public reset(): void { + if (this._refInput.value) { + this._refInput.value.value = ''; + } + } + protected render(): TemplateResult { + const changed = () => { + const value = this._refInput.value?.value; + + dispatchFrigateCardEvent(this, 'date-picker:change', { + date: value ? new Date(value) : null, + }); + }; + return html` { - const value = this._refInput.value?.value; - if (value) { - dispatchFrigateCardEvent(this, 'date-picker:change', { - date: new Date(value), - }); - } - }} + @input=${() => changed()} + @change=${() => changed()} /> { stopEventFromActivatingCardWideActions(ev); this._refInput.value?.showPicker(); diff --git a/src/components/media-filter.ts b/src/components/media-filter.ts index e442770f..b85be987 100644 --- a/src/components/media-filter.ts +++ b/src/components/media-filter.ts @@ -1,73 +1,32 @@ -import { ScopedRegistryHost } from '@lit-labs/scoped-registry-mixin'; import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import endOfDay from 'date-fns/endOfDay'; -import endOfMonth from 'date-fns/endOfMonth'; -import endOfYesterday from 'date-fns/endOfYesterday'; -import endOfToday from 'date-fns/esm/endOfToday'; -import startOfToday from 'date-fns/esm/startOfToday'; -import format from 'date-fns/format'; -import parse from 'date-fns/parse'; -import startOfDay from 'date-fns/startOfDay'; -import startOfYesterday from 'date-fns/startOfYesterday'; -import sub from 'date-fns/sub'; +import { ScopedRegistryHost } from '@lit-labs/scoped-registry-mixin'; import { CSSResultGroup, html, LitElement, PropertyValues, - ReactiveController, - ReactiveControllerHost, TemplateResult, unsafeCSS, } from 'lit'; import { customElement, property } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; import { createRef, ref, Ref } from 'lit/directives/ref.js'; -import isEqual from 'lodash-es/isEqual'; -import orderBy from 'lodash-es/orderBy'; -import uniqWith from 'lodash-es/uniqWith'; import { CameraManager } from '../camera-manager/manager'; -import { DateRange } from '../camera-manager/range'; -import { DataQuery, MediaMetadata, QueryType } from '../camera-manager/types'; +import { + MediaFilterController, + MediaFilterCoreFavoriteSelection, + MediaFilterCoreWhen, + MediaFilterMediaType, +} from '../components-lib/media-filter-controller'; import { CardWideConfig } from '../config/types'; import { localize } from '../localize/localize'; import mediaFilterStyle from '../scss/media-filter.scss'; -import { errorToConsole, formatDate, prettifyTitle } from '../utils/basic'; -import { executeMediaQueryForViewWithErrorDispatching } from '../utils/media-to-view.js'; -import { EventMediaQueries, RecordingMediaQueries } from '../view/media-queries'; -import { MediaQueriesClassifier } from '../view/media-queries-classifier'; import { View } from '../view/view'; -import './select'; -import { FrigateCardSelect, SelectOption, SelectValues } from './select'; +import { FrigateCardDatePicker } from './date-picker'; +import './date-picker.js'; +import { FrigateCardSelect } from './select'; import './select.js'; -interface MediaFilterCoreDefaults { - cameraIDs?: string[]; - favorite?: MediaFilterCoreFavoriteSelection; - mediaType?: MediaFilterMediaType; - what?: string[]; - when?: string; - where?: string[]; - tags?: string[]; -} - -export enum MediaFilterCoreFavoriteSelection { - Favorite = 'favorite', - NotFavorite = 'not-favorite', -} - -export enum MediaFilterCoreWhen { - Today = 'today', - Yesterday = 'yesterday', - PastWeek = 'past-week', - PastMonth = 'past-month', -} - -export enum MediaFilterMediaType { - Clips = 'clips', - Snapshots = 'snapshots', - Recordings = 'recordings', -} - @customElement('frigate-card-media-filter') class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) { @property({ attribute: false }) @@ -84,429 +43,196 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) { static elementDefinitions = { 'frigate-card-select': FrigateCardSelect, + 'frigate-card-date-picker': FrigateCardDatePicker, }; - protected _mediaMetadataController?: MediaMetadataController; - - protected _mediaTypeOptions: SelectOption[]; - protected _cameraOptions?: SelectOption[]; - protected _whenOptions?: SelectOption[]; - protected _favoriteOptions: SelectOption[]; - - protected _defaults: MediaFilterCoreDefaults | null = null; + protected _mediaFilterController = new MediaFilterController(this); protected _refMediaType: Ref = createRef(); protected _refCamera: Ref = createRef(); protected _refWhen: Ref = createRef(); + protected _refWhenFrom: Ref = createRef(); + protected _refWhenTo: Ref = createRef(); protected _refWhat: Ref = createRef(); protected _refWhere: Ref = createRef(); protected _refFavorite: Ref = createRef(); protected _refTags: Ref = createRef(); - constructor() { - super(); - this._favoriteOptions = [ - { - value: MediaFilterCoreFavoriteSelection.Favorite, - label: localize('media_filter.favorite'), - }, - { - value: MediaFilterCoreFavoriteSelection.NotFavorite, - label: localize('media_filter.not_favorite'), - }, - ]; - this._mediaTypeOptions = [ - { - value: MediaFilterMediaType.Clips, - label: localize('media_filter.media_types.clips'), - }, - { - value: MediaFilterMediaType.Snapshots, - label: localize('media_filter.media_types.snapshots'), - }, - { - value: MediaFilterMediaType.Recordings, - label: localize('media_filter.media_types.recordings'), - }, - ]; - } - - protected _stringToDateRange(input: string): DateRange { - const dates = input.split(','); - return { - start: parse(dates[0], 'yyyy-MM-dd', new Date()), - end: parse(dates[1], 'yyyy-MM-dd', new Date()), - }; - } - - protected _dateRangeToString(when: DateRange): string { - return `${formatDate(when.start)},${formatDate(when.end)}`; - } - - protected _getWhen(): DateRange | null { - const value = this._refWhen.value?.value; - if (!value || Array.isArray(value)) { - return null; - } - const now = new Date(); - switch (value) { - case MediaFilterCoreWhen.Today: - return { start: startOfToday(), end: endOfToday() }; - case MediaFilterCoreWhen.Yesterday: - return { start: startOfYesterday(), end: endOfYesterday() }; - case MediaFilterCoreWhen.PastWeek: - return { start: startOfDay(sub(now, { days: 7 })), end: endOfDay(now) }; - case MediaFilterCoreWhen.PastMonth: - return { start: startOfDay(sub(now, { months: 1 })), end: endOfDay(now) }; - default: - return this._stringToDateRange(value); - } - } - - protected async _valueChangedHandler( - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _ev: CustomEvent<{ value: unknown }>, - ): Promise { - const visibleCameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); - if (!this.hass || !visibleCameraIDs || !this.cameraManager || !this.view) { - return; - } - - const getArrayValueAsSet = (val?: SelectValues): Set | null => { - // The reported value may be '' if the field is clearable (i.e. the user - // can click 'x'). - if (val && Array.isArray(val) && val.length && !val.includes('')) { - return new Set([...val]); - } - return null; - }; - - const cameraIDs = - getArrayValueAsSet(this._refCamera.value?.value) ?? visibleCameraIDs; - const mediaType = this._refMediaType.value?.value as - | MediaFilterMediaType - | undefined; - const when = this._getWhen(); - const favorite = this._refFavorite.value?.value - ? this._refFavorite.value.value === MediaFilterCoreFavoriteSelection.Favorite - : null; - - // A note on views: - // - In the below, if the user selects a camera to view media for, the main - // view camera is also set to that value (e.g. a user browsing the - // gallery, chooses a different camera in the media filter, then - // subsequently chooses the live button -- they would expect the live view - // for that filtered camera not the prior camera). - // - Similarly, if the user chooses clips or snapshots, set the actual view - // to 'clips' or 'snapshots' in order to ensure the right icon is shown as - // selected in the menu. - const limit = this.cardWideConfig?.performance?.features.media_chunk_size; - - if ( - mediaType === MediaFilterMediaType.Clips || - mediaType === MediaFilterMediaType.Snapshots - ) { - const where = getArrayValueAsSet(this._refWhere.value?.value); - const what = getArrayValueAsSet(this._refWhat.value?.value); - const tags = getArrayValueAsSet(this._refTags.value?.value); - - const queries = new EventMediaQueries([ - { - type: QueryType.Event, - cameraIDs: cameraIDs, - ...(tags && { tags: tags }), - ...(what && { what: what }), - ...(where && { where: where }), - ...(favorite !== null && { favorite: favorite }), - ...(when && { start: when.start, end: when.end }), - ...(limit && { limit: limit }), - ...(mediaType === MediaFilterMediaType.Clips && { hasClip: true }), - ...(mediaType === MediaFilterMediaType.Snapshots && { - hasSnapshot: true, - }), - }, - ]); - - ( - await executeMediaQueryForViewWithErrorDispatching( - this, - this.cameraManager, - this.view, - queries, - { - // See 'A note on views' above for these two arguments. - ...(cameraIDs.size === 1 && { targetCameraID: [...cameraIDs][0] }), - targetView: mediaType === MediaFilterMediaType.Clips ? 'clips' : 'snapshots', - }, - ) - )?.dispatchChangeEvent(this); - } else if (mediaType === MediaFilterMediaType.Recordings) { - const queries = new RecordingMediaQueries([ - { - type: QueryType.Recording, - cameraIDs: cameraIDs, - ...(limit && { limit: limit }), - ...(when && { start: when.start, end: when.end }), - }, - ]); - - ( - await executeMediaQueryForViewWithErrorDispatching( - this, - this.cameraManager, - this.view, - queries, - { - // See 'A note on views' above for these two arguments. - ...(cameraIDs.size === 1 && { targetCameraID: [...cameraIDs][0] }), - targetView: 'recordings', - }, - ) - )?.dispatchChangeEvent(this); - } - } - protected willUpdate(changedProps: PropertyValues): void { - if (changedProps.has('cameraManager')) { - const cameras = this.cameraManager?.getStore().getVisibleCameraIDs(); - if (cameras) { - this._cameraOptions = [...cameras].map((cameraID) => ({ - value: cameraID, - label: this.hass - ? this.cameraManager?.getCameraMetadata(cameraID)?.title ?? '' - : '', - })); - } + if (changedProps.has('cameraManager') && this.cameraManager) { + this._mediaFilterController.computeCameraOptions(this.cameraManager); + this._mediaFilterController.computeMetadataOptions(this.cameraManager); } - - if (changedProps.has('cameraManager') && this.hass && this.cameraManager) { - this._mediaMetadataController = new MediaMetadataController( - this, + if ( + changedProps.has('view') && + !changedProps.get('view') && + this.view && + this.cameraManager + ) { + this._mediaFilterController.computeInitialDefaultsFromView( this.cameraManager, + this.view, ); } - - // Relative time based options are not pre-computed here to ensure relative - // dates (e.g. 'today') are always calculated when activated not when - // rendered. - this._whenOptions = [ - { - value: MediaFilterCoreWhen.Today, - label: localize('media_filter.whens.today'), - }, - { - value: MediaFilterCoreWhen.Yesterday, - label: localize('media_filter.whens.yesterday'), - }, - { - value: MediaFilterCoreWhen.PastWeek, - label: localize('media_filter.whens.past_week'), - }, - { - value: MediaFilterCoreWhen.PastMonth, - label: localize('media_filter.whens.past_month'), - }, - ...(this._mediaMetadataController?.whenOptions ?? []), - ]; - - if (changedProps.has('view')) { - const newDefaults = this._getDefaultsFromView(); - if (!isEqual(newDefaults, this._defaults)) { - this._defaults = newDefaults; - } - } - } - - protected _getDefaultsFromView(): MediaFilterCoreDefaults | null { - const queries = this.view?.query?.getQueries(); - const visibleCameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); - if (!this.view || !queries || !visibleCameraIDs) { - return null; - } - - let mediaType: MediaFilterMediaType | undefined; - let cameraIDs: string[] | undefined; - let what: string[] | undefined; - let where: string[] | undefined; - let favorite: MediaFilterCoreFavoriteSelection | undefined; - let tags: string[] | undefined; - - const cameraIDSets = uniqWith( - queries.map((query: DataQuery) => query.cameraIDs), - isEqual, - ); - // Special note: If all visible cameras are selected, this is the same as no - // selector at all. - if (cameraIDSets.length === 1 && !isEqual(queries[0].cameraIDs, visibleCameraIDs)) { - cameraIDs = [...queries[0].cameraIDs]; - } - - const favoriteValues = uniqWith( - queries.map((query) => query.favorite), - isEqual, - ); - if (favoriteValues.length === 1 && queries[0].favorite !== undefined) { - favorite = queries[0].favorite - ? MediaFilterCoreFavoriteSelection.Favorite - : MediaFilterCoreFavoriteSelection.NotFavorite; - } - - if (MediaQueriesClassifier.areEventQueries(this.view.query)) { - const queries = this.view.query.getQueries(); - if (!queries) { - return null; - } - - const hasClips = uniqWith( - queries.map((query) => query.hasClip), - isEqual, - ); - const hasSnapshots = uniqWith( - queries.map((query) => query.hasSnapshot), - isEqual, - ); - if (hasClips.length === 1 && hasSnapshots.length === 1) { - mediaType = !!hasClips[0] - ? MediaFilterMediaType.Clips - : !!hasSnapshots[0] - ? MediaFilterMediaType.Snapshots - : undefined; - } - - const whatSets = uniqWith( - queries.map((query) => query.what), - isEqual, - ); - if (whatSets.length === 1 && queries[0].what?.size) { - what = [...queries[0].what]; - } - const whereSets = uniqWith( - queries.map((query) => query.where), - isEqual, - ); - if (whereSets.length === 1 && queries[0].where?.size) { - where = [...queries[0].where]; - } - const tagsSets = uniqWith( - queries.map((query) => query.tags), - isEqual, - ); - if (tagsSets.length === 1 && queries[0].tags?.size) { - tags = [...queries[0].tags]; - } - } else if (MediaQueriesClassifier.areRecordingQueries(this.view.query)) { - mediaType = MediaFilterMediaType.Recordings; - } - - return { - ...(mediaType && { mediaType: mediaType }), - ...(cameraIDs && { cameraIDs: cameraIDs }), - ...(what && { what: what }), - ...(where && { where: where }), - ...(favorite !== undefined && { favorite: favorite }), - ...(tags && { tags: tags }), - }; } protected render(): TemplateResult | void { - if (!this._mediaMetadataController) { + const valueChange = async () => { + if (!this.cameraManager || !this.view || !this.cardWideConfig) { + return; + } + await this._mediaFilterController.valueChangeHandler( + this.cameraManager, + this.view, + this.cardWideConfig, + { + camera: this._refCamera.value?.value, + mediaType: this._refMediaType.value?.value as MediaFilterMediaType | undefined, + when: { + selected: this._refWhen.value?.value, + from: this._refWhenFrom.value?.value, + to: this._refWhenTo.value?.value, + }, + favorite: this._refFavorite.value?.value as + | MediaFilterCoreFavoriteSelection + | undefined, + where: this._refWhere.value?.value, + what: this._refWhat.value?.value, + tags: this._refTags.value?.value, + }, + ); + }; + + // Ensure that the "When" selector and the custom calendar to/from selectors + // are ~mutually exclusive. + const whenChange = async (whenPriority?: 'custom' | 'selected'): Promise => { + if (whenPriority === 'custom' && this._refWhen.value) { + if (!this._refWhenFrom.value?.value && !this._refWhenTo.value?.value) { + this._refWhen.value.reset(); + } else { + this._refWhen.value.value = MediaFilterCoreWhen.Custom; + } + } else if (this._refWhen.value?.value !== MediaFilterCoreWhen.Custom) { + this._refWhenFrom.value?.reset(); + this._refWhenTo.value?.reset(); + } + await valueChange(); + }; + + if (!this.cameraManager || !this.view) { return; } - const areEvents = !!( - this.view?.query && MediaQueriesClassifier.areEventQueries(this.view.query) + const controls = this._mediaFilterController.getControlsToShow( + this.cameraManager, + this.view, ); - const areRecordings = !!( - this.view?.query && MediaQueriesClassifier.areRecordingQueries(this.view.query) - ); - const managerCapabilities = this.cameraManager?.getAggregateCameraCapabilities(); - - // Which media controls are shown depends on the view. - const showFavoriteControl = areEvents - ? !!managerCapabilities?.canFavoriteEvents - : areRecordings - ? !!managerCapabilities?.canFavoriteRecordings - : false; + const defaults = this._mediaFilterController.getDefaults(); + const whatOptions = this._mediaFilterController.getWhatOptions(); + const tagsOptions = this._mediaFilterController.getTagsOptions(); + const whereOptions = this._mediaFilterController.getWhereOptions(); return html` - - valueChange()} > +
+ whenChange('selected')} + > + + whenChange('custom')} + > + + whenChange('custom')} + > + +
valueChange()} > - ${areEvents && this._mediaMetadataController.whatOptions.length + ${controls.events && whatOptions.length ? html` valueChange()} > ` : ''} - ${areEvents && this._mediaMetadataController.tagsOptions.length + ${controls.events && tagsOptions.length ? html` valueChange()} > ` : ''} - ${areEvents && this._mediaMetadataController.whereOptions.length + ${controls.events && whereOptions.length ? html` valueChange()} > ` : ''} - ${showFavoriteControl + ${controls.favorites ? html` valueChange()} > ` @@ -518,76 +244,6 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) { } } -export class MediaMetadataController implements ReactiveController { - protected _host: ReactiveControllerHost; - protected _cameraManager: CameraManager; - - public tagsOptions: SelectOption[] = []; - public whenOptions: SelectOption[] = []; - public whatOptions: SelectOption[] = []; - public whereOptions: SelectOption[] = []; - - constructor(host: ReactiveControllerHost, cameraManager: CameraManager) { - this._host = host; - this._cameraManager = cameraManager; - host.addController(this); - } - - protected _dateRangeToString(when: DateRange): string { - return `${formatDate(when.start)},${formatDate(when.end)}`; - } - - async hostConnected() { - let metadata: MediaMetadata | null; - try { - metadata = await this._cameraManager.getMediaMetadata(); - } catch (e) { - errorToConsole(e as Error); - return; - } - if (!metadata) { - return; - } - - if (metadata.what) { - this.whatOptions = [...metadata.what] - .sort() - .map((what) => ({ value: what, label: prettifyTitle(what) })); - } - if (metadata.where) { - this.whereOptions = [...metadata.where] - .sort() - .map((where) => ({ value: where, label: prettifyTitle(where) })); - } - if (metadata.tags) { - this.tagsOptions = [...metadata.tags] - .sort() - .map((tag) => ({ value: tag, label: prettifyTitle(tag) })); - } - if (metadata.days) { - const yearMonths: Set = new Set(); - [...metadata.days].forEach((day) => { - // An efficient conversion: "2023-01-26" -> "2023-01" - yearMonths.add(day.substring(0, 7)); - }); - const monthStarts: Date[] = []; - yearMonths.forEach((yearMonth) => { - monthStarts.push(parse(yearMonth, 'yyyy-MM', new Date())); - }); - this.whenOptions = orderBy(monthStarts, (date) => date.getTime(), 'desc').map( - (monthStart) => ({ - label: format(monthStart, 'MMMM yyyy'), - value: this._dateRangeToString({ - start: monthStart, - end: endOfMonth(monthStart), - }), - }), - ); - } - this._host.requestUpdate(); - } -} - declare global { interface HTMLElementTagNameMap { 'frigate-card-media-filter': FrigateCardMediaFilter; diff --git a/src/components/select.ts b/src/components/select.ts index a56930a9..3a1bca79 100644 --- a/src/components/select.ts +++ b/src/components/select.ts @@ -1,4 +1,11 @@ -import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit'; +import { + CSSResultGroup, + html, + LitElement, + PropertyValues, + TemplateResult, + unsafeCSS, +} from 'lit'; import { property } from 'lit/decorators.js'; import { createRef, ref, Ref } from 'lit/directives/ref.js'; import selectStyle from '../scss/select.scss'; @@ -26,6 +33,9 @@ export class FrigateCardSelect extends ScopedRegistryHost(LitElement) { @property({ attribute: false, hasChanged: contentsChanged }) public value?: SelectValues; + @property({ attribute: false, hasChanged: contentsChanged }) + public initialValue?: SelectValues; + @property({ attribute: true }) public label?: string; @@ -45,6 +55,10 @@ export class FrigateCardSelect extends ScopedRegistryHost(LitElement) { ...grSelectElements, }; + public reset(): void { + this.value = undefined; + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars protected _valueChangedHandler(_ev: CustomEvent<{ value: unknown }>): void { const value: SelectValues | undefined = this._refSelect.value?.value; @@ -57,6 +71,12 @@ export class FrigateCardSelect extends ScopedRegistryHost(LitElement) { } } + protected willUpdate(changedProps: PropertyValues): void { + if (changedProps.has('initialValue') && this.initialValue && !this.value) { + this.value = this.initialValue; + } + } + protected render(): TemplateResult | void { return html` ${this.options?.map( diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 17ae1d19..a7ed952d 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -335,7 +335,9 @@ export class FrigateCardTimelineCore extends LitElement { ) => { - this._timeline?.moveTo(ev.detail.date); + if (ev.detail.date) { + this._timeline?.moveTo(ev.detail.date); + } }} > diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 241f4e4c..eed8911a 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -555,6 +555,7 @@ "what": "What", "when": "When", "whens": { + "custom": "Custom", "past_month": "Past Month", "past_week": "Past Week", "today": "Today", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 0a9b8e08..c2296b40 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -545,6 +545,7 @@ "what": "Che cosa", "when": "Quando", "whens": { + "custom": "", "past_month": "Mese scorso", "past_week": "Settimana scorso", "today": "Oggi", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 7b91adc2..99b8ebc0 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -554,6 +554,7 @@ "what": "O que", "when": "Quando", "whens": { + "custom": "", "past_month": "Mês passado", "past_week": "Semana passada", "today": "Hoje", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index c342ed09..10686bba 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -537,6 +537,7 @@ "what": "O que", "when": "Quando", "whens": { + "custom": "", "past_month": "O mes passado", "past_week": "A semana passada", "today": "Hoje", diff --git a/src/scoped-elements/gr-select.js b/src/scoped-elements/gr-select.js index ac71fe58..8285255e 100644 --- a/src/scoped-elements/gr-select.js +++ b/src/scoped-elements/gr-select.js @@ -2,6 +2,7 @@ import { GrSelect } from '@graphiteds/core/components/gr-select'; import { GrMenuItem } from '@graphiteds/core/components/gr-menu-item'; // It was difficult to find a multi-select web component that matches these criteria: +// - Is a dropdown vs multi-select list. // - Open source. // - Supports being in a ScopedRegistry out of the box (i.e. does not auto-register with customElements). // - Looks attractive / compatible with mostly Material elements. diff --git a/src/scss/media-filter.scss b/src/scss/media-filter.scss index 6dc9aa2f..e70f5f69 100644 --- a/src/scss/media-filter.scss +++ b/src/scss/media-filter.scss @@ -22,3 +22,26 @@ frigate-card-select { padding: 5px; } + +div.when { + display: inline-flex; + align-items: flex-end; +} +div.when frigate-card-select { + flex: 1; +} +div.when frigate-card-date-picker { + // Visually line up the date-picker icon with the bottom of the select + // dropdown. + padding-bottom: 5px; + transition: width 0.5s ease-in-out; +} +div.when frigate-card-date-picker { + color: var(--secondary-color); +} +div.when frigate-card-date-picker.selected { + color: var(--primary-color); +} +div.when frigate-card-date-picker.hidden { + width: 0px; +} \ No newline at end of file diff --git a/tests/components-lib/media-filter-controller.test.ts b/tests/components-lib/media-filter-controller.test.ts new file mode 100644 index 00000000..3ade7447 --- /dev/null +++ b/tests/components-lib/media-filter-controller.test.ts @@ -0,0 +1,944 @@ +import endOfDay from 'date-fns/endOfDay'; +import startOfDay from 'date-fns/startOfDay'; +import sub from 'date-fns/sub'; +import { LitElement } from 'lit'; +import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { CameraManagerStore } from '../../src/camera-manager/store'; +import { QueryType } from '../../src/camera-manager/types'; +import { + MediaFilterController, + MediaFilterCoreDefaults, + MediaFilterCoreFavoriteSelection, + MediaFilterCoreWhen, + MediaFilterMediaType +} from '../../src/components-lib/media-filter-controller'; +import { executeMediaQueryForViewWithErrorDispatching } from '../../src/utils/media-to-view'; +import { + EventMediaQueries, + MediaQueries, + RecordingMediaQueries +} from '../../src/view/media-queries'; +import { + createAggregateCameraCapabilities, + createCameraConfig, + createCameraManager, + createPerformanceConfig, + createStore, + createView +} from '../test-utils'; + +vi.mock('../../src/utils/media-to-view'); + +const createHost = (): LitElement => { + const host = document.createElement('div') as unknown as LitElement; + host.requestUpdate = vi.fn(); + return host; +}; + +const createCameraStore = (): CameraManagerStore => { + return createStore([ + { + cameraID: 'camera.kitchen', + config: createCameraConfig({ + camera_entity: 'camera.kitchen', + }), + }, + ]); +}; + +// @vitest-environment jsdom +describe('MediaFilterController', () => { + beforeEach(() => { + vi.restoreAllMocks(); + }); + + describe('should have correct default options', () => { + it('media type', () => { + const controller = new MediaFilterController(createHost()); + expect(controller.getMediaTypeOptions()).toEqual([ + { + value: MediaFilterMediaType.Clips, + label: 'Clips', + }, + { + value: MediaFilterMediaType.Snapshots, + label: 'Snapshots', + }, + { + value: MediaFilterMediaType.Recordings, + label: 'Recordings', + }, + ]); + }); + + it('favorite', () => { + const controller = new MediaFilterController(createHost()); + expect(controller.getFavoriteOptions()).toEqual([ + { + value: MediaFilterCoreFavoriteSelection.Favorite, + label: 'Favorite', + }, + { + value: MediaFilterCoreFavoriteSelection.NotFavorite, + label: 'Not Favorite', + }, + ]); + }); + + it('when', () => { + const controller = new MediaFilterController(createHost()); + expect(controller.getWhenOptions()).toEqual([ + { + value: MediaFilterCoreWhen.Today, + label: 'Today', + }, + { + value: MediaFilterCoreWhen.Yesterday, + label: 'Yesterday', + }, + { + value: MediaFilterCoreWhen.PastWeek, + label: 'Past Week', + }, + { + value: MediaFilterCoreWhen.PastMonth, + label: 'Past Month', + }, + { + value: MediaFilterCoreWhen.Custom, + label: 'Custom', + }, + ]); + }); + + it('cameras', () => { + const controller = new MediaFilterController(createHost()); + expect(controller.getCameraOptions()).toEqual([]); + }); + + it('what', () => { + const controller = new MediaFilterController(createHost()); + expect(controller.getWhatOptions()).toEqual([]); + }); + + it('where', () => { + const controller = new MediaFilterController(createHost()); + expect(controller.getWhereOptions()).toEqual([]); + }); + + it('tags', () => { + const controller = new MediaFilterController(createHost()); + expect(controller.getTagsOptions()).toEqual([]); + }); + }); + + describe('should calculate correct dynamic options', () => { + describe('cameras', () => { + it('with valid camera', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getCameraMetadata).mockReturnValue({ + title: 'Kitchen Camera', + icon: 'mdi:camera', + }); + vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); + + const controller = new MediaFilterController(createHost()); + controller.computeCameraOptions(cameraManager); + expect(controller.getCameraOptions()).toEqual([ + { + label: 'Kitchen Camera', + value: 'camera.kitchen', + }, + ]); + }); + + it('without camera metadata', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getCameraMetadata).mockReturnValue(null); + vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); + + const controller = new MediaFilterController(createHost()); + controller.computeCameraOptions(cameraManager); + expect(controller.getCameraOptions()).toEqual([ + { + label: 'camera.kitchen', + value: 'camera.kitchen', + }, + ]); + }); + }); + + describe('metadata', () => { + it('with failed getMediaMetadata call', async () => { + vi.spyOn(global.console, 'warn').mockReturnValue(undefined); + + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getMediaMetadata).mockRejectedValue(new Error('error')); + + const host = createHost(); + const controller = new MediaFilterController(host); + await controller.computeMetadataOptions(cameraManager); + expect(host.requestUpdate).not.toBeCalled(); + }); + + it('with metadata for what', async () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getMediaMetadata).mockResolvedValue({ + what: new Set(['person', 'car']), + }); + + const host = createHost(); + const controller = new MediaFilterController(host); + await controller.computeMetadataOptions(cameraManager); + expect(controller.getWhatOptions()).toEqual([ + { + value: 'car', + label: 'Car', + }, + { + value: 'person', + label: 'Person', + }, + ]); + expect(host.requestUpdate).toBeCalled(); + }); + + it('with metadata for where', async () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getMediaMetadata).mockResolvedValue({ + where: new Set(['front_door', 'back_yard']), + }); + + const host = createHost(); + const controller = new MediaFilterController(host); + await controller.computeMetadataOptions(cameraManager); + expect(controller.getWhereOptions()).toEqual([ + { + value: 'back_yard', + label: 'Back Yard', + }, + { + value: 'front_door', + label: 'Front Door', + }, + ]); + expect(host.requestUpdate).toBeCalled(); + }); + + it('with metadata for tags', async () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getMediaMetadata).mockResolvedValue({ + tags: new Set(['tag-1', 'tag-2']), + }); + + const host = createHost(); + const controller = new MediaFilterController(host); + await controller.computeMetadataOptions(cameraManager); + expect(controller.getTagsOptions()).toEqual([ + { + value: 'tag-1', + label: 'Tag-1', + }, + { + value: 'tag-2', + label: 'Tag-2', + }, + ]); + expect(host.requestUpdate).toBeCalled(); + }); + + it('with metadata for days', async () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getMediaMetadata).mockResolvedValue({ + days: new Set(['2024-02-04', '2024-02-05']), + }); + + const host = createHost(); + const controller = new MediaFilterController(host); + await controller.computeMetadataOptions(cameraManager); + + expect(controller.getWhenOptions()).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + value: '2024-02-01,2024-02-29', + label: 'February 2024', + }), + ]), + ); + expect(host.requestUpdate).toBeCalled(); + }); + }); + }); + + describe('should get correct controls to show', () => { + it('view with events', () => { + const view = createView({ query: new EventMediaQueries() }); + const cameraManager = createCameraManager(); + + const controller = new MediaFilterController(createHost()); + expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ + events: true, + recordings: false, + }); + }); + + it('view with recordings', () => { + const view = createView({ query: new RecordingMediaQueries() }); + const cameraManager = createCameraManager(); + + const controller = new MediaFilterController(createHost()); + expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ + events: false, + recordings: true, + }); + }); + + it('can favorite events', () => { + const view = createView({ query: new EventMediaQueries() }); + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ canFavoriteEvents: true }), + ); + + const controller = new MediaFilterController(createHost()); + expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ + favorites: true, + }); + }); + + it('can favorite recordings', () => { + const view = createView({ query: new RecordingMediaQueries() }); + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ canFavoriteRecordings: true }), + ); + + const controller = new MediaFilterController(createHost()); + expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ + favorites: true, + }); + }); + + it('can not favorite without a query', () => { + const view = createView(); + const cameraManager = createCameraManager(); + + const controller = new MediaFilterController(createHost()); + expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ + favorites: false, + }); + }); + }); + + describe('should handle value change', () => { + it('must have visible cameras', async () => { + const host = createHost(); + const controller = new MediaFilterController(host); + await controller.valueChangeHandler( + createCameraManager(), + createView(), + {}, + { when: {} }, + ); + + expect(host.requestUpdate).not.toBeCalled(); + }); + + describe('with events media type', () => { + it.each([['clips' as const], ['snapshots' as const]])( + '%s', + async (viewName: 'clips' | 'snapshots') => { + const eventListener = vi.fn(); + const host = createHost(); + host.addEventListener('frigate-card:view:change', eventListener); + + const controller = new MediaFilterController(host); + const cameraManager = createCameraManager(); + const view = createView(); + vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); + vi.mocked(executeMediaQueryForViewWithErrorDispatching).mockResolvedValueOnce( + view, + ); + + const from = new Date('2024-02-06T21:59'); + const to = new Date('2024-02-06T22:00'); + + await controller.valueChangeHandler( + cameraManager, + view, + { + performance: createPerformanceConfig({ + features: { + media_chunk_size: 11, + }, + }), + }, + { + mediaType: + viewName === 'clips' + ? MediaFilterMediaType.Clips + : MediaFilterMediaType.Snapshots, + when: { + to: to, + from: from, + }, + tags: ['tag-1', 'tag-2'], + what: ['what-1', 'what-2'], + where: ['where-1', 'where-2'], + favorite: MediaFilterCoreFavoriteSelection.Favorite, + }, + ); + + expect(vi.mocked(executeMediaQueryForViewWithErrorDispatching)).toBeCalledWith( + host, + cameraManager, + view, + expect.anything(), + { + targetCameraID: 'camera.kitchen', + targetView: viewName, + }, + ); + expect( + vi + .mocked(executeMediaQueryForViewWithErrorDispatching) + .mock.calls[0][3].getQueries(), + ).toEqual([ + { + cameraIDs: new Set(['camera.kitchen']), + ...(viewName === 'clips' && { hasClip: true }), + ...(viewName === 'snapshots' && { hasSnapshot: true }), + type: 'event-query', + tags: new Set(['tag-1', 'tag-2']), + what: new Set(['what-1', 'what-2']), + where: new Set(['where-1', 'where-2']), + favorite: true, + start: from, + end: to, + limit: 11, + }, + ]); + + expect(eventListener).toBeCalled(); + expect(host.requestUpdate).toBeCalled(); + }, + ); + }); + + it('with recordings media type', async () => { + const eventListener = vi.fn(); + const host = createHost(); + host.addEventListener('frigate-card:view:change', eventListener); + + const controller = new MediaFilterController(host); + const cameraManager = createCameraManager(); + const view = createView(); + vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); + vi.mocked(executeMediaQueryForViewWithErrorDispatching).mockResolvedValueOnce( + view, + ); + + const from = new Date('2024-02-06T21:59'); + const to = new Date('2024-02-06T22:00'); + + await controller.valueChangeHandler( + cameraManager, + view, + { + performance: createPerformanceConfig({ + features: { + media_chunk_size: 11, + }, + }), + }, + { + mediaType: MediaFilterMediaType.Recordings, + when: { + to: to, + from: from, + }, + favorite: MediaFilterCoreFavoriteSelection.Favorite, + }, + ); + + expect(vi.mocked(executeMediaQueryForViewWithErrorDispatching)).toBeCalledWith( + host, + cameraManager, + view, + expect.anything(), + { + targetCameraID: 'camera.kitchen', + targetView: 'recordings', + }, + ); + expect( + vi + .mocked(executeMediaQueryForViewWithErrorDispatching) + .mock.calls[0][3].getQueries(), + ).toEqual([ + { + cameraIDs: new Set(['camera.kitchen']), + type: 'recording-query', + favorite: true, + start: from, + end: to, + limit: 11, + }, + ]); + + expect(eventListener).toBeCalled(); + expect(host.requestUpdate).toBeCalled(); + }); + + it('without favorites', async () => { + const controller = new MediaFilterController(createHost()); + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); + + await controller.valueChangeHandler( + cameraManager, + createView(), + {}, + { + mediaType: MediaFilterMediaType.Recordings, + when: {}, + }, + ); + + expect( + vi + .mocked(executeMediaQueryForViewWithErrorDispatching) + .mock.calls[0][3].getQueries(), + ).toEqual([ + { + cameraIDs: new Set(['camera.kitchen']), + type: 'recording-query', + }, + ]); + }); + + describe('with fixed when selection', () => { + const date = new Date('2024-10-01T17:14'); + + beforeAll(() => { + vi.useFakeTimers(); + vi.setSystemTime(date); + }); + + afterAll(() => { + vi.useFakeTimers(); + }); + + it.each([ + [MediaFilterCoreWhen.Today, startOfDay(date), endOfDay(date)], + [ + MediaFilterCoreWhen.Yesterday, + startOfDay(sub(date, { days: 1 })), + endOfDay(sub(date, { days: 1 })), + ], + [ + MediaFilterCoreWhen.PastWeek, + startOfDay(sub(date, { days: 7 })), + endOfDay(date), + ], + [ + MediaFilterCoreWhen.PastMonth, + startOfDay(sub(date, { months: 1 })), + endOfDay(date), + ], + [ + '2024-02-01,2024-02-29', + new Date('2024-02-01T00:00:00'), + new Date('2024-02-29T23:59:59.999'), + ], + ])('%s', async (value: MediaFilterCoreWhen | string, from: Date, to: Date) => { + const controller = new MediaFilterController(createHost()); + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); + + await controller.valueChangeHandler( + cameraManager, + createView(), + {}, + { + mediaType: MediaFilterMediaType.Recordings, + when: { + selected: value, + }, + }, + ); + + expect( + vi + .mocked(executeMediaQueryForViewWithErrorDispatching) + .mock.calls[0][3].getQueries(), + ).toEqual([ + { + cameraIDs: new Set(['camera.kitchen']), + type: 'recording-query', + start: from, + end: to, + }, + ]); + }); + + it('custom without values', async () => { + const controller = new MediaFilterController(createHost()); + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); + + await controller.valueChangeHandler( + cameraManager, + createView(), + {}, + { + mediaType: MediaFilterMediaType.Recordings, + when: { + selected: MediaFilterCoreWhen.Custom, + }, + }, + ); + + expect( + vi + .mocked(executeMediaQueryForViewWithErrorDispatching) + .mock.calls[0][3].getQueries(), + ).toEqual([ + { + cameraIDs: new Set(['camera.kitchen']), + type: 'recording-query', + }, + ]); + }); + }); + }); + + describe('should calculate correct defaults', () => { + it('with no queries', () => { + const controller = new MediaFilterController(createHost()); + + controller.computeInitialDefaultsFromView(createCameraManager(), createView()); + + expect(controller.getDefaults()).toBeNull(); + }); + + it('with no cameras', () => { + const controller = new MediaFilterController(createHost()); + + controller.computeInitialDefaultsFromView( + createCameraManager(), + createView({ + query: new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera.kitchen']) }, + ]), + }), + ); + + expect(controller.getDefaults()).toBeNull(); + }); + + describe('for queries', () => { + it.each([ + [ + 'same cameras' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen', 'camera.living_room']), + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen', 'camera.living_room']), + }, + ]), + { + cameraIDs: ['camera.kitchen', 'camera.living_room'], + }, + ], + [ + 'different cameras' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.living_room']), + }, + ]), + {}, + ], + [ + 'all cameras' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + }, + ]), + {}, + ], + [ + 'different favorites ' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + favorite: true, + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + favorite: undefined, + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + favorite: false, + }, + ]), + {}, + ], + [ + 'all favorites' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + favorite: true, + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + favorite: true, + }, + ]), + { + favorite: MediaFilterCoreFavoriteSelection.Favorite, + }, + ], + [ + 'all not favorites' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + favorite: false, + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + favorite: false, + }, + ]), + { + favorite: MediaFilterCoreFavoriteSelection.NotFavorite, + }, + ], + [ + 'same hasClip' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + hasClip: true, + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + hasClip: true, + }, + ]), + { + mediaType: MediaFilterMediaType.Clips, + }, + ], + [ + 'different hasClip' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + hasClip: true, + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + hasClip: false, + }, + ]), + {}, + ], + [ + 'same hasSnapshot' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + hasSnapshot: true, + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + hasSnapshot: true, + }, + ]), + { + mediaType: MediaFilterMediaType.Snapshots, + }, + ], + [ + 'different hasSnapshot' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + hasSnapshot: true, + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + hasSnapshot: false, + }, + ]), + {}, + ], + [ + 'same what' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + what: new Set(['person']), + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + what: new Set(['person']), + }, + ]), + { + what: ['person' as const], + }, + ], + [ + 'different what' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + what: new Set(['person']), + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + what: new Set(['car']), + }, + ]), + {}, + ], + [ + 'same where' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + where: new Set(['front_door']), + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + where: new Set(['front_door']), + }, + ]), + { + where: ['front_door' as const], + }, + ], + [ + 'different where' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + where: new Set(['front_door']), + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + where: new Set(['back_steps']), + }, + ]), + {}, + ], + [ + 'same tags' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + tags: new Set(['tag-1']), + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + tags: new Set(['tag-1']), + }, + ]), + { + tags: ['tag-1' as const], + }, + ], + [ + 'different tags' as const, + new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + tags: new Set(['tag-1']), + }, + { + type: QueryType.Event, + cameraIDs: new Set(['camera.kitchen']), + tags: new Set(['tag-2']), + }, + ]), + {}, + ], + [ + 'recordings' as const, + new RecordingMediaQueries([ + { + type: QueryType.Recording, + cameraIDs: new Set(['camera.kitchen']), + }, + ]), + { + mediaType: MediaFilterMediaType.Recordings + }, + ], + ])( + '%s', + ( + _name: string, + mediaQueries: MediaQueries, + defaults: MediaFilterCoreDefaults | null, + ) => { + const controller = new MediaFilterController(createHost()); + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); + + controller.computeInitialDefaultsFromView( + cameraManager, + createView({ + query: mediaQueries, + }), + ); + + expect(controller.getDefaults()).toEqual(defaults); + }, + ); + }); + }); +}); diff --git a/vite.config.ts b/vite.config.ts index c9e5ca8e..cd591cf8 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,10 +10,10 @@ export default defineConfig({ // Thresholds will automatically be updated as coverage improves to avoid // back-sliding. thresholdAutoUpdate: true, - statements: 72.76, - branches: 61.95, - functions: 74.01, - lines: 72.66, + statements: 73.59, + branches: 63.6, + functions: 74.86, + lines: 73.49, }, }, }); From 559f8368b1ad8cfc032e3e25c5f3265b59e9eb47 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 7 Feb 2024 22:18:43 -0800 Subject: [PATCH 091/189] Fix test coverage target. --- vite.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vite.config.ts b/vite.config.ts index cd591cf8..108e7a88 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -13,7 +13,7 @@ export default defineConfig({ statements: 73.59, branches: 63.6, functions: 74.86, - lines: 73.49, + lines: 73.48, }, }, }); From 88bea0ae7d761d588ca00795ba40d6d0807abf55 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 3 Mar 2024 15:40:20 -0800 Subject: [PATCH 092/189] Allow camera engines to signal events to the card. --- .vscode/extensions.json | 2 +- .vscode/settings.json | 4 +- README.md | 162 +- images/{scan-mode.gif => triggered.gif} | Bin package.json | 18 +- src/camera-manager/browse-media/camera.ts | 30 + .../browse-media/engine-browse-media.ts | 42 +- src/camera-manager/camera.ts | 71 +- src/camera-manager/engine-factory.ts | 8 +- src/camera-manager/engine.ts | 14 +- src/camera-manager/frigate/camera.ts | 308 + src/camera-manager/frigate/engine-frigate.ts | 243 +- src/camera-manager/frigate/types.ts | 33 + src/camera-manager/generic/engine-generic.ts | 42 +- src/camera-manager/manager.ts | 143 +- .../motioneye/engine-motioneye.ts | 26 +- src/camera-manager/store.ts | 5 +- src/camera-manager/types.ts | 16 + src/camera-manager/utils.ts | 2 +- src/card-controller/card-element-manager.ts | 11 + src/card-controller/conditions-manager.ts | 4 + src/card-controller/hass-manager.ts | 21 +- src/card-controller/triggers-manager.ts | 166 +- src/card-controller/types.ts | 52 +- src/card-controller/view-manager.ts | 1 - src/card.ts | 9 +- src/components-lib/timeline-source.ts | 4 + src/components/live/go2rtc/video-rtc.d.ts | 2 +- src/components/live/live-go2rtc.ts | 6 +- src/components/surround.ts | 2 +- src/components/viewer.ts | 4 +- src/config-mgmt.ts | 55 +- src/config/types.ts | 56 +- src/const.ts | 34 +- src/editor.ts | 209 +- src/localize/languages/en.json | 17 +- src/localize/languages/it.json | 13 +- src/localize/languages/pt-BR.json | 13 +- src/localize/languages/pt-PT.json | 13 +- src/utils/ha/index.ts | 70 +- src/utils/ha/types.ts | 21 + src/utils/initializer/initializer.ts | 2 +- src/utils/media-to-view.ts | 11 +- .../browse-media/camera.test.ts | 37 + tests/camera-manager/camera.test.ts | 169 +- tests/camera-manager/frigate/camera.test.ts | 965 +++ .../generic/engine-generic.test.ts | 2 +- tests/camera-manager/manager.test.ts | 1229 ++++ tests/camera-manager/store.test.ts | 31 +- tests/camera-manager/utils.test.ts | 13 + .../card-element-manager.test.ts | 4 + .../conditions-manager.test.ts | 8 + tests/card-controller/hass-manager.test.ts | 43 - .../card-controller/triggers-manager.test.ts | 429 +- tests/config-mgmt.test.ts | 140 +- tests/config/types.test.ts | 14 +- tests/test-utils.ts | 46 +- tests/utils/ha/index.test.ts | 106 +- tests/utils/media-to-view.test.ts | 70 + vite.config.ts | 15 +- yarn.lock | 6407 +++++++++-------- 61 files changed, 7480 insertions(+), 4213 deletions(-) rename images/{scan-mode.gif => triggered.gif} (100%) create mode 100644 src/camera-manager/browse-media/camera.ts create mode 100644 src/camera-manager/frigate/camera.ts create mode 100644 src/utils/ha/types.ts create mode 100644 tests/camera-manager/browse-media/camera.test.ts create mode 100644 tests/camera-manager/frigate/camera.test.ts create mode 100644 tests/camera-manager/manager.test.ts diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 317f0be3..89715101 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -9,6 +9,6 @@ "davidanson.vscode-markdownlint", "redhat.vscode-yaml", "lokalise.i18n-ally", - "zixuanchen.vitest-explorer" + "vitest.explorer" ] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 1814a117..a4a10938 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,7 +4,5 @@ "i18n-ally.sortKeys": true, "i18n-ally.keepFulfilled": true, "i18n-ally.editor.preferEditor": true, - "i18n-ally.translate.saveAsCandidates": true, - "vitest.commandLine": "npx vitest --root .", - "diffEditor.experimental.useVersion2": true + "i18n-ally.translate.saveAsCandidates": true } diff --git a/README.md b/README.md index 3400d854..bb8359d3 100644 --- a/README.md +++ b/README.md @@ -167,11 +167,11 @@ See the [fully expanded cameras configuration example](#config-expanded-cameras) ##### Engine Capabilities -|Engine|Live|Supports clips|Supports Snapshots|Supports Recordings|Supports Timeline|Supports PTZ out of the box|Supports manually configured PTZ|Favorite events|Favorite recordings| -| - | - | - | - | - | - | - | - | - | - | -|`frigate`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | -|`generic`| :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | -|`motioneye`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | +|Engine|Live|Supports clips|Supports Snapshots|Supports Recordings|Supports Timeline|Supports PTZ out of the box|Supports manually configured PTZ|Favorite events|Favorite recordings|Detect new events|Detect new snapshots|Detect new clips| +| - | - | - | - | - | - | - | - | - | - | - | - | - | +|`frigate`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +|`generic`| :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | +|`motioneye`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | ##### Live providers supported per Engine @@ -320,7 +320,7 @@ cameras: #### Camera Trigger Configuration -The `triggers` block configures what triggers a camera. Triggering can be used to either reset to the default view / update the card, or active the camera in [scan mode](#scan-mode). +The `triggers` block configures what triggers a camera. Triggering can be used to activate an action (e.g. view a camera in live, reset the card to the default view). See [`view.triggers`](#view.triggers) to control what happens when a camera is triggered. ```yaml cameras: @@ -329,8 +329,9 @@ cameras: | Option | Default | Overridable | Description | | - | - | - | - | +| `events` | `[events, clips, snapshots]` | :white_check_mark: | Whether to trigger the camera when `events` occur (whether or not media is available) or whenever updated `clips` or `snapshots` are detected. Detection support varies by camera engine, see [engine capabilities](#engines). | | `motion` | `false` | :white_check_mark: | Whether to not to trigger the camera by automatically detecting and using the motion `binary_sensor` for this camera. This autodetection only works for Frigate cameras, and only when the motion `binary_sensor` entity has been enabled in Home Assistant.| -| `occupancy` | `true` | :white_check_mark: | Whether to not to trigger the camera by automatically detecting and using the occupancy `binary_sensor` for this camera and its configured zones and labels. This autodetection only works for Frigate cameras, and only when the occupancy `binary_sensor` entity has been enabled in Home Assistant. If this camera has configured zones, only occupancy sensors for those zones are used -- if the overall _camera_ occupancy sensor is also required, it can be manually added to `entities`. If this camera has configured labels, only occupancy sensors for those labels are used.| +| `occupancy` | `false` | :white_check_mark: | Whether to not to trigger the camera by automatically detecting and using the occupancy `binary_sensor` for this camera and its configured zones and labels. This autodetection only works for Frigate cameras, and only when the occupancy `binary_sensor` entity has been enabled in Home Assistant. If this camera has configured zones, only occupancy sensors for those zones are used -- if the overall _camera_ occupancy sensor is also required, it can be manually added to `entities`. If this camera has configured labels, only occupancy sensors for those labels are used. | | `entities` | | :white_check_mark: | Whether to not to trigger the camera when the state of any Home Assistant entity becomes active (i.e. state becomes `on` or `open`). This works for Frigate or non-Frigate cameras.| #### Camera Cast Configuration @@ -403,46 +404,49 @@ See the [fully expanded view configuration example](#config-expanded-view) for h | `dark_mode` | `off` | :white_check_mark: | Whether or not to turn dark mode `on`, `off` or `auto` to automatically turn on if the card `interaction_seconds` has expired (i.e. card has been left unattended for that period of time) or if dark mode is enabled in the HA profile theme setting. Dark mode dims the brightness by `25%`.| | `interaction_seconds` | `300` | :white_check_mark: | After a mouse/touch interaction with the Frigate card, it will be considered "interacted with" until this number of seconds elapses without further interaction. May be used in conditions with the `interaction` parameter of a [Frigate card condition](#frigate-card-condition) or with `reset_after_interaction` (below). `0` means no interactions are reported / acted upon. | | `reset_after_interaction` | `true` | :white_check_mark: | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | -| `update_seconds` | `0` | :white_check_mark: | A number of seconds after which to automatically update/refresh the default view. See [card updates](#card-updates) below for behavior and usecases. If the default view occurs sooner (e.g. manually) the timer will start over. `0` disables this functionality.| -| `update_force` | `false` | :white_check_mark: | Whether automated card updates/refreshes should ignore user interaction. See [card updates](#card-updates) below for behavior and usecases.| -| `update_entities` | | :white_check_mark: | **YAML only**: A card-wide list of entities that should cause the view to reset to the default (if the entity only pertains to a particular camera use `triggers` for the selected camera instead, see [Trigger Configuration](#camera-triggers-configuration)). See [card updates](#card-updates) below for behavior and usecases.| +| `update_seconds` | `0` | :white_check_mark: | A number of seconds after which to automatically update/refresh the default view. If the default view occurs sooner (e.g. manually) the timer will start over. `0` disables this functionality.| +| `update_force` | `false` | :white_check_mark: | Whether automated card updates should ignore user interaction. | +| `update_entities` | | :white_check_mark: | **YAML only**: A card-wide list of entities that should cause the view to reset to the default (if the entity only pertains to a particular camera use `triggers` for the selected camera instead, see [Trigger Configuration](#camera-triggers-configuration)). | | `update_cycle_camera` | `false` | :white_check_mark: | When set to `true` the selected camera is cycled on each default view change. | | `render_entities` | | :white_check_mark: | **YAML only**: A list of entity ids that should cause the card to re-render 'in-place'. The view/camera is not changed. `update_*` flags do not pertain/relate to the behavior of this flag. This should **very** rarely be needed, but could be useful if the card is both setting and changing HA state of the same object as could be the case for some complex `card_mod` scenarios ([example](https://github.com/dermotduffy/frigate-hass-card/issues/343)). | -| `scan` | | :white_check_mark: | Configuration for [scan mode](#scan-mode). | +| `triggers` | | :white_check_mark: | How to react when a camera is [triggered](#view.triggers). | | `actions` | | :white_check_mark: | Actions to use for all views, individual actions may be overriden by view-specific actions. See [actions](#actions) below.| - + -#### View: Scan Mode configuration +#### View: Triggers configuration All configuration is under: ```yaml view: - scan: + triggers: ``` -Scan mode allows the card to automatically "follow the action". In this mode the card will automatically execute an action (defined by `trigger_action`) when a camera is 'triggered', by default selecting that camera in the `live` view . The trigger entities considered are defined by your camera configuration (see `triggers` parameters). An untrigger is defined as the state for all the configured entities returning to inactive (i.e. not `on` or `open`), with an optional number of seconds to wait prior to the untriggering (see `untrigger_seconds`). +The `view.triggers` block controls how the card reacts when a camera is triggered (note that _what_ triggers the camera is controlled by the `triggers` block within the config for a given camera). This can be used for a variety of purposes, such as allowing the card to automatically "follow the action" (i.e. change to `live` for a camera that triggers). -When the camera untriggers, a different action (defined by `untrigger_action`) is automatically executed, by default returning the card to the default view and camera. +When a camera untriggers (e.g. an entity state returning to something other than `on` or `open`), an action can also be taken, with an optional number of seconds to wait prior to the acting (see `untrigger_seconds`). -By default, triggering is only allowed when there is no ongoing human interaction with the card. This behavior can be controlled by the `interaction_mode` parameter. +By default, triggering is only allowed when there is no ongoing human +interaction with the card. This behavior can be controlled by the +`interaction_mode` parameter. -Scan mode tracks Home Assistant state *changes* -- when the card is first started, it takes an active change in state to trigger (i.e. an already occupied room will not trigger it, but a newly occupied room will). +Triggers based on Home Assistant entities require state *changes* -- when the card is first started, it takes an active change in state to trigger (i.e. an already occupied room will not trigger, but a newly occupied room will). | Option | Default | Overridable | Description | | - | - | - | - | -| `enabled` | `false` | :white_check_mark: | Whether to enable scan mode. | | `filter_selected_camera` | `false` | :white_check_mark: | If set to `true` will only trigger on the currently selected camera.| -| `show_trigger_status` | `true` | :white_check_mark: | Whether or not the `live` view should show a visual indication that it is triggered (a pulsing border around the camera edge). | -| `untrigger_seconds` | `0` | :white_check_mark: | The number of seconds to wait after all entities are inactive before untriggering. | -| `actions` | | :white_check_mark: | The actions to take when scan mode triggers (see below). | +| `show_trigger_status` | `false` | :white_check_mark: | Whether or not the `live` view should show a visual indication that it is triggered (a pulsing border around the camera edge). | +| `untrigger_seconds` | `0` | :white_check_mark: | The number of seconds to wait after a camera untriggers before considering the card untriggered and taking the `untrigger` action. | +| `actions` | | :white_check_mark: | The actions to take when a camera is triggered (see below). | -#### View: Scan Mode Actions configuration +#### View: Triggers Action configuration -| `trigger` | `live` | :white_check_mark | When `live` the trigger will select the triggered camera in `live` view, when `none` will take no action. | -| `untrigger` | `default` | :white_check_mark | When `default` the untrigger will return to the default view and camera, when `none` will take no action. | -| `interaction_mode` | `inactive` | :white_check_mark: | Whether actions should be taken when the card is being interacted with. If `all`, actions will always be taken regardless. If `inactive` actions will only be taken if the card has *not* had human interaction recently (as defined by `view.interaction_seconds`). If `active` actions will only be taken if the card *has* had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed.| +| Option | Default | Overridable | Description | +| - | - | - | - | +| `trigger` | `default` | :white_check_mark | If set to `default` the default view of the card will be reloaded. If set to `live` the triggered camera will be selected in `live` view. If set to `media` the appropriate media view (e.g. `clip` or `snapshot`) will be chosen to match a newly available media item (please note that only some camera engines support new media detection, e.g. `frigate`, see [engines](#engines)). If set to `none` no action is taken. | +| `untrigger` | `none` | :white_check_mark | If set to `default` the the default view of the card will be reloaded. If set to `none` no action will be taken. | +| `interaction_mode` | `inactive` | :white_check_mark: | Whether actions should be taken when the card is being interacted with. If `all`, actions will always left be taken regardless. If `inactive` actions will only be taken if the card has *not* had human interaction recently (as defined by `view.interaction_seconds`). If `active` actions will only be taken if the card *has* had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed. | ### Menu Options @@ -1293,7 +1297,7 @@ All variables listed are under a `conditions:` section. | `media_loaded` | If `true` the condition is satisfied if there is media load**ED** (not load**ING**) in the card (e.g. a clip, snapshot or live view). This may be used to hide controls during media loading or when a message (not media) is being displayed. Note that if `true` this condition will never be satisfied for views that do not themselves load media directly (e.g. gallery).| | `media_query` | Any valid [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries) string. Media queries must start and end with parentheses. This may be used to alter card configuration based on device/media properties (e.g. viewport width, orientation). Please note that `width` and `height` refer to the entire viewport not just the card. See the [media query example](#media-query-example).| | `interacted` | If `true` the condition is satisfied if the card has had human interaction within `view.interaction_seconds` elapsed seconds. If `false` the condition is satisfied if the card has **NOT** had human interaction in that time. | -| `triggered` | A list of camera IDs which, if triggered in [scan mode](#scan-mode), satisfy the condition.| +| `triggered` | A list of camera IDs which, if [triggered](#camera-triggers-configuration), satisfy the condition.| | `microphone` | A object to include microphone state as part of the condition evaluation. See below.| See the [example below](#frigate-card-conditional-example) for a real-world example of how these conditions can be used. @@ -1619,11 +1623,11 @@ Cast media from the card to a local player. Cast media -### Scan Mode +### Triggered! Automatically choose the camera with the action! -Cast media +Triggered! ### Thumbnail Drawers @@ -1935,15 +1939,14 @@ view: render_entities: - switch.render_card dark_mode: 'off' - scan: - enabled: false - show_trigger_status: true - filter_selected_camera: false + triggers: + show_trigger_status: false + filter_selected_camera: true untrigger_seconds: 0 actions: - interaction_mode: 'inactive' as const, - trigger: 'live' as const, - untrigger: 'default' as const, + interaction_mode: inactive + trigger: default + untrigger: none actions: entity: light.office_main_lights tap_action: @@ -3580,8 +3583,6 @@ cameras: ``` - - ### Using `card-mod` to style the card This card allows the use of @@ -3670,28 +3671,33 @@ cameras: ``` -### Using Scan Mode +### Taking action when a camera is triggered! -Have your card follow the action with Scan Mode. +Have your card follow the action when a camera is triggered.
- Expand: Using scan mode + Expand: Changing to `live` when a camera is triggered ```yaml type: custom:frigate-card cameras: + # This is a Frigate camera which will automatically be triggered when events occur. - camera_entity: camera.back_yard - # This camera will automatically trigger by occupancy. + # This is a Frigate camera which will only be triggered by motion entity changes or a door being opened. - camera_entity: camera.front_door triggers: occupancy: false motion: true entities: - binary_sensor.door_opened + events: [] view: - scan: - enabled: true - trigger_show_border: true + triggers: + show_trigger_status: true + filter_selected_camera: false + actions: + trigger: live + untrigger: default ```
@@ -3720,9 +3726,6 @@ elements: conditions: triggered: - camera.office -view: - scan: - enabled: true ``` @@ -4146,72 +4149,9 @@ automations: frigate_card_action: live_substream_off conditions: interaction: true -view: - scan: - enabled: true ``` - - -## Card Refreshes - -Four sets of flags govern when the card will automatically refresh in the -absence of user interaction. - -The following table describes the behavior these flags have. - -### Card Update Truth Table - -Note that no (other) automated updates are permitted when [scan mode](#scan-mode) is being triggered. - -In the below "Trigger Entities" refers to the combination of `view.update_entities` and the `triggers.entities` for the currently selected camera (which in turn will also include the occupancy and motion sensor entities for Frigate cameras if `triggers.occupancy` and `triggers.motion` options are enabled, see [Trigger Configuration](#camera-triggers-configuration)). - -| `view . update_seconds` | `view . interaction_seconds` | `view . update_force` | Trigger Entities | Behavior | -| :-: | :-: | :-: | :-: | - | -| `0` | `0` | *(Any value)* | Unset | Card will not automatically refresh. | -| `0` | `0` | *(Any value)* | *(Any entity)* | Card will reload default view & camera when entity state changes. | -| `0` | `X` seconds | *(Any value)* | Unset | Card will reload default view & camera `X` seconds after user interaction stops. | -| `0` | `X` seconds | `false` | *(Any entity)* | Card will reload default view & camera `X` seconds after user interaction stops, or when entity state changes (as long as user interaction has not occurred in the last `X` seconds). | -| `0` | `X` seconds | `true` | *(Any entity)* | Card will reload default view & camera `X` seconds after user interaction stops or when entity state changes. | -| `Y` seconds | `0` | *(Any value)* | Unset | Card will reload default view & camera every `Y` seconds. | -| `Y` seconds | `0` | *(Any value)* | *(Any entity)* | Card will reload default view & camera every `Y` seconds, or whenever entity state changes. | -| `Y` seconds | `X` seconds | `false` | Unset | Card will reload default view & camera `X` seconds after user interaction stops, and every `Y` seconds (as long as there hasn't been user interaction in the last `X` seconds). | -| `Y` seconds | `X` seconds | `false` | *(Any entity)* | Card will reload default view & camera `X` seconds after user interaction stops, and every `Y` seconds or whenever entity state changes (in both cases -- as long as there hasn't been user interaction in the last `X` seconds). | -| `Y` seconds | `X` seconds | `true` | Unset | Card will reload default view & camera `X` seconds after user interaction stops, and every `Y` seconds. | -| `Y` seconds | `X` seconds | `true` | *(Any entity)* | Card will reload default view & camera `X` seconds after user interaction stops, and every `Y` seconds or whenever entity state changes. | - -### Usecases For Automated Refreshes - - * Refreshing the `live` thumbnails every 30 seconds. -```yaml -view: - default: live - update_seconds: 30 -``` - * Using `clip` or `snapshot` as the default view (for the most recent clip or - snapshot respectively) and having the card automatically refresh (to fetch a - newer clip/snapshot) on motion. -```yaml -cameras: - - entity: camera.office - triggers: - motion: true -``` - * Cycle the live view of the camera every 60 seconds -```yaml -view: - update_cycle_camera: true - update_seconds: 60 -``` - * Return to the most recent clip of the default camera 30 seconds after user - interaction with the card stops. -```yaml -view: - default: clip - interaction_seconds: 30 -``` - ### Passing the card actions from the URL diff --git a/images/scan-mode.gif b/images/triggered.gif similarity index 100% rename from images/scan-mode.gif rename to images/triggered.gif diff --git a/package.json b/package.json index 016203f5..cb7ddbf8 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "@dermotduffy/panzoom": "^4.5.1", "@egjs/hammerjs": "^2.0.17", "@graphiteds/core": "^1.9.11", - "@lit-labs/scoped-registry-mixin": "^1.0.1", + "@lit-labs/scoped-registry-mixin": "^1.0.3", "@lit-labs/task": "^1.1.3", "@types/bluebird": "^3.5.36", "component-emitter": "^1.3.0", @@ -31,7 +31,7 @@ "embla-carousel-wheel-gestures": "8.0.0-rc04", "home-assistant-js-websocket": "^8.0.0", "keycharm": "^0.4.0", - "lit": "^2.3.1", + "lit": "^3.1.2", "lodash-es": "^4.17.21", "masonry-layout": "^4.2.2", "moment": "^2.29.4", @@ -40,8 +40,8 @@ "screenfull": "^6.0.2", "side-drawer": "^3.1.0", "uuid": "^8.3.2", - "vis-data": "^7.1.4", - "vis-timeline": "^7.7.0", + "vis-data": "^7.1.9", + "vis-timeline": "^7.7.3", "vis-util": "^5.0.2", "web-dialog": "^0.0.11", "xss": "^1.0.14", @@ -61,7 +61,7 @@ "@types/masonry-layout": "^4.2.5", "@typescript-eslint/eslint-plugin": "^5.36.2", "@typescript-eslint/parser": "^5.36.2", - "@vitest/coverage-istanbul": "^0.34.3", + "@vitest/coverage-istanbul": "^1.3.1", "eslint": "^8.23.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^8.5.0", @@ -79,8 +79,8 @@ "sass": "^1.54.9", "ts-prune": "^0.10.3", "typescript": "^4.9.5", - "vitest": "^0.34.3", - "vitest-mock-extended": "^1.2.1" + "vitest": "^1.3.1", + "vitest-mock-extended": "^1.3.1" }, "scripts": { "start": "rollup -c --watch", @@ -92,7 +92,7 @@ "coverage": "vitest run --coverage" }, "volta": { - "node": "18.14.0", - "yarn": "3.4.1" + "node": "18.17.1", + "yarn": "4.1.0" } } diff --git a/src/camera-manager/browse-media/camera.ts b/src/camera-manager/browse-media/camera.ts new file mode 100644 index 00000000..030707d4 --- /dev/null +++ b/src/camera-manager/browse-media/camera.ts @@ -0,0 +1,30 @@ +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { localize } from '../../localize/localize'; +import { EntityRegistryManager } from '../../utils/ha/entity-registry'; +import { Entity } from '../../utils/ha/entity-registry/types'; +import { Camera } from '../camera'; +import { CameraInitializationError } from '../error'; + +export class BrowseMediaCamera extends Camera { + protected _entity: Entity | null = null; + + public async initialize( + hass: HomeAssistant, + entityRegistryManager: EntityRegistryManager, + ): Promise { + const config = this.getConfig(); + const entity = config.camera_entity + ? await entityRegistryManager.getEntity(hass, config.camera_entity) + : null; + + if (!entity || !config.camera_entity) { + throw new CameraInitializationError(localize('error.no_camera_entity'), config); + } + this._entity = entity; + return this; + } + + public getEntity(): Entity | null { + return this._entity; + } +} diff --git a/src/camera-manager/browse-media/engine-browse-media.ts b/src/camera-manager/browse-media/engine-browse-media.ts index 22c41b9b..74a4d9e1 100644 --- a/src/camera-manager/browse-media/engine-browse-media.ts +++ b/src/camera-manager/browse-media/engine-browse-media.ts @@ -1,6 +1,5 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import { CameraConfig } from '../../config/types'; -import { localize } from '../../localize/localize'; import { ExtendedHomeAssistant } from '../../types'; import { canonicalizeHAURL } from '../../utils/ha'; import { BrowseMediaManager } from '../../utils/ha/browse-media/browse-media-manager'; @@ -11,24 +10,24 @@ import { RichBrowseMedia, } from '../../utils/ha/browse-media/types'; import { EntityRegistryManager } from '../../utils/ha/entity-registry'; -import { Entity } from '../../utils/ha/entity-registry/types'; import { ResolvedMediaCache, resolveMedia } from '../../utils/ha/resolved-media'; import { ViewMedia } from '../../view/media'; import { RequestCache } from '../cache'; import { Camera } from '../camera'; import { CameraManagerEngine } from '../engine'; -import { CameraInitializationError } from '../error'; import { GenericCameraManagerEngine } from '../generic/engine-generic'; import { rangesOverlap } from '../range'; import { CameraManagerReadOnlyConfigStore } from '../store'; import { CameraEndpoint, + CameraEventCallback, CameraManagerMediaCapabilities, DataQuery, EventQuery, PartialEventQuery, QueryType, } from '../types'; +import { BrowseMediaCamera } from './camera'; import { BrowseMediaViewMediaFactory } from './media'; import { BrowseMediaMetadata } from './types'; @@ -121,7 +120,6 @@ export class BrowseMediaCameraManagerEngine extends GenericCameraManagerEngine implements CameraManagerEngine { - protected _cameraEntities: Map = new Map(); protected _browseMediaManager: BrowseMediaManager; protected _resolvedMediaCache: ResolvedMediaCache; protected _requestCache: RequestCache; @@ -130,38 +128,32 @@ export class BrowseMediaCameraManagerEngine browseMediaManager: BrowseMediaManager, resolvedMediaCache: ResolvedMediaCache, requestCache: RequestCache, + eventCallback?: CameraEventCallback, ) { - super(); + super(eventCallback); this._browseMediaManager = browseMediaManager; this._resolvedMediaCache = resolvedMediaCache; this._requestCache = requestCache; } - public async initializeCamera( + public async createCamera( hass: HomeAssistant, entityRegistryManager: EntityRegistryManager, cameraConfig: CameraConfig, ): Promise { - const entity = cameraConfig.camera_entity - ? await entityRegistryManager.getEntity(hass, cameraConfig.camera_entity) - : null; - if (!entity || !cameraConfig.camera_entity) { - throw new CameraInitializationError( - localize('error.no_camera_entity'), - cameraConfig, - ); - } - this._cameraEntities.set(cameraConfig.camera_entity, entity); - - return new Camera(cameraConfig, this, { - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, - supportsClips: true, - supportsRecordings: false, - supportsSnapshots: true, - supportsTimeline: true, + const camera = new BrowseMediaCamera(cameraConfig, this, { + capabilities: { + canFavoriteEvents: false, + canFavoriteRecordings: false, + canSeek: false, + supportsClips: true, + supportsRecordings: false, + supportsSnapshots: true, + supportsTimeline: true, + }, + eventCallback: this._eventCallback, }); + return await camera.initialize(hass, entityRegistryManager); } public generateDefaultEventQuery( diff --git a/src/camera-manager/camera.ts b/src/camera-manager/camera.ts index dd6990ee..fd59026d 100644 --- a/src/camera-manager/camera.ts +++ b/src/camera-manager/camera.ts @@ -1,22 +1,81 @@ +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import { CameraConfig } from '../config/types'; import { localize } from '../localize/localize'; +import { allPromises } from '../utils/basic'; +import { + isTriggeredState, + parseStateChangeTrigger, + subscribeToTrigger, +} from '../utils/ha'; +import { EntityRegistryManager } from '../utils/ha/entity-registry'; import { CameraManagerEngine } from './engine'; import { CameraNoIDError } from './error'; -import { CameraManagerCameraCapabilities } from './types'; +import { CameraEventCallback, CameraManagerCameraCapabilities } from './types'; + +type DestroyCallback = () => Promise; export class Camera { protected _config: CameraConfig; protected _engine: CameraManagerEngine; - protected _capabilities: CameraManagerCameraCapabilities; + protected _capabilities?: CameraManagerCameraCapabilities; + protected _eventCallback?: CameraEventCallback; + protected _destroyCallbacks: DestroyCallback[] = []; constructor( config: CameraConfig, engine: CameraManagerEngine, - capabilities: CameraManagerCameraCapabilities, + options?: { + capabilities?: CameraManagerCameraCapabilities; + eventCallback?: CameraEventCallback; + }, ) { this._config = config; this._engine = engine; - this._capabilities = capabilities; + this._capabilities = options?.capabilities; + this._eventCallback = options?.eventCallback; + } + + protected async _convertStateChangeToCameraEvent(data: unknown): Promise { + const stateChange = parseStateChangeTrigger(data); + if (!stateChange) { + return; + } + + this._eventCallback?.({ + cameraID: this.getID(), + type: isTriggeredState(stateChange.to_state.state) ? 'new' : 'end', + }); + } + + protected async _subscribeToTriggerEntities(hass: HomeAssistant): Promise { + if (!this._config.triggers.entities.length) { + return; + } + + this._destroyCallbacks.push( + await subscribeToTrigger( + hass, + (data) => this._convertStateChangeToCameraEvent(data), + { + entityID: this._config.triggers.entities, + platform: 'state', + stateOnly: true, + }, + ), + ); + } + + async initialize( + hass: HomeAssistant, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _entityRegistryManager: EntityRegistryManager, + ): Promise { + await this._subscribeToTriggerEntities(hass); + return this; + } + + async destroy(): Promise { + await allPromises(this._destroyCallbacks, (cb) => cb()); } public getConfig(): CameraConfig { @@ -38,7 +97,7 @@ export class Camera { return this._engine; } - public getCapabilities(): CameraManagerCameraCapabilities { - return this._capabilities; + public getCapabilities(): CameraManagerCameraCapabilities | null { + return this._capabilities ?? null; } } diff --git a/src/camera-manager/engine-factory.ts b/src/camera-manager/engine-factory.ts index 38a694ca..397f390f 100644 --- a/src/camera-manager/engine-factory.ts +++ b/src/camera-manager/engine-factory.ts @@ -9,7 +9,7 @@ import { ResolvedMediaCache } from '../utils/ha/resolved-media'; import { MemoryRequestCache, RecordingSegmentsCache, RequestCache } from './cache'; import { CameraManagerEngine } from './engine'; import { CameraInitializationError } from './error'; -import { Engine } from './types'; +import { CameraEventCallback, Engine } from './types'; import { getCameraEntityFromConfig } from './utils'; export class CameraManagerEngineFactory { @@ -24,18 +24,19 @@ export class CameraManagerEngineFactory { this._resolvedMediaCache = resolvedMediaCache; } - public async createEngine(engine: Engine): Promise { + public async createEngine(engine: Engine, eventCallback?: CameraEventCallback): Promise { let cameraManagerEngine: CameraManagerEngine; switch (engine) { case Engine.Generic: const { GenericCameraManagerEngine } = await import('./generic/engine-generic'); - cameraManagerEngine = new GenericCameraManagerEngine(); + cameraManagerEngine = new GenericCameraManagerEngine(eventCallback); break; case Engine.Frigate: const { FrigateCameraManagerEngine } = await import('./frigate/engine-frigate'); cameraManagerEngine = new FrigateCameraManagerEngine( new RecordingSegmentsCache(), new RequestCache(), + eventCallback, ); break; case Engine.MotionEye: @@ -46,6 +47,7 @@ export class CameraManagerEngineFactory { new BrowseMediaManager(new MemoryRequestCache()), this._resolvedMediaCache, new RequestCache(), + eventCallback, ); } return cameraManagerEngine; diff --git a/src/camera-manager/engine.ts b/src/camera-manager/engine.ts index 8f013cbc..d9d09971 100644 --- a/src/camera-manager/engine.ts +++ b/src/camera-manager/engine.ts @@ -1,9 +1,5 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { - CameraConfig, - PTZAction, - PTZPhase, -} from '../config/types'; +import { CameraConfig, PTZAction, PTZPhase } from '../config/types'; import { ExtendedHomeAssistant } from '../types'; import { EntityRegistryManager } from '../utils/ha/entity-registry'; import { ViewMedia } from '../view/media'; @@ -37,7 +33,7 @@ export const CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT = 10000; export interface CameraManagerEngine { getEngineType(): Engine; - initializeCamera( + createCamera( hass: HomeAssistant, entityRegistryManager: EntityRegistryManager, cameraConfig: CameraConfig, @@ -143,8 +139,8 @@ export interface CameraManagerEngine { cameraConfig: CameraConfig, action: PTZAction, options?: { - phase?: PTZPhase, - preset?: string, - } + phase?: PTZPhase; + preset?: string; + }, ): Promise; } diff --git a/src/camera-manager/frigate/camera.ts b/src/camera-manager/frigate/camera.ts new file mode 100644 index 00000000..35eb4a29 --- /dev/null +++ b/src/camera-manager/frigate/camera.ts @@ -0,0 +1,308 @@ +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import uniq from 'lodash-es/uniq'; +import { CameraConfig } from '../../config/types'; +import { localize } from '../../localize/localize'; +import { errorToConsole } from '../../utils/basic'; +import { subscribeToTrigger } from '../../utils/ha'; +import { EntityRegistryManager } from '../../utils/ha/entity-registry'; +import { Entity } from '../../utils/ha/entity-registry/types'; +import { Camera } from '../camera'; +import { CameraInitializationError } from '../error'; +import { PTZCapabilities, PTZMovementType } from '../types'; +import { getCameraEntityFromConfig } from '../utils.js'; +import { getPTZInfo } from './requests'; +import { PTZInfo, frigateEventChangeTriggerResponseSchema } from './types'; + +const CAMERA_BIRDSEYE = 'birdseye' as const; + +export const isBirdseye = (cameraConfig: CameraConfig): boolean => { + return cameraConfig.frigate.camera_name === CAMERA_BIRDSEYE; +}; + +export class FrigateCamera extends Camera { + public async initialize( + hass: HomeAssistant, + entityRegistryManager: EntityRegistryManager, + ): Promise { + await this._initializeConfig(hass, entityRegistryManager); + await this._initializeCapabilities(hass); + await this._subscribeToEvents(hass); + return await super.initialize(hass, entityRegistryManager); + } + + protected async _initializeConfig( + hass: HomeAssistant, + entityRegistryManager: EntityRegistryManager, + ): Promise { + const config = this.getConfig(); + const hasCameraName = !!config.frigate?.camera_name; + const hasAutoTriggers = config.triggers.motion || config.triggers.occupancy; + + let entity: Entity | null = null; + const cameraEntity = getCameraEntityFromConfig(config); + + // Entity information is required if the Frigate camera name is missing, or + // if the entity requires automatic resolution of motion/occupancy sensors. + if (cameraEntity && (!hasCameraName || hasAutoTriggers)) { + try { + entity = await entityRegistryManager.getEntity(hass, cameraEntity); + } catch (e) { + throw new CameraInitializationError(localize('error.no_camera_entity'), config); + } + } + + if (entity && !hasCameraName) { + const resolvedName = this._getFrigateCameraNameFromEntity(entity); + if (resolvedName) { + this._config.frigate.camera_name = resolvedName; + } + } + + if (hasAutoTriggers) { + // Try to find the correct entities for the motion & occupancy sensors. + // We know they are binary_sensors, and that they'll have the same + // config entry ID as the camera. Searching via unique_id ensures this + // search still works if the user renames the entity_id. + const binarySensorEntities = await entityRegistryManager.getMatchingEntities( + hass, + (ent) => + ent.config_entry_id === entity?.config_entry_id && + !ent.disabled_by && + ent.entity_id.startsWith('binary_sensor.'), + ); + + if (config.triggers.motion) { + const motionEntity = this._getMotionSensor(config, [ + ...binarySensorEntities.values(), + ]); + if (motionEntity) { + config.triggers.entities.push(motionEntity); + } + } + + if (config.triggers.occupancy) { + const occupancyEntities = this._getOccupancySensor(config, [ + ...binarySensorEntities.values(), + ]); + if (occupancyEntities) { + config.triggers.entities.push(...occupancyEntities); + } + } + + // De-duplicate triggering entities. + config.triggers.entities = uniq(config.triggers.entities); + } + } + + protected async _initializeCapabilities(hass: HomeAssistant): Promise { + const config = this.getConfig(); + const ptz = await this._getPTZCapabilities(hass, config); + const birdseye = isBirdseye(config); + this._capabilities = { + canFavoriteEvents: !birdseye, + canFavoriteRecordings: !birdseye, + canSeek: true, + supportsClips: !birdseye, + supportsSnapshots: !birdseye, + supportsRecordings: !birdseye, + supportsTimeline: !birdseye, + ...(ptz && { ptz: ptz }), + }; + } + + protected _getFrigateCameraNameFromEntity(entity: Entity): string | null { + if ( + entity.platform === 'frigate' && + entity.unique_id && + typeof entity.unique_id === 'string' + ) { + const match = entity.unique_id.match(/:camera:(?[^:]+)$/); + if (match && match.groups) { + return match.groups['camera']; + } + } + return null; + } + + protected async _getPTZCapabilities( + hass: HomeAssistant, + cameraConfig: CameraConfig, + ): Promise { + if (!cameraConfig.frigate.camera_name) { + return null; + } + + let ptzInfo: PTZInfo | null = null; + try { + ptzInfo = await getPTZInfo( + hass, + cameraConfig.frigate.client_id, + cameraConfig.frigate.camera_name, + ); + } catch (e) { + errorToConsole(e as Error); + return null; + } + + const panTilt: PTZMovementType[] = [ + ...(ptzInfo.features?.includes('pt') ? ['continuous' as const] : []), + ...(ptzInfo.features?.includes('pt-r') ? ['relative' as const] : []), + ]; + const zoom: PTZMovementType[] = [ + ...(ptzInfo.features?.includes('zoom') ? ['continuous' as const] : []), + ...(ptzInfo.features?.includes('zoom-r') ? ['relative' as const] : []), + ]; + const presets = ptzInfo.presets; + + if (panTilt.length || zoom.length || presets?.length) { + return { + ...(panTilt && { panTilt: panTilt }), + ...(zoom && { zoom: zoom }), + ...(presets && { presets: presets }), + }; + } + return null; + } + + /** + * Get the motion sensor entity for a given camera. + * @param cache The EntityCache of entity registry information. + * @param cameraConfig The camera config in question. + * @returns The entity id of the motion sensor or null. + */ + protected _getMotionSensor( + cameraConfig: CameraConfig, + entities: Entity[], + ): string | null { + if (cameraConfig.frigate.camera_name) { + return ( + entities.find( + (entity) => + typeof entity.unique_id === 'string' && + !!entity.unique_id?.match( + new RegExp(`:motion_sensor:${cameraConfig.frigate.camera_name}`), + ), + )?.entity_id ?? null + ); + } + return null; + } + + /** + * Get the occupancy sensor entity for a given camera. + * @param cache The EntityCache of entity registry information. + * @param cameraConfig The camera config in question. + * @returns The entity id of the occupancy sensor or null. + */ + protected _getOccupancySensor( + cameraConfig: CameraConfig, + entities: Entity[], + ): string[] | null { + const entityIDs: string[] = []; + const addEntityIDIfFound = (cameraOrZone: string, label: string): void => { + const entityID = + entities.find( + (entity) => + typeof entity.unique_id === 'string' && + !!entity.unique_id?.match( + new RegExp(`:occupancy_sensor:${cameraOrZone}_${label}`), + ), + )?.entity_id ?? null; + if (entityID) { + entityIDs.push(entityID); + } + }; + + if (cameraConfig.frigate.camera_name) { + // If zone(s) are specified, the master occupancy sensor for the overall + // camera is not used by default (but could be manually added by the + // user). + const camerasAndZones = cameraConfig.frigate.zones?.length + ? cameraConfig.frigate.zones + : [cameraConfig.frigate.camera_name]; + + const labels = cameraConfig.frigate.labels?.length + ? cameraConfig.frigate.labels + : ['all']; + for (const cameraOrZone of camerasAndZones) { + for (const label of labels) { + addEntityIDIfFound(cameraOrZone, label); + } + } + + if (entityIDs.length) { + return entityIDs; + } + } + return null; + } + + protected async _subscribeToEvents(hass: HomeAssistant): Promise { + const config = this.getConfig(); + if (!config.triggers.events.length || !config.frigate.camera_name) { + return; + } + + this._destroyCallbacks.push( + await subscribeToTrigger(hass, (ev) => this._handleEventChange(ev), { + platform: 'mqtt', + topic: `${config.frigate.client_id}/events`, + + // Only trigger for events pertaining to this camera. + payload: config.frigate.camera_name, + valueTemplate: '{{ value_json.after.camera }}', + }), + ); + } + + protected _handleEventChange(ev: unknown): void { + const parseResult = frigateEventChangeTriggerResponseSchema.safeParse(ev); + if (!parseResult.success) { + console.warn('Ignoring unparseable Frigate event', ev); + return; + } + + const change = parseResult.data.variables.trigger.payload_json; + const snapshotChange = + (!change.before.has_snapshot && change.after.has_snapshot) || + change.before.snapshot?.frame_time !== change.after.snapshot?.frame_time; + const clipChange = !change.before.has_clip && change.after.has_clip; + + const config = this.getConfig(); + if (config.frigate.camera_name !== change.after.camera) { + return; + } + + if ( + (config.frigate.zones?.length && + !config.frigate.zones.some((zone) => + change.after.current_zones.includes(zone), + )) || + (config.frigate.labels?.length && + !config.frigate.labels.includes(change.after.label)) + ) { + return; + } + + const eventsToTriggerOn = config.triggers.events; + if ( + !( + eventsToTriggerOn.includes('events') || + (eventsToTriggerOn.includes('snapshots') && snapshotChange) || + (eventsToTriggerOn.includes('clips') && clipChange) + ) + ) { + return; + } + + this._eventCallback?.({ + fidelity: 'high', + cameraID: this.getID(), + type: change.type, + // In cases where there are both clip and snapshot media, ensure to only + // trigger on the media type that is allowed by the configuration. + clip: clipChange && eventsToTriggerOn.includes('clips'), + snapshot: snapshotChange && eventsToTriggerOn.includes('snapshots'), + }); + } +} diff --git a/src/camera-manager/frigate/engine-frigate.ts b/src/camera-manager/frigate/engine-frigate.ts index f7936f3d..ea44df50 100644 --- a/src/camera-manager/frigate/engine-frigate.ts +++ b/src/camera-manager/frigate/engine-frigate.ts @@ -7,30 +7,25 @@ import startOfHour from 'date-fns/startOfHour'; import isEqual from 'lodash-es/isEqual'; import orderBy from 'lodash-es/orderBy'; import throttle from 'lodash-es/throttle'; -import uniq from 'lodash-es/uniq'; import uniqWith from 'lodash-es/uniqWith'; import { CameraConfig, PTZAction, PTZPhase } from '../../config/types'; -import { localize } from '../../localize/localize'; import { ExtendedHomeAssistant } from '../../types'; import { allPromises, - errorToConsole, formatDate, prettifyTitle, runWhenIdleIfSupported, } from '../../utils/basic'; import { getEntityTitle } from '../../utils/ha'; import { EntityRegistryManager } from '../../utils/ha/entity-registry'; -import { Entity } from '../../utils/ha/entity-registry/types'; import { ViewMedia } from '../../view/media'; import { ViewMediaClassifier } from '../../view/media-classifier'; import { RecordingSegmentsCache, RequestCache } from '../cache'; import { Camera } from '../camera'; import { - CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT, CameraManagerEngine, + CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT, } from '../engine'; -import { CameraInitializationError } from '../error'; import { GenericCameraManagerEngine } from '../generic/engine-generic'; import { DateRange } from '../range'; import { CameraManagerReadOnlyConfigStore } from '../store'; @@ -38,6 +33,7 @@ import { CameraEndpoint, CameraEndpoints, CameraEndpointsContext, + CameraEventCallback, CameraManagerCameraMetadata, CameraManagerMediaCapabilities, DataQuery, @@ -52,8 +48,6 @@ import { PartialEventQuery, PartialRecordingQuery, PartialRecordingSegmentsQuery, - PTZCapabilities, - PTZMovementType, QueryResults, QueryResultsType, QueryReturnType, @@ -65,34 +59,31 @@ import { RecordingSegmentsQuery, RecordingSegmentsQueryResultsMap, } from '../types'; -import { getCameraEntityFromConfig, getDefaultGo2RTCEndpoint } from '../utils.js'; +import { getDefaultGo2RTCEndpoint } from '../utils.js'; import frigateLogo from './assets/frigate-logo-dark.svg'; +import { FrigateCamera, isBirdseye } from './camera'; import { FrigateViewMediaFactory } from './media'; import { FrigateViewMediaClassifier } from './media-classifier'; import { - NativeFrigateEventQuery, - NativeFrigateRecordingSegmentsQuery, - getEventSummary, getEvents, + getEventSummary, getRecordingSegments, getRecordingsSummary, + NativeFrigateEventQuery, + NativeFrigateRecordingSegmentsQuery, retainEvent, - getPTZInfo, } from './requests'; import { FrigateEventQueryResults, FrigateRecording, FrigateRecordingQueryResults, FrigateRecordingSegmentsQueryResults, - PTZInfo, } from './types'; const EVENT_REQUEST_CACHE_MAX_AGE_SECONDS = 60; const RECORDING_SUMMARY_REQUEST_CACHE_MAX_AGE_SECONDS = 60; const MEDIA_METADATA_REQUEST_CACHE_AGE_SECONDS = 60; -const CAMERA_BIRDSEYE = 'birdseye' as const; - class FrigateQueryResultsClassifier { public static isFrigateEventQueryResults( results: QueryResults, @@ -135,8 +126,9 @@ export class FrigateCameraManagerEngine constructor( recordingSegmentsCache: RecordingSegmentsCache, requestCache: RequestCache, + eventCallback?: CameraEventCallback, ) { - super(); + super(eventCallback); this._recordingSegmentsCache = recordingSegmentsCache; this._requestCache = requestCache; } @@ -145,222 +137,15 @@ export class FrigateCameraManagerEngine return Engine.Frigate; } - public async initializeCamera( + public async createCamera( hass: HomeAssistant, entityRegistryManager: EntityRegistryManager, cameraConfig: CameraConfig, ): Promise { - const hasCameraName = !!cameraConfig.frigate?.camera_name; - const hasAutoTriggers = - cameraConfig.triggers.motion || cameraConfig.triggers.occupancy; - - let entity: Entity | null = null; - const cameraEntity = getCameraEntityFromConfig(cameraConfig); - - // Entity information is required if the Frigate camera name is missing, or - // if the entity requires automatic resolution of motion/occupancy sensors. - if (cameraEntity && (!hasCameraName || hasAutoTriggers)) { - try { - entity = await entityRegistryManager.getEntity(hass, cameraEntity); - } catch (e) { - throw new CameraInitializationError( - localize('error.no_camera_entity'), - cameraConfig, - ); - } - } - - if (entity && !hasCameraName) { - const resolvedName = this._getFrigateCameraNameFromEntity(entity); - if (resolvedName) { - cameraConfig.frigate.camera_name = resolvedName; - } - } - - if (hasAutoTriggers) { - // Try to find the correct entities for the motion & occupancy sensors. - // We know they are binary_sensors, and that they'll have the same - // config entry ID as the camera. Searching via unique_id ensures this - // search still works if the user renames the entity_id. - const binarySensorEntities = await entityRegistryManager.getMatchingEntities( - hass, - (ent) => - ent.config_entry_id === entity?.config_entry_id && - !ent.disabled_by && - ent.entity_id.startsWith('binary_sensor.'), - ); - - if (cameraConfig.triggers.motion) { - const motionEntity = this._getMotionSensor(cameraConfig, [ - ...binarySensorEntities.values(), - ]); - if (motionEntity) { - cameraConfig.triggers.entities.push(motionEntity); - } - } - - if (cameraConfig.triggers.occupancy) { - const occupancyEntities = this._getOccupancySensor(cameraConfig, [ - ...binarySensorEntities.values(), - ]); - if (occupancyEntities) { - cameraConfig.triggers.entities.push(...occupancyEntities); - } - } - - // De-duplicate triggering entities. - cameraConfig.triggers.entities = uniq(cameraConfig.triggers.entities); - } - - const ptz = await this._getPTZCapabilities(hass, cameraConfig); - - const isBirdseye = this._isBirdseye(cameraConfig); - return new Camera(cameraConfig, this, { - canFavoriteEvents: !isBirdseye, - canFavoriteRecordings: !isBirdseye, - canSeek: true, - supportsClips: !isBirdseye, - supportsSnapshots: !isBirdseye, - supportsRecordings: !isBirdseye, - supportsTimeline: !isBirdseye, - - ...(ptz && { ptz: ptz }), + const camera = new FrigateCamera(cameraConfig, this, { + eventCallback: this._eventCallback, }); - } - - protected async _getPTZCapabilities( - hass: HomeAssistant, - cameraConfig: CameraConfig, - ): Promise { - if (!cameraConfig.frigate.camera_name) { - return null; - } - - let ptzInfo: PTZInfo | null = null; - try { - ptzInfo = await getPTZInfo( - hass, - cameraConfig.frigate.client_id, - cameraConfig.frigate.camera_name, - ); - } catch (e) { - errorToConsole(e as Error); - return null; - } - - const panTilt: PTZMovementType[] = [ - ...(ptzInfo.features?.includes('pt') ? ['continuous' as const] : []), - ...(ptzInfo.features?.includes('pt-r') ? ['relative' as const] : []), - ]; - const zoom: PTZMovementType[] = [ - ...(ptzInfo.features?.includes('zoom') ? ['continuous' as const] : []), - ...(ptzInfo.features?.includes('zoom-r') ? ['relative' as const] : []), - ]; - const presets = ptzInfo.presets; - - if (panTilt.length || zoom.length || presets?.length) { - return { - ...(panTilt && { panTilt: panTilt }), - ...(zoom && { zoom: zoom }), - ...(presets && { presets: presets }), - }; - } - return null; - } - - protected _isBirdseye(cameraConfig: CameraConfig): boolean { - return cameraConfig.frigate.camera_name === CAMERA_BIRDSEYE; - } - - /** - * Get the Frigate camera name from an entity. - * @returns The Frigate camera name or null if unavailable. - */ - protected _getFrigateCameraNameFromEntity(entity: Entity): string | null { - if ( - entity.platform === 'frigate' && - entity.unique_id && - typeof entity.unique_id === 'string' - ) { - const match = entity.unique_id.match(/:camera:(?[^:]+)$/); - if (match && match.groups) { - return match.groups['camera']; - } - } - return null; - } - - /** - * Get the motion sensor entity for a given camera. - * @param cache The EntityCache of entity registry information. - * @param cameraConfig The camera config in question. - * @returns The entity id of the motion sensor or null. - */ - protected _getMotionSensor( - cameraConfig: CameraConfig, - entities: Entity[], - ): string | null { - if (cameraConfig.frigate.camera_name) { - return ( - entities.find( - (entity) => - typeof entity.unique_id === 'string' && - !!entity.unique_id?.match( - new RegExp(`:motion_sensor:${cameraConfig.frigate.camera_name}`), - ), - )?.entity_id ?? null - ); - } - return null; - } - - /** - * Get the occupancy sensor entity for a given camera. - * @param cache The EntityCache of entity registry information. - * @param cameraConfig The camera config in question. - * @returns The entity id of the occupancy sensor or null. - */ - protected _getOccupancySensor( - cameraConfig: CameraConfig, - entities: Entity[], - ): string[] | null { - const entityIDs: string[] = []; - const addEntityIDIfFound = (cameraOrZone: string, label: string): void => { - const entityID = - entities.find( - (entity) => - typeof entity.unique_id === 'string' && - !!entity.unique_id?.match( - new RegExp(`:occupancy_sensor:${cameraOrZone}_${label}`), - ), - )?.entity_id ?? null; - if (entityID) { - entityIDs.push(entityID); - } - }; - - if (cameraConfig.frigate.camera_name) { - // If zone(s) are specified, the master occupancy sensor for the overall - // camera is not used by default (but could be manually added by the - // user). - const camerasAndZones = cameraConfig.frigate.zones?.length - ? cameraConfig.frigate.zones - : [cameraConfig.frigate.camera_name]; - - const labels = cameraConfig.frigate.labels?.length - ? cameraConfig.frigate.labels - : ['all']; - for (const cameraOrZone of camerasAndZones) { - for (const label of labels) { - addEntityIDIfFound(cameraOrZone, label); - } - } - - if (entityIDs.length) { - return entityIDs; - } - } - return null; + return await camera.initialize(hass, entityRegistryManager); } public async getMediaDownloadPath( @@ -904,7 +689,7 @@ export class FrigateCameraManagerEngine cameraID: string, ): CameraConfig | null { const cameraConfig = store.getCameraConfig(cameraID); - if (!cameraConfig || this._isBirdseye(cameraConfig)) { + if (!cameraConfig || isBirdseye(cameraConfig)) { return null; } return cameraConfig; diff --git a/src/camera-manager/frigate/types.ts b/src/camera-manager/frigate/types.ts index 1d3bf95d..7cc7559b 100644 --- a/src/camera-manager/frigate/types.ts +++ b/src/camera-manager/frigate/types.ts @@ -83,6 +83,39 @@ export const ptzInfoSchema = z.object({ }); export type PTZInfo = z.infer; +// Frigate events as stored in MQTT updates. +const frigateEventChangeSchema = z.object({ + camera: z.string(), + snapshot: z + .object({ + frame_time: z.number(), + }) + .nullable(), + has_clip: z.boolean(), + has_snapshot: z.boolean(), + label: z.string(), + current_zones: z.string().array(), +}); +export type FrigateEventChange = z.infer; + +const frigateEventChangeType = z.enum(['new', 'update', 'end']); +export type FrigateEventChangeType = z.infer; + +export const frigateEventChangeTriggerResponseSchema = z.object({ + variables: z.object({ + trigger: z.object({ + payload_json: z.object({ + before: frigateEventChangeSchema, + after: frigateEventChangeSchema, + type: frigateEventChangeType, + }), + }), + }), +}); +export type FrigateEventChangeTriggerResponse = z.infer< + typeof frigateEventChangeTriggerResponseSchema +>; + // ============================== // Frigate concrete query results // ============================== diff --git a/src/camera-manager/generic/engine-generic.ts b/src/camera-manager/generic/engine-generic.ts index ed8986a4..195ebedf 100644 --- a/src/camera-manager/generic/engine-generic.ts +++ b/src/camera-manager/generic/engine-generic.ts @@ -1,11 +1,7 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { - CameraConfig, - PTZAction, - PTZPhase -} from '../../config/types'; +import { CameraConfig, PTZAction, PTZPhase } from '../../config/types'; import { ExtendedHomeAssistant } from '../../types'; import { getEntityIcon, getEntityTitle } from '../../utils/ha'; import { EntityRegistryManager } from '../../utils/ha/entity-registry'; @@ -17,6 +13,7 @@ import { CameraEndpoint, CameraEndpoints, CameraEndpointsContext, + CameraEventCallback, CameraManagerCameraMetadata, CameraManagerMediaCapabilities, DataQuery, @@ -33,29 +30,38 @@ import { RecordingQuery, RecordingQueryResultsMap, RecordingSegmentsQuery, - RecordingSegmentsQueryResultsMap + RecordingSegmentsQueryResultsMap, } from '../types'; import { getCameraEntityFromConfig, getDefaultGo2RTCEndpoint } from '../utils.js'; export class GenericCameraManagerEngine implements CameraManagerEngine { + protected _eventCallback?: CameraEventCallback; + + constructor(eventCallback?: CameraEventCallback) { + this._eventCallback = eventCallback; + } + public getEngineType(): Engine { return Engine.Generic; } - public async initializeCamera( - _hass: HomeAssistant, - _entityRegistryManager: EntityRegistryManager, + public async createCamera( + hass: HomeAssistant, + entityRegistryManager: EntityRegistryManager, cameraConfig: CameraConfig, ): Promise { - return new Camera(cameraConfig, this, { - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, - supportsClips: false, - supportsRecordings: false, - supportsSnapshots: false, - supportsTimeline: false, - }); + return await new Camera(cameraConfig, this, { + capabilities: { + canFavoriteEvents: false, + canFavoriteRecordings: false, + canSeek: false, + supportsClips: false, + supportsRecordings: false, + supportsSnapshots: false, + supportsTimeline: false, + }, + eventCallback: this._eventCallback, + }).initialize(hass, entityRegistryManager); } public generateDefaultEventQuery( diff --git a/src/camera-manager/manager.ts b/src/camera-manager/manager.ts index efcefd4f..18bf305b 100644 --- a/src/camera-manager/manager.ts +++ b/src/camera-manager/manager.ts @@ -47,11 +47,11 @@ import { RecordingSegmentsQuery, RecordingSegmentsQueryResults, RecordingSegmentsQueryResultsMap, - ResultsMap + ResultsMap, } from './types.js'; import { sortMedia } from './utils.js'; -class QueryClassifier { +export class QueryClassifier { public static isEventQuery(query: DataQuery | PartialDataQuery): query is EventQuery { return query.type === QueryType.Event; } @@ -72,23 +72,23 @@ class QueryClassifier { } } -class QueryResultClassifier { +export class QueryResultClassifier { public static isEventQueryResult( queryResults: QueryResults, ): queryResults is EventQueryResults { return queryResults.type === QueryResultsType.Event; } - public static isRecordingQuery( + public static isRecordingQueryResult( queryResults: QueryResults, ): queryResults is RecordingQueryResults { return queryResults.type === QueryResultsType.Recording; } - public static isRecordingSegmentsQuery( + public static isRecordingSegmentsQueryResult( queryResults: QueryResults, ): queryResults is RecordingSegmentsQueryResults { return queryResults.type === QueryResultsType.RecordingSegments; } - public static isMediaMetadataQuery( + public static isMediaMetadataQueryResult( queryResults: QueryResults, ): queryResults is MediaMetadataQueryResults { return queryResults.type === QueryResultsType.MediaMetadata; @@ -105,13 +105,25 @@ export class CameraManager { protected _engineFactory: CameraManagerEngineFactory; protected _store: CameraManagerStore; - constructor(api: CardCameraAPI, store?: CameraManagerStore) { + constructor( + api: CardCameraAPI, + options?: { + store?: CameraManagerStore; + factory?: CameraManagerEngineFactory; + }, + ) { this._api = api; - this._engineFactory = new CameraManagerEngineFactory( - this._api.getEntityRegistryManager(), - this._api.getResolvedMediaCache(), - ); - this._store = store ?? new CameraManagerStore(); + this._engineFactory = + options?.factory ?? + new CameraManagerEngineFactory( + this._api.getEntityRegistryManager(), + this._api.getResolvedMediaCache(), + ); + this._store = options?.store ?? new CameraManagerStore(); + } + + public async reset(): Promise { + await this._store.reset(); } public async initializeCamerasFromConfig(): Promise { @@ -122,7 +134,7 @@ export class CameraManager { return false; } - this._store.reset(); + await this.reset(); // For each camera merge the config (which has no defaults) into the camera // global config (which does have defaults). The merging must happen in this @@ -148,6 +160,7 @@ export class CameraManager { const engines: Map = new Map(); const hass = this._api.getHASSManager().getHASS(); + /* istanbul ignore if: the if path cannot be reached -- @preserve */ if (!hass) { return output; } @@ -162,7 +175,10 @@ export class CameraManager { for (const [index, cameraConfig] of camerasConfig.entries()) { const engineType = engineTypes[index]; const engine = engineType - ? engines.get(engineType) ?? (await this._engineFactory.createEngine(engineType)) + ? engines.get(engineType) ?? + (await this._engineFactory.createEngine(engineType, (ev) => + this._api.getTriggersManager().handleCameraEvent(ev), + )) : null; if (!engine || !engineType) { throw new CameraInitializationError( @@ -182,6 +198,7 @@ export class CameraManager { const initializationStartTime = new Date(); const hass = this._api.getHASSManager().getHASS(); + /* istanbul ignore if: the if path cannot be reached -- @preserve */ if (!hass) { return; } @@ -208,7 +225,7 @@ export class CameraManager { const cameras = await allPromises( engineByConfig.entries(), async ([cameraConfig, engine]) => - await engine.initializeCamera( + await engine.createCamera( hass, this._api.getEntityRegistryManager(), cameraConfig, @@ -292,45 +309,6 @@ export class CameraManager { }); } - public async getMediaMetadata(): Promise { - const tags: Set = new Set(); - const what: Set = new Set(); - const where: Set = new Set(); - const days: Set = new Set(); - - const query: MediaMetadataQuery = { - type: QueryType.MediaMetadata, - cameraIDs: this._store.getCameraIDs(), - }; - - const results = await this._handleQuery(query); - - for (const result of results?.values() ?? []) { - if (result.metadata.tags) { - result.metadata.tags.forEach(tags.add, tags); - } - if (result.metadata.what) { - result.metadata.what.forEach(what.add, what); - } - if (result.metadata.where) { - result.metadata.where.forEach(where.add, where); - } - if (result.metadata.days) { - result.metadata.days.forEach(days.add, days); - } - } - - if (!what.size && !where.size && !days.size) { - return null; - } - return { - ...(tags.size && { tags: tags }), - ...(what.size && { what: what }), - ...(where.size && { where: where }), - ...(days.size && { days: days }), - }; - } - protected _generateDefaultQueries( cameraIDs: string | Set, partialQuery: PQT, @@ -338,13 +316,13 @@ export class CameraManager { const concreteQueries: PartialQueryConcreteType[] = []; const _cameraIDs = setify(cameraIDs); const engines = this._store.getEnginesForCameraIDs(_cameraIDs); - if (!engines) { return null; } for (const [engine, cameraIDs] of engines) { let queries: DataQuery[] | null = null; + /* istanbul ignore else: the else path cannot be reached -- @preserve */ if (QueryClassifier.isEventQuery(partialQuery)) { queries = engine.generateDefaultEventQuery(this._store, cameraIDs, partialQuery); } else if (QueryClassifier.isRecordingQuery(partialQuery)) { @@ -368,6 +346,45 @@ export class CameraManager { return concreteQueries.length ? concreteQueries : null; } + public async getMediaMetadata(): Promise { + const tags: Set = new Set(); + const what: Set = new Set(); + const where: Set = new Set(); + const days: Set = new Set(); + + const query: MediaMetadataQuery = { + type: QueryType.MediaMetadata, + cameraIDs: this._store.getCameraIDs(), + }; + + const results = await this._handleQuery(query); + + for (const result of results.values()) { + if (result.metadata.tags) { + result.metadata.tags.forEach(tags.add, tags); + } + if (result.metadata.what) { + result.metadata.what.forEach(what.add, what); + } + if (result.metadata.where) { + result.metadata.where.forEach(where.add, where); + } + if (result.metadata.days) { + result.metadata.days.forEach(days.add, days); + } + } + + if (!what.size && !where.size && !days.size && !tags.size) { + return null; + } + return { + ...(tags.size && { tags: tags }), + ...(what.size && { what: what }), + ...(where.size && { where: where }), + ...(days.size && { days: days }), + }; + } + public async getEvents( query: EventQuery | EventQuery[], engineOptions?: EngineOptions, @@ -438,15 +455,18 @@ export class CameraManager { for (const query of queries) { const newChunkQuery = { ...query }; + /* istanbul ignore else: the else path cannot be reached -- @preserve */ if (direction === 'later') { const latestResult = getTimeFromResults('latest'); if (latestResult) { newChunkQuery.start = latestResult; + delete(newChunkQuery.end); } } else if (direction === 'earlier') { const earliestResult = getTimeFromResults('earliest'); if (earliestResult) { newChunkQuery.end = earliestResult; + delete(newChunkQuery.start); } } newChunkQuery.limit = chunkSize; @@ -550,13 +570,11 @@ export class CameraManager { public async getMediaSeekTime(media: ViewMedia, target: Date): Promise { const startTime = media.getStartTime(); const endTime = media.getEndTime(); - const cameraConfig = this._store.getCameraConfigForMedia(media); const engine = this._store.getEngineForMedia(media); const hass = this._api.getHASSManager().getHASS(); if ( !hass || - !cameraConfig || !engine || !startTime || !endTime || @@ -584,13 +602,11 @@ export class CameraManager { const processEngineQuery = async ( engine: CameraManagerEngine, - query?: QT, + query: QT, ): Promise => { - if (!query) { - return; - } - let engineResult: Map> | null = null; + + /* istanbul ignore else: the else path cannot be reached -- @preserve */ if (QueryClassifier.isEventQuery(query)) { engineResult = (await engine.getEvents( hass, @@ -676,6 +692,7 @@ export class CameraManager { if (engine) { let media: ViewMedia[] | null = null; + /* istanbul ignore else: the else path cannot be reached -- @preserve */ if ( QueryClassifier.isEventQuery(query) && QueryResultClassifier.isEventQueryResult(result) @@ -683,7 +700,7 @@ export class CameraManager { media = engine.generateMediaFromEvents(hass, this._store, query, result); } else if ( QueryClassifier.isRecordingQuery(query) && - QueryResultClassifier.isRecordingQuery(result) + QueryResultClassifier.isRecordingQueryResult(result) ) { media = engine.generateMediaFromRecordings(hass, this._store, query, result); } diff --git a/src/camera-manager/motioneye/engine-motioneye.ts b/src/camera-manager/motioneye/engine-motioneye.ts index f326b08f..41540ddc 100644 --- a/src/camera-manager/motioneye/engine-motioneye.ts +++ b/src/camera-manager/motioneye/engine-motioneye.ts @@ -8,18 +8,21 @@ import { CameraConfig } from '../../config/types'; import { allPromises, formatDate, isValidDate } from '../../utils/basic'; import { BrowseMediaStep, - BrowseMediaTarget + BrowseMediaTarget, } from '../../utils/ha/browse-media/browse-media-manager'; import { - BrowseMedia, BROWSE_MEDIA_CACHE_SECONDS, MEDIA_CLASS_IMAGE, + BrowseMedia, + BROWSE_MEDIA_CACHE_SECONDS, + MEDIA_CLASS_IMAGE, MEDIA_CLASS_VIDEO, - RichBrowseMedia + RichBrowseMedia, } from '../../utils/ha/browse-media/types'; import { ViewMedia } from '../../view/media'; +import { BrowseMediaCamera } from '../browse-media/camera'; import { BrowseMediaCameraManagerEngine, getViewMediaFromBrowseMediaArray, - isMediaWithinDates + isMediaWithinDates, } from '../browse-media/engine-browse-media'; import { BrowseMediaMetadata } from '../browse-media/types'; import { CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT } from '../engine'; @@ -39,7 +42,7 @@ import { MediaMetadataQueryResultsMap, QueryResults, QueryResultsType, - QueryReturnType + QueryReturnType, } from '../types'; import motioneyeLogo from './assets/motioneye-logo.svg'; import { MotionEyeEventQueryResults } from './types'; @@ -134,13 +137,18 @@ export class MotionEyeCameraManagerEngine extends BrowseMediaCameraManagerEngine } | null, engineOptions?: EngineOptions, ): Promise[] | null> { - const cameraConfig = store.getCameraConfig(cameraID); - const cameraEntityID = cameraConfig?.camera_entity; - const entity = cameraEntityID ? this._cameraEntities.get(cameraEntityID) : null; + const camera = store.getCamera(cameraID); + const cameraConfig = camera?.getConfig(); + + if (!(camera instanceof BrowseMediaCamera) || !cameraConfig) { + return null; + } + + const entity = camera.getEntity(); const configID = entity?.config_entry_id; const deviceID = entity?.device_id; - if (!configID || !deviceID || !cameraConfig) { + if (!configID || !deviceID) { return null; } diff --git a/src/camera-manager/store.ts b/src/camera-manager/store.ts index 752a6aaf..c27e3ebe 100644 --- a/src/camera-manager/store.ts +++ b/src/camera-manager/store.ts @@ -1,4 +1,5 @@ import { CameraConfig } from '../config/types'; +import { allPromises } from '../utils/basic'; import { ViewMedia } from '../view/media'; import { Camera } from './camera'; import { CameraManagerEngine } from './engine'; @@ -35,7 +36,9 @@ export class CameraManagerStore implements CameraManagerReadOnlyConfigStore { this._cameras.set(camera.getID(), camera); this._enginesByType.set(camera.getEngine().getEngineType(), camera.getEngine()); } - public reset(): void { + + public async reset(): Promise { + await allPromises(this._cameras.values(), (camera) => camera.destroy()); this._cameras.clear(); this._enginesByType.clear(); } diff --git a/src/camera-manager/types.ts b/src/camera-manager/types.ts index 9f4353bd..76d0f7bc 100644 --- a/src/camera-manager/types.ts +++ b/src/camera-manager/types.ts @@ -150,6 +150,22 @@ export interface EngineOptions { useCache?: boolean; } +export interface CameraEvent { + cameraID: string; + + type: 'new' | 'update' | 'end'; + + // When fidelity is `high`, the engine is assumed to provide exact details of + // what new media is available. Otherwise all media types are assumed to be + // possibly newly available. + fidelity?: 'high' | 'low'; + + // Whether a new clip/snapshot/recording may be available. + clip?: boolean; + snapshot?: boolean; +} +export type CameraEventCallback = (ev: CameraEvent) => void; + // =========== // Event Query // =========== diff --git a/src/camera-manager/utils.ts b/src/camera-manager/utils.ts index dfa33d8b..89c9b2e7 100644 --- a/src/camera-manager/utils.ts +++ b/src/camera-manager/utils.ts @@ -51,7 +51,7 @@ export const sortMedia = (mediaArray: ViewMedia[]): ViewMedia[] => { // Sort all items leading oldest -> youngest (so media is loaded in this // order in the viewer which matches the left-to-right timeline order). - (media) => media.getStartTime(), + (media) => media.getStartTime() ?? media.getID(), 'asc', ); }; diff --git a/src/card-controller/card-element-manager.ts b/src/card-controller/card-element-manager.ts index cbbc6107..38599fd2 100644 --- a/src/card-controller/card-element-manager.ts +++ b/src/card-controller/card-element-manager.ts @@ -2,6 +2,7 @@ import { LitElement, ReactiveControllerHost } from 'lit'; import { ActionEventTarget } from '../action-handler-directive'; import { setOrRemoveAttribute } from '../utils/basic'; import { isCardInPanel } from '../utils/ha'; +import { InitializationAspect } from './initialization-manager'; import { CardElementAPI } from './types'; export type ScrollCallback = () => void; @@ -103,6 +104,16 @@ export class CardElementManager { this._api.getMediaLoadedInfoManager().clear(); this._api.getFullscreenManager().disconnect(); + // Reset and uninitialize cameras to cause them to reinitialize on + // reconnection, to ensure the state subscription/unsubscription works + // correctly for triggers. + this._api + .getCameraManager() + .reset() + .then(() => + this._api.getInitializationManager().uninitialize(InitializationAspect.CAMERAS), + ); + this._element.removeEventListener( 'mousemove', this._api.getInteractionManager().reportInteraction, diff --git a/src/card-controller/conditions-manager.ts b/src/card-controller/conditions-manager.ts index 7072323b..848d2a1e 100644 --- a/src/card-controller/conditions-manager.ts +++ b/src/card-controller/conditions-manager.ts @@ -192,6 +192,10 @@ export class ConditionsManager { }; this._triggerChange(); } + + public getState(): ConditionState { + return this._state; + } public hasHAStateConditions(): boolean { return this._hasHAStateConditions; diff --git a/src/card-controller/hass-manager.ts b/src/card-controller/hass-manager.ts index 4c697165..db50c7c9 100644 --- a/src/card-controller/hass-manager.ts +++ b/src/card-controller/hass-manager.ts @@ -1,4 +1,3 @@ -import { CameraConfig } from '../config/types'; import { localize } from '../localize/localize'; import { ExtendedHomeAssistant } from '../types'; import { hasHAConnectionStateChanged, isHassDifferent } from '../utils/ha'; @@ -17,15 +16,6 @@ export class HASSManager { } public setHASS(hass?: ExtendedHomeAssistant | null): void { - const getSelectedCameraConfig = (): CameraConfig | null => { - const view = this._api.getViewManager().getView(); - const cameraManager = this._api.getCameraManager(); - - return view && cameraManager - ? cameraManager?.getStore().getCameraConfig(view.camera) ?? null - : null; - }; - if (hasHAConnectionStateChanged(this._hass, hass)) { if (!hass?.connected) { this._api.getMessageManager().setMessageIfHigherPriority({ @@ -54,10 +44,11 @@ export class HASSManager { // Assistant update if there's been recent interaction (e.g. clicks on the // card) or if there is media active playing. this._isAutomatedViewUpdateAllowed() && - isHassDifferent(this._hass, oldHass, [ - ...(this._api.getConfigManager().getConfig()?.view.update_entities ?? []), - ...(getSelectedCameraConfig()?.triggers.entities ?? []), - ]) + isHassDifferent( + this._hass, + oldHass, + this._api.getConfigManager().getConfig()?.view.update_entities ?? [], + ) ) { // If entities being monitored have changed then reset the view to the // default. @@ -74,8 +65,6 @@ export class HASSManager { this._api.getCardElementManager().update(); } - this._api.getTriggersManager().updateTriggerHAState(oldHass); - if (this._api.getConditionsManager().hasHAStateConditions()) { this._api.getConditionsManager().setState({ state: this._hass.states }); } diff --git a/src/card-controller/triggers-manager.ts b/src/card-controller/triggers-manager.ts index ff4362ff..46de4752 100644 --- a/src/card-controller/triggers-manager.ts +++ b/src/card-controller/triggers-manager.ts @@ -1,8 +1,8 @@ -import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import isEqual from 'lodash-es/isEqual'; import orderBy from 'lodash-es/orderBy'; -import { getHassDifferences, isTriggeredState } from '../utils/ha'; +import throttle from 'lodash-es/throttle'; +import { CameraEvent } from '../camera-manager/types'; import { Timer } from '../utils/timer'; -import { View } from '../view/view'; import { CardTriggersAPI } from './types'; export class TriggersManager { @@ -10,7 +10,10 @@ export class TriggersManager { protected _triggeredCameras: Map = new Map(); protected _triggeredCameraTimers: Map = new Map(); - protected _triggeredState: Set = new Set(); + + protected _throttledTriggerAction = throttle(this._triggerAction.bind(this), 1000, { + trailing: true, + }); constructor(api: CardTriggersAPI) { this._api = api; @@ -33,125 +36,112 @@ export class TriggersManager { return sorted.length ? sorted[0][0] : null; } - public updateTriggerHAState(oldHass?: HomeAssistant | null): void { - const scanConfig = this._api.getConfigManager().getConfig()?.view.scan; - if (!scanConfig || !scanConfig.enabled) { + public handleCameraEvent(ev: CameraEvent): void { + const triggersConfig = this._api.getConfigManager().getConfig()?.view.triggers; + const selectedCameraID = this._api.getViewManager().getView()?.camera; + + if (!triggersConfig || !selectedCameraID) { return; } - const hass = this._api.getHASSManager().getHASS(); - let triggerChanges = false; - - const visibleCameraIDs = this._api + const dependentCameraIDs = this._api .getCameraManager() .getStore() - .getVisibleCameraIDs(); - for (const [cameraID, config] of this._api - .getCameraManager() - .getStore() - .getCameraConfigEntries(visibleCameraIDs)) { - const triggerEntities = config.triggers.entities; - const diffs = getHassDifferences(hass, oldHass, triggerEntities, { - stateOnly: true, - }); - const shouldTrigger = diffs.some((diff) => isTriggeredState(diff.newState)); - const shouldUntrigger = triggerEntities.every( - (entity) => !isTriggeredState(hass?.states[entity]), - ); - if (shouldTrigger) { - this._triggeredState.add(cameraID); - triggerChanges = true; - } else if (shouldUntrigger && this._triggeredState.has(cameraID)) { - this._triggeredState.delete(cameraID); - triggerChanges = true; - } - } + .getAllDependentCameras(selectedCameraID); - if (triggerChanges) { - this._evaluateTriggers(); - } - } - - public updateView(oldView?: View | null): void { - if (oldView?.camera !== this._api.getViewManager().getView()?.camera) { - // If the view changes, a new camera may have been selected, which may - // mean a trigger is required (in the case that `filter_selected_camera` - // is true). - this._evaluateTriggers(); - } - } - - protected _evaluateTriggers(): void { - const scanConfig = this._api.getConfigManager().getConfig()?.view.scan; - if (!scanConfig) { + if (triggersConfig.filter_selected_camera && !dependentCameraIDs.has(ev.cameraID)) { return; } - const now = new Date(); - for (const cameraID of this._triggeredState.keys()) { - if ( - !this._triggeredCameras.has(cameraID) && - (!scanConfig.filter_selected_camera || - cameraID === this._api.getViewManager().getView()?.camera) - ) { - this._triggeredCameras.set(cameraID, now); - this._setConditionState(); - this._triggerAction(cameraID); - } + if (ev.type === 'end') { + this._startUntriggerTimer(ev.cameraID); + return; } - for (const cameraID of this._triggeredCameras.keys()) { - if (!this._triggeredState.has(cameraID)) { - this._startUntriggerTimer(cameraID); - } - } + this._triggeredCameras.set(ev.cameraID, new Date()); + this._setConditionStateIfNecessary(); + this._throttledTriggerAction(ev); } protected _hasAllowableInteractionStateForAction(): boolean { - const scanConfig = this._api.getConfigManager().getConfig()?.view.scan; + const triggersConfig = this._api.getConfigManager().getConfig()?.view.triggers; const hasInteraction = this._api.getInteractionManager().hasInteraction(); return ( - !!scanConfig && - (scanConfig.actions.interaction_mode === 'all' || - (scanConfig.actions.interaction_mode === 'active' && hasInteraction) || - (scanConfig.actions.interaction_mode === 'inactive' && !hasInteraction)) + !!triggersConfig && + (triggersConfig.actions.interaction_mode === 'all' || + (triggersConfig.actions.interaction_mode === 'active' && hasInteraction) || + (triggersConfig.actions.interaction_mode === 'inactive' && !hasInteraction)) ); } - protected _triggerAction(cameraID: string): void { - const action = this._api.getConfigManager().getConfig()?.view.scan.actions.trigger; + protected _triggerAction(ev: CameraEvent): void { + const triggerAction = this._api.getConfigManager().getConfig()?.view.triggers + .actions.trigger; + const defaultView = this._api.getConfigManager().getConfig()?.view.default; - if (action === 'live' && this._hasAllowableInteractionStateForAction()) { - this._api.getViewManager().setViewByParameters({ - viewName: 'live', - cameraID: cameraID, - }); + // If this is a high-fidelity event where we are certain about new media, + // don't take action unless it's to change to live (Frigate engine may pump + // out events where there's no new media to show). + if ( + ev.fidelity === 'high' && + !ev.snapshot && + !ev.clip && + !( + triggerAction === 'live' || + (triggerAction === 'default' && defaultView === 'live') + ) + ) { + return; } - // Must update master element to add border pulsing. + if (this._hasAllowableInteractionStateForAction()) { + if (triggerAction === 'live') { + this._api.getViewManager().setViewByParameters({ + viewName: 'live', + cameraID: ev.cameraID, + }); + } else if (triggerAction === 'default') { + this._api.getViewManager().setViewDefault({ + cameraID: ev.cameraID, + }); + } else if (ev.fidelity === 'high' && triggerAction === 'media') { + this._api.getViewManager().setViewByParameters({ + viewName: ev.clip ? 'clip' : 'snapshot', + cameraID: ev.cameraID, + }); + } + } + + // Must update master element to add border pulsing to live view. this._api.getCardElementManager().update(); } - protected _setConditionState(): void { - this._api.getConditionsManager().setState({ - triggered: this._triggeredCameras.size - ? new Set(this._triggeredCameras.keys()) - : undefined, - }); + protected _setConditionStateIfNecessary(): void { + const triggeredCameraIDs = new Set(this._triggeredCameras.keys()); + const triggeredState = triggeredCameraIDs.size ? triggeredCameraIDs : undefined; + + if ( + !isEqual(triggeredState, this._api.getConditionsManager().getState().triggered) + ) { + this._api.getConditionsManager().setState({ + triggered: triggeredState, + }); + } } protected _untriggerAction(cameraID: string): void { - const action = this._api.getConfigManager().getConfig()?.view.scan.actions.untrigger; + const action = this._api.getConfigManager().getConfig()?.view.triggers + .actions.untrigger; if (action === 'default' && this._hasAllowableInteractionStateForAction()) { this._api.getViewManager().setViewDefault(); } this._triggeredCameras.delete(cameraID); this._deleteTimer(cameraID); - this._setConditionState(); + this._setConditionStateIfNecessary(); - // Must update master element to remove border pulsing. + // Must update master element to remove border pulsing from live view. this._api.getCardElementManager().update(); } @@ -164,7 +154,7 @@ export class TriggersManager { /* istanbul ignore next: the case of config being null here cannot be reached, as there's no way to have the untrigger call happen without a config. -- @preserve */ - this._api.getConfigManager().getConfig()?.view.scan.untrigger_seconds ?? 0, + this._api.getConfigManager().getConfig()?.view.triggers.untrigger_seconds ?? 0, () => { this._untriggerAction(cameraID); }, diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index 89122b00..33c4df07 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -1,27 +1,27 @@ -import { CameraManager } from '../camera-manager/manager'; -import { ConditionsManager } from './conditions-manager'; -import { EntityRegistryManager } from '../utils/ha/entity-registry'; -import { ResolvedMediaCache } from '../utils/ha/resolved-media'; -import { ActionsManager } from './actions-manager'; -import { AutoUpdateManager } from './auto-update-manager'; -import { AutomationsManager } from './automations-manager'; -import { CameraURLManager } from './camera-url-manager'; -import { CardElementManager } from './card-element-manager'; -import { ConfigManager } from './config-manager'; -import { DownloadManager } from './download-manager'; -import { ExpandManager } from './expand-manager'; -import { FullscreenManager } from './fullscreen-manager'; -import { HASSManager } from './hass-manager'; -import { InitializationManager } from './initialization-manager'; -import { InteractionManager } from './interaction-manager'; -import { MediaLoadedInfoManager } from './media-info-manager'; -import { MediaPlayerManager } from './media-player-manager'; -import { MessageManager } from './message-manager'; -import { MicrophoneManager } from './microphone-manager'; -import { StyleManager } from './style-manager'; -import { TriggersManager } from './triggers-manager'; -import { ViewManager } from './view-manager'; -import { QueryStringManager } from './query-string-manager'; +import type { CameraManager } from '../camera-manager/manager'; +import type { ConditionsManager } from './conditions-manager'; +import type { EntityRegistryManager } from '../utils/ha/entity-registry'; +import type { ResolvedMediaCache } from '../utils/ha/resolved-media'; +import type { ActionsManager } from './actions-manager'; +import type { AutoUpdateManager } from './auto-update-manager'; +import type { AutomationsManager } from './automations-manager'; +import type { CameraURLManager } from './camera-url-manager'; +import type { CardElementManager } from './card-element-manager'; +import type { ConfigManager } from './config-manager'; +import type { DownloadManager } from './download-manager'; +import type { ExpandManager } from './expand-manager'; +import type { FullscreenManager } from './fullscreen-manager'; +import type { HASSManager } from './hass-manager'; +import type { InitializationManager } from './initialization-manager'; +import type { InteractionManager } from './interaction-manager'; +import type { MediaLoadedInfoManager } from './media-info-manager'; +import type { MediaPlayerManager } from './media-player-manager'; +import type { MessageManager } from './message-manager'; +import type { MicrophoneManager } from './microphone-manager'; +import type { StyleManager } from './style-manager'; +import type { TriggersManager } from './triggers-manager'; +import type { ViewManager } from './view-manager'; +import type { QueryStringManager } from './query-string-manager'; /** * This defines a series of limited APIs that various manager helpers use to @@ -67,6 +67,7 @@ export interface CardCameraAPI { getHASSManager(): HASSManager; getMessageManager(): MessageManager; getResolvedMediaCache(): ResolvedMediaCache; + getTriggersManager(): TriggersManager; } export interface CardCameraURLAPI { @@ -100,8 +101,10 @@ export interface CardDownloadAPI { export interface CardElementAPI { getActionsManager(): ActionsManager; + getCameraManager(): CameraManager; getExpandManager(): ExpandManager; getFullscreenManager(): FullscreenManager; + getInitializationManager(): InitializationManager; getInteractionManager(): InteractionManager; getMediaLoadedInfoManager(): MediaLoadedInfoManager; getMicrophoneManager(): MicrophoneManager; @@ -205,7 +208,6 @@ export interface CardTriggersAPI { getConditionsManager(): ConditionsManager; getCardElementManager(): CardElementManager; getConfigManager(): ConfigManager; - getHASSManager(): HASSManager; getInteractionManager(): InteractionManager; getViewManager(): ViewManager; } diff --git a/src/card-controller/view-manager.ts b/src/card-controller/view-manager.ts index 71940719..fe5c9657 100644 --- a/src/card-controller/view-manager.ts +++ b/src/card-controller/view-manager.ts @@ -245,7 +245,6 @@ export class ViewManager { displayMode: view.displayMode ?? undefined, }); - this._api.getTriggersManager().updateView(oldView); this._api.getCardElementManager().update(); } diff --git a/src/card.ts b/src/card.ts index 57633f66..9370f2b1 100644 --- a/src/card.ts +++ b/src/card.ts @@ -163,6 +163,13 @@ class FrigateCard extends LitElement { } protected shouldUpdate(): boolean { + // Do not allow a disconnected element to update, as it may cause cameras to + // reinitialize/subscribe for an element that is no longer part of the + // document. + if (!this.isConnected) { + return false; + } + // Always allow messages to render, as a message may be generated during // initialization. if (this._controller.getMessageManager().hasMessage()) { @@ -307,7 +314,7 @@ class FrigateCard extends LitElement { ?.getEpoch()} .hide=${!!this._controller.getMessageManager().hasMessage()} .microphoneManager=${this._controller.getMicrophoneManager()} - .triggeredCameraIDs=${this._config?.view.scan.show_trigger_status + .triggeredCameraIDs=${this._config?.view.triggers.show_trigger_status ? this._controller.getTriggersManager().getTriggeredCameraIDs() : undefined} >`} diff --git a/src/components-lib/timeline-source.ts b/src/components-lib/timeline-source.ts index ad9eb210..823cce5c 100644 --- a/src/components-lib/timeline-source.ts +++ b/src/components-lib/timeline-source.ts @@ -29,6 +29,10 @@ export interface FrigateCardTimelineItem extends TimelineItem { // high-quantity recording segments). start: number; end?: number; + + // DataSet requires string (not HTMLElement) content. + content: string; + media?: ViewMedia; } diff --git a/src/components/live/go2rtc/video-rtc.d.ts b/src/components/live/go2rtc/video-rtc.d.ts index 8261c7fb..3da8d890 100644 --- a/src/components/live/go2rtc/video-rtc.d.ts +++ b/src/components/live/go2rtc/video-rtc.d.ts @@ -9,7 +9,7 @@ export class VideoRTC extends HTMLElement { pcConfig: RTCConfiguration; wsState: number; pcState: number; - video: HTMLVideoElement; + video: HTMLVideoElement | null; ws: WebSocket | null; wsURL: string; pc: RTCPeerConnection | null; diff --git a/src/components/live/live-go2rtc.ts b/src/components/live/live-go2rtc.ts index be722aba..102e6f3d 100644 --- a/src/components/live/live-go2rtc.ts +++ b/src/components/live/live-go2rtc.ts @@ -71,7 +71,7 @@ export class FrigateCardGo2RTC extends LitElement implements FrigateCardMediaPla } public isMuted(): boolean { - return this._player?.video.muted ?? true; + return this._player?.video?.muted ?? true; } public async seek(seconds: number): Promise { @@ -87,11 +87,11 @@ export class FrigateCardGo2RTC extends LitElement implements FrigateCardMediaPla } public isPaused(): boolean { - return this._player?.video.paused ?? true; + return this._player?.video?.paused ?? true; } public async getScreenshotURL(): Promise { - return this._player ? screenshotMedia(this._player.video) : null; + return this._player?.video ? screenshotMedia(this._player.video) : null; } disconnectedCallback(): void { diff --git a/src/components/surround.ts b/src/components/surround.ts index ad89f4ec..c7cc0d5b 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -133,7 +133,7 @@ export class FrigateCardSurround extends LitElement { */ protected willUpdate(changedProperties: PropertyValues): void { if (this.timelineConfig?.mode && this.timelineConfig.mode !== 'none') { - import('./timeline.js'); + import('./timeline-core.js'); } // Only reset the timeline cameraIDs when the media or display mode diff --git a/src/components/viewer.ts b/src/components/viewer.ts index 7310853d..1b1791ab 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -139,7 +139,7 @@ export class FrigateCardViewer extends LitElement { const mediaType = this.view.getDefaultMediaType(); if (!mediaType) { // Directly render an error message (instead of dispatching it upwards) - // to preserve the mini-timeline if the user scans into an area with no + // to preserve the mini-timeline if the user pans into an area with no // media. return renderMessage({ type: 'info', @@ -157,6 +157,7 @@ export class FrigateCardViewer extends LitElement { { allCameras: this.view.isGrid(), targetView: 'recording', + useCache: false, }, ); } else { @@ -169,6 +170,7 @@ export class FrigateCardViewer extends LitElement { allCameras: this.view.isGrid(), targetView: 'media', eventsMediaType: mediaType, + useCache: false, }, ); } diff --git a/src/config-mgmt.ts b/src/config-mgmt.ts index fd0e0e20..dd13f89f 100644 --- a/src/config-mgmt.ts +++ b/src/config-mgmt.ts @@ -18,7 +18,10 @@ import { CONF_OVERRIDES, CONF_TIMELINE_EVENTS_MEDIA_TYPE, CONF_VIEW_INTERACTION_SECONDS, - CONF_VIEW_SCAN_ACTIONS_UNTRIGGER, + CONF_VIEW_TRIGGERS, + CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER, + CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER, + CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA, } from './const'; import { arrayify } from './utils/basic'; @@ -213,6 +216,18 @@ export const upgradeWithOverrides = function ( return upgradeMoveToWithOverrides(path, path, { transform: transform }); }; +/** + * Delete a property in place with overrides. + * @param path The property path. + * @returns A function that returns `true` if the configuration was modified. + */ +export const deleteWithOverrides = function ( + path: string, +): (obj: RawFrigateCardConfig) => boolean { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + return upgradeMoveToWithOverrides(path, path, { transform: (_) => null }); +}; + /** * Given a path to an array, apply an upgrade to each object in the array. * @param arrayPath The path to the array to upgrade. @@ -480,14 +495,6 @@ const UPGRADES = [ ); }, upgradePTZElementsToLive(), - upgradeMoveToWithOverrides( - 'view.scan.untrigger_reset', - CONF_VIEW_SCAN_ACTIONS_UNTRIGGER, - { - // Delete the value if it's set to the default. - transform: (val) => (val ? 'default' : null), - }, - ), upgradeMoveToWithOverrides('view.timeout_seconds', CONF_VIEW_INTERACTION_SECONDS), upgradeWithOverrides('live.lazy_unload', (data) => data === 'all' ? ['unselected', 'hidden'] : data === 'never' ? null : arrayify(data), @@ -524,10 +531,7 @@ const UPGRADES = [ 'live.controls.thumbnails.media', CONF_LIVE_CONTROLS_THUMBNAILS_EVENTS_MEDIA_TYPE, ), - upgradeMoveToWithOverrides( - 'timeline.media', - CONF_TIMELINE_EVENTS_MEDIA_TYPE, - ), + upgradeMoveToWithOverrides('timeline.media', CONF_TIMELINE_EVENTS_MEDIA_TYPE), upgradeMoveToWithOverrides( 'live.controls.timeline.media', CONF_LIVE_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, @@ -536,4 +540,29 @@ const UPGRADES = [ 'media_viewer.controls.timeline.media', CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, ), + upgradeMoveToWithOverrides('view.scan', CONF_VIEW_TRIGGERS), + upgradeMoveToWithOverrides( + 'view.triggers.enabled', + CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER, + { + transform: (data) => (data === true ? 'live' : null), + // Keep it around, for the following transform. + keepOriginal: true, + }, + ), + upgradeMoveToWithOverrides( + 'view.triggers.enabled', + CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA, + { + transform: (data) => (data === true ? false : null), + }, + ), + upgradeMoveToWithOverrides( + 'view.triggers.untrigger_reset', + CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER, + { + // Delete the value if it's set to the default. + transform: (val) => (val ? 'default' : null), + }, + ), ]; diff --git a/src/config/types.ts b/src/config/types.ts index 1ab1941f..39d745cc 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -77,6 +77,16 @@ export type PTZAction = (typeof PTZ_ACTIONS)[number]; const PTZ_PHASES = ['start', 'stop'] as const; export type PTZPhase = (typeof PTZ_PHASES)[number]; +const CAMERA_TRIGGER_EVENT_TYPES = [ + // An event whether or not it has any media yet associated with it. + 'events', + + // Specific media availability. + 'clips', + 'snapshots', +] as const; +export type CameraTriggerEventType = (typeof CAMERA_TRIGGER_EVENT_TYPES)[number]; + // ************************************************************************* // View Display Mode // ************************************************************************* @@ -326,7 +336,7 @@ const actionsSchema = z.object({ }); const elementsBaseSchema = actionsBaseSchema.extend({ - style: z.record(z.string().nullable().or(z.undefined())).optional(), + style: z.record(z.string().nullable().or(z.undefined()).or(z.number())).optional(), title: z.string().nullable().optional(), }); @@ -1038,7 +1048,8 @@ const cameraConfigDefault = { }, triggers: { motion: false, - occupancy: true, + occupancy: false, + events: [...CAMERA_TRIGGER_EVENT_TYPES], entities: [], }, }; @@ -1071,6 +1082,10 @@ export const cameraConfigSchema = z motion: z.boolean().default(cameraConfigDefault.triggers.motion), occupancy: z.boolean().default(cameraConfigDefault.triggers.occupancy), entities: z.string().array().default(cameraConfigDefault.triggers.entities), + events: z + .enum(CAMERA_TRIGGER_EVENT_TYPES) + .array() + .default(cameraConfigDefault.triggers.events), }) .default(cameraConfigDefault.triggers), @@ -1145,41 +1160,42 @@ const viewConfigDefault = { update_force: false, update_cycle_camera: false, dark_mode: 'off' as const, - scan: { - enabled: false, - show_trigger_status: true, - filter_selected_camera: false, + triggers: { + show_trigger_status: false, + filter_selected_camera: true, actions: { interaction_mode: 'inactive' as const, - trigger: 'live' as const, - untrigger: 'default' as const, + trigger: 'default' as const, + untrigger: 'none' as const, }, untrigger_seconds: 0, }, }; -export const scanSchema = z.object({ - enabled: z.boolean().default(viewConfigDefault.scan.enabled), - +export const triggersSchema = z.object({ filter_selected_camera: z .boolean() - .default(viewConfigDefault.scan.filter_selected_camera), - show_trigger_status: z.boolean().default(viewConfigDefault.scan.show_trigger_status), + .default(viewConfigDefault.triggers.filter_selected_camera), + show_trigger_status: z + .boolean() + .default(viewConfigDefault.triggers.show_trigger_status), actions: z .object({ interaction_mode: z .enum(['all', 'inactive', 'active']) - .default(viewConfigDefault.scan.actions.interaction_mode), - trigger: z.enum(['live', 'none']).default(viewConfigDefault.scan.actions.trigger), + .default(viewConfigDefault.triggers.actions.interaction_mode), + trigger: z + .enum(['live', 'default', 'media', 'none']) + .default(viewConfigDefault.triggers.actions.trigger), untrigger: z .enum(['default', 'none']) - .default(viewConfigDefault.scan.actions.untrigger), + .default(viewConfigDefault.triggers.actions.untrigger), }) - .default(viewConfigDefault.scan.actions), - untrigger_seconds: z.number().default(viewConfigDefault.scan.untrigger_seconds), + .default(viewConfigDefault.triggers.actions), + untrigger_seconds: z.number().default(viewConfigDefault.triggers.untrigger_seconds), }); -export type ScanOptions = z.infer; +export type TriggersOptions = z.infer; const viewConfigSchema = z .object({ @@ -1199,7 +1215,7 @@ const viewConfigSchema = z update_entities: z.string().array().optional(), render_entities: z.string().array().optional(), dark_mode: z.enum(['on', 'off', 'auto']).optional(), - scan: scanSchema.default(viewConfigDefault.scan), + triggers: triggersSchema.default(viewConfigDefault.triggers), }) .merge(actionsSchema) .default(viewConfigDefault); diff --git a/src/const.ts b/src/const.ts index f3f3298b..5addcfae 100644 --- a/src/const.ts +++ b/src/const.ts @@ -54,6 +54,8 @@ export const CONF_CAMERAS_ARRAY_TRIGGERS_OCCUPANCY = `${CONF_CAMERAS}.#.triggers.occupancy` as const; export const CONF_CAMERAS_ARRAY_TRIGGERS_ENTITIES = `${CONF_CAMERAS}.#.triggers.entities` as const; +export const CONF_CAMERAS_ARRAY_TRIGGERS_EVENTS = + `${CONF_CAMERAS}.#.triggers.events` as const; const CONF_CAMERAS_GLOBAL = 'cameras_global' as const; export const CONF_CAMERAS_GLOBAL_IMAGE = `${CONF_CAMERAS_GLOBAL}.image` as const; @@ -77,21 +79,20 @@ export const CONF_VIEW_UPDATE_FORCE = `${CONF_VIEW}.update_force` as const; export const CONF_VIEW_UPDATE_SECONDS = `${CONF_VIEW}.update_seconds` as const; export const CONF_VIEW_RESET_AFTER_INTERACTION = `${CONF_VIEW}.reset_after_interaction` as const; -export const CONF_VIEW_SCAN = `${CONF_VIEW}.scan` as const; -export const CONF_VIEW_SCAN_ENABLED = `${CONF_VIEW_SCAN}.enabled` as const; -export const CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS = - `${CONF_VIEW_SCAN}.show_trigger_status` as const; -export const CONF_VIEW_SCAN_FILTER_SELECTED_CAMERA = - `${CONF_VIEW_SCAN}.filter_selected_camera` as const; -export const CONF_VIEW_SCAN_UNTRIGGER_SECONDS = - `${CONF_VIEW_SCAN}.untrigger_seconds` as const; -export const CONF_VIEW_SCAN_ACTIONS = `${CONF_VIEW_SCAN}.actions` as const; -export const CONF_VIEW_SCAN_ACTIONS_TRIGGER = - `${CONF_VIEW_SCAN_ACTIONS}.trigger` as const; -export const CONF_VIEW_SCAN_ACTIONS_UNTRIGGER = - `${CONF_VIEW_SCAN_ACTIONS}.untrigger` as const; -export const CONF_VIEW_SCAN_ACTIONS_INTERACTION_MODE = - `${CONF_VIEW_SCAN_ACTIONS}.interaction_mode` as const; +export const CONF_VIEW_TRIGGERS = `${CONF_VIEW}.triggers` as const; +export const CONF_VIEW_TRIGGERS_SHOW_TRIGGER_STATUS = + `${CONF_VIEW_TRIGGERS}.show_trigger_status` as const; +export const CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA = + `${CONF_VIEW_TRIGGERS}.filter_selected_camera` as const; +export const CONF_VIEW_TRIGGERS_UNTRIGGER_SECONDS = + `${CONF_VIEW_TRIGGERS}.untrigger_seconds` as const; +export const CONF_VIEW_TRIGGERS_ACTIONS = `${CONF_VIEW_TRIGGERS}.actions` as const; +export const CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER = + `${CONF_VIEW_TRIGGERS_ACTIONS}.trigger` as const; +export const CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER = + `${CONF_VIEW_TRIGGERS_ACTIONS}.untrigger` as const; +export const CONF_VIEW_TRIGGERS_ACTIONS_INTERACTION_MODE = + `${CONF_VIEW_TRIGGERS_ACTIONS}.interaction_mode` as const; export const CONF_MEDIA_GALLERY = 'media_gallery' as const; export const CONF_MEDIA_GALLERY_CONTROLS_FILTER_MODE = @@ -258,7 +259,8 @@ const CONF_TIMELINE = 'timeline' as const; export const CONF_TIMELINE_WINDOW_SECONDS = `${CONF_TIMELINE}.window_seconds` as const; export const CONF_TIMELINE_CLUSTERING_THRESHOLD = `${CONF_TIMELINE}.clustering_threshold` as const; -export const CONF_TIMELINE_EVENTS_MEDIA_TYPE = `${CONF_TIMELINE}.events_media_type` as const; +export const CONF_TIMELINE_EVENTS_MEDIA_TYPE = + `${CONF_TIMELINE}.events_media_type` as const; export const CONF_TIMELINE_SHOW_RECORDINGS = `${CONF_TIMELINE}.show_recordings` as const; export const CONF_TIMELINE_STYLE = `${CONF_TIMELINE}.style` as const; export const CONF_TIMELINE_CONTROLS_THUMBNAILS_MODE = diff --git a/src/editor.ts b/src/editor.ts index fbd589a8..250467b9 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -22,9 +22,9 @@ import { } from './config-mgmt.js'; import { BUTTON_SIZE_MIN, + FRIGATE_MENU_PRIORITY_MAX, FrigateCardConfig, frigateCardConfigDefaults, - FRIGATE_MENU_PRIORITY_MAX, RawFrigateCardConfig, RawFrigateCardConfigArray, THUMBNAIL_WIDTH_MAX, @@ -58,6 +58,7 @@ import { CONF_CAMERAS_ARRAY_MOTIONEYE_URL, CONF_CAMERAS_ARRAY_TITLE, CONF_CAMERAS_ARRAY_TRIGGERS_ENTITIES, + CONF_CAMERAS_ARRAY_TRIGGERS_EVENTS, CONF_CAMERAS_ARRAY_TRIGGERS_MOTION, CONF_CAMERAS_ARRAY_TRIGGERS_OCCUPANCY, CONF_CAMERAS_ARRAY_WEBRTC_CARD_ENTITY, @@ -159,8 +160,8 @@ import { CONF_MEDIA_VIEWER_TRANSITION_EFFECT, CONF_MEDIA_VIEWER_ZOOMABLE, CONF_MENU_ALIGNMENT, - CONF_MENU_BUTTONS, CONF_MENU_BUTTON_SIZE, + CONF_MENU_BUTTONS, CONF_MENU_POSITION, CONF_MENU_STYLE, CONF_PERFORMANCE_FEATURES_ANIMATED_PROGRESS_INDICATOR, @@ -184,15 +185,14 @@ import { CONF_VIEW_DEFAULT, CONF_VIEW_INTERACTION_SECONDS, CONF_VIEW_RESET_AFTER_INTERACTION, - CONF_VIEW_SCAN, - CONF_VIEW_SCAN_ACTIONS, - CONF_VIEW_SCAN_ACTIONS_INTERACTION_MODE, - CONF_VIEW_SCAN_ACTIONS_TRIGGER, - CONF_VIEW_SCAN_ACTIONS_UNTRIGGER, - CONF_VIEW_SCAN_ENABLED, - CONF_VIEW_SCAN_FILTER_SELECTED_CAMERA, - CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS, - CONF_VIEW_SCAN_UNTRIGGER_SECONDS, + CONF_VIEW_TRIGGERS, + CONF_VIEW_TRIGGERS_ACTIONS, + CONF_VIEW_TRIGGERS_ACTIONS_INTERACTION_MODE, + CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER, + CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER, + CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA, + CONF_VIEW_TRIGGERS_SHOW_TRIGGER_STATUS, + CONF_VIEW_TRIGGERS_UNTRIGGER_SECONDS, CONF_VIEW_UPDATE_CYCLE_CAMERA, CONF_VIEW_UPDATE_FORCE, CONF_VIEW_UPDATE_SECONDS, @@ -244,8 +244,8 @@ const MENU_OPTIONS = 'options'; const MENU_PERFORMANCE_FEATURES = 'performance.features'; const MENU_PERFORMANCE_STYLE = 'performance.style'; const MENU_TIMELINE_CONTROLS_THUMBNAILS = 'timeline.controls.thumbnails'; -const MENU_VIEW_SCAN = 'scan'; -const MENU_VIEW_SCAN_ACTIONS = 'scan.actions'; +const MENU_VIEW_TRIGGERS = 'view.triggers'; +const MENU_VIEW_TRIGGERS_ACTIONS = 'view.triggers.actions'; interface EditorOptionsSet { icon: string; @@ -514,8 +514,14 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor protected _timelineEventsMediaTypes: EditorSelectOption[] = [ { value: '', label: '' }, { value: 'all', label: localize('config.common.timeline.events_media_types.all') }, - { value: 'clips', label: localize('config.common.timeline.events_media_types.clips') }, - { value: 'snapshots', label: localize('config.common.timeline.events_media_types.snapshots') }, + { + value: 'clips', + label: localize('config.common.timeline.events_media_types.clips'), + }, + { + value: 'snapshots', + label: localize('config.common.timeline.events_media_types.snapshots'), + }, ]; protected _timelineStyleTypes: EditorSelectOption[] = [ @@ -653,43 +659,67 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor }, ]; - protected _scanActionsInteractionModes: EditorSelectOption[] = [ + protected _triggersActionsInteractionModes: EditorSelectOption[] = [ { value: '', label: '' }, { value: 'all', - label: localize('config.view.scan.actions.interaction_modes.all'), + label: localize('config.view.triggers.actions.interaction_modes.all'), }, { value: 'inactive', - label: localize('config.view.scan.actions.interaction_modes.inactive'), + label: localize('config.view.triggers.actions.interaction_modes.inactive'), }, { value: 'active', - label: localize('config.view.scan.actions.interaction_modes.active'), + label: localize('config.view.triggers.actions.interaction_modes.active'), }, ]; - protected _scanActionsTrigger: EditorSelectOption[] = [ - { value: '', label: '' }, - { - value: 'live', - label: localize('config.view.scan.actions.triggers.live'), - }, - { - value: 'none', - label: localize('config.view.scan.actions.triggers.none'), - }, - ]; - - protected _scanActionsUntrigger: EditorSelectOption[] = [ + protected _triggersActionsTrigger: EditorSelectOption[] = [ { value: '', label: '' }, { value: 'default', - label: localize('config.view.scan.actions.untriggers.default'), + label: localize('config.view.triggers.actions.triggers.default'), + }, + { + value: 'live', + label: localize('config.view.triggers.actions.triggers.live'), + }, + { + value: 'media', + label: localize('config.view.triggers.actions.triggers.media'), }, { value: 'none', - label: localize('config.view.scan.actions.untriggers.none'), + label: localize('config.view.triggers.actions.triggers.none'), + }, + ]; + + protected _triggersActionsUntrigger: EditorSelectOption[] = [ + { value: '', label: '' }, + { + value: 'default', + label: localize('config.view.triggers.actions.untriggers.default'), + }, + { + value: 'none', + label: localize('config.view.triggers.actions.untriggers.none'), + }, + ]; + + protected _triggersEvents: EditorSelectOption[] = [ + { value: '', label: '' }, + { + value: 'events', + label: localize('config.cameras.triggers.events.events'), + }, + { + value: 'clips', + label: localize('config.cameras.triggers.events.clips'), + }, + { + value: 'snapshots', + label: localize('config.cameras.triggers.events.snapshots'), }, ]; @@ -948,57 +978,54 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ); } - protected _renderViewScanMenu(): TemplateResult { + protected _renderViewTriggersMenu(): TemplateResult { return this._putInSubmenu( - MENU_VIEW_SCAN, + MENU_VIEW_TRIGGERS, true, - `config.${CONF_VIEW_SCAN}.editor_label`, + `config.${CONF_VIEW_TRIGGERS}.editor_label`, { name: 'mdi:target-account' }, html` - ${this._renderSwitch(CONF_VIEW_SCAN_ENABLED, this._defaults.view.scan.enabled, { - label: localize(`config.${CONF_VIEW_SCAN_ENABLED}`), - })} ${this._renderSwitch( - CONF_VIEW_SCAN_FILTER_SELECTED_CAMERA, - this._defaults.view.scan.filter_selected_camera, + CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA, + this._defaults.view.triggers.filter_selected_camera, { - label: localize(`config.${CONF_VIEW_SCAN_FILTER_SELECTED_CAMERA}`), + label: localize(`config.${CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA}`), }, )} ${this._renderSwitch( - CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS, - this._defaults.view.scan.show_trigger_status, + CONF_VIEW_TRIGGERS_SHOW_TRIGGER_STATUS, + this._defaults.view.triggers.show_trigger_status, { - label: localize(`config.${CONF_VIEW_SCAN_SHOW_TRIGGER_STATUS}`), + label: localize(`config.${CONF_VIEW_TRIGGERS_SHOW_TRIGGER_STATUS}`), }, )} - ${this._renderNumberInput(CONF_VIEW_SCAN_UNTRIGGER_SECONDS, { - default: this._defaults.view.scan.untrigger_seconds, + ${this._renderNumberInput(CONF_VIEW_TRIGGERS_UNTRIGGER_SECONDS, { + default: this._defaults.view.triggers.untrigger_seconds, })} ${this._putInSubmenu( - MENU_VIEW_SCAN_ACTIONS, + MENU_VIEW_TRIGGERS_ACTIONS, true, - `config.${CONF_VIEW_SCAN_ACTIONS}.editor_label`, + `config.${CONF_VIEW_TRIGGERS_ACTIONS}.editor_label`, { name: 'mdi:cogs' }, html` ${this._renderOptionSelector( - CONF_VIEW_SCAN_ACTIONS_TRIGGER, - this._scanActionsTrigger, + CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER, + this._triggersActionsTrigger, { - label: localize('config.view.scan.actions.trigger'), + label: localize('config.view.triggers.actions.trigger'), }, )} ${this._renderOptionSelector( - CONF_VIEW_SCAN_ACTIONS_UNTRIGGER, - this._scanActionsUntrigger, + CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER, + this._triggersActionsUntrigger, { - label: localize('config.view.scan.actions.untrigger'), + label: localize('config.view.triggers.actions.untrigger'), }, )} ${this._renderOptionSelector( - CONF_VIEW_SCAN_ACTIONS_INTERACTION_MODE, - this._scanActionsInteractionModes, + CONF_VIEW_TRIGGERS_ACTIONS_INTERACTION_MODE, + this._triggersActionsInteractionModes, { - label: localize('config.view.scan.actions.interaction_mode'), + label: localize('config.view.triggers.actions.interaction_mode'), }, )}`, )} @@ -1188,9 +1215,13 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderNumberInput(configPathClusteringThreshold, { label: localize(`config.common.${CONF_TIMELINE_CLUSTERING_THRESHOLD}`), })} - ${this._renderOptionSelector(configPathTimelineEventsMediaType, this._timelineEventsMediaTypes, { - label: localize(`config.common.${CONF_TIMELINE_EVENTS_MEDIA_TYPE}`), - })} + ${this._renderOptionSelector( + configPathTimelineEventsMediaType, + this._timelineEventsMediaTypes, + { + label: localize(`config.common.${CONF_TIMELINE_EVENTS_MEDIA_TYPE}`), + }, + )} ${this._renderSwitch(configPathShowRecordings, defaultShowRecordings, { label: localize(`config.common.${CONF_TIMELINE_SHOW_RECORDINGS}`), })}`; @@ -1801,21 +1832,40 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor cameraIndex, 'config.cameras.triggers.editor_label', { name: 'mdi:magnify-scan' }, - html` ${this._renderSwitch( - getArrayConfigPath(CONF_CAMERAS_ARRAY_TRIGGERS_OCCUPANCY, cameraIndex), - this._defaults.cameras.triggers.occupancy, - )} - ${this._renderSwitch( - getArrayConfigPath(CONF_CAMERAS_ARRAY_TRIGGERS_MOTION, cameraIndex), - this._defaults.cameras.triggers.motion, - )} - ${this._renderOptionSelector( - getArrayConfigPath(CONF_CAMERAS_ARRAY_TRIGGERS_ENTITIES, cameraIndex), - entities, - { - multiple: true, - }, - )}`, + html` + ${this._renderSwitch( + getArrayConfigPath( + CONF_CAMERAS_ARRAY_TRIGGERS_OCCUPANCY, + cameraIndex, + ), + this._defaults.cameras.triggers.occupancy, + )} + ${this._renderSwitch( + getArrayConfigPath(CONF_CAMERAS_ARRAY_TRIGGERS_MOTION, cameraIndex), + this._defaults.cameras.triggers.motion, + )} + ${this._renderOptionSelector( + getArrayConfigPath( + CONF_CAMERAS_ARRAY_TRIGGERS_ENTITIES, + cameraIndex, + ), + entities, + { + multiple: true, + }, + )} + ${this._renderOptionSelector( + getArrayConfigPath( + CONF_CAMERAS_ARRAY_TRIGGERS_EVENTS, + cameraIndex, + ), + this._triggersEvents, + { + multiple: true, + label: localize('config.cameras.triggers.events.editor_label'), + }, + )} + `, )} ${this._putInSubmenu( MENU_CAMERAS_CAST, @@ -1992,7 +2042,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor CONF_VIEW_UPDATE_CYCLE_CAMERA, this._defaults.view.update_cycle_camera, )} - ${this._renderViewScanMenu()} + ${this._renderViewTriggersMenu()}
` : ''} @@ -2125,7 +2175,8 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor this._defaults.live.controls.thumbnails, { configPathMediaType: CONF_LIVE_CONTROLS_THUMBNAILS_MEDIA_TYPE, - configPathEventsMediaType: CONF_LIVE_CONTROLS_THUMBNAILS_EVENTS_MEDIA_TYPE, + configPathEventsMediaType: + CONF_LIVE_CONTROLS_THUMBNAILS_EVENTS_MEDIA_TYPE, configPathMode: CONF_LIVE_CONTROLS_THUMBNAILS_MODE, }, )} diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index eed8911a..c329ce44 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -85,6 +85,12 @@ "triggers": { "editor_label": "Trigger Options", "entities": "Trigger from other entities", + "events": { + "clips": "Events with new clips", + "editor_label": "Trigger Events", + "events": "All events", + "snapshots": "Events with new snapshots" + }, "motion": "Trigger by auto-detecting the motion sensor", "occupancy": "Trigger by auto-detecting the occupancy sensor" }, @@ -394,9 +400,9 @@ "default": "Default view", "interaction_seconds": "Seconds after user action to remain interacted with (0=never)", "reset_after_interaction": "Reset to the default view after user interaction", - "scan": { + "triggers": { "actions": { - "editor_label": "Scan mode actions", + "editor_label": "Trigger actions", "interaction_mode": "How to handle actions when the card has human interaction", "interaction_modes": { "active": "Only trigger actions when card has human interaction", @@ -405,7 +411,9 @@ }, "trigger": "Trigger action", "triggers": { - "live": "Change to live", + "default": "Change to or update default view", + "live": "Change to or update live view", + "media": "Change to the relevant media view for new media", "none": "No action" }, "untrigger": "Untrigger action", @@ -414,8 +422,7 @@ "none": "No action" } }, - "editor_label": "Scan mode", - "enabled": "Scan mode enabled", + "editor_label": "Behavior when a camera is triggered", "filter_selected_camera": "Only trigger on selected camera", "show_trigger_status": "Show pulsing border when triggered", "untrigger_seconds": "Seconds after inactive state change to untrigger" diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index c2296b40..ef8c0706 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -85,6 +85,12 @@ "triggers": { "editor_label": "Trigger Opzioni", "entities": "Trigger da altre entità", + "events": { + "clips": "", + "editor_label": "", + "events": "", + "snapshots": "" + }, "motion": "Trigger rilevando automaticamente dal sensore di movimento", "occupancy": "Attivare rilevando automatico tramite il sensore di presenza" }, @@ -390,7 +396,7 @@ "default": "Visualizzazione predefinita", "interaction_seconds": "", "reset_after_interaction": "", - "scan": { + "triggers": { "actions": { "editor_label": "", "interaction_mode": "", @@ -401,7 +407,9 @@ }, "trigger": "", "triggers": { + "default": "", "live": "", + "media": "", "none": "" }, "untrigger": "", @@ -410,8 +418,7 @@ "none": "" } }, - "editor_label": "Modalità di scansione", - "enabled": "Modalità di scansione abilitata", + "editor_label": "", "filter_selected_camera": "", "show_trigger_status": "Mostra bordo pulsante quando attivato", "untrigger_seconds": "Reimposta la vista ai valori predefiniti dopo aver annullato l'attivazione" diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 99b8ebc0..87dcb442 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -85,6 +85,12 @@ "triggers": { "editor_label": "Opções de acionamento", "entities": "Acionar a partir de outras entidades", + "events": { + "clips": "", + "editor_label": "", + "events": "", + "snapshots": "" + }, "motion": "Acionar detectando automaticamente o sensor de movimento", "occupancy": "Acionar detectando automaticamente o sensor de ocupação" }, @@ -393,7 +399,7 @@ "default": "Visualização padrão", "interaction_seconds": "", "reset_after_interaction": "", - "scan": { + "triggers": { "actions": { "editor_label": "", "interaction_mode": "", @@ -404,7 +410,9 @@ }, "trigger": "", "triggers": { + "default": "", "live": "", + "media": "", "none": "" }, "untrigger": "", @@ -413,8 +421,7 @@ "none": "" } }, - "editor_label": "Modo scan", - "enabled": "Modo scan ativado", + "editor_label": "", "filter_selected_camera": "", "show_trigger_status": "Pulsar borda quando acionado", "untrigger_seconds": "Segundos após a mudar para o estado inativo para desacionar" diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 10686bba..0ef522bc 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -85,6 +85,12 @@ "triggers": { "editor_label": "Opções de activação", "entities": "Activar a partir de outras entidades", + "events": { + "editor_label": "", + "events": "", + "clips": "", + "snapshots": "" + }, "motion": "Activar detectando automaticamente o sensor de movimento", "occupancy": "Activar detectando automaticamente o sensor de ocupação" }, @@ -383,7 +389,7 @@ "default": "Visualização padrão", "interaction_seconds": "", "reset_after_interaction": "", - "scan": { + "triggers": { "actions": { "editor_label": "", "interaction_mode": "", @@ -394,7 +400,9 @@ }, "trigger": "", "triggers": { + "default": "", "live": "", + "media": "", "none": "" }, "untrigger": "", @@ -403,8 +411,7 @@ "none": "" } }, - "editor_label": "Modo scan", - "enabled": "Modo scan ativado", + "editor_label": "", "filter_selected_camera": "", "show_trigger_status": "Exibir estado do gatilho", "untrigger_seconds": "Segundos após a mudar para o estado inativo para desacionar" diff --git a/src/utils/ha/index.ts b/src/utils/ha/index.ts index b8d46426..3b6e18b2 100644 --- a/src/utils/ha/index.ts +++ b/src/utils/ha/index.ts @@ -1,4 +1,8 @@ -import { computeDomain, computeStateDomain, HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { + computeDomain, + computeStateDomain, + HomeAssistant, +} from '@dermotduffy/custom-card-helpers'; import { HassEntity, MessageBase } from 'home-assistant-js-websocket'; import { StyleInfo } from 'lit/directives/style-map.js'; import { ZodSchema } from 'zod'; @@ -13,6 +17,12 @@ import { } from '../../types.js'; import { domainIcon } from '../icons/domain-icon.js'; import { getParseErrorKeys } from '../zod.js'; +import { + HAStateChangeFromTo, + haStateChangeTriggerResponseSchema, + SubscriptionCallback, + SubscriptionUnsubscribe, +} from './types.js'; /** * Make a HomeAssistant websocket request. May throw. @@ -103,7 +113,7 @@ interface HassStateDifference { * strings only, firstOnly: whether or not to get the first difference only. * @returns An array of HassStateDifference objects. */ -export function getHassDifferences( +function getHassDifferences( newHass: HomeAssistant | undefined | null, oldHass: HomeAssistant | undefined | null, entities: string[] | null, @@ -326,11 +336,11 @@ export const sideLoadHomeAssistantElements = async (): Promise => { /** * Determine if a given state qualifies as 'triggered'. - * @param state The HASSEntity. + * @param state The HA entity state string. * @returns `true` if triggered, `false` otherwise. */ -export const isTriggeredState = (state?: HassEntity): boolean => { - return !!state && ['on', 'open'].includes(state.state); +export const isTriggeredState = (state?: string): boolean => { + return !!state && ['on', 'open'].includes(state); }; /** @@ -390,3 +400,53 @@ export const hasHAConnectionStateChanged = ( ): boolean => { return oldHass?.connected !== newHass?.connected; }; + +/** + * Subscribe to a HA trigger + * @param hass The HA object. + * @param callback The callback to call with the data. + * @param options Parameters to the trigger, see: + * https://www.home-assistant.io/docs/automation/trigger/#state-trigger + * @returns A callback to unsubscribe. + */ +export const subscribeToTrigger = async ( + hass: HomeAssistant, + callback: SubscriptionCallback, + options?: { + entityID?: string | string[]; + platform?: string; + topic?: string; + payload?: string; + valueTemplate?: string; + stateOnly?: boolean; + }, +): Promise => { + return await hass.connection.subscribeMessage(callback, { + type: 'subscribe_trigger', + trigger: { + ...(options?.platform && { platform: options.platform }), + ...(options?.entityID && { entity_id: options.entityID }), + ...(options?.topic && { topic: options.topic }), + ...(options?.payload && { payload: options.payload }), + ...(options?.valueTemplate && { value_template: options.valueTemplate }), + ...(options?.stateOnly && { + from: null, + to: null, + }), + }, + }); +}; + +/** + * Parse a state change trigger response. + * @param data The raw data. + * @returns A HAStateChangeFromTo object. + */ +export const parseStateChangeTrigger = (data: unknown): HAStateChangeFromTo | null => { + const parseResult = haStateChangeTriggerResponseSchema.safeParse(data); + if (!parseResult.success) { + console.warn('Ignoring unparseable HA state change', data); + return null; + } + return parseResult.data.variables.trigger; +}; diff --git a/src/utils/ha/types.ts b/src/utils/ha/types.ts new file mode 100644 index 00000000..d1c54943 --- /dev/null +++ b/src/utils/ha/types.ts @@ -0,0 +1,21 @@ +import { z } from 'zod'; + +export type SubscriptionUnsubscribe = () => Promise; +export type SubscriptionCallback = (data: unknown) => void; + +const haStateChangeSchema = z.object({ + entity_id: z.string(), + state: z.string(), +}); + +const haStateChangeFromToSchema = z.object({ + from_state: haStateChangeSchema, + to_state: haStateChangeSchema, +}); +export type HAStateChangeFromTo = z.infer; + +export const haStateChangeTriggerResponseSchema = z.object({ + variables: z.object({ + trigger: haStateChangeFromToSchema, + }), +}); diff --git a/src/utils/initializer/initializer.ts b/src/utils/initializer/initializer.ts index ef3ea8b7..3ab033a9 100644 --- a/src/utils/initializer/initializer.ts +++ b/src/utils/initializer/initializer.ts @@ -22,7 +22,7 @@ export class Initializer { ): Promise { const results = await allPromises( Object.entries(aspects), - async ([aspect, options]) => this.initializeIfNecessary(aspect, options), + async ([aspect, options]) => await this.initializeIfNecessary(aspect, options), ); return results.every(Boolean); } diff --git a/src/utils/media-to-view.ts b/src/utils/media-to-view.ts index 4383b29c..e940c7c4 100644 --- a/src/utils/media-to-view.ts +++ b/src/utils/media-to-view.ts @@ -27,6 +27,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( eventsMediaType?: ClipsOrSnapshotsOrAll; targetView?: FrigateCardView; select?: ResultSelectType; + useCache?: boolean; }, ): Promise => { const cameraIDs = options?.allCameras @@ -52,6 +53,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( { targetView: options?.targetView, select: options?.select, + useCache: options?.useCache, }, ) )?.dispatchChangeEvent(element); @@ -93,6 +95,7 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( allCameras?: boolean; targetView?: FrigateCardView; select?: ResultSelectType; + useCache?: boolean; }, ): Promise => { const cameraIDs = options?.allCameras @@ -120,6 +123,7 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( { targetView: options?.targetView, select: options?.select, + useCache: options?.useCache, }, ) )?.dispatchChangeEvent(element); @@ -147,6 +151,7 @@ export const executeMediaQueryForView = async ( targetView?: FrigateCardView; targetTime?: Date; select?: ResultSelectType; + useCache?: boolean; }, ): Promise => { const queries = query.getQueries(); @@ -154,7 +159,9 @@ export const executeMediaQueryForView = async ( return null; } - const mediaArray = await cameraManager.executeMediaQueries(queries); + const mediaArray = await cameraManager.executeMediaQueries(queries, { + useCache: options?.useCache, + }); if (!mediaArray) { return null; } @@ -194,6 +201,7 @@ export const executeMediaQueryForViewWithErrorDispatching = async ( targetView?: FrigateCardView; targetTime?: Date; select?: ResultSelectType; + useCache?: boolean; }, ): Promise => { try { @@ -202,6 +210,7 @@ export const executeMediaQueryForViewWithErrorDispatching = async ( targetView: options?.targetView, targetTime: options?.targetTime, select: options?.select, + useCache: options?.useCache, }); } catch (e: unknown) { errorToConsole(e as Error); diff --git a/tests/camera-manager/browse-media/camera.test.ts b/tests/camera-manager/browse-media/camera.test.ts new file mode 100644 index 00000000..c7905f24 --- /dev/null +++ b/tests/camera-manager/browse-media/camera.test.ts @@ -0,0 +1,37 @@ +import { describe, expect, it } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { BrowseMediaCamera } from '../../../src/camera-manager/browse-media/camera'; +import { CameraManagerEngine } from '../../../src/camera-manager/engine'; +import { EntityRegistryManager } from '../../../src/utils/ha/entity-registry'; +import { Entity } from '../../../src/utils/ha/entity-registry/types'; +import { createCameraConfig, createHASS } from '../../test-utils'; + +describe('BrowseMediaCamera', () => { + describe('should initialize', () => { + it('without a camera_entity', async () => { + const camera = new BrowseMediaCamera( + createCameraConfig(), + mock(), + ); + + expect( + async () => await camera.initialize(createHASS(), mock()), + ).rejects.toThrowError(/Could not find camera entity/); + }); + + it('with a camera_entity', async () => { + const camera = new BrowseMediaCamera( + createCameraConfig({ + camera_entity: 'camera.foo', + }), + mock(), + ); + const entityRegistryManager = mock(); + const entity = mock(); + entityRegistryManager.getEntity.mockResolvedValue(entity); + + expect(await camera.initialize(createHASS(), entityRegistryManager)).toBe(camera); + expect(camera.getEntity()).toBe(entity); + }); + }); +}); diff --git a/tests/camera-manager/camera.test.ts b/tests/camera-manager/camera.test.ts index 358203d8..fc14557d 100644 --- a/tests/camera-manager/camera.test.ts +++ b/tests/camera-manager/camera.test.ts @@ -1,57 +1,170 @@ -import { describe, expect, it } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; import { Camera } from '../../src/camera-manager/camera.js'; import { GenericCameraManagerEngine } from '../../src/camera-manager/generic/engine-generic.js'; -import { createCameraCapabilities, createCameraConfig } from '../test-utils.js'; +import { EntityRegistryManager } from '../../src/utils/ha/entity-registry/index.js'; +import { + callHASubscribeMessageHandler, + createCameraCapabilities, + createCameraConfig, + createHASS, +} from '../test-utils.js'; describe('Camera', () => { it('should get config', async () => { const config = createCameraConfig(); - const camera = new Camera( - config, - new GenericCameraManagerEngine(), - createCameraCapabilities(), - ); + const camera = new Camera(config, new GenericCameraManagerEngine()); expect(camera.getConfig()).toBe(config); }); - it('should get capabilities', async () => { - const capabilities = createCameraCapabilities(); - const camera = new Camera( - createCameraConfig(), - new GenericCameraManagerEngine(), - capabilities, - ); - expect(camera.getCapabilities()).toBe(capabilities); + describe('should get capabilities', async () => { + it('when populated', async () => { + const capabilities = createCameraCapabilities(); + const camera = new Camera(createCameraConfig(), new GenericCameraManagerEngine(), { + capabilities: capabilities, + }); + expect(camera.getCapabilities()).toBe(capabilities); + }); + + it('when unpopulated', async () => { + const camera = new Camera(createCameraConfig(), new GenericCameraManagerEngine()); + expect(camera.getCapabilities()).toBeNull(); + }); }); it('should get engine', async () => { const engine = new GenericCameraManagerEngine(); - const camera = new Camera(createCameraConfig(), engine, createCameraCapabilities()); + const camera = new Camera(createCameraConfig(), engine); expect(camera.getEngine()).toBe(engine); }); it('should set and get id', async () => { - const config = createCameraConfig(); - const camera = new Camera( - config, - new GenericCameraManagerEngine(), - createCameraCapabilities(), - ); + const camera = new Camera(createCameraConfig(), new GenericCameraManagerEngine()); camera.setID('foo'); expect(camera.getID()).toBe('foo'); expect(camera.getConfig().id).toBe('foo'); }); it('should throw without id', async () => { - const config = createCameraConfig(); - const camera = new Camera( - config, - new GenericCameraManagerEngine(), - createCameraCapabilities(), - ); + const camera = new Camera(createCameraConfig(), new GenericCameraManagerEngine()); expect(() => camera.getID()).toThrowError( 'Could not determine camera id for the following ' + "camera, may need to set 'id' parameter manually", ); }); + + it('should initialize and destroy', async () => { + const camera = new Camera( + createCameraConfig({ + triggers: { + entities: ['camera.foo'], + }, + }), + new GenericCameraManagerEngine(), + ); + const hass = createHASS(); + const unsubcribeCallback = vi.fn(); + + vi.mocked(hass.connection.subscribeMessage).mockResolvedValue(unsubcribeCallback); + + await camera.initialize(hass, mock()); + + expect(hass.connection.subscribeMessage).toBeCalledWith( + expect.anything(), + expect.objectContaining({ + type: 'subscribe_trigger', + trigger: { + entity_id: ['camera.foo'], + platform: 'state', + from: null, + to: null, + }, + }), + ); + expect(unsubcribeCallback).not.toBeCalled(); + + await camera.destroy(); + expect(unsubcribeCallback).toBeCalled(); + }); + + it('should not subscribe without trigger entities', async () => { + const camera = new Camera(createCameraConfig(), new GenericCameraManagerEngine()); + const hass = createHASS(); + + await camera.initialize(hass, mock()); + expect(hass.connection.subscribeMessage).not.toBeCalled(); + }); + + describe('should handle trigger state changes', () => { + beforeEach(() => { + vi.restoreAllMocks(); + }); + + it('when malformed', async () => { + vi.spyOn(global.console, 'warn').mockReturnValue(undefined); + + const eventCallback = vi.fn(); + const camera = new Camera( + createCameraConfig({ + triggers: { + entities: ['camera.foo'], + }, + }), + new GenericCameraManagerEngine(), + { eventCallback: eventCallback }, + ); + + const hass = createHASS(); + await camera.initialize(hass, mock()); + + callHASubscribeMessageHandler(hass, 'MALFORMED_DATA'); + + expect(eventCallback).not.toBeCalled(); + }); + + it.each([ + ['off' as const, 'on' as const, 'new' as const], + ['on' as const, 'off' as const, 'end' as const], + ])( + 'from %s to %s', + async (stateFrom: string, stateTo: string, eventType: 'new' | 'end') => { + vi.spyOn(global.console, 'warn').mockReturnValue(undefined); + + const eventCallback = vi.fn(); + const camera = new Camera( + createCameraConfig({ + id: 'camera_1', + triggers: { + entities: ['binary_sensor.foo'], + }, + }), + new GenericCameraManagerEngine(), + { eventCallback: eventCallback }, + ); + + const hass = createHASS(); + await camera.initialize(hass, mock()); + + callHASubscribeMessageHandler(hass, { + variables: { + trigger: { + from_state: { + entity_id: 'binary_sensor.foo', + state: stateFrom, + }, + to_state: { + entity_id: 'binary_sensor.foo', + state: stateTo, + }, + }, + }, + }); + + expect(eventCallback).toBeCalledWith({ + cameraID: 'camera_1', + type: eventType, + }); + }, + ); + }); }); diff --git a/tests/camera-manager/frigate/camera.test.ts b/tests/camera-manager/frigate/camera.test.ts new file mode 100644 index 00000000..f9698fcf --- /dev/null +++ b/tests/camera-manager/frigate/camera.test.ts @@ -0,0 +1,965 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { CameraManagerEngine } from '../../../src/camera-manager/engine'; +import { FrigateCamera } from '../../../src/camera-manager/frigate/camera'; +import { getPTZInfo } from '../../../src/camera-manager/frigate/requests'; +import { + FrigateEventChange, + FrigateEventChangeTriggerResponse, + FrigateEventChangeType, +} from '../../../src/camera-manager/frigate/types'; +import { CameraTriggerEventType } from '../../../src/config/types'; +import { EntityRegistryManager } from '../../../src/utils/ha/entity-registry'; +import { Entity } from '../../../src/utils/ha/entity-registry/types'; +import { + callHASubscribeMessageHandler, + createCameraConfig, + createHASS, + createRegistryEntity, +} from '../../test-utils'; + +vi.mock('../../../src/camera-manager/frigate/requests'); + +const createFrigateEventChangeTrigger = ( + type: FrigateEventChangeType, + before: FrigateEventChange, + after: FrigateEventChange, +): FrigateEventChangeTriggerResponse => { + return { + variables: { + trigger: { + payload_json: { + before: before, + after: after, + type: type, + }, + }, + }, + }; +}; + +describe('FrigateCamera', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.mocked(getPTZInfo).mockResolvedValue({}); + }); + + describe('should initialize config', () => { + describe('should detect camera name', () => { + it('without a camera_entity', async () => { + const config = createCameraConfig(); + const camera = new FrigateCamera(config, mock()); + const beforeConfig = { ...config }; + + await camera.initialize(createHASS(), mock()); + + expect(beforeConfig).toEqual(camera.getConfig()); + }); + + it('with a missing camera_entity', async () => { + const camera = new FrigateCamera( + createCameraConfig({ + camera_entity: 'camera.not_here', + }), + mock(), + ); + const entityRegistryManager = mock(); + entityRegistryManager.getEntity.mockRejectedValue(null); + + expect( + async () => await camera.initialize(createHASS(), entityRegistryManager), + ).rejects.toThrowError(/Could not find camera entity/); + }); + + it('with a valid camera_entity', async () => { + const camera = new FrigateCamera( + createCameraConfig({ + camera_entity: 'camera.front_door', + }), + mock(), + ); + const entityRegistryManager = mock(); + const entity = createRegistryEntity({ + unique_id: '8c4e19d258359e82bc0cf9d47b021c46:camera:fnt_dr', + platform: 'frigate', + }); + entityRegistryManager.getEntity.mockResolvedValue(entity); + + await camera.initialize(createHASS(), entityRegistryManager); + + expect(camera.getConfig().frigate.camera_name).toBe('fnt_dr'); + }); + + it('with a camera_entity without camera_name match', async () => { + const camera = new FrigateCamera( + createCameraConfig({ + camera_entity: 'camera.front_door', + }), + mock(), + ); + const entityRegistryManager = mock(); + const entity = createRegistryEntity({ + unique_id: '8c4e19d258359e82bc0cf9d47b021c46:WRONG:fnt_dr', + platform: 'frigate', + }); + entityRegistryManager.getEntity.mockResolvedValue(entity); + + await camera.initialize(createHASS(), entityRegistryManager); + + expect(camera.getConfig().frigate.camera_name).toBeUndefined(); + }); + + it('with a camera_entity without platform match', async () => { + const camera = new FrigateCamera( + createCameraConfig({ + camera_entity: 'camera.front_door', + }), + mock(), + ); + const entityRegistryManager = mock(); + const entity = createRegistryEntity({ + unique_id: '8c4e19d258359e82bc0cf9d47b021c46:camera:fnt_dr', + platform: 'something_else', + }); + entityRegistryManager.getEntity.mockResolvedValue(entity); + + await camera.initialize(createHASS(), entityRegistryManager); + + expect(camera.getConfig().frigate.camera_name).toBeUndefined(); + }); + }); + }); + + describe('should detect capabilities', () => { + const nonBirdseyeBaseCapabilities = { + canFavoriteEvents: true, + canFavoriteRecordings: true, + canSeek: true, + supportsClips: true, + supportsSnapshots: true, + supportsRecordings: true, + supportsTimeline: true, + }; + + it('basic non-birdseye', async () => { + const camera = new FrigateCamera( + createCameraConfig(), + mock(), + ); + + await camera.initialize(createHASS(), mock()); + + expect(camera.getCapabilities()).toEqual(nonBirdseyeBaseCapabilities); + }); + + it('basic birdseye', async () => { + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + camera_name: 'birdseye', + }, + }), + mock(), + ); + + await camera.initialize(createHASS(), mock()); + + expect(camera.getCapabilities()).toEqual({ + ...nonBirdseyeBaseCapabilities, + canFavoriteEvents: false, + canFavoriteRecordings: false, + supportsClips: false, + supportsSnapshots: false, + supportsRecordings: false, + supportsTimeline: false, + }); + }); + + describe('with ptz', () => { + it('when getPTZInfo call fails', async () => { + const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined); + + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + camera_name: 'front_door', + }, + }), + mock(), + ); + vi.mocked(getPTZInfo).mockRejectedValue(new Error()); + await camera.initialize(createHASS(), mock()); + + expect(camera.getCapabilities()).toEqual({ + ...nonBirdseyeBaseCapabilities, + }); + expect(consoleSpy).toBeCalled(); + }); + + it('when getPTZInfo call succeeds with continuous motion', async () => { + vi.spyOn(global.console, 'warn').mockReturnValue(undefined); + + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + camera_name: 'front_door', + }, + }), + mock(), + ); + vi.mocked(getPTZInfo).mockResolvedValue({ + features: ['pt', 'zoom'], + name: 'front_door', + presets: ['preset01'], + }); + await camera.initialize(createHASS(), mock()); + + expect(camera.getCapabilities()).toEqual({ + ...nonBirdseyeBaseCapabilities, + ptz: { + panTilt: ['continuous'], + zoom: ['continuous'], + presets: ['preset01'], + }, + }); + }); + + it('when getPTZInfo call succeeds with relative motion', async () => { + vi.spyOn(global.console, 'warn').mockReturnValue(undefined); + + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + camera_name: 'front_door', + }, + }), + mock(), + ); + vi.mocked(getPTZInfo).mockResolvedValue({ + features: ['pt-r', 'zoom-r'], + name: 'front_door', + presets: ['preset01'], + }); + await camera.initialize(createHASS(), mock()); + + expect(camera.getCapabilities()).toEqual({ + ...nonBirdseyeBaseCapabilities, + ptz: { + panTilt: ['relative'], + zoom: ['relative'], + presets: ['preset01'], + }, + }); + }); + }); + }); + + describe('should handle events', () => { + it('should subscribe', async () => { + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + client_id: 'CLIENT_ID', + camera_name: 'CAMERA', + }, + }), + mock(), + ); + const hass = createHASS(); + + await camera.initialize(hass, mock()); + + expect(hass.connection.subscribeMessage).toBeCalledWith(expect.anything(), { + type: 'subscribe_trigger', + trigger: { + platform: 'mqtt', + topic: `CLIENT_ID/events`, + payload: 'CAMERA', + value_template: '{{ value_json.after.camera }}', + }, + }); + }); + + it('should not subscribe with no trigger events', async () => { + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + client_id: 'CLIENT_ID', + camera_name: 'CAMERA', + }, + triggers: { + events: [], + }, + }), + mock(), + ); + const hass = createHASS(); + + await camera.initialize(hass, mock()); + + expect(hass.connection.subscribeMessage).not.toBeCalled(); + }); + + it('should not subscribe with no camera name', async () => { + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + client_id: 'CLIENT_ID', + }, + }), + mock(), + ); + const hass = createHASS(); + + await camera.initialize(hass, mock()); + + expect(hass.connection.subscribeMessage).not.toBeCalled(); + }); + + it('should unsubscribe on destroy', async () => { + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { camera_name: 'front_door' }, + }), + mock(), + ); + const hass = createHASS(); + const unsubscribeCallback = vi.fn(); + vi.mocked(hass.connection.subscribeMessage).mockResolvedValue(unsubscribeCallback); + + await camera.initialize(hass, mock()); + expect(unsubscribeCallback).not.toBeCalled(); + + await camera.destroy(); + expect(unsubscribeCallback).toBeCalled(); + }); + + describe('should call handler correctly', () => { + it('with malformed Frigate event', async () => { + const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined); + + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { camera_name: 'front_door' }, + }), + mock(), + ); + + const hass = createHASS(); + await camera.initialize(hass, mock()); + + callHASubscribeMessageHandler(hass, 'GARBAGE'); + + expect(consoleSpy).toBeCalledWith( + 'Ignoring unparseable Frigate event', + 'GARBAGE', + ); + }); + + it('with wrong camera', async () => { + const eventCallback = vi.fn(); + const camera = new FrigateCamera( + createCameraConfig({ + id: 'CAMERA_1', + frigate: { + camera_name: 'camera.front_door', + }, + }), + mock(), + { + eventCallback: eventCallback, + }, + ); + + const hass = createHASS(); + await camera.initialize(hass, mock()); + + callHASubscribeMessageHandler( + hass, + createFrigateEventChangeTrigger( + 'new', + { + camera: 'camera.back_door', + snapshot: null, + has_clip: false, + has_snapshot: false, + label: 'person', + current_zones: [], + }, + { + camera: 'camera.back_door', + snapshot: null, + has_clip: false, + has_snapshot: true, + label: 'person', + current_zones: [], + }, + ), + ); + + expect(eventCallback).not.toBeCalled(); + }); + + describe('should handle event type correctly', () => { + it.each([ + [ + ['events' as const, 'snapshots' as const, 'clips' as const], + false, + false, + true, + ], + [ + ['events' as const, 'snapshots' as const, 'clips' as const], + false, + true, + true, + ], + [ + ['events' as const, 'snapshots' as const, 'clips' as const], + true, + false, + true, + ], + [ + ['events' as const, 'snapshots' as const, 'clips' as const], + true, + true, + true, + ], + + [['events' as const, 'snapshots' as const], false, false, true], + [['events' as const, 'snapshots' as const], false, true, true], + [['events' as const, 'snapshots' as const], true, false, true], + [['events' as const, 'snapshots' as const], true, true, true], + + [['events' as const, 'clips' as const], false, false, true], + [['events' as const, 'clips' as const], false, true, true], + [['events' as const, 'clips' as const], true, false, true], + [['events' as const, 'clips' as const], true, true, true], + + [['events' as const], false, false, true], + [['events' as const], false, true, true], + [['events' as const], true, false, true], + [['events' as const], true, true, true], + + [['snapshots' as const, 'clips' as const], false, false, false], + [['snapshots' as const, 'clips' as const], false, true, true], + [['snapshots' as const, 'clips' as const], true, false, true], + [['snapshots' as const, 'clips' as const], true, true, true], + + [['snapshots' as const], false, false, false], + [['snapshots' as const], false, true, false], + [['snapshots' as const], true, false, true], + [['snapshots' as const], true, true, true], + + [['clips' as const], false, false, false], + [['clips' as const], false, true, true], + [['clips' as const], true, false, false], + [['clips' as const], true, true, true], + ])( + 'with events %s when snapshot %s and clip %s', + async ( + events: CameraTriggerEventType[], + hasSnapshot: boolean, + hasClip: boolean, + call: boolean, + ) => { + const eventCallback = vi.fn(); + const camera = new FrigateCamera( + createCameraConfig({ + id: 'CAMERA_1', + frigate: { + camera_name: 'camera.front_door', + }, + triggers: { + events: events, + }, + }), + mock(), + { + eventCallback: eventCallback, + }, + ); + + const hass = createHASS(); + await camera.initialize(hass, mock()); + + callHASubscribeMessageHandler( + hass, + createFrigateEventChangeTrigger( + 'new', + { + camera: 'camera.front_door', + snapshot: null, + has_clip: false, + has_snapshot: false, + label: 'person', + current_zones: [], + }, + { + camera: 'camera.front_door', + snapshot: null, + has_clip: hasClip, + has_snapshot: hasSnapshot, + label: 'person', + current_zones: [], + }, + ), + ); + + if (call) { + expect(eventCallback).toBeCalledWith({ + type: 'new', + cameraID: 'CAMERA_1', + clip: hasClip && events.includes('clips'), + snapshot: hasSnapshot && events.includes('snapshots'), + fidelity: 'high', + }); + } else { + expect(eventCallback).not.toBeCalled(); + } + }, + ); + }); + + describe('should handle zones correctly', () => { + it.each([ + ['has no zone', [], false], + ['has mismatched zone', ['fence'], false], + ['has matching zone', ['front_steps'], true], + ])('%s', async (_name: string, zones: string[], call: boolean) => { + const eventCallback = vi.fn(); + const camera = new FrigateCamera( + createCameraConfig({ + id: 'CAMERA_1', + frigate: { + camera_name: 'camera.front_door', + zones: ['front_steps'], + }, + }), + mock(), + { + eventCallback: eventCallback, + }, + ); + + const hass = createHASS(); + await camera.initialize(hass, mock()); + + callHASubscribeMessageHandler( + hass, + createFrigateEventChangeTrigger( + 'new', + { + camera: 'camera.front_door', + snapshot: null, + has_clip: false, + has_snapshot: false, + label: 'person', + current_zones: [], + }, + { + camera: 'camera.front_door', + snapshot: null, + has_clip: false, + has_snapshot: true, + label: 'person', + current_zones: zones, + }, + ), + ); + + expect(eventCallback).toHaveBeenCalledTimes(call ? 1 : 0); + }); + }); + + describe('should handle labels correctly', () => { + it.each([ + ['has mismatched label', 'car', false], + ['has matching label', 'person', true], + ])('%s', async (_name: string, label: string, call: boolean) => { + const eventCallback = vi.fn(); + const camera = new FrigateCamera( + createCameraConfig({ + id: 'CAMERA_1', + frigate: { + camera_name: 'camera.front_door', + labels: ['person'], + }, + }), + mock(), + { + eventCallback: eventCallback, + }, + ); + + const hass = createHASS(); + await camera.initialize(hass, mock()); + + callHASubscribeMessageHandler( + hass, + createFrigateEventChangeTrigger( + 'new', + { + camera: 'camera.front_door', + snapshot: null, + has_clip: false, + has_snapshot: false, + // Even new events appear to have the event label in the + // 'before' dictionary. + label: label, + current_zones: [], + }, + { + camera: 'camera.front_door', + snapshot: null, + has_clip: false, + has_snapshot: true, + label: label, + current_zones: [], + }, + ), + ); + + expect(eventCallback).toHaveBeenCalledTimes(call ? 1 : 0); + }); + }); + }); + }); + + describe('should handle triggers', () => { + const cameraEntity: Partial = { + config_entry_id: 'config_entry_id', + }; + + const occupancySensorEntityAll: Partial = { + config_entry_id: 'config_entry_id', + disabled_by: null, + entity_id: 'binary_sensor.foo', + unique_id: '8c4e19d258359e82bc0cf9d47b021c46:occupancy_sensor:front_door_all', + }; + + const motionSensorEntity: Partial = { + config_entry_id: 'config_entry_id', + disabled_by: null, + entity_id: 'binary_sensor.foo', + unique_id: '8c4e19d258359e82bc0cf9d47b021c46:motion_sensor:front_door', + }; + + describe('should detect motion sensor', () => { + it('without a camera name', async () => { + const entityRegistryManager = mock(); + entityRegistryManager.getEntity.mockResolvedValue( + createRegistryEntity(cameraEntity), + ); + entityRegistryManager.getMatchingEntities.mockResolvedValue([ + createRegistryEntity(motionSensorEntity), + ]); + const camera = new FrigateCamera( + createCameraConfig({ + triggers: { + motion: true, + }, + }), + mock(), + ); + const hass = createHASS(); + await camera.initialize(hass, entityRegistryManager); + + expect(camera.getConfig().triggers.entities).toEqual([]); + }); + + it('with camera entity and name', async () => { + const entityRegistryManager = mock(); + entityRegistryManager.getEntity.mockResolvedValue( + createRegistryEntity(cameraEntity), + ); + entityRegistryManager.getMatchingEntities.mockResolvedValue([ + createRegistryEntity(motionSensorEntity), + ]); + const camera = new FrigateCamera( + createCameraConfig({ + camera_entity: 'camera.front_door', + frigate: { + camera_name: 'front_door', + }, + triggers: { + motion: true, + }, + }), + mock(), + ); + const hass = createHASS(); + await camera.initialize(hass, entityRegistryManager); + + expect(camera.getConfig().triggers.entities).toEqual(['binary_sensor.foo']); + }); + + it('with matching entity', async () => { + const entityRegistryManager = mock(); + entityRegistryManager.getEntity.mockResolvedValue( + createRegistryEntity(cameraEntity), + ); + entityRegistryManager.getMatchingEntities.mockResolvedValue([ + createRegistryEntity(motionSensorEntity), + ]); + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + camera_name: 'front_door', + }, + triggers: { + motion: true, + }, + }), + mock(), + ); + const hass = createHASS(); + await camera.initialize(hass, entityRegistryManager); + + expect(camera.getConfig().triggers.entities).toEqual(['binary_sensor.foo']); + }); + + it('without matching entity', async () => { + const entityRegistryManager = mock(); + entityRegistryManager.getEntity.mockResolvedValue( + createRegistryEntity(cameraEntity), + ); + entityRegistryManager.getMatchingEntities.mockResolvedValue([]); + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + camera_name: 'front_door', + }, + triggers: { + motion: true, + }, + }), + mock(), + ); + const hass = createHASS(); + await camera.initialize(hass, entityRegistryManager); + + expect(camera.getConfig().triggers.entities).toEqual([]); + }); + }); + + describe('should detect occupancy sensor', () => { + it('without a camera name', async () => { + const entityRegistryManager = mock(); + entityRegistryManager.getEntity.mockResolvedValue( + createRegistryEntity(cameraEntity), + ); + entityRegistryManager.getMatchingEntities.mockResolvedValue([ + createRegistryEntity(occupancySensorEntityAll), + ]); + const camera = new FrigateCamera( + createCameraConfig({ + triggers: { + occupancy: true, + }, + }), + mock(), + ); + const hass = createHASS(); + await camera.initialize(hass, entityRegistryManager); + + expect(camera.getConfig().triggers.entities).toEqual([]); + }); + + it('without a camera name but with occupancy trigger', async () => { + const entityRegistryManager = mock(); + entityRegistryManager.getEntity.mockResolvedValue( + createRegistryEntity(cameraEntity), + ); + entityRegistryManager.getMatchingEntities.mockResolvedValue([ + createRegistryEntity(occupancySensorEntityAll), + ]); + const camera = new FrigateCamera( + createCameraConfig({ + triggers: { + occupancy: true, + }, + }), + mock(), + ); + const hass = createHASS(); + await camera.initialize(hass, entityRegistryManager); + + expect(camera.getConfig().triggers.entities).toEqual([]); + }); + + it('with matching entity', async () => { + const entityRegistryManager = mock(); + entityRegistryManager.getEntity.mockResolvedValue( + createRegistryEntity(cameraEntity), + ); + entityRegistryManager.getMatchingEntities.mockResolvedValue([ + createRegistryEntity(occupancySensorEntityAll), + ]); + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + camera_name: 'front_door', + }, + triggers: { + occupancy: true, + }, + }), + mock(), + ); + const hass = createHASS(); + await camera.initialize(hass, entityRegistryManager); + + expect(camera.getConfig().triggers.entities).toEqual(['binary_sensor.foo']); + }); + + it('without matching entity', async () => { + const entityRegistryManager = mock(); + entityRegistryManager.getEntity.mockResolvedValue( + createRegistryEntity(cameraEntity), + ); + entityRegistryManager.getMatchingEntities.mockResolvedValue([]); + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + camera_name: 'front_door', + }, + triggers: { + occupancy: true, + }, + }), + mock(), + ); + const hass = createHASS(); + await camera.initialize(hass, entityRegistryManager); + + expect(camera.getConfig().triggers.entities).toEqual([]); + }); + + it('with zones', async () => { + const entityRegistryManager = mock(); + entityRegistryManager.getEntity.mockResolvedValue( + createRegistryEntity(cameraEntity), + ); + entityRegistryManager.getMatchingEntities.mockResolvedValue([ + createRegistryEntity({ + ...occupancySensorEntityAll, + unique_id: '8c4e19d258359e82bc0cf9d47b021c46:occupancy_sensor:zone_all', + }), + ]); + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + camera_name: 'front_door', + zones: ['zone'], + }, + triggers: { + occupancy: true, + }, + }), + mock(), + ); + const hass = createHASS(); + await camera.initialize(hass, entityRegistryManager); + + expect(camera.getConfig().triggers.entities).toEqual(['binary_sensor.foo']); + }); + + it('with labels', async () => { + const entityRegistryManager = mock(); + entityRegistryManager.getEntity.mockResolvedValue( + createRegistryEntity(cameraEntity), + ); + entityRegistryManager.getMatchingEntities.mockResolvedValue([ + createRegistryEntity({ + ...occupancySensorEntityAll, + unique_id: + '8c4e19d258359e82bc0cf9d47b021c46:occupancy_sensor:front_door_car', + }), + ]); + const camera = new FrigateCamera( + createCameraConfig({ + frigate: { + camera_name: 'front_door', + labels: ['car'], + }, + triggers: { + occupancy: true, + }, + }), + mock(), + ); + const hass = createHASS(); + await camera.initialize(hass, entityRegistryManager); + + expect(camera.getConfig().triggers.entities).toEqual(['binary_sensor.foo']); + }); + }); + + it('should filter entities with correct function', async () => { + const entityRegistryManager = mock(); + entityRegistryManager.getEntity.mockResolvedValue( + createRegistryEntity(cameraEntity), + ); + entityRegistryManager.getMatchingEntities.mockResolvedValue([ + createRegistryEntity({ + ...occupancySensorEntityAll, + }), + ]); + const camera = new FrigateCamera( + createCameraConfig({ + camera_entity: 'camera.foo', + triggers: { + occupancy: true, + }, + }), + mock(), + ); + const hass = createHASS(); + await camera.initialize(hass, entityRegistryManager); + + const filterFunc = entityRegistryManager.getMatchingEntities.mock.calls[0][1]; + + expect( + filterFunc( + createRegistryEntity({ + config_entry_id: cameraEntity.config_entry_id, + disabled_by: '', + entity_id: 'binary_sensor.foo', + }), + ), + ).toBeTruthy(); + + expect( + filterFunc( + createRegistryEntity({ + config_entry_id: cameraEntity.config_entry_id, + disabled_by: 'user', + entity_id: 'binary_sensor.foo', + }), + ), + ).toBeFalsy(); + + expect( + filterFunc( + createRegistryEntity({ + config_entry_id: cameraEntity.config_entry_id, + disabled_by: '', + entity_id: 'camera.is_not_a_binary_sensor', + }), + ), + ).toBeFalsy(); + + expect( + filterFunc( + createRegistryEntity({ + config_entry_id: 'not_a_matching_config_entry_id', + disabled_by: '', + entity_id: 'binary_sensor.foo', + }), + ), + ).toBeFalsy(); + }); + }); +}); diff --git a/tests/camera-manager/generic/engine-generic.test.ts b/tests/camera-manager/generic/engine-generic.test.ts index c023c808..f0edd57e 100644 --- a/tests/camera-manager/generic/engine-generic.test.ts +++ b/tests/camera-manager/generic/engine-generic.test.ts @@ -27,7 +27,7 @@ describe('GenericCameraManagerEngine', () => { it('should initialize camera', async () => { const config = createGenericCameraConfig(); - const camera = await createEngine().initializeCamera( + const camera = await createEngine().createCamera( createHASS(), mock(), config, diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts new file mode 100644 index 00000000..642a11e2 --- /dev/null +++ b/tests/camera-manager/manager.test.ts @@ -0,0 +1,1229 @@ +import add from 'date-fns/add'; +import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { Camera } from '../../src/camera-manager/camera'; +import { CameraManagerEngine } from '../../src/camera-manager/engine'; +import { CameraManagerEngineFactory } from '../../src/camera-manager/engine-factory.js'; +import { + CameraManager, + QueryClassifier, + QueryResultClassifier, +} from '../../src/camera-manager/manager'; +import { CameraManagerStore } from '../../src/camera-manager/store'; +import { + CameraEndpoint, + CameraEndpoints, + CameraEndpointsContext, + CameraEvent, + CameraManagerCameraCapabilities, + CameraManagerCameraMetadata, + CameraManagerMediaCapabilities, + Engine, + EventQuery, + EventQueryResults, + MediaMetadata, + QueryResults, + QueryResultsType, + QueryType, +} from '../../src/camera-manager/types'; +import { sortMedia } from '../../src/camera-manager/utils'; +import { CardController } from '../../src/card-controller/controller'; +import { CameraConfig } from '../../src/config/types'; +import { ViewMedia } from '../../src/view/media'; +import { + TestViewMedia, + createCamera, + createCameraCapabilities, + createCameraConfig, + createCardAPI, + createConfig, + createHASS, + generateViewMediaArray, +} from '../test-utils'; + +describe('QueryClassifier', async () => { + it('should classify event query', async () => { + expect(QueryClassifier.isEventQuery({ type: QueryType.Event })).toBeTruthy(); + expect(QueryClassifier.isEventQuery({ type: QueryType.Recording })).toBeFalsy(); + expect( + QueryClassifier.isEventQuery({ type: QueryType.RecordingSegments }), + ).toBeFalsy(); + expect(QueryClassifier.isEventQuery({ type: QueryType.MediaMetadata })).toBeFalsy(); + }); + it('should classify recording query', async () => { + expect(QueryClassifier.isRecordingQuery({ type: QueryType.Event })).toBeFalsy(); + expect(QueryClassifier.isRecordingQuery({ type: QueryType.Recording })).toBeTruthy(); + expect( + QueryClassifier.isRecordingQuery({ type: QueryType.RecordingSegments }), + ).toBeFalsy(); + expect( + QueryClassifier.isRecordingQuery({ type: QueryType.MediaMetadata }), + ).toBeFalsy(); + }); + it('should classify recording segments query', async () => { + expect( + QueryClassifier.isRecordingSegmentsQuery({ type: QueryType.Event }), + ).toBeFalsy(); + expect( + QueryClassifier.isRecordingSegmentsQuery({ type: QueryType.Recording }), + ).toBeFalsy(); + expect( + QueryClassifier.isRecordingSegmentsQuery({ type: QueryType.RecordingSegments }), + ).toBeTruthy(); + expect( + QueryClassifier.isRecordingSegmentsQuery({ type: QueryType.MediaMetadata }), + ).toBeFalsy(); + }); + it('should classify media metadata query', async () => { + expect(QueryClassifier.isMediaMetadataQuery({ type: QueryType.Event })).toBeFalsy(); + expect( + QueryClassifier.isMediaMetadataQuery({ type: QueryType.Recording }), + ).toBeFalsy(); + expect( + QueryClassifier.isMediaMetadataQuery({ type: QueryType.RecordingSegments }), + ).toBeFalsy(); + expect( + QueryClassifier.isMediaMetadataQuery({ type: QueryType.MediaMetadata }), + ).toBeTruthy(); + }); +}); + +describe('QueryResultClassifier', async () => { + const createResults = (type: Partial): QueryResults => { + return { + type: type, + engine: Engine.Generic, + }; + }; + + it('should classify event query result', async () => { + expect( + QueryResultClassifier.isEventQueryResult(createResults(QueryResultsType.Event)), + ).toBeTruthy(); + expect( + QueryResultClassifier.isEventQueryResult( + createResults(QueryResultsType.Recording), + ), + ).toBeFalsy(); + expect( + QueryResultClassifier.isEventQueryResult( + createResults(QueryResultsType.RecordingSegments), + ), + ).toBeFalsy(); + expect( + QueryResultClassifier.isEventQueryResult( + createResults(QueryResultsType.MediaMetadata), + ), + ).toBeFalsy(); + }); + it('should classify recording query result', async () => { + expect( + QueryResultClassifier.isRecordingQueryResult( + createResults(QueryResultsType.Event), + ), + ).toBeFalsy(); + expect( + QueryResultClassifier.isRecordingQueryResult( + createResults(QueryResultsType.Recording), + ), + ).toBeTruthy(); + expect( + QueryResultClassifier.isRecordingQueryResult( + createResults(QueryResultsType.RecordingSegments), + ), + ).toBeFalsy(); + expect( + QueryResultClassifier.isRecordingQueryResult( + createResults(QueryResultsType.MediaMetadata), + ), + ).toBeFalsy(); + }); + it('should classify recording segments query result', async () => { + expect( + QueryResultClassifier.isRecordingSegmentsQueryResult( + createResults(QueryResultsType.Event), + ), + ).toBeFalsy(); + expect( + QueryResultClassifier.isRecordingSegmentsQueryResult( + createResults(QueryResultsType.Recording), + ), + ).toBeFalsy(); + expect( + QueryResultClassifier.isRecordingSegmentsQueryResult( + createResults(QueryResultsType.RecordingSegments), + ), + ).toBeTruthy(); + expect( + QueryResultClassifier.isRecordingSegmentsQueryResult( + createResults(QueryResultsType.MediaMetadata), + ), + ).toBeFalsy(); + }); + it('should classify media metadata query result', async () => { + expect( + QueryResultClassifier.isMediaMetadataQueryResult( + createResults(QueryResultsType.Event), + ), + ).toBeFalsy(); + expect( + QueryResultClassifier.isMediaMetadataQueryResult( + createResults(QueryResultsType.Recording), + ), + ).toBeFalsy(); + expect( + QueryResultClassifier.isMediaMetadataQueryResult( + createResults(QueryResultsType.RecordingSegments), + ), + ).toBeFalsy(); + expect( + QueryResultClassifier.isMediaMetadataQueryResult( + createResults(QueryResultsType.MediaMetadata), + ), + ).toBeTruthy(); + }); +}); + +describe('CameraManager', async () => { + const baseCameraConfig = { + id: 'id', + camera_entity: 'camera.foo', + engine: 'generic', + }; + + const baseEventQuery: EventQuery = { + type: QueryType.Event as const, + cameraIDs: new Set(['id']), + }; + + const baseEventQueryResults: EventQueryResults = { + type: QueryResultsType.Event as const, + engine: Engine.Generic, + }; + + const baseRecordingQuery = { + type: QueryType.Recording as const, + cameraIDs: new Set(['id']), + }; + + const baseRecordingQueryResults = { + type: QueryResultsType.Recording as const, + engine: Engine.Generic, + }; + + const createCameraManager = ( + api: CardController, + engine?: CameraManagerEngine, + cameras: { + config?: CameraConfig; + engineType?: Engine | null; + capabilties?: CameraManagerCameraCapabilities; + }[] = [{}], + factory?: CameraManagerEngineFactory, + ): CameraManager => { + const camerasConfig = cameras?.map( + (camera) => camera.config ?? createCameraConfig({ engine: 'generic' }), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + cameras: camerasConfig, + }), + ); + + const mockFactory = factory ?? mock(); + const mockEngine = engine ?? mock(); + vi.mocked(mockFactory.createEngine).mockResolvedValueOnce(mockEngine); + + for (const camera of cameras ?? []) { + const engineType = + camera.engineType === undefined ? Engine.Generic : camera.engineType; + if (engineType) { + vi.mocked(mockEngine.createCamera).mockResolvedValueOnce( + createCamera( + camera.config ?? createCameraConfig(baseCameraConfig), + mockEngine, + camera.capabilties ?? createCameraCapabilities(), + ), + ); + } + vi.mocked(mockFactory.getEngineForCamera).mockResolvedValueOnce(engineType); + } + + return new CameraManager(api, { factory: mockFactory }); + }; + + it('should reset', async () => { + const store = new CameraManagerStore(); + store.addCamera( + new Camera(createCameraConfig({ id: 'id' }), mock()), + ); + const manager = new CameraManager(createCardAPI(), { store: store }); + + expect(manager.getStore().getCameraCount()).toBe(1); + await manager.reset(); + expect(manager.getStore().getCameraCount()).toBe(0); + }); + + describe('should initialize cameras from config', () => { + beforeEach(() => { + vi.clearAllMocks(); + }); + + it('successfully', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + const manager = createCameraManager(api); + + await manager.initializeCamerasFromConfig(); + expect(manager.getStore().getCameraCount()).toBe(1); + expect(manager.isInitialized()).toBeTruthy(); + }); + + it('without hass', async () => { + const manager = createCameraManager(createCardAPI()); + + await manager.initializeCamerasFromConfig(); + expect(manager.getStore().getCameraCount()).toBe(0); + }); + + it('without a config', async () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(null); + + const manager = createCameraManager(api); + + await manager.initializeCamerasFromConfig(); + expect(manager.getStore().getCameraCount()).toBe(0); + }); + + it('without an id', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const manager = createCameraManager(api, mock(), [ + { + config: createCameraConfig({ + // No id. + engine: 'generic', + }), + }, + ]); + expect(await manager.initializeCamerasFromConfig()).toBeFalsy(); + expect(api.getMessageManager().setErrorIfHigherPriority).toBeCalledWith( + new Error( + 'Could not determine camera id for the following camera, ' + + "may need to set 'id' parameter manually", + ), + ); + }); + + it('with a duplicate id', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const cameraConfig = createCameraConfig({ + id: 'DUPLICATE', + engine: 'generic', + }); + const manager = createCameraManager(api, mock(), [ + { + config: cameraConfig, + }, + { + config: cameraConfig, + }, + ]); + expect(await manager.initializeCamerasFromConfig()).toBeFalsy(); + expect(api.getMessageManager().setErrorIfHigherPriority).toBeCalledWith( + new Error( + 'Duplicate Frigate camera id for the following camera, ' + + "use the 'id' parameter to uniquely identify cameras", + ), + ); + }); + + it('with no engine', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const manager = createCameraManager(api, mock(), [ + { + config: createCameraConfig({ + id: 'id', + }), + engineType: null, + }, + ]); + expect(await manager.initializeCamerasFromConfig()).toBeFalsy(); + expect(api.getMessageManager().setErrorIfHigherPriority).toBeCalledWith( + new Error('Could not determine suitable engine for camera'), + ); + }); + + it('with no cameras', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const manager = createCameraManager(api, mock(), []); + expect(await manager.initializeCamerasFromConfig()).toBeFalsy(); + expect(api.getMessageManager().setErrorIfHigherPriority).toBeCalledWith( + new Error( + 'No visible cameras found, you must configure at least one non-hidden camera', + ), + ); + }); + + it('should pass events to triggers manager', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const factory = mock(); + const manager = createCameraManager( + api, + mock(), + [{}], + factory, + ); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + const triggerCallback = factory.createEngine.mock.calls[0][1]; + + const cameraEvent: CameraEvent = { + cameraID: 'camera', + type: 'new', + }; + triggerCallback?.(cameraEvent); + expect(api.getTriggersManager().handleCameraEvent).toBeCalledWith(cameraEvent); + }); + + describe('should fetch entity list when required', () => { + it('with entity based trigger', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const manager = createCameraManager(api, mock(), [ + { + config: createCameraConfig({ + ...baseCameraConfig, + triggers: { + occupancy: true, + }, + }), + }, + ]); + + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + expect(api.getEntityRegistryManager().fetchEntityList).toBeCalled(); + }); + + it('without entity based trigger', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const manager = createCameraManager(api); + + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + expect(api.getEntityRegistryManager().fetchEntityList).not.toBeCalled(); + }); + }); + + describe('generate default queries', () => { + it.each([ + [ + QueryType.Event as const, + 'generateDefaultEventQuery', + 'generateDefaultEventQueries', + ], + [ + QueryType.Recording as const, + 'generateDefaultRecordingQuery', + 'generateDefaultRecordingQueries', + ], + [ + QueryType.RecordingSegments as const, + 'generateDefaultRecordingSegmentsQuery', + 'generateDefaultRecordingSegmentsQueries', + ], + ])( + 'basic %s', + async ( + queryType: string, + engineMethodName: string, + managerMethodName: string, + ) => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const engine = mock(); + const manager = createCameraManager(api, engine); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const queries = [{ type: queryType, cameraIDs: new Set(['id']) }]; + engine[engineMethodName].mockReturnValue(queries); + expect(manager[managerMethodName]('id')).toEqual(queries); + }, + ); + + it('without cameras', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const manager = createCameraManager(api, mock(), []); + + expect(manager.generateDefaultEventQueries('not_a_camera')).toBeNull(); + }); + + it('without queries', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const engine = mock(); + const manager = createCameraManager(api, engine); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + engine.generateDefaultEventQuery.mockReturnValue(null); + expect(manager.generateDefaultEventQueries('id')).toBeNull(); + }); + }); + }); + + describe('should get media metadata', () => { + const query = { + type: QueryType.MediaMetadata as const, + cameraIDs: new Set('id'), + }; + + it('with nothing', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const engine = mock(); + const manager = createCameraManager(api, engine); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const queryResults = { + type: QueryResultsType.MediaMetadata as const, + engine: Engine.Generic, + metadata: {}, + }; + + engine.getMediaMetadata.mockResolvedValue(new Map([[query, queryResults]])); + expect(await manager.getMediaMetadata()).toBeNull(); + }); + + it.each([['days'], ['tags'], ['where'], ['what']])( + 'with %s', + async (metadataType: string) => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const engine = mock(); + const manager = createCameraManager(api, engine); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const metadata: MediaMetadata = { + [metadataType]: new Set(['data']), + }; + const queryResults = { + type: QueryResultsType.MediaMetadata as const, + engine: Engine.Generic, + metadata: metadata, + }; + + engine.getMediaMetadata.mockResolvedValue(new Map([[query, queryResults]])); + expect(await manager.getMediaMetadata()).toEqual(metadata); + }, + ); + }); + + describe('should get events', () => { + it('without hass', async () => { + const manager = createCameraManager(createCardAPI()); + expect(await manager.getEvents(baseEventQuery)).toEqual(new Map()); + }); + + it('without cameras', async () => { + const api = createCardAPI(); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const manager = createCameraManager(api); + expect(await manager.getEvents(baseEventQuery)).toEqual(new Map()); + }); + + it('successfully', async () => { + const api = createCardAPI(); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const engine = mock(); + const manager = createCameraManager(api, engine); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const engineOptions = {}; + const results = new Map([[baseEventQuery, baseEventQueryResults]]); + engine.getEvents.mockResolvedValue(results); + expect(await manager.getEvents(baseEventQuery, engineOptions)).toEqual(results); + expect(engine.getEvents).toBeCalledWith( + hass, + expect.anything(), + baseEventQuery, + engineOptions, + ); + }); + }); + + describe('should get recordings', () => { + it('successfully', async () => { + const api = createCardAPI(); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const engine = mock(); + const manager = createCameraManager(api, engine); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const engineOptions = {}; + const results = new Map([[baseRecordingQuery, baseRecordingQueryResults]]); + engine.getRecordings.mockResolvedValue(results); + expect(await manager.getRecordings(baseRecordingQuery, engineOptions)).toEqual( + results, + ); + }); + }); + + describe('should get recording segments', () => { + const query = { + type: QueryType.RecordingSegments as const, + cameraIDs: new Set(['id']), + start: new Date(), + end: new Date(), + }; + + const queryResults = { + type: QueryResultsType.RecordingSegments as const, + engine: Engine.Generic, + segments: [], + }; + + it('successfully', async () => { + const api = createCardAPI(); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const engine = mock(); + const manager = createCameraManager(api, engine); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const engineOptions = {}; + const results = new Map([[query, queryResults]]); + engine.getRecordingSegments.mockResolvedValue(results); + expect(await manager.getRecordingSegments(query, engineOptions)).toEqual(results); + }); + }); + + describe('should execute media queries', () => { + it('events', async () => { + const api = createCardAPI(); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const engine = mock(); + vi.mocked(engine.getEngineType).mockReturnValue(Engine.Generic); + + const manager = createCameraManager(api, engine); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const results = new Map([[baseEventQuery, baseEventQueryResults]]); + engine.getEvents.mockResolvedValue(results); + const media = sortMedia(generateViewMediaArray({ count: 5 })); + engine.generateMediaFromEvents.mockReturnValue(media); + + expect(await manager.executeMediaQueries([baseEventQuery])).toEqual(media); + }); + + it('no converted media', async () => { + const api = createCardAPI(); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const engine = mock(); + vi.mocked(engine.getEngineType).mockReturnValue(Engine.Generic); + + const manager = createCameraManager(api, engine); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const results = new Map([[baseEventQuery, baseEventQueryResults]]); + engine.getEvents.mockResolvedValue(results); + engine.generateMediaFromEvents.mockReturnValue(null); + + expect(await manager.executeMediaQueries([baseEventQuery])).toEqual([]); + }); + + it('without matching camera engine during conversion', async () => { + const api = createCardAPI(); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const engine = mock(); + vi.mocked(engine.getEngineType).mockReturnValue(Engine.Generic); + + const manager = createCameraManager(api, engine); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const results = new Map([ + [baseEventQuery, { ...baseEventQueryResults, engine: Engine.MotionEye }], + ]); + engine.getEvents.mockResolvedValue(results); + + expect(await manager.executeMediaQueries([baseEventQuery])).toEqual([]); + }); + + it('recordings', async () => { + const api = createCardAPI(); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const engine = mock(); + vi.mocked(engine.getEngineType).mockReturnValue(Engine.Generic); + + const manager = createCameraManager(api, engine); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const results = new Map([[baseRecordingQuery, baseRecordingQueryResults]]); + engine.getRecordings.mockResolvedValue(results); + const media = sortMedia(generateViewMediaArray({ count: 5 })); + engine.generateMediaFromRecordings.mockReturnValue(media); + + expect(await manager.executeMediaQueries([baseRecordingQuery])).toEqual(media); + }); + + it('without hass', async () => { + const engine = mock(); + vi.mocked(engine.getEngineType).mockReturnValue(Engine.Generic); + + const manager = createCameraManager(createCardAPI(), engine); + const results = new Map([[baseEventQuery, baseEventQueryResults]]); + engine.getEvents.mockResolvedValue(results); + + expect(await manager.executeMediaQueries([baseEventQuery])).toEqual([]); + }); + }); + + describe('should extend media queries', () => { + const dateBase = new Date('2024-03-01T20:01:00'); + const mediaTwoCameras = generateViewMediaArray({ count: 5 }); + const mediaMixedStart: ViewMedia[] = [ + new TestViewMedia({ + startTime: dateBase, + }), + new TestViewMedia({ + startTime: add(dateBase, { days: 1 }), + }), + new TestViewMedia({ + startTime: add(dateBase, { days: 2 }), + }), + ]; + + it('without hass', async () => { + const engine = mock(); + vi.mocked(engine.getEngineType).mockReturnValue(Engine.Generic); + + const manager = createCameraManager(createCardAPI(), engine); + expect(await manager.extendMediaQueries([baseEventQuery], [], 'later')).toBeNull(); + }); + + it.each([ + ['empty query and results', new Map(), [], [], [], null], + [ + 'query without existing media', + new Map([[baseEventQuery, baseEventQueryResults]]), + [], + [{ ...baseEventQuery, limit: 50 }], + generateViewMediaArray({ count: 5 }), + { + queries: [{ ...baseEventQuery, limit: 50 }], + results: sortMedia(generateViewMediaArray({ count: 5 })), + }, + ], + [ + 'query that extends existing results', + new Map([[baseEventQuery, baseEventQueryResults]]), + generateViewMediaArray({ count: 5, cameraIDs: ['kitchen'] }), + [{ ...baseEventQuery, limit: 50 }], + generateViewMediaArray({ count: 5, cameraIDs: ['office'] }), + { + queries: [{ ...baseEventQuery, limit: 50 }], + results: sortMedia(mediaTwoCameras), + }, + ], + [ + 'query with existing media but no new media', + new Map([[baseEventQuery, baseEventQueryResults]]), + mediaTwoCameras, + [ + { + ...baseEventQuery, + limit: 50, + }, + ], + + // Fetch identical media again. + mediaTwoCameras, + + // Returns null to signify nothing new. + null, + ], + [ + 'query fetching later', + new Map([[{ ...baseEventQuery, start: dateBase }, baseEventQueryResults]]), + mediaMixedStart, + [ + { + ...baseEventQuery, + limit: 50, + start: add(dateBase, { days: 2 }), + }, + ], + mediaTwoCameras, + { + queries: [{ ...baseEventQuery, limit: 50, start: dateBase }], + results: sortMedia(mediaMixedStart.concat(mediaTwoCameras)), + }, + 'later' as const, + ], + [ + 'query fetching earlier', + new Map([[{ ...baseEventQuery, start: dateBase }, baseEventQueryResults]]), + mediaMixedStart, + [ + { + ...baseEventQuery, + limit: 50, + end: dateBase, + }, + ], + mediaTwoCameras, + { + queries: [{ ...baseEventQuery, limit: 50, start: dateBase }], + results: sortMedia(mediaMixedStart.concat(mediaTwoCameras)), + }, + 'earlier' as const, + ], + ])( + 'handles %s', + async ( + _name: string, + // The previously submitted query & results. + inputQueries: Map, + + // The previously received media. + inputMediaResults: ViewMedia[], + + // The queries expected to be dispatched. + newChunkQueries: EventQuery[], + + // The media received from the new queries. + outputMediaResults: ViewMedia[], + + // The expect extended queries and results. + expected?: { + queries: EventQuery[]; + results: ViewMedia[]; + } | null, + direction?: 'earlier' | 'later', + ) => { + const engine = mock(); + vi.mocked(engine.getEngineType).mockReturnValue(Engine.Generic); + + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const manager = createCameraManager(api, engine); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + engine.getEvents.mockResolvedValue(inputQueries); + engine.generateMediaFromEvents.mockReturnValue(outputMediaResults); + + expect( + await manager.extendMediaQueries( + [...inputQueries.keys()], + inputMediaResults, + direction ?? 'later', + ), + ).toEqual(expected); + + // Make sure the issued queries are correct. + for (const query of newChunkQueries) { + expect(engine.getEvents).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + query, + undefined, + ); + } + }, + ); + }); + + describe('should get media download path', () => { + it('without camera', async () => { + const manager = createCameraManager(createCardAPI()); + expect(await manager.getMediaDownloadPath(new TestViewMedia())).toBeNull(); + }); + + it('without hass', async () => { + const api = createCardAPI(); + const manager = createCameraManager(api); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(null); + expect(await manager.getMediaDownloadPath(new TestViewMedia())).toBeNull(); + }); + + it('successfully', async () => { + const api = createCardAPI(); + const engine = mock(); + const manager = createCameraManager(api, engine); + + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const result: CameraEndpoint = { + endpoint: 'http://localhost/path/to/media', + }; + vi.mocked(engine.getMediaDownloadPath).mockResolvedValue(result); + expect( + await manager.getMediaDownloadPath(new TestViewMedia({ cameraID: 'id' })), + ).toBe(result); + }); + }); + + describe('should get media capabilities', () => { + it('without camera', async () => { + const manager = createCameraManager(createCardAPI()); + expect(manager.getMediaCapabilities(new TestViewMedia())).toBeNull(); + }); + + it('successfully', async () => { + const api = createCardAPI(); + const engine = mock(); + const manager = createCameraManager(api, engine); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const result: CameraManagerMediaCapabilities = { + canFavorite: false, + canDownload: false, + }; + vi.mocked(engine.getMediaCapabilities).mockReturnValue(result); + expect(manager.getMediaCapabilities(new TestViewMedia({ cameraID: 'id' }))).toBe( + result, + ); + }); + }); + + describe('should favorite media', () => { + it('without camera', async () => { + const engine = mock(); + const manager = createCameraManager(createCardAPI(), engine); + manager.favoriteMedia(new TestViewMedia(), true); + + expect(engine.favoriteMedia).not.toBeCalled(); + }); + + it('successfully', async () => { + const api = createCardAPI(); + const engine = mock(); + const manager = createCameraManager(api, engine); + + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const media = new TestViewMedia({ cameraID: 'id' }); + manager.favoriteMedia(media, true); + expect(engine.favoriteMedia).toBeCalledWith(hass, expect.anything(), media, true); + }); + }); + + describe('should get camera endpoints', () => { + it('without camera', () => { + const manager = createCameraManager(createCardAPI()); + expect(manager.getCameraEndpoints('BAD')).toBeNull(); + }); + + it('successfully', async () => { + const api = createCardAPI(); + const engine = mock(); + const manager = createCameraManager(api, engine); + + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const result: CameraEndpoints = {}; + const context: CameraEndpointsContext = {}; + vi.mocked(engine.getCameraEndpoints).mockReturnValue(result); + + expect(manager.getCameraEndpoints('id', context)).toBe(result); + expect(engine.getCameraEndpoints).toBeCalledWith(expect.anything(), context); + }); + }); + + describe('should get camera metadata', () => { + it('without camera', () => { + const manager = createCameraManager(createCardAPI()); + expect(manager.getCameraMetadata('BAD')).toBeNull(); + }); + + it('successfully', async () => { + const api = createCardAPI(); + const engine = mock(); + const manager = createCameraManager(api, engine); + + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const result: CameraManagerCameraMetadata = { + title: 'My Camera', + icon: 'mdi:camera', + }; + vi.mocked(engine.getCameraMetadata).mockReturnValue(result); + + expect(manager.getCameraMetadata('id')).toBe(result); + }); + }); + + describe('should get camera capabilities', () => { + it('without camera', () => { + const manager = createCameraManager(createCardAPI()); + expect(manager.getCameraCapabilities('BAD')).toBeNull(); + }); + + it('successfully', async () => { + const api = createCardAPI(); + const engine = mock(); + const manager = createCameraManager(api, engine); + + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + expect(manager.getCameraCapabilities('id')).toEqual(createCameraCapabilities()); + }); + }); + + describe('should get aggregate camera capabilities', () => { + it('without camera', () => { + const manager = createCameraManager(createCardAPI()); + expect(manager.getAggregateCameraCapabilities()).toEqual({ + canFavoriteEvents: false, + canFavoriteRecordings: false, + canSeek: false, + + supportsClips: false, + supportsRecordings: false, + supportsSnapshots: false, + supportsTimeline: false, + + supportsPTZ: false, + }); + }); + + it('successfully', async () => { + const api = createCardAPI(); + const manager = createCameraManager(api, mock(), [ + { + capabilties: { + canFavoriteEvents: false, + canFavoriteRecordings: false, + canSeek: false, + + supportsClips: false, + supportsRecordings: false, + supportsSnapshots: false, + supportsTimeline: false, + }, + }, + { + config: createCameraConfig({ baseCameraConfig, id: 'another' }), + capabilties: { + canFavoriteEvents: true, + canFavoriteRecordings: true, + canSeek: true, + + supportsClips: true, + supportsRecordings: true, + supportsSnapshots: true, + supportsTimeline: true, + + ptz: {}, + }, + }, + ]); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + expect(manager.getAggregateCameraCapabilities()).toEqual({ + canFavoriteEvents: true, + canFavoriteRecordings: true, + canSeek: true, + + supportsClips: true, + supportsRecordings: true, + supportsSnapshots: true, + supportsTimeline: true, + + supportsPTZ: true, + }); + }); + }); + + describe('should execute PTZ action', () => { + it('without camera', () => { + const engine = mock(); + const manager = createCameraManager(createCardAPI(), engine); + + manager.executePTZAction('id', 'left', {}); + + expect(engine.executePTZAction).not.toBeCalled(); + }); + + it('successfully', async () => { + const api = createCardAPI(); + const engine = mock(); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + const manager = createCameraManager(api, engine); + + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + const action = 'left'; + const options = {}; + manager.executePTZAction('id', action, options); + + expect(engine.executePTZAction).toBeCalledWith( + hass, + expect.anything(), + action, + options, + ); + }); + }); + + describe('should determine if queries are fresh', () => { + beforeAll(() => { + const start = new Date('2024-03-02T20:35:00'); + vi.useFakeTimers(); + vi.setSystemTime(start); + }); + + afterAll(() => { + vi.useRealTimers(); + }); + + it.each([ + ['not fresh', new Date('2024-03-02T20:32:00'), false], + ['fresh on lower bound', new Date('2024-03-02T20:34:00'), true], + ['fresh at current time', new Date('2024-03-02T20:35:00'), true], + ['fresh in the future', new Date('2024-03-02T20:40:00'), true], + [ + 'unknown camera', + new Date('2024-03-02T20:35:00'), + + // Default assumed to be fresh. + true, + [ + { + ...baseEventQuery, + cameraIDs: new Set(['BAD']), + }, + ], + ], + ])( + '%s', + async ( + _name: string, + resultsTimestamp: Date, + expectedFresh: boolean, + queries: EventQuery[] = [baseEventQuery], + ) => { + const api = createCardAPI(); + const engine = mock(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + const manager = createCameraManager(api, engine); + + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + engine.getQueryResultMaxAge.mockReturnValue(60); + expect(manager.areMediaQueriesResultsFresh(queries, resultsTimestamp)).toBe( + expectedFresh, + ); + }, + ); + }); + + describe('should get media seek time', () => { + const startTime = new Date('2024-03-02T20:52:00'); + const endTime = new Date('2024-03-02T20:53:00'); + const middleTime = new Date('2024-03-02T20:52:30'); + + describe('invalid requests', () => { + it.each([ + ['null start and end', null, null, middleTime], + ['no start', null, endTime, middleTime], + ['no end', startTime, null, middleTime], + ['target < start', endTime, endTime, startTime], + ['target > end', startTime, startTime, endTime], + ])( + '%s', + async (_name: string, start: Date | null, end: Date | null, target: Date) => { + const api = createCardAPI(); + const engine = mock(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + const manager = createCameraManager(api, engine); + + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + expect( + await manager.getMediaSeekTime( + new TestViewMedia({ startTime: start, endTime: end }), + target, + ), + ).toBeNull(); + }, + ); + }); + + it('successfully', async () => { + const api = createCardAPI(); + const engine = mock(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + const manager = createCameraManager(api, engine); + + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + engine.getMediaSeekTime.mockResolvedValue(42); + + const media = new TestViewMedia({ + cameraID: 'id', + startTime: startTime, + endTime: endTime, + }); + expect(await manager.getMediaSeekTime(media, middleTime)).toBe(42); + + expect(engine.getMediaSeekTime).toBeCalledWith( + expect.anything(), + expect.anything(), + media, + middleTime, + ); + }); + }); +}); diff --git a/tests/camera-manager/store.test.ts b/tests/camera-manager/store.test.ts index 384f43e7..fa67beab 100644 --- a/tests/camera-manager/store.test.ts +++ b/tests/camera-manager/store.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it } from 'vitest'; +import { describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { Camera } from '../../src/camera-manager/camera.js'; import { CameraManagerEngineFactory } from '../../src/camera-manager/engine-factory.js'; @@ -6,11 +6,7 @@ import { CameraManagerStore } from '../../src/camera-manager/store.js'; import { Engine } from '../../src/camera-manager/types.js'; import { EntityRegistryManager } from '../../src/utils/ha/entity-registry/index.js'; import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media.js'; -import { - TestViewMedia, - createCameraCapabilities, - createCameraConfig, -} from '../test-utils.js'; +import { createCameraConfig, TestViewMedia } from '../test-utils.js'; describe('CameraManagerStore', async () => { const configVisible = createCameraConfig({ @@ -31,10 +27,14 @@ describe('CameraManagerStore', async () => { const setupStore = (): CameraManagerStore => { const store = new CameraManagerStore(); - store.addCamera( - new Camera(configVisible, engineGeneric, createCameraCapabilities()), - ); - store.addCamera(new Camera(configHidden, engineFrigate, createCameraCapabilities())); + const camera_1 = new Camera(configVisible, engineGeneric); + const camera_2 = new Camera(configHidden, engineFrigate); + + camera_1.destroy = vi.fn(); + camera_2.destroy = vi.fn(); + + store.addCamera(camera_1); + store.addCamera(camera_2); return store; }; @@ -123,11 +123,15 @@ describe('CameraManagerStore', async () => { it('reset', async () => { const store = setupStore(); + const cameras = [...store.getCameras().values()]; - store.reset(); + await store.reset(); expect(store.getCameraCount()).toBe(0); expect(store.getVisibleCameraCount()).toBe(0); + for (const camera of cameras) { + expect(camera.destroy).toBeCalled(); + } }); it('getCameraConfigForMedia', async () => { @@ -169,7 +173,6 @@ describe('CameraManagerStore', async () => { id: 'camera-visible2', }, engineGeneric, - createCameraCapabilities(), ), ); @@ -209,7 +212,6 @@ describe('CameraManagerStore', async () => { }, }), engineGeneric, - createCameraCapabilities(), ), ); store.addCamera( @@ -218,7 +220,6 @@ describe('CameraManagerStore', async () => { id: 'two', }), engineGeneric, - createCameraCapabilities(), ), ); expect(store.getAllDependentCameras('one')).toEqual(new Set(['one', 'two'])); @@ -234,7 +235,6 @@ describe('CameraManagerStore', async () => { }, }), engineGeneric, - createCameraCapabilities(), ), ); store.addCamera( @@ -243,7 +243,6 @@ describe('CameraManagerStore', async () => { id: 'two', }), engineGeneric, - createCameraCapabilities(), ), ); expect(store.getAllDependentCameras('one')).toEqual(new Set(['one', 'two'])); diff --git a/tests/camera-manager/utils.test.ts b/tests/camera-manager/utils.test.ts index e5a58d0b..561d1df8 100644 --- a/tests/camera-manager/utils.test.ts +++ b/tests/camera-manager/utils.test.ts @@ -107,6 +107,19 @@ describe('sortMedia', () => { it('should remove duplicate id', () => { expect(sortMedia([media_1, media_2, media_3_dup_id])).toEqual([media_1, media_2]); }); + it('should sort by id when time not available', () => { + expect( + sortMedia([ + new TestViewMedia({ id: 'snake' }), + new TestViewMedia({ id: 'zebra' }), + new TestViewMedia({ id: 'aardvark' }), + ]), + ).toEqual([ + new TestViewMedia({ id: 'aardvark' }), + new TestViewMedia({ id: 'snake' }), + new TestViewMedia({ id: 'zebra' }), + ]); + }); it('should remove de-duplicate by object if no id', () => { expect(sortMedia([media_1, media_2, media_4_no_id, media_4_no_id])).toEqual([ media_1, diff --git a/tests/card-controller/card-element-manager.test.ts b/tests/card-controller/card-element-manager.test.ts index 89a5e8e1..a695b637 100644 --- a/tests/card-controller/card-element-manager.test.ts +++ b/tests/card-controller/card-element-manager.test.ts @@ -154,6 +154,8 @@ describe('CardElementManager', () => { element.removeEventListener = removeEventListener; const api = createCardAPI(); + vi.mocked(api.getCameraManager().reset).mockResolvedValue(); + const manager = new CardElementManager( api, element, @@ -184,5 +186,7 @@ describe('CardElementManager', () => { expect.anything(), ); expect(windowRemoveEventListener).toBeCalledWith('popstate', expect.anything()); + + expect(api.getCameraManager().reset).toBeCalled(); }); }); diff --git a/tests/card-controller/conditions-manager.test.ts b/tests/card-controller/conditions-manager.test.ts index 08e71c67..b40dffaf 100644 --- a/tests/card-controller/conditions-manager.test.ts +++ b/tests/card-controller/conditions-manager.test.ts @@ -206,6 +206,14 @@ describe('ConditionsManager', () => { expect(epoch_1).not.toBe(epoch_2); }); + it('should get state', () => { + const state = { fullscreen: true }; + + const manager = new ConditionsManager(createCardAPI()); + manager.setState(state); + expect(manager.getState()).toEqual(state); + }); + it('should not return hasHAStateConditions without HA state conditions', () => { const manager = new ConditionsManager(createCardAPI()); expect(manager.hasHAStateConditions()).toBeFalsy(); diff --git a/tests/card-controller/hass-manager.test.ts b/tests/card-controller/hass-manager.test.ts index 51f64728..45205f0e 100644 --- a/tests/card-controller/hass-manager.test.ts +++ b/tests/card-controller/hass-manager.test.ts @@ -66,18 +66,6 @@ describe('HASSManager', () => { }); }); - it('should update triggered cameras', () => { - const api = createAPIWithoutMediaPlayers(); - const manager = new HASSManager(api); - - const originalHASS = createHASS(); - manager.setHASS(originalHASS); - expect(api.getTriggersManager().updateTriggerHAState).toBeCalledWith(null); - - manager.setHASS(createHASS()); - expect(api.getTriggersManager().updateTriggerHAState).toBeCalledWith(originalHASS); - }); - describe('should handle connection state change when', () => { it('initially disconnected', () => { const api = createAPIWithoutMediaPlayers(); @@ -156,37 +144,6 @@ describe('HASSManager', () => { }); describe('should set default view when', () => { - it('selected camera trigger entity changes', () => { - const api = createAPIWithoutMediaPlayers(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.foo', - config: createCameraConfig({ - triggers: { - entities: ['binary_sensor.motion'], - }, - }), - }, - ]), - ); - vi.mocked(api.getViewManager().getView).mockReturnValue( - createView({ - camera: 'camera.foo', - }), - ); - - const manager = new HASSManager(api); - const hass = createHASS({ - 'binary_sensor.motion': createStateEntity(), - }); - - manager.setHASS(hass); - - expect(api.getViewManager().setViewDefault).toBeCalled(); - }); - it('selected camera is unknown', () => { const api = createAPIWithoutMediaPlayers(); vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); diff --git a/tests/card-controller/triggers-manager.test.ts b/tests/card-controller/triggers-manager.test.ts index 90bcedd7..45193dda 100644 --- a/tests/card-controller/triggers-manager.test.ts +++ b/tests/card-controller/triggers-manager.test.ts @@ -1,22 +1,22 @@ import add from 'date-fns/add'; -import { HassEntities } from 'home-assistant-js-websocket'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { CardController } from '../../src/card-controller/controller'; import { TriggersManager } from '../../src/card-controller/triggers-manager'; -import { ScanOptions, scanSchema } from '../../src/config/types'; +import { TriggersOptions, triggersSchema } from '../../src/config/types'; import { createCameraConfig, createCameraManager, createCardAPI, createConfig, - createHASS, - createStateEntity, createStore, createView, } from '../test-utils'; -const baseScanConfig: Partial = { - enabled: true, +vi.mock('lodash-es/throttle', () => ({ + default: vi.fn((fn) => fn), +})); + +const baseTriggersConfig: Partial = { untrigger_seconds: 10, filter_selected_camera: false, actions: { @@ -29,21 +29,20 @@ const baseScanConfig: Partial = { // Creating and mocking a trigger API is a lot of boilerplate, this convenience // function reduces it. const createTriggerAPI = (options?: { - config?: Partial; - hassStates?: HassEntities; + config?: Partial; interaction?: boolean; }): CardController => { const api = createCardAPI(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { - scan: options?.config ? scanSchema.parse(options.config) : baseScanConfig, + triggers: options?.config + ? triggersSchema.parse(options.config) + : baseTriggersConfig, }, }), ); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue( - createHASS(options?.hassStates), - ); + vi.mocked(api.getConditionsManager().getState).mockReturnValue({}); vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); vi.mocked(api.getCameraManager().getStore).mockReturnValue( createStore([ @@ -60,22 +59,22 @@ const createTriggerAPI = (options?: { vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue( options?.interaction ?? false, ); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + camera: 'camera_1' as const, + }), + ); return api; }; // @vitest-environment jsdom describe('TriggersManager', () => { - const hassActiveState = { - 'binary_sensor.motion': createStateEntity({ state: 'on' }), - }; - const hassInactiveState = { - 'binary_sensor.motion': createStateEntity({ state: 'off' }), - }; + const start = new Date('2023-10-01T17:14'); beforeEach(() => { - vi.resetAllMocks(); vi.useFakeTimers(); + vi.setSystemTime(start); }); it('should not be triggered by default', () => { @@ -83,23 +82,8 @@ describe('TriggersManager', () => { expect(manager.isTriggered()).toBeFalsy(); }); - it('should not trigger when scan mode disabled default', () => { - const api = createTriggerAPI({ - config: { enabled: false }, - hassStates: hassActiveState, - }); - const manager = new TriggersManager(api); - - manager.updateTriggerHAState(null); - - expect(manager.isTriggered()).toBeFalsy(); - }); - - it('should not trigger without a scan config', () => { - const api = createTriggerAPI({ - hassStates: hassActiveState, - }); - + it('should not trigger without a triggers config', () => { + const api = createTriggerAPI(); vi.mocked(api.getViewManager().getView).mockReturnValue( createView({ camera: 'camera_1' as const, @@ -108,19 +92,23 @@ describe('TriggersManager', () => { vi.mocked(api.getConfigManager().getConfig).mockReturnValue(null); const manager = new TriggersManager(api); - manager.updateView(null); + + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + }); + expect(manager.isTriggered()).toBeFalsy(); }); - it('should trigger and untrigger based on entity state', () => { - const start = new Date('2023-10-01T17:14'); - vi.setSystemTime(start); - const api = createTriggerAPI({ - hassStates: hassActiveState, - }); + it('should trigger and untrigger based on low fidelity event', () => { + const api = createTriggerAPI(); const manager = new TriggersManager(api); - manager.updateTriggerHAState(createHASS(hassInactiveState)); + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + }); expect(manager.isTriggered()).toBeTruthy(); expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({ @@ -132,14 +120,14 @@ describe('TriggersManager', () => { cameraID: 'camera_1' as const, }); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue( - createHASS(hassInactiveState), - ); + vi.mocked(api.getConditionsManager().getState).mockReturnValue({ + triggered: new Set(['camera_1']), + }); - manager.updateTriggerHAState(createHASS(hassActiveState)); - - // Intentional state update with no change. - manager.updateTriggerHAState(createHASS(hassActiveState)); + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'end', + }); // Will still be triggered, but untrigger timer will be running. expect(manager.isTriggered()).toBeTruthy(); @@ -155,34 +143,141 @@ describe('TriggersManager', () => { expect(api.getViewManager().setViewDefault).toBeCalled(); }); - it('should trigger when entity state is active on startup', () => { + describe('should treat high fidelity events appropriately', () => { + it('with no media', () => { + const api = createTriggerAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + default: 'clips', + }, + }), + ); + + const manager = new TriggersManager(api); + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + fidelity: 'high', + + // Intentionally blank. + }); + + expect(manager.isTriggered()).toBeTruthy(); + expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + }); + + it('with media', () => { + const api = createTriggerAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + default: 'clips', + }, + }), + ); + + const manager = new TriggersManager(api); + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + fidelity: 'high', + clip: true, + }); + + expect(manager.isTriggered()).toBeTruthy(); + expect(api.getViewManager().setViewDefault).toBeCalled(); + }); + }); + + it('should change to default view when suitably configured', () => { const api = createTriggerAPI({ - hassStates: hassActiveState, + config: { + actions: { + interaction_mode: 'all', + trigger: 'default', + untrigger: 'none', + }, + }, }); const manager = new TriggersManager(api); - expect(manager.isTriggered()).toBeFalsy(); - manager.updateTriggerHAState(null); + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + }); + expect(manager.isTriggered()).toBeTruthy(); + expect(api.getViewManager().setViewDefault).toBeCalledWith({ + cameraID: 'camera_1', + }); + }); + + describe('should change to media view', () => { + it.each([ + [false, false, null], + [false, true, 'clip' as const], + [true, false, 'snapshot' as const], + [true, true, 'clip' as const], + ])( + 'with snapshot %s and clip %s', + async ( + hasSnapshot: boolean, + hasClip: boolean, + viewName: 'clip' | 'snapshot' | null, + ) => { + const api = createTriggerAPI({ + config: { + actions: { + interaction_mode: 'all', + trigger: 'media', + untrigger: 'none', + }, + }, + }); + const manager = new TriggersManager(api); + + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + fidelity: 'high', + snapshot: hasSnapshot, + clip: hasClip, + }); + + if (!viewName) { + expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + } else { + expect(manager.isTriggered()).toBeTruthy(); + expect(api.getViewManager().setViewByParameters).toBeCalledWith({ + cameraID: 'camera_1', + viewName: viewName, + }); + } + }, + ); }); it('should take no actions with human interactions', () => { - const start = new Date('2023-10-01T17:14'); const api = createTriggerAPI({ - hassStates: hassActiveState, // Interaction present. interaction: true, }); const manager = new TriggersManager(api); - manager.updateTriggerHAState(createHASS(hassInactiveState)); + + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + }); + expect(manager.isTriggered()).toBeTruthy(); expect(api.getViewManager().setViewByParameters).not.toBeCalled(); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue( - createHASS(hassInactiveState), - ); - manager.updateTriggerHAState(createHASS(hassActiveState)); + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'end', + }); vi.setSystemTime(add(start, { seconds: 10 })); vi.runOnlyPendingTimers(); @@ -193,11 +288,8 @@ describe('TriggersManager', () => { }); it('should take no actions when actions are set to none', () => { - const start = new Date('2023-10-01T17:14'); const api = createTriggerAPI({ - hassStates: hassActiveState, config: { - enabled: true, actions: { interaction_mode: 'all', trigger: 'none', @@ -206,32 +298,31 @@ describe('TriggersManager', () => { }, }); const manager = new TriggersManager(api); - manager.updateTriggerHAState(createHASS(hassInactiveState)); + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + }); expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue( - createHASS(hassInactiveState), - ); - manager.updateTriggerHAState(createHASS(hassActiveState)); + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'end', + }); vi.setSystemTime(add(start, { seconds: 10 })); vi.runOnlyPendingTimers(); expect(manager.isTriggered()).toBeFalsy(); - expect(api.getViewManager().setViewDefault).not.toBeCalled(); }); it('should take actions with human interactions when interaction mode is active', () => { - const start = new Date('2023-10-01T17:14'); const api = createTriggerAPI({ - hassStates: hassActiveState, // Interaction present. interaction: true, config: { - ...baseScanConfig, + ...baseTriggersConfig, actions: { trigger: 'live' as const, untrigger: 'default' as const, @@ -240,18 +331,21 @@ describe('TriggersManager', () => { }, }); const manager = new TriggersManager(api); - manager.updateTriggerHAState(createHASS(hassInactiveState)); - expect(manager.isTriggered()).toBeTruthy(); + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + }); + expect(manager.isTriggered()).toBeTruthy(); expect(api.getViewManager().setViewByParameters).toBeCalledWith({ viewName: 'live' as const, cameraID: 'camera_1' as const, }); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue( - createHASS(hassInactiveState), - ); - manager.updateTriggerHAState(createHASS(hassActiveState)); + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'end', + }); vi.setSystemTime(add(start, { seconds: 10 })); vi.runOnlyPendingTimers(); @@ -262,14 +356,7 @@ describe('TriggersManager', () => { }); it('should report multiple triggered cameras', () => { - const start = new Date('2023-10-01T17:14'); - const bothOnState = { - 'binary_sensor.one': createStateEntity({ state: 'on' }), - 'binary_sensor.two': createStateEntity({ state: 'on' }), - }; - const api = createTriggerAPI({ - hassStates: bothOnState, - }); + const api = createTriggerAPI(); vi.mocked(api.getCameraManager().getStore).mockReturnValue( createStore([ { @@ -297,7 +384,15 @@ describe('TriggersManager', () => { expect(manager.getMostRecentlyTriggeredCameraID()).toBeNull(); expect(manager.getTriggeredCameraIDs()).toEqual(new Set()); - manager.updateTriggerHAState(null); + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + }); + manager.handleCameraEvent({ + cameraID: 'camera_2', + type: 'new', + }); + expect(manager.isTriggered()).toBeTruthy(); expect(manager.getTriggeredCameraIDs()).toEqual(new Set(['camera_1', 'camera_2'])); @@ -306,14 +401,10 @@ describe('TriggersManager', () => { manager.getMostRecentlyTriggeredCameraID(), ); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue( - createHASS({ - 'binary_sensor.one': createStateEntity({ state: 'off' }), - 'binary_sensor.two': createStateEntity({ state: 'on' }), - }), - ); - - manager.updateTriggerHAState(createHASS(bothOnState)); + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'end', + }); vi.setSystemTime(add(start, { seconds: 10 })); vi.runOnlyPendingTimers(); @@ -322,75 +413,87 @@ describe('TriggersManager', () => { expect(manager.getMostRecentlyTriggeredCameraID()).toBe('camera_2'); }); - it('should filter triggers by camera', () => { - const start = new Date('2023-10-01T17:14'); - const api = createTriggerAPI({ - config: { - ...baseScanConfig, - // Filter triggers to selected camera only. - filter_selected_camera: true, - }, - hassStates: hassActiveState, - }); - const manager = new TriggersManager(api); - manager.updateTriggerHAState(createHASS(hassInactiveState)); - expect(manager.isTriggered()).toBeFalsy(); + describe('should filter triggers by camera', () => { + it('no dependencies', () => { + const api = createTriggerAPI({ + config: { + ...baseTriggersConfig, + // Filter triggers to selected camera only. + filter_selected_camera: true, + }, + }); + const manager = new TriggersManager(api); + expect(manager.isTriggered()).toBeFalsy(); - const otherCameraSelected = createView({ - camera: 'camera_SOME_OTHER_CAMERA' as const, + const otherCameraSelected = createView({ + camera: 'camera_SOME_OTHER_CAMERA' as const, + }); + vi.mocked(api.getViewManager().getView).mockReturnValue(otherCameraSelected); + + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + }); + expect(manager.isTriggered()).toBeFalsy(); + + const thisCameraSelected = createView({ + camera: 'camera_1' as const, + }); + vi.mocked(api.getViewManager().getView).mockReturnValue(thisCameraSelected); + + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + }); + expect(manager.isTriggered()).toBeTruthy(); }); - vi.mocked(api.getViewManager().getView).mockReturnValue(otherCameraSelected); - manager.updateView(null); - expect(manager.isTriggered()).toBeFalsy(); + it('dependencies', () => { + const api = createTriggerAPI({ + config: { + ...baseTriggersConfig, + // Filter triggers to selected camera only. + filter_selected_camera: true, + }, + }); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera_primary', + config: createCameraConfig({ + triggers: { + entities: ['binary_sensor.motion'], + }, + dependencies: { + all_cameras: true, + }, + }), + }, + { + cameraID: 'camera_secondary', + config: createCameraConfig({ + triggers: { + entities: ['binary_sensor.motion'], + }, + }), + }, + ]), + ); - const thisCameraSelected = createView({ - camera: 'camera_1' as const, + const manager = new TriggersManager(api); + + const primaryCameraView = createView({ + camera: 'camera_primary' as const, + }); + vi.mocked(api.getViewManager().getView).mockReturnValue(primaryCameraView); + + // Events for the secondary will still trigger when filter_selected_camera + // is true. + manager.handleCameraEvent({ + cameraID: 'camera_secondary', + type: 'new', + }); + expect(manager.isTriggered()).toBeTruthy(); }); - - vi.mocked(api.getViewManager().getView).mockReturnValue(thisCameraSelected); - manager.updateView(otherCameraSelected); - expect(manager.isTriggered()).toBeTruthy(); - - // Ensure a view change to the same camera stays triggered. - vi.mocked(api.getViewManager().getView).mockReturnValue(thisCameraSelected); - manager.updateView(thisCameraSelected); - expect(manager.isTriggered()).toBeTruthy(); - }); - - it('should not untrigger triggers by camera', () => { - const start = new Date('2023-10-01T17:14'); - const api = createTriggerAPI({ - config: { - ...baseScanConfig, - // Filter triggers to selected camera only. - filter_selected_camera: true, - }, - hassStates: hassActiveState, - }); - const manager = new TriggersManager(api); - manager.updateTriggerHAState(createHASS(hassInactiveState)); - expect(manager.isTriggered()).toBeFalsy(); - - const otherCameraSelected = createView({ - camera: 'camera_SOME_OTHER_CAMERA' as const, - }); - - vi.mocked(api.getViewManager().getView).mockReturnValue(otherCameraSelected); - manager.updateView(null); - expect(manager.isTriggered()).toBeFalsy(); - - const thisCameraSelected = createView({ - camera: 'camera_1' as const, - }); - - vi.mocked(api.getViewManager().getView).mockReturnValue(thisCameraSelected); - manager.updateView(otherCameraSelected); - expect(manager.isTriggered()).toBeTruthy(); - - // Ensure a view change to the same camera stays triggered. - vi.mocked(api.getViewManager().getView).mockReturnValue(thisCameraSelected); - manager.updateView(thisCameraSelected); - expect(manager.isTriggered()).toBeTruthy(); }); }); diff --git a/tests/config-mgmt.test.ts b/tests/config-mgmt.test.ts index 702a2637..9ca34a98 100644 --- a/tests/config-mgmt.test.ts +++ b/tests/config-mgmt.test.ts @@ -4,6 +4,7 @@ import { createRangedTransform, deleteConfigValue, deleteTransform, + deleteWithOverrides, getArrayConfigPath, getConfigValue, isConfigUpgradeable, @@ -344,6 +345,12 @@ describe('upgrade functions', () => { it('should have upgrades with bad input data', () => { expect(upgradeConfig(3 as unknown as RawFrigateCardConfig)).toBeFalsy(); }); + + it('should delete properties', () => { + const config = { c: 10, d: 10 }; + expect(deleteWithOverrides('c')(config)).toBeTruthy(); + expect(config).toEqual({ d: 10 }); + }); }); describe('should handle version specific upgrades', () => { @@ -1167,52 +1174,6 @@ describe('should handle version specific upgrades', () => { }); }); - describe('should move and transform untrigger_reset', () => { - it('when true', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - view: { - scan: { - untrigger_reset: true, - }, - }, - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - view: { - scan: { - actions: { - untrigger: 'default', - }, - }, - }, - }); - }); - - it('when false', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - view: { - scan: { - untrigger_reset: false, - }, - }, - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - view: { - scan: {}, - }, - }); - }); - }); - it('should move view.timeout_seconds', () => { const config = { type: 'custom:frigate-card', @@ -1690,5 +1651,92 @@ describe('should handle version specific upgrades', () => { }, ); }); + + describe('should transform scan mode', () => { + describe('should move and transform untrigger_reset', () => { + it('when true', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + scan: { + untrigger_reset: true, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + triggers: { + actions: { + untrigger: 'default', + }, + }, + }, + }); + }); + + it('when false', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + scan: { + untrigger_reset: false, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + triggers: {}, + }, + }); + }); + }); + + describe('should rename view.scan.enabled to a trigger action', () => { + it('when true', () => { + const config = { + view: { + scan: { + enabled: true, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + view: { + triggers: { + filter_selected_camera: false, + actions: { + trigger: 'live', + }, + }, + }, + }); + }); + + it('when false', () => { + const config = { + view: { + scan: { + enabled: false, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + view: { + triggers: {}, + }, + }); + }); + }); + }); }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index d34b057f..632586a7 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -38,9 +38,10 @@ describe('config defaults', () => { }, }, triggers: { + events: ['events', 'clips', 'snapshots'], entities: [], motion: false, - occupancy: true, + occupancy: false, }, }, debug: { @@ -279,16 +280,15 @@ describe('config defaults', () => { camera_select: 'current', dark_mode: 'off', default: 'live', - scan: { - enabled: false, - show_trigger_status: true, + triggers: { + show_trigger_status: false, untrigger_seconds: 0, actions: { - trigger: 'live', - untrigger: 'default', + trigger: 'default', + untrigger: 'none', interaction_mode: 'inactive', }, - filter_selected_camera: false, + filter_selected_camera: true, }, interaction_seconds: 300, reset_after_interaction: true, diff --git a/tests/test-utils.ts b/tests/test-utils.ts index 8c134c6d..773c3220 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -1,5 +1,6 @@ +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import { HassEntities, HassEntity } from 'home-assistant-js-websocket'; -import { vi } from 'vitest'; +import { expect, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { Camera } from '../src/camera-manager/camera'; import { CameraManagerEngine } from '../src/camera-manager/engine'; @@ -8,6 +9,7 @@ import { GenericCameraManagerEngine } from '../src/camera-manager/generic/engine import { CameraManager } from '../src/camera-manager/manager'; import { CameraManagerStore } from '../src/camera-manager/store'; import { + CameraEventCallback, CameraManagerCameraCapabilities, CameraManagerCapabilities, CameraManagerMediaCapabilities, @@ -36,16 +38,17 @@ import { TriggersManager } from '../src/card-controller/triggers-manager'; import { ViewManager } from '../src/card-controller/view-manager'; import { CameraConfig, - cameraConfigSchema, FrigateCardCondition, - frigateCardConditionSchema, FrigateCardConfig, - frigateCardConfigSchema, PerformanceConfig, - performanceConfigSchema, RawFrigateCardConfig, + cameraConfigSchema, + frigateCardConditionSchema, + frigateCardConfigSchema, + performanceConfigSchema, } from '../src/config/types'; import { ExtendedHomeAssistant, MediaLoadedInfo } from '../src/types'; +import { EntityRegistryManager } from '../src/utils/ha/entity-registry'; import { Entity } from '../src/utils/ha/entity-registry/types'; import { ViewMedia, ViewMediaType } from '../src/view/media'; import { MediaQueriesResults } from '../src/view/media-queries-results'; @@ -69,11 +72,20 @@ export const createConfig = (config?: RawFrigateCardConfig): FrigateCardConfig = }); }; +export const createCamera = ( + config: CameraConfig, + engine: CameraManagerEngine, + capabilities?: CameraManagerCameraCapabilities, +): Camera => { + return new Camera(config, engine, { capabilities: capabilities }); +}; + export const createHASS = (states?: HassEntities): ExtendedHomeAssistant => { const hass = mock(); if (states) { hass.states = states; } + hass.connection.subscribeMessage = vi.fn(); return hass; }; @@ -158,14 +170,19 @@ export const createStore = ( engine?: CameraManagerEngine; config?: CameraConfig; capabilities?: CameraManagerCameraCapabilities; + eventCallback?: CameraEventCallback; }[], ): CameraManagerStore => { const store = new CameraManagerStore(); for (const cameraProps of cameras ?? []) { + const eventCallback = cameraProps.eventCallback ?? vi.fn(); const camera = new Camera( cameraProps.config ?? createCameraConfig(), - cameraProps.engine ?? new GenericCameraManagerEngine(), - cameraProps.capabilities ?? createCameraCapabilities(), + cameraProps.engine ?? new GenericCameraManagerEngine(eventCallback), + { + capabilities: cameraProps.capabilities ?? createCameraCapabilities(), + eventCallback: eventCallback, + }, ); camera.setID(cameraProps.cameraID); store.addCamera(camera); @@ -260,10 +277,10 @@ export class TestViewMedia extends ViewMedia { constructor(options?: { id?: string | null; - startTime?: Date; + startTime?: Date | null; mediaType?: ViewMediaType; cameraID?: string; - endTime?: Date; + endTime?: Date | null; inProgress?: boolean; contentID?: string; title?: string; @@ -364,6 +381,7 @@ export const createCardAPI = (): CardController => { api.getConditionsManager.mockReturnValue(mock()); api.getConfigManager.mockReturnValue(mock()); api.getDownloadManager.mockReturnValue(mock()); + api.getEntityRegistryManager.mockReturnValue(mock()); api.getExpandManager.mockReturnValue(mock()); api.getFullscreenManager.mockReturnValue(mock()); api.getHASSManager.mockReturnValue(mock()); @@ -380,3 +398,13 @@ export const createCardAPI = (): CardController => { return api; }; + +export const callHASubscribeMessageHandler = ( + hass: HomeAssistant, + ev: unknown, + n = 0, +): void => { + const mock = vi.mocked(hass.connection.subscribeMessage).mock; + expect(mock.calls.length).greaterThan(n); + mock.calls[n][0](ev); +}; diff --git a/tests/utils/ha/index.test.ts b/tests/utils/ha/index.test.ts index 823f7ead..8c25a4f8 100644 --- a/tests/utils/ha/index.test.ts +++ b/tests/utils/ha/index.test.ts @@ -1,8 +1,10 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { describe, expect, it } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { getEntityIcon, hasHAConnectionStateChanged, + parseStateChangeTrigger, + subscribeToTrigger, } from '../../../src/utils/ha/index.js'; import { createHASS, createStateEntity } from '../../test-utils.js'; @@ -67,3 +69,105 @@ describe('getEntityIcon', () => { expect(getEntityIcon(createHASS(), 'camera.test')).toBe('mdi:video'); }); }); + +describe('should subscribe to trigger', () => { + it('mqtt', async () => { + const hass = createHASS(); + const callback = vi.fn(); + + await subscribeToTrigger(hass, callback, { + platform: 'mqtt', + topic: 'topic', + payload: 'payload', + valueTemplate: 'value_template', + }); + + expect(hass.connection.subscribeMessage).toBeCalledWith(callback, { + type: 'subscribe_trigger', + trigger: { + platform: 'mqtt', + topic: 'topic', + payload: 'payload', + value_template: 'value_template', + }, + }); + }); + + it('state and attributes', async () => { + const hass = createHASS(); + const callback = vi.fn(); + + await subscribeToTrigger(hass, callback, { + platform: 'state', + entityID: 'camera.foo', + }); + + expect(hass.connection.subscribeMessage).toBeCalledWith(callback, { + type: 'subscribe_trigger', + trigger: { + platform: 'state', + entity_id: 'camera.foo', + }, + }); + }); + + it('state only', async () => { + const hass = createHASS(); + const callback = vi.fn(); + + await subscribeToTrigger(hass, callback, { + platform: 'state', + entityID: 'camera.foo', + stateOnly: true, + }); + + expect(hass.connection.subscribeMessage).toBeCalledWith(callback, { + type: 'subscribe_trigger', + trigger: { + platform: 'state', + entity_id: 'camera.foo', + from: null, + to: null, + }, + }); + }); +}); + +describe('should parse state change response', () => { + beforeEach(() => { + vi.restoreAllMocks(); + }); + + it('malformed response', async () => { + const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined); + + expect(parseStateChangeTrigger('INVALID')).toBeNull(); + + expect(consoleSpy).toBeCalledWith('Ignoring unparseable HA state change', 'INVALID'); + }); + + it('valid response', async () => { + const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined); + + const stateChange = { + from_state: { + entity_id: 'camera.foo', + state: 'off', + }, + to_state: { + entity_id: 'camera.foo', + state: 'on', + }, + }; + + expect( + parseStateChangeTrigger({ + variables: { + trigger: stateChange, + }, + }), + ).toEqual(stateChange); + + expect(consoleSpy).not.toBeCalled(); + }); +}); diff --git a/tests/utils/media-to-view.test.ts b/tests/utils/media-to-view.test.ts index 24ac2bf9..2a96605c 100644 --- a/tests/utils/media-to-view.test.ts +++ b/tests/utils/media-to-view.test.ts @@ -202,6 +202,40 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { ); }); + it('should respect useCache', async () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera', + }, + ]), + ); + vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera']), + }, + ]); + + await changeViewToRecentEventsForCameraAndDependents( + createElementListenForView().element, + cameraManager, + {}, + createView(), + { + useCache: false, + }, + ); + + expect(vi.mocked(cameraManager.executeMediaQueries)).toBeCalledWith( + expect.anything(), + expect.objectContaining({ + useCache: false, + }), + ); + }); + describe('should respect request for media type', () => { it.each([ ['snapshots' as const, 'hasSnapshot'], @@ -463,6 +497,42 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => { }), ); }); + + it('should respect useCache', async () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera', + }, + ]), + ); + vi.mocked(cameraManager.generateDefaultRecordingQueries).mockReturnValue([ + { + type: QueryType.Recording, + cameraIDs: new Set(['camera']), + }, + ]); + + await changeViewToRecentRecordingForCameraAndDependents( + createElementListenForView().element, + cameraManager, + {}, + createView(), + { + targetView: 'recordings', + select: 'latest', + useCache: false, + }, + ); + + expect(vi.mocked(cameraManager.executeMediaQueries)).toBeCalledWith( + expect.anything(), + expect.objectContaining({ + useCache: false, + }), + ); + }); }); // @vitest-environment jsdom diff --git a/vite.config.ts b/vite.config.ts index 108e7a88..c22c0b38 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,17 +3,22 @@ import { defineConfig } from 'vitest/config'; // ts-prune-ignore-next export default defineConfig({ test: { + include: [ + "tests/**/*.test.ts" + ], coverage: { // Favor istanbul for coverage over v8 due to better accuracy. provider: 'istanbul', // Thresholds will automatically be updated as coverage improves to avoid // back-sliding. - thresholdAutoUpdate: true, - statements: 73.59, - branches: 63.6, - functions: 74.86, - lines: 73.48, + thresholds: { + autoUpdate: true, + statements: 73.59, + branches: 63.6, + functions: 74.86, + lines: 73.48, + }, }, }, }); diff --git a/yarn.lock b/yarn.lock index 89af7f0d..da79a3f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,233 +2,140 @@ # Manual changes might be lost - proceed with caution! __metadata: - version: 6 - cacheKey: 8 + version: 8 + cacheKey: 10c0 "@a11y/focus-trap@npm:^1.0.5": version: 1.0.5 resolution: "@a11y/focus-trap@npm:1.0.5" - checksum: aa5dbdcbfa0ce2de0a9778c1696a67c25ce28e06126079bb8c302a97fbffe620608a4fc0038a3ee0c0cfbbd4dc7fdafe029353e7aa06b0e5fdf9da69b0008b6b + checksum: 10c0/194206784b7bff55f1e8403275cd7fa4562f7e9d529a79a5e3a008f9e4c76ecbddab07257fec42540a5d230b9d8bef1527170bb6999c81024952326e087682d2 languageName: node linkType: hard -"@ampproject/remapping@npm:^2.1.0": - version: 2.2.0 - resolution: "@ampproject/remapping@npm:2.2.0" - dependencies: - "@jridgewell/gen-mapping": ^0.1.0 - "@jridgewell/trace-mapping": ^0.3.9 - checksum: d74d170d06468913921d72430259424b7e4c826b5a7d39ff839a29d547efb97dc577caa8ba3fb5cf023624e9af9d09651afc3d4112a45e2050328abc9b3a2292 +"@aashutoshrathi/word-wrap@npm:^1.2.3": + version: 1.2.6 + resolution: "@aashutoshrathi/word-wrap@npm:1.2.6" + checksum: 10c0/53c2b231a61a46792b39a0d43bc4f4f776bb4542aa57ee04930676802e5501282c2fc8aac14e4cd1f1120ff8b52616b6ff5ab539ad30aa2277d726444b71619f languageName: node linkType: hard "@ampproject/remapping@npm:^2.2.0": - version: 2.2.1 - resolution: "@ampproject/remapping@npm:2.2.1" + version: 2.3.0 + resolution: "@ampproject/remapping@npm:2.3.0" dependencies: - "@jridgewell/gen-mapping": ^0.3.0 - "@jridgewell/trace-mapping": ^0.3.9 - checksum: 03c04fd526acc64a1f4df22651186f3e5ef0a9d6d6530ce4482ec9841269cf7a11dbb8af79237c282d721c5312024ff17529cd72cc4768c11e999b58e2302079 + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/81d63cca5443e0f0c72ae18b544cc28c7c0ec2cea46e7cb888bb0e0f411a1191d0d6b7af798d54e30777d8d1488b2ec0732aac2be342d3d7d3ffd271c6f489ed languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/code-frame@npm:7.18.6" +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/code-frame@npm:7.23.5" dependencies: - "@babel/highlight": ^7.18.6 - checksum: 195e2be3172d7684bf95cff69ae3b7a15a9841ea9d27d3c843662d50cdd7d6470fd9c8e64be84d031117e4a4083486effba39f9aef6bbb2c89f7f21bcfba33ba + "@babel/highlight": "npm:^7.23.4" + chalk: "npm:^2.4.2" + checksum: 10c0/a10e843595ddd9f97faa99917414813c06214f4d9205294013e20c70fbdf4f943760da37dec1d998bf3e6fc20fa2918a47c0e987a7e458663feb7698063ad7c6 languageName: node linkType: hard -"@babel/code-frame@npm:^7.22.10, @babel/code-frame@npm:^7.22.5": - version: 7.22.13 - resolution: "@babel/code-frame@npm:7.22.13" +"@babel/compat-data@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/compat-data@npm:7.23.5" + checksum: 10c0/081278ed46131a890ad566a59c61600a5f9557bd8ee5e535890c8548192532ea92590742fd74bd9db83d74c669ef8a04a7e1c85cdea27f960233e3b83c3a957c + languageName: node + linkType: hard + +"@babel/core@npm:^7.19.0, @babel/core@npm:^7.23.9": + version: 7.24.0 + resolution: "@babel/core@npm:7.24.0" dependencies: - "@babel/highlight": ^7.22.13 - chalk: ^2.4.2 - checksum: 22e342c8077c8b77eeb11f554ecca2ba14153f707b85294fcf6070b6f6150aae88a7b7436dd88d8c9289970585f3fe5b9b941c5aa3aa26a6d5a8ef3f292da058 + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.23.5" + "@babel/generator": "npm:^7.23.6" + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helpers": "npm:^7.24.0" + "@babel/parser": "npm:^7.24.0" + "@babel/template": "npm:^7.24.0" + "@babel/traverse": "npm:^7.24.0" + "@babel/types": "npm:^7.24.0" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10c0/bb37cbf0bdfd676b246af0a3d9a7932d10573f2d45114fdda02a71889e35530ce13d8930177e78b065d6734b8d45a4fbf7c77f223b1d44b4a28cfe5fefee93ed languageName: node linkType: hard -"@babel/compat-data@npm:^7.20.5": - version: 7.20.14 - resolution: "@babel/compat-data@npm:7.20.14" - checksum: 6c9efe36232094e4ad0b70d165587f21ca718e5d011f7a52a77a18502a7524e90e2855aa5a2e086395bcfd21bd2c7c99128dcd8d9fdffe94316b72acf5c66f2c - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.22.9": - version: 7.22.9 - resolution: "@babel/compat-data@npm:7.22.9" - checksum: bed77d9044ce948b4327b30dd0de0779fa9f3a7ed1f2d31638714ed00229fa71fc4d1617ae0eb1fad419338d3658d0e9a5a083297451e09e73e078d0347ff808 - languageName: node - linkType: hard - -"@babel/core@npm:^7.12.3": - version: 7.22.11 - resolution: "@babel/core@npm:7.22.11" +"@babel/generator@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/generator@npm:7.23.6" dependencies: - "@ampproject/remapping": ^2.2.0 - "@babel/code-frame": ^7.22.10 - "@babel/generator": ^7.22.10 - "@babel/helper-compilation-targets": ^7.22.10 - "@babel/helper-module-transforms": ^7.22.9 - "@babel/helpers": ^7.22.11 - "@babel/parser": ^7.22.11 - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.11 - "@babel/types": ^7.22.11 - convert-source-map: ^1.7.0 - debug: ^4.1.0 - gensync: ^1.0.0-beta.2 - json5: ^2.2.3 - semver: ^6.3.1 - checksum: f258b2539ea2e5bfe55a708c2f3e1093a1b4744f12becc35abeb896037b66210de9a8ad6296a706046d5dc3a24e564362b73a9b814e5bfe500c8baab60c22d2e + "@babel/types": "npm:^7.23.6" + "@jridgewell/gen-mapping": "npm:^0.3.2" + "@jridgewell/trace-mapping": "npm:^0.3.17" + jsesc: "npm:^2.5.1" + checksum: 10c0/53540e905cd10db05d9aee0a5304e36927f455ce66f95d1253bb8a179f286b88fa7062ea0db354c566fe27f8bb96567566084ffd259f8feaae1de5eccc8afbda languageName: node linkType: hard -"@babel/core@npm:^7.19.0": - version: 7.20.12 - resolution: "@babel/core@npm:7.20.12" +"@babel/helper-annotate-as-pure@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" dependencies: - "@ampproject/remapping": ^2.1.0 - "@babel/code-frame": ^7.18.6 - "@babel/generator": ^7.20.7 - "@babel/helper-compilation-targets": ^7.20.7 - "@babel/helper-module-transforms": ^7.20.11 - "@babel/helpers": ^7.20.7 - "@babel/parser": ^7.20.7 - "@babel/template": ^7.20.7 - "@babel/traverse": ^7.20.12 - "@babel/types": ^7.20.7 - convert-source-map: ^1.7.0 - debug: ^4.1.0 - gensync: ^1.0.0-beta.2 - json5: ^2.2.2 - semver: ^6.3.0 - checksum: 62e6c3e2149a70b5c9729ef5f0d3e2e97e9dcde89fc039c8d8e3463d5d7ba9b29ee84d10faf79b61532ac1645aa62f2bd42338320617e6e3a8a4d8e2a27076e7 + "@babel/types": "npm:^7.22.5" + checksum: 10c0/5a80dc364ddda26b334bbbc0f6426cab647381555ef7d0cd32eb284e35b867c012ce6ce7d52a64672ed71383099c99d32765b3d260626527bb0e3470b0f58e45 languageName: node linkType: hard -"@babel/generator@npm:^7.20.7": - version: 7.20.14 - resolution: "@babel/generator@npm:7.20.14" +"@babel/helper-compilation-targets@npm:^7.23.6": + version: 7.23.6 + resolution: "@babel/helper-compilation-targets@npm:7.23.6" dependencies: - "@babel/types": ^7.20.7 - "@jridgewell/gen-mapping": ^0.3.2 - jsesc: ^2.5.1 - checksum: 5f6aa2d86af26e76d276923a5c34191124a119b16ee9ccc34aef654a7dec84fbd7d2daed2e6458a6a06bf87f3661deb77c9fea59b8f67faff5c90793c96d76d6 + "@babel/compat-data": "npm:^7.23.5" + "@babel/helper-validator-option": "npm:^7.23.5" + browserslist: "npm:^4.22.2" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10c0/ba38506d11185f48b79abf439462ece271d3eead1673dd8814519c8c903c708523428806f05f2ec5efd0c56e4e278698fac967e5a4b5ee842c32415da54bc6fa languageName: node linkType: hard -"@babel/generator@npm:^7.22.10": - version: 7.22.10 - resolution: "@babel/generator@npm:7.22.10" +"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/helper-create-class-features-plugin@npm:7.24.0" dependencies: - "@babel/types": ^7.22.10 - "@jridgewell/gen-mapping": ^0.3.2 - "@jridgewell/trace-mapping": ^0.3.17 - jsesc: ^2.5.1 - checksum: 59a79730abdff9070692834bd3af179e7a9413fa2ff7f83dff3eb888765aeaeb2bfc7b0238a49613ed56e1af05956eff303cc139f2407eda8df974813e486074 - languageName: node - linkType: hard - -"@babel/helper-annotate-as-pure@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/helper-annotate-as-pure@npm:7.18.6" - dependencies: - "@babel/types": ^7.18.6 - checksum: 88ccd15ced475ef2243fdd3b2916a29ea54c5db3cd0cfabf9d1d29ff6e63b7f7cd1c27264137d7a40ac2e978b9b9a542c332e78f40eb72abe737a7400788fc1b - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.20.7": - version: 7.20.7 - resolution: "@babel/helper-compilation-targets@npm:7.20.7" - dependencies: - "@babel/compat-data": ^7.20.5 - "@babel/helper-validator-option": ^7.18.6 - browserslist: ^4.21.3 - lru-cache: ^5.1.1 - semver: ^6.3.0 + "@babel/helper-annotate-as-pure": "npm:^7.22.5" + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-function-name": "npm:^7.23.0" + "@babel/helper-member-expression-to-functions": "npm:^7.23.0" + "@babel/helper-optimise-call-expression": "npm:^7.22.5" + "@babel/helper-replace-supers": "npm:^7.22.20" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + semver: "npm:^6.3.1" peerDependencies: "@babel/core": ^7.0.0 - checksum: 8c32c873ba86e2e1805b30e0807abd07188acbe00ebb97576f0b09061cc65007f1312b589eccb4349c5a8c7f8bb9f2ab199d41da7030bf103d9f347dcd3a3cf4 + checksum: 10c0/341548496df202805489422a160bba75b111d994c64d788a397c35f01784632af48bf06023af8aa2fe72c2c254f8c885b4e0f7f3df5ef17a37370f2feaf80328 languageName: node linkType: hard -"@babel/helper-compilation-targets@npm:^7.22.10": - version: 7.22.10 - resolution: "@babel/helper-compilation-targets@npm:7.22.10" +"@babel/helper-environment-visitor@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-environment-visitor@npm:7.22.20" + checksum: 10c0/e762c2d8f5d423af89bd7ae9abe35bd4836d2eb401af868a63bbb63220c513c783e25ef001019418560b3fdc6d9a6fb67e6c0b650bcdeb3a2ac44b5c3d2bdd94 + languageName: node + linkType: hard + +"@babel/helper-function-name@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-function-name@npm:7.23.0" dependencies: - "@babel/compat-data": ^7.22.9 - "@babel/helper-validator-option": ^7.22.5 - browserslist: ^4.21.9 - lru-cache: ^5.1.1 - semver: ^6.3.1 - checksum: f6f1896816392bcff671bbe6e277307729aee53befb4a66ea126e2a91eda78d819a70d06fa384c74ef46c1595544b94dca50bef6c78438d9ffd31776dafbd435 - languageName: node - linkType: hard - -"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.20.12": - version: 7.20.12 - resolution: "@babel/helper-create-class-features-plugin@npm:7.20.12" - dependencies: - "@babel/helper-annotate-as-pure": ^7.18.6 - "@babel/helper-environment-visitor": ^7.18.9 - "@babel/helper-function-name": ^7.19.0 - "@babel/helper-member-expression-to-functions": ^7.20.7 - "@babel/helper-optimise-call-expression": ^7.18.6 - "@babel/helper-replace-supers": ^7.20.7 - "@babel/helper-skip-transparent-expression-wrappers": ^7.20.0 - "@babel/helper-split-export-declaration": ^7.18.6 - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 1e9ed4243b75278fa24deb40dc62bf537b79307987223a2d2d2ae5abf7ba6dc8435d6e3bb55d52ceb30d3e1eba88e7eb6a1885a8bb519e5cfc3e9dedb97d43e6 - languageName: node - linkType: hard - -"@babel/helper-environment-visitor@npm:^7.18.9": - version: 7.18.9 - resolution: "@babel/helper-environment-visitor@npm:7.18.9" - checksum: b25101f6162ddca2d12da73942c08ad203d7668e06663df685634a8fde54a98bc015f6f62938e8554457a592a024108d45b8f3e651fd6dcdb877275b73cc4420 - languageName: node - linkType: hard - -"@babel/helper-environment-visitor@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-environment-visitor@npm:7.22.5" - checksum: 248532077d732a34cd0844eb7b078ff917c3a8ec81a7f133593f71a860a582f05b60f818dc5049c2212e5baa12289c27889a4b81d56ef409b4863db49646c4b1 - languageName: node - linkType: hard - -"@babel/helper-function-name@npm:^7.19.0": - version: 7.19.0 - resolution: "@babel/helper-function-name@npm:7.19.0" - dependencies: - "@babel/template": ^7.18.10 - "@babel/types": ^7.19.0 - checksum: eac1f5db428ba546270c2b8d750c24eb528b8fcfe50c81de2e0bdebf0e20f24bec688d4331533b782e4a907fad435244621ca2193cfcf80a86731299840e0f6e - languageName: node - linkType: hard - -"@babel/helper-function-name@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-function-name@npm:7.22.5" - dependencies: - "@babel/template": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: 6b1f6ce1b1f4e513bf2c8385a557ea0dd7fa37971b9002ad19268ca4384bbe90c09681fe4c076013f33deabc63a53b341ed91e792de741b4b35e01c00238177a - languageName: node - linkType: hard - -"@babel/helper-hoist-variables@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/helper-hoist-variables@npm:7.18.6" - dependencies: - "@babel/types": ^7.18.6 - checksum: fd9c35bb435fda802bf9ff7b6f2df06308a21277c6dec2120a35b09f9de68f68a33972e2c15505c1a1a04b36ec64c9ace97d4a9e26d6097b76b4396b7c5fa20f + "@babel/template": "npm:^7.22.15" + "@babel/types": "npm:^7.23.0" + checksum: 10c0/d771dd1f3222b120518176733c52b7cadac1c256ff49b1889dbbe5e3fed81db855b8cc4e40d949c9d3eae0e795e8229c1c8c24c0e83f27cfa6ee3766696c6428 languageName: node linkType: hard @@ -236,105 +143,70 @@ __metadata: version: 7.22.5 resolution: "@babel/helper-hoist-variables@npm:7.22.5" dependencies: - "@babel/types": ^7.22.5 - checksum: 394ca191b4ac908a76e7c50ab52102669efe3a1c277033e49467913c7ed6f7c64d7eacbeabf3bed39ea1f41731e22993f763b1edce0f74ff8563fd1f380d92cc + "@babel/types": "npm:^7.22.5" + checksum: 10c0/60a3077f756a1cd9f14eb89f0037f487d81ede2b7cfe652ea6869cd4ec4c782b0fb1de01b8494b9a2d2050e3d154d7d5ad3be24806790acfb8cbe2073bf1e208 languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.20.7": - version: 7.20.7 - resolution: "@babel/helper-member-expression-to-functions@npm:7.20.7" +"@babel/helper-member-expression-to-functions@npm:^7.22.15, @babel/helper-member-expression-to-functions@npm:^7.23.0": + version: 7.23.0 + resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0" dependencies: - "@babel/types": ^7.20.7 - checksum: cec17aab7e964830b0146e575bd141127032319f26ed864a65b35abd75ad618d264d3e11449b9b4e29cfd95bb1a7e774afddd4884fdcc29c36ac9cbd2b66359f + "@babel/types": "npm:^7.23.0" + checksum: 10c0/b810daddf093ffd0802f1429052349ed9ea08ef7d0c56da34ffbcdecbdafac86f95bdea2fe30e0e0e629febc7dd41b56cb5eacc10d1a44336d37b755dac31fa4 languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/helper-module-imports@npm:7.18.6" +"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helper-module-imports@npm:7.22.15" dependencies: - "@babel/types": ^7.18.6 - checksum: f393f8a3b3304b1b7a288a38c10989de754f01d29caf62ce7c4e5835daf0a27b81f3ac687d9d2780d39685aae7b55267324b512150e7b2be967b0c493b6a1def + "@babel/types": "npm:^7.22.15" + checksum: 10c0/4e0d7fc36d02c1b8c8b3006dfbfeedf7a367d3334a04934255de5128115ea0bafdeb3e5736a2559917f0653e4e437400d54542da0468e08d3cbc86d3bbfa8f30 languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-module-imports@npm:7.22.5" +"@babel/helper-module-transforms@npm:^7.23.3": + version: 7.23.3 + resolution: "@babel/helper-module-transforms@npm:7.23.3" dependencies: - "@babel/types": ^7.22.5 - checksum: 9ac2b0404fa38b80bdf2653fbeaf8e8a43ccb41bd505f9741d820ed95d3c4e037c62a1bcdcb6c9527d7798d2e595924c4d025daed73283badc180ada2c9c49ad - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.20.11": - version: 7.20.11 - resolution: "@babel/helper-module-transforms@npm:7.20.11" - dependencies: - "@babel/helper-environment-visitor": ^7.18.9 - "@babel/helper-module-imports": ^7.18.6 - "@babel/helper-simple-access": ^7.20.2 - "@babel/helper-split-export-declaration": ^7.18.6 - "@babel/helper-validator-identifier": ^7.19.1 - "@babel/template": ^7.20.7 - "@babel/traverse": ^7.20.10 - "@babel/types": ^7.20.7 - checksum: 29319ebafa693d48756c6ba0d871677bb0037e0da084fbe221a17c38d57093fc8aa38543c07d76e788266a937976e37ab4901971ca7f237c5ab45f524b9ecca0 - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.22.9": - version: 7.22.9 - resolution: "@babel/helper-module-transforms@npm:7.22.9" - dependencies: - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-module-imports": ^7.22.5 - "@babel/helper-simple-access": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/helper-validator-identifier": ^7.22.5 + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-module-imports": "npm:^7.22.15" + "@babel/helper-simple-access": "npm:^7.22.5" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + "@babel/helper-validator-identifier": "npm:^7.22.20" peerDependencies: "@babel/core": ^7.0.0 - checksum: 2751f77660518cf4ff027514d6f4794f04598c6393be7b04b8e46c6e21606e11c19f3f57ab6129a9c21bacdf8b3ffe3af87bb401d972f34af2d0ffde02ac3001 + checksum: 10c0/211e1399d0c4993671e8e5c2b25383f08bee40004ace5404ed4065f0e9258cc85d99c1b82fd456c030ce5cfd4d8f310355b54ef35de9924eabfc3dff1331d946 languageName: node linkType: hard -"@babel/helper-optimise-call-expression@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/helper-optimise-call-expression@npm:7.18.6" +"@babel/helper-optimise-call-expression@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" dependencies: - "@babel/types": ^7.18.6 - checksum: e518fe8418571405e21644cfb39cf694f30b6c47b10b006609a92469ae8b8775cbff56f0b19732343e2ea910641091c5a2dc73b56ceba04e116a33b0f8bd2fbd + "@babel/types": "npm:^7.22.5" + checksum: 10c0/31b41a764fc3c585196cf5b776b70cf4705c132e4ce9723f39871f215f2ddbfb2e28a62f9917610f67c8216c1080482b9b05f65dd195dae2a52cef461f2ac7b8 languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.19.0, @babel/helper-plugin-utils@npm:^7.20.2": - version: 7.20.2 - resolution: "@babel/helper-plugin-utils@npm:7.20.2" - checksum: f6cae53b7fdb1bf3abd50fa61b10b4470985b400cc794d92635da1e7077bb19729f626adc0741b69403d9b6e411cddddb9c0157a709cc7c4eeb41e663be5d74b +"@babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/helper-plugin-utils@npm:7.24.0" + checksum: 10c0/90f41bd1b4dfe7226b1d33a4bb745844c5c63e400f9e4e8bf9103a7ceddd7d425d65333b564d9daba3cebd105985764d51b4bd4c95822b97c2e3ac1201a8a5da languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.20.7": - version: 7.20.7 - resolution: "@babel/helper-replace-supers@npm:7.20.7" +"@babel/helper-replace-supers@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-replace-supers@npm:7.22.20" dependencies: - "@babel/helper-environment-visitor": ^7.18.9 - "@babel/helper-member-expression-to-functions": ^7.20.7 - "@babel/helper-optimise-call-expression": ^7.18.6 - "@babel/template": ^7.20.7 - "@babel/traverse": ^7.20.7 - "@babel/types": ^7.20.7 - checksum: b8e0087c9b0c1446e3c6f3f72b73b7e03559c6b570e2cfbe62c738676d9ebd8c369a708cf1a564ef88113b4330750a50232ee1131d303d478b7a5e65e46fbc7c - languageName: node - linkType: hard - -"@babel/helper-simple-access@npm:^7.20.2": - version: 7.20.2 - resolution: "@babel/helper-simple-access@npm:7.20.2" - dependencies: - "@babel/types": ^7.20.2 - checksum: ad1e96ee2e5f654ffee2369a586e5e8d2722bf2d8b028a121b4c33ebae47253f64d420157b9f0a8927aea3a9e0f18c0103e74fdd531815cf3650a0a4adca11a1 + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-member-expression-to-functions": "npm:^7.22.15" + "@babel/helper-optimise-call-expression": "npm:^7.22.5" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/6b0858811ad46873817c90c805015d63300e003c5a85c147a17d9845fa2558a02047c3cc1f07767af59014b2dd0fa75b503e5bc36e917f360e9b67bb6f1e79f4 languageName: node linkType: hard @@ -342,26 +214,17 @@ __metadata: version: 7.22.5 resolution: "@babel/helper-simple-access@npm:7.22.5" dependencies: - "@babel/types": ^7.22.5 - checksum: fe9686714caf7d70aedb46c3cce090f8b915b206e09225f1e4dbc416786c2fdbbee40b38b23c268b7ccef749dd2db35f255338fb4f2444429874d900dede5ad2 + "@babel/types": "npm:^7.22.5" + checksum: 10c0/f0cf81a30ba3d09a625fd50e5a9069e575c5b6719234e04ee74247057f8104beca89ed03e9217b6e9b0493434cedc18c5ecca4cea6244990836f1f893e140369 languageName: node linkType: hard -"@babel/helper-skip-transparent-expression-wrappers@npm:^7.20.0": - version: 7.20.0 - resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.20.0" +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5": + version: 7.22.5 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5" dependencies: - "@babel/types": ^7.20.0 - checksum: 34da8c832d1c8a546e45d5c1d59755459ffe43629436707079989599b91e8c19e50e73af7a4bd09c95402d389266731b0d9c5f69e372d8ebd3a709c05c80d7dd - languageName: node - linkType: hard - -"@babel/helper-split-export-declaration@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/helper-split-export-declaration@npm:7.18.6" - dependencies: - "@babel/types": ^7.18.6 - checksum: c6d3dede53878f6be1d869e03e9ffbbb36f4897c7cc1527dc96c56d127d834ffe4520a6f7e467f5b6f3c2843ea0e81a7819d66ae02f707f6ac057f3d57943a2b + "@babel/types": "npm:^7.22.5" + checksum: 10c0/ab7fa2aa709ab49bb8cd86515a1e715a3108c4bb9a616965ba76b43dc346dee66d1004ccf4d222b596b6224e43e04cbc5c3a34459501b388451f8c589fbc3691 languageName: node linkType: hard @@ -369,112 +232,60 @@ __metadata: version: 7.22.6 resolution: "@babel/helper-split-export-declaration@npm:7.22.6" dependencies: - "@babel/types": ^7.22.5 - checksum: e141cace583b19d9195f9c2b8e17a3ae913b7ee9b8120246d0f9ca349ca6f03cb2c001fd5ec57488c544347c0bb584afec66c936511e447fd20a360e591ac921 + "@babel/types": "npm:^7.22.5" + checksum: 10c0/d83e4b623eaa9622c267d3c83583b72f3aac567dc393dda18e559d79187961cb29ae9c57b2664137fc3d19508370b12ec6a81d28af73a50e0846819cb21c6e44 languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.19.4": - version: 7.19.4 - resolution: "@babel/helper-string-parser@npm:7.19.4" - checksum: b2f8a3920b30dfac81ec282ac4ad9598ea170648f8254b10f475abe6d944808fb006aab325d3eb5a8ad3bea8dfa888cfa6ef471050dae5748497c110ec060943 +"@babel/helper-string-parser@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/helper-string-parser@npm:7.23.4" + checksum: 10c0/f348d5637ad70b6b54b026d6544bd9040f78d24e7ec245a0fc42293968181f6ae9879c22d89744730d246ce8ec53588f716f102addd4df8bbc79b73ea10004ac languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-string-parser@npm:7.22.5" - checksum: 836851ca5ec813077bbb303acc992d75a360267aa3b5de7134d220411c852a6f17de7c0d0b8c8dcc0f567f67874c00f4528672b2a4f1bc978a3ada64c8c78467 +"@babel/helper-validator-identifier@npm:^7.22.20": + version: 7.22.20 + resolution: "@babel/helper-validator-identifier@npm:7.22.20" + checksum: 10c0/dcad63db345fb110e032de46c3688384b0008a42a4845180ce7cd62b1a9c0507a1bed727c4d1060ed1a03ae57b4d918570259f81724aaac1a5b776056f37504e languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.18.6, @babel/helper-validator-identifier@npm:^7.19.1": - version: 7.19.1 - resolution: "@babel/helper-validator-identifier@npm:7.19.1" - checksum: 0eca5e86a729162af569b46c6c41a63e18b43dbe09fda1d2a3c8924f7d617116af39cac5e4cd5d431bb760b4dca3c0970e0c444789b1db42bcf1fa41fbad0a3a +"@babel/helper-validator-option@npm:^7.23.5": + version: 7.23.5 + resolution: "@babel/helper-validator-option@npm:7.23.5" + checksum: 10c0/af45d5c0defb292ba6fd38979e8f13d7da63f9623d8ab9ededc394f67eb45857d2601278d151ae9affb6e03d5d608485806cd45af08b4468a0515cf506510e94 languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-validator-identifier@npm:7.22.5" - checksum: 7f0f30113474a28298c12161763b49de5018732290ca4de13cdaefd4fd0d635a6fe3f6686c37a02905fb1e64f21a5ee2b55140cf7b070e729f1bd66866506aea - languageName: node - linkType: hard - -"@babel/helper-validator-option@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/helper-validator-option@npm:7.18.6" - checksum: f9cc6eb7cc5d759c5abf006402180f8d5e4251e9198197428a97e05d65eb2f8ae5a0ce73b1dfd2d35af41d0eb780627a64edf98a4e71f064eeeacef8de58f2cf - languageName: node - linkType: hard - -"@babel/helper-validator-option@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-validator-option@npm:7.22.5" - checksum: bbeca8a85ee86990215c0424997438b388b8d642d69b9f86c375a174d3cdeb270efafd1ff128bc7a1d370923d13b6e45829ba8581c027620e83e3a80c5c414b3 - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.20.7": - version: 7.20.13 - resolution: "@babel/helpers@npm:7.20.13" +"@babel/helpers@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/helpers@npm:7.24.0" dependencies: - "@babel/template": ^7.20.7 - "@babel/traverse": ^7.20.13 - "@babel/types": ^7.20.7 - checksum: d62076fa834f342798f8c3fd7aec0870cc1725d273d99e540cbaa8d6c3ed10258228dd14601c8e66bfeabbb9424c3b31090ecc467fe855f7bd72c4734df7fb09 + "@babel/template": "npm:^7.24.0" + "@babel/traverse": "npm:^7.24.0" + "@babel/types": "npm:^7.24.0" + checksum: 10c0/dd27c9f11c1c5244ef312fae37636f2fcc69c541c46508017b846c4cf680af059f1922ce84e3f778f123a70d027ded75c96070ee8e906f3bc52dc26dc43df608 languageName: node linkType: hard -"@babel/helpers@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/helpers@npm:7.22.11" +"@babel/highlight@npm:^7.23.4": + version: 7.23.4 + resolution: "@babel/highlight@npm:7.23.4" dependencies: - "@babel/template": ^7.22.5 - "@babel/traverse": ^7.22.11 - "@babel/types": ^7.22.11 - checksum: 93186544228b5e371486466ec3b86a77cce91beeff24a5670ca8ec46d50328f7700dab82d532351286e9d68624dc51d6d71589b051dd9535e44be077a43ec013 + "@babel/helper-validator-identifier": "npm:^7.22.20" + chalk: "npm:^2.4.2" + js-tokens: "npm:^4.0.0" + checksum: 10c0/fbff9fcb2f5539289c3c097d130e852afd10d89a3a08ac0b5ebebbc055cc84a4bcc3dcfed463d488cde12dd0902ef1858279e31d7349b2e8cee43913744bda33 languageName: node linkType: hard -"@babel/highlight@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/highlight@npm:7.18.6" - dependencies: - "@babel/helper-validator-identifier": ^7.18.6 - chalk: ^2.0.0 - js-tokens: ^4.0.0 - checksum: 92d8ee61549de5ff5120e945e774728e5ccd57fd3b2ed6eace020ec744823d4a98e242be1453d21764a30a14769ecd62170fba28539b211799bbaf232bbb2789 - languageName: node - linkType: hard - -"@babel/highlight@npm:^7.22.13": - version: 7.22.13 - resolution: "@babel/highlight@npm:7.22.13" - dependencies: - "@babel/helper-validator-identifier": ^7.22.5 - chalk: ^2.4.2 - js-tokens: ^4.0.0 - checksum: 7266d2bff8aa8fc78eb65b6e92a8211e12897a731126a282d2f9bb50d8fcaa4c1b02af2284f990ac7e3ab8d892d448a2cab8f5ed0ea8a90bce2c025b11ebe802 - languageName: node - linkType: hard - -"@babel/parser@npm:^7.14.7, @babel/parser@npm:^7.22.11, @babel/parser@npm:^7.22.5": - version: 7.22.14 - resolution: "@babel/parser@npm:7.22.14" +"@babel/parser@npm:^7.23.6, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/parser@npm:7.24.0" bin: parser: ./bin/babel-parser.js - checksum: a2293971f0889726a3d5a35fcceedc71d2fa4c8d97f438fc348fe0cf7e739affc6e2665e4c6ddd4900714772e19bfd5d6feb967ca1f623b894c0099ecb148b52 - languageName: node - linkType: hard - -"@babel/parser@npm:^7.20.13, @babel/parser@npm:^7.20.7": - version: 7.20.15 - resolution: "@babel/parser@npm:7.20.15" - bin: - parser: ./bin/babel-parser.js - checksum: 1d0f47ca67ff2652f1c0ff1570bed8deccbc4b53509e7cd73476af9cc7ed23480c99f1179bd6d0be01612368b92b39e206d330ad6054009d699934848a89298b + checksum: 10c0/77593d0b9de9906823c4d653bb6cda1c7593837598516330f655f70cba6224a37def7dbe5b4dad0038482d407d8d209eb8be5f48ca9a13357d769f829c5adb8e languageName: node linkType: hard @@ -482,124 +293,91 @@ __metadata: version: 7.18.6 resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" dependencies: - "@babel/helper-create-class-features-plugin": ^7.18.6 - "@babel/helper-plugin-utils": ^7.18.6 + "@babel/helper-create-class-features-plugin": "npm:^7.18.6" + "@babel/helper-plugin-utils": "npm:^7.18.6" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 49a78a2773ec0db56e915d9797e44fd079ab8a9b2e1716e0df07c92532f2c65d76aeda9543883916b8e0ff13606afeffa67c5b93d05b607bc87653ad18a91422 + checksum: 10c0/d5172ac6c9948cdfc387e94f3493ad86cb04035cf7433f86b5d358270b1b9752dc25e176db0c5d65892a246aca7bdb4636672e15626d7a7de4bc0bd0040168d9 languageName: node linkType: hard "@babel/plugin-proposal-decorators@npm:^7.19.0": - version: 7.20.13 - resolution: "@babel/plugin-proposal-decorators@npm:7.20.13" + version: 7.24.0 + resolution: "@babel/plugin-proposal-decorators@npm:7.24.0" dependencies: - "@babel/helper-create-class-features-plugin": ^7.20.12 - "@babel/helper-plugin-utils": ^7.20.2 - "@babel/helper-replace-supers": ^7.20.7 - "@babel/helper-split-export-declaration": ^7.18.6 - "@babel/plugin-syntax-decorators": ^7.19.0 + "@babel/helper-create-class-features-plugin": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-decorators": "npm:^7.24.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 445723b410627d52ab2d195589eb9fe5fbd66a00ebfc9bedcf63b6cbfdfc42e163d77ac391f8738ab9f632779e6f2aa427fe468fbbd6661177ef0cdca735a7d5 + checksum: 10c0/6bf16cb2b5b2f1b63b5ea964853cd3b3419c8285296b5bf64a64127c9d5c1b2e6829e84bd92734e4b71df67686d8f36fb01bb8a45fc52bcece7503b73bc42ec7 languageName: node linkType: hard -"@babel/plugin-syntax-decorators@npm:^7.19.0": - version: 7.19.0 - resolution: "@babel/plugin-syntax-decorators@npm:7.19.0" +"@babel/plugin-syntax-decorators@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/plugin-syntax-decorators@npm:7.24.0" dependencies: - "@babel/helper-plugin-utils": ^7.19.0 + "@babel/helper-plugin-utils": "npm:^7.24.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 105a13d581a8643ba145d4d0d31f34a492b352defa5b155e785702da6ce9c3ff0c1843ba9bee176e35f6e38afa19dc7bd12c120220af0495de4b128f1dd27f6e + checksum: 10c0/6c11801e062772d4e1b0b418a4732574128b1dfc13193a2909fa93937346746aaa7046f88f6026ff3c80777c967d0fe2e4bb19a1d3fb399e8349c81741e4f471 languageName: node linkType: hard -"@babel/template@npm:^7.18.10, @babel/template@npm:^7.20.7": - version: 7.20.7 - resolution: "@babel/template@npm:7.20.7" +"@babel/runtime@npm:^7.21.0": + version: 7.24.0 + resolution: "@babel/runtime@npm:7.24.0" dependencies: - "@babel/code-frame": ^7.18.6 - "@babel/parser": ^7.20.7 - "@babel/types": ^7.20.7 - checksum: 2eb1a0ab8d415078776bceb3473d07ab746e6bb4c2f6ca46ee70efb284d75c4a32bb0cd6f4f4946dec9711f9c0780e8e5d64b743208deac6f8e9858afadc349e + regenerator-runtime: "npm:^0.14.0" + checksum: 10c0/3495eed727bf4a4f84c35bb51ab53317ae38f4bbc3b1d0a8303751f9dfa0ce6f5fb2afced72b76c3dd0d8bb2ccb84787559a4dee9886291a36b26f02f0f759b4 languageName: node linkType: hard -"@babel/template@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/template@npm:7.22.5" +"@babel/template@npm:^7.22.15, @babel/template@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/template@npm:7.24.0" dependencies: - "@babel/code-frame": ^7.22.5 - "@babel/parser": ^7.22.5 - "@babel/types": ^7.22.5 - checksum: c5746410164039aca61829cdb42e9a55410f43cace6f51ca443313f3d0bdfa9a5a330d0b0df73dc17ef885c72104234ae05efede37c1cc8a72dc9f93425977a3 + "@babel/code-frame": "npm:^7.23.5" + "@babel/parser": "npm:^7.24.0" + "@babel/types": "npm:^7.24.0" + checksum: 10c0/9d3dd8d22fe1c36bc3bdef6118af1f4b030aaf6d7d2619f5da203efa818a2185d717523486c111de8d99a8649ddf4bbf6b2a7a64962d8411cf6a8fa89f010e54 languageName: node linkType: hard -"@babel/traverse@npm:^7.20.10, @babel/traverse@npm:^7.20.12, @babel/traverse@npm:^7.20.13, @babel/traverse@npm:^7.20.7": - version: 7.20.13 - resolution: "@babel/traverse@npm:7.20.13" +"@babel/traverse@npm:^7.24.0": + version: 7.24.0 + resolution: "@babel/traverse@npm:7.24.0" dependencies: - "@babel/code-frame": ^7.18.6 - "@babel/generator": ^7.20.7 - "@babel/helper-environment-visitor": ^7.18.9 - "@babel/helper-function-name": ^7.19.0 - "@babel/helper-hoist-variables": ^7.18.6 - "@babel/helper-split-export-declaration": ^7.18.6 - "@babel/parser": ^7.20.13 - "@babel/types": ^7.20.7 - debug: ^4.1.0 - globals: ^11.1.0 - checksum: 30ca6e0bd18233fda48fa09315efd14dfc61dcf5b8fa3712b343bfc61b32bc63b5e85ea1773cc9576c9b293b96f46b4589aaeb0a52e1f3eeac4edc076d049fc7 + "@babel/code-frame": "npm:^7.23.5" + "@babel/generator": "npm:^7.23.6" + "@babel/helper-environment-visitor": "npm:^7.22.20" + "@babel/helper-function-name": "npm:^7.23.0" + "@babel/helper-hoist-variables": "npm:^7.22.5" + "@babel/helper-split-export-declaration": "npm:^7.22.6" + "@babel/parser": "npm:^7.24.0" + "@babel/types": "npm:^7.24.0" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10c0/55ffd2b0ce0fbd0a09051edc4def4fb1e96f35e0b100c0dc2a7429df569971ae312c290e980e423471f350961705698a257c7eea8c8304918024cc26f02468ba languageName: node linkType: hard -"@babel/traverse@npm:^7.22.11": - version: 7.22.11 - resolution: "@babel/traverse@npm:7.22.11" +"@babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.6, @babel/types@npm:^7.24.0, @babel/types@npm:^7.8.3": + version: 7.24.0 + resolution: "@babel/types@npm:7.24.0" dependencies: - "@babel/code-frame": ^7.22.10 - "@babel/generator": ^7.22.10 - "@babel/helper-environment-visitor": ^7.22.5 - "@babel/helper-function-name": ^7.22.5 - "@babel/helper-hoist-variables": ^7.22.5 - "@babel/helper-split-export-declaration": ^7.22.6 - "@babel/parser": ^7.22.11 - "@babel/types": ^7.22.11 - debug: ^4.1.0 - globals: ^11.1.0 - checksum: 4ad62d548ca8b95dbf45bae16cc167428f174f3c837d55a5878b1f17bdbc8b384d6df741dc7c461b62c04d881cf25644d3ab885909ba46e3ac43224e2b15b504 - languageName: node - linkType: hard - -"@babel/types@npm:^7.18.6, @babel/types@npm:^7.19.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.2, @babel/types@npm:^7.20.7, @babel/types@npm:^7.8.3": - version: 7.20.7 - resolution: "@babel/types@npm:7.20.7" - dependencies: - "@babel/helper-string-parser": ^7.19.4 - "@babel/helper-validator-identifier": ^7.19.1 - to-fast-properties: ^2.0.0 - checksum: b39af241f0b72bba67fd6d0d23914f6faec8c0eba8015c181cbd5ea92e59fc91a52a1ab490d3520c7dbd19ddb9ebb76c476308f6388764f16d8201e37fae6811 - languageName: node - linkType: hard - -"@babel/types@npm:^7.22.10, @babel/types@npm:^7.22.11, @babel/types@npm:^7.22.5": - version: 7.22.11 - resolution: "@babel/types@npm:7.22.11" - dependencies: - "@babel/helper-string-parser": ^7.22.5 - "@babel/helper-validator-identifier": ^7.22.5 - to-fast-properties: ^2.0.0 - checksum: 431a6446896adb62c876d0fe75263835735d3c974aae05356a87eb55f087c20a777028cf08eadcace7993e058bbafe3b21ce2119363222c6cef9eedd7a204810 + "@babel/helper-string-parser": "npm:^7.23.4" + "@babel/helper-validator-identifier": "npm:^7.22.20" + to-fast-properties: "npm:^2.0.0" + checksum: 10c0/777a0bb5dbe038ca4c905fdafb1cdb6bdd10fe9d63ce13eca0bd91909363cbad554a53dc1f902004b78c1dcbc742056f877f2c99eeedff647333b1fadf51235d languageName: node linkType: hard "@cycjimmy/jsmpeg-player@npm:^6.0.4": version: 6.0.5 resolution: "@cycjimmy/jsmpeg-player@npm:6.0.5" - checksum: c83c4cc2060f75d3933c889c92e6261fe207bb79e3af41538be3809a33188875363266b87cb7f70c34f3aaaf475615813ec0520b70c6eae0503f526857b4b4c0 + checksum: 10c0/f061a030fcee2b27157e5e6f196b33b9b47d4e7780a75645fd528bb447e3f766613e27136506499d95b3c5901c5a8951182dd55b154f14f637ec8ed6732074b0 languageName: node linkType: hard @@ -607,21 +385,21 @@ __metadata: version: 1.9.0 resolution: "@dermotduffy/custom-card-helpers@npm:1.9.0" dependencies: - "@formatjs/intl-utils": ^3.8.4 - home-assistant-js-websocket: ^6.0.1 - intl-messageformat: ^9.11.1 - lit: ^2.1.1 - rollup: ^2.63.0 - superstruct: ^0.15.3 - typescript: ^4.5.4 - checksum: 356b6ee436a9c07ce09f8ce435d39eae0448f3d9b4eaef1d32bd6ce3565d5a84c57624b3a28506d265bf55c86bb444e8211054bc9cdd0eb6cf08e1a5ca1e7e4d + "@formatjs/intl-utils": "npm:^3.8.4" + home-assistant-js-websocket: "npm:^6.0.1" + intl-messageformat: "npm:^9.11.1" + lit: "npm:^2.1.1" + rollup: "npm:^2.63.0" + superstruct: "npm:^0.15.3" + typescript: "npm:^4.5.4" + checksum: 10c0/312a31a9abe6ddc37109ffe2725df30e72213b4fa2cceacbb4bdb3712b46a73e49b9fb7fab69dc521050538e882d7180e3d7434011f637a34f2bc9098b880e97 languageName: node linkType: hard "@dermotduffy/panzoom@npm:^4.5.1": version: 4.5.1 resolution: "@dermotduffy/panzoom@npm:4.5.1" - checksum: 4c826f910425e50d9155005947e14bf344ec6b6a68783feb5a62f6bd2d7261cc541ceb18462552be271539a284a24b423dca27201caf45e153002fc5bf1c188e + checksum: 10c0/566f62a81714f9b836b6c0138cdc9913577c3854fe7ce6b609e26734c6692a3db5c9282945930bb6e83c0a70befa269203694f9aeb588e8831842a698c7b51cf languageName: node linkType: hard @@ -629,8 +407,8 @@ __metadata: version: 1.4.0 resolution: "@duetds/date-picker@npm:1.4.0" dependencies: - "@stencil/core": ^2.3.0 - checksum: a7b82bbf207768b6f1ad1e38893ec21ef360d48f155d5c29863cc83414adaf2537f279dec2c146631967e9ea4761eb026d78e209aa1054d3a42e31deaad3a4fc + "@stencil/core": "npm:^2.3.0" + checksum: 10c0/a3be1c26af595a96228bf045fab30585a54dd6a57175a9229da3669952025213c2a8288e32695b946d8491b623bbd2e537dc95114c5ef97cfa2c60a8c908afa2 languageName: node linkType: hard @@ -638,179 +416,211 @@ __metadata: version: 2.0.17 resolution: "@egjs/hammerjs@npm:2.0.17" dependencies: - "@types/hammerjs": ^2.0.36 - checksum: 8945137cec5837edd70af3f2e0ea621543eb0aa3b667e6269ec6485350f4d120c2434b37c7c30b1cf42a65275dd61c1f24626749c616696d3956ac0c008c4766 + "@types/hammerjs": "npm:^2.0.36" + checksum: 10c0/dbedc15a0e633f887c08394bd636faf6a3abd05726dc0909a0e01209d5860a752d9eca5e512da623aecfabe665f49f1d035de3103eb2f9022c5cea692f9cc9be languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/android-arm64@npm:0.17.15" +"@esbuild/aix-ppc64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/aix-ppc64@npm:0.19.12" + conditions: os=aix & cpu=ppc64 + languageName: node + linkType: hard + +"@esbuild/android-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/android-arm64@npm:0.19.12" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/android-arm@npm:0.17.15" +"@esbuild/android-arm@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/android-arm@npm:0.19.12" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/android-x64@npm:0.17.15" +"@esbuild/android-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/android-x64@npm:0.19.12" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/darwin-arm64@npm:0.17.15" +"@esbuild/darwin-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/darwin-arm64@npm:0.19.12" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/darwin-x64@npm:0.17.15" +"@esbuild/darwin-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/darwin-x64@npm:0.19.12" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/freebsd-arm64@npm:0.17.15" +"@esbuild/freebsd-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/freebsd-arm64@npm:0.19.12" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/freebsd-x64@npm:0.17.15" +"@esbuild/freebsd-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/freebsd-x64@npm:0.19.12" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/linux-arm64@npm:0.17.15" +"@esbuild/linux-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-arm64@npm:0.19.12" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/linux-arm@npm:0.17.15" +"@esbuild/linux-arm@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-arm@npm:0.19.12" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/linux-ia32@npm:0.17.15" +"@esbuild/linux-ia32@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-ia32@npm:0.19.12" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/linux-loong64@npm:0.17.15" +"@esbuild/linux-loong64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-loong64@npm:0.19.12" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/linux-mips64el@npm:0.17.15" +"@esbuild/linux-mips64el@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-mips64el@npm:0.19.12" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/linux-ppc64@npm:0.17.15" +"@esbuild/linux-ppc64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-ppc64@npm:0.19.12" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/linux-riscv64@npm:0.17.15" +"@esbuild/linux-riscv64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-riscv64@npm:0.19.12" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/linux-s390x@npm:0.17.15" +"@esbuild/linux-s390x@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-s390x@npm:0.19.12" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/linux-x64@npm:0.17.15" +"@esbuild/linux-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/linux-x64@npm:0.19.12" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/netbsd-x64@npm:0.17.15" +"@esbuild/netbsd-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/netbsd-x64@npm:0.19.12" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/openbsd-x64@npm:0.17.15" +"@esbuild/openbsd-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/openbsd-x64@npm:0.19.12" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/sunos-x64@npm:0.17.15" +"@esbuild/sunos-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/sunos-x64@npm:0.19.12" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/win32-arm64@npm:0.17.15" +"@esbuild/win32-arm64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/win32-arm64@npm:0.19.12" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/win32-ia32@npm:0.17.15" +"@esbuild/win32-ia32@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/win32-ia32@npm:0.19.12" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.17.15": - version: 0.17.15 - resolution: "@esbuild/win32-x64@npm:0.17.15" +"@esbuild/win32-x64@npm:0.19.12": + version: 0.19.12 + resolution: "@esbuild/win32-x64@npm:0.19.12" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@eslint/eslintrc@npm:^1.4.1": - version: 1.4.1 - resolution: "@eslint/eslintrc@npm:1.4.1" +"@eslint-community/eslint-utils@npm:^4.2.0": + version: 4.4.0 + resolution: "@eslint-community/eslint-utils@npm:4.4.0" dependencies: - ajv: ^6.12.4 - debug: ^4.3.2 - espree: ^9.4.0 - globals: ^13.19.0 - ignore: ^5.2.0 - import-fresh: ^3.2.1 - js-yaml: ^4.1.0 - minimatch: ^3.1.2 - strip-json-comments: ^3.1.1 - checksum: cd3e5a8683db604739938b1c1c8b77927dc04fce3e28e0c88e7f2cd4900b89466baf83dfbad76b2b9e4d2746abdd00dd3f9da544d3e311633d8693f327d04cd7 + eslint-visitor-keys: "npm:^3.3.0" + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + checksum: 10c0/7e559c4ce59cd3a06b1b5a517b593912e680a7f981ae7affab0d01d709e99cd5647019be8fafa38c350305bc32f1f7d42c7073edde2ab536c745e365f37b607e + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.4.0, @eslint-community/regexpp@npm:^4.6.1": + version: 4.10.0 + resolution: "@eslint-community/regexpp@npm:4.10.0" + checksum: 10c0/c5f60ef1f1ea7649fa7af0e80a5a79f64b55a8a8fa5086de4727eb4c86c652aedee407a9c143b8995d2c0b2d75c1222bec9ba5d73dbfc1f314550554f0979ef4 + languageName: node + linkType: hard + +"@eslint/eslintrc@npm:^2.1.4": + version: 2.1.4 + resolution: "@eslint/eslintrc@npm:2.1.4" + dependencies: + ajv: "npm:^6.12.4" + debug: "npm:^4.3.2" + espree: "npm:^9.6.0" + globals: "npm:^13.19.0" + ignore: "npm:^5.2.0" + import-fresh: "npm:^3.2.1" + js-yaml: "npm:^4.1.0" + minimatch: "npm:^3.1.2" + strip-json-comments: "npm:^3.1.1" + checksum: 10c0/32f67052b81768ae876c84569ffd562491ec5a5091b0c1e1ca1e0f3c24fb42f804952fdd0a137873bc64303ba368a71ba079a6f691cee25beee9722d94cc8573 + languageName: node + linkType: hard + +"@eslint/js@npm:8.57.0": + version: 8.57.0 + resolution: "@eslint/js@npm:8.57.0" + checksum: 10c0/9a518bb8625ba3350613903a6d8c622352ab0c6557a59fe6ff6178bf882bf57123f9d92aa826ee8ac3ee74b9c6203fe630e9ee00efb03d753962dcf65ee4bd94 languageName: node linkType: hard @@ -818,9 +628,9 @@ __metadata: version: 1.11.4 resolution: "@formatjs/ecma402-abstract@npm:1.11.4" dependencies: - "@formatjs/intl-localematcher": 0.2.25 - tslib: ^2.1.0 - checksum: 05dbe1c6457acfe9cdc0fc770940260e19fa588be6c655b1ff1697506348dac1eee9b249b64e6544531174d07a5a74a9e75f68430947cfdc074ebe8e3c86f86f + "@formatjs/intl-localematcher": "npm:0.2.25" + tslib: "npm:^2.1.0" + checksum: 10c0/c25d56a54f7c6a356c8475ba76ba5357bbf8cb035ab1da5a6b3b75b41a49dae6e1790271bb619e8d09aca52f1daa3e28d5fa2297297fdef5e986e213be4c84b7 languageName: node linkType: hard @@ -828,8 +638,8 @@ __metadata: version: 1.2.1 resolution: "@formatjs/fast-memoize@npm:1.2.1" dependencies: - tslib: ^2.1.0 - checksum: 7df9e941142be16e5862afe7387926cec44ec136d2c2f9a7e1598cb6c8c23a65e420ed90251ec9b48df083f5473b10d6fbbee2e9fc7233d5bf1f27efffba59a7 + tslib: "npm:^2.1.0" + checksum: 10c0/ec3d5f256ab5c889d7061f58a6c178908b3cec43831d26efdbf79db7f31a6045ab7d4448cf1829de213fa05bec144b795a632249d6a6cd566f7eb7f98daec574 languageName: node linkType: hard @@ -837,10 +647,10 @@ __metadata: version: 2.1.0 resolution: "@formatjs/icu-messageformat-parser@npm:2.1.0" dependencies: - "@formatjs/ecma402-abstract": 1.11.4 - "@formatjs/icu-skeleton-parser": 1.3.6 - tslib: ^2.1.0 - checksum: 8dab4d102b334dd7ab25b85817b074f1b54845d02f9ef9fa5a1fa6a9723176ad28a59d845fdc0eeedb868b891e61a4c530384b123db29f5b14e1f3f8b207373f + "@formatjs/ecma402-abstract": "npm:1.11.4" + "@formatjs/icu-skeleton-parser": "npm:1.3.6" + tslib: "npm:^2.1.0" + checksum: 10c0/d4d432df5232143e343a613a691abf4253f3e97a1fc0edc04b8dcdf2a88628f52fe5a47ed3e4c90ab20d843b6b4ac4c84cb883d040487d576181bfcae7f760f1 languageName: node linkType: hard @@ -848,9 +658,9 @@ __metadata: version: 1.3.6 resolution: "@formatjs/icu-skeleton-parser@npm:1.3.6" dependencies: - "@formatjs/ecma402-abstract": 1.11.4 - tslib: ^2.1.0 - checksum: cce2d8bea54f0096c557dc03920bfe4785893e60962313fab9eeee41f0b411d38b9d45852882b19f261417d730362c8685bea6ba5ac1e2dee141f030cda624e9 + "@formatjs/ecma402-abstract": "npm:1.11.4" + tslib: "npm:^2.1.0" + checksum: 10c0/47aed8193fb632e005a361c229725e2cd9e21844ef1c73995f2e64c67a15dd6c35897760a63af2345f1cbc1807d9ff8b3d90bc9d8c5d985ebfe877e079fdba27 languageName: node linkType: hard @@ -858,8 +668,8 @@ __metadata: version: 0.2.25 resolution: "@formatjs/intl-localematcher@npm:0.2.25" dependencies: - tslib: ^2.1.0 - checksum: ee00ddc23317dc47a58831aaca5112e101d8bb1f38adc0ecfe1a9d7e008d0bb1091519f07e1d7d805b0c1e28f2c3e75f697ae479e22423445814412c7669284c + tslib: "npm:^2.1.0" + checksum: 10c0/a49d5d1a09ff5d02b3c14176783f0e26978895878a35b986fafdf8ecbaa474d669eb1ee1b7a257167cb8df54d5001011d6abde691bc7f75fd123e070e87c194a languageName: node linkType: hard @@ -867,58 +677,65 @@ __metadata: version: 3.8.4 resolution: "@formatjs/intl-utils@npm:3.8.4" dependencies: - emojis-list: ^3.0.0 - checksum: e38a98d391ec68d8abc4bb1824426bd804dfb022ce61be004459faec69f7843ddb3733bae8d0dce4aafbfafad59cb10e67fc21d22d62f68d98251ce0bce8e704 - languageName: node - linkType: hard - -"@gar/promisify@npm:^1.1.3": - version: 1.1.3 - resolution: "@gar/promisify@npm:1.1.3" - checksum: 4059f790e2d07bf3c3ff3e0fec0daa8144fe35c1f6e0111c9921bd32106adaa97a4ab096ad7dab1e28ee6a9060083c4d1a4ada42a7f5f3f7a96b8812e2b757c1 + emojis-list: "npm:^3.0.0" + checksum: 10c0/737d5e796c46da0efc956a31a73a754e4e368fa1d7d7190a6c5a10192f6bab93569437a3165669fb0d435f6f054e0651f30e511f3d14bab467fd79384d0e2062 languageName: node linkType: hard "@graphiteds/core@npm:^1.9.11": - version: 1.9.11 - resolution: "@graphiteds/core@npm:1.9.11" + version: 1.9.20 + resolution: "@graphiteds/core@npm:1.9.20" dependencies: - "@duetds/date-picker": ^1.4.0 - "@popperjs/core": ^2.11.5 - "@stencil/core": ^2.20.0 - checksum: de67030f51fb165563bd73dc55a1294063f40e6de1bd55f864ea9c627069da81fbdb171de7908ae34a8c3f8d0505fd9414762bd695a0e449304d441867bc59cc + "@duetds/date-picker": "npm:^1.4.0" + "@popperjs/core": "npm:^2.11.5" + "@stencil/core": "npm:^2.20.0" + checksum: 10c0/934f79ef0a19dd581841321df5a0760c4aabdb7c2609ed5a15dbf54faf0ad8442ff86aa120e57215d56f6e914011c14debac99840d87b32929789f407698b176 languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.11.8": - version: 0.11.8 - resolution: "@humanwhocodes/config-array@npm:0.11.8" +"@humanwhocodes/config-array@npm:^0.11.14": + version: 0.11.14 + resolution: "@humanwhocodes/config-array@npm:0.11.14" dependencies: - "@humanwhocodes/object-schema": ^1.2.1 - debug: ^4.1.1 - minimatch: ^3.0.5 - checksum: 0fd6b3c54f1674ce0a224df09b9c2f9846d20b9e54fabae1281ecfc04f2e6ad69bf19e1d6af6a28f88e8aa3990168b6cb9e1ef755868c3256a630605ec2cb1d3 + "@humanwhocodes/object-schema": "npm:^2.0.2" + debug: "npm:^4.3.1" + minimatch: "npm:^3.0.5" + checksum: 10c0/66f725b4ee5fdd8322c737cb5013e19fac72d4d69c8bf4b7feb192fcb83442b035b92186f8e9497c220e58b2d51a080f28a73f7899bc1ab288c3be172c467541 languageName: node linkType: hard "@humanwhocodes/module-importer@npm:^1.0.1": version: 1.0.1 resolution: "@humanwhocodes/module-importer@npm:1.0.1" - checksum: 0fd22007db8034a2cdf2c764b140d37d9020bbfce8a49d3ec5c05290e77d4b0263b1b972b752df8c89e5eaa94073408f2b7d977aed131faf6cf396ebb5d7fb61 + checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529 languageName: node linkType: hard -"@humanwhocodes/object-schema@npm:^1.2.1": - version: 1.2.1 - resolution: "@humanwhocodes/object-schema@npm:1.2.1" - checksum: a824a1ec31591231e4bad5787641f59e9633827d0a2eaae131a288d33c9ef0290bd16fda8da6f7c0fcb014147865d12118df10db57f27f41e20da92369fcb3f1 +"@humanwhocodes/object-schema@npm:^2.0.2": + version: 2.0.2 + resolution: "@humanwhocodes/object-schema@npm:2.0.2" + checksum: 10c0/6fd83dc320231d71c4541d0244051df61f301817e9f9da9fd4cb7e44ec8aacbde5958c1665b0c419401ab935114fdf532a6ad5d4e7294b1af2f347dd91a6983f languageName: node linkType: hard -"@istanbuljs/schema@npm:^0.1.2": +"@isaacs/cliui@npm:^8.0.2": + version: 8.0.2 + resolution: "@isaacs/cliui@npm:8.0.2" + dependencies: + string-width: "npm:^5.1.2" + string-width-cjs: "npm:string-width@^4.2.0" + strip-ansi: "npm:^7.0.1" + strip-ansi-cjs: "npm:strip-ansi@^6.0.1" + wrap-ansi: "npm:^8.1.0" + wrap-ansi-cjs: "npm:wrap-ansi@^7.0.0" + checksum: 10c0/b1bf42535d49f11dc137f18d5e4e63a28c5569de438a221c369483731e9dac9fb797af554e8bf02b6192d1e5eba6e6402cf93900c3d0ac86391d00d04876789e + languageName: node + linkType: hard + +"@istanbuljs/schema@npm:^0.1.2, @istanbuljs/schema@npm:^0.1.3": version: 0.1.3 resolution: "@istanbuljs/schema@npm:0.1.3" - checksum: 5282759d961d61350f33d9118d16bcaed914ebf8061a52f4fa474b2cb08720c9c81d165e13b82f2e5a8a212cc5af482f0c6fc1ac27b9e067e5394c9a6ed186c9 + checksum: 10c0/61c5286771676c9ca3eb2bd8a7310a9c063fb6e0e9712225c8471c582d157392c88f5353581c8c9adbe0dff98892317d2fdfc56c3499aa42e0194405206a963a languageName: node linkType: hard @@ -926,111 +743,77 @@ __metadata: version: 29.6.3 resolution: "@jest/schemas@npm:29.6.3" dependencies: - "@sinclair/typebox": ^0.27.8 - checksum: 910040425f0fc93cd13e68c750b7885590b8839066dfa0cd78e7def07bbb708ad869381f725945d66f2284de5663bbecf63e8fdd856e2ae6e261ba30b1687e93 + "@sinclair/typebox": "npm:^0.27.8" + checksum: 10c0/b329e89cd5f20b9278ae1233df74016ebf7b385e0d14b9f4c1ad18d096c4c19d1e687aa113a9c976b16ec07f021ae53dea811fb8c1248a50ac34fbe009fdf6be languageName: node linkType: hard -"@jridgewell/gen-mapping@npm:^0.1.0": - version: 0.1.1 - resolution: "@jridgewell/gen-mapping@npm:0.1.1" +"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2, @jridgewell/gen-mapping@npm:^0.3.5": + version: 0.3.5 + resolution: "@jridgewell/gen-mapping@npm:0.3.5" dependencies: - "@jridgewell/set-array": ^1.0.0 - "@jridgewell/sourcemap-codec": ^1.4.10 - checksum: 3bcc21fe786de6ffbf35c399a174faab05eb23ce6a03e8769569de28abbf4facc2db36a9ddb0150545ae23a8d35a7cf7237b2aa9e9356a7c626fb4698287d5cc - languageName: node - linkType: hard - -"@jridgewell/gen-mapping@npm:^0.3.0, @jridgewell/gen-mapping@npm:^0.3.2": - version: 0.3.2 - resolution: "@jridgewell/gen-mapping@npm:0.3.2" - dependencies: - "@jridgewell/set-array": ^1.0.1 - "@jridgewell/sourcemap-codec": ^1.4.10 - "@jridgewell/trace-mapping": ^0.3.9 - checksum: 1832707a1c476afebe4d0fbbd4b9434fdb51a4c3e009ab1e9938648e21b7a97049fa6009393bdf05cab7504108413441df26d8a3c12193996e65493a4efb6882 - languageName: node - linkType: hard - -"@jridgewell/resolve-uri@npm:3.1.0": - version: 3.1.0 - resolution: "@jridgewell/resolve-uri@npm:3.1.0" - checksum: b5ceaaf9a110fcb2780d1d8f8d4a0bfd216702f31c988d8042e5f8fbe353c55d9b0f55a1733afdc64806f8e79c485d2464680ac48a0d9fcadb9548ee6b81d267 + "@jridgewell/set-array": "npm:^1.2.1" + "@jridgewell/sourcemap-codec": "npm:^1.4.10" + "@jridgewell/trace-mapping": "npm:^0.3.24" + checksum: 10c0/1be4fd4a6b0f41337c4f5fdf4afc3bd19e39c3691924817108b82ffcb9c9e609c273f936932b9fba4b3a298ce2eb06d9bff4eb1cc3bd81c4f4ee1b4917e25feb languageName: node linkType: hard "@jridgewell/resolve-uri@npm:^3.1.0": - version: 3.1.1 - resolution: "@jridgewell/resolve-uri@npm:3.1.1" - checksum: f5b441fe7900eab4f9155b3b93f9800a916257f4e8563afbcd3b5a5337b55e52bd8ae6735453b1b745457d9f6cdb16d74cd6220bbdd98cf153239e13f6cbb653 + version: 3.1.2 + resolution: "@jridgewell/resolve-uri@npm:3.1.2" + checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e languageName: node linkType: hard -"@jridgewell/set-array@npm:^1.0.0, @jridgewell/set-array@npm:^1.0.1": - version: 1.1.2 - resolution: "@jridgewell/set-array@npm:1.1.2" - checksum: 69a84d5980385f396ff60a175f7177af0b8da4ddb81824cb7016a9ef914eee9806c72b6b65942003c63f7983d4f39a5c6c27185bbca88eb4690b62075602e28e +"@jridgewell/set-array@npm:^1.2.1": + version: 1.2.1 + resolution: "@jridgewell/set-array@npm:1.2.1" + checksum: 10c0/2a5aa7b4b5c3464c895c802d8ae3f3d2b92fcbe84ad12f8d0bfbb1f5ad006717e7577ee1fd2eac00c088abe486c7adb27976f45d2941ff6b0b92b2c3302c60f4 languageName: node linkType: hard -"@jridgewell/source-map@npm:^0.3.2": - version: 0.3.2 - resolution: "@jridgewell/source-map@npm:0.3.2" +"@jridgewell/source-map@npm:^0.3.3": + version: 0.3.5 + resolution: "@jridgewell/source-map@npm:0.3.5" dependencies: - "@jridgewell/gen-mapping": ^0.3.0 - "@jridgewell/trace-mapping": ^0.3.9 - checksum: 1b83f0eb944e77b70559a394d5d3b3f98a81fcc186946aceb3ef42d036762b52ef71493c6c0a3b7c1d2f08785f53ba2df1277fe629a06e6109588ff4cdcf7482 + "@jridgewell/gen-mapping": "npm:^0.3.0" + "@jridgewell/trace-mapping": "npm:^0.3.9" + checksum: 10c0/b985d9ebd833a21a6e9ace820c8a76f60345a34d9e28d98497c16b6e93ce1f131bff0abd45f8585f14aa382cce678ed680d628c631b40a9616a19cfbc2049b68 languageName: node linkType: hard -"@jridgewell/sourcemap-codec@npm:1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.10": - version: 1.4.14 - resolution: "@jridgewell/sourcemap-codec@npm:1.4.14" - checksum: 61100637b6d173d3ba786a5dff019e1a74b1f394f323c1fee337ff390239f053b87266c7a948777f4b1ee68c01a8ad0ab61e5ff4abb5a012a0b091bec391ab97 - languageName: node - linkType: hard - -"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.15": +"@jridgewell/sourcemap-codec@npm:^1.4.10, @jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.4.15": version: 1.4.15 resolution: "@jridgewell/sourcemap-codec@npm:1.4.15" - checksum: b881c7e503db3fc7f3c1f35a1dd2655a188cc51a3612d76efc8a6eb74728bef5606e6758ee77423e564092b4a518aba569bbb21c9bac5ab7a35b0c6ae7e344c8 + checksum: 10c0/0c6b5ae663087558039052a626d2d7ed5208da36cfd707dcc5cea4a07cfc918248403dcb5989a8f7afaf245ce0573b7cc6fd94c4a30453bd10e44d9363940ba5 languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.17": - version: 0.3.19 - resolution: "@jridgewell/trace-mapping@npm:0.3.19" +"@jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.9": + version: 0.3.24 + resolution: "@jridgewell/trace-mapping@npm:0.3.24" dependencies: - "@jridgewell/resolve-uri": ^3.1.0 - "@jridgewell/sourcemap-codec": ^1.4.14 - checksum: 956a6f0f6fec060fb48c6bf1f5ec2064e13cd38c8be3873877d4b92b4a27ba58289a34071752671262a3e3c202abcc3fa2aac64d8447b4b0fa1ba3c9047f1c20 + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10c0/5d6656c439f67cee8bc196a72ceebc446c23924dba6c67806fd3dfefb3ef4c8b2168ea44a0293d8c33c71b88e60862e0397576ef8707e4321e64898fec7a0189 languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.9": - version: 0.3.17 - resolution: "@jridgewell/trace-mapping@npm:0.3.17" +"@lit-labs/scoped-registry-mixin@npm:^1.0.3": + version: 1.0.3 + resolution: "@lit-labs/scoped-registry-mixin@npm:1.0.3" dependencies: - "@jridgewell/resolve-uri": 3.1.0 - "@jridgewell/sourcemap-codec": 1.4.14 - checksum: 9d703b859cff5cd83b7308fd457a431387db5db96bd781a63bf48e183418dd9d3d44e76b9e4ae13237f6abeeb25d739ec9215c1d5bfdd08f66f750a50074a339 + "@lit/reactive-element": "npm:^1.0.0 || ^2.0.0" + lit: "npm:^2.0.0 || ^3.0.0" + checksum: 10c0/eb03fd10ba400eb80ef7acac84a128a10f595dc38ad8e9d559d5fd141e36b51441a79c262852e91560ea60437815e65e216098537a5baf2f1fe2cb5404377620 languageName: node linkType: hard -"@lit-labs/scoped-registry-mixin@npm:^1.0.1": - version: 1.0.1 - resolution: "@lit-labs/scoped-registry-mixin@npm:1.0.1" - dependencies: - "@lit/reactive-element": ^1.0.0 - lit: ^2.0.0 - checksum: 94a86c8329d27b0f7e3b6ec1928c0eb7efc64f6dc2ed2d5cce09184650e465ce63e77ca4fec95d508583ea0d793fe0495b75a7b0830f5c1f951caa28d7d51842 - languageName: node - linkType: hard - -"@lit-labs/ssr-dom-shim@npm:^1.0.0": - version: 1.0.0 - resolution: "@lit-labs/ssr-dom-shim@npm:1.0.0" - checksum: ccba6675ad631c6f7360af4e12e328e88d877a52ec992ae9254a1be9902ef699b7916d851b073803dd91244d0f709de2c0539a7db643889cfe341ff6e1a74eb5 +"@lit-labs/ssr-dom-shim@npm:^1.0.0, @lit-labs/ssr-dom-shim@npm:^1.1.0, @lit-labs/ssr-dom-shim@npm:^1.2.0": + version: 1.2.0 + resolution: "@lit-labs/ssr-dom-shim@npm:1.2.0" + checksum: 10c0/016168cf6901ab343462c13fb168dda6d549f8b42680aa394e6b7cd0af7cce51271e00dbfa5bbbe388912bf89cbb8f941a21cc3ec9bf95d6a84b6241aa9e5a72 languageName: node linkType: hard @@ -1038,17 +821,26 @@ __metadata: version: 1.1.3 resolution: "@lit-labs/task@npm:1.1.3" dependencies: - "@lit/reactive-element": ^1.1.0 - checksum: 82b3680a8b6d5c447364857a0beb8e28237c05fdffe06456183196521000b4fcd696da374f17d28020248042bda2af7d4ddf9adbe40309c32e6672afa6e58935 + "@lit/reactive-element": "npm:^1.1.0" + checksum: 10c0/bea28fbd87a486a06d4f2f51ba63db27419e659a97e723dc6c0009375262fb0f526a7436273589830fdf42dc1117f7aec372c5bf975c6adfca69cf64eaeecfd0 languageName: node linkType: hard -"@lit/reactive-element@npm:^1.0.0, @lit/reactive-element@npm:^1.1.0, @lit/reactive-element@npm:^1.3.0, @lit/reactive-element@npm:^1.6.0": - version: 1.6.1 - resolution: "@lit/reactive-element@npm:1.6.1" +"@lit/reactive-element@npm:^1.0.0 || ^2.0.0, @lit/reactive-element@npm:^2.0.4": + version: 2.0.4 + resolution: "@lit/reactive-element@npm:2.0.4" dependencies: - "@lit-labs/ssr-dom-shim": ^1.0.0 - checksum: fab0bcfdade9c26af2ad5115fb564bcf8ba0732a3a8be86c157851c2771e3fdc65ab38f2cd60fa121946058bf6e487461fd217f87b01f96e88ee7a95d5d866ba + "@lit-labs/ssr-dom-shim": "npm:^1.2.0" + checksum: 10c0/359cc19ea9ee8b65e1417eb9c12f40dddba8f0a5ab32f0e5facaecee6060629e44eb4ca27d9af945fe6eda8c033aa636abaa5f0c4e6a529b224d78674acf47ba + languageName: node + linkType: hard + +"@lit/reactive-element@npm:^1.1.0, @lit/reactive-element@npm:^1.3.0, @lit/reactive-element@npm:^1.6.0": + version: 1.6.3 + resolution: "@lit/reactive-element@npm:1.6.3" + dependencies: + "@lit-labs/ssr-dom-shim": "npm:^1.0.0" + checksum: 10c0/10f1d25e24e32feb21c4c6f9e11d062901241602e12c4ecf746b3138f87fed4d8394194645514d5c1bfd5f33f3fd56ee8ef41344e2cb4413c40fe4961ec9d419 languageName: node linkType: hard @@ -1056,16 +848,16 @@ __metadata: version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" dependencies: - "@nodelib/fs.stat": 2.0.5 - run-parallel: ^1.1.9 - checksum: a970d595bd23c66c880e0ef1817791432dbb7acbb8d44b7e7d0e7a22f4521260d4a83f7f9fd61d44fda4610105577f8f58a60718105fb38352baed612fd79e59 + "@nodelib/fs.stat": "npm:2.0.5" + run-parallel: "npm:^1.1.9" + checksum: 10c0/732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb languageName: node linkType: hard "@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": version: 2.0.5 resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 012480b5ca9d97bff9261571dbbec7bbc6033f69cc92908bc1ecfad0792361a5a1994bc48674b9ef76419d056a03efadfce5a6cf6dbc0a36559571a7a483f6f0 + checksum: 10c0/88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d languageName: node linkType: hard @@ -1073,36 +865,45 @@ __metadata: version: 1.2.8 resolution: "@nodelib/fs.walk@npm:1.2.8" dependencies: - "@nodelib/fs.scandir": 2.1.5 - fastq: ^1.6.0 - checksum: 190c643f156d8f8f277bf2a6078af1ffde1fd43f498f187c2db24d35b4b4b5785c02c7dc52e356497b9a1b65b13edc996de08de0b961c32844364da02986dc53 + "@nodelib/fs.scandir": "npm:2.1.5" + fastq: "npm:^1.6.0" + checksum: 10c0/db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1 languageName: node linkType: hard -"@npmcli/fs@npm:^2.1.0": - version: 2.1.2 - resolution: "@npmcli/fs@npm:2.1.2" +"@npmcli/agent@npm:^2.0.0": + version: 2.2.1 + resolution: "@npmcli/agent@npm:2.2.1" dependencies: - "@gar/promisify": ^1.1.3 - semver: ^7.3.5 - checksum: 405074965e72d4c9d728931b64d2d38e6ea12066d4fad651ac253d175e413c06fe4350970c783db0d749181da8fe49c42d3880bd1cbc12cd68e3a7964d820225 + agent-base: "npm:^7.1.0" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.1" + lru-cache: "npm:^10.0.1" + socks-proxy-agent: "npm:^8.0.1" + checksum: 10c0/38ee5cbe8f3cde13be916e717bfc54fd1a7605c07af056369ff894e244c221e0b56b08ca5213457477f9bc15bca9e729d51a4788829b5c3cf296b3c996147f76 languageName: node linkType: hard -"@npmcli/move-file@npm:^2.0.0": - version: 2.0.1 - resolution: "@npmcli/move-file@npm:2.0.1" +"@npmcli/fs@npm:^3.1.0": + version: 3.1.0 + resolution: "@npmcli/fs@npm:3.1.0" dependencies: - mkdirp: ^1.0.4 - rimraf: ^3.0.2 - checksum: 52dc02259d98da517fae4cb3a0a3850227bdae4939dda1980b788a7670636ca2b4a01b58df03dd5f65c1e3cb70c50fa8ce5762b582b3f499ec30ee5ce1fd9380 + semver: "npm:^7.3.5" + checksum: 10c0/162b4a0b8705cd6f5c2470b851d1dc6cd228c86d2170e1769d738c1fbb69a87160901411c3c035331e9e99db72f1f1099a8b734bf1637cc32b9a5be1660e4e1e + languageName: node + linkType: hard + +"@pkgjs/parseargs@npm:^0.11.0": + version: 0.11.0 + resolution: "@pkgjs/parseargs@npm:0.11.0" + checksum: 10c0/5bd7576bb1b38a47a7fc7b51ac9f38748e772beebc56200450c4a817d712232b8f1d3ef70532c80840243c657d491cf6a6be1e3a214cff907645819fdc34aadd languageName: node linkType: hard "@popperjs/core@npm:^2.11.5": - version: 2.11.6 - resolution: "@popperjs/core@npm:2.11.6" - checksum: 47fb328cec1924559d759b48235c78574f2d71a8a6c4c03edb6de5d7074078371633b91e39bbf3f901b32aa8af9b9d8f82834856d2f5737a23475036b16817f0 + version: 2.11.8 + resolution: "@popperjs/core@npm:2.11.8" + checksum: 10c0/4681e682abc006d25eb380d0cf3efc7557043f53b6aea7a5057d0d1e7df849a00e281cd8ea79c902a35a414d7919621fc2ba293ecec05f413598e0b23d5a1e63 languageName: node linkType: hard @@ -1110,8 +911,8 @@ __metadata: version: 5.3.1 resolution: "@rollup/plugin-babel@npm:5.3.1" dependencies: - "@babel/helper-module-imports": ^7.10.4 - "@rollup/pluginutils": ^3.1.0 + "@babel/helper-module-imports": "npm:^7.10.4" + "@rollup/pluginutils": "npm:^3.1.0" peerDependencies: "@babel/core": ^7.0.0 "@types/babel__core": ^7.1.9 @@ -1119,7 +920,7 @@ __metadata: peerDependenciesMeta: "@types/babel__core": optional: true - checksum: 220d71e4647330f252ef33d5f29700aef2e8284a0b61acfcceb47617a7f96208aa1ed16eae75619424bf08811ede5241e271a6d031f07026dee6b3a2bdcdc638 + checksum: 10c0/2766134dd5567c0d4fd6909d1f511ce9bf3bd9d727e1bc5ffdd6097a3606faca324107ae8e0961839ee4dbb45e5e579ae601efe472fc0a271259aea79920cafa languageName: node linkType: hard @@ -1127,31 +928,31 @@ __metadata: version: 22.0.2 resolution: "@rollup/plugin-commonjs@npm:22.0.2" dependencies: - "@rollup/pluginutils": ^3.1.0 - commondir: ^1.0.1 - estree-walker: ^2.0.1 - glob: ^7.1.6 - is-reference: ^1.2.1 - magic-string: ^0.25.7 - resolve: ^1.17.0 + "@rollup/pluginutils": "npm:^3.1.0" + commondir: "npm:^1.0.1" + estree-walker: "npm:^2.0.1" + glob: "npm:^7.1.6" + is-reference: "npm:^1.2.1" + magic-string: "npm:^0.25.7" + resolve: "npm:^1.17.0" peerDependencies: rollup: ^2.68.0 - checksum: 70098a4b91afe3f164f5d27cba65edf148c5ed146ee0e07a964b66940681553ac77391083114cdcf9427e7f2706bf0d61eab310b3a2caeab83b7452c0292fcae + checksum: 10c0/2b9df23a40493e5ca6dab50b28a7803c0fe73f5fe84c16f38e3e00e38b9a246de450d1ee8dba145ea5dc3c661616a4ae1927b084fdbb47ae3afcac979fdfa1d1 languageName: node linkType: hard "@rollup/plugin-image@npm:^3.0.2": - version: 3.0.2 - resolution: "@rollup/plugin-image@npm:3.0.2" + version: 3.0.3 + resolution: "@rollup/plugin-image@npm:3.0.3" dependencies: - "@rollup/pluginutils": ^5.0.1 - mini-svg-data-uri: ^1.4.4 + "@rollup/pluginutils": "npm:^5.0.1" + mini-svg-data-uri: "npm:^1.4.4" peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true - checksum: f9d8f587f10c51398fa8c23f1543e3073f969cf7e4acd7f401e02a3e3752702a9eb289ddb14009733ce37d04474c549aba9e7d13ebf50e26226266ba51546b69 + checksum: 10c0/e699e52c44b1799df887f72959779c9d2af11f04b23ed84dc7a4c423f72c66b14510c8a366a9856e07047fbabbd6e94c1972fcced2c80b2c5e7e91e8414e8b48 languageName: node linkType: hard @@ -1159,10 +960,10 @@ __metadata: version: 4.1.0 resolution: "@rollup/plugin-json@npm:4.1.0" dependencies: - "@rollup/pluginutils": ^3.0.8 + "@rollup/pluginutils": "npm:^3.0.8" peerDependencies: rollup: ^1.20.0 || ^2.0.0 - checksum: 867bc9339b4ccf0b9ff3b2617a95b3b8920115163f86c8e3b1f068a14ca25949472d3c05b09a5ac38ca0fe2185756e34617eaeb219d4a2b6e2307c501c7d4552 + checksum: 10c0/9fc4a3ee60929afcb5269ebda602914d1cf5dc020808f85be90c0a5a2ba9ca26136b0284a1935984861f0549a1e1db30fc372906c14425f5da4909f0fd21e5ea languageName: node linkType: hard @@ -1170,15 +971,15 @@ __metadata: version: 13.3.0 resolution: "@rollup/plugin-node-resolve@npm:13.3.0" dependencies: - "@rollup/pluginutils": ^3.1.0 - "@types/resolve": 1.17.1 - deepmerge: ^4.2.2 - is-builtin-module: ^3.1.0 - is-module: ^1.0.0 - resolve: ^1.19.0 + "@rollup/pluginutils": "npm:^3.1.0" + "@types/resolve": "npm:1.17.1" + deepmerge: "npm:^4.2.2" + is-builtin-module: "npm:^3.1.0" + is-module: "npm:^1.0.0" + resolve: "npm:^1.19.0" peerDependencies: rollup: ^2.42.0 - checksum: ec5418e6b3c23a9e30683056b3010e9d325316dcfae93fbc673ae64dad8e56a2ce761c15c48f5e2dcfe0c822fdc4a4905ee6346e3dcf90603ba2260afef5a5e6 + checksum: 10c0/6caa32a8304a20f1c9953111b25e9543f4de7d254958d81ce0158ad909e4493946bc2060c4ace23d9748b560ebc84c920ee7bc1b7d50dbf8ba852ef13c91af58 languageName: node linkType: hard @@ -1186,11 +987,11 @@ __metadata: version: 4.0.0 resolution: "@rollup/plugin-replace@npm:4.0.0" dependencies: - "@rollup/pluginutils": ^3.1.0 - magic-string: ^0.25.7 + "@rollup/pluginutils": "npm:^3.1.0" + magic-string: "npm:^0.25.7" peerDependencies: rollup: ^1.20.0 || ^2.0.0 - checksum: b61701e612661a46da06ca88f390c3839b586708abc0329a476411b90aa8ac59fe94437ede4c3fe53fea268b3054ea9d7d4ee851d7bd0cb7a5f06906002067cb + checksum: 10c0/90c8983ec6944dcc85bb8f0a4448a57329f43662ca5d6ebf26aad97c3871d39ba7f2d344569bc93f35eb57ddd697470b6fcb255cd1f4a9331f3334b16cb3c1aa languageName: node linkType: hard @@ -1198,12 +999,12 @@ __metadata: version: 3.1.0 resolution: "@rollup/pluginutils@npm:3.1.0" dependencies: - "@types/estree": 0.0.39 - estree-walker: ^1.0.1 - picomatch: ^2.2.2 + "@types/estree": "npm:0.0.39" + estree-walker: "npm:^1.0.1" + picomatch: "npm:^2.2.2" peerDependencies: rollup: ^1.20.0||^2.0.0 - checksum: 8be16e27863c219edbb25a4e6ec2fe0e1e451d9e917b6a43cf2ae5bc025a6b8faaa40f82a6e53b66d0de37b58ff472c6c3d57a83037ae635041f8df959d6d9aa + checksum: 10c0/7151753160d15ba2b259461a6c25b3932150994ea52dba8fd3144f634c7647c2e56733d986e2c15de67c4d96a9ee7d6278efa6d2e626a7169898fd64adc0f90c languageName: node linkType: hard @@ -1211,55 +1012,146 @@ __metadata: version: 4.2.1 resolution: "@rollup/pluginutils@npm:4.2.1" dependencies: - estree-walker: ^2.0.1 - picomatch: ^2.2.2 - checksum: 6bc41f22b1a0f1efec3043899e4d3b6b1497b3dea4d94292d8f83b4cf07a1073ecbaedd562a22d11913ff7659f459677b01b09e9598a98936e746780ecc93a12 + estree-walker: "npm:^2.0.1" + picomatch: "npm:^2.2.2" + checksum: 10c0/3ee56b2c8f1ed8dfd0a92631da1af3a2dfdd0321948f089b3752b4de1b54dc5076701eadd0e5fc18bd191b77af594ac1db6279e83951238ba16bf8a414c64c48 languageName: node linkType: hard "@rollup/pluginutils@npm:^5.0.1": - version: 5.0.2 - resolution: "@rollup/pluginutils@npm:5.0.2" + version: 5.1.0 + resolution: "@rollup/pluginutils@npm:5.1.0" dependencies: - "@types/estree": ^1.0.0 - estree-walker: ^2.0.2 - picomatch: ^2.3.1 + "@types/estree": "npm:^1.0.0" + estree-walker: "npm:^2.0.2" + picomatch: "npm:^2.3.1" peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true - checksum: edea15e543bebc7dcac3b0ac8bc7b8e8e6dbd46e2864dbe5dd28072de1fbd5b0e10d545a610c0edaa178e8a7ac432e2a2a52e547ece1308471412caba47db8ce + checksum: 10c0/c7bed15711f942d6fdd3470fef4105b73991f99a478605e13d41888963330a6f9e32be37e6ddb13f012bc7673ff5e54f06f59fd47109436c1c513986a8a7612d + languageName: node + linkType: hard + +"@rollup/rollup-android-arm-eabi@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-android-arm-eabi@npm:4.12.0" + conditions: os=android & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-android-arm64@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-android-arm64@npm:4.12.0" + conditions: os=android & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-arm64@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-darwin-arm64@npm:4.12.0" + conditions: os=darwin & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-darwin-x64@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-darwin-x64@npm:4.12.0" + conditions: os=darwin & cpu=x64 + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm-gnueabihf@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-linux-arm-gnueabihf@npm:4.12.0" + conditions: os=linux & cpu=arm + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-gnu@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-linux-arm64-gnu@npm:4.12.0" + conditions: os=linux & cpu=arm64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-arm64-musl@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-linux-arm64-musl@npm:4.12.0" + conditions: os=linux & cpu=arm64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-linux-riscv64-gnu@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-linux-riscv64-gnu@npm:4.12.0" + conditions: os=linux & cpu=riscv64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-gnu@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-linux-x64-gnu@npm:4.12.0" + conditions: os=linux & cpu=x64 & libc=glibc + languageName: node + linkType: hard + +"@rollup/rollup-linux-x64-musl@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-linux-x64-musl@npm:4.12.0" + conditions: os=linux & cpu=x64 & libc=musl + languageName: node + linkType: hard + +"@rollup/rollup-win32-arm64-msvc@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-win32-arm64-msvc@npm:4.12.0" + conditions: os=win32 & cpu=arm64 + languageName: node + linkType: hard + +"@rollup/rollup-win32-ia32-msvc@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-win32-ia32-msvc@npm:4.12.0" + conditions: os=win32 & cpu=ia32 + languageName: node + linkType: hard + +"@rollup/rollup-win32-x64-msvc@npm:4.12.0": + version: 4.12.0 + resolution: "@rollup/rollup-win32-x64-msvc@npm:4.12.0" + conditions: os=win32 & cpu=x64 languageName: node linkType: hard "@sinclair/typebox@npm:^0.27.8": version: 0.27.8 resolution: "@sinclair/typebox@npm:0.27.8" - checksum: 00bd7362a3439021aa1ea51b0e0d0a0e8ca1351a3d54c606b115fdcc49b51b16db6e5f43b4fe7a28c38688523e22a94d49dd31168868b655f0d4d50f032d07a1 + checksum: 10c0/ef6351ae073c45c2ac89494dbb3e1f87cc60a93ce4cde797b782812b6f97da0d620ae81973f104b43c9b7eaa789ad20ba4f6a1359f1cc62f63729a55a7d22d4e languageName: node linkType: hard "@stencil/core@npm:^2.20.0, @stencil/core@npm:^2.3.0": - version: 2.22.2 - resolution: "@stencil/core@npm:2.22.2" + version: 2.22.3 + resolution: "@stencil/core@npm:2.22.3" bin: stencil: bin/stencil - checksum: 139a7b63b81c7eaa5026e76e1c947a402f58d0a6d1d353a34883995ea7e480fa6991e71c0c3d812f7046d395b99d0f7f7b11af9277f04a3c62aba96cda18dd5d + checksum: 10c0/6df88e165ec0cf132b1dbdb71d61399359974c7533a20b5e2bcee5f9ab4495a63dff5cbb4b2687639ee711c91ef36ac55af45e613464e4f904ce346f490b04dc languageName: node linkType: hard "@tootallnate/once@npm:2": version: 2.0.0 resolution: "@tootallnate/once@npm:2.0.0" - checksum: ad87447820dd3f24825d2d947ebc03072b20a42bfc96cbafec16bff8bbda6c1a81fcb0be56d5b21968560c5359a0af4038a68ba150c3e1694fe4c109a063bed8 + checksum: 10c0/073bfa548026b1ebaf1659eb8961e526be22fa77139b10d60e712f46d2f0f05f4e6c8bec62a087d41088ee9e29faa7f54838568e475ab2f776171003c3920858 languageName: node linkType: hard "@trysound/sax@npm:0.2.0": version: 0.2.0 resolution: "@trysound/sax@npm:0.2.0" - checksum: 11226c39b52b391719a2a92e10183e4260d9651f86edced166da1d95f39a0a1eaa470e44d14ac685ccd6d3df7e2002433782872c0feeb260d61e80f21250e65c + checksum: 10c0/44907308549ce775a41c38a815f747009ac45929a45d642b836aa6b0a536e4978d30b8d7d680bbd116e9dd73b7dbe2ef0d1369dcfc2d09e83ba381e485ecbe12 languageName: node linkType: hard @@ -1267,133 +1159,112 @@ __metadata: version: 0.12.3 resolution: "@ts-morph/common@npm:0.12.3" dependencies: - fast-glob: ^3.2.7 - minimatch: ^3.0.4 - mkdirp: ^1.0.4 - path-browserify: ^1.0.1 - checksum: d96ea9805d4f0300cc05c47daa9454438903b86ffb7116f5181a1eba71e881012a1adc2a867b3afbe4429ef29e3e0d6204175cbaf33ecdd7a7d09b5d8a37f12d + fast-glob: "npm:^3.2.7" + minimatch: "npm:^3.0.4" + mkdirp: "npm:^1.0.4" + path-browserify: "npm:^1.0.1" + checksum: 10c0/2a0b25128eca547cfdf4795d39e7d6e15c81008b74867ccdda9d0d9c1b0eaca534d6d729220572e726a811786efa3c38f3b6a482d3fc970d3bf0acea39a7248f languageName: node linkType: hard "@types/bluebird@npm:^3.5.36": - version: 3.5.38 - resolution: "@types/bluebird@npm:3.5.38" - checksum: 8d1b04261e8e58816ec84ffa616c9e641c9416d0ab10c915ddb9cd8a0e7070af16df4f2eec243a3809cbed8ecee2fb3f45600ae43b3ab0ceea563aa18ceb6ab1 - languageName: node - linkType: hard - -"@types/chai-subset@npm:^1.3.3": - version: 1.3.3 - resolution: "@types/chai-subset@npm:1.3.3" - dependencies: - "@types/chai": "*" - checksum: 4481da7345022995f5a105e6683744f7203d2c3d19cfe88d8e17274d045722948abf55e0adfd97709e0f043dade37a4d4e98cd4c660e2e8a14f23e6ecf79418f - languageName: node - linkType: hard - -"@types/chai@npm:*": - version: 4.3.4 - resolution: "@types/chai@npm:4.3.4" - checksum: 571184967beb03bf64c4392a13a7d44e72da9af5a1e83077ff81c39cf59c0fda2a5c78d2005084601cf8f3d11726608574d8b5b4a0e3e9736792807afd926cd0 - languageName: node - linkType: hard - -"@types/chai@npm:^4.3.5": - version: 4.3.5 - resolution: "@types/chai@npm:4.3.5" - checksum: c8f26a88c6b5b53a3275c7f5ff8f107028e3cbb9ff26795fff5f3d9dea07106a54ce9e2dce5e40347f7c4cc35657900aaf0c83934a25a1ae12e61e0f5516e431 + version: 3.5.42 + resolution: "@types/bluebird@npm:3.5.42" + checksum: 10c0/ce752a5e277bbc0cdee3dee9c875ac093d1331905a8a5175665ccb8cb76b7b95a84836f92bc46076c2fd1e384a107866893eeeb20f6fb33427482663879faf93 languageName: node linkType: hard "@types/cssnano@npm:^5.0.0": - version: 5.1.0 - resolution: "@types/cssnano@npm:5.1.0" + version: 5.0.0 + resolution: "@types/cssnano@npm:5.0.0" dependencies: - cssnano: "*" - checksum: 4cce9e5d041a6276cd2e4bc3fce3e9ef5cd53531f86cedee2e9abdd12b050fb927e7a68a87043dbfa222f74ad3eced377d677a113b4772ec7297c737cdab0d74 + postcss: "npm:^8" + checksum: 10c0/3b939509d65c053c274dc261cef17d9329e02d82784b569e441e01fb61dbcd5c914c5f7f53499cc641a1b224c30a9c814e419f8cb682be249d87fa2ddc20e9ae languageName: node linkType: hard -"@types/estree@npm:*, @types/estree@npm:^1.0.0": - version: 1.0.0 - resolution: "@types/estree@npm:1.0.0" - checksum: 910d97fb7092c6738d30a7430ae4786a38542023c6302b95d46f49420b797f21619cdde11fa92b338366268795884111c2eb10356e4bd2c8ad5b92941e9e6443 +"@types/estree@npm:*, @types/estree@npm:1.0.5, @types/estree@npm:^1.0.0": + version: 1.0.5 + resolution: "@types/estree@npm:1.0.5" + checksum: 10c0/b3b0e334288ddb407c7b3357ca67dbee75ee22db242ca7c56fe27db4e1a31989cb8af48a84dd401deb787fe10cc6b2ab1ee82dc4783be87ededbe3d53c79c70d languageName: node linkType: hard "@types/estree@npm:0.0.39": version: 0.0.39 resolution: "@types/estree@npm:0.0.39" - checksum: 412fb5b9868f2c418126451821833414189b75cc6bf84361156feed733e3d92ec220b9d74a89e52722e03d5e241b2932732711b7497374a404fad49087adc248 + checksum: 10c0/f0af6c95ac1988c4827964bd9d3b51d24da442e2188943f6dfcb1e1559103d5d024d564b2e9d3f84c53714a02a0a7435c7441138eb63d9af5de4dfc66cdc0d92 languageName: node linkType: hard "@types/hammerjs@npm:^2.0.36": - version: 2.0.41 - resolution: "@types/hammerjs@npm:2.0.41" - checksum: d16fbd688fc9b18cc270abe8dea8d4c50ef7bd8375e593d92c233d299387933a6b003c8db69819344833052458bc5f9ef1b472001277a49f095928d184356006 + version: 2.0.45 + resolution: "@types/hammerjs@npm:2.0.45" + checksum: 10c0/1f01e3d0260e3cb824fd0ae32c9a8e1b3727e53ef31682612a0a282c4a84bb758dd30b04749b2ae91e621443c80bfe541b38e91e33308f9dea5d9ac92bd0e854 languageName: node linkType: hard "@types/jquery@npm:*": - version: 3.5.16 - resolution: "@types/jquery@npm:3.5.16" + version: 3.5.29 + resolution: "@types/jquery@npm:3.5.29" dependencies: - "@types/sizzle": "*" - checksum: 13c995f15d1c2f1d322103dc1cb0a22b95eecc3e7546f00279b8731aea21d7ec04550af40e609ee48e755d4e11bf61c25b4aa9f53df3bcbec4b8fe8e81471732 + "@types/sizzle": "npm:*" + checksum: 10c0/17409b551956c54d641264895790b9e63a2179bacdabe2a87d5f8f2baebe2f16625d111b17b1441cdffbf9e059e683bb25bf04ba6ea56b36e39ea50cc77f5b8c languageName: node linkType: hard "@types/json-schema@npm:^7.0.9": - version: 7.0.11 - resolution: "@types/json-schema@npm:7.0.11" - checksum: 527bddfe62db9012fccd7627794bd4c71beb77601861055d87e3ee464f2217c85fca7a4b56ae677478367bbd248dbde13553312b7d4dbc702a2f2bbf60c4018d + version: 7.0.15 + resolution: "@types/json-schema@npm:7.0.15" + checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db languageName: node linkType: hard "@types/json5@npm:^0.0.29": version: 0.0.29 resolution: "@types/json5@npm:0.0.29" - checksum: e60b153664572116dfea673c5bda7778dbff150498f44f998e34b5886d8afc47f16799280e4b6e241c0472aef1bc36add771c569c68fc5125fc2ae519a3eb9ac + checksum: 10c0/6bf5337bc447b706bb5b4431d37686aa2ea6d07cfd6f79cc31de80170d6ff9b1c7384a9c0ccbc45b3f512bae9e9f75c2e12109806a15331dc94e8a8db6dbb4ac languageName: node linkType: hard "@types/lodash-es@npm:^4.17.5": - version: 4.17.6 - resolution: "@types/lodash-es@npm:4.17.6" + version: 4.17.12 + resolution: "@types/lodash-es@npm:4.17.12" dependencies: - "@types/lodash": "*" - checksum: 9bd239dd525086e278821949ce12fbdd4f100a060fed9323fc7ad5661113e1641f28a7ebab617230ed3474680d8f4de705c1928b48252bb684be6ec9eed715db + "@types/lodash": "npm:*" + checksum: 10c0/5d12d2cede07f07ab067541371ed1b838a33edb3c35cb81b73284e93c6fd0c4bbeaefee984e69294bffb53f62d7272c5d679fdba8e595ff71e11d00f2601dde0 languageName: node linkType: hard "@types/lodash@npm:*": - version: 4.14.191 - resolution: "@types/lodash@npm:4.14.191" - checksum: ba0d5434e10690869f32d5ea49095250157cae502f10d57de0a723fd72229ce6c6a4979576f0f13e0aa9fbe3ce2457bfb9fa7d4ec3d6daba56730a51906d1491 + version: 4.14.202 + resolution: "@types/lodash@npm:4.14.202" + checksum: 10c0/6064d43c8f454170841bd67c8266cc9069d9e570a72ca63f06bceb484cb4a3ee60c9c1f305c1b9e3a87826049fd41124b8ef265c4dd08b00f6766609c7fe9973 languageName: node linkType: hard "@types/masonry-layout@npm:^4.2.5": - version: 4.2.5 - resolution: "@types/masonry-layout@npm:4.2.5" + version: 4.2.7 + resolution: "@types/masonry-layout@npm:4.2.7" dependencies: - "@types/jquery": "*" - checksum: 68961e4dd393a8d51e6e80676a814a6741c0c9175501a1a556ec6d4ef5438aa1e982248a90c7f00099fb18da9529e9f6733be5ffebdb9b2e95cd36a6adeecb40 + "@types/jquery": "npm:*" + checksum: 10c0/81ea3d8c0780ff7a4523dd8e954f4825806ca2c9928e13a19489571f2517e483c0a7143abc322da9fc820392e8c92a8a88aa9eda0a67ceb68a4bd346711aa157 languageName: node linkType: hard "@types/node@npm:*": - version: 18.11.19 - resolution: "@types/node@npm:18.11.19" - checksum: d7cd19fcfc59cbdd3f9ba0b4072cb7adc21bd575bd8eb7d7e698975e63564aaa83f03434f32b12331f84f73d0b369d9cbe2371e359d9d7f5c3361f4987f4f7da + version: 20.11.24 + resolution: "@types/node@npm:20.11.24" + dependencies: + undici-types: "npm:~5.26.4" + checksum: 10c0/5a62225eb4797b41e6953f9c08c4611d607b5422ddd153312fc81ed6ed37115228ae27e3e3caa1a3bf52d88310306a196ba1cfbd8b2ec918a20f64d80dfa22c9 languageName: node linkType: hard "@types/parse-json@npm:^4.0.0": - version: 4.0.0 - resolution: "@types/parse-json@npm:4.0.0" - checksum: fd6bce2b674b6efc3db4c7c3d336bd70c90838e8439de639b909ce22f3720d21344f52427f1d9e57b265fcb7f6c018699b99e5e0c208a1a4823014269a6bf35b + version: 4.0.2 + resolution: "@types/parse-json@npm:4.0.2" + checksum: 10c0/b1b863ac34a2c2172fbe0807a1ec4d5cb684e48d422d15ec95980b81475fac4fdb3768a8b13eef39130203a7c04340fc167bae057c7ebcafd7dec9fe6c36aeb1 languageName: node linkType: hard @@ -1401,233 +1272,244 @@ __metadata: version: 1.17.1 resolution: "@types/resolve@npm:1.17.1" dependencies: - "@types/node": "*" - checksum: dc6a6df507656004e242dcb02c784479deca516d5f4b58a1707e708022b269ae147e1da0521f3e8ad0d63638869d87e0adc023f0bd5454aa6f72ac66c7525cf5 + "@types/node": "npm:*" + checksum: 10c0/6eeb9c27d99bf4b393bf168d43208f63e78cefca5644662a0bdb2bdbf8352386f4f3aca66add138fc41bce5f66fd48a0de430a1473f11b612fbed0375ae78031 languageName: node linkType: hard "@types/semver@npm:^7.3.12": - version: 7.3.13 - resolution: "@types/semver@npm:7.3.13" - checksum: 00c0724d54757c2f4bc60b5032fe91cda6410e48689633d5f35ece8a0a66445e3e57fa1d6e07eb780f792e82ac542948ec4d0b76eb3484297b79bd18b8cf1cb0 + version: 7.5.8 + resolution: "@types/semver@npm:7.5.8" + checksum: 10c0/8663ff927234d1c5fcc04b33062cb2b9fcfbe0f5f351ed26c4d1e1581657deebd506b41ff7fdf89e787e3d33ce05854bc01686379b89e9c49b564c4cfa988efa languageName: node linkType: hard "@types/sizzle@npm:*": - version: 2.3.3 - resolution: "@types/sizzle@npm:2.3.3" - checksum: 586a9fb1f6ff3e325e0f2cc1596a460615f0bc8a28f6e276ac9b509401039dd242fa8b34496d3a30c52f5b495873922d09a9e76c50c2ab2bcc70ba3fb9c4e160 + version: 2.3.8 + resolution: "@types/sizzle@npm:2.3.8" + checksum: 10c0/ab5460147ae6680cc20c2223a8f17d9f7c97144b70f00a222a1c32d68b5207696d48177ab9784dda88c74d93ed5a78dd31f74d271b15382520b423c81b4aac89 languageName: node linkType: hard "@types/trusted-types@npm:^2.0.2": - version: 2.0.2 - resolution: "@types/trusted-types@npm:2.0.2" - checksum: 3371eef5f1c50e1c3c07a127c1207b262ba65b83dd167a1c460fc1b135a3fb0c97b9f508efebd383f239cc5dd5b7169093686a692a501fde9c3f7208657d9b0d + version: 2.0.7 + resolution: "@types/trusted-types@npm:2.0.7" + checksum: 10c0/4c4855f10de7c6c135e0d32ce462419d8abbbc33713b31d294596c0cc34ae1fa6112a2f9da729c8f7a20707782b0d69da3b1f8df6645b0366d08825ca1522e0c languageName: node linkType: hard "@typescript-eslint/eslint-plugin@npm:^5.36.2": - version: 5.51.0 - resolution: "@typescript-eslint/eslint-plugin@npm:5.51.0" + version: 5.62.0 + resolution: "@typescript-eslint/eslint-plugin@npm:5.62.0" dependencies: - "@typescript-eslint/scope-manager": 5.51.0 - "@typescript-eslint/type-utils": 5.51.0 - "@typescript-eslint/utils": 5.51.0 - debug: ^4.3.4 - grapheme-splitter: ^1.0.4 - ignore: ^5.2.0 - natural-compare-lite: ^1.4.0 - regexpp: ^3.2.0 - semver: ^7.3.7 - tsutils: ^3.21.0 + "@eslint-community/regexpp": "npm:^4.4.0" + "@typescript-eslint/scope-manager": "npm:5.62.0" + "@typescript-eslint/type-utils": "npm:5.62.0" + "@typescript-eslint/utils": "npm:5.62.0" + debug: "npm:^4.3.4" + graphemer: "npm:^1.4.0" + ignore: "npm:^5.2.0" + natural-compare-lite: "npm:^1.4.0" + semver: "npm:^7.3.7" + tsutils: "npm:^3.21.0" peerDependencies: "@typescript-eslint/parser": ^5.0.0 eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 5351d8cec13bd9867ce4aaf7052aa31c9ca867fc89c620fc0fe5718ac2cbc165903275db59974324d98e45df0d33a73a4367d236668772912731031a672cfdcd + checksum: 10c0/3f40cb6bab5a2833c3544e4621b9fdacd8ea53420cadc1c63fac3b89cdf5c62be1e6b7bcf56976dede5db4c43830de298ced3db60b5494a3b961ca1b4bff9f2a languageName: node linkType: hard "@typescript-eslint/parser@npm:^5.36.2": - version: 5.51.0 - resolution: "@typescript-eslint/parser@npm:5.51.0" + version: 5.62.0 + resolution: "@typescript-eslint/parser@npm:5.62.0" dependencies: - "@typescript-eslint/scope-manager": 5.51.0 - "@typescript-eslint/types": 5.51.0 - "@typescript-eslint/typescript-estree": 5.51.0 - debug: ^4.3.4 + "@typescript-eslint/scope-manager": "npm:5.62.0" + "@typescript-eslint/types": "npm:5.62.0" + "@typescript-eslint/typescript-estree": "npm:5.62.0" + debug: "npm:^4.3.4" peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: typescript: optional: true - checksum: 096ec819132839febd4f390c4bbf31687e06191092c244dbd189a64cd7383fbaba728f2765e8809cd9834c0069163ab38b0e5f0f6360157d831647d4c295f8cd + checksum: 10c0/315194b3bf39beb9bd16c190956c46beec64b8371e18d6bb72002108b250983eb1e186a01d34b77eb4045f4941acbb243b16155fbb46881105f65e37dc9e24d4 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.51.0": - version: 5.51.0 - resolution: "@typescript-eslint/scope-manager@npm:5.51.0" +"@typescript-eslint/scope-manager@npm:5.62.0": + version: 5.62.0 + resolution: "@typescript-eslint/scope-manager@npm:5.62.0" dependencies: - "@typescript-eslint/types": 5.51.0 - "@typescript-eslint/visitor-keys": 5.51.0 - checksum: b3c9f48b6b7a7ae2ebcad4745ef91e4727776b2cf56d31be6456b1aa063aa649539e20f9fffa83cad9ccaaa9c492f2354a1c15526a2b789e235ec58b3a82d22c + "@typescript-eslint/types": "npm:5.62.0" + "@typescript-eslint/visitor-keys": "npm:5.62.0" + checksum: 10c0/861253235576c1c5c1772d23cdce1418c2da2618a479a7de4f6114a12a7ca853011a1e530525d0931c355a8fd237b9cd828fac560f85f9623e24054fd024726f languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.51.0": - version: 5.51.0 - resolution: "@typescript-eslint/type-utils@npm:5.51.0" +"@typescript-eslint/type-utils@npm:5.62.0": + version: 5.62.0 + resolution: "@typescript-eslint/type-utils@npm:5.62.0" dependencies: - "@typescript-eslint/typescript-estree": 5.51.0 - "@typescript-eslint/utils": 5.51.0 - debug: ^4.3.4 - tsutils: ^3.21.0 + "@typescript-eslint/typescript-estree": "npm:5.62.0" + "@typescript-eslint/utils": "npm:5.62.0" + debug: "npm:^4.3.4" + tsutils: "npm:^3.21.0" peerDependencies: eslint: "*" peerDependenciesMeta: typescript: optional: true - checksum: ab9747b0c629cfaaab903eed8ce1e39d34d69a402ce5faf2f1fff2bbb461bdbe034044b1368ba67ba8e5c1c512172e07d83c8a563635d8de811bf148d95c7dec + checksum: 10c0/93112e34026069a48f0484b98caca1c89d9707842afe14e08e7390af51cdde87378df29d213d3bbd10a7cfe6f91b228031b56218515ce077bdb62ddea9d9f474 languageName: node linkType: hard -"@typescript-eslint/types@npm:5.51.0": - version: 5.51.0 - resolution: "@typescript-eslint/types@npm:5.51.0" - checksum: b31021a0866f41ba5d71b6c4c7e20cc9b99d49c93bb7db63b55b2e51542fb75b4e27662ee86350da3c1318029e278a5a807facaf4cb5aeea724be8b0e021e836 +"@typescript-eslint/types@npm:5.62.0": + version: 5.62.0 + resolution: "@typescript-eslint/types@npm:5.62.0" + checksum: 10c0/7febd3a7f0701c0b927e094f02e82d8ee2cada2b186fcb938bc2b94ff6fbad88237afc304cbaf33e82797078bbbb1baf91475f6400912f8b64c89be79bfa4ddf languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.51.0": - version: 5.51.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.51.0" +"@typescript-eslint/typescript-estree@npm:5.62.0": + version: 5.62.0 + resolution: "@typescript-eslint/typescript-estree@npm:5.62.0" dependencies: - "@typescript-eslint/types": 5.51.0 - "@typescript-eslint/visitor-keys": 5.51.0 - debug: ^4.3.4 - globby: ^11.1.0 - is-glob: ^4.0.3 - semver: ^7.3.7 - tsutils: ^3.21.0 + "@typescript-eslint/types": "npm:5.62.0" + "@typescript-eslint/visitor-keys": "npm:5.62.0" + debug: "npm:^4.3.4" + globby: "npm:^11.1.0" + is-glob: "npm:^4.0.3" + semver: "npm:^7.3.7" + tsutils: "npm:^3.21.0" peerDependenciesMeta: typescript: optional: true - checksum: aec23e5cab48ee72fefa6d1ac266639ebabf6cebec1e0207ad47011d3a48186ac9a632c8e34c3bac896155f54895a497230c11d789fd81263b08eb267d7113ce + checksum: 10c0/d7984a3e9d56897b2481940ec803cb8e7ead03df8d9cfd9797350be82ff765dfcf3cfec04e7355e1779e948da8f02bc5e11719d07a596eb1cb995c48a95e38cf languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.51.0": - version: 5.51.0 - resolution: "@typescript-eslint/utils@npm:5.51.0" +"@typescript-eslint/utils@npm:5.62.0": + version: 5.62.0 + resolution: "@typescript-eslint/utils@npm:5.62.0" dependencies: - "@types/json-schema": ^7.0.9 - "@types/semver": ^7.3.12 - "@typescript-eslint/scope-manager": 5.51.0 - "@typescript-eslint/types": 5.51.0 - "@typescript-eslint/typescript-estree": 5.51.0 - eslint-scope: ^5.1.1 - eslint-utils: ^3.0.0 - semver: ^7.3.7 + "@eslint-community/eslint-utils": "npm:^4.2.0" + "@types/json-schema": "npm:^7.0.9" + "@types/semver": "npm:^7.3.12" + "@typescript-eslint/scope-manager": "npm:5.62.0" + "@typescript-eslint/types": "npm:5.62.0" + "@typescript-eslint/typescript-estree": "npm:5.62.0" + eslint-scope: "npm:^5.1.1" + semver: "npm:^7.3.7" peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: c6e28c942fbac5500f0e8ed67ef304b484ba296486e55306f78fb090dc9d5bb1f25a0bedc065e14680041eadce5e95fa10aab618cb0c316599ec987e6ea72442 + checksum: 10c0/f09b7d9952e4a205eb1ced31d7684dd55cee40bf8c2d78e923aa8a255318d97279825733902742c09d8690f37a50243f4c4d383ab16bd7aefaf9c4b438f785e1 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.51.0": - version: 5.51.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.51.0" +"@typescript-eslint/visitor-keys@npm:5.62.0": + version: 5.62.0 + resolution: "@typescript-eslint/visitor-keys@npm:5.62.0" dependencies: - "@typescript-eslint/types": 5.51.0 - eslint-visitor-keys: ^3.3.0 - checksum: b49710f3c6b3b62a846a163afffd81be5eb2b1f44e25bec51ff3c9f4c3b579d74aa4cbd3753b4fc09ea3dbc64a7062f9c658c08d22bb2740a599cb703d876220 + "@typescript-eslint/types": "npm:5.62.0" + eslint-visitor-keys: "npm:^3.3.0" + checksum: 10c0/7c3b8e4148e9b94d9b7162a596a1260d7a3efc4e65199693b8025c71c4652b8042501c0bc9f57654c1e2943c26da98c0f77884a746c6ae81389fcb0b513d995d languageName: node linkType: hard -"@vitest/coverage-istanbul@npm:^0.34.3": - version: 0.34.3 - resolution: "@vitest/coverage-istanbul@npm:0.34.3" +"@ungap/structured-clone@npm:^1.2.0": + version: 1.2.0 + resolution: "@ungap/structured-clone@npm:1.2.0" + checksum: 10c0/8209c937cb39119f44eb63cf90c0b73e7c754209a6411c707be08e50e29ee81356dca1a848a405c8bdeebfe2f5e4f831ad310ae1689eeef65e7445c090c6657d + languageName: node + linkType: hard + +"@vitest/coverage-istanbul@npm:^1.3.1": + version: 1.3.1 + resolution: "@vitest/coverage-istanbul@npm:1.3.1" dependencies: - istanbul-lib-coverage: ^3.2.0 - istanbul-lib-instrument: ^6.0.0 - istanbul-lib-report: ^3.0.1 - istanbul-lib-source-maps: ^4.0.1 - istanbul-reports: ^3.1.5 - test-exclude: ^6.0.0 + debug: "npm:^4.3.4" + istanbul-lib-coverage: "npm:^3.2.2" + istanbul-lib-instrument: "npm:^6.0.1" + istanbul-lib-report: "npm:^3.0.1" + istanbul-lib-source-maps: "npm:^4.0.1" + istanbul-reports: "npm:^3.1.6" + magicast: "npm:^0.3.3" + picocolors: "npm:^1.0.0" + test-exclude: "npm:^6.0.0" peerDependencies: - vitest: ">=0.32.0 <1" - checksum: 6e5f437d8b3d1e93aa25180661d47339b2a1df24686a5d7154cd266db47fbf0c2a2faa58290f79dd009e531e16c14bfb8a0fb49031d9a14b6e962de82155eb12 + vitest: 1.3.1 + checksum: 10c0/40efacde51e5998bde8032dd45d64fe214674f1efb97c094c4ae9ef1893afc4e0ef97f3fa4cc4923561b67b1196c27a877a0fa5bc71a049b8e48e3ef1f5c48db languageName: node linkType: hard -"@vitest/expect@npm:0.34.3": - version: 0.34.3 - resolution: "@vitest/expect@npm:0.34.3" +"@vitest/expect@npm:1.3.1": + version: 1.3.1 + resolution: "@vitest/expect@npm:1.3.1" dependencies: - "@vitest/spy": 0.34.3 - "@vitest/utils": 0.34.3 - chai: ^4.3.7 - checksum: 79afaa37d2efb7bb5503332caf389860b2261f198dbe61557e8061262b628d18658e59eb51d1808ecd35fc59f4bb4d04c0e0f97a27c7db02584ab5b424147b8d + "@vitest/spy": "npm:1.3.1" + "@vitest/utils": "npm:1.3.1" + chai: "npm:^4.3.10" + checksum: 10c0/ea66a1e912d896a481a27631b68089b885af7e8ed62ba8aaa119c37a9beafe6c094fd672775a20e6e23460af66e294f9ca259e6e0562708d1b7724eaaf53c7bb languageName: node linkType: hard -"@vitest/runner@npm:0.34.3": - version: 0.34.3 - resolution: "@vitest/runner@npm:0.34.3" +"@vitest/runner@npm:1.3.1": + version: 1.3.1 + resolution: "@vitest/runner@npm:1.3.1" dependencies: - "@vitest/utils": 0.34.3 - p-limit: ^4.0.0 - pathe: ^1.1.1 - checksum: 945580eaa58e8edbe29a64059bc2a524a9e85117b6d600fdb457cfe84cbfb81bf6d7e98e1227e7cb4e7399992c8fe8d83d0791d0385ff005dc1a4d9da125443b + "@vitest/utils": "npm:1.3.1" + p-limit: "npm:^5.0.0" + pathe: "npm:^1.1.1" + checksum: 10c0/d732de2368d2bc32cbc27f0bbc5477f6e36088ddfb873c036935a45b1b252ebc529b932cf5cd944eed9b692243acebef828f6d3218583cb8a6817a8270712050 languageName: node linkType: hard -"@vitest/snapshot@npm:0.34.3": - version: 0.34.3 - resolution: "@vitest/snapshot@npm:0.34.3" +"@vitest/snapshot@npm:1.3.1": + version: 1.3.1 + resolution: "@vitest/snapshot@npm:1.3.1" dependencies: - magic-string: ^0.30.1 - pathe: ^1.1.1 - pretty-format: ^29.5.0 - checksum: 234893e91a1efd4bdbbde047a68de40975e02ead8407724ce8ca4a24edf0fb2d725f8a3efceb104965388407b598faf22407aadfbf4164cc74b3cf1e0e9f4543 + magic-string: "npm:^0.30.5" + pathe: "npm:^1.1.1" + pretty-format: "npm:^29.7.0" + checksum: 10c0/cad0844270852c6d53c1ca6b7ca279034880d2140837ff245d5bd2376f4356cc924929c58dc69bcf9fad83ba934d4a06000c908971cc24b5d7a9ec2656b72d29 languageName: node linkType: hard -"@vitest/spy@npm:0.34.3": - version: 0.34.3 - resolution: "@vitest/spy@npm:0.34.3" +"@vitest/spy@npm:1.3.1": + version: 1.3.1 + resolution: "@vitest/spy@npm:1.3.1" dependencies: - tinyspy: ^2.1.1 - checksum: a2b64b9c357a56ad2f2340ecd225ffe787e61afba4ffb24a6670aad3fc90ea2606ed48daa188ed62b3ef67d55c0259fda6b101143d6c91b58c9ac4298d8be4f9 + tinyspy: "npm:^2.2.0" + checksum: 10c0/efc42f679d2a51fc6583ca3136ccd47581cb27c923ed3cb0500f5dee9aac99b681bfdd400c16ef108f2e0761daa642bc190816a6411931a2aba99ebf8b213dd4 languageName: node linkType: hard -"@vitest/utils@npm:0.34.3": - version: 0.34.3 - resolution: "@vitest/utils@npm:0.34.3" +"@vitest/utils@npm:1.3.1": + version: 1.3.1 + resolution: "@vitest/utils@npm:1.3.1" dependencies: - diff-sequences: ^29.4.3 - loupe: ^2.3.6 - pretty-format: ^29.5.0 - checksum: aeb8ef7fd98b32cb6c403796880d0aa8f5411bbdb249bb23b3301a70e1b7d1ee025ddb204aae8c1db5756f6ac428c49ebbb8e2ed23ce185c8a659b67413efa85 + diff-sequences: "npm:^29.6.3" + estree-walker: "npm:^3.0.3" + loupe: "npm:^2.3.7" + pretty-format: "npm:^29.7.0" + checksum: 10c0/d604c8ad3b1aee30d4dcd889098f591407bfe18547ff96485b1d1ed54eff58219c756a9544a7fbd4e37886863abacd7a89a76334cb3ea7f84c3d496bb757db23 languageName: node linkType: hard "abab@npm:^2.0.6": version: 2.0.6 resolution: "abab@npm:2.0.6" - checksum: 6ffc1af4ff315066c62600123990d87551ceb0aafa01e6539da77b0f5987ac7019466780bf480f1787576d4385e3690c81ccc37cfda12819bf510b8ab47e5a3e + checksum: 10c0/0b245c3c3ea2598fe0025abf7cc7bb507b06949d51e8edae5d12c1b847a0a0c09639abcb94788332b4e2044ac4491c1e8f571b51c7826fd4b0bda1685ad4a278 languageName: node linkType: hard -"abbrev@npm:^1.0.0": - version: 1.1.1 - resolution: "abbrev@npm:1.1.1" - checksum: a4a97ec07d7ea112c517036882b2ac22f3109b7b19077dc656316d07d308438aac28e4d9746dc4d84bf6b1e75b4a7b0a5f3cb30592419f128ca9a8cee3bcfa17 +"abbrev@npm:^2.0.0": + version: 2.0.0 + resolution: "abbrev@npm:2.0.0" + checksum: 10c0/f742a5a107473946f426c691c08daba61a1d15942616f300b5d32fd735be88fef5cba24201757b6c407fd564555fb48c751cfa33519b2605c8a7aadd22baf372 languageName: node linkType: hard @@ -1635,9 +1517,9 @@ __metadata: version: 7.0.1 resolution: "acorn-globals@npm:7.0.1" dependencies: - acorn: ^8.1.0 - acorn-walk: ^8.0.2 - checksum: 2a2998a547af6d0db5f0cdb90acaa7c3cbca6709010e02121fb8b8617c0fbd8bab0b869579903fde358ac78454356a14fadcc1a672ecb97b04b1c2ccba955ce8 + acorn: "npm:^8.1.0" + acorn-walk: "npm:^8.0.2" + checksum: 10c0/7437f58e92d99292dbebd0e79531af27d706c9f272f31c675d793da6c82d897e75302a8744af13c7f7978a8399840f14a353b60cf21014647f71012982456d2b languageName: node linkType: hard @@ -1646,52 +1528,41 @@ __metadata: resolution: "acorn-jsx@npm:5.3.2" peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: c3d3b2a89c9a056b205b69530a37b972b404ee46ec8e5b341666f9513d3163e2a4f214a71f4dfc7370f5a9c07472d2fd1c11c91c3f03d093e37637d95da98950 + checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 languageName: node linkType: hard -"acorn-walk@npm:^8.0.2, acorn-walk@npm:^8.2.0": - version: 8.2.0 - resolution: "acorn-walk@npm:8.2.0" - checksum: 1715e76c01dd7b2d4ca472f9c58968516a4899378a63ad5b6c2d668bba8da21a71976c14ec5f5b75f887b6317c4ae0b897ab141c831d741dc76024d8745f1ad1 +"acorn-walk@npm:^8.0.2, acorn-walk@npm:^8.3.2": + version: 8.3.2 + resolution: "acorn-walk@npm:8.3.2" + checksum: 10c0/7e2a8dad5480df7f872569b9dccff2f3da7e65f5353686b1d6032ab9f4ddf6e3a2cb83a9b52cf50b1497fd522154dda92f0abf7153290cc79cd14721ff121e52 languageName: node linkType: hard -"acorn@npm:^8.1.0, acorn@npm:^8.5.0, acorn@npm:^8.8.0, acorn@npm:^8.8.2": - version: 8.8.2 - resolution: "acorn@npm:8.8.2" +"acorn@npm:^8.1.0, acorn@npm:^8.11.3, acorn@npm:^8.8.2, acorn@npm:^8.9.0": + version: 8.11.3 + resolution: "acorn@npm:8.11.3" bin: acorn: bin/acorn - checksum: f790b99a1bf63ef160c967e23c46feea7787e531292bb827126334612c234ed489a0dc2c7ba33156416f0ffa8d25bf2b0fdb7f35c2ba60eb3e960572bece4001 + checksum: 10c0/3ff155f8812e4a746fee8ecff1f227d527c4c45655bb1fad6347c3cb58e46190598217551b1500f18542d2bbe5c87120cb6927f5a074a59166fbdd9468f0a299 languageName: node linkType: hard -"acorn@npm:^8.10.0, acorn@npm:^8.9.0": - version: 8.10.0 - resolution: "acorn@npm:8.10.0" - bin: - acorn: bin/acorn - checksum: 538ba38af0cc9e5ef983aee196c4b8b4d87c0c94532334fa7e065b2c8a1f85863467bb774231aae91613fcda5e68740c15d97b1967ae3394d20faddddd8af61d - languageName: node - linkType: hard - -"agent-base@npm:6, agent-base@npm:^6.0.2": +"agent-base@npm:6": version: 6.0.2 resolution: "agent-base@npm:6.0.2" dependencies: - debug: 4 - checksum: f52b6872cc96fd5f622071b71ef200e01c7c4c454ee68bc9accca90c98cfb39f2810e3e9aa330435835eedc8c23f4f8a15267f67c6e245d2b33757575bdac49d + debug: "npm:4" + checksum: 10c0/dc4f757e40b5f3e3d674bc9beb4f1048f4ee83af189bae39be99f57bf1f48dde166a8b0a5342a84b5944ee8e6ed1e5a9d801858f4ad44764e84957122fe46261 languageName: node linkType: hard -"agentkeepalive@npm:^4.2.1": - version: 4.2.1 - resolution: "agentkeepalive@npm:4.2.1" +"agent-base@npm:^7.0.2, agent-base@npm:^7.1.0": + version: 7.1.0 + resolution: "agent-base@npm:7.1.0" dependencies: - debug: ^4.1.0 - depd: ^1.1.2 - humanize-ms: ^1.2.1 - checksum: 39cb49ed8cf217fd6da058a92828a0a84e0b74c35550f82ee0a10e1ee403c4b78ade7948be2279b188b7a7303f5d396ea2738b134731e464bf28de00a4f72a18 + debug: "npm:^4.3.4" + checksum: 10c0/fc974ab57ffdd8421a2bc339644d312a9cca320c20c3393c9d8b1fd91731b9bbabdb985df5fc860f5b79d81c3e350daa3fcb31c5c07c0bb385aafc817df004ce languageName: node linkType: hard @@ -1699,28 +1570,35 @@ __metadata: version: 3.1.0 resolution: "aggregate-error@npm:3.1.0" dependencies: - clean-stack: ^2.0.0 - indent-string: ^4.0.0 - checksum: 1101a33f21baa27a2fa8e04b698271e64616b886795fd43c31068c07533c7b3facfcaf4e9e0cab3624bd88f729a592f1c901a1a229c9e490eafce411a8644b79 + clean-stack: "npm:^2.0.0" + indent-string: "npm:^4.0.0" + checksum: 10c0/a42f67faa79e3e6687a4923050e7c9807db3848a037076f791d10e092677d65c1d2d863b7848560699f40fc0502c19f40963fb1cd1fb3d338a7423df8e45e039 languageName: node linkType: hard -"ajv@npm:^6.10.0, ajv@npm:^6.12.4": +"ajv@npm:^6.12.4": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: - fast-deep-equal: ^3.1.1 - fast-json-stable-stringify: ^2.0.0 - json-schema-traverse: ^0.4.1 - uri-js: ^4.2.2 - checksum: 874972efe5c4202ab0a68379481fbd3d1b5d0a7bd6d3cc21d40d3536ebff3352a2a1fabb632d4fd2cc7fe4cbdcd5ed6782084c9bbf7f32a1536d18f9da5007d4 + fast-deep-equal: "npm:^3.1.1" + fast-json-stable-stringify: "npm:^2.0.0" + json-schema-traverse: "npm:^0.4.1" + uri-js: "npm:^4.2.2" + checksum: 10c0/41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71 languageName: node linkType: hard "ansi-regex@npm:^5.0.1": version: 5.0.1 resolution: "ansi-regex@npm:5.0.1" - checksum: 2aa4bb54caf2d622f1afdad09441695af2a83aa3fe8b8afa581d205e57ed4261c183c4d3877cee25794443fde5876417d859c108078ab788d6af7e4fe52eb66b + checksum: 10c0/9a64bb8627b434ba9327b60c027742e5d17ac69277960d041898596271d992d4d52ba7267a63ca10232e29f6107fc8a835f6ce8d719b88c5f8493f8254813737 + languageName: node + linkType: hard + +"ansi-regex@npm:^6.0.1": + version: 6.0.1 + resolution: "ansi-regex@npm:6.0.1" + checksum: 10c0/cbe16dbd2c6b2735d1df7976a7070dd277326434f0212f43abf6d87674095d247968209babdaad31bb00882fa68807256ba9be340eec2f1004de14ca75f52a08 languageName: node linkType: hard @@ -1728,8 +1606,8 @@ __metadata: version: 3.2.1 resolution: "ansi-styles@npm:3.2.1" dependencies: - color-convert: ^1.9.0 - checksum: d85ade01c10e5dd77b6c89f34ed7531da5830d2cb5882c645f330079975b716438cd7ebb81d0d6e6b4f9c577f19ae41ab55f07f19786b02f9dfd9e0377395665 + color-convert: "npm:^1.9.0" + checksum: 10c0/ece5a8ef069fcc5298f67e3f4771a663129abd174ea2dfa87923a2be2abf6cd367ef72ac87942da00ce85bd1d651d4cd8595aebdb1b385889b89b205860e977b languageName: node linkType: hard @@ -1737,15 +1615,22 @@ __metadata: version: 4.3.0 resolution: "ansi-styles@npm:4.3.0" dependencies: - color-convert: ^2.0.1 - checksum: 513b44c3b2105dd14cc42a19271e80f386466c4be574bccf60b627432f9198571ebf4ab1e4c3ba17347658f4ee1711c163d574248c0c1cdc2d5917a0ad582ec4 + color-convert: "npm:^2.0.1" + checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 languageName: node linkType: hard "ansi-styles@npm:^5.0.0": version: 5.2.0 resolution: "ansi-styles@npm:5.2.0" - checksum: d7f4e97ce0623aea6bc0d90dcd28881ee04cba06c570b97fd3391bd7a268eedfd9d5e2dd4fdcbdd82b8105df5faf6f24aaedc08eaf3da898e702db5948f63469 + checksum: 10c0/9c4ca80eb3c2fb7b33841c210d2f20807f40865d27008d7c3f707b7f95cab7d67462a565e2388ac3285b71cb3d9bb2173de8da37c57692a362885ec34d6e27df + languageName: node + linkType: hard + +"ansi-styles@npm:^6.1.0": + version: 6.2.1 + resolution: "ansi-styles@npm:6.2.1" + checksum: 10c0/5d1ec38c123984bcedd996eac680d548f31828bd679a66db2bdf11844634dde55fec3efa9c6bb1d89056a5e79c1ac540c4c784d592ea1d25028a92227d2f2d5c languageName: node linkType: hard @@ -1753,119 +1638,156 @@ __metadata: version: 3.1.3 resolution: "anymatch@npm:3.1.3" dependencies: - normalize-path: ^3.0.0 - picomatch: ^2.0.4 - checksum: 3e044fd6d1d26545f235a9fe4d7a534e2029d8e59fa7fd9f2a6eb21230f6b5380ea1eaf55136e60cbf8e613544b3b766e7a6fa2102e2a3a117505466e3025dc2 - languageName: node - linkType: hard - -"aproba@npm:^1.0.3 || ^2.0.0": - version: 2.0.0 - resolution: "aproba@npm:2.0.0" - checksum: 5615cadcfb45289eea63f8afd064ab656006361020e1735112e346593856f87435e02d8dcc7ff0d11928bc7d425f27bc7c2a84f6c0b35ab0ff659c814c138a24 - languageName: node - linkType: hard - -"are-we-there-yet@npm:^3.0.0": - version: 3.0.1 - resolution: "are-we-there-yet@npm:3.0.1" - dependencies: - delegates: ^1.0.0 - readable-stream: ^3.6.0 - checksum: 52590c24860fa7173bedeb69a4c05fb573473e860197f618b9a28432ee4379049336727ae3a1f9c4cb083114601c1140cee578376164d0e651217a9843f9fe83 + normalize-path: "npm:^3.0.0" + picomatch: "npm:^2.0.4" + checksum: 10c0/57b06ae984bc32a0d22592c87384cd88fe4511b1dd7581497831c56d41939c8a001b28e7b853e1450f2bf61992dfcaa8ae2d0d161a0a90c4fb631ef07098fbac languageName: node linkType: hard "argparse@npm:^2.0.1": version: 2.0.1 resolution: "argparse@npm:2.0.1" - checksum: 83644b56493e89a254bae05702abf3a1101b4fa4d0ca31df1c9985275a5a5bd47b3c27b7fa0b71098d41114d8ca000e6ed90cad764b306f8a503665e4d517ced + checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e languageName: node linkType: hard -"array-includes@npm:^3.1.6": - version: 3.1.6 - resolution: "array-includes@npm:3.1.6" +"array-buffer-byte-length@npm:^1.0.1": + version: 1.0.1 + resolution: "array-buffer-byte-length@npm:1.0.1" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - get-intrinsic: ^1.1.3 - is-string: ^1.0.7 - checksum: f22f8cd8ba8a6448d91eebdc69f04e4e55085d09232b5216ee2d476dab3ef59984e8d1889e662c6a0ed939dcb1b57fd05b2c0209c3370942fc41b752c82a2ca5 + call-bind: "npm:^1.0.5" + is-array-buffer: "npm:^3.0.4" + checksum: 10c0/f5cdf54527cd18a3d2852ddf73df79efec03829e7373a8322ef5df2b4ef546fb365c19c71d6b42d641cb6bfe0f1a2f19bc0ece5b533295f86d7c3d522f228917 + languageName: node + linkType: hard + +"array-includes@npm:^3.1.7": + version: 3.1.7 + resolution: "array-includes@npm:3.1.7" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + get-intrinsic: "npm:^1.2.1" + is-string: "npm:^1.0.7" + checksum: 10c0/692907bd7f19d06dc58ccb761f34b58f5dc0b437d2b47a8fe42a1501849a5cf5c27aed3d521a9702667827c2c85a7e75df00a402c438094d87fc43f39ebf9b2b languageName: node linkType: hard "array-union@npm:^2.1.0": version: 2.1.0 resolution: "array-union@npm:2.1.0" - checksum: 5bee12395cba82da674931df6d0fea23c4aa4660cb3b338ced9f828782a65caa232573e6bf3968f23e0c5eb301764a382cef2f128b170a9dc59de0e36c39f98d + checksum: 10c0/429897e68110374f39b771ec47a7161fc6a8fc33e196857c0a396dc75df0b5f65e4d046674db764330b6bb66b39ef48dd7c53b6a2ee75cfb0681e0c1a7033962 languageName: node linkType: hard -"array.prototype.flat@npm:^1.3.1": - version: 1.3.1 - resolution: "array.prototype.flat@npm:1.3.1" +"array.prototype.filter@npm:^1.0.3": + version: 1.0.3 + resolution: "array.prototype.filter@npm:1.0.3" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - es-shim-unscopables: ^1.0.0 - checksum: 5a8415949df79bf6e01afd7e8839bbde5a3581300e8ad5d8449dea52639e9e59b26a467665622783697917b43bf39940a6e621877c7dd9b3d1c1f97484b9b88b + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + es-array-method-boxes-properly: "npm:^1.0.0" + is-string: "npm:^1.0.7" + checksum: 10c0/8b70b5f866df5d90fa27aa5bfa30f5fefc44cbea94b0513699d761713658077c2a24cbf06aac5179eabddb6c93adc467af4c288b7a839c5bc5a769ee5a2d48ad languageName: node linkType: hard -"array.prototype.flatmap@npm:^1.3.1": - version: 1.3.1 - resolution: "array.prototype.flatmap@npm:1.3.1" +"array.prototype.findlastindex@npm:^1.2.3": + version: 1.2.4 + resolution: "array.prototype.findlastindex@npm:1.2.4" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - es-shim-unscopables: ^1.0.0 - checksum: 8c1c43a4995f12cf12523436da28515184c753807b3f0bc2ca6c075f71c470b099e2090cc67dba8e5280958fea401c1d0c59e1db0143272aef6cd1103921a987 + call-bind: "npm:^1.0.5" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.22.3" + es-errors: "npm:^1.3.0" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10c0/b23ae35cf7621c82c20981ee110626090734a264798e781b052e534e3d61d576f03d125d92cf2e3672062bb5cc5907e02e69f2d80196a55f3cdb0197b4aa8c64 + languageName: node + linkType: hard + +"array.prototype.flat@npm:^1.3.2": + version: 1.3.2 + resolution: "array.prototype.flat@npm:1.3.2" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + es-shim-unscopables: "npm:^1.0.0" + checksum: 10c0/a578ed836a786efbb6c2db0899ae80781b476200617f65a44846cb1ed8bd8b24c8821b83703375d8af639c689497b7b07277060024b9919db94ac3e10dc8a49b + languageName: node + linkType: hard + +"array.prototype.flatmap@npm:^1.3.2": + version: 1.3.2 + resolution: "array.prototype.flatmap@npm:1.3.2" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + es-shim-unscopables: "npm:^1.0.0" + checksum: 10c0/67b3f1d602bb73713265145853128b1ad77cc0f9b833c7e1e056b323fbeac41a4ff1c9c99c7b9445903caea924d9ca2450578d9011913191aa88cc3c3a4b54f4 + languageName: node + linkType: hard + +"arraybuffer.prototype.slice@npm:^1.0.3": + version: 1.0.3 + resolution: "arraybuffer.prototype.slice@npm:1.0.3" + dependencies: + array-buffer-byte-length: "npm:^1.0.1" + call-bind: "npm:^1.0.5" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.22.3" + es-errors: "npm:^1.2.1" + get-intrinsic: "npm:^1.2.3" + is-array-buffer: "npm:^3.0.4" + is-shared-array-buffer: "npm:^1.0.2" + checksum: 10c0/d32754045bcb2294ade881d45140a5e52bda2321b9e98fa514797b7f0d252c4c5ab0d1edb34112652c62fa6a9398def568da63a4d7544672229afea283358c36 languageName: node linkType: hard "assertion-error@npm:^1.1.0": version: 1.1.0 resolution: "assertion-error@npm:1.1.0" - checksum: fd9429d3a3d4fd61782eb3962ae76b6d08aa7383123fca0596020013b3ebd6647891a85b05ce821c47d1471ed1271f00b0545cf6a4326cf2fc91efcc3b0fbecf + checksum: 10c0/25456b2aa333250f01143968e02e4884a34588a8538fbbf65c91a637f1dbfb8069249133cd2f4e530f10f624d206a664e7df30207830b659e9f5298b00a4099b languageName: node linkType: hard "asynckit@npm:^0.4.0": version: 0.4.0 resolution: "asynckit@npm:0.4.0" - checksum: 7b78c451df768adba04e2d02e63e2d0bf3b07adcd6e42b4cf665cb7ce899bedd344c69a1dcbce355b5f972d597b25aaa1c1742b52cffd9caccb22f348114f6be + checksum: 10c0/d73e2ddf20c4eb9337e1b3df1a0f6159481050a5de457c55b14ea2e5cb6d90bb69e004c9af54737a5ee0917fcf2c9e25de67777bbe58261847846066ba75bc9d languageName: node linkType: hard -"available-typed-arrays@npm:^1.0.5": - version: 1.0.5 - resolution: "available-typed-arrays@npm:1.0.5" - checksum: 20eb47b3cefd7db027b9bbb993c658abd36d4edd3fe1060e83699a03ee275b0c9b216cc076ff3f2db29073225fb70e7613987af14269ac1fe2a19803ccc97f1a +"available-typed-arrays@npm:^1.0.6, available-typed-arrays@npm:^1.0.7": + version: 1.0.7 + resolution: "available-typed-arrays@npm:1.0.7" + dependencies: + possible-typed-array-names: "npm:^1.0.0" + checksum: 10c0/d07226ef4f87daa01bd0fe80f8f310982e345f372926da2e5296aecc25c41cab440916bbaa4c5e1034b453af3392f67df5961124e4b586df1e99793a1374bdb2 languageName: node linkType: hard "balanced-match@npm:^1.0.0": version: 1.0.2 resolution: "balanced-match@npm:1.0.2" - checksum: 9706c088a283058a8a99e0bf91b0a2f75497f185980d9ffa8b304de1d9e58ebda7c72c07ebf01dadedaac5b2907b2c6f566f660d62bd336c3468e960403b9d65 + checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee languageName: node linkType: hard "binary-extensions@npm:^2.0.0": version: 2.2.0 resolution: "binary-extensions@npm:2.2.0" - checksum: ccd267956c58d2315f5d3ea6757cf09863c5fc703e50fbeb13a7dc849b812ef76e3cf9ca8f35a0c48498776a7478d7b4a0418e1e2b8cb9cb9731f2922aaad7f8 + checksum: 10c0/d73d8b897238a2d3ffa5f59c0241870043aa7471335e89ea5e1ff48edb7c2d0bb471517a3e4c5c3f4c043615caa2717b5f80a5e61e07503d51dc85cb848e665d languageName: node linkType: hard "boolbase@npm:^1.0.0": version: 1.0.0 resolution: "boolbase@npm:1.0.0" - checksum: 3e25c80ef626c3a3487c73dbfc70ac322ec830666c9ad915d11b701142fab25ec1e63eff2c450c74347acfd2de854ccde865cd79ef4db1683f7c7b046ea43bb0 + checksum: 10c0/e4b53deb4f2b85c52be0e21a273f2045c7b6a6ea002b0e139c744cb6f95e9ec044439a52883b0d74dedd1ff3da55ed140cfdddfed7fb0cccbed373de5dce1bcf languageName: node linkType: hard @@ -1873,9 +1795,9 @@ __metadata: version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" dependencies: - balanced-match: ^1.0.0 - concat-map: 0.0.1 - checksum: faf34a7bb0c3fcf4b59c7808bc5d2a96a40988addf2e7e09dfbb67a2251800e0d14cd2bfc1aa79174f2f5095c54ff27f46fb1289fe2d77dac755b5eb3434cc07 + balanced-match: "npm:^1.0.0" + concat-map: "npm:0.0.1" + checksum: 10c0/695a56cd058096a7cb71fb09d9d6a7070113c7be516699ed361317aca2ec169f618e28b8af352e02ab4233fb54eb0168460a40dc320bab0034b36ab59aaad668 languageName: node linkType: hard @@ -1883,8 +1805,8 @@ __metadata: version: 2.0.1 resolution: "brace-expansion@npm:2.0.1" dependencies: - balanced-match: ^1.0.0 - checksum: a61e7cd2e8a8505e9f0036b3b6108ba5e926b4b55089eeb5550cd04a471fe216c96d4fe7e4c7f995c728c554ae20ddfc4244cad10aef255e72b62930afd233d1 + balanced-match: "npm:^1.0.0" + checksum: 10c0/b358f2fe060e2d7a87aa015979ecea07f3c37d4018f8d6deb5bd4c229ad3a0384fe6029bb76cd8be63c81e516ee52d1a0673edbe2023d53a5191732ae3c3e49f languageName: node linkType: hard @@ -1892,100 +1814,83 @@ __metadata: version: 3.0.2 resolution: "braces@npm:3.0.2" dependencies: - fill-range: ^7.0.1 - checksum: e2a8e769a863f3d4ee887b5fe21f63193a891c68b612ddb4b68d82d1b5f3ff9073af066c343e9867a393fe4c2555dcb33e89b937195feb9c1613d259edfcd459 + fill-range: "npm:^7.0.1" + checksum: 10c0/321b4d675791479293264019156ca322163f02dc06e3c4cab33bb15cd43d80b51efef69b0930cfde3acd63d126ebca24cd0544fa6f261e093a0fb41ab9dda381 languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.16.6, browserslist@npm:^4.21.3, browserslist@npm:^4.21.4": - version: 4.21.5 - resolution: "browserslist@npm:4.21.5" +"browserslist@npm:^4.0.0, browserslist@npm:^4.21.4, browserslist@npm:^4.22.2": + version: 4.23.0 + resolution: "browserslist@npm:4.23.0" dependencies: - caniuse-lite: ^1.0.30001449 - electron-to-chromium: ^1.4.284 - node-releases: ^2.0.8 - update-browserslist-db: ^1.0.10 + caniuse-lite: "npm:^1.0.30001587" + electron-to-chromium: "npm:^1.4.668" + node-releases: "npm:^2.0.14" + update-browserslist-db: "npm:^1.0.13" bin: browserslist: cli.js - checksum: 9755986b22e73a6a1497fd8797aedd88e04270be33ce66ed5d85a1c8a798292a65e222b0f251bafa1c2522261e237d73b08b58689d4920a607e5a53d56dc4706 - languageName: node - linkType: hard - -"browserslist@npm:^4.21.9": - version: 4.21.10 - resolution: "browserslist@npm:4.21.10" - dependencies: - caniuse-lite: ^1.0.30001517 - electron-to-chromium: ^1.4.477 - node-releases: ^2.0.13 - update-browserslist-db: ^1.0.11 - bin: - browserslist: cli.js - checksum: 1e27c0f111a35d1dd0e8fc2c61781b0daefabc2c9471b0b10537ce54843014bceb2a1ce4571af1a82b2bf1e6e6e05d38865916689a158f03bc2c7a4ec2577db8 + checksum: 10c0/8e9cc154529062128d02a7af4d8adeead83ca1df8cd9ee65a88e2161039f3d68a4d40fea7353cab6bae4c16182dec2fdd9a1cf7dc2a2935498cee1af0e998943 languageName: node linkType: hard "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" - checksum: 0448524a562b37d4d7ed9efd91685a5b77a50672c556ea254ac9a6d30e3403a517d8981f10e565db24e8339413b43c97ca2951f10e399c6125a0d8911f5679bb + checksum: 10c0/124fff9d66d691a86d3b062eff4663fe437a9d9ee4b47b1b9e97f5a5d14f6d5399345db80f796827be7c95e70a8e765dd404b7c3ff3b3324f98e9b0c8826cc34 languageName: node linkType: hard "builtin-modules@npm:^3.3.0": version: 3.3.0 resolution: "builtin-modules@npm:3.3.0" - checksum: db021755d7ed8be048f25668fe2117620861ef6703ea2c65ed2779c9e3636d5c3b82325bd912244293959ff3ae303afa3471f6a15bf5060c103e4cc3a839749d + checksum: 10c0/2cb3448b4f7306dc853632a4fcddc95e8d4e4b9868c139400027b71938fc6806d4ff44007deffb362ac85724bd40c2c6452fb6a0aa4531650eeddb98d8e5ee8a languageName: node linkType: hard "cac@npm:^6.7.14": version: 6.7.14 resolution: "cac@npm:6.7.14" - checksum: 45a2496a9443abbe7f52a49b22fbe51b1905eff46e03fd5e6c98e3f85077be3f8949685a1849b1a9cd2bc3e5567dfebcf64f01ce01847baf918f1b37c839791a + checksum: 10c0/4ee06aaa7bab8981f0d54e5f5f9d4adcd64058e9697563ce336d8a3878ed018ee18ebe5359b2430eceae87e0758e62ea2019c3f52ae6e211b1bd2e133856cd10 languageName: node linkType: hard -"cacache@npm:^16.1.0": - version: 16.1.3 - resolution: "cacache@npm:16.1.3" +"cacache@npm:^18.0.0": + version: 18.0.2 + resolution: "cacache@npm:18.0.2" dependencies: - "@npmcli/fs": ^2.1.0 - "@npmcli/move-file": ^2.0.0 - chownr: ^2.0.0 - fs-minipass: ^2.1.0 - glob: ^8.0.1 - infer-owner: ^1.0.4 - lru-cache: ^7.7.1 - minipass: ^3.1.6 - minipass-collect: ^1.0.2 - minipass-flush: ^1.0.5 - minipass-pipeline: ^1.2.4 - mkdirp: ^1.0.4 - p-map: ^4.0.0 - promise-inflight: ^1.0.1 - rimraf: ^3.0.2 - ssri: ^9.0.0 - tar: ^6.1.11 - unique-filename: ^2.0.0 - checksum: d91409e6e57d7d9a3a25e5dcc589c84e75b178ae8ea7de05cbf6b783f77a5fae938f6e8fda6f5257ed70000be27a681e1e44829251bfffe4c10216002f8f14e6 + "@npmcli/fs": "npm:^3.1.0" + fs-minipass: "npm:^3.0.0" + glob: "npm:^10.2.2" + lru-cache: "npm:^10.0.1" + minipass: "npm:^7.0.3" + minipass-collect: "npm:^2.0.1" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + p-map: "npm:^4.0.0" + ssri: "npm:^10.0.0" + tar: "npm:^6.1.11" + unique-filename: "npm:^3.0.0" + checksum: 10c0/7992665305cc251a984f4fdbab1449d50e88c635bc43bf2785530c61d239c61b349e5734461baa461caaee65f040ab14e2d58e694f479c0810cffd181ba5eabc languageName: node linkType: hard -"call-bind@npm:^1.0.0, call-bind@npm:^1.0.2": - version: 1.0.2 - resolution: "call-bind@npm:1.0.2" +"call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.6, call-bind@npm:^1.0.7": + version: 1.0.7 + resolution: "call-bind@npm:1.0.7" dependencies: - function-bind: ^1.1.1 - get-intrinsic: ^1.0.2 - checksum: f8e31de9d19988a4b80f3e704788c4a2d6b6f3d17cfec4f57dc29ced450c53a49270dc66bf0fbd693329ee948dd33e6c90a329519aef17474a4d961e8d6426b0 + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.4" + set-function-length: "npm:^1.2.1" + checksum: 10c0/a3ded2e423b8e2a265983dba81c27e125b48eefb2655e7dfab6be597088da3d47c47976c24bc51b8fd9af1061f8f87b4ab78a314f3c77784b2ae2ba535ad8b8d languageName: node linkType: hard "callsites@npm:^3.0.0": version: 3.1.0 resolution: "callsites@npm:3.1.0" - checksum: 072d17b6abb459c2ba96598918b55868af677154bec7e73d222ef95a8fdb9bbf7dae96a8421085cdad8cd190d86653b5b6dc55a4484f2e5b2e27d5e0c3fc15b3 + checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 languageName: node linkType: hard @@ -1993,51 +1898,44 @@ __metadata: version: 3.0.0 resolution: "caniuse-api@npm:3.0.0" dependencies: - browserslist: ^4.0.0 - caniuse-lite: ^1.0.0 - lodash.memoize: ^4.1.2 - lodash.uniq: ^4.5.0 - checksum: db2a229383b20d0529b6b589dde99d7b6cb56ba371366f58cbbfa2929c9f42c01f873e2b6ef641d4eda9f0b4118de77dbb2805814670bdad4234bf08e720b0b4 + browserslist: "npm:^4.0.0" + caniuse-lite: "npm:^1.0.0" + lodash.memoize: "npm:^4.1.2" + lodash.uniq: "npm:^4.5.0" + checksum: 10c0/60f9e85a3331e6d761b1b03eec71ca38ef7d74146bece34694853033292156b815696573ed734b65583acf493e88163618eda915c6c826d46a024c71a9572b4c languageName: node linkType: hard -"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001449": - version: 1.0.30001450 - resolution: "caniuse-lite@npm:1.0.30001450" - checksum: 511b360bfc907b2e437699364cf96b83507bc45043926450056642332bcd6f65a1e72540c828534ae15e0ac906e3e9af46cb2bb84458dd580bc31478e9dce282 +"caniuse-lite@npm:^1.0.0, caniuse-lite@npm:^1.0.30001587": + version: 1.0.30001591 + resolution: "caniuse-lite@npm:1.0.30001591" + checksum: 10c0/21937d341c3d75994504db21340f65573a1e847a8ab33ee4964ed493994d6552864c494ba144485459abd9c711c75c0708bc9fa19f2bff525bff75ffb0a42c3b languageName: node linkType: hard -"caniuse-lite@npm:^1.0.30001517": - version: 1.0.30001525 - resolution: "caniuse-lite@npm:1.0.30001525" - checksum: a0d190c185b8e1220dbc72e42f310633059aa175ca3396eb781b249ac3da6c62b30cb8efc5fa24d632cb938f58d90b0c7772d1c9942b6643cf418c27c2cb8632 - languageName: node - linkType: hard - -"chai@npm:^4.3.7": - version: 4.3.7 - resolution: "chai@npm:4.3.7" +"chai@npm:^4.3.10": + version: 4.4.1 + resolution: "chai@npm:4.4.1" dependencies: - assertion-error: ^1.1.0 - check-error: ^1.0.2 - deep-eql: ^4.1.2 - get-func-name: ^2.0.0 - loupe: ^2.3.1 - pathval: ^1.1.1 - type-detect: ^4.0.5 - checksum: 0bba7d267848015246a66995f044ce3f0ebc35e530da3cbdf171db744e14cbe301ab913a8d07caf7952b430257ccbb1a4a983c570a7c5748dc537897e5131f7c + assertion-error: "npm:^1.1.0" + check-error: "npm:^1.0.3" + deep-eql: "npm:^4.1.3" + get-func-name: "npm:^2.0.2" + loupe: "npm:^2.3.6" + pathval: "npm:^1.1.1" + type-detect: "npm:^4.0.8" + checksum: 10c0/91590a8fe18bd6235dece04ccb2d5b4ecec49984b50924499bdcd7a95c02cb1fd2a689407c19bb854497bde534ef57525cfad6c7fdd2507100fd802fbc2aefbd languageName: node linkType: hard -"chalk@npm:^2.0.0, chalk@npm:^2.4.2": +"chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" dependencies: - ansi-styles: ^3.2.1 - escape-string-regexp: ^1.0.5 - supports-color: ^5.3.0 - checksum: ec3661d38fe77f681200f878edbd9448821924e0f93a9cefc0e26a33b145f1027a2084bf19967160d11e1f03bfe4eaffcabf5493b89098b2782c3fe0b03d80c2 + ansi-styles: "npm:^3.2.1" + escape-string-regexp: "npm:^1.0.5" + supports-color: "npm:^5.3.0" + checksum: 10c0/e6543f02ec877732e3a2d1c3c3323ddb4d39fbab687c23f526e25bd4c6a9bf3b83a696e8c769d078e04e5754921648f7821b2a2acfd16c550435fd630026e073 languageName: node linkType: hard @@ -2045,49 +1943,51 @@ __metadata: version: 4.1.2 resolution: "chalk@npm:4.1.2" dependencies: - ansi-styles: ^4.1.0 - supports-color: ^7.1.0 - checksum: fe75c9d5c76a7a98d45495b91b2172fa3b7a09e0cc9370e5c8feb1c567b85c4288e2b3fded7cfdd7359ac28d6b3844feb8b82b8686842e93d23c827c417e83fc + ansi-styles: "npm:^4.1.0" + supports-color: "npm:^7.1.0" + checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 languageName: node linkType: hard -"check-error@npm:^1.0.2": - version: 1.0.2 - resolution: "check-error@npm:1.0.2" - checksum: d9d106504404b8addd1ee3f63f8c0eaa7cd962a1a28eb9c519b1c4a1dc7098be38007fc0060f045ee00f075fbb7a2a4f42abcf61d68323677e11ab98dc16042e +"check-error@npm:^1.0.3": + version: 1.0.3 + resolution: "check-error@npm:1.0.3" + dependencies: + get-func-name: "npm:^2.0.2" + checksum: 10c0/94aa37a7315c0e8a83d0112b5bfb5a8624f7f0f81057c73e4707729cdd8077166c6aefb3d8e2b92c63ee130d4a2ff94bad46d547e12f3238cc1d78342a973841 languageName: node linkType: hard "chokidar@npm:>=3.0.0 <4.0.0": - version: 3.5.3 - resolution: "chokidar@npm:3.5.3" + version: 3.6.0 + resolution: "chokidar@npm:3.6.0" dependencies: - anymatch: ~3.1.2 - braces: ~3.0.2 - fsevents: ~2.3.2 - glob-parent: ~5.1.2 - is-binary-path: ~2.1.0 - is-glob: ~4.0.1 - normalize-path: ~3.0.0 - readdirp: ~3.6.0 + anymatch: "npm:~3.1.2" + braces: "npm:~3.0.2" + fsevents: "npm:~2.3.2" + glob-parent: "npm:~5.1.2" + is-binary-path: "npm:~2.1.0" + is-glob: "npm:~4.0.1" + normalize-path: "npm:~3.0.0" + readdirp: "npm:~3.6.0" dependenciesMeta: fsevents: optional: true - checksum: b49fcde40176ba007ff361b198a2d35df60d9bb2a5aab228279eb810feae9294a6b4649ab15981304447afe1e6ffbf4788ad5db77235dc770ab777c6e771980c + checksum: 10c0/8361dcd013f2ddbe260eacb1f3cb2f2c6f2b0ad118708a343a5ed8158941a39cb8fb1d272e0f389712e74ee90ce8ba864eece9e0e62b9705cb468a2f6d917462 languageName: node linkType: hard "chownr@npm:^2.0.0": version: 2.0.0 resolution: "chownr@npm:2.0.0" - checksum: c57cf9dd0791e2f18a5ee9c1a299ae6e801ff58fee96dc8bfd0dcb4738a6ce58dd252a3605b1c93c6418fe4f9d5093b28ffbf4d66648cb2a9c67eaef9679be2f + checksum: 10c0/594754e1303672171cc04e50f6c398ae16128eb134a88f801bf5354fd96f205320f23536a045d9abd8b51024a149696e51231565891d4efdab8846021ecf88e6 languageName: node linkType: hard "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" - checksum: 2ac8cd2b2f5ec986a3c743935ec85b07bc174d5421a5efc8017e1f146a1cf5f781ae962618f416352103b32c9cd7e203276e8c28241bbe946160cab16149fb68 + checksum: 10c0/1f90262d5f6230a17e27d0c190b09d47ebe7efdd76a03b5a1127863f7b3c9aec4c3e6c8bb3a7bbf81d553d56a1fd35728f5a8ef4c63f867ac8d690109742a8c1 languageName: node linkType: hard @@ -2095,17 +1995,17 @@ __metadata: version: 8.0.1 resolution: "cliui@npm:8.0.1" dependencies: - string-width: ^4.2.0 - strip-ansi: ^6.0.1 - wrap-ansi: ^7.0.0 - checksum: 79648b3b0045f2e285b76fb2e24e207c6db44323581e421c3acbd0e86454cba1b37aea976ab50195a49e7384b871e6dfb2247ad7dec53c02454ac6497394cb56 + string-width: "npm:^4.2.0" + strip-ansi: "npm:^6.0.1" + wrap-ansi: "npm:^7.0.0" + checksum: 10c0/4bda0f09c340cbb6dfdc1ed508b3ca080f12992c18d68c6be4d9cf51756033d5266e61ec57529e610dacbf4da1c634423b0c1b11037709cc6b09045cbd815df5 languageName: node linkType: hard "code-block-writer@npm:^11.0.0": version: 11.0.3 resolution: "code-block-writer@npm:11.0.3" - checksum: f0a2605f19963d7087267c9b0fd0b05a6638a50e7b29b70f97aa01a514f59475b0626f8aa092188df853ee6d96745426dfa132d6a677795df462c6ce32c21639 + checksum: 10c0/12fe4c02152a2b607e8913b39dcc31dcb5240f7c8933a3335d4e42a5418af409bf7ed454c80d6d8c12f9c59bb685dd88f9467874b46be62236dfbed446d03fd6 languageName: node linkType: hard @@ -2113,8 +2013,8 @@ __metadata: version: 1.9.3 resolution: "color-convert@npm:1.9.3" dependencies: - color-name: 1.1.3 - checksum: fd7a64a17cde98fb923b1dd05c5f2e6f7aefda1b60d67e8d449f9328b4e53b228a428fd38bfeaeb2db2ff6b6503a776a996150b80cdf224062af08a5c8a3a203 + color-name: "npm:1.1.3" + checksum: 10c0/5ad3c534949a8c68fca8fbc6f09068f435f0ad290ab8b2f76841b9e6af7e0bb57b98cb05b0e19fe33f5d91e5a8611ad457e5f69e0a484caad1f7487fd0e8253c languageName: node linkType: hard @@ -2122,38 +2022,29 @@ __metadata: version: 2.0.1 resolution: "color-convert@npm:2.0.1" dependencies: - color-name: ~1.1.4 - checksum: 79e6bdb9fd479a205c71d89574fccfb22bd9053bd98c6c4d870d65c132e5e904e6034978e55b43d69fcaa7433af2016ee203ce76eeba9cfa554b373e7f7db336 + color-name: "npm:~1.1.4" + checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 languageName: node linkType: hard "color-name@npm:1.1.3": version: 1.1.3 resolution: "color-name@npm:1.1.3" - checksum: 09c5d3e33d2105850153b14466501f2bfb30324a2f76568a408763a3b7433b0e50e5b4ab1947868e65cb101bb7cb75029553f2c333b6d4b8138a73fcc133d69d + checksum: 10c0/566a3d42cca25b9b3cd5528cd7754b8e89c0eb646b7f214e8e2eaddb69994ac5f0557d9c175eb5d8f0ad73531140d9c47525085ee752a91a2ab15ab459caf6d6 languageName: node linkType: hard "color-name@npm:~1.1.4": version: 1.1.4 resolution: "color-name@npm:1.1.4" - checksum: b0445859521eb4021cd0fb0cc1a75cecf67fceecae89b63f62b201cca8d345baf8b952c966862a9d9a2632987d4f6581f0ec8d957dfacece86f0a7919316f610 - languageName: node - linkType: hard - -"color-support@npm:^1.1.3": - version: 1.1.3 - resolution: "color-support@npm:1.1.3" - bin: - color-support: bin.js - checksum: 9b7356817670b9a13a26ca5af1c21615463b500783b739b7634a0c2047c16cef4b2865d7576875c31c3cddf9dd621fa19285e628f20198b233a5cfdda6d0793b + checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 languageName: node linkType: hard "colord@npm:^2.9.1": version: 2.9.3 resolution: "colord@npm:2.9.3" - checksum: 95d909bfbcfd8d5605cbb5af56f2d1ce2b323990258fd7c0d2eb0e6d3bb177254d7fb8213758db56bb4ede708964f78c6b992b326615f81a18a6aaf11d64c650 + checksum: 10c0/9699e956894d8996b28c686afe8988720785f476f59335c80ce852ded76ab3ebe252703aec53d9bef54f6219aea6b960fb3d9a8300058a1d0c0d4026460cd110 languageName: node linkType: hard @@ -2161,71 +2052,64 @@ __metadata: version: 1.0.8 resolution: "combined-stream@npm:1.0.8" dependencies: - delayed-stream: ~1.0.0 - checksum: 49fa4aeb4916567e33ea81d088f6584749fc90c7abec76fd516bf1c5aa5c79f3584b5ba3de6b86d26ddd64bae5329c4c7479343250cfe71c75bb366eae53bb7c + delayed-stream: "npm:~1.0.0" + checksum: 10c0/0dbb829577e1b1e839fa82b40c07ffaf7de8a09b935cadd355a73652ae70a88b4320db322f6634a4ad93424292fa80973ac6480986247f1734a1137debf271d5 languageName: node linkType: hard "commander@npm:^2.20.0, commander@npm:^2.20.3": version: 2.20.3 resolution: "commander@npm:2.20.3" - checksum: ab8c07884e42c3a8dbc5dd9592c606176c7eb5c1ca5ff274bcf907039b2c41de3626f684ea75ccf4d361ba004bbaff1f577d5384c155f3871e456bdf27becf9e + checksum: 10c0/74c781a5248c2402a0a3e966a0a2bba3c054aad144f5c023364be83265e796b20565aa9feff624132ff629aa64e16999fa40a743c10c12f7c61e96a794b99288 languageName: node linkType: hard "commander@npm:^6.2.1": version: 6.2.1 resolution: "commander@npm:6.2.1" - checksum: d7090410c0de6bc5c67d3ca41c41760d6d268f3c799e530aafb73b7437d1826bbf0d2a3edac33f8b57cc9887b4a986dce307fa5557e109be40eadb7c43b21742 + checksum: 10c0/85748abd9d18c8bc88febed58b98f66b7c591d9b5017cad459565761d7b29ca13b7783ea2ee5ce84bf235897333706c4ce29adf1ce15c8252780e7000e2ce9ea languageName: node linkType: hard "commander@npm:^7.2.0": version: 7.2.0 resolution: "commander@npm:7.2.0" - checksum: 53501cbeee61d5157546c0bef0fedb6cdfc763a882136284bed9a07225f09a14b82d2a84e7637edfd1a679fb35ed9502fd58ef1d091e6287f60d790147f68ddc + checksum: 10c0/8d690ff13b0356df7e0ebbe6c59b4712f754f4b724d4f473d3cc5b3fdcf978e3a5dc3078717858a2ceb50b0f84d0660a7f22a96cdc50fb877d0c9bb31593d23a languageName: node linkType: hard "commondir@npm:^1.0.1": version: 1.0.1 resolution: "commondir@npm:1.0.1" - checksum: 59715f2fc456a73f68826285718503340b9f0dd89bfffc42749906c5cf3d4277ef11ef1cca0350d0e79204f00f1f6d83851ececc9095dc88512a697ac0b9bdcb + checksum: 10c0/33a124960e471c25ee19280c9ce31ccc19574b566dc514fe4f4ca4c34fa8b0b57cf437671f5de380e11353ea9426213fca17687dd2ef03134fea2dbc53809fd6 languageName: node linkType: hard "component-emitter@npm:^1.3.0": - version: 1.3.0 - resolution: "component-emitter@npm:1.3.0" - checksum: b3c46de38ffd35c57d1c02488355be9f218e582aec72d72d1b8bbec95a3ac1b38c96cd6e03ff015577e68f550fbb361a3bfdbd9bb248be9390b7b3745691be6b + version: 1.3.1 + resolution: "component-emitter@npm:1.3.1" + checksum: 10c0/e4900b1b790b5e76b8d71b328da41482118c0f3523a516a41be598dc2785a07fd721098d9bf6e22d89b19f4fa4e1025160dc00317ea111633a3e4f75c2b86032 languageName: node linkType: hard "concat-map@npm:0.0.1": version: 0.0.1 resolution: "concat-map@npm:0.0.1" - checksum: 902a9f5d8967a3e2faf138d5cb784b9979bad2e6db5357c5b21c568df4ebe62bcb15108af1b2253744844eb964fc023fbd9afbbbb6ddd0bcc204c6fb5b7bf3af + checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f languageName: node linkType: hard "confusing-browser-globals@npm:^1.0.10": version: 1.0.11 resolution: "confusing-browser-globals@npm:1.0.11" - checksum: 3afc635abd37e566477f610e7978b15753f0e84025c25d49236f1f14d480117185516bdd40d2a2167e6bed8048641a9854964b9c067e3dcdfa6b5d0ad3c3a5ef + checksum: 10c0/475d0a284fa964a5182b519af5738b5b64bf7e413cfd703c1b3496bf6f4df9f827893a9b221c0ea5873c1476835beb1e0df569ba643eff0734010c1eb780589e languageName: node linkType: hard -"console-control-strings@npm:^1.1.0": - version: 1.1.0 - resolution: "console-control-strings@npm:1.1.0" - checksum: 8755d76787f94e6cf79ce4666f0c5519906d7f5b02d4b884cf41e11dcd759ed69c57da0670afd9236d229a46e0f9cf519db0cd829c6dca820bb5a5c3def584ed - languageName: node - linkType: hard - -"convert-source-map@npm:^1.7.0": - version: 1.9.0 - resolution: "convert-source-map@npm:1.9.0" - checksum: dc55a1f28ddd0e9485ef13565f8f756b342f9a46c4ae18b843fe3c30c675d058d6a4823eff86d472f187b176f0adf51ea7b69ea38be34be4a63cbbf91b0593c8 +"convert-source-map@npm:^2.0.0": + version: 2.0.0 + resolution: "convert-source-map@npm:2.0.0" + checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b languageName: node linkType: hard @@ -2233,39 +2117,39 @@ __metadata: version: 7.1.0 resolution: "cosmiconfig@npm:7.1.0" dependencies: - "@types/parse-json": ^4.0.0 - import-fresh: ^3.2.1 - parse-json: ^5.0.0 - path-type: ^4.0.0 - yaml: ^1.10.0 - checksum: c53bf7befc1591b2651a22414a5e786cd5f2eeaa87f3678a3d49d6069835a9d8d1aef223728e98aa8fec9a95bf831120d245096db12abe019fecb51f5696c96f + "@types/parse-json": "npm:^4.0.0" + import-fresh: "npm:^3.2.1" + parse-json: "npm:^5.0.0" + path-type: "npm:^4.0.0" + yaml: "npm:^1.10.0" + checksum: 10c0/b923ff6af581638128e5f074a5450ba12c0300b71302398ea38dbeabd33bbcaa0245ca9adbedfcf284a07da50f99ede5658c80bb3e39e2ce770a99d28a21ef03 languageName: node linkType: hard -"cross-spawn@npm:^7.0.2": +"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" dependencies: - path-key: ^3.1.0 - shebang-command: ^2.0.0 - which: ^2.0.1 - checksum: 671cc7c7288c3a8406f3c69a3ae2fc85555c04169e9d611def9a675635472614f1c0ed0ef80955d5b6d4e724f6ced67f0ad1bb006c2ea643488fcfef994d7f52 + path-key: "npm:^3.1.0" + shebang-command: "npm:^2.0.0" + which: "npm:^2.0.1" + checksum: 10c0/5738c312387081c98d69c98e105b6327b069197f864a60593245d64c8089c8a0a744e16349281210d56835bb9274130d825a78b2ad6853ca13cfbeffc0c31750 languageName: node linkType: hard "crypto@npm:^1.0.1": version: 1.0.1 resolution: "crypto@npm:1.0.1" - checksum: 087fe3165bd94c333a49e6ed66a0193911f63eac38a24f379b3001a5fe260a59c413646e53a0f67875ba13902b2686d81dc703cb2c147a4ec727dcdc04e5645e + checksum: 10c0/fcf7dbd68ac5415b7fde7d7208fe203038e92e83e8a8fcf6e86ab4771ce3dd026d6967a990ba56b9d1c771378210814d5c90d907d3739fbd1723d552ad6c8ab8 languageName: node linkType: hard "css-declaration-sorter@npm:^6.3.1": - version: 6.3.1 - resolution: "css-declaration-sorter@npm:6.3.1" + version: 6.4.1 + resolution: "css-declaration-sorter@npm:6.4.1" peerDependencies: postcss: ^8.0.9 - checksum: ff0d9989ee21ec4c42430b9bb86c43f973ed5024d68f30edc1e3fb07a22828ce3c3e5b922019f2ccbff606722e43c407c5c76e3cddac523ac4afcb31e4b2601c + checksum: 10c0/b8b664338dac528266a1ed9b27927ac51a907fb16bc1954fa9038b5286c442603bd494cc920c6a3616111309d18ee6b5a85b6d9927938efc942af452a5145160 languageName: node linkType: hard @@ -2273,12 +2157,12 @@ __metadata: version: 4.3.0 resolution: "css-select@npm:4.3.0" dependencies: - boolbase: ^1.0.0 - css-what: ^6.0.1 - domhandler: ^4.3.1 - domutils: ^2.8.0 - nth-check: ^2.0.1 - checksum: d6202736839194dd7f910320032e7cfc40372f025e4bf21ca5bf6eb0a33264f322f50ba9c0adc35dadd342d3d6fae5ca244779a4873afbfa76561e343f2058e0 + boolbase: "npm:^1.0.0" + css-what: "npm:^6.0.1" + domhandler: "npm:^4.3.1" + domutils: "npm:^2.8.0" + nth-check: "npm:^2.0.1" + checksum: 10c0/a489d8e5628e61063d5a8fe0fa1cc7ae2478cb334a388a354e91cf2908154be97eac9fa7ed4dffe87a3e06cf6fcaa6016553115335c4fd3377e13dac7bd5a8e1 languageName: node linkType: hard @@ -2286,16 +2170,16 @@ __metadata: version: 1.1.3 resolution: "css-tree@npm:1.1.3" dependencies: - mdn-data: 2.0.14 - source-map: ^0.6.1 - checksum: 79f9b81803991b6977b7fcb1588799270438274d89066ce08f117f5cdb5e20019b446d766c61506dd772c839df84caa16042d6076f20c97187f5abe3b50e7d1f + mdn-data: "npm:2.0.14" + source-map: "npm:^0.6.1" + checksum: 10c0/499a507bfa39b8b2128f49736882c0dd636b0cd3370f2c69f4558ec86d269113286b7df469afc955de6a68b0dba00bc533e40022a73698081d600072d5d83c1c languageName: node linkType: hard "css-what@npm:^6.0.1": version: 6.1.0 resolution: "css-what@npm:6.1.0" - checksum: b975e547e1e90b79625918f84e67db5d33d896e6de846c9b584094e529f0c63e2ab85ee33b9daffd05bff3a146a1916bec664e18bb76dd5f66cbff9fc13b2bbe + checksum: 10c0/a09f5a6b14ba8dcf57ae9a59474722e80f20406c53a61e9aedb0eedc693b135113ffe2983f4efc4b5065ae639442e9ae88df24941ef159c218b231011d733746 languageName: node linkType: hard @@ -2304,53 +2188,53 @@ __metadata: resolution: "cssesc@npm:3.0.0" bin: cssesc: bin/cssesc - checksum: f8c4ababffbc5e2ddf2fa9957dda1ee4af6048e22aeda1869d0d00843223c1b13ad3f5d88b51caa46c994225eacb636b764eb807a8883e2fb6f99b4f4e8c48b2 + checksum: 10c0/6bcfd898662671be15ae7827120472c5667afb3d7429f1f917737f3bf84c4176003228131b643ae74543f17a394446247df090c597bb9a728cce298606ed0aa7 languageName: node linkType: hard "cssfilter@npm:0.0.10": version: 0.0.10 resolution: "cssfilter@npm:0.0.10" - checksum: bc2c52bbb3426c3f2e4832edb6f8573e6cfa65b40b540932762d1e018f0f0157725e2991b77344bbc8266c6bbf4daa2803b0707cfb1bd0877505bf83a68e4b04 + checksum: 10c0/478a227a616fb6e9bb338eb95f690df141b86231ec737cbea574484f31a09a51db894b4921afc4987459dae08d584355fd689ff2a7a7c7a74de4bb4c072ce553 languageName: node linkType: hard -"cssnano-preset-default@npm:^5.2.13": - version: 5.2.13 - resolution: "cssnano-preset-default@npm:5.2.13" +"cssnano-preset-default@npm:^5.2.14": + version: 5.2.14 + resolution: "cssnano-preset-default@npm:5.2.14" dependencies: - css-declaration-sorter: ^6.3.1 - cssnano-utils: ^3.1.0 - postcss-calc: ^8.2.3 - postcss-colormin: ^5.3.0 - postcss-convert-values: ^5.1.3 - postcss-discard-comments: ^5.1.2 - postcss-discard-duplicates: ^5.1.0 - postcss-discard-empty: ^5.1.1 - postcss-discard-overridden: ^5.1.0 - postcss-merge-longhand: ^5.1.7 - postcss-merge-rules: ^5.1.3 - postcss-minify-font-values: ^5.1.0 - postcss-minify-gradients: ^5.1.1 - postcss-minify-params: ^5.1.4 - postcss-minify-selectors: ^5.2.1 - postcss-normalize-charset: ^5.1.0 - postcss-normalize-display-values: ^5.1.0 - postcss-normalize-positions: ^5.1.1 - postcss-normalize-repeat-style: ^5.1.1 - postcss-normalize-string: ^5.1.0 - postcss-normalize-timing-functions: ^5.1.0 - postcss-normalize-unicode: ^5.1.1 - postcss-normalize-url: ^5.1.0 - postcss-normalize-whitespace: ^5.1.1 - postcss-ordered-values: ^5.1.3 - postcss-reduce-initial: ^5.1.1 - postcss-reduce-transforms: ^5.1.0 - postcss-svgo: ^5.1.0 - postcss-unique-selectors: ^5.1.1 + css-declaration-sorter: "npm:^6.3.1" + cssnano-utils: "npm:^3.1.0" + postcss-calc: "npm:^8.2.3" + postcss-colormin: "npm:^5.3.1" + postcss-convert-values: "npm:^5.1.3" + postcss-discard-comments: "npm:^5.1.2" + postcss-discard-duplicates: "npm:^5.1.0" + postcss-discard-empty: "npm:^5.1.1" + postcss-discard-overridden: "npm:^5.1.0" + postcss-merge-longhand: "npm:^5.1.7" + postcss-merge-rules: "npm:^5.1.4" + postcss-minify-font-values: "npm:^5.1.0" + postcss-minify-gradients: "npm:^5.1.1" + postcss-minify-params: "npm:^5.1.4" + postcss-minify-selectors: "npm:^5.2.1" + postcss-normalize-charset: "npm:^5.1.0" + postcss-normalize-display-values: "npm:^5.1.0" + postcss-normalize-positions: "npm:^5.1.1" + postcss-normalize-repeat-style: "npm:^5.1.1" + postcss-normalize-string: "npm:^5.1.0" + postcss-normalize-timing-functions: "npm:^5.1.0" + postcss-normalize-unicode: "npm:^5.1.1" + postcss-normalize-url: "npm:^5.1.0" + postcss-normalize-whitespace: "npm:^5.1.1" + postcss-ordered-values: "npm:^5.1.3" + postcss-reduce-initial: "npm:^5.1.2" + postcss-reduce-transforms: "npm:^5.1.0" + postcss-svgo: "npm:^5.1.0" + postcss-unique-selectors: "npm:^5.1.1" peerDependencies: postcss: ^8.2.15 - checksum: f773de44f67f71e7301e1f4b4664b894c3a48bba4dadc16c559acd0b14ceafed228bdc76fe19d500b0ded9394732377069daadff2184465fa369f8dfd72d47e2 + checksum: 10c0/d125bdb9ac007f97f920e30be953c550a8e7de0cb9298f67e0bc9744f4b920039046b5a6b817e345872836b08689af747f82fbf2189c8bd48da3e6f0c1087b89 languageName: node linkType: hard @@ -2359,20 +2243,20 @@ __metadata: resolution: "cssnano-utils@npm:3.1.0" peerDependencies: postcss: ^8.2.15 - checksum: 975c84ce9174cf23bb1da1e9faed8421954607e9ea76440cd3bb0c1bea7e17e490d800fca5ae2812d1d9e9d5524eef23ede0a3f52497d7ccc628e5d7321536f2 + checksum: 10c0/057508645a3e7584decede1045daa5b362dbfa2f5df96c3527c7d52e41e787a3442a56a8ea0c0af6a757f518e79a459ee580a35c323ad0d0eec912afd67d7630 languageName: node linkType: hard -"cssnano@npm:*, cssnano@npm:^5.0.15": - version: 5.1.14 - resolution: "cssnano@npm:5.1.14" +"cssnano@npm:^5.0.15": + version: 5.1.15 + resolution: "cssnano@npm:5.1.15" dependencies: - cssnano-preset-default: ^5.2.13 - lilconfig: ^2.0.3 - yaml: ^1.10.2 + cssnano-preset-default: "npm:^5.2.14" + lilconfig: "npm:^2.0.3" + yaml: "npm:^1.10.2" peerDependencies: postcss: ^8.2.15 - checksum: 73463c723c5e598b37b8b4d2f014145bd72133e6581349a1b154904e0830e58de17afb1e801ed3ea3b18e386883964ce4d0299e43d4dc37d339214a956c6697f + checksum: 10c0/4252e4f4edd7a0fbdd4017825c0f8632b7a12ecbfdd432d2ff7ec268d48eb956a0a10bbf209602181f9f84ceeecea4a864719ecde03aa2cc48f5d9636fcf5f9a languageName: node linkType: hard @@ -2380,8 +2264,8 @@ __metadata: version: 4.2.0 resolution: "csso@npm:4.2.0" dependencies: - css-tree: ^1.1.2 - checksum: 380ba9663da3bcea58dee358a0d8c4468bb6539be3c439dc266ac41c047217f52fd698fb7e4b6b6ccdfb8cf53ef4ceed8cc8ceccb8dfca2aa628319826b5b998 + css-tree: "npm:^1.1.2" + checksum: 10c0/f8c6b1300efaa0f8855a7905ae3794a29c6496e7f16a71dec31eb6ca7cfb1f058a4b03fd39b66c4deac6cb06bf6b4ba86da7b67d7320389cb9994d52b924b903 languageName: node linkType: hard @@ -2389,8 +2273,8 @@ __metadata: version: 3.0.0 resolution: "cssstyle@npm:3.0.0" dependencies: - rrweb-cssom: ^0.6.0 - checksum: 31f694dfed9998ed93570fe539610837b878193dd8487c33cb12db8004333c53c2a3904166288bbec68388c72fb01014d46d3243ddfb02fe845989d852c06f27 + rrweb-cssom: "npm:^0.6.0" + checksum: 10c0/23acee092c1cec670fb7b8110e48abd740dc4e574d3b74848743067cb3377a86a1f64cf02606aabd7bb153785e68c2c1e09ce53295ddf7a4b470b3c7c55ec807 languageName: node linkType: hard @@ -2398,10 +2282,10 @@ __metadata: version: 4.0.0 resolution: "data-urls@npm:4.0.0" dependencies: - abab: ^2.0.6 - whatwg-mimetype: ^3.0.0 - whatwg-url: ^12.0.0 - checksum: 006e869b5bf079647949a3e9b1dd69d84b2d5d26e6b01c265485699bc96e83817d4b5aae758b2910a4c58c0601913f3a0034121c1ca2da268e9a244c57515b15 + abab: "npm:^2.0.6" + whatwg-mimetype: "npm:^3.0.0" + whatwg-url: "npm:^12.0.0" + checksum: 10c0/928d9a21db31d3dcee125d514fddfeb88067c348b1225e9d2c6ca55db16e1cbe49bf58c092cae7163de958f415fd5c612c2aef2eef87896e097656fce205d766 languageName: node linkType: hard @@ -2410,26 +2294,28 @@ __metadata: resolution: "date-fns-tz@npm:1.3.8" peerDependencies: date-fns: ">=2.0.0" - checksum: dbf17cb88de7c7b71a9f86b815ac62ebdbf725c030e78d2421309456b5001a85284a5b6763f4af0ba660183f12e876c165e725a0723f642edb7846407db03133 + checksum: 10c0/4cb16aeae3ea4a72ac4ae9f7db2011e38797aff122a78be16217a0492dde3938e1e62d21dbf1469a36fb4426824196233cedc70807f0a3033bca132bf76d563e languageName: node linkType: hard "date-fns@npm:^2.29.2": - version: 2.29.3 - resolution: "date-fns@npm:2.29.3" - checksum: e01cf5b62af04e05dfff921bb9c9933310ed0e1ae9a81eb8653452e64dc841acf7f6e01e1a5ae5644d0337e9a7f936175fd2cb6819dc122fdd9c5e86c56be484 + version: 2.30.0 + resolution: "date-fns@npm:2.30.0" + dependencies: + "@babel/runtime": "npm:^7.21.0" + checksum: 10c0/e4b521fbf22bc8c3db332bbfb7b094fd3e7627de0259a9d17c7551e2d2702608a7307a449206065916538e384f37b181565447ce2637ae09828427aed9cb5581 languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: - ms: 2.1.2 + ms: "npm:2.1.2" peerDependenciesMeta: supports-color: optional: true - checksum: 3dbad3f94ea64f34431a9cbf0bafb61853eda57bff2880036153438f50fb5a84f27683ba0d8e5426bf41a8c6ff03879488120cf5b3a761e77953169c0600a708 + checksum: 10c0/cedbec45298dd5c501d01b92b119cd3faebe5438c3917ff11ae1bff86a6c722930ac9c8659792824013168ba6db7c4668225d845c633fbdafbbf902a6389f736 languageName: node linkType: hard @@ -2437,97 +2323,95 @@ __metadata: version: 3.2.7 resolution: "debug@npm:3.2.7" dependencies: - ms: ^2.1.1 - checksum: b3d8c5940799914d30314b7c3304a43305fd0715581a919dacb8b3176d024a782062368405b47491516d2091d6462d4d11f2f4974a405048094f8bfebfa3071c + ms: "npm:^2.1.1" + checksum: 10c0/37d96ae42cbc71c14844d2ae3ba55adf462ec89fd3a999459dec3833944cd999af6007ff29c780f1c61153bcaaf2c842d1e4ce1ec621e4fc4923244942e4a02a languageName: node linkType: hard "decimal.js@npm:^10.4.3": version: 10.4.3 resolution: "decimal.js@npm:10.4.3" - checksum: 796404dcfa9d1dbfdc48870229d57f788b48c21c603c3f6554a1c17c10195fc1024de338b0cf9e1efe0c7c167eeb18f04548979bcc5fdfabebb7cc0ae3287bae + checksum: 10c0/6d60206689ff0911f0ce968d40f163304a6c1bc739927758e6efc7921cfa630130388966f16bf6ef6b838cb33679fbe8e7a78a2f3c478afce841fd55ac8fb8ee languageName: node linkType: hard "decode-uri-component@npm:^0.2.2": version: 0.2.2 resolution: "decode-uri-component@npm:0.2.2" - checksum: 95476a7d28f267292ce745eac3524a9079058bbb35767b76e3ee87d42e34cd0275d2eb19d9d08c3e167f97556e8a2872747f5e65cbebcac8b0c98d83e285f139 + checksum: 10c0/1f4fa54eb740414a816b3f6c24818fbfcabd74ac478391e9f4e2282c994127db02010ce804f3d08e38255493cfe68608b3f5c8e09fd6efc4ae46c807691f7a31 languageName: node linkType: hard -"deep-eql@npm:^4.1.2": +"deep-eql@npm:^4.1.3": version: 4.1.3 resolution: "deep-eql@npm:4.1.3" dependencies: - type-detect: ^4.0.0 - checksum: 7f6d30cb41c713973dc07eaadded848b2ab0b835e518a88b91bea72f34e08c4c71d167a722a6f302d3a6108f05afd8e6d7650689a84d5d29ec7fe6220420397f + type-detect: "npm:^4.0.0" + checksum: 10c0/ff34e8605d8253e1bf9fe48056e02c6f347b81d9b5df1c6650a1b0f6f847b4a86453b16dc226b34f853ef14b626e85d04e081b022e20b00cd7d54f079ce9bbdd languageName: node linkType: hard -"deep-is@npm:^0.1.3, deep-is@npm:~0.1.3": +"deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" - checksum: edb65dd0d7d1b9c40b2f50219aef30e116cedd6fc79290e740972c132c09106d2e80aa0bc8826673dd5a00222d4179c84b36a790eef63a4c4bca75a37ef90804 + checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c languageName: node linkType: hard "deepmerge@npm:^4.2.2": - version: 4.3.0 - resolution: "deepmerge@npm:4.3.0" - checksum: c7980eb5c5be040b371f1df0d566473875cfabed9f672ccc177b81ba8eee5686ce2478de2f1d0076391621cbe729e5eacda397179a59ef0f68901849647db126 + version: 4.3.1 + resolution: "deepmerge@npm:4.3.1" + checksum: 10c0/e53481aaf1aa2c4082b5342be6b6d8ad9dfe387bc92ce197a66dea08bd4265904a087e75e464f14d1347cf2ac8afe1e4c16b266e0561cc5df29382d3c5f80044 + languageName: node + linkType: hard + +"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.2, define-data-property@npm:^1.1.4": + version: 1.1.4 + resolution: "define-data-property@npm:1.1.4" + dependencies: + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + gopd: "npm:^1.0.1" + checksum: 10c0/dea0606d1483eb9db8d930d4eac62ca0fa16738b0b3e07046cddfacf7d8c868bbe13fa0cb263eb91c7d0d527960dc3f2f2471a69ed7816210307f6744fe62e37 languageName: node linkType: hard "define-lazy-prop@npm:^2.0.0": version: 2.0.0 resolution: "define-lazy-prop@npm:2.0.0" - checksum: 0115fdb065e0490918ba271d7339c42453d209d4cb619dfe635870d906731eff3e1ade8028bb461ea27ce8264ec5e22c6980612d332895977e89c1bbc80fcee2 + checksum: 10c0/db6c63864a9d3b7dc9def55d52764968a5af296de87c1b2cc71d8be8142e445208071953649e0386a8cc37cfcf9a2067a47207f1eb9ff250c2a269658fdae422 languageName: node linkType: hard -"define-properties@npm:^1.1.3, define-properties@npm:^1.1.4": - version: 1.1.4 - resolution: "define-properties@npm:1.1.4" +"define-properties@npm:^1.1.3, define-properties@npm:^1.2.0, define-properties@npm:^1.2.1": + version: 1.2.1 + resolution: "define-properties@npm:1.2.1" dependencies: - has-property-descriptors: ^1.0.0 - object-keys: ^1.1.1 - checksum: ce0aef3f9eb193562b5cfb79b2d2c86b6a109dfc9fdcb5f45d680631a1a908c06824ddcdb72b7573b54e26ace07f0a23420aaba0d5c627b34d2c1de8ef527e2b + define-data-property: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.0" + object-keys: "npm:^1.1.1" + checksum: 10c0/88a152319ffe1396ccc6ded510a3896e77efac7a1bfbaa174a7b00414a1747377e0bb525d303794a47cf30e805c2ec84e575758512c6e44a993076d29fd4e6c3 languageName: node linkType: hard "delayed-stream@npm:~1.0.0": version: 1.0.0 resolution: "delayed-stream@npm:1.0.0" - checksum: 46fe6e83e2cb1d85ba50bd52803c68be9bd953282fa7096f51fc29edd5d67ff84ff753c51966061e5ba7cb5e47ef6d36a91924eddb7f3f3483b1c560f77a0020 - languageName: node - linkType: hard - -"delegates@npm:^1.0.0": - version: 1.0.0 - resolution: "delegates@npm:1.0.0" - checksum: a51744d9b53c164ba9c0492471a1a2ffa0b6727451bdc89e31627fdf4adda9d51277cfcbfb20f0a6f08ccb3c436f341df3e92631a3440226d93a8971724771fd - languageName: node - linkType: hard - -"depd@npm:^1.1.2": - version: 1.1.2 - resolution: "depd@npm:1.1.2" - checksum: 6b406620d269619852885ce15965272b829df6f409724415e0002c8632ab6a8c0a08ec1f0bd2add05dc7bd7507606f7e2cc034fa24224ab829580040b835ecd9 + checksum: 10c0/d758899da03392e6712f042bec80aa293bbe9e9ff1b2634baae6a360113e708b91326594c8a486d475c69d6259afb7efacdc3537bfcda1c6c648e390ce601b19 languageName: node linkType: hard "desandro-matches-selector@npm:^2.0.0": version: 2.0.2 resolution: "desandro-matches-selector@npm:2.0.2" - checksum: 30979e6b45d7720d259d4db11ec026fcbee242deee5ec0944c265d7e386a7358ab29f7417cbc3631830d0dbe6e827940dee31f789ed865dba22880d209fc9f8e + checksum: 10c0/f4b1f42e6ccd6c97e93e3f99a64461eef2722075b03d8a9e349e31766436f8b385d1fd50802b024dae951dc69399f13de20a139c1187000fd5e2fcf11cb5eb00 languageName: node linkType: hard -"diff-sequences@npm:^29.4.3": +"diff-sequences@npm:^29.6.3": version: 29.6.3 resolution: "diff-sequences@npm:29.6.3" - checksum: f4914158e1f2276343d98ff5b31fc004e7304f5470bf0f1adb2ac6955d85a531a6458d33e87667f98f6ae52ebd3891bb47d420bb48a5bd8b7a27ee25b20e33aa + checksum: 10c0/32e27ac7dbffdf2fb0eb5a84efd98a9ad084fbabd5ac9abb8757c6770d5320d2acd172830b28c4add29bb873d59420601dfc805ac4064330ce59b1adfd0593b2 languageName: node linkType: hard @@ -2535,8 +2419,8 @@ __metadata: version: 3.0.1 resolution: "dir-glob@npm:3.0.1" dependencies: - path-type: ^4.0.0 - checksum: fa05e18324510d7283f55862f3161c6759a3f2f8dbce491a2fc14c8324c498286c54282c1f0e933cb930da8419b30679389499b919122952a4f8592362ef4615 + path-type: "npm:^4.0.0" + checksum: 10c0/dcac00920a4d503e38bb64001acb19df4efc14536ada475725e12f52c16777afdee4db827f55f13a908ee7efc0cb282e2e3dbaeeb98c0993dd93d1802d3bf00c languageName: node linkType: hard @@ -2544,8 +2428,8 @@ __metadata: version: 2.1.0 resolution: "doctrine@npm:2.1.0" dependencies: - esutils: ^2.0.2 - checksum: a45e277f7feaed309fe658ace1ff286c6e2002ac515af0aaf37145b8baa96e49899638c7cd47dccf84c3d32abfc113246625b3ac8f552d1046072adee13b0dc8 + esutils: "npm:^2.0.2" + checksum: 10c0/b6416aaff1f380bf56c3b552f31fdf7a69b45689368deca72d28636f41c16bb28ec3ebc40ace97db4c1afc0ceeb8120e8492fe0046841c94c2933b2e30a7d5ac languageName: node linkType: hard @@ -2553,8 +2437,8 @@ __metadata: version: 3.0.0 resolution: "doctrine@npm:3.0.0" dependencies: - esutils: ^2.0.2 - checksum: fd7673ca77fe26cd5cba38d816bc72d641f500f1f9b25b83e8ce28827fe2da7ad583a8da26ab6af85f834138cf8dae9f69b0cd6ab925f52ddab1754db44d99ce + esutils: "npm:^2.0.2" + checksum: 10c0/c96bdccabe9d62ab6fea9399fdff04a66e6563c1d6fb3a3a063e8d53c3bb136ba63e84250bbf63d00086a769ad53aef92d2bd483f03f837fc97b71cbee6b2520 languageName: node linkType: hard @@ -2562,17 +2446,17 @@ __metadata: version: 1.4.1 resolution: "dom-serializer@npm:1.4.1" dependencies: - domelementtype: ^2.0.1 - domhandler: ^4.2.0 - entities: ^2.0.0 - checksum: fbb0b01f87a8a2d18e6e5a388ad0f7ec4a5c05c06d219377da1abc7bb0f674d804f4a8a94e3f71ff15f6cb7dcfc75704a54b261db672b9b3ab03da6b758b0b22 + domelementtype: "npm:^2.0.1" + domhandler: "npm:^4.2.0" + entities: "npm:^2.0.0" + checksum: 10c0/67d775fa1ea3de52035c98168ddcd59418356943b5eccb80e3c8b3da53adb8e37edb2cc2f885802b7b1765bf5022aec21dfc32910d7f9e6de4c3148f095ab5e0 languageName: node linkType: hard "domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0": version: 2.3.0 resolution: "domelementtype@npm:2.3.0" - checksum: ee837a318ff702622f383409d1f5b25dd1024b692ef64d3096ff702e26339f8e345820f29a68bcdcea8cfee3531776b3382651232fbeae95612d6f0a75efb4f6 + checksum: 10c0/686f5a9ef0fff078c1412c05db73a0dce096190036f33e400a07e2a4518e9f56b1e324f5c576a0a747ef0e75b5d985c040b0d51945ce780c0dd3c625a18cd8c9 languageName: node linkType: hard @@ -2580,8 +2464,8 @@ __metadata: version: 4.0.0 resolution: "domexception@npm:4.0.0" dependencies: - webidl-conversions: ^7.0.0 - checksum: ddbc1268edf33a8ba02ccc596735ede80375ee0cf124b30d2f05df5b464ba78ef4f49889b6391df4a04954e63d42d5631c7fcf8b1c4f12bc531252977a5f13d5 + webidl-conversions: "npm:^7.0.0" + checksum: 10c0/774277cd9d4df033f852196e3c0077a34dbd15a96baa4d166e0e47138a80f4c0bdf0d94e4703e6ff5883cec56bb821a6fff84402d8a498e31de7c87eb932a294 languageName: node linkType: hard @@ -2589,8 +2473,8 @@ __metadata: version: 4.3.1 resolution: "domhandler@npm:4.3.1" dependencies: - domelementtype: ^2.2.0 - checksum: 4c665ceed016e1911bf7d1dadc09dc888090b64dee7851cccd2fcf5442747ec39c647bb1cb8c8919f8bbdd0f0c625a6bafeeed4b2d656bbecdbae893f43ffaaa + domelementtype: "npm:^2.2.0" + checksum: 10c0/5c199c7468cb052a8b5ab80b13528f0db3d794c64fc050ba793b574e158e67c93f8336e87fd81e9d5ee43b0e04aea4d8b93ed7be4899cb726a1601b3ba18538b languageName: node linkType: hard @@ -2598,24 +2482,24 @@ __metadata: version: 2.8.0 resolution: "domutils@npm:2.8.0" dependencies: - dom-serializer: ^1.0.1 - domelementtype: ^2.2.0 - domhandler: ^4.2.0 - checksum: abf7434315283e9aadc2a24bac0e00eab07ae4313b40cc239f89d84d7315ebdfd2fb1b5bf750a96bc1b4403d7237c7b2ebf60459be394d625ead4ca89b934391 + dom-serializer: "npm:^1.0.1" + domelementtype: "npm:^2.2.0" + domhandler: "npm:^4.2.0" + checksum: 10c0/d58e2ae01922f0dd55894e61d18119924d88091837887bf1438f2327f32c65eb76426bd9384f81e7d6dcfb048e0f83c19b222ad7101176ad68cdc9c695b563db languageName: node linkType: hard -"electron-to-chromium@npm:^1.4.284": - version: 1.4.288 - resolution: "electron-to-chromium@npm:1.4.288" - checksum: 312e1210f62c6bb593d1f57a15a1c64729e6a5edeacecc5d28dfb21f1a78ed3fac11805a0749a4e68f1fe1536229bf9d7bca36e1f34303369248a749a78aec1f +"eastasianwidth@npm:^0.2.0": + version: 0.2.0 + resolution: "eastasianwidth@npm:0.2.0" + checksum: 10c0/26f364ebcdb6395f95124fda411f63137a4bfb5d3a06453f7f23dfe52502905bd84e0488172e0f9ec295fdc45f05c23d5d91baf16bd26f0fe9acd777a188dc39 languageName: node linkType: hard -"electron-to-chromium@npm:^1.4.477": - version: 1.4.508 - resolution: "electron-to-chromium@npm:1.4.508" - checksum: 4475eb18f5805d43f84d9542364045a39b183a14cd9f4626e0951ea61d0fa4f84a5ed579c2c32189f9af4a27a31041d09fed78f60930ac36b3baa08547dd3aa6 +"electron-to-chromium@npm:^1.4.668": + version: 1.4.690 + resolution: "electron-to-chromium@npm:1.4.690" + checksum: 10c0/fba87387968bac5ac55161dc176e55d92a54146ae1e5fb16c3fdd5bf4f250ce6f271713659c0cdfa7fc0fd9a9ea1a79803f266fa2b936535b208c0759a4d3983 languageName: node linkType: hard @@ -2623,31 +2507,38 @@ __metadata: version: 8.0.0-rc04 resolution: "embla-carousel-wheel-gestures@npm:8.0.0-rc04" dependencies: - wheel-gestures: ^2.2.5 + wheel-gestures: "npm:^2.2.5" peerDependencies: embla-carousel: 8.0.0-rc03 - checksum: ace8ab88b661e8d360c2d99ae61c0fe61085ccd71f059ac7c6b8dc1ebb52c17919a00025010502d86012273490940c25c6c1fdb143f932670ab36c09fb4c6bca + checksum: 10c0/3b32b6565de5acd70a8cc3b427cfc411e9e2ed6671ce216efb8706f8897ac68da30e11e419d57aafbc6f9bf1d2405665c9d037002985f7033d770475f0569b62 languageName: node linkType: hard "embla-carousel@npm:8.0.0-rc14": version: 8.0.0-rc14 resolution: "embla-carousel@npm:8.0.0-rc14" - checksum: 48f6b7420fbb5c6800e84fb15f37fbd9b2b951b36a3f30ff66ee6121d7e722bf6bc28bd986a83136651f216940ca8e472d569774e74bf2ed01e4f8e349f74289 + checksum: 10c0/f8dcb810e43d2f898b60188648b7f23e1dd904b70d4935d067dde4a245ffc0527b793ddb4c744342c0268ad43ca6ca627619ced506d5fe08f27cdc34963b0b03 languageName: node linkType: hard "emoji-regex@npm:^8.0.0": version: 8.0.0 resolution: "emoji-regex@npm:8.0.0" - checksum: d4c5c39d5a9868b5fa152f00cada8a936868fd3367f33f71be515ecee4c803132d11b31a6222b2571b1e5f7e13890156a94880345594d0ce7e3c9895f560f192 + checksum: 10c0/b6053ad39951c4cf338f9092d7bfba448cdfd46fe6a2a034700b149ac9ffbc137e361cbd3c442297f86bed2e5f7576c1b54cc0a6bf8ef5106cc62f496af35010 + languageName: node + linkType: hard + +"emoji-regex@npm:^9.2.2": + version: 9.2.2 + resolution: "emoji-regex@npm:9.2.2" + checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 languageName: node linkType: hard "emojis-list@npm:^3.0.0": version: 3.0.0 resolution: "emojis-list@npm:3.0.0" - checksum: ddaaa02542e1e9436c03970eeed445f4ed29a5337dfba0fe0c38dfdd2af5da2429c2a0821304e8a8d1cadf27fdd5b22ff793571fa803ae16852a6975c65e8e70 + checksum: 10c0/7dc4394b7b910444910ad64b812392159a21e1a7ecc637c775a440227dcb4f80eff7fe61f4453a7d7603fa23d23d30cc93fe9e4b5ed985b88d6441cd4a35117b languageName: node linkType: hard @@ -2655,36 +2546,36 @@ __metadata: version: 0.1.13 resolution: "encoding@npm:0.1.13" dependencies: - iconv-lite: ^0.6.2 - checksum: bb98632f8ffa823996e508ce6a58ffcf5856330fde839ae42c9e1f436cc3b5cc651d4aeae72222916545428e54fd0f6aa8862fd8d25bdbcc4589f1e3f3715e7f + iconv-lite: "npm:^0.6.2" + checksum: 10c0/36d938712ff00fe1f4bac88b43bcffb5930c1efa57bbcdca9d67e1d9d6c57cfb1200fb01efe0f3109b2ce99b231f90779532814a81370a1bd3274a0f58585039 languageName: node linkType: hard "entities@npm:^2.0.0": version: 2.2.0 resolution: "entities@npm:2.2.0" - checksum: 19010dacaf0912c895ea262b4f6128574f9ccf8d4b3b65c7e8334ad0079b3706376360e28d8843ff50a78aabcb8f08f0a32dbfacdc77e47ed77ca08b713669b3 + checksum: 10c0/7fba6af1f116300d2ba1c5673fc218af1961b20908638391b4e1e6d5850314ee2ac3ec22d741b3a8060479911c99305164aed19b6254bde75e7e6b1b2c3f3aa3 languageName: node linkType: hard "entities@npm:^4.4.0": version: 4.5.0 resolution: "entities@npm:4.5.0" - checksum: 853f8ebd5b425d350bffa97dd6958143179a5938352ccae092c62d1267c4e392a039be1bae7d51b6e4ffad25f51f9617531fedf5237f15df302ccfb452cbf2d7 + checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 languageName: node linkType: hard "env-paths@npm:^2.2.0": version: 2.2.1 resolution: "env-paths@npm:2.2.1" - checksum: 65b5df55a8bab92229ab2b40dad3b387fad24613263d103a97f91c9fe43ceb21965cd3392b1ccb5d77088021e525c4e0481adb309625d0cb94ade1d1fb8dc17e + checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 languageName: node linkType: hard "err-code@npm:^2.0.2": version: 2.0.3 resolution: "err-code@npm:2.0.3" - checksum: 8b7b1be20d2de12d2255c0bc2ca638b7af5171142693299416e6a9339bd7d88fc8d7707d913d78e0993176005405a236b066b45666b27b797252c771156ace54 + checksum: 10c0/b642f7b4dd4a376e954947550a3065a9ece6733ab8e51ad80db727aaae0817c2e99b02a97a3d6cecc648a97848305e728289cf312d09af395403a90c9d4d8a66 languageName: node linkType: hard @@ -2692,69 +2583,100 @@ __metadata: version: 1.3.2 resolution: "error-ex@npm:1.3.2" dependencies: - is-arrayish: ^0.2.1 - checksum: c1c2b8b65f9c91b0f9d75f0debaa7ec5b35c266c2cac5de412c1a6de86d4cbae04ae44e510378cb14d032d0645a36925d0186f8bb7367bcc629db256b743a001 + is-arrayish: "npm:^0.2.1" + checksum: 10c0/ba827f89369b4c93382cfca5a264d059dfefdaa56ecc5e338ffa58a6471f5ed93b71a20add1d52290a4873d92381174382658c885ac1a2305f7baca363ce9cce languageName: node linkType: hard -"es-abstract@npm:^1.19.0, es-abstract@npm:^1.20.4": - version: 1.21.1 - resolution: "es-abstract@npm:1.21.1" +"es-abstract@npm:^1.22.1, es-abstract@npm:^1.22.3": + version: 1.22.5 + resolution: "es-abstract@npm:1.22.5" dependencies: - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - es-set-tostringtag: ^2.0.1 - es-to-primitive: ^1.2.1 - function-bind: ^1.1.1 - function.prototype.name: ^1.1.5 - get-intrinsic: ^1.1.3 - get-symbol-description: ^1.0.0 - globalthis: ^1.0.3 - gopd: ^1.0.1 - has: ^1.0.3 - has-property-descriptors: ^1.0.0 - has-proto: ^1.0.1 - has-symbols: ^1.0.3 - internal-slot: ^1.0.4 - is-array-buffer: ^3.0.1 - is-callable: ^1.2.7 - is-negative-zero: ^2.0.2 - is-regex: ^1.1.4 - is-shared-array-buffer: ^1.0.2 - is-string: ^1.0.7 - is-typed-array: ^1.1.10 - is-weakref: ^1.0.2 - object-inspect: ^1.12.2 - object-keys: ^1.1.1 - object.assign: ^4.1.4 - regexp.prototype.flags: ^1.4.3 - safe-regex-test: ^1.0.0 - string.prototype.trimend: ^1.0.6 - string.prototype.trimstart: ^1.0.6 - typed-array-length: ^1.0.4 - unbox-primitive: ^1.0.2 - which-typed-array: ^1.1.9 - checksum: 23ff60d42d17a55d150e7bcedbdb065d4077a8b98c436e0e2e1ef4dd532a6d78a56028673de0bd8ed464a43c46ba781c50d9af429b6a17e44dbd14c7d7fb7926 + array-buffer-byte-length: "npm:^1.0.1" + arraybuffer.prototype.slice: "npm:^1.0.3" + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.7" + es-define-property: "npm:^1.0.0" + es-errors: "npm:^1.3.0" + es-set-tostringtag: "npm:^2.0.3" + es-to-primitive: "npm:^1.2.1" + function.prototype.name: "npm:^1.1.6" + get-intrinsic: "npm:^1.2.4" + get-symbol-description: "npm:^1.0.2" + globalthis: "npm:^1.0.3" + gopd: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.2" + has-proto: "npm:^1.0.3" + has-symbols: "npm:^1.0.3" + hasown: "npm:^2.0.1" + internal-slot: "npm:^1.0.7" + is-array-buffer: "npm:^3.0.4" + is-callable: "npm:^1.2.7" + is-negative-zero: "npm:^2.0.3" + is-regex: "npm:^1.1.4" + is-shared-array-buffer: "npm:^1.0.3" + is-string: "npm:^1.0.7" + is-typed-array: "npm:^1.1.13" + is-weakref: "npm:^1.0.2" + object-inspect: "npm:^1.13.1" + object-keys: "npm:^1.1.1" + object.assign: "npm:^4.1.5" + regexp.prototype.flags: "npm:^1.5.2" + safe-array-concat: "npm:^1.1.0" + safe-regex-test: "npm:^1.0.3" + string.prototype.trim: "npm:^1.2.8" + string.prototype.trimend: "npm:^1.0.7" + string.prototype.trimstart: "npm:^1.0.7" + typed-array-buffer: "npm:^1.0.2" + typed-array-byte-length: "npm:^1.0.1" + typed-array-byte-offset: "npm:^1.0.2" + typed-array-length: "npm:^1.0.5" + unbox-primitive: "npm:^1.0.2" + which-typed-array: "npm:^1.1.14" + checksum: 10c0/4bca5a60f0dff6c0a5690d8e51374cfcb8760d5dbbb1069174b4d41461cf4e0c3e0c1993bccbc5aa0799ff078199f1bcde2122b8709e0d17c2beffafff01010a languageName: node linkType: hard -"es-set-tostringtag@npm:^2.0.1": - version: 2.0.1 - resolution: "es-set-tostringtag@npm:2.0.1" - dependencies: - get-intrinsic: ^1.1.3 - has: ^1.0.3 - has-tostringtag: ^1.0.0 - checksum: ec416a12948cefb4b2a5932e62093a7cf36ddc3efd58d6c58ca7ae7064475ace556434b869b0bbeb0c365f1032a8ccd577211101234b69837ad83ad204fff884 - languageName: node - linkType: hard - -"es-shim-unscopables@npm:^1.0.0": +"es-array-method-boxes-properly@npm:^1.0.0": version: 1.0.0 - resolution: "es-shim-unscopables@npm:1.0.0" + resolution: "es-array-method-boxes-properly@npm:1.0.0" + checksum: 10c0/4b7617d3fbd460d6f051f684ceca6cf7e88e6724671d9480388d3ecdd72119ddaa46ca31f2c69c5426a82e4b3091c1e81867c71dcdc453565cd90005ff2c382d + languageName: node + linkType: hard + +"es-define-property@npm:^1.0.0": + version: 1.0.0 + resolution: "es-define-property@npm:1.0.0" dependencies: - has: ^1.0.3 - checksum: 83e95cadbb6ee44d3644dfad60dcad7929edbc42c85e66c3e99aefd68a3a5c5665f2686885cddb47dfeabfd77bd5ea5a7060f2092a955a729bbd8834f0d86fa1 + get-intrinsic: "npm:^1.2.4" + checksum: 10c0/6bf3191feb7ea2ebda48b577f69bdfac7a2b3c9bcf97307f55fd6ef1bbca0b49f0c219a935aca506c993d8c5d8bddd937766cb760cd5e5a1071351f2df9f9aa4 + languageName: node + linkType: hard + +"es-errors@npm:^1.0.0, es-errors@npm:^1.2.1, es-errors@npm:^1.3.0": + version: 1.3.0 + resolution: "es-errors@npm:1.3.0" + checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85 + languageName: node + linkType: hard + +"es-set-tostringtag@npm:^2.0.3": + version: 2.0.3 + resolution: "es-set-tostringtag@npm:2.0.3" + dependencies: + get-intrinsic: "npm:^1.2.4" + has-tostringtag: "npm:^1.0.2" + hasown: "npm:^2.0.1" + checksum: 10c0/f22aff1585eb33569c326323f0b0d175844a1f11618b86e193b386f8be0ea9474cfbe46df39c45d959f7aa8f6c06985dc51dd6bce5401645ec5a74c4ceaa836a + languageName: node + linkType: hard + +"es-shim-unscopables@npm:^1.0.0, es-shim-unscopables@npm:^1.0.2": + version: 1.0.2 + resolution: "es-shim-unscopables@npm:1.0.2" + dependencies: + hasown: "npm:^2.0.0" + checksum: 10c0/f495af7b4b7601a4c0cfb893581c352636e5c08654d129590386a33a0432cf13a7bdc7b6493801cadd990d838e2839b9013d1de3b880440cb537825e834fe783 languageName: node linkType: hard @@ -2762,40 +2684,43 @@ __metadata: version: 1.2.1 resolution: "es-to-primitive@npm:1.2.1" dependencies: - is-callable: ^1.1.4 - is-date-object: ^1.0.1 - is-symbol: ^1.0.2 - checksum: 4ead6671a2c1402619bdd77f3503991232ca15e17e46222b0a41a5d81aebc8740a77822f5b3c965008e631153e9ef0580540007744521e72de8e33599fca2eed + is-callable: "npm:^1.1.4" + is-date-object: "npm:^1.0.1" + is-symbol: "npm:^1.0.2" + checksum: 10c0/0886572b8dc075cb10e50c0af62a03d03a68e1e69c388bd4f10c0649ee41b1fbb24840a1b7e590b393011b5cdbe0144b776da316762653685432df37d6de60f1 languageName: node linkType: hard -"esbuild@npm:^0.17.5": - version: 0.17.15 - resolution: "esbuild@npm:0.17.15" +"esbuild@npm:^0.19.3": + version: 0.19.12 + resolution: "esbuild@npm:0.19.12" dependencies: - "@esbuild/android-arm": 0.17.15 - "@esbuild/android-arm64": 0.17.15 - "@esbuild/android-x64": 0.17.15 - "@esbuild/darwin-arm64": 0.17.15 - "@esbuild/darwin-x64": 0.17.15 - "@esbuild/freebsd-arm64": 0.17.15 - "@esbuild/freebsd-x64": 0.17.15 - "@esbuild/linux-arm": 0.17.15 - "@esbuild/linux-arm64": 0.17.15 - "@esbuild/linux-ia32": 0.17.15 - "@esbuild/linux-loong64": 0.17.15 - "@esbuild/linux-mips64el": 0.17.15 - "@esbuild/linux-ppc64": 0.17.15 - "@esbuild/linux-riscv64": 0.17.15 - "@esbuild/linux-s390x": 0.17.15 - "@esbuild/linux-x64": 0.17.15 - "@esbuild/netbsd-x64": 0.17.15 - "@esbuild/openbsd-x64": 0.17.15 - "@esbuild/sunos-x64": 0.17.15 - "@esbuild/win32-arm64": 0.17.15 - "@esbuild/win32-ia32": 0.17.15 - "@esbuild/win32-x64": 0.17.15 + "@esbuild/aix-ppc64": "npm:0.19.12" + "@esbuild/android-arm": "npm:0.19.12" + "@esbuild/android-arm64": "npm:0.19.12" + "@esbuild/android-x64": "npm:0.19.12" + "@esbuild/darwin-arm64": "npm:0.19.12" + "@esbuild/darwin-x64": "npm:0.19.12" + "@esbuild/freebsd-arm64": "npm:0.19.12" + "@esbuild/freebsd-x64": "npm:0.19.12" + "@esbuild/linux-arm": "npm:0.19.12" + "@esbuild/linux-arm64": "npm:0.19.12" + "@esbuild/linux-ia32": "npm:0.19.12" + "@esbuild/linux-loong64": "npm:0.19.12" + "@esbuild/linux-mips64el": "npm:0.19.12" + "@esbuild/linux-ppc64": "npm:0.19.12" + "@esbuild/linux-riscv64": "npm:0.19.12" + "@esbuild/linux-s390x": "npm:0.19.12" + "@esbuild/linux-x64": "npm:0.19.12" + "@esbuild/netbsd-x64": "npm:0.19.12" + "@esbuild/openbsd-x64": "npm:0.19.12" + "@esbuild/sunos-x64": "npm:0.19.12" + "@esbuild/win32-arm64": "npm:0.19.12" + "@esbuild/win32-ia32": "npm:0.19.12" + "@esbuild/win32-x64": "npm:0.19.12" dependenciesMeta: + "@esbuild/aix-ppc64": + optional: true "@esbuild/android-arm": optional: true "@esbuild/android-arm64": @@ -2842,47 +2767,46 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 4e3640d7bc8f6edb3465c076eb519ccb7684382714a1b883e000a7a592f8e285501ec7e82cb68441dfec8f7be7f70f40b00129ceb05057f6fa87f95d2187370a + checksum: 10c0/0f2d21ffe24ebead64843f87c3aebe2e703a5ed9feb086a0728b24907fac2eb9923e4a79857d3df9059c915739bd7a870dd667972eae325c67f478b592b8582d languageName: node linkType: hard "escalade@npm:^3.1.1": - version: 3.1.1 - resolution: "escalade@npm:3.1.1" - checksum: a3e2a99f07acb74b3ad4989c48ca0c3140f69f923e56d0cba0526240ee470b91010f9d39001f2a4a313841d237ede70a729e92125191ba5d21e74b106800b133 + version: 3.1.2 + resolution: "escalade@npm:3.1.2" + checksum: 10c0/6b4adafecd0682f3aa1cd1106b8fff30e492c7015b178bc81b2d2f75106dabea6c6d6e8508fc491bd58e597c74abb0e8e2368f943ecb9393d4162e3c2f3cf287 languageName: node linkType: hard "escape-string-regexp@npm:^1.0.5": version: 1.0.5 resolution: "escape-string-regexp@npm:1.0.5" - checksum: 6092fda75c63b110c706b6a9bfde8a612ad595b628f0bd2147eea1d3406723020810e591effc7db1da91d80a71a737a313567c5abb3813e8d9c71f4aa595b410 + checksum: 10c0/a968ad453dd0c2724e14a4f20e177aaf32bb384ab41b674a8454afe9a41c5e6fe8903323e0a1052f56289d04bd600f81278edf140b0fcc02f5cac98d0f5b5371 languageName: node linkType: hard "escape-string-regexp@npm:^4.0.0": version: 4.0.0 resolution: "escape-string-regexp@npm:4.0.0" - checksum: 98b48897d93060f2322108bf29db0feba7dd774be96cd069458d1453347b25ce8682ecc39859d4bca2203cc0ab19c237bcc71755eff49a0f8d90beadeeba5cc5 + checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9 languageName: node linkType: hard "escodegen@npm:^2.0.0": - version: 2.0.0 - resolution: "escodegen@npm:2.0.0" + version: 2.1.0 + resolution: "escodegen@npm:2.1.0" dependencies: - esprima: ^4.0.1 - estraverse: ^5.2.0 - esutils: ^2.0.2 - optionator: ^0.8.1 - source-map: ~0.6.1 + esprima: "npm:^4.0.1" + estraverse: "npm:^5.2.0" + esutils: "npm:^2.0.2" + source-map: "npm:~0.6.1" dependenciesMeta: source-map: optional: true bin: escodegen: bin/escodegen.js esgenerate: bin/esgenerate.js - checksum: 5aa6b2966fafe0545e4e77936300cc94ad57cfe4dc4ebff9950492eaba83eef634503f12d7e3cbd644ecc1bab388ad0e92b06fd32222c9281a75d1cf02ec6cef + checksum: 10c0/e1450a1f75f67d35c061bf0d60888b15f62ab63aef9df1901cffc81cffbbb9e8b3de237c5502cf8613a017c1df3a3003881307c78835a1ab54d8c8d2206e01d3 languageName: node linkType: hard @@ -2890,73 +2814,75 @@ __metadata: version: 15.0.0 resolution: "eslint-config-airbnb-base@npm:15.0.0" dependencies: - confusing-browser-globals: ^1.0.10 - object.assign: ^4.1.2 - object.entries: ^1.1.5 - semver: ^6.3.0 + confusing-browser-globals: "npm:^1.0.10" + object.assign: "npm:^4.1.2" + object.entries: "npm:^1.1.5" + semver: "npm:^6.3.0" peerDependencies: eslint: ^7.32.0 || ^8.2.0 eslint-plugin-import: ^2.25.2 - checksum: 38626bad2ce2859fccac86b30cd2b86c9b7d8d71d458331860861dc05290a5b198bded2f4fb89efcb9046ec48f8ab4c4fb00365ba8916f27b172671da28b93ea + checksum: 10c0/93639d991654414756f82ad7860aac30b0dc6797277b7904ddb53ed88a32c470598696bbc6c503e066414024d305221974d3769e6642de65043bedf29cbbd30f languageName: node linkType: hard "eslint-config-prettier@npm:^8.5.0": - version: 8.6.0 - resolution: "eslint-config-prettier@npm:8.6.0" + version: 8.10.0 + resolution: "eslint-config-prettier@npm:8.10.0" peerDependencies: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: ff0d0dfc839a556355422293428637e8d35693de58dabf8638bf0b6529131a109d0b2ade77521aa6e54573bb842d7d9d322e465dd73dd61c7590fa3834c3fa81 + checksum: 10c0/19f8c497d9bdc111a17a61b25ded97217be3755bbc4714477dfe535ed539dddcaf42ef5cf8bb97908b058260cf89a3d7c565cb0be31096cbcd39f4c2fa5fe43c languageName: node linkType: hard -"eslint-import-resolver-node@npm:^0.3.7": - version: 0.3.7 - resolution: "eslint-import-resolver-node@npm:0.3.7" +"eslint-import-resolver-node@npm:^0.3.9": + version: 0.3.9 + resolution: "eslint-import-resolver-node@npm:0.3.9" dependencies: - debug: ^3.2.7 - is-core-module: ^2.11.0 - resolve: ^1.22.1 - checksum: 3379aacf1d2c6952c1b9666c6fa5982c3023df695430b0d391c0029f6403a7775414873d90f397e98ba6245372b6c8960e16e74d9e4a3b0c0a4582f3bdbe3d6e + debug: "npm:^3.2.7" + is-core-module: "npm:^2.13.0" + resolve: "npm:^1.22.4" + checksum: 10c0/0ea8a24a72328a51fd95aa8f660dcca74c1429806737cf10261ab90cfcaaf62fd1eff664b76a44270868e0a932711a81b250053942595bcd00a93b1c1575dd61 languageName: node linkType: hard -"eslint-module-utils@npm:^2.7.4": - version: 2.7.4 - resolution: "eslint-module-utils@npm:2.7.4" +"eslint-module-utils@npm:^2.8.0": + version: 2.8.1 + resolution: "eslint-module-utils@npm:2.8.1" dependencies: - debug: ^3.2.7 + debug: "npm:^3.2.7" peerDependenciesMeta: eslint: optional: true - checksum: 5da13645daff145a5c922896b258f8bba560722c3767254e458d894ff5fbb505d6dfd945bffa932a5b0ae06714da2379bd41011c4c20d2d59cc83e23895360f7 + checksum: 10c0/1aeeb97bf4b688d28de136ee57c824480c37691b40fa825c711a4caf85954e94b99c06ac639d7f1f6c1d69223bd21bcb991155b3e589488e958d5b83dfd0f882 languageName: node linkType: hard "eslint-plugin-import@npm:^2.25.4": - version: 2.27.5 - resolution: "eslint-plugin-import@npm:2.27.5" + version: 2.29.1 + resolution: "eslint-plugin-import@npm:2.29.1" dependencies: - array-includes: ^3.1.6 - array.prototype.flat: ^1.3.1 - array.prototype.flatmap: ^1.3.1 - debug: ^3.2.7 - doctrine: ^2.1.0 - eslint-import-resolver-node: ^0.3.7 - eslint-module-utils: ^2.7.4 - has: ^1.0.3 - is-core-module: ^2.11.0 - is-glob: ^4.0.3 - minimatch: ^3.1.2 - object.values: ^1.1.6 - resolve: ^1.22.1 - semver: ^6.3.0 - tsconfig-paths: ^3.14.1 + array-includes: "npm:^3.1.7" + array.prototype.findlastindex: "npm:^1.2.3" + array.prototype.flat: "npm:^1.3.2" + array.prototype.flatmap: "npm:^1.3.2" + debug: "npm:^3.2.7" + doctrine: "npm:^2.1.0" + eslint-import-resolver-node: "npm:^0.3.9" + eslint-module-utils: "npm:^2.8.0" + hasown: "npm:^2.0.0" + is-core-module: "npm:^2.13.1" + is-glob: "npm:^4.0.3" + minimatch: "npm:^3.1.2" + object.fromentries: "npm:^2.0.7" + object.groupby: "npm:^1.0.1" + object.values: "npm:^1.1.7" + semver: "npm:^6.3.1" + tsconfig-paths: "npm:^3.15.0" peerDependencies: eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - checksum: f500571a380167e25d72a4d925ef9a7aae8899eada57653e5f3051ec3d3c16d08271fcefe41a30a9a2f4fefc232f066253673ee4ea77b30dba65ae173dade85d + checksum: 10c0/5f35dfbf4e8e67f741f396987de9504ad125c49f4144508a93282b4ea0127e052bde65ab6def1f31b6ace6d5d430be698333f75bdd7dca3bc14226c92a083196 languageName: node linkType: hard @@ -2964,14 +2890,14 @@ __metadata: version: 4.2.1 resolution: "eslint-plugin-prettier@npm:4.2.1" dependencies: - prettier-linter-helpers: ^1.0.0 + prettier-linter-helpers: "npm:^1.0.0" peerDependencies: eslint: ">=7.28.0" prettier: ">=2.0.0" peerDependenciesMeta: eslint-config-prettier: optional: true - checksum: b9e839d2334ad8ec7a5589c5cb0f219bded260839a857d7a486997f9870e95106aa59b8756ff3f37202085ebab658de382b0267cae44c3a7f0eb0bcc03a4f6d6 + checksum: 10c0/c5e7316baeab9d96ac39c279f16686e837277e5c67a8006c6588bcff317edffdc1532fb580441eb598bc6770f6444006756b68a6575dff1cd85ebe227252d0b7 languageName: node linkType: hard @@ -2979,104 +2905,85 @@ __metadata: version: 5.1.1 resolution: "eslint-scope@npm:5.1.1" dependencies: - esrecurse: ^4.3.0 - estraverse: ^4.1.1 - checksum: 47e4b6a3f0cc29c7feedee6c67b225a2da7e155802c6ea13bbef4ac6b9e10c66cd2dcb987867ef176292bf4e64eccc680a49e35e9e9c669f4a02bac17e86abdb + esrecurse: "npm:^4.3.0" + estraverse: "npm:^4.1.1" + checksum: 10c0/d30ef9dc1c1cbdece34db1539a4933fe3f9b14e1ffb27ecc85987902ee663ad7c9473bbd49a9a03195a373741e62e2f807c4938992e019b511993d163450e70a languageName: node linkType: hard -"eslint-scope@npm:^7.1.1": - version: 7.1.1 - resolution: "eslint-scope@npm:7.1.1" +"eslint-scope@npm:^7.2.2": + version: 7.2.2 + resolution: "eslint-scope@npm:7.2.2" dependencies: - esrecurse: ^4.3.0 - estraverse: ^5.2.0 - checksum: 9f6e974ab2db641ca8ab13508c405b7b859e72afe9f254e8131ff154d2f40c99ad4545ce326fd9fde3212ff29707102562a4834f1c48617b35d98c71a97fbf3e + esrecurse: "npm:^4.3.0" + estraverse: "npm:^5.2.0" + checksum: 10c0/613c267aea34b5a6d6c00514e8545ef1f1433108097e857225fed40d397dd6b1809dffd11c2fde23b37ca53d7bf935fe04d2a18e6fc932b31837b6ad67e1c116 languageName: node linkType: hard -"eslint-utils@npm:^3.0.0": - version: 3.0.0 - resolution: "eslint-utils@npm:3.0.0" - dependencies: - eslint-visitor-keys: ^2.0.0 - peerDependencies: - eslint: ">=5" - checksum: 0668fe02f5adab2e5a367eee5089f4c39033af20499df88fe4e6aba2015c20720404d8c3d6349b6f716b08fdf91b9da4e5d5481f265049278099c4c836ccb619 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^2.0.0": - version: 2.1.0 - resolution: "eslint-visitor-keys@npm:2.1.0" - checksum: e3081d7dd2611a35f0388bbdc2f5da60b3a3c5b8b6e928daffff7391146b434d691577aa95064c8b7faad0b8a680266bcda0a42439c18c717b80e6718d7e267d - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^3.3.0": - version: 3.3.0 - resolution: "eslint-visitor-keys@npm:3.3.0" - checksum: d59e68a7c5a6d0146526b0eec16ce87fbf97fe46b8281e0d41384224375c4e52f5ffb9e16d48f4ea50785cde93f766b0c898e31ab89978d88b0e1720fbfb7808 +"eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": + version: 3.4.3 + resolution: "eslint-visitor-keys@npm:3.4.3" + checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 languageName: node linkType: hard "eslint@npm:^8.23.0": - version: 8.33.0 - resolution: "eslint@npm:8.33.0" + version: 8.57.0 + resolution: "eslint@npm:8.57.0" dependencies: - "@eslint/eslintrc": ^1.4.1 - "@humanwhocodes/config-array": ^0.11.8 - "@humanwhocodes/module-importer": ^1.0.1 - "@nodelib/fs.walk": ^1.2.8 - ajv: ^6.10.0 - chalk: ^4.0.0 - cross-spawn: ^7.0.2 - debug: ^4.3.2 - doctrine: ^3.0.0 - escape-string-regexp: ^4.0.0 - eslint-scope: ^7.1.1 - eslint-utils: ^3.0.0 - eslint-visitor-keys: ^3.3.0 - espree: ^9.4.0 - esquery: ^1.4.0 - esutils: ^2.0.2 - fast-deep-equal: ^3.1.3 - file-entry-cache: ^6.0.1 - find-up: ^5.0.0 - glob-parent: ^6.0.2 - globals: ^13.19.0 - grapheme-splitter: ^1.0.4 - ignore: ^5.2.0 - import-fresh: ^3.0.0 - imurmurhash: ^0.1.4 - is-glob: ^4.0.0 - is-path-inside: ^3.0.3 - js-sdsl: ^4.1.4 - js-yaml: ^4.1.0 - json-stable-stringify-without-jsonify: ^1.0.1 - levn: ^0.4.1 - lodash.merge: ^4.6.2 - minimatch: ^3.1.2 - natural-compare: ^1.4.0 - optionator: ^0.9.1 - regexpp: ^3.2.0 - strip-ansi: ^6.0.1 - strip-json-comments: ^3.1.0 - text-table: ^0.2.0 + "@eslint-community/eslint-utils": "npm:^4.2.0" + "@eslint-community/regexpp": "npm:^4.6.1" + "@eslint/eslintrc": "npm:^2.1.4" + "@eslint/js": "npm:8.57.0" + "@humanwhocodes/config-array": "npm:^0.11.14" + "@humanwhocodes/module-importer": "npm:^1.0.1" + "@nodelib/fs.walk": "npm:^1.2.8" + "@ungap/structured-clone": "npm:^1.2.0" + ajv: "npm:^6.12.4" + chalk: "npm:^4.0.0" + cross-spawn: "npm:^7.0.2" + debug: "npm:^4.3.2" + doctrine: "npm:^3.0.0" + escape-string-regexp: "npm:^4.0.0" + eslint-scope: "npm:^7.2.2" + eslint-visitor-keys: "npm:^3.4.3" + espree: "npm:^9.6.1" + esquery: "npm:^1.4.2" + esutils: "npm:^2.0.2" + fast-deep-equal: "npm:^3.1.3" + file-entry-cache: "npm:^6.0.1" + find-up: "npm:^5.0.0" + glob-parent: "npm:^6.0.2" + globals: "npm:^13.19.0" + graphemer: "npm:^1.4.0" + ignore: "npm:^5.2.0" + imurmurhash: "npm:^0.1.4" + is-glob: "npm:^4.0.0" + is-path-inside: "npm:^3.0.3" + js-yaml: "npm:^4.1.0" + json-stable-stringify-without-jsonify: "npm:^1.0.1" + levn: "npm:^0.4.1" + lodash.merge: "npm:^4.6.2" + minimatch: "npm:^3.1.2" + natural-compare: "npm:^1.4.0" + optionator: "npm:^0.9.3" + strip-ansi: "npm:^6.0.1" + text-table: "npm:^0.2.0" bin: eslint: bin/eslint.js - checksum: 727e63ab8b7acf281442323c5971f6afdd5b656fbcebc4476cf54e35af51b2f180617433fc5e1952f0449ca3f43a905527f9407ea4b8a7ea7562fc9c3f278d4c + checksum: 10c0/00bb96fd2471039a312435a6776fe1fd557c056755eaa2b96093ef3a8508c92c8775d5f754768be6b1dddd09fdd3379ddb231eeb9b6c579ee17ea7d68000a529 languageName: node linkType: hard -"espree@npm:^9.4.0": - version: 9.4.1 - resolution: "espree@npm:9.4.1" +"espree@npm:^9.6.0, espree@npm:^9.6.1": + version: 9.6.1 + resolution: "espree@npm:9.6.1" dependencies: - acorn: ^8.8.0 - acorn-jsx: ^5.3.2 - eslint-visitor-keys: ^3.3.0 - checksum: 4d266b0cf81c7dfe69e542c7df0f246e78d29f5b04dda36e514eb4c7af117ee6cfbd3280e560571ed82ff6c9c3f0003c05b82583fc7a94006db7497c4fe4270e + acorn: "npm:^8.9.0" + acorn-jsx: "npm:^5.3.2" + eslint-visitor-keys: "npm:^3.4.1" + checksum: 10c0/1a2e9b4699b715347f62330bcc76aee224390c28bb02b31a3752e9d07549c473f5f986720483c6469cf3cfb3c9d05df612ffc69eb1ee94b54b739e67de9bb460 languageName: node linkType: hard @@ -3086,16 +2993,16 @@ __metadata: bin: esparse: ./bin/esparse.js esvalidate: ./bin/esvalidate.js - checksum: b45bc805a613dbea2835278c306b91aff6173c8d034223fa81498c77dcbce3b2931bf6006db816f62eacd9fd4ea975dfd85a5b7f3c6402cfd050d4ca3c13a628 + checksum: 10c0/ad4bab9ead0808cf56501750fd9d3fb276f6b105f987707d059005d57e182d18a7c9ec7f3a01794ebddcca676773e42ca48a32d67a250c9d35e009ca613caba3 languageName: node linkType: hard -"esquery@npm:^1.4.0": - version: 1.4.0 - resolution: "esquery@npm:1.4.0" +"esquery@npm:^1.4.2": + version: 1.5.0 + resolution: "esquery@npm:1.5.0" dependencies: - estraverse: ^5.1.0 - checksum: a0807e17abd7fbe5fbd4fab673038d6d8a50675cdae6b04fbaa520c34581be0c5fa24582990e8acd8854f671dd291c78bb2efb9e0ed5b62f33bac4f9cf820210 + estraverse: "npm:^5.1.0" + checksum: 10c0/a084bd049d954cc88ac69df30534043fb2aee5555b56246493f42f27d1e168f00d9e5d4192e46f10290d312dc30dc7d58994d61a609c579c1219d636996f9213 languageName: node linkType: hard @@ -3103,107 +3010,140 @@ __metadata: version: 4.3.0 resolution: "esrecurse@npm:4.3.0" dependencies: - estraverse: ^5.2.0 - checksum: ebc17b1a33c51cef46fdc28b958994b1dc43cd2e86237515cbc3b4e5d2be6a811b2315d0a1a4d9d340b6d2308b15322f5c8291059521cc5f4802f65e7ec32837 + estraverse: "npm:^5.2.0" + checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 languageName: node linkType: hard "estraverse@npm:^4.1.1": version: 4.3.0 resolution: "estraverse@npm:4.3.0" - checksum: a6299491f9940bb246124a8d44b7b7a413a8336f5436f9837aaa9330209bd9ee8af7e91a654a3545aee9c54b3308e78ee360cef1d777d37cfef77d2fa33b5827 + checksum: 10c0/9cb46463ef8a8a4905d3708a652d60122a0c20bb58dec7e0e12ab0e7235123d74214fc0141d743c381813e1b992767e2708194f6f6e0f9fd00c1b4e0887b8b6d languageName: node linkType: hard "estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": version: 5.3.0 resolution: "estraverse@npm:5.3.0" - checksum: 072780882dc8416ad144f8fe199628d2b3e7bbc9989d9ed43795d2c90309a2047e6bc5979d7e2322a341163d22cfad9e21f4110597fe487519697389497e4e2b + checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 languageName: node linkType: hard "estree-walker@npm:^1.0.1": version: 1.0.1 resolution: "estree-walker@npm:1.0.1" - checksum: 7e70da539691f6db03a08e7ce94f394ce2eef4180e136d251af299d41f92fb2d28ebcd9a6e393e3728d7970aeb5358705ddf7209d52fbcb2dd4693f95dcf925f + checksum: 10c0/fa9e5f8c1bbe8d01e314c0f03067b64a4f22d4c58410fc5237060d0c15b81e58c23921c41acc60abbdab490f1fdfcbd6408ede2d03ca704454272e0244d61a55 languageName: node linkType: hard "estree-walker@npm:^2.0.1, estree-walker@npm:^2.0.2": version: 2.0.2 resolution: "estree-walker@npm:2.0.2" - checksum: 6151e6f9828abe2259e57f5fd3761335bb0d2ebd76dc1a01048ccee22fabcfef3c0859300f6d83ff0d1927849368775ec5a6d265dde2f6de5a1be1721cd94efc + checksum: 10c0/53a6c54e2019b8c914dc395890153ffdc2322781acf4bd7d1a32d7aedc1710807bdcd866ac133903d5629ec601fbb50abe8c2e5553c7f5a0afdd9b6af6c945af + languageName: node + linkType: hard + +"estree-walker@npm:^3.0.3": + version: 3.0.3 + resolution: "estree-walker@npm:3.0.3" + dependencies: + "@types/estree": "npm:^1.0.0" + checksum: 10c0/c12e3c2b2642d2bcae7d5aa495c60fa2f299160946535763969a1c83fc74518ffa9c2cd3a8b69ac56aea547df6a8aac25f729a342992ef0bbac5f1c73e78995d languageName: node linkType: hard "esutils@npm:^2.0.2": version: 2.0.3 resolution: "esutils@npm:2.0.3" - checksum: 22b5b08f74737379a840b8ed2036a5fb35826c709ab000683b092d9054e5c2a82c27818f12604bfc2a9a76b90b6834ef081edbc1c7ae30d1627012e067c6ec87 + checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 languageName: node linkType: hard "ev-emitter@npm:^1.0.0": version: 1.1.1 resolution: "ev-emitter@npm:1.1.1" - checksum: 3dd78a7620701ef8095794f611dd251bdd9023badf322b3d6fa5e10a660c50e83eec5ee5bbc7654682635cf7b8858c94e2c77e1d10bdc188a2b0593436403476 + checksum: 10c0/332dcb444de2b1d81035fb22a10dd33926311baa7ea6fc24f1de7b60c6eff5b7e133611000fce740471f0c8f95259d3914d49b4201af2d85a51f0aeb8cb1ceda languageName: node linkType: hard "eventemitter3@npm:^4.0.4": version: 4.0.7 resolution: "eventemitter3@npm:4.0.7" - checksum: 1875311c42fcfe9c707b2712c32664a245629b42bb0a5a84439762dd0fd637fc54d078155ea83c2af9e0323c9ac13687e03cfba79b03af9f40c89b4960099374 + checksum: 10c0/5f6d97cbcbac47be798e6355e3a7639a84ee1f7d9b199a07017f1d2f1e2fe236004d14fa5dfaeba661f94ea57805385e326236a6debbc7145c8877fbc0297c6b + languageName: node + linkType: hard + +"execa@npm:^8.0.1": + version: 8.0.1 + resolution: "execa@npm:8.0.1" + dependencies: + cross-spawn: "npm:^7.0.3" + get-stream: "npm:^8.0.1" + human-signals: "npm:^5.0.0" + is-stream: "npm:^3.0.0" + merge-stream: "npm:^2.0.0" + npm-run-path: "npm:^5.1.0" + onetime: "npm:^6.0.0" + signal-exit: "npm:^4.1.0" + strip-final-newline: "npm:^3.0.0" + checksum: 10c0/2c52d8775f5bf103ce8eec9c7ab3059909ba350a5164744e9947ed14a53f51687c040a250bda833f906d1283aa8803975b84e6c8f7a7c42f99dc8ef80250d1af + languageName: node + linkType: hard + +"exponential-backoff@npm:^3.1.1": + version: 3.1.1 + resolution: "exponential-backoff@npm:3.1.1" + checksum: 10c0/160456d2d647e6019640bd07111634d8c353038d9fa40176afb7cd49b0548bdae83b56d05e907c2cce2300b81cae35d800ef92fefb9d0208e190fa3b7d6bb579 languageName: node linkType: hard "fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": version: 3.1.3 resolution: "fast-deep-equal@npm:3.1.3" - checksum: e21a9d8d84f53493b6aa15efc9cfd53dd5b714a1f23f67fb5dc8f574af80df889b3bce25dc081887c6d25457cce704e636395333abad896ccdec03abaf1f3f9d + checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 languageName: node linkType: hard "fast-diff@npm:^1.1.2": - version: 1.2.0 - resolution: "fast-diff@npm:1.2.0" - checksum: 1b5306eaa9e826564d9e5ffcd6ebd881eb5f770b3f977fcbf38f05c824e42172b53c79920e8429c54eb742ce15a0caf268b0fdd5b38f6de52234c4a8368131ae + version: 1.3.0 + resolution: "fast-diff@npm:1.3.0" + checksum: 10c0/5c19af237edb5d5effda008c891a18a585f74bf12953be57923f17a3a4d0979565fc64dbc73b9e20926b9d895f5b690c618cbb969af0cf022e3222471220ad29 languageName: node linkType: hard "fast-glob@npm:^3.2.7, fast-glob@npm:^3.2.9": - version: 3.2.12 - resolution: "fast-glob@npm:3.2.12" + version: 3.3.2 + resolution: "fast-glob@npm:3.3.2" dependencies: - "@nodelib/fs.stat": ^2.0.2 - "@nodelib/fs.walk": ^1.2.3 - glob-parent: ^5.1.2 - merge2: ^1.3.0 - micromatch: ^4.0.4 - checksum: 0b1990f6ce831c7e28c4d505edcdaad8e27e88ab9fa65eedadb730438cfc7cde4910d6c975d6b7b8dc8a73da4773702ebcfcd6e3518e73938bb1383badfe01c2 + "@nodelib/fs.stat": "npm:^2.0.2" + "@nodelib/fs.walk": "npm:^1.2.3" + glob-parent: "npm:^5.1.2" + merge2: "npm:^1.3.0" + micromatch: "npm:^4.0.4" + checksum: 10c0/42baad7b9cd40b63e42039132bde27ca2cb3a4950d0a0f9abe4639ea1aa9d3e3b40f98b1fe31cbc0cc17b664c9ea7447d911a152fa34ec5b72977b125a6fc845 languageName: node linkType: hard "fast-json-stable-stringify@npm:^2.0.0": version: 2.1.0 resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: b191531e36c607977e5b1c47811158733c34ccb3bfde92c44798929e9b4154884378536d26ad90dfecd32e1ffc09c545d23535ad91b3161a27ddbb8ebe0cbecb + checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b languageName: node linkType: hard -"fast-levenshtein@npm:^2.0.6, fast-levenshtein@npm:~2.0.6": +"fast-levenshtein@npm:^2.0.6": version: 2.0.6 resolution: "fast-levenshtein@npm:2.0.6" - checksum: 92cfec0a8dfafd9c7a15fba8f2cc29cd0b62b85f056d99ce448bbcd9f708e18ab2764bda4dd5158364f4145a7c72788538994f0d1787b956ef0d1062b0f7c24c + checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4 languageName: node linkType: hard "fastq@npm:^1.6.0": - version: 1.15.0 - resolution: "fastq@npm:1.15.0" + version: 1.17.1 + resolution: "fastq@npm:1.17.1" dependencies: - reusify: ^1.0.4 - checksum: 0170e6bfcd5d57a70412440b8ef600da6de3b2a6c5966aeaf0a852d542daff506a0ee92d6de7679d1de82e644bce69d7a574a6c93f0b03964b5337eed75ada1a + reusify: "npm:^1.0.4" + checksum: 10c0/1095f16cea45fb3beff558bb3afa74ca7a9250f5a670b65db7ed585f92b4b48381445cd328b3d87323da81e43232b5d5978a8201bde84e0cd514310f1ea6da34 languageName: node linkType: hard @@ -3211,8 +3151,8 @@ __metadata: version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" dependencies: - flat-cache: ^3.0.4 - checksum: f49701feaa6314c8127c3c2f6173cfefff17612f5ed2daaafc6da13b5c91fd43e3b2a58fd0d63f9f94478a501b167615931e7200e31485e320f74a33885a9c74 + flat-cache: "npm:^3.0.4" + checksum: 10c0/58473e8a82794d01b38e5e435f6feaf648e3f36fdb3a56e98f417f4efae71ad1c0d4ebd8a9a7c50c3ad085820a93fc7494ad721e0e4ebc1da3573f4e1c3c7cdd languageName: node linkType: hard @@ -3220,15 +3160,15 @@ __metadata: version: 7.0.1 resolution: "fill-range@npm:7.0.1" dependencies: - to-regex-range: ^5.0.1 - checksum: cc283f4e65b504259e64fd969bcf4def4eb08d85565e906b7d36516e87819db52029a76b6363d0f02d0d532f0033c9603b9e2d943d56ee3b0d4f7ad3328ff917 + to-regex-range: "npm:^5.0.1" + checksum: 10c0/7cdad7d426ffbaadf45aeb5d15ec675bbd77f7597ad5399e3d2766987ed20bda24d5fac64b3ee79d93276f5865608bb22344a26b9b1ae6c4d00bd94bf611623f languageName: node linkType: hard "filter-obj@npm:^1.1.0": version: 1.1.0 resolution: "filter-obj@npm:1.1.0" - checksum: cf2104a7c45ff48e7f505b78a3991c8f7f30f28bd8106ef582721f321f1c6277f7751aacd5d83026cb079d9d5091082f588d14a72e7c5d720ece79118fa61e10 + checksum: 10c0/071e0886b2b50238ca5026c5bbf58c26a7c1a1f720773b8c7813d16ba93d0200de977af14ac143c5ac18f666b2cfc83073f3a5fe6a4e996c49e0863d5500fccf languageName: node linkType: hard @@ -3236,10 +3176,10 @@ __metadata: version: 3.3.2 resolution: "find-cache-dir@npm:3.3.2" dependencies: - commondir: ^1.0.1 - make-dir: ^3.0.2 - pkg-dir: ^4.1.0 - checksum: 1e61c2e64f5c0b1c535bd85939ae73b0e5773142713273818cc0b393ee3555fb0fd44e1a5b161b8b6c3e03e98c2fcc9c227d784850a13a90a8ab576869576817 + commondir: "npm:^1.0.1" + make-dir: "npm:^3.0.2" + pkg-dir: "npm:^4.1.0" + checksum: 10c0/92747cda42bff47a0266b06014610981cfbb71f55d60f2c8216bc3108c83d9745507fb0b14ecf6ab71112bed29cd6fb1a137ee7436179ea36e11287e3159e587 languageName: node linkType: hard @@ -3247,9 +3187,9 @@ __metadata: version: 4.1.0 resolution: "find-up@npm:4.1.0" dependencies: - locate-path: ^5.0.0 - path-exists: ^4.0.0 - checksum: 4c172680e8f8c1f78839486e14a43ef82e9decd0e74145f40707cc42e7420506d5ec92d9a11c22bd2c48fb0c384ea05dd30e10dd152fefeec6f2f75282a8b844 + locate-path: "npm:^5.0.0" + path-exists: "npm:^4.0.0" + checksum: 10c0/0406ee89ebeefa2d507feb07ec366bebd8a6167ae74aa4e34fb4c4abd06cf782a3ce26ae4194d70706f72182841733f00551c209fe575cb00bd92104056e78c1 languageName: node linkType: hard @@ -3257,9 +3197,9 @@ __metadata: version: 5.0.0 resolution: "find-up@npm:5.0.0" dependencies: - locate-path: ^6.0.0 - path-exists: ^4.0.0 - checksum: 07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095 + locate-path: "npm:^6.0.0" + path-exists: "npm:^4.0.0" + checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a languageName: node linkType: hard @@ -3267,25 +3207,26 @@ __metadata: version: 2.0.7 resolution: "fizzy-ui-utils@npm:2.0.7" dependencies: - desandro-matches-selector: ^2.0.0 - checksum: 001e54effa22c4f62728b90a25e8eb5477057ab53d0184e1c3231bbdfc7c34e278418fbcaf7d63c75ede823d82e61245e668ce8cba90e1c5699de960188c654f + desandro-matches-selector: "npm:^2.0.0" + checksum: 10c0/4c36d45db4e2e0cf1507aa9633af6710a12bdc047146fa89505e10aedc5bfb16cbfb0da686d5dfd89a37e1da4bce86bbee365e22be88705ab4ffccd530b4902a languageName: node linkType: hard "flat-cache@npm:^3.0.4": - version: 3.0.4 - resolution: "flat-cache@npm:3.0.4" + version: 3.2.0 + resolution: "flat-cache@npm:3.2.0" dependencies: - flatted: ^3.1.0 - rimraf: ^3.0.2 - checksum: 4fdd10ecbcbf7d520f9040dd1340eb5dfe951e6f0ecf2252edeec03ee68d989ec8b9a20f4434270e71bcfd57800dc09b3344fca3966b2eb8f613072c7d9a2365 + flatted: "npm:^3.2.9" + keyv: "npm:^4.5.3" + rimraf: "npm:^3.0.2" + checksum: 10c0/b76f611bd5f5d68f7ae632e3ae503e678d205cf97a17c6ab5b12f6ca61188b5f1f7464503efae6dc18683ed8f0b41460beb48ac4b9ac63fe6201296a91ba2f75 languageName: node linkType: hard -"flatted@npm:^3.1.0": - version: 3.2.7 - resolution: "flatted@npm:3.2.7" - checksum: 427633049d55bdb80201c68f7eb1cbd533e03eac541f97d3aecab8c5526f12a20ccecaeede08b57503e772c769e7f8680b37e8d482d1e5f8d7e2194687f9ea35 +"flatted@npm:^3.2.9": + version: 3.3.1 + resolution: "flatted@npm:3.3.1" + checksum: 10c0/324166b125ee07d4ca9bcf3a5f98d915d5db4f39d711fba640a3178b959919aae1f7cfd8aabcfef5826ed8aa8a2aa14cc85b2d7d18ff638ddf4ae3df39573eaf languageName: node linkType: hard @@ -3293,8 +3234,18 @@ __metadata: version: 0.3.3 resolution: "for-each@npm:0.3.3" dependencies: - is-callable: ^1.1.3 - checksum: 6c48ff2bc63362319c65e2edca4a8e1e3483a2fabc72fbe7feaf8c73db94fc7861bd53bc02c8a66a0c1dd709da6b04eec42e0abdd6b40ce47305ae92a25e5d28 + is-callable: "npm:^1.1.3" + checksum: 10c0/22330d8a2db728dbf003ec9182c2d421fbcd2969b02b4f97ec288721cda63eb28f2c08585ddccd0f77cb2930af8d958005c9e72f47141dc51816127a118f39aa + languageName: node + linkType: hard + +"foreground-child@npm:^3.1.0": + version: 3.1.1 + resolution: "foreground-child@npm:3.1.1" + dependencies: + cross-spawn: "npm:^7.0.0" + signal-exit: "npm:^4.0.1" + checksum: 10c0/9700a0285628abaeb37007c9a4d92bd49f67210f09067638774338e146c8e9c825c5c877f072b2f75f41dc6a2d0be8664f79ffc03f6576649f54a84fb9b47de0 languageName: node linkType: hard @@ -3302,10 +3253,10 @@ __metadata: version: 4.0.0 resolution: "form-data@npm:4.0.0" dependencies: - asynckit: ^0.4.0 - combined-stream: ^1.0.8 - mime-types: ^2.1.12 - checksum: 01135bf8675f9d5c61ff18e2e2932f719ca4de964e3be90ef4c36aacfc7b9cb2fceb5eca0b7e0190e3383fe51c5b37f4cb80b62ca06a99aaabfcfd6ac7c9328c + asynckit: "npm:^0.4.0" + combined-stream: "npm:^1.0.8" + mime-types: "npm:^2.1.12" + checksum: 10c0/cb6f3ac49180be03ff07ba3ff125f9eba2ff0b277fb33c7fc47569fc5e616882c5b1c69b9904c4c4187e97dd0419dd03b134174756f296dec62041e6527e2c6e languageName: node linkType: hard @@ -3313,70 +3264,70 @@ __metadata: version: 0.0.0-use.local resolution: "frigate-hass-card@workspace:." dependencies: - "@babel/core": ^7.19.0 - "@babel/plugin-proposal-class-properties": ^7.18.6 - "@babel/plugin-proposal-decorators": ^7.19.0 - "@cycjimmy/jsmpeg-player": ^6.0.4 - "@dermotduffy/custom-card-helpers": ^1.9.0 - "@dermotduffy/panzoom": ^4.5.1 - "@egjs/hammerjs": ^2.0.17 - "@graphiteds/core": ^1.9.11 - "@lit-labs/scoped-registry-mixin": ^1.0.1 - "@lit-labs/task": ^1.1.3 - "@rollup/plugin-babel": ^5.3.1 - "@rollup/plugin-commonjs": ^22.0.2 - "@rollup/plugin-image": ^3.0.2 - "@rollup/plugin-json": ^4.1.0 - "@rollup/plugin-node-resolve": ^13.3.0 - "@rollup/plugin-replace": ^4.0.0 - "@types/bluebird": ^3.5.36 - "@types/lodash-es": ^4.17.5 - "@types/masonry-layout": ^4.2.5 - "@typescript-eslint/eslint-plugin": ^5.36.2 - "@typescript-eslint/parser": ^5.36.2 - "@vitest/coverage-istanbul": ^0.34.3 - component-emitter: ^1.3.0 - crypto: ^1.0.1 - date-fns: ^2.29.2 - date-fns-tz: ^1.3.7 - embla-carousel: 8.0.0-rc14 - embla-carousel-wheel-gestures: 8.0.0-rc04 - eslint: ^8.23.0 - eslint-config-airbnb-base: ^15.0.0 - eslint-config-prettier: ^8.5.0 - eslint-plugin-import: ^2.25.4 - eslint-plugin-prettier: ^4.2.1 - home-assistant-js-websocket: ^8.0.0 - jsdom: ^21.1.1 - keycharm: ^0.4.0 - lit: ^2.3.1 - lodash-es: ^4.17.21 - masonry-layout: ^4.2.2 - moment: ^2.29.4 - prettier: ^2.6.0 - propagating-hammerjs: ^2.0.1 - quick-lru: ^6.1.0 - rollup: ^2.79.0 - rollup-plugin-git-info: ^1.0.0 - rollup-plugin-serve: ^2.0.1 - rollup-plugin-styles: ^4.0.0 - rollup-plugin-terser: ^7.0.2 - rollup-plugin-typescript2: ^0.33.0 - rollup-plugin-visualizer: ^5.8.2 - sass: ^1.54.9 - screenfull: ^6.0.2 - side-drawer: ^3.1.0 - ts-prune: ^0.10.3 - typescript: ^4.9.5 - uuid: ^8.3.2 - vis-data: ^7.1.4 - vis-timeline: ^7.7.0 - vis-util: ^5.0.2 - vitest: ^0.34.3 - vitest-mock-extended: ^1.2.1 - web-dialog: ^0.0.11 - xss: ^1.0.14 - zod: ^3.21.4 + "@babel/core": "npm:^7.19.0" + "@babel/plugin-proposal-class-properties": "npm:^7.18.6" + "@babel/plugin-proposal-decorators": "npm:^7.19.0" + "@cycjimmy/jsmpeg-player": "npm:^6.0.4" + "@dermotduffy/custom-card-helpers": "npm:^1.9.0" + "@dermotduffy/panzoom": "npm:^4.5.1" + "@egjs/hammerjs": "npm:^2.0.17" + "@graphiteds/core": "npm:^1.9.11" + "@lit-labs/scoped-registry-mixin": "npm:^1.0.3" + "@lit-labs/task": "npm:^1.1.3" + "@rollup/plugin-babel": "npm:^5.3.1" + "@rollup/plugin-commonjs": "npm:^22.0.2" + "@rollup/plugin-image": "npm:^3.0.2" + "@rollup/plugin-json": "npm:^4.1.0" + "@rollup/plugin-node-resolve": "npm:^13.3.0" + "@rollup/plugin-replace": "npm:^4.0.0" + "@types/bluebird": "npm:^3.5.36" + "@types/lodash-es": "npm:^4.17.5" + "@types/masonry-layout": "npm:^4.2.5" + "@typescript-eslint/eslint-plugin": "npm:^5.36.2" + "@typescript-eslint/parser": "npm:^5.36.2" + "@vitest/coverage-istanbul": "npm:^1.3.1" + component-emitter: "npm:^1.3.0" + crypto: "npm:^1.0.1" + date-fns: "npm:^2.29.2" + date-fns-tz: "npm:^1.3.7" + embla-carousel: "npm:8.0.0-rc14" + embla-carousel-wheel-gestures: "npm:8.0.0-rc04" + eslint: "npm:^8.23.0" + eslint-config-airbnb-base: "npm:^15.0.0" + eslint-config-prettier: "npm:^8.5.0" + eslint-plugin-import: "npm:^2.25.4" + eslint-plugin-prettier: "npm:^4.2.1" + home-assistant-js-websocket: "npm:^8.0.0" + jsdom: "npm:^21.1.1" + keycharm: "npm:^0.4.0" + lit: "npm:^3.1.2" + lodash-es: "npm:^4.17.21" + masonry-layout: "npm:^4.2.2" + moment: "npm:^2.29.4" + prettier: "npm:^2.6.0" + propagating-hammerjs: "npm:^2.0.1" + quick-lru: "npm:^6.1.0" + rollup: "npm:^2.79.0" + rollup-plugin-git-info: "npm:^1.0.0" + rollup-plugin-serve: "npm:^2.0.1" + rollup-plugin-styles: "npm:^4.0.0" + rollup-plugin-terser: "npm:^7.0.2" + rollup-plugin-typescript2: "npm:^0.33.0" + rollup-plugin-visualizer: "npm:^5.8.2" + sass: "npm:^1.54.9" + screenfull: "npm:^6.0.2" + side-drawer: "npm:^3.1.0" + ts-prune: "npm:^0.10.3" + typescript: "npm:^4.9.5" + uuid: "npm:^8.3.2" + vis-data: "npm:^7.1.9" + vis-timeline: "npm:^7.7.3" + vis-util: "npm:^5.0.2" + vitest: "npm:^1.3.1" + vitest-mock-extended: "npm:^1.3.1" + web-dialog: "npm:^0.0.11" + xss: "npm:^1.0.14" + zod: "npm:^3.21.4" languageName: unknown linkType: soft @@ -3384,136 +3335,139 @@ __metadata: version: 10.1.0 resolution: "fs-extra@npm:10.1.0" dependencies: - graceful-fs: ^4.2.0 - jsonfile: ^6.0.1 - universalify: ^2.0.0 - checksum: dc94ab37096f813cc3ca12f0f1b5ad6744dfed9ed21e953d72530d103cea193c2f81584a39e9dee1bea36de5ee66805678c0dddc048e8af1427ac19c00fffc50 + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10c0/5f579466e7109719d162a9249abbeffe7f426eb133ea486e020b89bc6d67a741134076bf439983f2eb79276ceaf6bd7b7c1e43c3fd67fe889863e69072fb0a5e languageName: node linkType: hard -"fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0": +"fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" dependencies: - minipass: ^3.0.0 - checksum: 1b8d128dae2ac6cc94230cc5ead341ba3e0efaef82dab46a33d171c044caaa6ca001364178d42069b2809c35a1c3c35079a32107c770e9ffab3901b59af8c8b1 + minipass: "npm:^3.0.0" + checksum: 10c0/703d16522b8282d7299337539c3ed6edddd1afe82435e4f5b76e34a79cd74e488a8a0e26a636afc2440e1a23b03878e2122e3a2cfe375a5cf63c37d92b86a004 + languageName: node + linkType: hard + +"fs-minipass@npm:^3.0.0": + version: 3.0.3 + resolution: "fs-minipass@npm:3.0.3" + dependencies: + minipass: "npm:^7.0.3" + checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 languageName: node linkType: hard "fs.realpath@npm:^1.0.0": version: 1.0.0 resolution: "fs.realpath@npm:1.0.0" - checksum: 99ddea01a7e75aa276c250a04eedeffe5662bce66c65c07164ad6264f9de18fb21be9433ead460e54cff20e31721c811f4fb5d70591799df5f85dce6d6746fd0 + checksum: 10c0/444cf1291d997165dfd4c0d58b69f0e4782bfd9149fd72faa4fe299e68e0e93d6db941660b37dd29153bf7186672ececa3b50b7e7249477b03fdf850f287c948 languageName: node linkType: hard -"fsevents@npm:~2.3.2": - version: 2.3.2 - resolution: "fsevents@npm:2.3.2" +"fsevents@npm:~2.3.2, fsevents@npm:~2.3.3": + version: 2.3.3 + resolution: "fsevents@npm:2.3.3" dependencies: - node-gyp: latest - checksum: 97ade64e75091afee5265e6956cb72ba34db7819b4c3e94c431d4be2b19b8bb7a2d4116da417950c3425f17c8fe693d25e20212cac583ac1521ad066b77ae31f + node-gyp: "npm:latest" + checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 conditions: os=darwin languageName: node linkType: hard -"fsevents@patch:fsevents@~2.3.2#~builtin": - version: 2.3.2 - resolution: "fsevents@patch:fsevents@npm%3A2.3.2#~builtin::version=2.3.2&hash=df0bf1" +"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin, fsevents@patch:fsevents@npm%3A~2.3.3#optional!builtin": + version: 2.3.3 + resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" dependencies: - node-gyp: latest + node-gyp: "npm:latest" conditions: os=darwin languageName: node linkType: hard -"function-bind@npm:^1.1.1": - version: 1.1.1 - resolution: "function-bind@npm:1.1.1" - checksum: b32fbaebb3f8ec4969f033073b43f5c8befbb58f1a79e12f1d7490358150359ebd92f49e72ff0144f65f2c48ea2a605bff2d07965f548f6474fd8efd95bf361a +"function-bind@npm:^1.1.2": + version: 1.1.2 + resolution: "function-bind@npm:1.1.2" + checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5 languageName: node linkType: hard -"function.prototype.name@npm:^1.1.5": - version: 1.1.5 - resolution: "function.prototype.name@npm:1.1.5" +"function.prototype.name@npm:^1.1.6": + version: 1.1.6 + resolution: "function.prototype.name@npm:1.1.6" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - es-abstract: ^1.19.0 - functions-have-names: ^1.2.2 - checksum: acd21d733a9b649c2c442f067567743214af5fa248dbeee69d8278ce7df3329ea5abac572be9f7470b4ec1cd4d8f1040e3c5caccf98ebf2bf861a0deab735c27 + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + functions-have-names: "npm:^1.2.3" + checksum: 10c0/9eae11294905b62cb16874adb4fc687927cda3162285e0ad9612e6a1d04934005d46907362ea9cdb7428edce05a2f2c3dabc3b2d21e9fd343e9bb278230ad94b languageName: node linkType: hard -"functions-have-names@npm:^1.2.2": +"functions-have-names@npm:^1.2.3": version: 1.2.3 resolution: "functions-have-names@npm:1.2.3" - checksum: c3f1f5ba20f4e962efb71344ce0a40722163e85bee2101ce25f88214e78182d2d2476aa85ef37950c579eb6cf6ee811c17b3101bb84004bb75655f3e33f3fdb5 - languageName: node - linkType: hard - -"gauge@npm:^4.0.3": - version: 4.0.4 - resolution: "gauge@npm:4.0.4" - dependencies: - aproba: ^1.0.3 || ^2.0.0 - color-support: ^1.1.3 - console-control-strings: ^1.1.0 - has-unicode: ^2.0.1 - signal-exit: ^3.0.7 - string-width: ^4.2.3 - strip-ansi: ^6.0.1 - wide-align: ^1.1.5 - checksum: 788b6bfe52f1dd8e263cda800c26ac0ca2ff6de0b6eee2fe0d9e3abf15e149b651bd27bf5226be10e6e3edb5c4e5d5985a5a1a98137e7a892f75eff76467ad2d + checksum: 10c0/33e77fd29bddc2d9bb78ab3eb854c165909201f88c75faa8272e35899e2d35a8a642a15e7420ef945e1f64a9670d6aa3ec744106b2aa42be68ca5114025954ca languageName: node linkType: hard "gensync@npm:^1.0.0-beta.2": version: 1.0.0-beta.2 resolution: "gensync@npm:1.0.0-beta.2" - checksum: a7437e58c6be12aa6c90f7730eac7fa9833dc78872b4ad2963d2031b00a3367a93f98aec75f9aaac7220848e4026d67a8655e870b24f20a543d103c0d65952ec + checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8 languageName: node linkType: hard "get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" - checksum: b9769a836d2a98c3ee734a88ba712e62703f1df31b94b784762c433c27a386dd6029ff55c2a920c392e33657d80191edbf18c61487e198844844516f843496b9 + checksum: 10c0/c6c7b60271931fa752aeb92f2b47e355eac1af3a2673f47c9589e8f8a41adc74d45551c1bc57b5e66a80609f10ffb72b6f575e4370d61cc3f7f3aaff01757cde languageName: node linkType: hard -"get-func-name@npm:^2.0.0": - version: 2.0.0 - resolution: "get-func-name@npm:2.0.0" - checksum: 8d82e69f3e7fab9e27c547945dfe5cc0c57fc0adf08ce135dddb01081d75684a03e7a0487466f478872b341d52ac763ae49e660d01ab83741f74932085f693c3 +"get-func-name@npm:^2.0.1, get-func-name@npm:^2.0.2": + version: 2.0.2 + resolution: "get-func-name@npm:2.0.2" + checksum: 10c0/89830fd07623fa73429a711b9daecdb304386d237c71268007f788f113505ef1d4cc2d0b9680e072c5082490aec9df5d7758bf5ac6f1c37062855e8e3dc0b9df languageName: node linkType: hard -"get-intrinsic@npm:^1.0.2, get-intrinsic@npm:^1.1.1, get-intrinsic@npm:^1.1.3": - version: 1.2.0 - resolution: "get-intrinsic@npm:1.2.0" +"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": + version: 1.2.4 + resolution: "get-intrinsic@npm:1.2.4" dependencies: - function-bind: ^1.1.1 - has: ^1.0.3 - has-symbols: ^1.0.3 - checksum: 78fc0487b783f5c58cf2dccafc3ae656ee8d2d8062a8831ce4a95e7057af4587a1d4882246c033aca0a7b4965276f4802b45cc300338d1b77a73d3e3e3f4877d + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + has-proto: "npm:^1.0.1" + has-symbols: "npm:^1.0.3" + hasown: "npm:^2.0.0" + checksum: 10c0/0a9b82c16696ed6da5e39b1267104475c47e3a9bdbe8b509dfe1710946e38a87be70d759f4bb3cda042d76a41ef47fe769660f3b7c0d1f68750299344ffb15b7 languageName: node linkType: hard "get-size@npm:^2.0.2": version: 2.0.3 resolution: "get-size@npm:2.0.3" - checksum: 18d5a5fdb3f541db8b1e6ad46a5411d4bb7da3061d2ef7e544db3bbce7a13543f05c91fd40c7f68b4bc4bc035c160fed23c45514cde7d5fb18de1cce10208b19 + checksum: 10c0/c9703caa61b4d38385eab34aa5068f3a25ab40f6d9cda6dac3f0dc4dcd8da38f7b0283035e71c9f52a47b670b9315372cae46f58d66ad709a4939e57c1fdc6cc languageName: node linkType: hard -"get-symbol-description@npm:^1.0.0": - version: 1.0.0 - resolution: "get-symbol-description@npm:1.0.0" +"get-stream@npm:^8.0.1": + version: 8.0.1 + resolution: "get-stream@npm:8.0.1" + checksum: 10c0/5c2181e98202b9dae0bb4a849979291043e5892eb40312b47f0c22b9414fc9b28a3b6063d2375705eb24abc41ecf97894d9a51f64ff021511b504477b27b4290 + languageName: node + linkType: hard + +"get-symbol-description@npm:^1.0.2": + version: 1.0.2 + resolution: "get-symbol-description@npm:1.0.2" dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.1 - checksum: 9ceff8fe968f9270a37a1f73bf3f1f7bda69ca80f4f80850670e0e7b9444ff99323f7ac52f96567f8b5f5fbe7ac717a0d81d3407c7313e82810c6199446a5247 + call-bind: "npm:^1.0.5" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.4" + checksum: 10c0/867be6d63f5e0eb026cb3b0ef695ec9ecf9310febb041072d2e142f260bd91ced9eeb426b3af98791d1064e324e653424afa6fd1af17dee373bea48ae03162bc languageName: node linkType: hard @@ -3521,8 +3475,8 @@ __metadata: version: 5.1.2 resolution: "glob-parent@npm:5.1.2" dependencies: - is-glob: ^4.0.1 - checksum: f4f2bfe2425296e8a47e36864e4f42be38a996db40420fe434565e4480e3322f18eb37589617a98640c5dc8fdec1a387007ee18dbb1f3f5553409c34d17f425e + is-glob: "npm:^4.0.1" + checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee languageName: node linkType: hard @@ -3530,8 +3484,23 @@ __metadata: version: 6.0.2 resolution: "glob-parent@npm:6.0.2" dependencies: - is-glob: ^4.0.3 - checksum: c13ee97978bef4f55106b71e66428eb1512e71a7466ba49025fc2aec59a5bfb0954d5abd58fc5ee6c9b076eef4e1f6d3375c2e964b88466ca390da4419a786a8 + is-glob: "npm:^4.0.3" + checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8 + languageName: node + linkType: hard + +"glob@npm:^10.2.2, glob@npm:^10.3.10": + version: 10.3.10 + resolution: "glob@npm:10.3.10" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^2.3.5" + minimatch: "npm:^9.0.1" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + path-scurry: "npm:^1.10.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/13d8a1feb7eac7945f8c8480e11cd4a44b24d26503d99a8d8ac8d5aefbf3e9802a2b6087318a829fad04cb4e829f25c5f4f1110c68966c498720dd261c7e344d languageName: node linkType: hard @@ -3539,42 +3508,29 @@ __metadata: version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^3.1.1 - once: ^1.3.0 - path-is-absolute: ^1.0.0 - checksum: 29452e97b38fa704dabb1d1045350fb2467cf0277e155aa9ff7077e90ad81d1ea9d53d3ee63bd37c05b09a065e90f16aec4a65f5b8de401d1dac40bc5605d133 - languageName: node - linkType: hard - -"glob@npm:^8.0.1": - version: 8.1.0 - resolution: "glob@npm:8.1.0" - dependencies: - fs.realpath: ^1.0.0 - inflight: ^1.0.4 - inherits: 2 - minimatch: ^5.0.1 - once: ^1.3.0 - checksum: 92fbea3221a7d12075f26f0227abac435de868dd0736a17170663783296d0dd8d3d532a5672b4488a439bf5d7fb85cdd07c11185d6cd39184f0385cbdfb86a47 + fs.realpath: "npm:^1.0.0" + inflight: "npm:^1.0.4" + inherits: "npm:2" + minimatch: "npm:^3.1.1" + once: "npm:^1.3.0" + path-is-absolute: "npm:^1.0.0" + checksum: 10c0/65676153e2b0c9095100fe7f25a778bf45608eeb32c6048cf307f579649bcc30353277b3b898a3792602c65764e5baa4f643714dfbdfd64ea271d210c7a425fe languageName: node linkType: hard "globals@npm:^11.1.0": version: 11.12.0 resolution: "globals@npm:11.12.0" - checksum: 67051a45eca3db904aee189dfc7cd53c20c7d881679c93f6146ddd4c9f4ab2268e68a919df740d39c71f4445d2b38ee360fc234428baea1dbdfe68bbcb46979e + checksum: 10c0/758f9f258e7b19226bd8d4af5d3b0dcf7038780fb23d82e6f98932c44e239f884847f1766e8fa9cc5635ccb3204f7fa7314d4408dd4002a5e8ea827b4018f0a1 languageName: node linkType: hard "globals@npm:^13.19.0": - version: 13.20.0 - resolution: "globals@npm:13.20.0" + version: 13.24.0 + resolution: "globals@npm:13.24.0" dependencies: - type-fest: ^0.20.2 - checksum: ad1ecf914bd051325faad281d02ea2c0b1df5d01bd94d368dcc5513340eac41d14b3c61af325768e3c7f8d44576e72780ec0b6f2d366121f8eec6e03c3a3b97a + type-fest: "npm:^0.20.2" + checksum: 10c0/d3c11aeea898eb83d5ec7a99508600fbe8f83d2cf00cbb77f873dbf2bcb39428eff1b538e4915c993d8a3b3473fa71eeebfe22c9bb3a3003d1e26b1f2c8a42cd languageName: node linkType: hard @@ -3582,8 +3538,8 @@ __metadata: version: 1.0.3 resolution: "globalthis@npm:1.0.3" dependencies: - define-properties: ^1.1.3 - checksum: fbd7d760dc464c886d0196166d92e5ffb4c84d0730846d6621a39fbbc068aeeb9c8d1421ad330e94b7bca4bb4ea092f5f21f3d36077812af5d098b4dc006c998 + define-properties: "npm:^1.1.3" + checksum: 10c0/0db6e9af102a5254630351557ac15e6909bc7459d3e3f6b001e59fe784c96d31108818f032d9095739355a88467459e6488ff16584ee6250cd8c27dec05af4b0 languageName: node linkType: hard @@ -3591,13 +3547,13 @@ __metadata: version: 11.1.0 resolution: "globby@npm:11.1.0" dependencies: - array-union: ^2.1.0 - dir-glob: ^3.0.1 - fast-glob: ^3.2.9 - ignore: ^5.2.0 - merge2: ^1.4.1 - slash: ^3.0.0 - checksum: b4be8885e0cfa018fc783792942d53926c35c50b3aefd3fdcfb9d22c627639dc26bd2327a40a0b74b074100ce95bb7187bfeae2f236856aa3de183af7a02aea6 + array-union: "npm:^2.1.0" + dir-glob: "npm:^3.0.1" + fast-glob: "npm:^3.2.9" + ignore: "npm:^5.2.0" + merge2: "npm:^1.4.1" + slash: "npm:^3.0.0" + checksum: 10c0/b39511b4afe4bd8a7aead3a27c4ade2b9968649abab0a6c28b1a90141b96ca68ca5db1302f7c7bd29eab66bf51e13916b8e0a3d0ac08f75e1e84a39b35691189 languageName: node linkType: hard @@ -3605,105 +3561,98 @@ __metadata: version: 1.0.1 resolution: "gopd@npm:1.0.1" dependencies: - get-intrinsic: ^1.1.3 - checksum: a5ccfb8806e0917a94e0b3de2af2ea4979c1da920bc381667c260e00e7cafdbe844e2cb9c5bcfef4e5412e8bf73bab837285bc35c7ba73aaaf0134d4583393a6 + get-intrinsic: "npm:^1.1.3" + checksum: 10c0/505c05487f7944c552cee72087bf1567debb470d4355b1335f2c262d218ebbff805cd3715448fe29b4b380bae6912561d0467233e4165830efd28da241418c63 languageName: node linkType: hard "graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": - version: 4.2.10 - resolution: "graceful-fs@npm:4.2.10" - checksum: 3f109d70ae123951905d85032ebeae3c2a5a7a997430df00ea30df0e3a6c60cf6689b109654d6fdacd28810a053348c4d14642da1d075049e6be1ba5216218da + version: 4.2.11 + resolution: "graceful-fs@npm:4.2.11" + checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 languageName: node linkType: hard -"grapheme-splitter@npm:^1.0.4": - version: 1.0.4 - resolution: "grapheme-splitter@npm:1.0.4" - checksum: 0c22ec54dee1b05cd480f78cf14f732cb5b108edc073572c4ec205df4cd63f30f8db8025afc5debc8835a8ddeacf648a1c7992fe3dcd6ad38f9a476d84906620 +"graphemer@npm:^1.4.0": + version: 1.4.0 + resolution: "graphemer@npm:1.4.0" + checksum: 10c0/e951259d8cd2e0d196c72ec711add7115d42eb9a8146c8eeda5b8d3ac91e5dd816b9cd68920726d9fd4490368e7ed86e9c423f40db87e2d8dfafa00fa17c3a31 languageName: node linkType: hard "has-bigints@npm:^1.0.1, has-bigints@npm:^1.0.2": version: 1.0.2 resolution: "has-bigints@npm:1.0.2" - checksum: 390e31e7be7e5c6fe68b81babb73dfc35d413604d7ee5f56da101417027a4b4ce6a27e46eff97ad040c835b5d228676eae99a9b5c3bc0e23c8e81a49241ff45b + checksum: 10c0/724eb1485bfa3cdff6f18d95130aa190561f00b3fcf9f19dc640baf8176b5917c143b81ec2123f8cddb6c05164a198c94b13e1377c497705ccc8e1a80306e83b languageName: node linkType: hard "has-flag@npm:^3.0.0": version: 3.0.0 resolution: "has-flag@npm:3.0.0" - checksum: 4a15638b454bf086c8148979aae044dd6e39d63904cd452d970374fa6a87623423da485dfb814e7be882e05c096a7ccf1ebd48e7e7501d0208d8384ff4dea73b + checksum: 10c0/1c6c83b14b8b1b3c25b0727b8ba3e3b647f99e9e6e13eb7322107261de07a4c1be56fc0d45678fc376e09772a3a1642ccdaf8fc69bdf123b6c086598397ce473 languageName: node linkType: hard "has-flag@npm:^4.0.0": version: 4.0.0 resolution: "has-flag@npm:4.0.0" - checksum: 261a1357037ead75e338156b1f9452c016a37dcd3283a972a30d9e4a87441ba372c8b81f818cd0fbcd9c0354b4ae7e18b9e1afa1971164aef6d18c2b6095a8ad + checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 languageName: node linkType: hard -"has-property-descriptors@npm:^1.0.0": - version: 1.0.0 - resolution: "has-property-descriptors@npm:1.0.0" +"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.1, has-property-descriptors@npm:^1.0.2": + version: 1.0.2 + resolution: "has-property-descriptors@npm:1.0.2" dependencies: - get-intrinsic: ^1.1.1 - checksum: a6d3f0a266d0294d972e354782e872e2fe1b6495b321e6ef678c9b7a06a40408a6891817350c62e752adced73a94ac903c54734fee05bf65b1905ee1368194bb + es-define-property: "npm:^1.0.0" + checksum: 10c0/253c1f59e80bb476cf0dde8ff5284505d90c3bdb762983c3514d36414290475fe3fd6f574929d84de2a8eec00d35cf07cb6776205ff32efd7c50719125f00236 languageName: node linkType: hard -"has-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "has-proto@npm:1.0.1" - checksum: febc5b5b531de8022806ad7407935e2135f1cc9e64636c3916c6842bd7995994ca3b29871ecd7954bd35f9e2986c17b3b227880484d22259e2f8e6ce63fd383e +"has-proto@npm:^1.0.1, has-proto@npm:^1.0.3": + version: 1.0.3 + resolution: "has-proto@npm:1.0.3" + checksum: 10c0/35a6989f81e9f8022c2f4027f8b48a552de714938765d019dbea6bb547bd49ce5010a3c7c32ec6ddac6e48fc546166a3583b128f5a7add8b058a6d8b4afec205 languageName: node linkType: hard "has-symbols@npm:^1.0.2, has-symbols@npm:^1.0.3": version: 1.0.3 resolution: "has-symbols@npm:1.0.3" - checksum: a054c40c631c0d5741a8285010a0777ea0c068f99ed43e5d6eb12972da223f8af553a455132fdb0801bdcfa0e0f443c0c03a68d8555aa529b3144b446c3f2410 + checksum: 10c0/e6922b4345a3f37069cdfe8600febbca791c94988c01af3394d86ca3360b4b93928bbf395859158f88099cb10b19d98e3bbab7c9ff2c1bd09cf665ee90afa2c3 languageName: node linkType: hard -"has-tostringtag@npm:^1.0.0": - version: 1.0.0 - resolution: "has-tostringtag@npm:1.0.0" +"has-tostringtag@npm:^1.0.0, has-tostringtag@npm:^1.0.1, has-tostringtag@npm:^1.0.2": + version: 1.0.2 + resolution: "has-tostringtag@npm:1.0.2" dependencies: - has-symbols: ^1.0.2 - checksum: cc12eb28cb6ae22369ebaad3a8ab0799ed61270991be88f208d508076a1e99abe4198c965935ce85ea90b60c94ddda73693b0920b58e7ead048b4a391b502c1c + has-symbols: "npm:^1.0.3" + checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c languageName: node linkType: hard -"has-unicode@npm:^2.0.1": +"hasown@npm:^2.0.0, hasown@npm:^2.0.1": version: 2.0.1 - resolution: "has-unicode@npm:2.0.1" - checksum: 1eab07a7436512db0be40a710b29b5dc21fa04880b7f63c9980b706683127e3c1b57cb80ea96d47991bdae2dfe479604f6a1ba410106ee1046a41d1bd0814400 - languageName: node - linkType: hard - -"has@npm:^1.0.3": - version: 1.0.3 - resolution: "has@npm:1.0.3" + resolution: "hasown@npm:2.0.1" dependencies: - function-bind: ^1.1.1 - checksum: b9ad53d53be4af90ce5d1c38331e712522417d017d5ef1ebd0507e07c2fbad8686fffb8e12ddecd4c39ca9b9b47431afbb975b8abf7f3c3b82c98e9aad052792 + function-bind: "npm:^1.1.2" + checksum: 10c0/9e27e70e8e4204f4124c8f99950d1ba2b1f5174864fd39ff26da190f9ea6488c1b3927dcc64981c26d1f637a971783c9489d62c829d393ea509e6f1ba20370bb languageName: node linkType: hard "home-assistant-js-websocket@npm:^6.0.1": version: 6.1.1 resolution: "home-assistant-js-websocket@npm:6.1.1" - checksum: b46dd44ac1b393ecfdda152743fe44dcd6534463d1df631c448a71e71166c04d4fea2a0827dbb2e55c85fcd8d9ccdea4f168713bf18e832c7f688b9b2fdc8d72 + checksum: 10c0/fe00b8d7a681d39b31ac5078b79fa1ef67cccd37df2c7ec31b1ad9ded33c899570b453c9439db71c3bda24df6d0c1e3d9d040583b0717f4630476ab528120a9f languageName: node linkType: hard "home-assistant-js-websocket@npm:^8.0.0": - version: 8.0.1 - resolution: "home-assistant-js-websocket@npm:8.0.1" - checksum: e8b2204d58b2b1fbdf26ca1ad196fcc02ec5d18e6d867179f27246a9f2d4fe5f91de9dbbe7b82806c19dcb0af0e2b77fb48d393668b5c8c0844c201a16832023 + version: 8.2.0 + resolution: "home-assistant-js-websocket@npm:8.2.0" + checksum: 10c0/9a1f1f5cb39ce0629653347d5ae31a14f14742596c15fea7bd72f4c0ee4ce4613b1172b4f4df52f293b4e5aeb3b5ead75f395d5fe5c4785193e7d00f8355ef5a languageName: node linkType: hard @@ -3711,22 +3660,22 @@ __metadata: version: 3.0.0 resolution: "html-encoding-sniffer@npm:3.0.0" dependencies: - whatwg-encoding: ^2.0.0 - checksum: 8d806aa00487e279e5ccb573366a951a9f68f65c90298eac9c3a2b440a7ffe46615aff2995a2f61c6746c639234e6179a97e18ca5ccbbf93d3725ef2099a4502 + whatwg-encoding: "npm:^2.0.0" + checksum: 10c0/b17b3b0fb5d061d8eb15121c3b0b536376c3e295ecaf09ba48dd69c6b6c957839db124fe1e2b3f11329753a4ee01aa7dedf63b7677999e86da17fbbdd82c5386 languageName: node linkType: hard "html-escaper@npm:^2.0.0": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" - checksum: d2df2da3ad40ca9ee3a39c5cc6475ef67c8f83c234475f24d8e9ce0dc80a2c82df8e1d6fa78ddd1e9022a586ea1bd247a615e80a5cd9273d90111ddda7d9e974 + checksum: 10c0/208e8a12de1a6569edbb14544f4567e6ce8ecc30b9394fcaa4e7bb1e60c12a7c9a1ed27e31290817157e8626f3a4f29e76c8747030822eb84a6abb15c255f0a0 languageName: node linkType: hard -"http-cache-semantics@npm:^4.1.0": +"http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" - checksum: 83ac0bc60b17a3a36f9953e7be55e5c8f41acc61b22583060e8dedc9dd5e3607c823a88d0926f9150e571f90946835c7fe150732801010845c72cd8bbff1a236 + checksum: 10c0/ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc languageName: node linkType: hard @@ -3734,29 +3683,47 @@ __metadata: version: 5.0.0 resolution: "http-proxy-agent@npm:5.0.0" dependencies: - "@tootallnate/once": 2 - agent-base: 6 - debug: 4 - checksum: e2ee1ff1656a131953839b2a19cd1f3a52d97c25ba87bd2559af6ae87114abf60971e498021f9b73f9fd78aea8876d1fb0d4656aac8a03c6caa9fc175f22b786 + "@tootallnate/once": "npm:2" + agent-base: "npm:6" + debug: "npm:4" + checksum: 10c0/32a05e413430b2c1e542e5c74b38a9f14865301dd69dff2e53ddb684989440e3d2ce0c4b64d25eb63cf6283e6265ff979a61cf93e3ca3d23047ddfdc8df34a32 languageName: node linkType: hard -"https-proxy-agent@npm:^5.0.0, https-proxy-agent@npm:^5.0.1": +"http-proxy-agent@npm:^7.0.0": + version: 7.0.2 + resolution: "http-proxy-agent@npm:7.0.2" + dependencies: + agent-base: "npm:^7.1.0" + debug: "npm:^4.3.4" + checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 + languageName: node + linkType: hard + +"https-proxy-agent@npm:^5.0.1": version: 5.0.1 resolution: "https-proxy-agent@npm:5.0.1" dependencies: - agent-base: 6 - debug: 4 - checksum: 571fccdf38184f05943e12d37d6ce38197becdd69e58d03f43637f7fa1269cf303a7d228aa27e5b27bbd3af8f09fd938e1c91dcfefff2df7ba77c20ed8dfc765 + agent-base: "npm:6" + debug: "npm:4" + checksum: 10c0/6dd639f03434003577c62b27cafdb864784ef19b2de430d8ae2a1d45e31c4fd60719e5637b44db1a88a046934307da7089e03d6089ec3ddacc1189d8de8897d1 languageName: node linkType: hard -"humanize-ms@npm:^1.2.1": - version: 1.2.1 - resolution: "humanize-ms@npm:1.2.1" +"https-proxy-agent@npm:^7.0.1": + version: 7.0.4 + resolution: "https-proxy-agent@npm:7.0.4" dependencies: - ms: ^2.0.0 - checksum: 9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16 + agent-base: "npm:^7.0.2" + debug: "npm:4" + checksum: 10c0/bc4f7c38da32a5fc622450b6cb49a24ff596f9bd48dcedb52d2da3fa1c1a80e100fb506bd59b326c012f21c863c69b275c23de1a01d0b84db396822fdf25e52b + languageName: node + linkType: hard + +"human-signals@npm:^5.0.0": + version: 5.0.0 + resolution: "human-signals@npm:5.0.0" + checksum: 10c0/5a9359073fe17a8b58e5a085e9a39a950366d9f00217c4ff5878bd312e09d80f460536ea6a3f260b5943a01fe55c158d1cea3fc7bee3d0520aeef04f6d915c82 languageName: node linkType: hard @@ -3764,8 +3731,8 @@ __metadata: version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" dependencies: - safer-buffer: ">= 2.1.2 < 3.0.0" - checksum: 3f60d47a5c8fc3313317edfd29a00a692cc87a19cac0159e2ce711d0ebc9019064108323b5e493625e25594f11c6236647d8e256fbe7a58f4a3b33b89e6d30bf + safer-buffer: "npm:>= 2.1.2 < 3.0.0" + checksum: 10c0/98102bc66b33fcf5ac044099d1257ba0b7ad5e3ccd3221f34dd508ab4070edff183276221684e1e0555b145fce0850c9f7d2b60a9fcac50fbb4ea0d6e845a3b1 languageName: node linkType: hard @@ -3774,52 +3741,45 @@ __metadata: resolution: "icss-utils@npm:5.1.0" peerDependencies: postcss: ^8.1.0 - checksum: 5c324d283552b1269cfc13a503aaaa172a280f914e5b81544f3803bc6f06a3b585fb79f66f7c771a2c052db7982c18bf92d001e3b47282e3abbbb4c4cc488d68 + checksum: 10c0/39c92936fabd23169c8611d2b5cc39e39d10b19b0d223352f20a7579f75b39d5f786114a6b8fc62bee8c5fed59ba9e0d38f7219a4db383e324fb3061664b043d languageName: node linkType: hard "ignore@npm:^5.2.0": - version: 5.2.4 - resolution: "ignore@npm:5.2.4" - checksum: 3d4c309c6006e2621659311783eaea7ebcd41fe4ca1d78c91c473157ad6666a57a2df790fe0d07a12300d9aac2888204d7be8d59f9aaf665b1c7fcdb432517ef + version: 5.3.1 + resolution: "ignore@npm:5.3.1" + checksum: 10c0/703f7f45ffb2a27fb2c5a8db0c32e7dee66b33a225d28e8db4e1be6474795f606686a6e3bcc50e1aa12f2042db4c9d4a7d60af3250511de74620fbed052ea4cd languageName: node linkType: hard "immutable@npm:^4.0.0": - version: 4.2.4 - resolution: "immutable@npm:4.2.4" - checksum: 3be84eded37b05e65cad57bfba630bc1bf170c498b7472144bc02d2650cc9baef79daf03574a9c2e41d195ebb55a1c12c9b312f41ee324b653927b24ad8bcaa7 + version: 4.3.5 + resolution: "immutable@npm:4.3.5" + checksum: 10c0/63d2d7908241a955d18c7822fd2215b6e89ff5a1a33cc72cd475b013cbbdef7a705aa5170a51ce9f84a57f62fdddfaa34e7b5a14b33d8a43c65cc6a881d6e894 languageName: node linkType: hard -"import-fresh@npm:^3.0.0, import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.2.1": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: - parent-module: ^1.0.0 - resolve-from: ^4.0.0 - checksum: 2cacfad06e652b1edc50be650f7ec3be08c5e5a6f6d12d035c440a42a8cc028e60a5b99ca08a77ab4d6b1346da7d971915828f33cdab730d3d42f08242d09baa + parent-module: "npm:^1.0.0" + resolve-from: "npm:^4.0.0" + checksum: 10c0/7f882953aa6b740d1f0e384d0547158bc86efbf2eea0f1483b8900a6f65c5a5123c2cf09b0d542cc419d0b98a759ecaeb394237e97ea427f2da221dc3cd80cc3 languageName: node linkType: hard "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" - checksum: 7cae75c8cd9a50f57dadd77482359f659eaebac0319dd9368bcd1714f55e65badd6929ca58569da2b6494ef13fdd5598cd700b1eba23f8b79c5f19d195a3ecf7 + checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 languageName: node linkType: hard "indent-string@npm:^4.0.0": version: 4.0.0 resolution: "indent-string@npm:4.0.0" - checksum: 824cfb9929d031dabf059bebfe08cf3137365e112019086ed3dcff6a0a7b698cb80cf67ccccde0e25b9e2d7527aa6cc1fed1ac490c752162496caba3e6699612 - languageName: node - linkType: hard - -"infer-owner@npm:^1.0.4": - version: 1.0.4 - resolution: "infer-owner@npm:1.0.4" - checksum: 181e732764e4a0611576466b4b87dac338972b839920b2a8cde43642e4ed6bd54dc1fb0b40874728f2a2df9a1b097b8ff83b56d5f8f8e3927f837fdcb47d8a89 + checksum: 10c0/1e1904ddb0cb3d6cce7cd09e27a90184908b7a5d5c21b92e232c93579d314f0b83c246ffb035493d0504b1e9147ba2c9b21df0030f48673fba0496ecd698161f languageName: node linkType: hard @@ -3827,27 +3787,27 @@ __metadata: version: 1.0.6 resolution: "inflight@npm:1.0.6" dependencies: - once: ^1.3.0 - wrappy: 1 - checksum: f4f76aa072ce19fae87ce1ef7d221e709afb59d445e05d47fba710e85470923a75de35bfae47da6de1b18afc3ce83d70facf44cfb0aff89f0a3f45c0a0244dfd + once: "npm:^1.3.0" + wrappy: "npm:1" + checksum: 10c0/7faca22584600a9dc5b9fca2cd5feb7135ac8c935449837b315676b4c90aa4f391ec4f42240178244b5a34e8bede1948627fda392ca3191522fc46b34e985ab2 languageName: node linkType: hard -"inherits@npm:2, inherits@npm:^2.0.3": +"inherits@npm:2": version: 2.0.4 resolution: "inherits@npm:2.0.4" - checksum: 4a48a733847879d6cf6691860a6b1e3f0f4754176e4d71494c41f3475553768b10f84b5ce1d40fbd0e34e6bfbb864ee35858ad4dd2cf31e02fc4a154b724d7f1 + checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 languageName: node linkType: hard -"internal-slot@npm:^1.0.4": - version: 1.0.4 - resolution: "internal-slot@npm:1.0.4" +"internal-slot@npm:^1.0.7": + version: 1.0.7 + resolution: "internal-slot@npm:1.0.7" dependencies: - get-intrinsic: ^1.1.3 - has: ^1.0.3 - side-channel: ^1.0.4 - checksum: 8974588d06bab4f675573a3b52975370facf6486df51bc0567a982c7024fa29495f10b76c0d4dc742dd951d1b72024fdc1e31bb0bedf1678dc7aacacaf5a4f73 + es-errors: "npm:^1.3.0" + hasown: "npm:^2.0.0" + side-channel: "npm:^1.0.4" + checksum: 10c0/f8b294a4e6ea3855fc59551bbf35f2b832cf01fd5e6e2a97f5c201a071cc09b49048f856e484b67a6c721da5e55736c5b6ddafaf19e2dbeb4a3ff1821680de6c languageName: node linkType: hard @@ -3855,36 +3815,38 @@ __metadata: version: 9.13.0 resolution: "intl-messageformat@npm:9.13.0" dependencies: - "@formatjs/ecma402-abstract": 1.11.4 - "@formatjs/fast-memoize": 1.2.1 - "@formatjs/icu-messageformat-parser": 2.1.0 - tslib: ^2.1.0 - checksum: effb840ae6e213adceab9951dbb2d18d1a354c82e35dbd213011daf23bcc79e2a18b6ef79157ae3b69c1e6d898fe66b54dd184ac180ee0646e26a70276e60038 + "@formatjs/ecma402-abstract": "npm:1.11.4" + "@formatjs/fast-memoize": "npm:1.2.1" + "@formatjs/icu-messageformat-parser": "npm:2.1.0" + tslib: "npm:^2.1.0" + checksum: 10c0/d50b220ae943278a4403cb004e3776f288b5c2a2673b0dc11347d9b9d4e0361c3c33288cea54189a69b42c64a35171608c9c25ed55d6a9a6ec7f7af5e7782541 languageName: node linkType: hard -"ip@npm:^2.0.0": - version: 2.0.0 - resolution: "ip@npm:2.0.0" - checksum: cfcfac6b873b701996d71ec82a7dd27ba92450afdb421e356f44044ed688df04567344c36cbacea7d01b1c39a4c732dc012570ebe9bebfb06f27314bca625349 - languageName: node - linkType: hard - -"is-array-buffer@npm:^3.0.1": - version: 3.0.1 - resolution: "is-array-buffer@npm:3.0.1" +"ip-address@npm:^9.0.5": + version: 9.0.5 + resolution: "ip-address@npm:9.0.5" dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.3 - is-typed-array: ^1.1.10 - checksum: f26ab87448e698285daf707e52a533920449f7abf63714140ffab9d5571aa5a71ac2fa2677e8b793ad0d5d3e40078d4d2c8a0ab39c957e3cfc6513bb6c9dfdc9 + jsbn: "npm:1.1.0" + sprintf-js: "npm:^1.1.3" + checksum: 10c0/331cd07fafcb3b24100613e4b53e1a2b4feab11e671e655d46dc09ee233da5011284d09ca40c4ecbdfe1d0004f462958675c224a804259f2f78d2465a87824bc + languageName: node + linkType: hard + +"is-array-buffer@npm:^3.0.4": + version: 3.0.4 + resolution: "is-array-buffer@npm:3.0.4" + dependencies: + call-bind: "npm:^1.0.2" + get-intrinsic: "npm:^1.2.1" + checksum: 10c0/42a49d006cc6130bc5424eae113e948c146f31f9d24460fc0958f855d9d810e6fd2e4519bf19aab75179af9c298ea6092459d8cafdec523cd19e529b26eab860 languageName: node linkType: hard "is-arrayish@npm:^0.2.1": version: 0.2.1 resolution: "is-arrayish@npm:0.2.1" - checksum: eef4417e3c10e60e2c810b6084942b3ead455af16c4509959a27e490e7aee87cfb3f38e01bbde92220b528a0ee1a18d52b787e1458ee86174d8c7f0e58cd488f + checksum: 10c0/e7fb686a739068bb70f860b39b67afc62acc62e36bb61c5f965768abce1873b379c563e61dd2adad96ebb7edf6651111b385e490cf508378959b0ed4cac4e729 languageName: node linkType: hard @@ -3892,8 +3854,8 @@ __metadata: version: 1.0.4 resolution: "is-bigint@npm:1.0.4" dependencies: - has-bigints: ^1.0.1 - checksum: c56edfe09b1154f8668e53ebe8252b6f185ee852a50f9b41e8d921cb2bed425652049fbe438723f6cb48a63ca1aa051e948e7e401e093477c99c84eba244f666 + has-bigints: "npm:^1.0.1" + checksum: 10c0/eb9c88e418a0d195ca545aff2b715c9903d9b0a5033bc5922fec600eb0c3d7b1ee7f882dbf2e0d5a6e694e42391be3683e4368737bd3c4a77f8ac293e7773696 languageName: node linkType: hard @@ -3901,8 +3863,8 @@ __metadata: version: 2.1.0 resolution: "is-binary-path@npm:2.1.0" dependencies: - binary-extensions: ^2.0.0 - checksum: 84192eb88cff70d320426f35ecd63c3d6d495da9d805b19bc65b518984b7c0760280e57dbf119b7e9be6b161784a5a673ab2c6abe83abb5198a432232ad5b35c + binary-extensions: "npm:^2.0.0" + checksum: 10c0/a16eaee59ae2b315ba36fad5c5dcaf8e49c3e27318f8ab8fa3cdb8772bf559c8d1ba750a589c2ccb096113bb64497084361a25960899cb6172a6925ab6123d38 languageName: node linkType: hard @@ -3910,9 +3872,9 @@ __metadata: version: 1.1.2 resolution: "is-boolean-object@npm:1.1.2" dependencies: - call-bind: ^1.0.2 - has-tostringtag: ^1.0.0 - checksum: c03b23dbaacadc18940defb12c1c0e3aaece7553ef58b162a0f6bba0c2a7e1551b59f365b91e00d2dbac0522392d576ef322628cb1d036a0fe51eb466db67222 + call-bind: "npm:^1.0.2" + has-tostringtag: "npm:^1.0.0" + checksum: 10c0/6090587f8a8a8534c0f816da868bc94f32810f08807aa72fa7e79f7e11c466d281486ffe7a788178809c2aa71fe3e700b167fe80dd96dad68026bfff8ebf39f7 languageName: node linkType: hard @@ -3920,24 +3882,24 @@ __metadata: version: 3.2.1 resolution: "is-builtin-module@npm:3.2.1" dependencies: - builtin-modules: ^3.3.0 - checksum: e8f0ffc19a98240bda9c7ada84d846486365af88d14616e737d280d378695c8c448a621dcafc8332dbf0fcd0a17b0763b845400709963fa9151ddffece90ae88 + builtin-modules: "npm:^3.3.0" + checksum: 10c0/5a66937a03f3b18803381518f0ef679752ac18cdb7dd53b5e23ee8df8d440558737bd8dcc04d2aae555909d2ecb4a81b5c0d334d119402584b61e6a003e31af1 languageName: node linkType: hard "is-callable@npm:^1.1.3, is-callable@npm:^1.1.4, is-callable@npm:^1.2.7": version: 1.2.7 resolution: "is-callable@npm:1.2.7" - checksum: 61fd57d03b0d984e2ed3720fb1c7a897827ea174bd44402878e059542ea8c4aeedee0ea0985998aa5cc2736b2fa6e271c08587addb5b3959ac52cf665173d1ac + checksum: 10c0/ceebaeb9d92e8adee604076971dd6000d38d6afc40bb843ea8e45c5579b57671c3f3b50d7f04869618242c6cee08d1b67806a8cb8edaaaf7c0748b3720d6066f languageName: node linkType: hard -"is-core-module@npm:^2.11.0, is-core-module@npm:^2.9.0": - version: 2.11.0 - resolution: "is-core-module@npm:2.11.0" +"is-core-module@npm:^2.13.0, is-core-module@npm:^2.13.1": + version: 2.13.1 + resolution: "is-core-module@npm:2.13.1" dependencies: - has: ^1.0.3 - checksum: f96fd490c6b48eb4f6d10ba815c6ef13f410b0ba6f7eb8577af51697de523e5f2cd9de1c441b51d27251bf0e4aebc936545e33a5d26d5d51f28d25698d4a8bab + hasown: "npm:^2.0.0" + checksum: 10c0/2cba9903aaa52718f11c4896dabc189bab980870aae86a62dc0d5cedb546896770ee946fb14c84b7adf0735f5eaea4277243f1b95f5cefa90054f92fbcac2518 languageName: node linkType: hard @@ -3945,8 +3907,8 @@ __metadata: version: 1.0.5 resolution: "is-date-object@npm:1.0.5" dependencies: - has-tostringtag: ^1.0.0 - checksum: baa9077cdf15eb7b58c79398604ca57379b2fc4cf9aa7a9b9e295278648f628c9b201400c01c5e0f7afae56507d741185730307cbe7cad3b9f90a77e5ee342fc + has-tostringtag: "npm:^1.0.0" + checksum: 10c0/eed21e5dcc619c48ccef804dfc83a739dbb2abee6ca202838ee1bd5f760fe8d8a93444f0d49012ad19bb7c006186e2884a1b92f6e1c056da7fd23d0a9ad5992e languageName: node linkType: hard @@ -3955,21 +3917,21 @@ __metadata: resolution: "is-docker@npm:2.2.1" bin: is-docker: cli.js - checksum: 3fef7ddbf0be25958e8991ad941901bf5922ab2753c46980b60b05c1bf9c9c2402d35e6dc32e4380b980ef5e1970a5d9d5e5aa2e02d77727c3b6b5e918474c56 + checksum: 10c0/e828365958d155f90c409cdbe958f64051d99e8aedc2c8c4cd7c89dcf35329daed42f7b99346f7828df013e27deb8f721cf9408ba878c76eb9e8290235fbcdcc languageName: node linkType: hard "is-extglob@npm:^2.1.1": version: 2.1.1 resolution: "is-extglob@npm:2.1.1" - checksum: df033653d06d0eb567461e58a7a8c9f940bd8c22274b94bf7671ab36df5719791aae15eef6d83bbb5e23283967f2f984b8914559d4449efda578c775c4be6f85 + checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 languageName: node linkType: hard "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" - checksum: 44a30c29457c7fb8f00297bce733f0a64cd22eca270f83e58c105e0d015e45c019491a4ab2faef91ab51d4738c670daff901c799f6a700e27f7314029e99e348 + checksum: 10c0/bb11d825e049f38e04c06373a8d72782eee0205bda9d908cc550ccb3c59b99d750ff9537982e01733c1c94a58e35400661f57042158ff5e8f3e90cf936daf0fc languageName: node linkType: hard @@ -3977,29 +3939,29 @@ __metadata: version: 4.0.3 resolution: "is-glob@npm:4.0.3" dependencies: - is-extglob: ^2.1.1 - checksum: d381c1319fcb69d341cc6e6c7cd588e17cd94722d9a32dbd60660b993c4fb7d0f19438674e68dfec686d09b7c73139c9166b47597f846af387450224a8101ab4 + is-extglob: "npm:^2.1.1" + checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a languageName: node linkType: hard "is-lambda@npm:^1.0.1": version: 1.0.1 resolution: "is-lambda@npm:1.0.1" - checksum: 93a32f01940220532e5948538699ad610d5924ac86093fcee83022252b363eb0cc99ba53ab084a04e4fb62bf7b5731f55496257a4c38adf87af9c4d352c71c35 + checksum: 10c0/85fee098ae62ba6f1e24cf22678805473c7afd0fb3978a3aa260e354cb7bcb3a5806cf0a98403188465efedec41ab4348e8e4e79305d409601323855b3839d4d languageName: node linkType: hard "is-module@npm:^1.0.0": version: 1.0.0 resolution: "is-module@npm:1.0.0" - checksum: 8cd5390730c7976fb4e8546dd0b38865ee6f7bacfa08dfbb2cc07219606755f0b01709d9361e01f13009bbbd8099fa2927a8ed665118a6105d66e40f1b838c3f + checksum: 10c0/795a3914bcae7c26a1c23a1e5574c42eac13429625045737bf3e324ce865c0601d61aee7a5afbca1bee8cb300c7d9647e7dc98860c9bdbc3b7fdc51d8ac0bffc languageName: node linkType: hard -"is-negative-zero@npm:^2.0.2": - version: 2.0.2 - resolution: "is-negative-zero@npm:2.0.2" - checksum: f3232194c47a549da60c3d509c9a09be442507616b69454716692e37ae9f37c4dea264fb208ad0c9f3efd15a796a46b79df07c7e53c6227c32170608b809149a +"is-negative-zero@npm:^2.0.3": + version: 2.0.3 + resolution: "is-negative-zero@npm:2.0.3" + checksum: 10c0/bcdcf6b8b9714063ffcfa9929c575ac69bfdabb8f4574ff557dfc086df2836cf07e3906f5bbc4f2a5c12f8f3ba56af640c843cdfc74da8caed86c7c7d66fd08e languageName: node linkType: hard @@ -4007,29 +3969,29 @@ __metadata: version: 1.0.7 resolution: "is-number-object@npm:1.0.7" dependencies: - has-tostringtag: ^1.0.0 - checksum: d1e8d01bb0a7134c74649c4e62da0c6118a0bfc6771ea3c560914d52a627873e6920dd0fd0ebc0e12ad2ff4687eac4c308f7e80320b973b2c8a2c8f97a7524f7 + has-tostringtag: "npm:^1.0.0" + checksum: 10c0/aad266da1e530f1804a2b7bd2e874b4869f71c98590b3964f9d06cc9869b18f8d1f4778f838ecd2a11011bce20aeecb53cb269ba916209b79c24580416b74b1b languageName: node linkType: hard "is-number@npm:^7.0.0": version: 7.0.0 resolution: "is-number@npm:7.0.0" - checksum: 456ac6f8e0f3111ed34668a624e45315201dff921e5ac181f8ec24923b99e9f32ca1a194912dc79d539c97d33dba17dc635202ff0b2cf98326f608323276d27a + checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 languageName: node linkType: hard "is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" - checksum: abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 + checksum: 10c0/cf7d4ac35fb96bab6a1d2c3598fe5ebb29aafb52c0aaa482b5a3ed9d8ba3edc11631e3ec2637660c44b3ce0e61a08d54946e8af30dec0b60a7c27296c68ffd05 languageName: node linkType: hard "is-potential-custom-element-name@npm:^1.0.1": version: 1.0.1 resolution: "is-potential-custom-element-name@npm:1.0.1" - checksum: ced7bbbb6433a5b684af581872afe0e1767e2d1146b2207ca0068a648fb5cab9d898495d1ac0583524faaf24ca98176a7d9876363097c2d14fee6dd324f3a1ab + checksum: 10c0/b73e2f22bc863b0939941d369486d308b43d7aef1f9439705e3582bfccaa4516406865e32c968a35f97a99396dac84e2624e67b0a16b0a15086a785e16ce7db9 languageName: node linkType: hard @@ -4037,8 +3999,8 @@ __metadata: version: 1.2.1 resolution: "is-reference@npm:1.2.1" dependencies: - "@types/estree": "*" - checksum: e7b48149f8abda2c10849ea51965904d6a714193d68942ad74e30522231045acf06cbfae5a4be2702fede5d232e61bf50b3183acdc056e6e3afe07fcf4f4b2bc + "@types/estree": "npm:*" + checksum: 10c0/7dc819fc8de7790264a0a5d531164f9f5b9ef5aa1cd05f35322d14db39c8a2ec78fd5d4bf57f9789f3ddd2b3abeea7728432b759636157a42db12a9e8c3b549b languageName: node linkType: hard @@ -4046,18 +4008,25 @@ __metadata: version: 1.1.4 resolution: "is-regex@npm:1.1.4" dependencies: - call-bind: ^1.0.2 - has-tostringtag: ^1.0.0 - checksum: 362399b33535bc8f386d96c45c9feb04cf7f8b41c182f54174c1a45c9abbbe5e31290bbad09a458583ff6bf3b2048672cdb1881b13289569a7c548370856a652 + call-bind: "npm:^1.0.2" + has-tostringtag: "npm:^1.0.0" + checksum: 10c0/bb72aae604a69eafd4a82a93002058c416ace8cde95873589a97fc5dac96a6c6c78a9977d487b7b95426a8f5073969124dd228f043f9f604f041f32fcc465fc1 languageName: node linkType: hard -"is-shared-array-buffer@npm:^1.0.2": - version: 1.0.2 - resolution: "is-shared-array-buffer@npm:1.0.2" +"is-shared-array-buffer@npm:^1.0.2, is-shared-array-buffer@npm:^1.0.3": + version: 1.0.3 + resolution: "is-shared-array-buffer@npm:1.0.3" dependencies: - call-bind: ^1.0.2 - checksum: 9508929cf14fdc1afc9d61d723c6e8d34f5e117f0bffda4d97e7a5d88c3a8681f633a74f8e3ad1fe92d5113f9b921dc5ca44356492079612f9a247efbce7032a + call-bind: "npm:^1.0.7" + checksum: 10c0/adc11ab0acbc934a7b9e5e9d6c588d4ec6682f6fea8cda5180721704fa32927582ede5b123349e32517fdadd07958973d24716c80e7ab198970c47acc09e59c7 + languageName: node + linkType: hard + +"is-stream@npm:^3.0.0": + version: 3.0.0 + resolution: "is-stream@npm:3.0.0" + checksum: 10c0/eb2f7127af02ee9aa2a0237b730e47ac2de0d4e76a4a905a50a11557f2339df5765eaea4ceb8029f1efa978586abe776908720bfcb1900c20c6ec5145f6f29d8 languageName: node linkType: hard @@ -4065,8 +4034,8 @@ __metadata: version: 1.0.7 resolution: "is-string@npm:1.0.7" dependencies: - has-tostringtag: ^1.0.0 - checksum: 323b3d04622f78d45077cf89aab783b2f49d24dc641aa89b5ad1a72114cfeff2585efc8c12ef42466dff32bde93d839ad321b26884cf75e5a7892a938b089989 + has-tostringtag: "npm:^1.0.0" + checksum: 10c0/905f805cbc6eedfa678aaa103ab7f626aac9ebbdc8737abb5243acaa61d9820f8edc5819106b8fcd1839e33db21de9f0116ae20de380c8382d16dc2a601921f6 languageName: node linkType: hard @@ -4074,21 +4043,17 @@ __metadata: version: 1.0.4 resolution: "is-symbol@npm:1.0.4" dependencies: - has-symbols: ^1.0.2 - checksum: 92805812ef590738d9de49d677cd17dfd486794773fb6fa0032d16452af46e9b91bb43ffe82c983570f015b37136f4b53b28b8523bfb10b0ece7a66c31a54510 + has-symbols: "npm:^1.0.2" + checksum: 10c0/9381dd015f7c8906154dbcbf93fad769de16b4b961edc94f88d26eb8c555935caa23af88bda0c93a18e65560f6d7cca0fd5a3f8a8e1df6f1abbb9bead4502ef7 languageName: node linkType: hard -"is-typed-array@npm:^1.1.10, is-typed-array@npm:^1.1.9": - version: 1.1.10 - resolution: "is-typed-array@npm:1.1.10" +"is-typed-array@npm:^1.1.13": + version: 1.1.13 + resolution: "is-typed-array@npm:1.1.13" dependencies: - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - for-each: ^0.3.3 - gopd: ^1.0.1 - has-tostringtag: ^1.0.0 - checksum: aac6ecb59d4c56a1cdeb69b1f129154ef462bbffe434cb8a8235ca89b42f258b7ae94073c41b3cb7bce37f6a1733ad4499f07882d5d5093a7ba84dfc4ebb8017 + which-typed-array: "npm:^1.1.14" + checksum: 10c0/fa5cb97d4a80e52c2cc8ed3778e39f175a1a2ae4ddf3adae3187d69586a1fd57cfa0b095db31f66aa90331e9e3da79184cea9c6abdcd1abc722dc3c3edd51cca languageName: node linkType: hard @@ -4096,8 +4061,8 @@ __metadata: version: 1.0.2 resolution: "is-weakref@npm:1.0.2" dependencies: - call-bind: ^1.0.2 - checksum: 95bd9a57cdcb58c63b1c401c60a474b0f45b94719c30f548c891860f051bc2231575c290a6b420c6bc6e7ed99459d424c652bd5bf9a1d5259505dc35b4bf83de + call-bind: "npm:^1.0.2" + checksum: 10c0/1545c5d172cb690c392f2136c23eec07d8d78a7f57d0e41f10078aa4f5daf5d7f57b6513a67514ab4f073275ad00c9822fc8935e00229d0a2089e1c02685d4b1 languageName: node linkType: hard @@ -4105,57 +4070,60 @@ __metadata: version: 2.2.0 resolution: "is-wsl@npm:2.2.0" dependencies: - is-docker: ^2.0.0 - checksum: 20849846ae414997d290b75e16868e5261e86ff5047f104027026fd61d8b5a9b0b3ade16239f35e1a067b3c7cc02f70183cb661010ed16f4b6c7c93dad1b19d8 + is-docker: "npm:^2.0.0" + checksum: 10c0/a6fa2d370d21be487c0165c7a440d567274fbba1a817f2f0bfa41cc5e3af25041d84267baa22df66696956038a43973e72fca117918c91431920bdef490fa25e + languageName: node + linkType: hard + +"isarray@npm:^2.0.5": + version: 2.0.5 + resolution: "isarray@npm:2.0.5" + checksum: 10c0/4199f14a7a13da2177c66c31080008b7124331956f47bca57dd0b6ea9f11687aa25e565a2c7a2b519bc86988d10398e3049a1f5df13c9f6b7664154690ae79fd languageName: node linkType: hard "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" - checksum: 26bf6c5480dda5161c820c5b5c751ae1e766c587b1f951ea3fcfc973bafb7831ae5b54a31a69bd670220e42e99ec154475025a468eae58ea262f813fdc8d1c62 + checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d languageName: node linkType: hard -"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0": - version: 3.2.0 - resolution: "istanbul-lib-coverage@npm:3.2.0" - checksum: a2a545033b9d56da04a8571ed05c8120bf10e9bce01cf8633a3a2b0d1d83dff4ac4fe78d6d5673c27fc29b7f21a41d75f83a36be09f82a61c367b56aa73c1ff9 +"isexe@npm:^3.1.1": + version: 3.1.1 + resolution: "isexe@npm:3.1.1" + checksum: 10c0/9ec257654093443eb0a528a9c8cbba9c0ca7616ccb40abd6dde7202734d96bb86e4ac0d764f0f8cd965856aacbff2f4ce23e730dc19dfb41e3b0d865ca6fdcc7 languageName: node linkType: hard -"istanbul-lib-instrument@npm:^6.0.0": - version: 6.0.0 - resolution: "istanbul-lib-instrument@npm:6.0.0" +"istanbul-lib-coverage@npm:^3.0.0, istanbul-lib-coverage@npm:^3.2.0, istanbul-lib-coverage@npm:^3.2.2": + version: 3.2.2 + resolution: "istanbul-lib-coverage@npm:3.2.2" + checksum: 10c0/6c7ff2106769e5f592ded1fb418f9f73b4411fd5a084387a5410538332b6567cd1763ff6b6cadca9b9eb2c443cce2f7ea7d7f1b8d315f9ce58539793b1e0922b + languageName: node + linkType: hard + +"istanbul-lib-instrument@npm:^6.0.1": + version: 6.0.2 + resolution: "istanbul-lib-instrument@npm:6.0.2" dependencies: - "@babel/core": ^7.12.3 - "@babel/parser": ^7.14.7 - "@istanbuljs/schema": ^0.1.2 - istanbul-lib-coverage: ^3.2.0 - semver: ^7.5.4 - checksum: b9dc3723a769e65dbe1b912f935088ffc07cf393fa78a3ce79022c91aabb0ad01405ffd56083cdd822e514798e9daae3ea7bfe85633b094ecb335d28eb0a3f97 + "@babel/core": "npm:^7.23.9" + "@babel/parser": "npm:^7.23.9" + "@istanbuljs/schema": "npm:^0.1.3" + istanbul-lib-coverage: "npm:^3.2.0" + semver: "npm:^7.5.4" + checksum: 10c0/405c6ac037bf8c7ee7495980b0cd5544b2c53078c10534d0c9ceeb92a9ea7dcf8510f58ccfce31336458a8fa6ccef27b570bbb602abaa8c1650f5496a807477c languageName: node linkType: hard -"istanbul-lib-report@npm:^3.0.0": - version: 3.0.0 - resolution: "istanbul-lib-report@npm:3.0.0" - dependencies: - istanbul-lib-coverage: ^3.0.0 - make-dir: ^3.0.0 - supports-color: ^7.1.0 - checksum: 3f29eb3f53c59b987386e07fe772d24c7f58c6897f34c9d7a296f4000de7ae3de9eb95c3de3df91dc65b134c84dee35c54eee572a56243e8907c48064e34ff1b - languageName: node - linkType: hard - -"istanbul-lib-report@npm:^3.0.1": +"istanbul-lib-report@npm:^3.0.0, istanbul-lib-report@npm:^3.0.1": version: 3.0.1 resolution: "istanbul-lib-report@npm:3.0.1" dependencies: - istanbul-lib-coverage: ^3.0.0 - make-dir: ^4.0.0 - supports-color: ^7.1.0 - checksum: fd17a1b879e7faf9bb1dc8f80b2a16e9f5b7b8498fe6ed580a618c34df0bfe53d2abd35bf8a0a00e628fb7405462576427c7df20bbe4148d19c14b431c974b21 + istanbul-lib-coverage: "npm:^3.0.0" + make-dir: "npm:^4.0.0" + supports-color: "npm:^7.1.0" + checksum: 10c0/84323afb14392de8b6a5714bd7e9af845cfbd56cfe71ed276cda2f5f1201aea673c7111901227ee33e68e4364e288d73861eb2ed48f6679d1e69a43b6d9b3ba7 languageName: node linkType: hard @@ -4163,20 +4131,33 @@ __metadata: version: 4.0.1 resolution: "istanbul-lib-source-maps@npm:4.0.1" dependencies: - debug: ^4.1.1 - istanbul-lib-coverage: ^3.0.0 - source-map: ^0.6.1 - checksum: 21ad3df45db4b81852b662b8d4161f6446cd250c1ddc70ef96a585e2e85c26ed7cd9c2a396a71533cfb981d1a645508bc9618cae431e55d01a0628e7dec62ef2 + debug: "npm:^4.1.1" + istanbul-lib-coverage: "npm:^3.0.0" + source-map: "npm:^0.6.1" + checksum: 10c0/19e4cc405016f2c906dff271a76715b3e881fa9faeb3f09a86cb99b8512b3a5ed19cadfe0b54c17ca0e54c1142c9c6de9330d65506e35873994e06634eebeb66 languageName: node linkType: hard -"istanbul-reports@npm:^3.1.5": - version: 3.1.6 - resolution: "istanbul-reports@npm:3.1.6" +"istanbul-reports@npm:^3.1.6": + version: 3.1.7 + resolution: "istanbul-reports@npm:3.1.7" dependencies: - html-escaper: ^2.0.0 - istanbul-lib-report: ^3.0.0 - checksum: 44c4c0582f287f02341e9720997f9e82c071627e1e862895745d5f52ec72c9b9f38e1d12370015d2a71dcead794f34c7732aaef3fab80a24bc617a21c3d911d6 + html-escaper: "npm:^2.0.0" + istanbul-lib-report: "npm:^3.0.0" + checksum: 10c0/a379fadf9cf8dc5dfe25568115721d4a7eb82fbd50b005a6672aff9c6989b20cc9312d7865814e0859cd8df58cbf664482e1d3604be0afde1f7fc3ccc1394a51 + languageName: node + linkType: hard + +"jackspeak@npm:^2.3.5": + version: 2.3.6 + resolution: "jackspeak@npm:2.3.6" + dependencies: + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 10c0/f01d8f972d894cd7638bc338e9ef5ddb86f7b208ce177a36d718eac96ec86638a6efa17d0221b10073e64b45edc2ce15340db9380b1f5d5c5d000cbc517dc111 languageName: node linkType: hard @@ -4184,24 +4165,24 @@ __metadata: version: 26.6.2 resolution: "jest-worker@npm:26.6.2" dependencies: - "@types/node": "*" - merge-stream: ^2.0.0 - supports-color: ^7.0.0 - checksum: f9afa3b88e3f12027901e4964ba3ff048285b5783b5225cab28fac25b4058cea8ad54001e9a1577ee2bed125fac3ccf5c80dc507b120300cc1bbcb368796533e - languageName: node - linkType: hard - -"js-sdsl@npm:^4.1.4": - version: 4.3.0 - resolution: "js-sdsl@npm:4.3.0" - checksum: ce908257cf6909e213af580af3a691a736f5ee8b16315454768f917a682a4ea0c11bde1b241bbfaecedc0eb67b72101b2c2df2ffaed32aed5d539fca816f054e + "@types/node": "npm:*" + merge-stream: "npm:^2.0.0" + supports-color: "npm:^7.0.0" + checksum: 10c0/07e4dba650381604cda253ab6d5837fe0279c8d68c25884995b45bfe149a7a1e1b5a97f304b4518f257dac2a9ddc1808d57d650649c3ab855e9e60cf824d2970 languageName: node linkType: hard "js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" - checksum: 8a95213a5a77deb6cbe94d86340e8d9ace2b93bc367790b260101d2f36a2eaf4e4e22d9fa9cf459b38af3a32fb4190e638024cf82ec95ef708680e405ea7cc78 + checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed + languageName: node + linkType: hard + +"js-tokens@npm:^8.0.2": + version: 8.0.3 + resolution: "js-tokens@npm:8.0.3" + checksum: 10c0/b50ba7d926b087ad31949d8155c7bc84374e0785019b17bdddeb2c4f98f5dea04ba464651fe23a8be4f7d15f50d06ce8bb536087b24ce3ebfbaea4a1dc5869f0 languageName: node linkType: hard @@ -4209,49 +4190,56 @@ __metadata: version: 4.1.0 resolution: "js-yaml@npm:4.1.0" dependencies: - argparse: ^2.0.1 + argparse: "npm:^2.0.1" bin: js-yaml: bin/js-yaml.js - checksum: c7830dfd456c3ef2c6e355cc5a92e6700ceafa1d14bba54497b34a99f0376cecbb3e9ac14d3e5849b426d5a5140709a66237a8c991c675431271c4ce5504151a + checksum: 10c0/184a24b4eaacfce40ad9074c64fd42ac83cf74d8c8cd137718d456ced75051229e5061b8633c3366b8aada17945a7a356b337828c19da92b51ae62126575018f + languageName: node + linkType: hard + +"jsbn@npm:1.1.0": + version: 1.1.0 + resolution: "jsbn@npm:1.1.0" + checksum: 10c0/4f907fb78d7b712e11dea8c165fe0921f81a657d3443dde75359ed52eb2b5d33ce6773d97985a089f09a65edd80b11cb75c767b57ba47391fee4c969f7215c96 languageName: node linkType: hard "jsdom@npm:^21.1.1": - version: 21.1.1 - resolution: "jsdom@npm:21.1.1" + version: 21.1.2 + resolution: "jsdom@npm:21.1.2" dependencies: - abab: ^2.0.6 - acorn: ^8.8.2 - acorn-globals: ^7.0.0 - cssstyle: ^3.0.0 - data-urls: ^4.0.0 - decimal.js: ^10.4.3 - domexception: ^4.0.0 - escodegen: ^2.0.0 - form-data: ^4.0.0 - html-encoding-sniffer: ^3.0.0 - http-proxy-agent: ^5.0.0 - https-proxy-agent: ^5.0.1 - is-potential-custom-element-name: ^1.0.1 - nwsapi: ^2.2.2 - parse5: ^7.1.2 - rrweb-cssom: ^0.6.0 - saxes: ^6.0.0 - symbol-tree: ^3.2.4 - tough-cookie: ^4.1.2 - w3c-xmlserializer: ^4.0.0 - webidl-conversions: ^7.0.0 - whatwg-encoding: ^2.0.0 - whatwg-mimetype: ^3.0.0 - whatwg-url: ^12.0.1 - ws: ^8.13.0 - xml-name-validator: ^4.0.0 + abab: "npm:^2.0.6" + acorn: "npm:^8.8.2" + acorn-globals: "npm:^7.0.0" + cssstyle: "npm:^3.0.0" + data-urls: "npm:^4.0.0" + decimal.js: "npm:^10.4.3" + domexception: "npm:^4.0.0" + escodegen: "npm:^2.0.0" + form-data: "npm:^4.0.0" + html-encoding-sniffer: "npm:^3.0.0" + http-proxy-agent: "npm:^5.0.0" + https-proxy-agent: "npm:^5.0.1" + is-potential-custom-element-name: "npm:^1.0.1" + nwsapi: "npm:^2.2.4" + parse5: "npm:^7.1.2" + rrweb-cssom: "npm:^0.6.0" + saxes: "npm:^6.0.0" + symbol-tree: "npm:^3.2.4" + tough-cookie: "npm:^4.1.2" + w3c-xmlserializer: "npm:^4.0.0" + webidl-conversions: "npm:^7.0.0" + whatwg-encoding: "npm:^2.0.0" + whatwg-mimetype: "npm:^3.0.0" + whatwg-url: "npm:^12.0.1" + ws: "npm:^8.13.0" + xml-name-validator: "npm:^4.0.0" peerDependencies: canvas: ^2.5.0 peerDependenciesMeta: canvas: optional: true - checksum: ea33c3f3f084b48685e3838baa1112f0cbffc2949b0249f90ee19152b66dbafc6ae7dd8573ee66933697f881e3bc04c0efc2b56cd26f64fd3e6321a64164e2d1 + checksum: 10c0/905012680891fa0c92b8c18acfa35fc0b3e4b15f778ee3494aec1aca3274875160d2be35917d666b8eacd0b3121f483bd95fbe35e14790a004b805b1cf01818a languageName: node linkType: hard @@ -4260,55 +4248,62 @@ __metadata: resolution: "jsesc@npm:2.5.2" bin: jsesc: bin/jsesc - checksum: 4dc190771129e12023f729ce20e1e0bfceac84d73a85bc3119f7f938843fe25a4aeccb54b6494dce26fcf263d815f5f31acdefac7cc9329efb8422a4f4d9fa9d + checksum: 10c0/dbf59312e0ebf2b4405ef413ec2b25abb5f8f4d9bc5fb8d9f90381622ebca5f2af6a6aa9a8578f65903f9e33990a6dc798edd0ce5586894bf0e9e31803a1de88 + languageName: node + linkType: hard + +"json-buffer@npm:3.0.1": + version: 3.0.1 + resolution: "json-buffer@npm:3.0.1" + checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7 languageName: node linkType: hard "json-parse-even-better-errors@npm:^2.3.0": version: 2.3.1 resolution: "json-parse-even-better-errors@npm:2.3.1" - checksum: 798ed4cf3354a2d9ccd78e86d2169515a0097a5c133337807cdf7f1fc32e1391d207ccfc276518cc1d7d8d4db93288b8a50ba4293d212ad1336e52a8ec0a941f + checksum: 10c0/140932564c8f0b88455432e0f33c4cb4086b8868e37524e07e723f4eaedb9425bdc2bafd71bd1d9765bd15fd1e2d126972bc83990f55c467168c228c24d665f3 languageName: node linkType: hard "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" - checksum: 7486074d3ba247769fda17d5181b345c9fb7d12e0da98b22d1d71a5db9698d8b4bd900a3ec1a4ffdd60846fc2556274a5c894d0c48795f14cb03aeae7b55260b + checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce languageName: node linkType: hard "json-stable-stringify-without-jsonify@npm:^1.0.1": version: 1.0.1 resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" - checksum: cff44156ddce9c67c44386ad5cddf91925fe06b1d217f2da9c4910d01f358c6e3989c4d5a02683c7a5667f9727ff05831f7aa8ae66c8ff691c556f0884d49215 + checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5 languageName: node linkType: hard -"json5@npm:^1.0.1": +"json5@npm:^1.0.2": version: 1.0.2 resolution: "json5@npm:1.0.2" dependencies: - minimist: ^1.2.0 + minimist: "npm:^1.2.0" bin: json5: lib/cli.js - checksum: 866458a8c58a95a49bef3adba929c625e82532bcff1fe93f01d29cb02cac7c3fe1f4b79951b7792c2da9de0b32871a8401a6e3c5b36778ad852bf5b8a61165d7 + checksum: 10c0/9ee316bf21f000b00752e6c2a3b79ecf5324515a5c60ee88983a1910a45426b643a4f3461657586e8aeca87aaf96f0a519b0516d2ae527a6c3e7eed80f68717f languageName: node linkType: hard -"json5@npm:^2.1.3, json5@npm:^2.2.2, json5@npm:^2.2.3": +"json5@npm:^2.1.3, json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: json5: lib/cli.js - checksum: 2a7436a93393830bce797d4626275152e37e877b265e94ca69c99e3d20c2b9dab021279146a39cdb700e71b2dd32a4cebd1514cd57cee102b1af906ce5040349 + checksum: 10c0/5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c languageName: node linkType: hard "jsonc-parser@npm:^3.2.0": - version: 3.2.0 - resolution: "jsonc-parser@npm:3.2.0" - checksum: 946dd9a5f326b745aa326d48a7257e3f4a4b62c5e98ec8e49fa2bdd8d96cef7e6febf1399f5c7016114fd1f68a1c62c6138826d5d90bc650448e3cf0951c53c7 + version: 3.2.1 + resolution: "jsonc-parser@npm:3.2.1" + checksum: 10c0/ada66dec143d7f9cb0e2d0d29c69e9ce40d20f3a4cb96b0c6efb745025ac7f9ba647d7ac0990d0adfc37a2d2ae084a12009a9c833dbdbeadf648879a99b9df89 languageName: node linkType: hard @@ -4316,19 +4311,28 @@ __metadata: version: 6.1.0 resolution: "jsonfile@npm:6.1.0" dependencies: - graceful-fs: ^4.1.6 - universalify: ^2.0.0 + graceful-fs: "npm:^4.1.6" + universalify: "npm:^2.0.0" dependenciesMeta: graceful-fs: optional: true - checksum: 7af3b8e1ac8fe7f1eccc6263c6ca14e1966fcbc74b618d3c78a0a2075579487547b94f72b7a1114e844a1e15bb00d440e5d1720bfc4612d790a6f285d5ea8354 + checksum: 10c0/4f95b5e8a5622b1e9e8f33c96b7ef3158122f595998114d1e7f03985649ea99cb3cd99ce1ed1831ae94c8c8543ab45ebd044207612f31a56fd08462140e46865 languageName: node linkType: hard "keycharm@npm:^0.4.0": version: 0.4.0 resolution: "keycharm@npm:0.4.0" - checksum: b6a601e04d7354af4f94facb4174bc46d0788b30b7d19ab8af37dacffb43f6f7ae4ab1f2a2a635de28b4da107b2f1b7219efc789887f7897ed53f209c97cce85 + checksum: 10c0/5e845331148b5cb652f65a6354a830df62a189e2c17faec56375fa12d91152a70f93c872c6f22b81acafe56b9df51268c9af6b7b8c0543cb65ba46042eb9713e + languageName: node + linkType: hard + +"keyv@npm:^4.5.3": + version: 4.5.4 + resolution: "keyv@npm:4.5.4" + dependencies: + json-buffer: "npm:3.0.1" + checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e languageName: node linkType: hard @@ -4336,70 +4340,95 @@ __metadata: version: 0.4.1 resolution: "levn@npm:0.4.1" dependencies: - prelude-ls: ^1.2.1 - type-check: ~0.4.0 - checksum: 12c5021c859bd0f5248561bf139121f0358285ec545ebf48bb3d346820d5c61a4309535c7f387ed7d84361cf821e124ce346c6b7cef8ee09a67c1473b46d0fc4 - languageName: node - linkType: hard - -"levn@npm:~0.3.0": - version: 0.3.0 - resolution: "levn@npm:0.3.0" - dependencies: - prelude-ls: ~1.1.2 - type-check: ~0.3.2 - checksum: 0d084a524231a8246bb10fec48cdbb35282099f6954838604f3c7fc66f2e16fa66fd9cc2f3f20a541a113c4dafdf181e822c887c8a319c9195444e6c64ac395e + prelude-ls: "npm:^1.2.1" + type-check: "npm:~0.4.0" + checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e languageName: node linkType: hard "lilconfig@npm:^2.0.3": - version: 2.0.6 - resolution: "lilconfig@npm:2.0.6" - checksum: 40a3cd72f103b1be5975f2ac1850810b61d4053e20ab09be8d3aeddfe042187e1ba70b4651a7e70f95efa1642e7dc8b2ae395b317b7d7753b241b43cef7c0f7d + version: 2.1.0 + resolution: "lilconfig@npm:2.1.0" + checksum: 10c0/64645641aa8d274c99338e130554abd6a0190533c0d9eb2ce7ebfaf2e05c7d9961f3ffe2bfa39efd3b60c521ba3dd24fa236fe2775fc38501bf82bf49d4678b8 languageName: node linkType: hard "lines-and-columns@npm:^1.1.6": version: 1.2.4 resolution: "lines-and-columns@npm:1.2.4" - checksum: 0c37f9f7fa212b38912b7145e1cd16a5f3cd34d782441c3e6ca653485d326f58b3caccda66efce1c5812bde4961bbde3374fae4b0d11bf1226152337f3894aa5 + checksum: 10c0/3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d languageName: node linkType: hard -"lit-element@npm:^3.2.0": - version: 3.2.2 - resolution: "lit-element@npm:3.2.2" +"lit-element@npm:^3.3.0": + version: 3.3.3 + resolution: "lit-element@npm:3.3.3" dependencies: - "@lit/reactive-element": ^1.3.0 - lit-html: ^2.2.0 - checksum: e1df57c02ad5ae4c42b49a5066b3b623bccf7fa6610bbc3f65bc22cbbe1546ecd6a7f717b1f01863929262f416c4b8b7a39ff166114215f93cc22f4e5b3825c3 + "@lit-labs/ssr-dom-shim": "npm:^1.1.0" + "@lit/reactive-element": "npm:^1.3.0" + lit-html: "npm:^2.8.0" + checksum: 10c0/f44c12fa3423a4e9ca5b84651410687e14646bb270ac258325e6905affac64a575f041f8440377e7ebaefa3910b6f0d6b8b1e902cb1aa5d0849b3fdfbf4fb3b6 languageName: node linkType: hard -"lit-html@npm:^2.2.0, lit-html@npm:^2.6.0": - version: 2.6.1 - resolution: "lit-html@npm:2.6.1" +"lit-element@npm:^4.0.4": + version: 4.0.4 + resolution: "lit-element@npm:4.0.4" dependencies: - "@types/trusted-types": ^2.0.2 - checksum: 32291eb5bcaa7fcc1d433522a9a62c3c3d240e49bb8c57ccea5c10014823d94f62f17e2d5361781cb6ee0b3c9078ef839de6164d5374371d650471904515e48e + "@lit-labs/ssr-dom-shim": "npm:^1.2.0" + "@lit/reactive-element": "npm:^2.0.4" + lit-html: "npm:^3.1.2" + checksum: 10c0/c8fa358ff8208b5ef4e40018e4e6f3ad691ffc6aaaf32bec222b2e9117da18f92c80ecd41d394d494e9a55f7b0eee8a18a6529b401698f1f35dbe353a3042339 languageName: node linkType: hard -"lit@npm:^2.0.0, lit@npm:^2.1.1, lit@npm:^2.3.1": - version: 2.6.1 - resolution: "lit@npm:2.6.1" +"lit-html@npm:^2.8.0": + version: 2.8.0 + resolution: "lit-html@npm:2.8.0" dependencies: - "@lit/reactive-element": ^1.6.0 - lit-element: ^3.2.0 - lit-html: ^2.6.0 - checksum: 74f2813152a48f195784f01b6b4ff7e4e7d8fa90ac272b725d1953fa3e1d6c9dca60b77da435f34144fcdd38705480889a8ea986835676932a8559c897cea517 + "@types/trusted-types": "npm:^2.0.2" + checksum: 10c0/90057dee050803823ac884c1355b0213ab8c05fbe2ec63943c694b61aade5d36272068f3925f45a312835e504f9c9784738ef797009f0a756a750351eafb52d5 languageName: node linkType: hard -"local-pkg@npm:^0.4.3": - version: 0.4.3 - resolution: "local-pkg@npm:0.4.3" - checksum: 7825aca531dd6afa3a3712a0208697aa4a5cd009065f32e3fb732aafcc42ed11f277b5ac67229222e96f4def55197171cdf3d5522d0381b489d2e5547b407d55 +"lit-html@npm:^3.1.2": + version: 3.1.2 + resolution: "lit-html@npm:3.1.2" + dependencies: + "@types/trusted-types": "npm:^2.0.2" + checksum: 10c0/923ef6e0d52aef0cd1f3d6922c7b46e9de7efe0493b205da7f0e5a1d50ab02884cab87425886e2281396ece7745e4b794220bb5e8c4fedbdba47281aeeb489d3 + languageName: node + linkType: hard + +"lit@npm:^2.0.0 || ^3.0.0, lit@npm:^3.1.2": + version: 3.1.2 + resolution: "lit@npm:3.1.2" + dependencies: + "@lit/reactive-element": "npm:^2.0.4" + lit-element: "npm:^4.0.4" + lit-html: "npm:^3.1.2" + checksum: 10c0/47f10dbc6716974de6d6d6b75db278ac28869839c099e77f8f8494b25b1d3913f2c62126a52372a8b0c5e4a1d0d2301637d98d9ff1e583ee7d961998686810c9 + languageName: node + linkType: hard + +"lit@npm:^2.1.1": + version: 2.8.0 + resolution: "lit@npm:2.8.0" + dependencies: + "@lit/reactive-element": "npm:^1.6.0" + lit-element: "npm:^3.3.0" + lit-html: "npm:^2.8.0" + checksum: 10c0/bf33c26b1937ee204aed1adbfa4b3d43a284e85aad8ea9763c7865365917426eded4e5888158b4136095ea42054812561fe272862b61775f1198fad3588b071f + languageName: node + linkType: hard + +"local-pkg@npm:^0.5.0": + version: 0.5.0 + resolution: "local-pkg@npm:0.5.0" + dependencies: + mlly: "npm:^1.4.2" + pkg-types: "npm:^1.0.3" + checksum: 10c0/f61cbd00d7689f275558b1a45c7ff2a3ddf8472654123ed880215677b9adfa729f1081e50c27ffb415cdb9fa706fb755fec5e23cdd965be375c8059e87ff1cc9 languageName: node linkType: hard @@ -4407,8 +4436,8 @@ __metadata: version: 5.0.0 resolution: "locate-path@npm:5.0.0" dependencies: - p-locate: ^4.1.0 - checksum: 83e51725e67517287d73e1ded92b28602e3ae5580b301fe54bfb76c0c723e3f285b19252e375712316774cf52006cb236aed5704692c32db0d5d089b69696e30 + p-locate: "npm:^4.1.0" + checksum: 10c0/33a1c5247e87e022f9713e6213a744557a3e9ec32c5d0b5efb10aa3a38177615bf90221a5592674857039c1a0fd2063b82f285702d37b792d973e9e72ace6c59 languageName: node linkType: hard @@ -4416,52 +4445,59 @@ __metadata: version: 6.0.0 resolution: "locate-path@npm:6.0.0" dependencies: - p-locate: ^5.0.0 - checksum: 72eb661788a0368c099a184c59d2fee760b3831c9c1c33955e8a19ae4a21b4116e53fa736dc086cdeb9fce9f7cc508f2f92d2d3aae516f133e16a2bb59a39f5a + p-locate: "npm:^5.0.0" + checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3 languageName: node linkType: hard "lodash-es@npm:^4.17.21": version: 4.17.21 resolution: "lodash-es@npm:4.17.21" - checksum: 05cbffad6e2adbb331a4e16fbd826e7faee403a1a04873b82b42c0f22090f280839f85b95393f487c1303c8a3d2a010048bf06151a6cbe03eee4d388fb0a12d2 + checksum: 10c0/fb407355f7e6cd523a9383e76e6b455321f0f153a6c9625e21a8827d10c54c2a2341bd2ae8d034358b60e07325e1330c14c224ff582d04612a46a4f0479ff2f2 languageName: node linkType: hard "lodash.memoize@npm:^4.1.2": version: 4.1.2 resolution: "lodash.memoize@npm:4.1.2" - checksum: 9ff3942feeccffa4f1fafa88d32f0d24fdc62fd15ded5a74a5f950ff5f0c6f61916157246744c620173dddf38d37095a92327d5fd3861e2063e736a5c207d089 + checksum: 10c0/c8713e51eccc650422716a14cece1809cfe34bc5ab5e242b7f8b4e2241c2483697b971a604252807689b9dd69bfe3a98852e19a5b89d506b000b4187a1285df8 languageName: node linkType: hard "lodash.merge@npm:^4.6.2": version: 4.6.2 resolution: "lodash.merge@npm:4.6.2" - checksum: ad580b4bdbb7ca1f7abf7e1bce63a9a0b98e370cf40194b03380a46b4ed799c9573029599caebc1b14e3f24b111aef72b96674a56cfa105e0f5ac70546cdc005 + checksum: 10c0/402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506 languageName: node linkType: hard "lodash.uniq@npm:^4.5.0": version: 4.5.0 resolution: "lodash.uniq@npm:4.5.0" - checksum: a4779b57a8d0f3c441af13d9afe7ecff22dd1b8ce1129849f71d9bbc8e8ee4e46dfb4b7c28f7ad3d67481edd6e51126e4e2a6ee276e25906d10f7140187c392d + checksum: 10c0/262d400bb0952f112162a320cc4a75dea4f66078b9e7e3075ffbc9c6aa30b3e9df3cf20e7da7d566105e1ccf7804e4fbd7d804eee0b53de05d83f16ffbf41c5e languageName: node linkType: hard "lodash@npm:^4.17.21": version: 4.17.21 resolution: "lodash@npm:4.17.21" - checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 + checksum: 10c0/d8cbea072bb08655bb4c989da418994b073a608dffa608b09ac04b43a791b12aeae7cd7ad919aa4c925f33b48490b5cfe6c1f71d827956071dae2e7bb3a6b74c languageName: node linkType: hard -"loupe@npm:^2.3.1, loupe@npm:^2.3.6": - version: 2.3.6 - resolution: "loupe@npm:2.3.6" +"loupe@npm:^2.3.6, loupe@npm:^2.3.7": + version: 2.3.7 + resolution: "loupe@npm:2.3.7" dependencies: - get-func-name: ^2.0.0 - checksum: cc83f1b124a1df7384601d72d8d1f5fe95fd7a8185469fec48bb2e4027e45243949e7a013e8d91051a138451ff0552310c32aa9786e60b6a30d1e801bdc2163f + get-func-name: "npm:^2.0.1" + checksum: 10c0/71a781c8fc21527b99ed1062043f1f2bb30bdaf54fa4cf92463427e1718bc6567af2988300bc243c1f276e4f0876f29e3cbf7b58106fdc186915687456ce5bf4 + languageName: node + linkType: hard + +"lru-cache@npm:^10.0.1, lru-cache@npm:^9.1.1 || ^10.0.0": + version: 10.2.0 + resolution: "lru-cache@npm:10.2.0" + checksum: 10c0/c9847612aa2daaef102d30542a8d6d9b2c2bb36581c1bf0dc3ebf5e5f3352c772a749e604afae2e46873b930a9e9523743faac4e5b937c576ab29196774712ee languageName: node linkType: hard @@ -4469,8 +4505,8 @@ __metadata: version: 5.1.1 resolution: "lru-cache@npm:5.1.1" dependencies: - yallist: ^3.0.2 - checksum: c154ae1cbb0c2206d1501a0e94df349653c92c8cbb25236d7e85190bcaf4567a03ac6eb43166fabfa36fd35623694da7233e88d9601fbf411a9a481d85dbd2cb + yallist: "npm:^3.0.2" + checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482 languageName: node linkType: hard @@ -4478,15 +4514,8 @@ __metadata: version: 6.0.0 resolution: "lru-cache@npm:6.0.0" dependencies: - yallist: ^4.0.0 - checksum: f97f499f898f23e4585742138a22f22526254fdba6d75d41a1c2526b3b6cc5747ef59c5612ba7375f42aca4f8461950e925ba08c991ead0651b4918b7c978297 - languageName: node - linkType: hard - -"lru-cache@npm:^7.7.1": - version: 7.14.1 - resolution: "lru-cache@npm:7.14.1" - checksum: d72c6713c6a6d86836a7a6523b3f1ac6764768cca47ec99341c3e76db06aacd4764620e5e2cda719a36848785a52a70e531822dc2b33fb071fa709683746c104 + yallist: "npm:^4.0.0" + checksum: 10c0/cb53e582785c48187d7a188d3379c181b5ca2a9c78d2bce3e7dee36f32761d1c42983da3fe12b55cb74e1779fa94cdc2e5367c028a9b35317184ede0c07a30a9 languageName: node linkType: hard @@ -4494,26 +4523,37 @@ __metadata: version: 0.25.9 resolution: "magic-string@npm:0.25.9" dependencies: - sourcemap-codec: ^1.4.8 - checksum: 9a0e55a15c7303fc360f9572a71cffba1f61451bc92c5602b1206c9d17f492403bf96f946dfce7483e66822d6b74607262e24392e87b0ac27b786e69a40e9b1a + sourcemap-codec: "npm:^1.4.8" + checksum: 10c0/37f5e01a7e8b19a072091f0b45ff127cda676232d373ce2c551a162dd4053c575ec048b9cbb4587a1f03adb6c5d0fd0dd49e8ab070cd2c83a4992b2182d9cb56 languageName: node linkType: hard -"magic-string@npm:^0.30.1": - version: 0.30.3 - resolution: "magic-string@npm:0.30.3" +"magic-string@npm:^0.30.5": + version: 0.30.7 + resolution: "magic-string@npm:0.30.7" dependencies: - "@jridgewell/sourcemap-codec": ^1.4.15 - checksum: a5a9ddf9bd3bf49a2de1048bf358464f1bda7b3cc1311550f4a0ba8f81a4070e25445d53a5ee28850161336f1bff3cf28aa3320c6b4aeff45ce3e689f300b2f3 + "@jridgewell/sourcemap-codec": "npm:^1.4.15" + checksum: 10c0/d1d949f7a53c37c6e685f4ea7b2b151c2fe0cc5af8f1f979ecba916f7d60d58f35309aaf4c8b09ce1aef7c160b957be39a38b52b478a91650750931e4ddd5daf languageName: node linkType: hard -"make-dir@npm:^3.0.0, make-dir@npm:^3.0.2": +"magicast@npm:^0.3.3": + version: 0.3.3 + resolution: "magicast@npm:0.3.3" + dependencies: + "@babel/parser": "npm:^7.23.6" + "@babel/types": "npm:^7.23.6" + source-map-js: "npm:^1.0.2" + checksum: 10c0/2eeba19545ac4328433be817bd81fcfa8a517ec67599260541e13ce5ce18b27ff8830f1b87d54a1392d408d1b96e44938bf026920f0110edbdfecc96980919b3 + languageName: node + linkType: hard + +"make-dir@npm:^3.0.2": version: 3.1.0 resolution: "make-dir@npm:3.1.0" dependencies: - semver: ^6.0.0 - checksum: 484200020ab5a1fdf12f393fe5f385fc8e4378824c940fba1729dcd198ae4ff24867bc7a5646331e50cead8abff5d9270c456314386e629acec6dff4b8016b78 + semver: "npm:^6.0.0" + checksum: 10c0/56aaafefc49c2dfef02c5c95f9b196c4eb6988040cf2c712185c7fe5c99b4091591a7fc4d4eafaaefa70ff763a26f6ab8c3ff60b9e75ea19876f49b18667ecaa languageName: node linkType: hard @@ -4521,32 +4561,27 @@ __metadata: version: 4.0.0 resolution: "make-dir@npm:4.0.0" dependencies: - semver: ^7.5.3 - checksum: bf0731a2dd3aab4db6f3de1585cea0b746bb73eb5a02e3d8d72757e376e64e6ada190b1eddcde5b2f24a81b688a9897efd5018737d05e02e2a671dda9cff8a8a + semver: "npm:^7.5.3" + checksum: 10c0/69b98a6c0b8e5c4fe9acb61608a9fbcfca1756d910f51e5dbe7a9e5cfb74fca9b8a0c8a0ffdf1294a740826c1ab4871d5bf3f62f72a3049e5eac6541ddffed68 languageName: node linkType: hard -"make-fetch-happen@npm:^10.0.3": - version: 10.2.1 - resolution: "make-fetch-happen@npm:10.2.1" +"make-fetch-happen@npm:^13.0.0": + version: 13.0.0 + resolution: "make-fetch-happen@npm:13.0.0" dependencies: - agentkeepalive: ^4.2.1 - cacache: ^16.1.0 - http-cache-semantics: ^4.1.0 - http-proxy-agent: ^5.0.0 - https-proxy-agent: ^5.0.0 - is-lambda: ^1.0.1 - lru-cache: ^7.7.1 - minipass: ^3.1.6 - minipass-collect: ^1.0.2 - minipass-fetch: ^2.0.3 - minipass-flush: ^1.0.5 - minipass-pipeline: ^1.2.4 - negotiator: ^0.6.3 - promise-retry: ^2.0.1 - socks-proxy-agent: ^7.0.0 - ssri: ^9.0.0 - checksum: 2332eb9a8ec96f1ffeeea56ccefabcb4193693597b132cd110734d50f2928842e22b84cfa1508e921b8385cdfd06dda9ad68645fed62b50fff629a580f5fb72c + "@npmcli/agent": "npm:^2.0.0" + cacache: "npm:^18.0.0" + http-cache-semantics: "npm:^4.1.1" + is-lambda: "npm:^1.0.1" + minipass: "npm:^7.0.2" + minipass-fetch: "npm:^3.0.0" + minipass-flush: "npm:^1.0.5" + minipass-pipeline: "npm:^1.2.4" + negotiator: "npm:^0.6.3" + promise-retry: "npm:^2.0.1" + ssri: "npm:^10.0.0" + checksum: 10c0/43b9f6dcbc6fe8b8604cb6396957c3698857a15ba4dbc38284f7f0e61f248300585ef1eb8cc62df54e9c724af977e45b5cdfd88320ef7f53e45070ed3488da55 languageName: node linkType: hard @@ -4554,30 +4589,30 @@ __metadata: version: 4.2.2 resolution: "masonry-layout@npm:4.2.2" dependencies: - get-size: ^2.0.2 - outlayer: ^2.1.0 - checksum: b947029b8fdfb384d17d7749d80a4f00f88d885acea04d77e1fefd36827cc2a345fd40d9ccddf720ed9323e133d8ea498125eece91d2c8517f69fd4e9e1bbdf4 + get-size: "npm:^2.0.2" + outlayer: "npm:^2.1.0" + checksum: 10c0/991044cf7c22acbbb1135690314d68f9f237ef17315494c9dd25ed00fa0c526a8eb27d6bcf99a141a9d049bd62c5c251f66f9c8a4c201ca9c0944d8e44c0f09f languageName: node linkType: hard "mdn-data@npm:2.0.14": version: 2.0.14 resolution: "mdn-data@npm:2.0.14" - checksum: 9d0128ed425a89f4cba8f787dca27ad9408b5cb1b220af2d938e2a0629d17d879a34d2cb19318bdb26c3f14c77dd5dfbae67211f5caaf07b61b1f2c5c8c7dc16 + checksum: 10c0/67241f8708c1e665a061d2b042d2d243366e93e5bf1f917693007f6d55111588b952dcbfd3ea9c2d0969fb754aad81b30fdcfdcc24546495fc3b24336b28d4bd languageName: node linkType: hard "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" - checksum: 6fa4dcc8d86629705cea944a4b88ef4cb0e07656ebf223fa287443256414283dd25d91c1cd84c77987f2aec5927af1a9db6085757cb43d90eb170ebf4b47f4f4 + checksum: 10c0/867fdbb30a6d58b011449b8885601ec1690c3e41c759ecd5a9d609094f7aed0096c37823ff4a7190ef0b8f22cc86beb7049196ff68c016e3b3c671d0dac91ce5 languageName: node linkType: hard "merge2@npm:^1.3.0, merge2@npm:^1.4.1": version: 1.4.1 resolution: "merge2@npm:1.4.1" - checksum: 7268db63ed5169466540b6fb947aec313200bcf6d40c5ab722c22e242f651994619bcd85601602972d3c85bd2cc45a358a4c61937e9f11a061919a1da569b0c2 + checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb languageName: node linkType: hard @@ -4585,16 +4620,16 @@ __metadata: version: 4.0.5 resolution: "micromatch@npm:4.0.5" dependencies: - braces: ^3.0.2 - picomatch: ^2.3.1 - checksum: 02a17b671c06e8fefeeb6ef996119c1e597c942e632a21ef589154f23898c9c6a9858526246abb14f8bca6e77734aa9dcf65476fca47cedfb80d9577d52843fc + braces: "npm:^3.0.2" + picomatch: "npm:^2.3.1" + checksum: 10c0/3d6505b20f9fa804af5d8c596cb1c5e475b9b0cd05f652c5b56141cf941bd72adaeb7a436fda344235cef93a7f29b7472efc779fcdb83b478eab0867b95cdeff languageName: node linkType: hard "mime-db@npm:1.52.0": version: 1.52.0 resolution: "mime-db@npm:1.52.0" - checksum: 0d99a03585f8b39d68182803b12ac601d9c01abfa28ec56204fa330bc9f3d1c5e14beb049bafadb3dbdf646dfb94b87e24d4ec7b31b7279ef906a8ea9b6a513f + checksum: 10c0/0557a01deebf45ac5f5777fe7740b2a5c309c6d62d40ceab4e23da9f821899ce7a900b7ac8157d4548ddbb7beffe9abc621250e6d182b0397ec7f10c7b91a5aa languageName: node linkType: hard @@ -4602,17 +4637,24 @@ __metadata: version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: - mime-db: 1.52.0 - checksum: 89a5b7f1def9f3af5dad6496c5ed50191ae4331cc5389d7c521c8ad28d5fdad2d06fd81baf38fed813dc4e46bb55c8145bb0ff406330818c9cf712fb2e9b3836 + mime-db: "npm:1.52.0" + checksum: 10c0/82fb07ec56d8ff1fc999a84f2f217aa46cb6ed1033fefaabd5785b9a974ed225c90dc72fff460259e66b95b73648596dbcc50d51ed69cdf464af2d237d3149b2 languageName: node linkType: hard -"mime@npm:>=2.4.6": +"mime@npm:^3": version: 3.0.0 resolution: "mime@npm:3.0.0" bin: mime: cli.js - checksum: f43f9b7bfa64534e6b05bd6062961681aeb406a5b53673b53b683f27fcc4e739989941836a355eef831f4478923651ecc739f4a5f6e20a76487b432bfd4db928 + checksum: 10c0/402e792a8df1b2cc41cb77f0dcc46472b7944b7ec29cb5bbcd398624b6b97096728f1239766d3fdeb20551dd8d94738344c195a6ea10c4f906eb0356323b0531 + languageName: node + linkType: hard + +"mimic-fn@npm:^4.0.0": + version: 4.0.0 + resolution: "mimic-fn@npm:4.0.0" + checksum: 10c0/de9cc32be9996fd941e512248338e43407f63f6d497abe8441fa33447d922e927de54d4cc3c1a3c6d652857acd770389d5a3823f311a744132760ce2be15ccbf languageName: node linkType: hard @@ -4621,7 +4663,7 @@ __metadata: resolution: "mini-svg-data-uri@npm:1.4.4" bin: mini-svg-data-uri: cli.js - checksum: 997f1fbd8d59a70f03761e18626d335197a3479cb9d1ff75678e4b64b864d32a0b8fc18115eabde035e5299b8b4a354a78e57dd6ac10f9d604162a6170898d09 + checksum: 10c0/24545fa30b5a45449241bf19c25b8bc37594b63ec06401b3d563bd1c2e8a6abb7c18741f8b354e0064baa63c291be214154bf3a66f201ae71dfab3cc1a5e3191 languageName: node linkType: hard @@ -4629,48 +4671,48 @@ __metadata: version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: - brace-expansion: ^1.1.7 - checksum: c154e566406683e7bcb746e000b84d74465b3a832c45d59912b9b55cd50dee66e5c4b1e5566dba26154040e51672f9aa450a9aef0c97cfc7336b78b7afb9540a + brace-expansion: "npm:^1.1.7" + checksum: 10c0/0262810a8fc2e72cca45d6fd86bd349eee435eb95ac6aa45c9ea2180e7ee875ef44c32b55b5973ceabe95ea12682f6e3725cbb63d7a2d1da3ae1163c8b210311 languageName: node linkType: hard -"minimatch@npm:^5.0.1": - version: 5.1.6 - resolution: "minimatch@npm:5.1.6" +"minimatch@npm:^9.0.1": + version: 9.0.3 + resolution: "minimatch@npm:9.0.3" dependencies: - brace-expansion: ^2.0.1 - checksum: 7564208ef81d7065a370f788d337cd80a689e981042cb9a1d0e6580b6c6a8c9279eba80010516e258835a988363f99f54a6f711a315089b8b42694f5da9d0d77 + brace-expansion: "npm:^2.0.1" + checksum: 10c0/85f407dcd38ac3e180f425e86553911d101455ca3ad5544d6a7cec16286657e4f8a9aa6695803025c55e31e35a91a2252b5dc8e7d527211278b8b65b4dbd5eac languageName: node linkType: hard "minimist@npm:^1.2.0, minimist@npm:^1.2.6": - version: 1.2.7 - resolution: "minimist@npm:1.2.7" - checksum: 7346574a1038ca23c32e02252f603801f09384dd1d78b69a943a4e8c2c28730b80e96193882d3d3b22a063445f460e48316b29b8a25addca2d7e5e8f75478bec + version: 1.2.8 + resolution: "minimist@npm:1.2.8" + checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 languageName: node linkType: hard -"minipass-collect@npm:^1.0.2": - version: 1.0.2 - resolution: "minipass-collect@npm:1.0.2" +"minipass-collect@npm:^2.0.1": + version: 2.0.1 + resolution: "minipass-collect@npm:2.0.1" dependencies: - minipass: ^3.0.0 - checksum: 14df761028f3e47293aee72888f2657695ec66bd7d09cae7ad558da30415fdc4752bbfee66287dcc6fd5e6a2fa3466d6c484dc1cbd986525d9393b9523d97f10 + minipass: "npm:^7.0.3" + checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e languageName: node linkType: hard -"minipass-fetch@npm:^2.0.3": - version: 2.1.2 - resolution: "minipass-fetch@npm:2.1.2" +"minipass-fetch@npm:^3.0.0": + version: 3.0.4 + resolution: "minipass-fetch@npm:3.0.4" dependencies: - encoding: ^0.1.13 - minipass: ^3.1.6 - minipass-sized: ^1.0.3 - minizlib: ^2.1.2 + encoding: "npm:^0.1.13" + minipass: "npm:^7.0.3" + minipass-sized: "npm:^1.0.3" + minizlib: "npm:^2.1.2" dependenciesMeta: encoding: optional: true - checksum: 3f216be79164e915fc91210cea1850e488793c740534985da017a4cbc7a5ff50506956d0f73bb0cb60e4fe91be08b6b61ef35101706d3ef5da2c8709b5f08f91 + checksum: 10c0/1b63c1f3313e88eeac4689f1b71c9f086598db9a189400e3ee960c32ed89e06737fa23976c9305c2d57464fb3fcdc12749d3378805c9d6176f5569b0d0ee8a75 languageName: node linkType: hard @@ -4678,8 +4720,8 @@ __metadata: version: 1.0.5 resolution: "minipass-flush@npm:1.0.5" dependencies: - minipass: ^3.0.0 - checksum: 56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf + minipass: "npm:^3.0.0" + checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd languageName: node linkType: hard @@ -4687,8 +4729,8 @@ __metadata: version: 1.2.4 resolution: "minipass-pipeline@npm:1.2.4" dependencies: - minipass: ^3.0.0 - checksum: b14240dac0d29823c3d5911c286069e36d0b81173d7bdf07a7e4a91ecdef92cdff4baaf31ea3746f1c61e0957f652e641223970870e2353593f382112257971b + minipass: "npm:^3.0.0" + checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 languageName: node linkType: hard @@ -4696,24 +4738,31 @@ __metadata: version: 1.0.3 resolution: "minipass-sized@npm:1.0.3" dependencies: - minipass: ^3.0.0 - checksum: 79076749fcacf21b5d16dd596d32c3b6bf4d6e62abb43868fac21674078505c8b15eaca4e47ed844985a4514854f917d78f588fcd029693709417d8f98b2bd60 + minipass: "npm:^3.0.0" + checksum: 10c0/298f124753efdc745cfe0f2bdfdd81ba25b9f4e753ca4a2066eb17c821f25d48acea607dfc997633ee5bf7b6dfffb4eee4f2051eb168663f0b99fad2fa4829cb languageName: node linkType: hard -"minipass@npm:^3.0.0, minipass@npm:^3.1.1, minipass@npm:^3.1.6": +"minipass@npm:^3.0.0": version: 3.3.6 resolution: "minipass@npm:3.3.6" dependencies: - yallist: ^4.0.0 - checksum: a30d083c8054cee83cdcdc97f97e4641a3f58ae743970457b1489ce38ee1167b3aaf7d815cd39ec7a99b9c40397fd4f686e83750e73e652b21cb516f6d845e48 + yallist: "npm:^4.0.0" + checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c languageName: node linkType: hard -"minipass@npm:^4.0.0": - version: 4.0.2 - resolution: "minipass@npm:4.0.2" - checksum: 2e4f4caaf85a45c01c6042adc43b5111a6113f62e300acf1db3b193ac3ec6e955bc893d6d8a08635598771a55a0f60487dcac59a1ac39557eb524295d4778c9e +"minipass@npm:^5.0.0": + version: 5.0.0 + resolution: "minipass@npm:5.0.0" + checksum: 10c0/a91d8043f691796a8ac88df039da19933ef0f633e3d7f0d35dcd5373af49131cf2399bfc355f41515dc495e3990369c3858cd319e5c2722b4753c90bf3152462 + languageName: node + linkType: hard + +"minipass@npm:^5.0.0 || ^6.0.2 || ^7.0.0, minipass@npm:^7.0.2, minipass@npm:^7.0.3": + version: 7.0.4 + resolution: "minipass@npm:7.0.4" + checksum: 10c0/6c7370a6dfd257bf18222da581ba89a5eaedca10e158781232a8b5542a90547540b4b9b7e7f490e4cda43acfbd12e086f0453728ecf8c19e0ef6921bc5958ac5 languageName: node linkType: hard @@ -4721,9 +4770,9 @@ __metadata: version: 2.1.2 resolution: "minizlib@npm:2.1.2" dependencies: - minipass: ^3.0.0 - yallist: ^4.0.0 - checksum: f1fdeac0b07cf8f30fcf12f4b586795b97be856edea22b5e9072707be51fc95d41487faec3f265b42973a304fe3a64acd91a44a3826a963e37b37bafde0212c3 + minipass: "npm:^3.0.0" + yallist: "npm:^4.0.0" + checksum: 10c0/64fae024e1a7d0346a1102bb670085b17b7f95bf6cfdf5b128772ec8faf9ea211464ea4add406a3a6384a7d87a0cd1a96263692134323477b4fb43659a6cab78 languageName: node linkType: hard @@ -4732,141 +4781,131 @@ __metadata: resolution: "mkdirp@npm:1.0.4" bin: mkdirp: bin/cmd.js - checksum: a96865108c6c3b1b8e1d5e9f11843de1e077e57737602de1b82030815f311be11f96f09cce59bd5b903d0b29834733e5313f9301e3ed6d6f6fba2eae0df4298f + checksum: 10c0/46ea0f3ffa8bc6a5bc0c7081ffc3907777f0ed6516888d40a518c5111f8366d97d2678911ad1a6882bf592fa9de6c784fea32e1687bb94e1f4944170af48a5cf languageName: node linkType: hard -"mlly@npm:^1.2.0, mlly@npm:^1.4.0": - version: 1.4.1 - resolution: "mlly@npm:1.4.1" +"mlly@npm:^1.2.0, mlly@npm:^1.4.2": + version: 1.6.1 + resolution: "mlly@npm:1.6.1" dependencies: - acorn: ^8.10.0 - pathe: ^1.1.1 - pkg-types: ^1.0.3 - ufo: ^1.3.0 - checksum: b2b59ab3d70196127be4e54609d2a442bd252345727138940fb245672a238b2fbdd431e8c75ec5c741ff90410ce488c5fd6446d5d3e6476d21dbf4c3fa35d4a0 + acorn: "npm:^8.11.3" + pathe: "npm:^1.1.2" + pkg-types: "npm:^1.0.3" + ufo: "npm:^1.3.2" + checksum: 10c0/a7bf26b3d4f83b0f5a5232caa3af44be08b464f562f31c11d885d1bc2d43b7d717137d47b0c06fdc69e1b33ffc09f902b6d2b18de02c577849d40914e8785092 languageName: node linkType: hard "moment@npm:^2.29.4": - version: 2.29.4 - resolution: "moment@npm:2.29.4" - checksum: 0ec3f9c2bcba38dc2451b1daed5daded747f17610b92427bebe1d08d48d8b7bdd8d9197500b072d14e326dd0ccf3e326b9e3d07c5895d3d49e39b6803b76e80e + version: 2.30.1 + resolution: "moment@npm:2.30.1" + checksum: 10c0/865e4279418c6de666fca7786607705fd0189d8a7b7624e2e56be99290ac846f90878a6f602e34b4e0455c549b85385b1baf9966845962b313699e7cb847543a languageName: node linkType: hard "ms@npm:2.1.2": version: 2.1.2 resolution: "ms@npm:2.1.2" - checksum: 673cdb2c3133eb050c745908d8ce632ed2c02d85640e2edb3ace856a2266a813b30c613569bf3354fdf4ea7d1a1494add3bfa95e2713baa27d0c2c71fc44f58f + checksum: 10c0/a437714e2f90dbf881b5191d35a6db792efbca5badf112f87b9e1c712aace4b4b9b742dd6537f3edf90fd6f684de897cec230abde57e87883766712ddda297cc languageName: node linkType: hard -"ms@npm:^2.0.0, ms@npm:^2.1.1": +"ms@npm:^2.1.1": version: 2.1.3 resolution: "ms@npm:2.1.3" - checksum: aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d + checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 languageName: node linkType: hard -"nanoid@npm:^3.3.4": - version: 3.3.4 - resolution: "nanoid@npm:3.3.4" +"nanoid@npm:^3.3.7": + version: 3.3.7 + resolution: "nanoid@npm:3.3.7" bin: nanoid: bin/nanoid.cjs - checksum: 2fddd6dee994b7676f008d3ffa4ab16035a754f4bb586c61df5a22cf8c8c94017aadd360368f47d653829e0569a92b129979152ff97af23a558331e47e37cd9c + checksum: 10c0/e3fb661aa083454f40500473bb69eedb85dc160e763150b9a2c567c7e9ff560ce028a9f833123b618a6ea742e311138b591910e795614a629029e86e180660f3 languageName: node linkType: hard "natural-compare-lite@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare-lite@npm:1.4.0" - checksum: 5222ac3986a2b78dd6069ac62cbb52a7bf8ffc90d972ab76dfe7b01892485d229530ed20d0c62e79a6b363a663b273db3bde195a1358ce9e5f779d4453887225 + checksum: 10c0/f6cef26f5044515754802c0fc475d81426f3b90fe88c20fabe08771ce1f736ce46e0397c10acb569a4dd0acb84c7f1ee70676122f95d5bfdd747af3a6c6bbaa8 languageName: node linkType: hard "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" - checksum: 23ad088b08f898fc9b53011d7bb78ec48e79de7627e01ab5518e806033861bef68d5b0cd0e2205c2f36690ac9571ff6bcb05eb777ced2eeda8d4ac5b44592c3d + checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 languageName: node linkType: hard "negotiator@npm:^0.6.3": version: 0.6.3 resolution: "negotiator@npm:0.6.3" - checksum: b8ffeb1e262eff7968fc90a2b6767b04cfd9842582a9d0ece0af7049537266e7b2506dfb1d107a32f06dd849ab2aea834d5830f7f4d0e5cb7d36e1ae55d021d9 + checksum: 10c0/3ec9fd413e7bf071c937ae60d572bc67155262068ed522cf4b3be5edbe6ddf67d095ec03a3a14ebf8fc8e95f8e1d61be4869db0dbb0de696f6b837358bd43fc2 languageName: node linkType: hard "node-gyp@npm:latest": - version: 9.3.1 - resolution: "node-gyp@npm:9.3.1" + version: 10.0.1 + resolution: "node-gyp@npm:10.0.1" dependencies: - env-paths: ^2.2.0 - glob: ^7.1.4 - graceful-fs: ^4.2.6 - make-fetch-happen: ^10.0.3 - nopt: ^6.0.0 - npmlog: ^6.0.0 - rimraf: ^3.0.2 - semver: ^7.3.5 - tar: ^6.1.2 - which: ^2.0.2 + env-paths: "npm:^2.2.0" + exponential-backoff: "npm:^3.1.1" + glob: "npm:^10.3.10" + graceful-fs: "npm:^4.2.6" + make-fetch-happen: "npm:^13.0.0" + nopt: "npm:^7.0.0" + proc-log: "npm:^3.0.0" + semver: "npm:^7.3.5" + tar: "npm:^6.1.2" + which: "npm:^4.0.0" bin: node-gyp: bin/node-gyp.js - checksum: b860e9976fa645ca0789c69e25387401b4396b93c8375489b5151a6c55cf2640a3b6183c212b38625ef7c508994930b72198338e3d09b9d7ade5acc4aaf51ea7 + checksum: 10c0/abddfff7d873312e4ed4a5fb75ce893a5c4fb69e7fcb1dfa71c28a6b92a7f1ef6b62790dffb39181b5a82728ba8f2f32d229cf8cbe66769fe02cea7db4a555aa languageName: node linkType: hard -"node-releases@npm:^2.0.13": - version: 2.0.13 - resolution: "node-releases@npm:2.0.13" - checksum: 17ec8f315dba62710cae71a8dad3cd0288ba943d2ece43504b3b1aa8625bf138637798ab470b1d9035b0545996f63000a8a926e0f6d35d0996424f8b6d36dda3 +"node-releases@npm:^2.0.14": + version: 2.0.14 + resolution: "node-releases@npm:2.0.14" + checksum: 10c0/199fc93773ae70ec9969bc6d5ac5b2bbd6eb986ed1907d751f411fef3ede0e4bfdb45ceb43711f8078bea237b6036db8b1bf208f6ff2b70c7d615afd157f3ab9 languageName: node linkType: hard -"node-releases@npm:^2.0.8": - version: 2.0.10 - resolution: "node-releases@npm:2.0.10" - checksum: d784ecde25696a15d449c4433077f5cce620ed30a1656c4abf31282bfc691a70d9618bae6868d247a67914d1be5cc4fde22f65a05f4398cdfb92e0fc83cadfbc - languageName: node - linkType: hard - -"nopt@npm:^6.0.0": - version: 6.0.0 - resolution: "nopt@npm:6.0.0" +"nopt@npm:^7.0.0": + version: 7.2.0 + resolution: "nopt@npm:7.2.0" dependencies: - abbrev: ^1.0.0 + abbrev: "npm:^2.0.0" bin: nopt: bin/nopt.js - checksum: 82149371f8be0c4b9ec2f863cc6509a7fd0fa729929c009f3a58e4eb0c9e4cae9920e8f1f8eb46e7d032fec8fb01bede7f0f41a67eb3553b7b8e14fa53de1dac + checksum: 10c0/9bd7198df6f16eb29ff16892c77bcf7f0cc41f9fb5c26280ac0def2cf8cf319f3b821b3af83eba0e74c85807cc430a16efe0db58fe6ae1f41e69519f585b6aff languageName: node linkType: hard "normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": version: 3.0.0 resolution: "normalize-path@npm:3.0.0" - checksum: 88eeb4da891e10b1318c4b2476b6e2ecbeb5ff97d946815ffea7794c31a89017c70d7f34b3c2ebf23ef4e9fc9fb99f7dffe36da22011b5b5c6ffa34f4873ec20 + checksum: 10c0/e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046 languageName: node linkType: hard "normalize-url@npm:^6.0.1": version: 6.1.0 resolution: "normalize-url@npm:6.1.0" - checksum: 4a4944631173e7d521d6b80e4c85ccaeceb2870f315584fa30121f505a6dfd86439c5e3fdd8cd9e0e291290c41d0c3599f0cb12ab356722ed242584c30348e50 + checksum: 10c0/95d948f9bdd2cfde91aa786d1816ae40f8262946e13700bf6628105994fe0ff361662c20af3961161c38a119dc977adeb41fc0b41b1745eb77edaaf9cb22db23 languageName: node linkType: hard -"npmlog@npm:^6.0.0": - version: 6.0.2 - resolution: "npmlog@npm:6.0.2" +"npm-run-path@npm:^5.1.0": + version: 5.3.0 + resolution: "npm-run-path@npm:5.3.0" dependencies: - are-we-there-yet: ^3.0.0 - console-control-strings: ^1.1.0 - gauge: ^4.0.3 - set-blocking: ^2.0.0 - checksum: ae238cd264a1c3f22091cdd9e2b106f684297d3c184f1146984ecbe18aaa86343953f26b9520dedd1b1372bc0316905b736c1932d778dbeb1fcf5a1001390e2a + path-key: "npm:^4.0.0" + checksum: 10c0/124df74820c40c2eb9a8612a254ea1d557ddfab1581c3e751f825e3e366d9f00b0d76a3c94ecd8398e7f3eee193018622677e95816e8491f0797b21e30b2deba languageName: node linkType: hard @@ -4874,63 +4913,87 @@ __metadata: version: 2.1.1 resolution: "nth-check@npm:2.1.1" dependencies: - boolbase: ^1.0.0 - checksum: 5afc3dafcd1573b08877ca8e6148c52abd565f1d06b1eb08caf982e3fa289a82f2cae697ffb55b5021e146d60443f1590a5d6b944844e944714a5b549675bcd3 + boolbase: "npm:^1.0.0" + checksum: 10c0/5fee7ff309727763689cfad844d979aedd2204a817fbaaf0e1603794a7c20db28548d7b024692f953557df6ce4a0ee4ae46cd8ebd9b36cfb300b9226b567c479 languageName: node linkType: hard -"nwsapi@npm:^2.2.2": - version: 2.2.4 - resolution: "nwsapi@npm:2.2.4" - checksum: a5eb9467158bdf255d27e9c4555e9ca02e4ba84ddce9b683856ed49de23eb1bb28ae3b8e791b7a93d156ad62b324a56f4d44cad827c2ca288c107ed6bdaff8a8 +"nwsapi@npm:^2.2.4": + version: 2.2.7 + resolution: "nwsapi@npm:2.2.7" + checksum: 10c0/44be198adae99208487a1c886c0a3712264f7bbafa44368ad96c003512fed2753d4e22890ca1e6edb2690c3456a169f2a3c33bfacde1905cf3bf01c7722464db languageName: node linkType: hard -"object-inspect@npm:^1.12.2, object-inspect@npm:^1.9.0": - version: 1.12.3 - resolution: "object-inspect@npm:1.12.3" - checksum: dabfd824d97a5f407e6d5d24810d888859f6be394d8b733a77442b277e0808860555176719c5905e765e3743a7cada6b8b0a3b85e5331c530fd418cc8ae991db +"object-inspect@npm:^1.13.1": + version: 1.13.1 + resolution: "object-inspect@npm:1.13.1" + checksum: 10c0/fad603f408e345c82e946abdf4bfd774260a5ed3e5997a0b057c44153ac32c7271ff19e3a5ae39c858da683ba045ccac2f65245c12763ce4e8594f818f4a648d languageName: node linkType: hard "object-keys@npm:^1.1.1": version: 1.1.1 resolution: "object-keys@npm:1.1.1" - checksum: b363c5e7644b1e1b04aa507e88dcb8e3a2f52b6ffd0ea801e4c7a62d5aa559affe21c55a07fd4b1fd55fc03a33c610d73426664b20032405d7b92a1414c34d6a + checksum: 10c0/b11f7ccdbc6d406d1f186cdadb9d54738e347b2692a14439ca5ac70c225fa6db46db809711b78589866d47b25fc3e8dee0b4c722ac751e11180f9380e3d8601d languageName: node linkType: hard -"object.assign@npm:^4.1.2, object.assign@npm:^4.1.4": - version: 4.1.4 - resolution: "object.assign@npm:4.1.4" +"object.assign@npm:^4.1.2, object.assign@npm:^4.1.5": + version: 4.1.5 + resolution: "object.assign@npm:4.1.5" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - has-symbols: ^1.0.3 - object-keys: ^1.1.1 - checksum: 76cab513a5999acbfe0ff355f15a6a125e71805fcf53de4e9d4e082e1989bdb81d1e329291e1e4e0ae7719f0e4ef80e88fb2d367ae60500d79d25a6224ac8864 + call-bind: "npm:^1.0.5" + define-properties: "npm:^1.2.1" + has-symbols: "npm:^1.0.3" + object-keys: "npm:^1.1.1" + checksum: 10c0/60108e1fa2706f22554a4648299b0955236c62b3685c52abf4988d14fffb0e7731e00aa8c6448397e3eb63d087dcc124a9f21e1980f36d0b2667f3c18bacd469 languageName: node linkType: hard "object.entries@npm:^1.1.5": - version: 1.1.6 - resolution: "object.entries@npm:1.1.6" + version: 1.1.7 + resolution: "object.entries@npm:1.1.7" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 0f8c47517e6a9a980241eafe3b73de11e59511883173c2b93d67424a008e47e11b77c80e431ad1d8a806f6108b225a1cab9223e53e555776c612a24297117d28 + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + checksum: 10c0/3ad1899cc7bf14546bf28f4a9b363ae8690b90948fcfbcac4c808395435d760f26193d9cae95337ce0e3c1e5c1f4fa45f7b46b31b68d389e9e117fce38775d86 languageName: node linkType: hard -"object.values@npm:^1.1.6": - version: 1.1.6 - resolution: "object.values@npm:1.1.6" +"object.fromentries@npm:^2.0.7": + version: 2.0.7 + resolution: "object.fromentries@npm:2.0.7" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: f6fff9fd817c24cfd8107f50fb33061d81cd11bacc4e3dbb3852e9ff7692fde4dbce823d4333ea27cd9637ef1b6690df5fbb61f1ed314fa2959598dc3ae23d8e + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + checksum: 10c0/071745c21f6fc9e6c914691f2532c1fb60ad967e5ddc52801d09958b5de926566299d07ae14466452a7efd29015f9145d6c09c573d93a0dc6f1683ee0ec2b93b + languageName: node + linkType: hard + +"object.groupby@npm:^1.0.1": + version: 1.0.2 + resolution: "object.groupby@npm:1.0.2" + dependencies: + array.prototype.filter: "npm:^1.0.3" + call-bind: "npm:^1.0.5" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.22.3" + es-errors: "npm:^1.0.0" + checksum: 10c0/b6266b1cfec7eb784b8bbe0bca5dc4b371cf9dd3e601b0897d72fa97a5934273d8fb05b3fc5222204104dbec32b50e25ba27e05ad681f71fb739cc1c7e9b81b1 + languageName: node + linkType: hard + +"object.values@npm:^1.1.7": + version: 1.1.7 + resolution: "object.values@npm:1.1.7" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + checksum: 10c0/e869d6a37fb7afdd0054dea49036d6ccebb84854a8848a093bbd1bc516f53e690bba88f0bc3e83fdfa74c601469ee6989c9b13359cda9604144c6e732fad3b6b languageName: node linkType: hard @@ -4938,19 +5001,28 @@ __metadata: version: 1.4.0 resolution: "once@npm:1.4.0" dependencies: - wrappy: 1 - checksum: cd0a88501333edd640d95f0d2700fbde6bff20b3d4d9bdc521bdd31af0656b5706570d6c6afe532045a20bb8dc0849f8332d6f2a416e0ba6d3d3b98806c7db68 + wrappy: "npm:1" + checksum: 10c0/5d48aca287dfefabd756621c5dfce5c91a549a93e9fdb7b8246bc4c4790aa2ec17b34a260530474635147aeb631a2dcc8b32c613df0675f96041cbb8244517d0 + languageName: node + linkType: hard + +"onetime@npm:^6.0.0": + version: 6.0.0 + resolution: "onetime@npm:6.0.0" + dependencies: + mimic-fn: "npm:^4.0.0" + checksum: 10c0/4eef7c6abfef697dd4479345a4100c382d73c149d2d56170a54a07418c50816937ad09500e1ed1e79d235989d073a9bade8557122aee24f0576ecde0f392bb6c languageName: node linkType: hard "open@npm:^8.4.0": - version: 8.4.0 - resolution: "open@npm:8.4.0" + version: 8.4.2 + resolution: "open@npm:8.4.2" dependencies: - define-lazy-prop: ^2.0.0 - is-docker: ^2.1.1 - is-wsl: ^2.2.0 - checksum: e9545bec64cdbf30a0c35c1bdc310344adf8428a117f7d8df3c0af0a0a24c513b304916a6d9b11db0190ff7225c2d578885080b761ed46a3d5f6f1eebb98b63c + define-lazy-prop: "npm:^2.0.0" + is-docker: "npm:^2.1.1" + is-wsl: "npm:^2.2.0" + checksum: 10c0/bb6b3a58401dacdb0aad14360626faf3fb7fba4b77816b373495988b724fb48941cad80c1b65d62bb31a17609b2cd91c41a181602caea597ca80dfbcc27e84c9 languageName: node linkType: hard @@ -4959,35 +5031,21 @@ __metadata: resolution: "opener@npm:1.5.2" bin: opener: bin/opener-bin.js - checksum: 33b620c0d53d5b883f2abc6687dd1c5fd394d270dbe33a6356f2d71e0a2ec85b100d5bac94694198ccf5c30d592da863b2292c5539009c715a9c80c697b4f6cc + checksum: 10c0/dd56256ab0cf796585617bc28e06e058adf09211781e70b264c76a1dbe16e90f868c974e5bf5309c93469157c7d14b89c35dc53fe7293b0e40b4d2f92073bc79 languageName: node linkType: hard -"optionator@npm:^0.8.1": - version: 0.8.3 - resolution: "optionator@npm:0.8.3" +"optionator@npm:^0.9.3": + version: 0.9.3 + resolution: "optionator@npm:0.9.3" dependencies: - deep-is: ~0.1.3 - fast-levenshtein: ~2.0.6 - levn: ~0.3.0 - prelude-ls: ~1.1.2 - type-check: ~0.3.2 - word-wrap: ~1.2.3 - checksum: b8695ddf3d593203e25ab0900e265d860038486c943ff8b774f596a310f8ceebdb30c6832407a8198ba3ec9debe1abe1f51d4aad94843612db3b76d690c61d34 - languageName: node - linkType: hard - -"optionator@npm:^0.9.1": - version: 0.9.1 - resolution: "optionator@npm:0.9.1" - dependencies: - deep-is: ^0.1.3 - fast-levenshtein: ^2.0.6 - levn: ^0.4.1 - prelude-ls: ^1.2.1 - type-check: ^0.4.0 - word-wrap: ^1.2.3 - checksum: dbc6fa065604b24ea57d734261914e697bd73b69eff7f18e967e8912aa2a40a19a9f599a507fa805be6c13c24c4eae8c71306c239d517d42d4c041c942f508a0 + "@aashutoshrathi/word-wrap": "npm:^1.2.3" + deep-is: "npm:^0.1.3" + fast-levenshtein: "npm:^2.0.6" + levn: "npm:^0.4.1" + prelude-ls: "npm:^1.2.1" + type-check: "npm:^0.4.0" + checksum: 10c0/66fba794d425b5be51353035cf3167ce6cfa049059cbb93229b819167687e0f48d2bc4603fcb21b091c99acb516aae1083624675b15c4765b2e4693a085e959c languageName: node linkType: hard @@ -4995,17 +5053,17 @@ __metadata: version: 2.1.1 resolution: "outlayer@npm:2.1.1" dependencies: - ev-emitter: ^1.0.0 - fizzy-ui-utils: ^2.0.0 - get-size: ^2.0.2 - checksum: a8b69d07bad6b498ea1956f89a4bae6d38414d81a5feeae6af06cd8206a1bf47db82f664dc3ccd13b8d2c5886a6cded4a4642d0fafcbbd80f68873b7eb9f4153 + ev-emitter: "npm:^1.0.0" + fizzy-ui-utils: "npm:^2.0.0" + get-size: "npm:^2.0.2" + checksum: 10c0/863f5568e16833d11d048a760ddd92395a9e1e49b51b669d863ff4ffda4cf8f6d91ebb2c4c20e26ca30175cb295f8f436075772a56c7e17ae40d3f095d449a53 languageName: node linkType: hard "p-finally@npm:^1.0.0": version: 1.0.0 resolution: "p-finally@npm:1.0.0" - checksum: 93a654c53dc805dd5b5891bab16eb0ea46db8f66c4bfd99336ae929323b1af2b70a8b0654f8f1eae924b2b73d037031366d645f1fd18b3d30cbd15950cc4b1d4 + checksum: 10c0/6b8552339a71fe7bd424d01d8451eea92d379a711fc62f6b2fe64cad8a472c7259a236c9a22b4733abca0b5666ad503cb497792a0478c5af31ded793d00937e7 languageName: node linkType: hard @@ -5013,8 +5071,8 @@ __metadata: version: 2.3.0 resolution: "p-limit@npm:2.3.0" dependencies: - p-try: ^2.0.0 - checksum: 84ff17f1a38126c3314e91ecfe56aecbf36430940e2873dadaa773ffe072dc23b7af8e46d4b6485d302a11673fe94c6b67ca2cfbb60c989848b02100d0594ac1 + p-try: "npm:^2.0.0" + checksum: 10c0/8da01ac53efe6a627080fafc127c873da40c18d87b3f5d5492d465bb85ec7207e153948df6b9cbaeb130be70152f874229b8242ee2be84c0794082510af97f12 languageName: node linkType: hard @@ -5022,17 +5080,17 @@ __metadata: version: 3.1.0 resolution: "p-limit@npm:3.1.0" dependencies: - yocto-queue: ^0.1.0 - checksum: 7c3690c4dbf62ef625671e20b7bdf1cbc9534e83352a2780f165b0d3ceba21907e77ad63401708145ca4e25bfc51636588d89a8c0aeb715e6c37d1c066430360 + yocto-queue: "npm:^0.1.0" + checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a languageName: node linkType: hard -"p-limit@npm:^4.0.0": - version: 4.0.0 - resolution: "p-limit@npm:4.0.0" +"p-limit@npm:^5.0.0": + version: 5.0.0 + resolution: "p-limit@npm:5.0.0" dependencies: - yocto-queue: ^1.0.0 - checksum: 01d9d70695187788f984226e16c903475ec6a947ee7b21948d6f597bed788e3112cc7ec2e171c1d37125057a5f45f3da21d8653e04a3a793589e12e9e80e756b + yocto-queue: "npm:^1.0.0" + checksum: 10c0/574e93b8895a26e8485eb1df7c4b58a1a6e8d8ae41b1750cc2cc440922b3d306044fc6e9a7f74578a883d46802d9db72b30f2e612690fcef838c173261b1ed83 languageName: node linkType: hard @@ -5040,8 +5098,8 @@ __metadata: version: 4.1.0 resolution: "p-locate@npm:4.1.0" dependencies: - p-limit: ^2.2.0 - checksum: 513bd14a455f5da4ebfcb819ef706c54adb09097703de6aeaa5d26fe5ea16df92b48d1ac45e01e3944ce1e6aa2a66f7f8894742b8c9d6e276e16cd2049a2b870 + p-limit: "npm:^2.2.0" + checksum: 10c0/1b476ad69ad7f6059744f343b26d51ce091508935c1dbb80c4e0a2f397ffce0ca3a1f9f5cd3c7ce19d7929a09719d5c65fe70d8ee289c3f267cd36f2881813e9 languageName: node linkType: hard @@ -5049,8 +5107,8 @@ __metadata: version: 5.0.0 resolution: "p-locate@npm:5.0.0" dependencies: - p-limit: ^3.0.2 - checksum: 1623088f36cf1cbca58e9b61c4e62bf0c60a07af5ae1ca99a720837356b5b6c5ba3eb1b2127e47a06865fee59dd0453cad7cc844cda9d5a62ac1a5a51b7c86d3 + p-limit: "npm:^3.0.2" + checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a languageName: node linkType: hard @@ -5058,8 +5116,8 @@ __metadata: version: 4.0.0 resolution: "p-map@npm:4.0.0" dependencies: - aggregate-error: ^3.0.0 - checksum: cb0ab21ec0f32ddffd31dfc250e3afa61e103ef43d957cc45497afe37513634589316de4eb88abdfd969fe6410c22c0b93ab24328833b8eb1ccc087fc0442a1c + aggregate-error: "npm:^3.0.0" + checksum: 10c0/592c05bd6262c466ce269ff172bb8de7c6975afca9b50c975135b974e9bdaafbfe80e61aaaf5be6d1200ba08b30ead04b88cfa7e25ff1e3b93ab28c9f62a2c75 languageName: node linkType: hard @@ -5067,9 +5125,9 @@ __metadata: version: 6.6.2 resolution: "p-queue@npm:6.6.2" dependencies: - eventemitter3: ^4.0.4 - p-timeout: ^3.2.0 - checksum: 832642fcc4ab6477b43e6d7c30209ab10952969ed211c6d6f2931be8a4f9935e3578c72e8cce053dc34f2eb6941a408a2c516a54904e989851a1a209cf19761c + eventemitter3: "npm:^4.0.4" + p-timeout: "npm:^3.2.0" + checksum: 10c0/5739ecf5806bbeadf8e463793d5e3004d08bb3f6177bd1a44a005da8fd81bb90f80e4633e1fb6f1dfd35ee663a5c0229abe26aebb36f547ad5a858347c7b0d3e languageName: node linkType: hard @@ -5077,15 +5135,15 @@ __metadata: version: 3.2.0 resolution: "p-timeout@npm:3.2.0" dependencies: - p-finally: ^1.0.0 - checksum: 3dd0eaa048780a6f23e5855df3dd45c7beacff1f820476c1d0d1bcd6648e3298752ba2c877aa1c92f6453c7dd23faaf13d9f5149fc14c0598a142e2c5e8d649c + p-finally: "npm:^1.0.0" + checksum: 10c0/524b393711a6ba8e1d48137c5924749f29c93d70b671e6db761afa784726572ca06149c715632da8f70c090073afb2af1c05730303f915604fd38ee207b70a61 languageName: node linkType: hard "p-try@npm:^2.0.0": version: 2.2.0 resolution: "p-try@npm:2.2.0" - checksum: f8a8e9a7693659383f06aec604ad5ead237c7a261c18048a6e1b5b85a5f8a067e469aa24f5bc009b991ea3b058a87f5065ef4176793a200d4917349881216cae + checksum: 10c0/c36c19907734c904b16994e6535b02c36c2224d433e01a2f1ab777237f4d86e6289fd5fd464850491e940379d4606ed850c03e0f9ab600b0ebddb511312e177f languageName: node linkType: hard @@ -5093,8 +5151,8 @@ __metadata: version: 1.0.1 resolution: "parent-module@npm:1.0.1" dependencies: - callsites: ^3.0.0 - checksum: 6ba8b255145cae9470cf5551eb74be2d22281587af787a2626683a6c20fbb464978784661478dd2a3f1dad74d1e802d403e1b03c1a31fab310259eec8ac560ff + callsites: "npm:^3.0.0" + checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556 languageName: node linkType: hard @@ -5102,11 +5160,11 @@ __metadata: version: 5.2.0 resolution: "parse-json@npm:5.2.0" dependencies: - "@babel/code-frame": ^7.0.0 - error-ex: ^1.3.1 - json-parse-even-better-errors: ^2.3.0 - lines-and-columns: ^1.1.6 - checksum: 62085b17d64da57f40f6afc2ac1f4d95def18c4323577e1eced571db75d9ab59b297d1d10582920f84b15985cbfc6b6d450ccbf317644cfa176f3ed982ad87e2 + "@babel/code-frame": "npm:^7.0.0" + error-ex: "npm:^1.3.1" + json-parse-even-better-errors: "npm:^2.3.0" + lines-and-columns: "npm:^1.1.6" + checksum: 10c0/77947f2253005be7a12d858aedbafa09c9ae39eb4863adf330f7b416ca4f4a08132e453e08de2db46459256fb66afaac5ee758b44fe6541b7cdaf9d252e59585 languageName: node linkType: hard @@ -5114,85 +5172,95 @@ __metadata: version: 7.1.2 resolution: "parse5@npm:7.1.2" dependencies: - entities: ^4.4.0 - checksum: 59465dd05eb4c5ec87b76173d1c596e152a10e290b7abcda1aecf0f33be49646ea74840c69af975d7887543ea45564801736356c568d6b5e71792fd0f4055713 + entities: "npm:^4.4.0" + checksum: 10c0/297d7af8224f4b5cb7f6617ecdae98eeaed7f8cbd78956c42785e230505d5a4f07cef352af10d3006fa5c1544b76b57784d3a22d861ae071bbc460c649482bf4 languageName: node linkType: hard "path-browserify@npm:^1.0.1": version: 1.0.1 resolution: "path-browserify@npm:1.0.1" - checksum: c6d7fa376423fe35b95b2d67990060c3ee304fc815ff0a2dc1c6c3cfaff2bd0d572ee67e18f19d0ea3bbe32e8add2a05021132ac40509416459fffee35200699 + checksum: 10c0/8b8c3fd5c66bd340272180590ae4ff139769e9ab79522e2eb82e3d571a89b8117c04147f65ad066dccfb42fcad902e5b7d794b3d35e0fd840491a8ddbedf8c66 languageName: node linkType: hard "path-exists@npm:^4.0.0": version: 4.0.0 resolution: "path-exists@npm:4.0.0" - checksum: 505807199dfb7c50737b057dd8d351b82c033029ab94cb10a657609e00c1bc53b951cfdbccab8de04c5584d5eff31128ce6afd3db79281874a5ef2adbba55ed1 + checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b languageName: node linkType: hard "path-is-absolute@npm:^1.0.0": version: 1.0.1 resolution: "path-is-absolute@npm:1.0.1" - checksum: 060840f92cf8effa293bcc1bea81281bd7d363731d214cbe5c227df207c34cd727430f70c6037b5159c8a870b9157cba65e775446b0ab06fd5ecc7e54615a3b8 + checksum: 10c0/127da03c82172a2a50099cddbf02510c1791fc2cc5f7713ddb613a56838db1e8168b121a920079d052e0936c23005562059756d653b7c544c53185efe53be078 languageName: node linkType: hard "path-key@npm:^3.1.0": version: 3.1.1 resolution: "path-key@npm:3.1.1" - checksum: 55cd7a9dd4b343412a8386a743f9c746ef196e57c823d90ca3ab917f90ab9f13dd0ded27252ba49dbdfcab2b091d998bc446f6220cd3cea65db407502a740020 + checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c + languageName: node + linkType: hard + +"path-key@npm:^4.0.0": + version: 4.0.0 + resolution: "path-key@npm:4.0.0" + checksum: 10c0/794efeef32863a65ac312f3c0b0a99f921f3e827ff63afa5cb09a377e202c262b671f7b3832a4e64731003fa94af0263713962d317b9887bd1e0c48a342efba3 languageName: node linkType: hard "path-parse@npm:^1.0.7": version: 1.0.7 resolution: "path-parse@npm:1.0.7" - checksum: 49abf3d81115642938a8700ec580da6e830dde670be21893c62f4e10bd7dd4c3742ddc603fe24f898cba7eb0c6bc1777f8d9ac14185d34540c6d4d80cd9cae8a + checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1 + languageName: node + linkType: hard + +"path-scurry@npm:^1.10.1": + version: 1.10.1 + resolution: "path-scurry@npm:1.10.1" + dependencies: + lru-cache: "npm:^9.1.1 || ^10.0.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: 10c0/e5dc78a7348d25eec61ab166317e9e9c7b46818aa2c2b9006c507a6ff48c672d011292d9662527213e558f5652ce0afcc788663a061d8b59ab495681840c0c1e languageName: node linkType: hard "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" - checksum: 5b1e2daa247062061325b8fdbfd1fb56dde0a448fb1455453276ea18c60685bdad23a445dc148cf87bc216be1573357509b7d4060494a6fd768c7efad833ee45 + checksum: 10c0/666f6973f332f27581371efaf303fd6c272cc43c2057b37aa99e3643158c7e4b2626549555d88626e99ea9e046f82f32e41bbde5f1508547e9a11b149b52387c languageName: node linkType: hard -"pathe@npm:^1.1.0": - version: 1.1.0 - resolution: "pathe@npm:1.1.0" - checksum: 6b9be9968ea08a90c0824934799707a1c6a1ad22ac1f22080f377e3f75856d5e53a331b01d327329bfce538a14590587cfb250e8e7947f64408797c84c252056 - languageName: node - linkType: hard - -"pathe@npm:^1.1.1": - version: 1.1.1 - resolution: "pathe@npm:1.1.1" - checksum: 34ab3da2e5aa832ebc6a330ffe3f73d7ba8aec6e899b53b8ec4f4018de08e40742802deb12cf5add9c73b7bf719b62c0778246bd376ca62b0fb23e0dde44b759 +"pathe@npm:^1.1.0, pathe@npm:^1.1.1, pathe@npm:^1.1.2": + version: 1.1.2 + resolution: "pathe@npm:1.1.2" + checksum: 10c0/64ee0a4e587fb0f208d9777a6c56e4f9050039268faaaaecd50e959ef01bf847b7872785c36483fa5cdcdbdfdb31fef2ff222684d4fc21c330ab60395c681897 languageName: node linkType: hard "pathval@npm:^1.1.1": version: 1.1.1 resolution: "pathval@npm:1.1.1" - checksum: 090e3147716647fb7fb5b4b8c8e5b55e5d0a6086d085b6cd23f3d3c01fcf0ff56fd3cc22f2f4a033bd2e46ed55d61ed8379e123b42afe7d531a2a5fc8bb556d6 + checksum: 10c0/f63e1bc1b33593cdf094ed6ff5c49c1c0dc5dc20a646ca9725cc7fe7cd9995002d51d5685b9b2ec6814342935748b711bafa840f84c0bb04e38ff40a335c94dc languageName: node linkType: hard "picocolors@npm:^1.0.0": version: 1.0.0 resolution: "picocolors@npm:1.0.0" - checksum: a2e8092dd86c8396bdba9f2b5481032848525b3dc295ce9b57896f931e63fc16f79805144321f72976383fc249584672a75cc18d6777c6b757603f372f745981 + checksum: 10c0/20a5b249e331c14479d94ec6817a182fd7a5680debae82705747b2db7ec50009a5f6648d0621c561b0572703f84dbef0858abcbd5856d3c5511426afcb1961f7 languageName: node linkType: hard "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" - checksum: 050c865ce81119c4822c45d3c84f1ced46f93a0126febae20737bd05ca20589c564d6e9226977df859ed5e03dc73f02584a2b0faad36e896936238238b0446cf + checksum: 10c0/26c02b8d06f03206fc2ab8d16f19960f2ff9e81a658f831ecb656d8f17d9edc799e8364b1f4a7873e89d9702dff96204be0fa26fe4181f6843f040f819dac4be languageName: node linkType: hard @@ -5200,8 +5268,8 @@ __metadata: version: 4.2.0 resolution: "pkg-dir@npm:4.2.0" dependencies: - find-up: ^4.0.0 - checksum: 9863e3f35132bf99ae1636d31ff1e1e3501251d480336edb1c211133c8d58906bed80f154a1d723652df1fda91e01c7442c2eeaf9dc83157c7ae89087e43c8d6 + find-up: "npm:^4.0.0" + checksum: 10c0/c56bda7769e04907a88423feb320babaed0711af8c436ce3e56763ab1021ba107c7b0cafb11cde7529f669cfc22bffcaebffb573645cbd63842ea9fb17cd7728 languageName: node linkType: hard @@ -5209,10 +5277,17 @@ __metadata: version: 1.0.3 resolution: "pkg-types@npm:1.0.3" dependencies: - jsonc-parser: ^3.2.0 - mlly: ^1.2.0 - pathe: ^1.1.0 - checksum: 4b305c834b912ddcc8a0fe77530c0b0321fe340396f84cbb87aecdbc126606f47f2178f23b8639e71a4870f9631c7217aef52ffed0ae17ea2dbbe7e43d116a6e + jsonc-parser: "npm:^3.2.0" + mlly: "npm:^1.2.0" + pathe: "npm:^1.1.0" + checksum: 10c0/7f692ff2005f51b8721381caf9bdbc7f5461506ba19c34f8631660a215c8de5e6dca268f23a319dd180b8f7c47a0dc6efea14b376c485ff99e98d810b8f786c4 + languageName: node + linkType: hard + +"possible-typed-array-names@npm:^1.0.0": + version: 1.0.0 + resolution: "possible-typed-array-names@npm:1.0.0" + checksum: 10c0/d9aa22d31f4f7680e20269db76791b41c3a32c01a373e25f8a4813b4d45f7456bfc2b6d68f752dc4aab0e0bb0721cb3d76fb678c9101cb7a16316664bc2c73fd languageName: node linkType: hard @@ -5220,25 +5295,25 @@ __metadata: version: 8.2.4 resolution: "postcss-calc@npm:8.2.4" dependencies: - postcss-selector-parser: ^6.0.9 - postcss-value-parser: ^4.2.0 + postcss-selector-parser: "npm:^6.0.9" + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.2 - checksum: 314b4cebb0c4ed0cf8356b4bce71eca78f5a7842e6a3942a3bba49db168d5296b2bd93c3f735ae1c616f2651d94719ade33becc03c73d2d79c7394fb7f73eabb + checksum: 10c0/8518a429488c3283ff1560c83a511f6f772329bc61d88875eb7c83e13a8683b7ccbdccaa9946024cf1553da3eacd2f40fcbcebf1095f7fdeb432bf86bc6ba6ba languageName: node linkType: hard -"postcss-colormin@npm:^5.3.0": - version: 5.3.0 - resolution: "postcss-colormin@npm:5.3.0" +"postcss-colormin@npm:^5.3.1": + version: 5.3.1 + resolution: "postcss-colormin@npm:5.3.1" dependencies: - browserslist: ^4.16.6 - caniuse-api: ^3.0.0 - colord: ^2.9.1 - postcss-value-parser: ^4.2.0 + browserslist: "npm:^4.21.4" + caniuse-api: "npm:^3.0.0" + colord: "npm:^2.9.1" + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: 3d3e3cc25071407fb73d68541ca1039ebd154fceb649041461a8a3cab0400cc89b42dbb34a4eeaf573be4ba2370ce23af5e01aff5e03a8d72275f40605577212 + checksum: 10c0/c4ca6f335dd992dc8e3df24bffc3495c4e504eba8489c81cb6836fdce3203f423cf4c0b640c4b63c586f588c59d82adb5313c3c5d1a68113896d18ed71caa462 languageName: node linkType: hard @@ -5246,11 +5321,11 @@ __metadata: version: 5.1.3 resolution: "postcss-convert-values@npm:5.1.3" dependencies: - browserslist: ^4.21.4 - postcss-value-parser: ^4.2.0 + browserslist: "npm:^4.21.4" + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: df48cdaffabf9737f9cfdc58a3dc2841cf282506a7a944f6c70236cff295d3a69f63de6e0935eeb8a9d3f504324e5b4e240abc29e21df9e35a02585d3060aeb5 + checksum: 10c0/cd10a81781a12487b2921ff84a1a068e948a1956b9539a284c202abecf4cacdd3e106eb026026b22dbf70933f4315c824c111f6b71f56c355e47b842ca9b1dec languageName: node linkType: hard @@ -5259,7 +5334,7 @@ __metadata: resolution: "postcss-discard-comments@npm:5.1.2" peerDependencies: postcss: ^8.2.15 - checksum: abfd064ebc27aeaf5037643dd51ffaff74d1fa4db56b0523d073ace4248cbb64ffd9787bd6924b0983a9d0bd0e9bf9f10d73b120e50391dc236e0d26c812fa2a + checksum: 10c0/cb5ba81623c498e18d406138e7d27d69fc668802a1139a8de69d28e80b3fe222cda7b634940512cae78d04f0c78afcd15d92bcf80e537c6c85fa8ff9cd61d00f languageName: node linkType: hard @@ -5268,7 +5343,7 @@ __metadata: resolution: "postcss-discard-duplicates@npm:5.1.0" peerDependencies: postcss: ^8.2.15 - checksum: 88d6964201b1f4ed6bf7a32cefe68e86258bb6e42316ca01d9b32bdb18e7887d02594f89f4a2711d01b51ea6e3fcca8c54be18a59770fe5f4521c61d3eb6ca35 + checksum: 10c0/3d3a49536c56097c06b4f085412e0cda0854fac1c559563ccb922d9fab6305ff13058cd6fee422aa66c1d7e466add4e7672d7ae2ff551a4af6f1a8d2142d471f languageName: node linkType: hard @@ -5277,7 +5352,7 @@ __metadata: resolution: "postcss-discard-empty@npm:5.1.1" peerDependencies: postcss: ^8.2.15 - checksum: 970adb12fae5c214c0768236ad9a821552626e77dedbf24a8213d19cc2c4a531a757cd3b8cdd3fc22fb1742471b8692a1db5efe436a71236dec12b1318ee8ff4 + checksum: 10c0/36c8b2197af836dbd93168c72cde4edc1f10fe00e564824119da076d3764909745bb60e4ada04052322e26872d1bce6a37c56815f1c48c813a21adca1a41fbdc languageName: node linkType: hard @@ -5286,7 +5361,7 @@ __metadata: resolution: "postcss-discard-overridden@npm:5.1.0" peerDependencies: postcss: ^8.2.15 - checksum: d64d4a545aa2c81b22542895cfcddc787d24119f294d35d29b0599a1c818b3cc51f4ee80b80f5a0a09db282453dd5ac49f104c2117cc09112d0ac9b40b499a41 + checksum: 10c0/7d3fc0b0d90599606fc083327a7c24390f90270a94a0119af4b74815d518948581579281f63b9bfa62e2644edf59bc9e725dc04ea5ba213f697804f3fb4dd8dc languageName: node linkType: hard @@ -5294,25 +5369,25 @@ __metadata: version: 5.1.7 resolution: "postcss-merge-longhand@npm:5.1.7" dependencies: - postcss-value-parser: ^4.2.0 - stylehacks: ^5.1.1 + postcss-value-parser: "npm:^4.2.0" + stylehacks: "npm:^5.1.1" peerDependencies: postcss: ^8.2.15 - checksum: 81c3fc809f001b9b71a940148e242bdd6e2d77713d1bfffa15eb25c1f06f6648d5e57cb21645746d020a2a55ff31e1740d2b27900442913a9d53d8a01fb37e1b + checksum: 10c0/4d9f44b03f19522cc81ae4f5b1f2a9ef2db918dbd8b3042d4f1b2461b2230b8ec1269334db6a67a863ba68f64cabd712e6e45340ddb22a3fc03cd34df69d2bf0 languageName: node linkType: hard -"postcss-merge-rules@npm:^5.1.3": - version: 5.1.3 - resolution: "postcss-merge-rules@npm:5.1.3" +"postcss-merge-rules@npm:^5.1.4": + version: 5.1.4 + resolution: "postcss-merge-rules@npm:5.1.4" dependencies: - browserslist: ^4.21.4 - caniuse-api: ^3.0.0 - cssnano-utils: ^3.1.0 - postcss-selector-parser: ^6.0.5 + browserslist: "npm:^4.21.4" + caniuse-api: "npm:^3.0.0" + cssnano-utils: "npm:^3.1.0" + postcss-selector-parser: "npm:^6.0.5" peerDependencies: postcss: ^8.2.15 - checksum: 0ddaddff98cd7f3fac2b0e716c641f529a61a8668be6d5b48d60770d0a1246126088e1d606f309b9748ff598a3794f3fd6dd5b8c3d79112f84744cab5375d4d9 + checksum: 10c0/e7686cdda052071bf98810ad381e26145c43a2286f9540f04f97ef93101604b78d478dd555db91e5f73751bb353c283ba75c2fcb16a3751ac7d93dc6a0130c41 languageName: node linkType: hard @@ -5320,10 +5395,10 @@ __metadata: version: 5.1.0 resolution: "postcss-minify-font-values@npm:5.1.0" dependencies: - postcss-value-parser: ^4.2.0 + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: 35e858fa41efa05acdeb28f1c76579c409fdc7eabb1744c3bd76e895bb9fea341a016746362a67609688ab2471f587202b9a3e14ea28ad677754d663a2777ece + checksum: 10c0/7aa4f93a853b657f79a8b28d0e924cafce3720086d9da02ce04b8b2f8de42e18ce32c8f7f1078390fb5ec82468e2d8e771614387cea3563f05fd9fa1798e1c59 languageName: node linkType: hard @@ -5331,12 +5406,12 @@ __metadata: version: 5.1.1 resolution: "postcss-minify-gradients@npm:5.1.1" dependencies: - colord: ^2.9.1 - cssnano-utils: ^3.1.0 - postcss-value-parser: ^4.2.0 + colord: "npm:^2.9.1" + cssnano-utils: "npm:^3.1.0" + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: 27354072a07c5e6dab36731103b94ca2354d4ed3c5bc6aacfdf2ede5a55fa324679d8fee5450800bc50888dbb5e9ed67569c0012040c2be128143d0cebb36d67 + checksum: 10c0/bcb2802d7c8f0f76c7cff089884844f26c24b95f35c3ec951d7dec8c212495d1873d6ba62d6225ce264570e8e0668e271f9bc79bb6f5d2429c1f8933f4e3021d languageName: node linkType: hard @@ -5344,12 +5419,12 @@ __metadata: version: 5.1.4 resolution: "postcss-minify-params@npm:5.1.4" dependencies: - browserslist: ^4.21.4 - cssnano-utils: ^3.1.0 - postcss-value-parser: ^4.2.0 + browserslist: "npm:^4.21.4" + cssnano-utils: "npm:^3.1.0" + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: bd63e2cc89edcf357bb5c2a16035f6d02ef676b8cede4213b2bddd42626b3d428403849188f95576fc9f03e43ebd73a29bf61d33a581be9a510b13b7f7f100d5 + checksum: 10c0/debce6f0f7dd9af69b4bb9e467ea1ccccff2d849b6020461a2b9741c0c137340e6076c245dc2e83880180eb2e82936280fa31dfe8608e5a2e3618f3d864314c5 languageName: node linkType: hard @@ -5357,10 +5432,10 @@ __metadata: version: 5.2.1 resolution: "postcss-minify-selectors@npm:5.2.1" dependencies: - postcss-selector-parser: ^6.0.5 + postcss-selector-parser: "npm:^6.0.5" peerDependencies: postcss: ^8.2.15 - checksum: 6fdbc84f99a60d56b43df8930707da397775e4c36062a106aea2fd2ac81b5e24e584a1892f4baa4469fa495cb87d1422560eaa8f6c9d500f9f0b691a5f95bab5 + checksum: 10c0/f3f4ec110f5f697cfc9dde3e491ff10aa07509bf33cc940aa539e4b5b643d1b9f8bb97f8bb83d05fc96f5eeb220500ebdeffbde513bd176c0671e21c2c96fab9 languageName: node linkType: hard @@ -5369,31 +5444,31 @@ __metadata: resolution: "postcss-modules-extract-imports@npm:3.0.0" peerDependencies: postcss: ^8.1.0 - checksum: 4b65f2f1382d89c4bc3c0a1bdc5942f52f3cb19c110c57bd591ffab3a5fee03fcf831604168205b0c1b631a3dce2255c70b61aaae3ef39d69cd7eb450c2552d2 + checksum: 10c0/f8879d66d8162fb7a3fcd916d37574006c584ea509107b1cfb798a5e090175ef9470f601e46f0a305070d8ff2500e07489a5c1ac381c29a1dc1120e827ca7943 languageName: node linkType: hard "postcss-modules-local-by-default@npm:^4.0.0": - version: 4.0.0 - resolution: "postcss-modules-local-by-default@npm:4.0.0" + version: 4.0.4 + resolution: "postcss-modules-local-by-default@npm:4.0.4" dependencies: - icss-utils: ^5.0.0 - postcss-selector-parser: ^6.0.2 - postcss-value-parser: ^4.1.0 + icss-utils: "npm:^5.0.0" + postcss-selector-parser: "npm:^6.0.2" + postcss-value-parser: "npm:^4.1.0" peerDependencies: postcss: ^8.1.0 - checksum: 6cf570badc7bc26c265e073f3ff9596b69bb954bc6ac9c5c1b8cba2995b80834226b60e0a3cbb87d5f399dbb52e6466bba8aa1d244f6218f99d834aec431a69d + checksum: 10c0/9ebf464867eb10b29b73501b1466dcac8352ed852ef68ec23571f515daa74401d7ace9a6c72f354542081fdbb47d098c9bc6b05373b553a6e35779d072f967bb languageName: node linkType: hard "postcss-modules-scope@npm:^3.0.0": - version: 3.0.0 - resolution: "postcss-modules-scope@npm:3.0.0" + version: 3.1.1 + resolution: "postcss-modules-scope@npm:3.1.1" dependencies: - postcss-selector-parser: ^6.0.4 + postcss-selector-parser: "npm:^6.0.4" peerDependencies: postcss: ^8.1.0 - checksum: 330b9398dbd44c992c92b0dc612c0626135e2cc840fee41841eb61247a6cfed95af2bd6f67ead9dd9d0bb41f5b0367129d93c6e434fa3e9c58ade391d9a5a138 + checksum: 10c0/3ef6ac14fcda1581bc43e37622256bd87b99ea49c59b2aae648d057d57f5ecc634648cce9910166220a797567af674bc09246ccc010f1dd58d2863b805719109 languageName: node linkType: hard @@ -5401,10 +5476,10 @@ __metadata: version: 4.0.0 resolution: "postcss-modules-values@npm:4.0.0" dependencies: - icss-utils: ^5.0.0 + icss-utils: "npm:^5.0.0" peerDependencies: postcss: ^8.1.0 - checksum: f7f2cdf14a575b60e919ad5ea52fed48da46fe80db2733318d71d523fc87db66c835814940d7d05b5746b0426e44661c707f09bdb83592c16aea06e859409db6 + checksum: 10c0/dd18d7631b5619fb9921b198c86847a2a075f32e0c162e0428d2647685e318c487a2566cc8cc669fc2077ef38115cde7a068e321f46fb38be3ad49646b639dbc languageName: node linkType: hard @@ -5413,7 +5488,7 @@ __metadata: resolution: "postcss-normalize-charset@npm:5.1.0" peerDependencies: postcss: ^8.2.15 - checksum: e79d92971fc05b8b3c9b72f3535a574e077d13c69bef68156a0965f397fdf157de670da72b797f57b0e3bac8f38155b5dd1735ecab143b9cc4032d72138193b4 + checksum: 10c0/aa481584d4db48e0dbf820f992fa235e6c41ff3d4701a62d349f33c1ad4c5c7dcdea3096db9ff2a5c9497e9bed2186d594ccdb1b42d57b30f58affba5829ad9c languageName: node linkType: hard @@ -5421,10 +5496,10 @@ __metadata: version: 5.1.0 resolution: "postcss-normalize-display-values@npm:5.1.0" dependencies: - postcss-value-parser: ^4.2.0 + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: b6eb7b9b02c3bdd62bbc54e01e2b59733d73a1c156905d238e178762962efe0c6f5104544da39f32cade8a4fb40f10ff54b63a8ebfbdff51e8780afb9fbdcf86 + checksum: 10c0/70b164fda885c097c02c98914fba4cd19b2382ff5f85f77e5315d88a1d477b4803f0f271d95a38e044e2a6c3b781c5c9bfb83222fc577199f2aeb0b8f4254e2f languageName: node linkType: hard @@ -5432,10 +5507,10 @@ __metadata: version: 5.1.1 resolution: "postcss-normalize-positions@npm:5.1.1" dependencies: - postcss-value-parser: ^4.2.0 + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: d9afc233729c496463c7b1cdd06732469f401deb387484c3a2422125b46ec10b4af794c101f8c023af56f01970b72b535e88373b9058ecccbbf88db81662b3c4 + checksum: 10c0/910d58991fd38a7cf6ed6471e6fa4a96349690ad1a99a02e8cac46d76ba5045f2fca453088b68b05ff665afd96dc617c4674c68acaeabbe83f502e4963fb78b1 languageName: node linkType: hard @@ -5443,10 +5518,10 @@ __metadata: version: 5.1.1 resolution: "postcss-normalize-repeat-style@npm:5.1.1" dependencies: - postcss-value-parser: ^4.2.0 + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: 2c6ad2b0ae10a1fda156b948c34f78c8f1e185513593de4d7e2480973586675520edfec427645fa168c337b0a6b3ceca26f92b96149741ca98a9806dad30d534 + checksum: 10c0/57c3817a2107ebb17e4ceee3831d230c72a3ccc7650f4d5f12aa54f6ea766777401f4f63b2615b721350b2e8c7ae0b0bbc3f1c5ad4e7fa737c9efb92cfa0cbb0 languageName: node linkType: hard @@ -5454,10 +5529,10 @@ __metadata: version: 5.1.0 resolution: "postcss-normalize-string@npm:5.1.0" dependencies: - postcss-value-parser: ^4.2.0 + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: 6e549c6e5b2831e34c7bdd46d8419e2278f6af1d5eef6d26884a37c162844e60339340c57e5e06058cdbe32f27fc6258eef233e811ed2f71168ef2229c236ada + checksum: 10c0/a5e9979998f478d385ddff865bdd8a4870af69fa8c91c9398572a299ff39b39a6bda922a48fab0d2cddc639f30159c39baaed880ed7d13cd27cc64eaa9400b3b languageName: node linkType: hard @@ -5465,10 +5540,10 @@ __metadata: version: 5.1.0 resolution: "postcss-normalize-timing-functions@npm:5.1.0" dependencies: - postcss-value-parser: ^4.2.0 + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: da550f50e90b0b23e17b67449a7d1efd1aa68288e66d4aa7614ca6f5cc012896be1972b7168eee673d27da36504faccf7b9f835c0f7e81243f966a42c8c030aa + checksum: 10c0/afb34d8e313004ae8cd92910bf1a6eb9885f29ae803cd9032b6dfe7b67a9ad93f800976f10e55170b2b08fe9484825e9272629971186812c2764c73843268237 languageName: node linkType: hard @@ -5476,11 +5551,11 @@ __metadata: version: 5.1.1 resolution: "postcss-normalize-unicode@npm:5.1.1" dependencies: - browserslist: ^4.21.4 - postcss-value-parser: ^4.2.0 + browserslist: "npm:^4.21.4" + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: 4c24d26cc9f4b19a9397db4e71dd600dab690f1de8e14a3809e2aa1452dbc3791c208c38a6316bbc142f29e934fdf02858e68c94038c06174d78a4937e0f273c + checksum: 10c0/c102888d488d05c53ab10ffcd4e0efb892ef0cc2f9b0abe9c9b175a2d7a9c226981ca6806ed9e5c1b82a8190f2b3a8342a6de800f019b417130661b0787ff6d7 languageName: node linkType: hard @@ -5488,11 +5563,11 @@ __metadata: version: 5.1.0 resolution: "postcss-normalize-url@npm:5.1.0" dependencies: - normalize-url: ^6.0.1 - postcss-value-parser: ^4.2.0 + normalize-url: "npm:^6.0.1" + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: 3bd4b3246d6600230bc827d1760b24cb3101827ec97570e3016cbe04dc0dd28f4dbe763245d1b9d476e182c843008fbea80823061f1d2219b96f0d5c724a24c0 + checksum: 10c0/a016cefd1ef80f74ef9dbed50593d3b533101e93aaadfc292896fddd8d6c3eb732a9fc5cb2e0d27f79c1f60f0fdfc40b045a494b514451e9610c6acf9392eb98 languageName: node linkType: hard @@ -5500,10 +5575,10 @@ __metadata: version: 5.1.1 resolution: "postcss-normalize-whitespace@npm:5.1.1" dependencies: - postcss-value-parser: ^4.2.0 + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: 12d8fb6d1c1cba208cc08c1830959b7d7ad447c3f5581873f7e185f99a9a4230c43d3af21ca12c818e4690a5085a95b01635b762ad4a7bef69d642609b4c0e19 + checksum: 10c0/d7b53dd90fe369bfb9838a40096db904a41f50dadfd04247ec07d7ab5588c3d4e70d1c7f930523bd061cb74e6683cef45c6e6c4eb57ea174ee3fc99f3de222d1 languageName: node linkType: hard @@ -5511,23 +5586,23 @@ __metadata: version: 5.1.3 resolution: "postcss-ordered-values@npm:5.1.3" dependencies: - cssnano-utils: ^3.1.0 - postcss-value-parser: ^4.2.0 + cssnano-utils: "npm:^3.1.0" + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: 6f3ca85b6ceffc68aadaf319d9ee4c5ac16d93195bf8cba2d1559b631555ad61941461cda6d3909faab86e52389846b2b36345cff8f0c3f4eb345b1b8efadcf9 + checksum: 10c0/55abfbd2c7267eefed62a881ed0b5c0c98409c50a589526a3ebb9f8d879979203e523b8888fa84732bdd1ac887f721287a037002fa70c27c8d33f1bcbae9d9c6 languageName: node linkType: hard -"postcss-reduce-initial@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-reduce-initial@npm:5.1.1" +"postcss-reduce-initial@npm:^5.1.2": + version: 5.1.2 + resolution: "postcss-reduce-initial@npm:5.1.2" dependencies: - browserslist: ^4.21.4 - caniuse-api: ^3.0.0 + browserslist: "npm:^4.21.4" + caniuse-api: "npm:^3.0.0" peerDependencies: postcss: ^8.2.15 - checksum: 1b704aba8c38103cbb5a75c6201dbf58ec2f3a978013c7f7e8957fd3bf3282f992050dec5a01bc050d031bad836e187dd6622b922ca78ab92bcd0afd21fb0b98 + checksum: 10c0/ddb2ce61c8d0997184f08200eafdf32b3c67e88228fee960f5e2010c32da0c1d8ea07712585bf2b3aaa15f583066401d45db2c1131527c5116ca6794ebebd865 languageName: node linkType: hard @@ -5535,20 +5610,20 @@ __metadata: version: 5.1.0 resolution: "postcss-reduce-transforms@npm:5.1.0" dependencies: - postcss-value-parser: ^4.2.0 + postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.15 - checksum: 0c6af2cba20e3ff63eb9ad045e634ddfb9c3e5c0e614c020db2a02f3aa20632318c4ede9e0c995f9225d9a101e673de91c0a6e10bb2fa5da6d6c75d15a55882f + checksum: 10c0/caefaeb78652ad8701b94e91500e38551255e4899fa298a7357519a36cbeebae088eab4535e00f17675a1230f448c4a7077045639d496da4614a46bc41df4add languageName: node linkType: hard "postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9": - version: 6.0.11 - resolution: "postcss-selector-parser@npm:6.0.11" + version: 6.0.15 + resolution: "postcss-selector-parser@npm:6.0.15" dependencies: - cssesc: ^3.0.0 - util-deprecate: ^1.0.2 - checksum: 0b01aa9c2d2c8dbeb51e9b204796b678284be9823abc8d6d40a8b16d4149514e922c264a8ed4deb4d6dbced564b9be390f5942c058582d8656351516d6c49cde + cssesc: "npm:^3.0.0" + util-deprecate: "npm:^1.0.2" + checksum: 10c0/48b425d6cef497bcf6b7d136f6fd95cfca43026955e07ec9290d3c15457de3a862dbf251dd36f42c07a0d5b5ab6f31e41acefeff02528995a989b955505e440b languageName: node linkType: hard @@ -5556,11 +5631,11 @@ __metadata: version: 5.1.0 resolution: "postcss-svgo@npm:5.1.0" dependencies: - postcss-value-parser: ^4.2.0 - svgo: ^2.7.0 + postcss-value-parser: "npm:^4.2.0" + svgo: "npm:^2.7.0" peerDependencies: postcss: ^8.2.15 - checksum: d86eb5213d9f700cf5efe3073799b485fb7cacae0c731db3d7749c9c2b1c9bc85e95e0baeca439d699ff32ea24815fc916c4071b08f67ed8219df229ce1129bd + checksum: 10c0/309634a587e38fef244648bc9cd1817e12144868d24f1173d87b1edc14a4a7fca614962b2cb9d93f4801e11bd8d676083986ad40ebab4438cb84731ce1571994 languageName: node linkType: hard @@ -5568,42 +5643,35 @@ __metadata: version: 5.1.1 resolution: "postcss-unique-selectors@npm:5.1.1" dependencies: - postcss-selector-parser: ^6.0.5 + postcss-selector-parser: "npm:^6.0.5" peerDependencies: postcss: ^8.2.15 - checksum: 637e7b786e8558265775c30400c54b6b3b24d4748923f4a39f16a65fd0e394f564ccc9f0a1d3c0e770618a7637a7502ea1d0d79f731d429cb202255253c23278 + checksum: 10c0/484f6409346d6244c134c5cdcd62f4f2751b269742f95222f13d8bac5fb224471ffe04e28a354670cbe0bdc2707778ead034fc1b801b473ffcbea5436807de30 languageName: node linkType: hard "postcss-value-parser@npm:^4.1.0, postcss-value-parser@npm:^4.2.0": version: 4.2.0 resolution: "postcss-value-parser@npm:4.2.0" - checksum: 819ffab0c9d51cf0acbabf8996dffbfafbafa57afc0e4c98db88b67f2094cb44488758f06e5da95d7036f19556a4a732525e84289a425f4f6fd8e412a9d7442f + checksum: 10c0/f4142a4f56565f77c1831168e04e3effd9ffcc5aebaf0f538eee4b2d465adfd4b85a44257bb48418202a63806a7da7fe9f56c330aebb3cac898e46b4cbf49161 languageName: node linkType: hard -"postcss@npm:^8.4.21, postcss@npm:^8.4.5": - version: 8.4.21 - resolution: "postcss@npm:8.4.21" +"postcss@npm:^8, postcss@npm:^8.4.35, postcss@npm:^8.4.5": + version: 8.4.35 + resolution: "postcss@npm:8.4.35" dependencies: - nanoid: ^3.3.4 - picocolors: ^1.0.0 - source-map-js: ^1.0.2 - checksum: e39ac60ccd1542d4f9d93d894048aac0d686b3bb38e927d8386005718e6793dbbb46930f0a523fe382f1bbd843c6d980aaea791252bf5e176180e5a4336d9679 + nanoid: "npm:^3.3.7" + picocolors: "npm:^1.0.0" + source-map-js: "npm:^1.0.2" + checksum: 10c0/e8dd04e48001eb5857abc9475365bf08f4e508ddf9bc0b8525449a95d190f10d025acebc5b56ac2e94b3c7146790e4ae78989bb9633cb7ee20d1cc9b7dc909b2 languageName: node linkType: hard "prelude-ls@npm:^1.2.1": version: 1.2.1 resolution: "prelude-ls@npm:1.2.1" - checksum: cd192ec0d0a8e4c6da3bb80e4f62afe336df3f76271ac6deb0e6a36187133b6073a19e9727a1ff108cd8b9982e4768850d413baa71214dd80c7979617dca827a - languageName: node - linkType: hard - -"prelude-ls@npm:~1.1.2": - version: 1.1.2 - resolution: "prelude-ls@npm:1.1.2" - checksum: c4867c87488e4a0c233e158e4d0d5565b609b105d75e4c05dc760840475f06b731332eb93cc8c9cecb840aa8ec323ca3c9a56ad7820ad2e63f0261dadcb154e4 + checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd languageName: node linkType: hard @@ -5611,35 +5679,35 @@ __metadata: version: 1.0.0 resolution: "prettier-linter-helpers@npm:1.0.0" dependencies: - fast-diff: ^1.1.2 - checksum: 00ce8011cf6430158d27f9c92cfea0a7699405633f7f1d4a45f07e21bf78e99895911cbcdc3853db3a824201a7c745bd49bfea8abd5fb9883e765a90f74f8392 + fast-diff: "npm:^1.1.2" + checksum: 10c0/81e0027d731b7b3697ccd2129470ed9913ecb111e4ec175a12f0fcfab0096516373bf0af2fef132af50cafb0a905b74ff57996d615f59512bb9ac7378fcc64ab languageName: node linkType: hard "prettier@npm:^2.6.0": - version: 2.8.3 - resolution: "prettier@npm:2.8.3" + version: 2.8.8 + resolution: "prettier@npm:2.8.8" bin: prettier: bin-prettier.js - checksum: 92f2ceb522d454370e02082aa74ad27388672f7cee8975028b59517c069fe643bdc73e322675c8faf2ff173d7a626d1a6389f26b474000308e793aa25fff46e5 + checksum: 10c0/463ea8f9a0946cd5b828d8cf27bd8b567345cf02f56562d5ecde198b91f47a76b7ac9eae0facd247ace70e927143af6135e8cf411986b8cb8478784a4d6d724a languageName: node linkType: hard -"pretty-format@npm:^29.5.0": - version: 29.6.3 - resolution: "pretty-format@npm:29.6.3" +"pretty-format@npm:^29.7.0": + version: 29.7.0 + resolution: "pretty-format@npm:29.7.0" dependencies: - "@jest/schemas": ^29.6.3 - ansi-styles: ^5.0.0 - react-is: ^18.0.0 - checksum: 4e1c0db48e65571c22e80ff92123925ff8b3a2a89b71c3a1683cfde711004d492de32fe60c6bc10eea8bf6c678e5cbe544ac6c56cb8096e1eb7caf856928b1c4 + "@jest/schemas": "npm:^29.6.3" + ansi-styles: "npm:^5.0.0" + react-is: "npm:^18.0.0" + checksum: 10c0/edc5ff89f51916f036c62ed433506b55446ff739358de77207e63e88a28ca2894caac6e73dcb68166a606e51c8087d32d400473e6a9fdd2dbe743f46c9c0276f languageName: node linkType: hard -"promise-inflight@npm:^1.0.1": - version: 1.0.1 - resolution: "promise-inflight@npm:1.0.1" - checksum: 22749483091d2c594261517f4f80e05226d4d5ecc1fc917e1886929da56e22b5718b7f2a75f3807e7a7d471bc3be2907fe92e6e8f373ddf5c64bae35b5af3981 +"proc-log@npm:^3.0.0": + version: 3.0.0 + resolution: "proc-log@npm:3.0.0" + checksum: 10c0/f66430e4ff947dbb996058f6fd22de2c66612ae1a89b097744e17fb18a4e8e7a86db99eda52ccf15e53f00b63f4ec0b0911581ff2aac0355b625c8eac509b0dc languageName: node linkType: hard @@ -5647,9 +5715,9 @@ __metadata: version: 2.0.1 resolution: "promise-retry@npm:2.0.1" dependencies: - err-code: ^2.0.2 - retry: ^0.12.0 - checksum: f96a3f6d90b92b568a26f71e966cbbc0f63ab85ea6ff6c81284dc869b41510e6cdef99b6b65f9030f0db422bf7c96652a3fff9f2e8fb4a0f069d8f4430359429 + err-code: "npm:^2.0.2" + retry: "npm:^0.12.0" + checksum: 10c0/9c7045a1a2928094b5b9b15336dcd2a7b1c052f674550df63cc3f36cd44028e5080448175b6f6ca32b642de81150f5e7b1a98b728f15cb069f2dd60ac2616b96 languageName: node linkType: hard @@ -5658,21 +5726,21 @@ __metadata: resolution: "propagating-hammerjs@npm:2.0.1" peerDependencies: "@egjs/hammerjs": ^2.0.17 - checksum: 7177010beae4536c681f0d44c5f7208fb46d4c90cd79f18d7e96e2b4e0f2a3386b79b291e74813a3ccc155ad5dd40bf87796ec63efda84f4e6bdd82007f4270a + checksum: 10c0/c708d4fc2e11ddcc59c4d84dcb5bebc27093cbb7cab63a328b1486599be3b57a061cf58baf1f375decb62d6479589dcc5af260ee2695bcddee84785cad8eabca languageName: node linkType: hard "psl@npm:^1.1.33": version: 1.9.0 resolution: "psl@npm:1.9.0" - checksum: 20c4277f640c93d393130673f392618e9a8044c6c7bf61c53917a0fddb4952790f5f362c6c730a9c32b124813e173733f9895add8d26f566ed0ea0654b2e711d + checksum: 10c0/6a3f805fdab9442f44de4ba23880c4eba26b20c8e8e0830eff1cb31007f6825dace61d17203c58bfe36946842140c97a1ba7f67bc63ca2d88a7ee052b65d97ab languageName: node linkType: hard "punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.0": - version: 2.3.0 - resolution: "punycode@npm:2.3.0" - checksum: 39f760e09a2a3bbfe8f5287cf733ecdad69d6af2fe6f97ca95f24b8921858b91e9ea3c9eeec6e08cede96181b3bb33f95c6ffd8c77e63986508aa2e8159fa200 + version: 2.3.1 + resolution: "punycode@npm:2.3.1" + checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 languageName: node linkType: hard @@ -5680,32 +5748,32 @@ __metadata: version: 7.1.3 resolution: "query-string@npm:7.1.3" dependencies: - decode-uri-component: ^0.2.2 - filter-obj: ^1.1.0 - split-on-first: ^1.0.0 - strict-uri-encode: ^2.0.0 - checksum: 91af02dcd9cc9227a052841d5c2eecb80a0d6489d05625df506a097ef1c59037cfb5e907f39b84643cbfd535c955abec3e553d0130a7b510120c37d06e0f4346 + decode-uri-component: "npm:^0.2.2" + filter-obj: "npm:^1.1.0" + split-on-first: "npm:^1.0.0" + strict-uri-encode: "npm:^2.0.0" + checksum: 10c0/a896c08e9e0d4f8ffd89a572d11f668c8d0f7df9c27c6f49b92ab31366d3ba0e9c331b9a620ee747893436cd1f2f821a6327e2bc9776bde2402ac6c270b801b2 languageName: node linkType: hard "querystringify@npm:^2.1.1": version: 2.2.0 resolution: "querystringify@npm:2.2.0" - checksum: 5641ea231bad7ef6d64d9998faca95611ed4b11c2591a8cae741e178a974f6a8e0ebde008475259abe1621cb15e692404e6b6626e927f7b849d5c09392604b15 + checksum: 10c0/3258bc3dbdf322ff2663619afe5947c7926a6ef5fb78ad7d384602974c467fadfc8272af44f5eb8cddd0d011aae8fabf3a929a8eee4b86edcc0a21e6bd10f9aa languageName: node linkType: hard "queue-microtask@npm:^1.2.2": version: 1.2.3 resolution: "queue-microtask@npm:1.2.3" - checksum: b676f8c040cdc5b12723ad2f91414d267605b26419d5c821ff03befa817ddd10e238d22b25d604920340fd73efd8ba795465a0377c4adf45a4a41e4234e42dc4 + checksum: 10c0/900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102 languageName: node linkType: hard "quick-lru@npm:^6.1.0": - version: 6.1.1 - resolution: "quick-lru@npm:6.1.1" - checksum: a9c75bf1d208c1d207590e10403a75d037f9faf7857f2e0d38c294d92b40d8b400776bcb5d4dd516baa84e6f5e3baf2a16cf405e6fedc18107922f46aeae83ee + version: 6.1.2 + resolution: "quick-lru@npm:6.1.2" + checksum: 10c0/f499f07bd276eec460c4d7d2ee286c519f3bd189cbbb5ddf3eb929e2182e4997f66b951ea8d24b3f3cee8ed5ac9f0006bf40636f082acd1b38c050a4cbf07ed3 languageName: node linkType: hard @@ -5713,26 +5781,15 @@ __metadata: version: 2.1.0 resolution: "randombytes@npm:2.1.0" dependencies: - safe-buffer: ^5.1.0 - checksum: d779499376bd4cbb435ef3ab9a957006c8682f343f14089ed5f27764e4645114196e75b7f6abf1cbd84fd247c0cb0651698444df8c9bf30e62120fbbc52269d6 + safe-buffer: "npm:^5.1.0" + checksum: 10c0/50395efda7a8c94f5dffab564f9ff89736064d32addf0cc7e8bf5e4166f09f8ded7a0849ca6c2d2a59478f7d90f78f20d8048bca3cdf8be09d8e8a10790388f3 languageName: node linkType: hard "react-is@npm:^18.0.0": version: 18.2.0 resolution: "react-is@npm:18.2.0" - checksum: e72d0ba81b5922759e4aff17e0252bd29988f9642ed817f56b25a3e217e13eea8a7f2322af99a06edb779da12d5d636e9fda473d620df9a3da0df2a74141d53e - languageName: node - linkType: hard - -"readable-stream@npm:^3.6.0": - version: 3.6.0 - resolution: "readable-stream@npm:3.6.0" - dependencies: - inherits: ^2.0.3 - string_decoder: ^1.1.1 - util-deprecate: ^1.0.1 - checksum: d4ea81502d3799439bb955a3a5d1d808592cf3133350ed352aeaa499647858b27b1c4013984900238b0873ec8d0d8defce72469fb7a83e61d53f5ad61cb80dc8 + checksum: 10c0/6eb5e4b28028c23e2bfcf73371e72cd4162e4ac7ab445ddae2afe24e347a37d6dc22fae6e1748632cd43c6d4f9b8f86dcf26bf9275e1874f436d129952528ae0 languageName: node linkType: hard @@ -5740,87 +5797,88 @@ __metadata: version: 3.6.0 resolution: "readdirp@npm:3.6.0" dependencies: - picomatch: ^2.2.1 - checksum: 1ced032e6e45670b6d7352d71d21ce7edf7b9b928494dcaba6f11fba63180d9da6cd7061ebc34175ffda6ff529f481818c962952004d273178acd70f7059b320 + picomatch: "npm:^2.2.1" + checksum: 10c0/6fa848cf63d1b82ab4e985f4cf72bd55b7dcfd8e0a376905804e48c3634b7e749170940ba77b32804d5fe93b3cc521aa95a8d7e7d725f830da6d93f3669ce66b languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.4.3": - version: 1.4.3 - resolution: "regexp.prototype.flags@npm:1.4.3" +"regenerator-runtime@npm:^0.14.0": + version: 0.14.1 + resolution: "regenerator-runtime@npm:0.14.1" + checksum: 10c0/1b16eb2c4bceb1665c89de70dcb64126a22bc8eb958feef3cd68fe11ac6d2a4899b5cd1b80b0774c7c03591dc57d16631a7f69d2daa2ec98100e2f29f7ec4cc4 + languageName: node + linkType: hard + +"regexp.prototype.flags@npm:^1.5.2": + version: 1.5.2 + resolution: "regexp.prototype.flags@npm:1.5.2" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.3 - functions-have-names: ^1.2.2 - checksum: 51228bae732592adb3ededd5e15426be25f289e9c4ef15212f4da73f4ec3919b6140806374b8894036a86020d054a8d2657d3fee6bb9b4d35d8939c20030b7a6 - languageName: node - linkType: hard - -"regexpp@npm:^3.2.0": - version: 3.2.0 - resolution: "regexpp@npm:3.2.0" - checksum: a78dc5c7158ad9ddcfe01aa9144f46e192ddbfa7b263895a70a5c6c73edd9ce85faf7c0430e59ac38839e1734e275b9c3de5c57ee3ab6edc0e0b1bdebefccef8 + call-bind: "npm:^1.0.6" + define-properties: "npm:^1.2.1" + es-errors: "npm:^1.3.0" + set-function-name: "npm:^2.0.1" + checksum: 10c0/0f3fc4f580d9c349f8b560b012725eb9c002f36daa0041b3fbf6f4238cb05932191a4d7d5db3b5e2caa336d5150ad0402ed2be81f711f9308fe7e1a9bf9bd552 languageName: node linkType: hard "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" - checksum: fb47e70bf0001fdeabdc0429d431863e9475e7e43ea5f94ad86503d918423c1543361cc5166d713eaa7029dd7a3d34775af04764bebff99ef413111a5af18c80 + checksum: 10c0/83aa76a7bc1531f68d92c75a2ca2f54f1b01463cb566cf3fbc787d0de8be30c9dbc211d1d46be3497dac5785fe296f2dd11d531945ac29730643357978966e99 languageName: node linkType: hard "requires-port@npm:^1.0.0": version: 1.0.0 resolution: "requires-port@npm:1.0.0" - checksum: eee0e303adffb69be55d1a214e415cf42b7441ae858c76dfc5353148644f6fd6e698926fc4643f510d5c126d12a705e7c8ed7e38061113bdf37547ab356797ff + checksum: 10c0/b2bfdd09db16c082c4326e573a82c0771daaf7b53b9ce8ad60ea46aa6e30aaf475fe9b164800b89f93b748d2c234d8abff945d2551ba47bf5698e04cd7713267 languageName: node linkType: hard "resolve-from@npm:^4.0.0": version: 4.0.0 resolution: "resolve-from@npm:4.0.0" - checksum: f4ba0b8494846a5066328ad33ef8ac173801a51739eb4d63408c847da9a2e1c1de1e6cbbf72699211f3d13f8fc1325648b169bd15eb7da35688e30a5fb0e4a7f + checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190 languageName: node linkType: hard -"resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.21.0, resolve@npm:^1.22.1": - version: 1.22.1 - resolution: "resolve@npm:1.22.1" +"resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.21.0, resolve@npm:^1.22.4": + version: 1.22.8 + resolution: "resolve@npm:1.22.8" dependencies: - is-core-module: ^2.9.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 + is-core-module: "npm:^2.13.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 07af5fc1e81aa1d866cbc9e9460fbb67318a10fa3c4deadc35c3ad8a898ee9a71a86a65e4755ac3195e0ea0cfbe201eb323ebe655ce90526fd61917313a34e4e + checksum: 10c0/07e179f4375e1fd072cfb72ad66d78547f86e6196c4014b31cb0b8bb1db5f7ca871f922d08da0fbc05b94e9fd42206f819648fa3b5b873ebbc8e1dc68fec433a languageName: node linkType: hard -"resolve@patch:resolve@^1.17.0#~builtin, resolve@patch:resolve@^1.19.0#~builtin, resolve@patch:resolve@^1.21.0#~builtin, resolve@patch:resolve@^1.22.1#~builtin": - version: 1.22.1 - resolution: "resolve@patch:resolve@npm%3A1.22.1#~builtin::version=1.22.1&hash=c3c19d" +"resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.21.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": + version: 1.22.8 + resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: - is-core-module: ^2.9.0 - path-parse: ^1.0.7 - supports-preserve-symlinks-flag: ^1.0.0 + is-core-module: "npm:^2.13.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 5656f4d0bedcf8eb52685c1abdf8fbe73a1603bb1160a24d716e27a57f6cecbe2432ff9c89c2bd57542c3a7b9d14b1882b73bfe2e9d7849c9a4c0b8b39f02b8b + checksum: 10c0/0446f024439cd2e50c6c8fa8ba77eaa8370b4180f401a96abf3d1ebc770ac51c1955e12764cde449fde3fff480a61f84388e3505ecdbab778f4bef5f8212c729 languageName: node linkType: hard "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" - checksum: 623bd7d2e5119467ba66202d733ec3c2e2e26568074923bc0585b6b99db14f357e79bdedb63cab56cec47491c4a0da7e6021a7465ca6dc4f481d3898fdd3158c + checksum: 10c0/59933e8501727ba13ad73ef4a04d5280b3717fd650408460c987392efe9d7be2040778ed8ebe933c5cbd63da3dcc37919c141ef8af0a54a6e4fca5a2af177bfe languageName: node linkType: hard "reusify@npm:^1.0.4": version: 1.0.4 resolution: "reusify@npm:1.0.4" - checksum: c3076ebcc22a6bc252cb0b9c77561795256c22b757f40c0d8110b1300723f15ec0fc8685e8d4ea6d7666f36c79ccc793b1939c748bf36f18f542744a4e379fcc + checksum: 10c0/c19ef26e4e188f408922c46f7ff480d38e8dfc55d448310dfb518736b23ed2c4f547fb64a6ed5bdba92cd7e7ddc889d36ff78f794816d5e71498d645ef476107 languageName: node linkType: hard @@ -5828,10 +5886,10 @@ __metadata: version: 3.0.2 resolution: "rimraf@npm:3.0.2" dependencies: - glob: ^7.1.3 + glob: "npm:^7.1.3" bin: rimraf: bin.js - checksum: 87f4164e396f0171b0a3386cc1877a817f572148ee13a7e113b238e48e8a9f2f31d009a92ec38a591ff1567d9662c6b67fd8818a2dbbaed74bc26a87a2a4a9a0 + checksum: 10c0/9cb7757acb489bd83757ba1a274ab545eafd75598a9d817e0c3f8b164238dd90eba50d6b848bd4dcc5f3040912e882dc7ba71653e35af660d77b25c381d402e8 languageName: node linkType: hard @@ -5839,18 +5897,18 @@ __metadata: version: 1.0.0 resolution: "rollup-plugin-git-info@npm:1.0.0" dependencies: - "@rollup/plugin-json": ^4.1.0 - checksum: b54133235f102fa392edfaae2da2c4568cd6c8ac59dfd0cdf5b003f6af0ce0dc423b3f4686ac671d1302af80bc752df04d10c76152a76b9e25b1d58f1c337751 + "@rollup/plugin-json": "npm:^4.1.0" + checksum: 10c0/d0d6d20d47da9abf6452a76932066d2fb831a33a1f5618f7bc876ad1a290abdcfe5065c761a256f13c433fd98bc6264cfb096cad08d348684399521f6d637724 languageName: node linkType: hard "rollup-plugin-serve@npm:^2.0.1": - version: 2.0.2 - resolution: "rollup-plugin-serve@npm:2.0.2" + version: 2.0.3 + resolution: "rollup-plugin-serve@npm:2.0.3" dependencies: - mime: ">=2.4.6" - opener: 1 - checksum: de74616bc197360d282cabb26aa2f77780b4864364f62562d1d6cb3fd3ba74f956e1ce1bd881edf122e11e234b96132857a760e0668f22aebbd54a0fc55d1bec + mime: "npm:^3" + opener: "npm:1" + checksum: 10c0/a130760039296c07926ae66552defad6fcefd2da95ed29ba0b468b3356c9323c0015d212c79f8892ae571a9f63904da7615bc51b7b50db51e6d64aba62722b9f languageName: node linkType: hard @@ -5858,27 +5916,27 @@ __metadata: version: 4.0.0 resolution: "rollup-plugin-styles@npm:4.0.0" dependencies: - "@rollup/pluginutils": ^4.1.2 - "@types/cssnano": ^5.0.0 - cosmiconfig: ^7.0.1 - cssnano: ^5.0.15 - fs-extra: ^10.0.0 - icss-utils: ^5.1.0 - mime-types: ^2.1.34 - p-queue: ^6.6.2 - postcss: ^8.4.5 - postcss-modules-extract-imports: ^3.0.0 - postcss-modules-local-by-default: ^4.0.0 - postcss-modules-scope: ^3.0.0 - postcss-modules-values: ^4.0.0 - postcss-value-parser: ^4.2.0 - query-string: ^7.1.0 - resolve: ^1.21.0 - source-map-js: ^1.0.1 - tslib: ^2.3.1 + "@rollup/pluginutils": "npm:^4.1.2" + "@types/cssnano": "npm:^5.0.0" + cosmiconfig: "npm:^7.0.1" + cssnano: "npm:^5.0.15" + fs-extra: "npm:^10.0.0" + icss-utils: "npm:^5.1.0" + mime-types: "npm:^2.1.34" + p-queue: "npm:^6.6.2" + postcss: "npm:^8.4.5" + postcss-modules-extract-imports: "npm:^3.0.0" + postcss-modules-local-by-default: "npm:^4.0.0" + postcss-modules-scope: "npm:^3.0.0" + postcss-modules-values: "npm:^4.0.0" + postcss-value-parser: "npm:^4.2.0" + query-string: "npm:^7.1.0" + resolve: "npm:^1.21.0" + source-map-js: "npm:^1.0.1" + tslib: "npm:^2.3.1" peerDependencies: rollup: ^2.63.0 - checksum: 857e5fd6820aedf2f751878d2ef4fa40210094fb548d1baaa1dafbcdd7f7ea9775bac1c899b305bd27a23026d0694940651692a39901ac2ba2f8ce9f2bd10eb1 + checksum: 10c0/dc9a15918ffa48d271fdaec921c71ec200b340b5ae986a0ea48227cd4e8cea0a9dd2316cc6ae22bb20ddddcee445c03a268e86d00d6b3658d36aeaf5b0e8b9bd languageName: node linkType: hard @@ -5886,13 +5944,13 @@ __metadata: version: 7.0.2 resolution: "rollup-plugin-terser@npm:7.0.2" dependencies: - "@babel/code-frame": ^7.10.4 - jest-worker: ^26.2.1 - serialize-javascript: ^4.0.0 - terser: ^5.0.0 + "@babel/code-frame": "npm:^7.10.4" + jest-worker: "npm:^26.2.1" + serialize-javascript: "npm:^4.0.0" + terser: "npm:^5.0.0" peerDependencies: rollup: ^2.0.0 - checksum: af84bb7a7a894cd00852b6486528dfb8653cf94df4c126f95f389a346f401d054b08c46bee519a2ab6a22b33804d1d6ac6d8c90b1b2bf8fffb097eed73fc3c72 + checksum: 10c0/f79b851c6f7b06555d3a8ce7a4e32abd2b7cb8318e89fb8db73e662fa6e3af1a59920e881d111efc65a7437fd9582b61b1f4859b6fd839ba948616829d92432d languageName: node linkType: hard @@ -5900,33 +5958,33 @@ __metadata: version: 0.33.0 resolution: "rollup-plugin-typescript2@npm:0.33.0" dependencies: - "@rollup/pluginutils": ^4.1.2 - find-cache-dir: ^3.3.2 - fs-extra: ^10.0.0 - tslib: ^2.4.0 + "@rollup/pluginutils": "npm:^4.1.2" + find-cache-dir: "npm:^3.3.2" + fs-extra: "npm:^10.0.0" + tslib: "npm:^2.4.0" peerDependencies: rollup: ">=1.26.3" typescript: ">=2.4.0" - checksum: 03e3077c5197f512222f11ebb8b7682c97ddbd6332189ea06884aa3e778a04107483d340f3be94dbc471595e8908687dd841b81976855485486097b6bb095f65 + checksum: 10c0/20cf7b9557245f6c540e496052656bc0a6e24aebdc27ba83b471545fe3f5bd1c35b69459fdeadde2d59dfe45cb9f18c15d228e11e1a577491bb5d01e357b81fa languageName: node linkType: hard "rollup-plugin-visualizer@npm:^5.8.2": - version: 5.9.0 - resolution: "rollup-plugin-visualizer@npm:5.9.0" + version: 5.12.0 + resolution: "rollup-plugin-visualizer@npm:5.12.0" dependencies: - open: ^8.4.0 - picomatch: ^2.3.1 - source-map: ^0.7.4 - yargs: ^17.5.1 + open: "npm:^8.4.0" + picomatch: "npm:^2.3.1" + source-map: "npm:^0.7.4" + yargs: "npm:^17.5.1" peerDependencies: - rollup: 2.x || 3.x + rollup: 2.x || 3.x || 4.x peerDependenciesMeta: rollup: optional: true bin: rollup-plugin-visualizer: dist/bin/cli.js - checksum: 362d4fac0295c14bd205dbc85c20c31f4b6c47604868da21d9565ed47e0333759f08b9fe0acb82f78221f5173ea01e4eb70d47351eb6012216afe71b5492ed5f + checksum: 10c0/0e44a641223377ebb472bb10f2b22efa773b5f6fbe8d54f197f07c68d7a432cbf00abad79a0aa1570f70c673c792f24700d926d663ed9a4d0ad8406ae5a0f4e4 languageName: node linkType: hard @@ -5934,34 +5992,74 @@ __metadata: version: 2.79.1 resolution: "rollup@npm:2.79.1" dependencies: - fsevents: ~2.3.2 + fsevents: "npm:~2.3.2" dependenciesMeta: fsevents: optional: true bin: rollup: dist/bin/rollup - checksum: 6a2bf167b3587d4df709b37d149ad0300692cc5deb510f89ac7bdc77c8738c9546ae3de9322b0968e1ed2b0e984571f5f55aae28fa7de4cfcb1bc5402a4e2be6 + checksum: 10c0/421418687f5dcd7324f4387f203c6bfc7118b7ace789e30f5da022471c43e037a76f5fd93837052754eeeae798a4fb266ac05ccee1e594406d912a59af98dde9 languageName: node linkType: hard -"rollup@npm:^3.18.0": - version: 3.20.2 - resolution: "rollup@npm:3.20.2" +"rollup@npm:^4.2.0": + version: 4.12.0 + resolution: "rollup@npm:4.12.0" dependencies: - fsevents: ~2.3.2 + "@rollup/rollup-android-arm-eabi": "npm:4.12.0" + "@rollup/rollup-android-arm64": "npm:4.12.0" + "@rollup/rollup-darwin-arm64": "npm:4.12.0" + "@rollup/rollup-darwin-x64": "npm:4.12.0" + "@rollup/rollup-linux-arm-gnueabihf": "npm:4.12.0" + "@rollup/rollup-linux-arm64-gnu": "npm:4.12.0" + "@rollup/rollup-linux-arm64-musl": "npm:4.12.0" + "@rollup/rollup-linux-riscv64-gnu": "npm:4.12.0" + "@rollup/rollup-linux-x64-gnu": "npm:4.12.0" + "@rollup/rollup-linux-x64-musl": "npm:4.12.0" + "@rollup/rollup-win32-arm64-msvc": "npm:4.12.0" + "@rollup/rollup-win32-ia32-msvc": "npm:4.12.0" + "@rollup/rollup-win32-x64-msvc": "npm:4.12.0" + "@types/estree": "npm:1.0.5" + fsevents: "npm:~2.3.2" dependenciesMeta: + "@rollup/rollup-android-arm-eabi": + optional: true + "@rollup/rollup-android-arm64": + optional: true + "@rollup/rollup-darwin-arm64": + optional: true + "@rollup/rollup-darwin-x64": + optional: true + "@rollup/rollup-linux-arm-gnueabihf": + optional: true + "@rollup/rollup-linux-arm64-gnu": + optional: true + "@rollup/rollup-linux-arm64-musl": + optional: true + "@rollup/rollup-linux-riscv64-gnu": + optional: true + "@rollup/rollup-linux-x64-gnu": + optional: true + "@rollup/rollup-linux-x64-musl": + optional: true + "@rollup/rollup-win32-arm64-msvc": + optional: true + "@rollup/rollup-win32-ia32-msvc": + optional: true + "@rollup/rollup-win32-x64-msvc": + optional: true fsevents: optional: true bin: rollup: dist/bin/rollup - checksum: 34b0932839b7c2a5d1742fb21ce95a47e0b49a0849f4abee2dccf25833187aa7babb898ca90d4fc761cffa4102b9ed0ac6ad7f6f6b96c8b8e2d67305abc5da65 + checksum: 10c0/1650168231ae8e2bd6fb4d82cc232e53b5c0fe67895188fa683370c9bd3f1febaa28e45c6b100cea333e54f8f5fae6f4d0eea7d86256ec2cc3e38212c55796d6 languageName: node linkType: hard "rrweb-cssom@npm:^0.6.0": version: 0.6.0 resolution: "rrweb-cssom@npm:0.6.0" - checksum: 182312f6e4f41d18230ccc34f14263bc8e8a6b9d30ee3ec0d2d8e643c6f27964cd7a8d638d4a00e988d93e8dc55369f4ab5a473ccfeff7a8bab95b36d2b5499c + checksum: 10c0/3d9d90d53c2349ea9c8509c2690df5a4ef930c9cf8242aeb9425d4046f09d712bb01047e00da0e1c1dab5db35740b3d78fd45c3e7272f75d3724a563f27c30a3 languageName: node linkType: hard @@ -5969,46 +6067,58 @@ __metadata: version: 1.2.0 resolution: "run-parallel@npm:1.2.0" dependencies: - queue-microtask: ^1.2.2 - checksum: cb4f97ad25a75ebc11a8ef4e33bb962f8af8516bb2001082ceabd8902e15b98f4b84b4f8a9b222e5d57fc3bd1379c483886ed4619367a7680dad65316993021d + queue-microtask: "npm:^1.2.2" + checksum: 10c0/200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39 languageName: node linkType: hard -"safe-buffer@npm:^5.1.0, safe-buffer@npm:~5.2.0": +"safe-array-concat@npm:^1.1.0": + version: 1.1.0 + resolution: "safe-array-concat@npm:1.1.0" + dependencies: + call-bind: "npm:^1.0.5" + get-intrinsic: "npm:^1.2.2" + has-symbols: "npm:^1.0.3" + isarray: "npm:^2.0.5" + checksum: 10c0/833d3d950fc7507a60075f9bfaf41ec6dac7c50c7a9d62b1e6b071ecc162185881f92e594ff95c1a18301c881352dd6fd236d56999d5819559db7b92da9c28af + languageName: node + linkType: hard + +"safe-buffer@npm:^5.1.0": version: 5.2.1 resolution: "safe-buffer@npm:5.2.1" - checksum: b99c4b41fdd67a6aaf280fcd05e9ffb0813654894223afb78a31f14a19ad220bba8aba1cb14eddce1fcfb037155fe6de4e861784eb434f7d11ed58d1e70dd491 + checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3 languageName: node linkType: hard -"safe-regex-test@npm:^1.0.0": - version: 1.0.0 - resolution: "safe-regex-test@npm:1.0.0" +"safe-regex-test@npm:^1.0.3": + version: 1.0.3 + resolution: "safe-regex-test@npm:1.0.3" dependencies: - call-bind: ^1.0.2 - get-intrinsic: ^1.1.3 - is-regex: ^1.1.4 - checksum: bc566d8beb8b43c01b94e67de3f070fd2781685e835959bbbaaec91cc53381145ca91f69bd837ce6ec244817afa0a5e974fc4e40a2957f0aca68ac3add1ddd34 + call-bind: "npm:^1.0.6" + es-errors: "npm:^1.3.0" + is-regex: "npm:^1.1.4" + checksum: 10c0/900bf7c98dc58f08d8523b7012b468e4eb757afa624f198902c0643d7008ba777b0bdc35810ba0b758671ce887617295fb742b3f3968991b178ceca54cb07603 languageName: node linkType: hard "safer-buffer@npm:>= 2.1.2 < 3.0.0": version: 2.1.2 resolution: "safer-buffer@npm:2.1.2" - checksum: cab8f25ae6f1434abee8d80023d7e72b598cf1327164ddab31003c51215526801e40b66c5e65d658a0af1e9d6478cadcb4c745f4bd6751f97d8644786c0978b0 + checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 languageName: node linkType: hard "sass@npm:^1.54.9": - version: 1.58.0 - resolution: "sass@npm:1.58.0" + version: 1.71.1 + resolution: "sass@npm:1.71.1" dependencies: - chokidar: ">=3.0.0 <4.0.0" - immutable: ^4.0.0 - source-map-js: ">=0.6.2 <2.0.0" + chokidar: "npm:>=3.0.0 <4.0.0" + immutable: "npm:^4.0.0" + source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: a7219634881d2de6441fb619787fb1a02e3fa0333fb715be26aa335ba49d6bdb4f1105d9df70a80a67200893022b08346745783dc49046095d94fc6e044492d6 + checksum: 10c0/59d79a6e106747746792b0c71908ae0aecdaf9b794d5724ee64e5249412f0d8ebe7ee2bf12946618848f14f949c4f6b530d82da3e62ab31c71198c6f73002130 languageName: node linkType: hard @@ -6016,55 +6126,35 @@ __metadata: version: 6.0.0 resolution: "saxes@npm:6.0.0" dependencies: - xmlchars: ^2.2.0 - checksum: d3fa3e2aaf6c65ed52ee993aff1891fc47d5e47d515164b5449cbf5da2cbdc396137e55590472e64c5c436c14ae64a8a03c29b9e7389fc6f14035cf4e982ef3b + xmlchars: "npm:^2.2.0" + checksum: 10c0/3847b839f060ef3476eb8623d099aa502ad658f5c40fd60c105ebce86d244389b0d76fcae30f4d0c728d7705ceb2f7e9b34bb54717b6a7dbedaf5dad2d9a4b74 languageName: node linkType: hard "screenfull@npm:^6.0.2": version: 6.0.2 resolution: "screenfull@npm:6.0.2" - checksum: 56a541da09241ae7c97115cc31245623c09230bcbebb93636871e955b545f26c7dcdb2299795234a0a21bff5d5401b7329b22609becf4c381a9e22347acf87ba + checksum: 10c0/e4accdb10410aa506dc10b3aa55b05f96421da8559ca3594c44e2cb80174d3a01819ea2b0e815797e24843844599f27778daa69d53bdb007f6bbd77c94e50d0d languageName: node linkType: hard -"semver@npm:^6.0.0, semver@npm:^6.3.0": - version: 6.3.0 - resolution: "semver@npm:6.3.0" - bin: - semver: ./bin/semver.js - checksum: 1b26ecf6db9e8292dd90df4e781d91875c0dcc1b1909e70f5d12959a23c7eebb8f01ea581c00783bbee72ceeaad9505797c381756326073850dc36ed284b21b9 - languageName: node - linkType: hard - -"semver@npm:^6.3.1": +"semver@npm:^6.0.0, semver@npm:^6.3.0, semver@npm:^6.3.1": version: 6.3.1 resolution: "semver@npm:6.3.1" bin: semver: bin/semver.js - checksum: ae47d06de28836adb9d3e25f22a92943477371292d9b665fb023fae278d345d508ca1958232af086d85e0155aee22e313e100971898bbb8d5d89b8b1d4054ca2 + checksum: 10c0/e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d languageName: node linkType: hard -"semver@npm:^7.3.5, semver@npm:^7.3.7": - version: 7.3.8 - resolution: "semver@npm:7.3.8" +"semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.3, semver@npm:^7.5.4": + version: 7.6.0 + resolution: "semver@npm:7.6.0" dependencies: - lru-cache: ^6.0.0 + lru-cache: "npm:^6.0.0" bin: semver: bin/semver.js - checksum: ba9c7cbbf2b7884696523450a61fee1a09930d888b7a8d7579025ad93d459b2d1949ee5bbfeb188b2be5f4ac163544c5e98491ad6152df34154feebc2cc337c1 - languageName: node - linkType: hard - -"semver@npm:^7.5.3, semver@npm:^7.5.4": - version: 7.5.4 - resolution: "semver@npm:7.5.4" - dependencies: - lru-cache: ^6.0.0 - bin: - semver: bin/semver.js - checksum: 12d8ad952fa353b0995bf180cdac205a4068b759a140e5d3c608317098b3575ac2f1e09182206bf2eb26120e1c0ed8fb92c48c592f6099680de56bb071423ca3 + checksum: 10c0/fbfe717094ace0aa8d6332d7ef5ce727259815bd8d8815700853f4faf23aacbd7192522f0dc5af6df52ef4fa85a355ebd2f5d39f554bd028200d6cf481ab9b53 languageName: node linkType: hard @@ -6072,15 +6162,34 @@ __metadata: version: 4.0.0 resolution: "serialize-javascript@npm:4.0.0" dependencies: - randombytes: ^2.1.0 - checksum: 3273b3394b951671fcf388726e9577021870dfbf85e742a1183fb2e91273e6101bdccea81ff230724f6659a7ee4cef924b0ff9baca32b79d9384ec37caf07302 + randombytes: "npm:^2.1.0" + checksum: 10c0/510dfe7f0311c0b2f7ab06311afa1668ba2969ab2f1faaac0a4924ede76b7f22ba85cfdeaa0052ec5a047bca42c8cd8ac8df8f0efe52f9bd290b3a39ae69fe9d languageName: node linkType: hard -"set-blocking@npm:^2.0.0": - version: 2.0.0 - resolution: "set-blocking@npm:2.0.0" - checksum: 6e65a05f7cf7ebdf8b7c75b101e18c0b7e3dff4940d480efed8aad3a36a4005140b660fa1d804cb8bce911cac290441dc728084a30504d3516ac2ff7ad607b02 +"set-function-length@npm:^1.2.1": + version: 1.2.1 + resolution: "set-function-length@npm:1.2.1" + dependencies: + define-data-property: "npm:^1.1.2" + es-errors: "npm:^1.3.0" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.3" + gopd: "npm:^1.0.1" + has-property-descriptors: "npm:^1.0.1" + checksum: 10c0/1927e296599f2c04d210c1911f1600430a5e49e04a6d8bb03dca5487b95a574da9968813a2ced9a774bd3e188d4a6208352c8f64b8d4674cdb021dca21e190ca + languageName: node + linkType: hard + +"set-function-name@npm:^2.0.1": + version: 2.0.2 + resolution: "set-function-name@npm:2.0.2" + dependencies: + define-data-property: "npm:^1.1.4" + es-errors: "npm:^1.3.0" + functions-have-names: "npm:^1.2.3" + has-property-descriptors: "npm:^1.0.2" + checksum: 10c0/fce59f90696c450a8523e754abb305e2b8c73586452619c2bad5f7bf38c7b6b4651895c9db895679c5bef9554339cf3ef1c329b66ece3eda7255785fbe299316 languageName: node linkType: hard @@ -6088,89 +6197,90 @@ __metadata: version: 2.0.0 resolution: "shebang-command@npm:2.0.0" dependencies: - shebang-regex: ^3.0.0 - checksum: 6b52fe87271c12968f6a054e60f6bde5f0f3d2db483a1e5c3e12d657c488a15474121a1d55cd958f6df026a54374ec38a4a963988c213b7570e1d51575cea7fa + shebang-regex: "npm:^3.0.0" + checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e languageName: node linkType: hard "shebang-regex@npm:^3.0.0": version: 3.0.0 resolution: "shebang-regex@npm:3.0.0" - checksum: 1a2bcae50de99034fcd92ad4212d8e01eedf52c7ec7830eedcf886622804fe36884278f2be8be0ea5fde3fd1c23911643a4e0f726c8685b61871c8908af01222 + checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 languageName: node linkType: hard "side-channel@npm:^1.0.4": - version: 1.0.4 - resolution: "side-channel@npm:1.0.4" + version: 1.0.6 + resolution: "side-channel@npm:1.0.6" dependencies: - call-bind: ^1.0.0 - get-intrinsic: ^1.0.2 - object-inspect: ^1.9.0 - checksum: 351e41b947079c10bd0858364f32bb3a7379514c399edb64ab3dce683933483fc63fb5e4efe0a15a2e8a7e3c436b6a91736ddb8d8c6591b0460a24bb4a1ee245 + call-bind: "npm:^1.0.7" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.4" + object-inspect: "npm:^1.13.1" + checksum: 10c0/d2afd163dc733cc0a39aa6f7e39bf0c436293510dbccbff446733daeaf295857dbccf94297092ec8c53e2503acac30f0b78830876f0485991d62a90e9cad305f languageName: node linkType: hard "side-drawer@npm:^3.1.0": version: 3.1.0 resolution: "side-drawer@npm:3.1.0" - checksum: aa6825741986bc67bac74729f377889f71af96769c4d28cc4f566a1caca828fee61d9b6c79a599914f160af3532942906ff740b385ef95535b45a596a402063e + checksum: 10c0/337e67929c6af45d27f0e2d89cb1b12553d262b5445e1d009f0b798c8bcee5c9373e53787cca9c481cc5da9ce9f67d381a7ebbd34ee23c74e9efc83b7ae85c82 languageName: node linkType: hard "siginfo@npm:^2.0.0": version: 2.0.0 resolution: "siginfo@npm:2.0.0" - checksum: 8aa5a98640ca09fe00d74416eca97551b3e42991614a3d1b824b115fc1401543650914f651ab1311518177e4d297e80b953f4cd4cd7ea1eabe824e8f2091de01 + checksum: 10c0/3def8f8e516fbb34cb6ae415b07ccc5d9c018d85b4b8611e3dc6f8be6d1899f693a4382913c9ed51a06babb5201639d76453ab297d1c54a456544acf5c892e34 languageName: node linkType: hard -"signal-exit@npm:^3.0.7": - version: 3.0.7 - resolution: "signal-exit@npm:3.0.7" - checksum: a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 +"signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": + version: 4.1.0 + resolution: "signal-exit@npm:4.1.0" + checksum: 10c0/41602dce540e46d599edba9d9860193398d135f7ff72cab629db5171516cfae628d21e7bfccde1bbfdf11c48726bc2a6d1a8fb8701125852fbfda7cf19c6aa83 languageName: node linkType: hard "slash@npm:^3.0.0": version: 3.0.0 resolution: "slash@npm:3.0.0" - checksum: 94a93fff615f25a999ad4b83c9d5e257a7280c90a32a7cb8b4a87996e4babf322e469c42b7f649fd5796edd8687652f3fb452a86dc97a816f01113183393f11c + checksum: 10c0/e18488c6a42bdfd4ac5be85b2ced3ccd0224773baae6ad42cfbb9ec74fc07f9fa8396bd35ee638084ead7a2a0818eb5e7151111544d4731ce843019dab4be47b languageName: node linkType: hard "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" - checksum: b5167a7142c1da704c0e3af85c402002b597081dd9575031a90b4f229ca5678e9a36e8a374f1814c8156a725d17008ae3bde63b92f9cfd132526379e580bec8b + checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 languageName: node linkType: hard -"socks-proxy-agent@npm:^7.0.0": - version: 7.0.0 - resolution: "socks-proxy-agent@npm:7.0.0" +"socks-proxy-agent@npm:^8.0.1": + version: 8.0.2 + resolution: "socks-proxy-agent@npm:8.0.2" dependencies: - agent-base: ^6.0.2 - debug: ^4.3.3 - socks: ^2.6.2 - checksum: 720554370154cbc979e2e9ce6a6ec6ced205d02757d8f5d93fe95adae454fc187a5cbfc6b022afab850a5ce9b4c7d73e0f98e381879cf45f66317a4895953846 + agent-base: "npm:^7.0.2" + debug: "npm:^4.3.4" + socks: "npm:^2.7.1" + checksum: 10c0/a842402fc9b8848a31367f2811ca3cd14c4106588b39a0901cd7a69029998adfc6456b0203617c18ed090542ad0c24ee4e9d4c75a0c4b75071e214227c177eb7 languageName: node linkType: hard -"socks@npm:^2.6.2": - version: 2.7.1 - resolution: "socks@npm:2.7.1" +"socks@npm:^2.7.1": + version: 2.8.1 + resolution: "socks@npm:2.8.1" dependencies: - ip: ^2.0.0 - smart-buffer: ^4.2.0 - checksum: 259d9e3e8e1c9809a7f5c32238c3d4d2a36b39b83851d0f573bfde5f21c4b1288417ce1af06af1452569cd1eb0841169afd4998f0e04ba04656f6b7f0e46d748 + ip-address: "npm:^9.0.5" + smart-buffer: "npm:^4.2.0" + checksum: 10c0/ac77b515c260473cc7c4452f09b20939e22510ce3ae48385c516d1d5784374d5cc75be3cb18ff66cc985a7f4f2ef8fef84e984c5ec70aad58355ed59241f40a8 languageName: node linkType: hard "source-map-js@npm:>=0.6.2 <2.0.0, source-map-js@npm:^1.0.1, source-map-js@npm:^1.0.2": version: 1.0.2 resolution: "source-map-js@npm:1.0.2" - checksum: c049a7fc4deb9a7e9b481ae3d424cc793cb4845daa690bc5a05d428bf41bf231ced49b4cf0c9e77f9d42fdb3d20d6187619fc586605f5eabe995a316da8d377c + checksum: 10c0/32f2dfd1e9b7168f9a9715eb1b4e21905850f3b50cf02cf476e47e4eebe8e6b762b63a64357896aa29b37e24922b4282df0f492e0d2ace572b43d15525976ff8 languageName: node linkType: hard @@ -6178,148 +6288,184 @@ __metadata: version: 0.5.21 resolution: "source-map-support@npm:0.5.21" dependencies: - buffer-from: ^1.0.0 - source-map: ^0.6.0 - checksum: 43e98d700d79af1d36f859bdb7318e601dfc918c7ba2e98456118ebc4c4872b327773e5a1df09b0524e9e5063bb18f0934538eace60cca2710d1fa687645d137 + buffer-from: "npm:^1.0.0" + source-map: "npm:^0.6.0" + checksum: 10c0/9ee09942f415e0f721d6daad3917ec1516af746a8120bba7bb56278707a37f1eb8642bde456e98454b8a885023af81a16e646869975f06afc1a711fb90484e7d languageName: node linkType: hard "source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.1": version: 0.6.1 resolution: "source-map@npm:0.6.1" - checksum: 59ce8640cf3f3124f64ac289012c2b8bd377c238e316fb323ea22fbfe83da07d81e000071d7242cad7a23cd91c7de98e4df8830ec3f133cb6133a5f6e9f67bc2 + checksum: 10c0/ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011 languageName: node linkType: hard "source-map@npm:^0.7.4": version: 0.7.4 resolution: "source-map@npm:0.7.4" - checksum: 01cc5a74b1f0e1d626a58d36ad6898ea820567e87f18dfc9d24a9843a351aaa2ec09b87422589906d6ff1deed29693e176194dc88bcae7c9a852dc74b311dbf5 + checksum: 10c0/dc0cf3768fe23c345ea8760487f8c97ef6fca8a73c83cd7c9bf2fde8bc2c34adb9c0824d6feb14bc4f9e37fb522e18af621543f1289038a66ac7586da29aa7dc languageName: node linkType: hard "sourcemap-codec@npm:^1.4.8": version: 1.4.8 resolution: "sourcemap-codec@npm:1.4.8" - checksum: b57981c05611afef31605732b598ccf65124a9fcb03b833532659ac4d29ac0f7bfacbc0d6c5a28a03e84c7510e7e556d758d0bb57786e214660016fb94279316 + checksum: 10c0/f099279fdaae070ff156df7414bbe39aad69cdd615454947ed3e19136bfdfcb4544952685ee73f56e17038f4578091e12b17b283ed8ac013882916594d95b9e6 languageName: node linkType: hard "split-on-first@npm:^1.0.0": version: 1.1.0 resolution: "split-on-first@npm:1.1.0" - checksum: 16ff85b54ddcf17f9147210a4022529b343edbcbea4ce977c8f30e38408b8d6e0f25f92cd35b86a524d4797f455e29ab89eb8db787f3c10708e0b47ebf528d30 + checksum: 10c0/56df8344f5a5de8521898a5c090023df1d8b8c75be6228f56c52491e0fc1617a5236f2ac3a066adb67a73231eac216ccea7b5b4a2423a543c277cb2f48d24c29 languageName: node linkType: hard -"ssri@npm:^9.0.0": - version: 9.0.1 - resolution: "ssri@npm:9.0.1" +"sprintf-js@npm:^1.1.3": + version: 1.1.3 + resolution: "sprintf-js@npm:1.1.3" + checksum: 10c0/09270dc4f30d479e666aee820eacd9e464215cdff53848b443964202bf4051490538e5dd1b42e1a65cf7296916ca17640aebf63dae9812749c7542ee5f288dec + languageName: node + linkType: hard + +"ssri@npm:^10.0.0": + version: 10.0.5 + resolution: "ssri@npm:10.0.5" dependencies: - minipass: ^3.1.1 - checksum: fb58f5e46b6923ae67b87ad5ef1c5ab6d427a17db0bead84570c2df3cd50b4ceb880ebdba2d60726588272890bae842a744e1ecce5bd2a2a582fccd5068309eb + minipass: "npm:^7.0.3" + checksum: 10c0/b091f2ae92474183c7ac5ed3f9811457e1df23df7a7e70c9476eaa9a0c4a0c8fc190fb45acefbf023ca9ee864dd6754237a697dc52a0fb182afe65d8e77443d8 languageName: node linkType: hard "stable@npm:^0.1.8": version: 0.1.8 resolution: "stable@npm:0.1.8" - checksum: 2ff482bb100285d16dd75cd8f7c60ab652570e8952c0bfa91828a2b5f646a0ff533f14596ea4eabd48bb7f4aeea408dce8f8515812b975d958a4cc4fa6b9dfeb + checksum: 10c0/df74b5883075076e78f8e365e4068ecd977af6c09da510cfc3148a303d4b87bc9aa8f7c48feb67ed4ef970b6140bd9eabba2129e28024aa88df5ea0114cba39d languageName: node linkType: hard "stackback@npm:0.0.2": version: 0.0.2 resolution: "stackback@npm:0.0.2" - checksum: 2d4dc4e64e2db796de4a3c856d5943daccdfa3dd092e452a1ce059c81e9a9c29e0b9badba91b43ef0d5ff5c04ee62feb3bcc559a804e16faf447bac2d883aa99 + checksum: 10c0/89a1416668f950236dd5ac9f9a6b2588e1b9b62b1b6ad8dff1bfc5d1a15dbf0aafc9b52d2226d00c28dffff212da464eaeebfc6b7578b9d180cef3e3782c5983 languageName: node linkType: hard -"std-env@npm:^3.3.3": - version: 3.4.3 - resolution: "std-env@npm:3.4.3" - checksum: bef186fb2baddda31911234b1e58fa18f181eb6930616aaec3b54f6d5db65f2da5daaa5f3b326b98445a7d50ca81d6fe8809ab4ebab85ecbe4a802f1b40921bf +"std-env@npm:^3.5.0": + version: 3.7.0 + resolution: "std-env@npm:3.7.0" + checksum: 10c0/60edf2d130a4feb7002974af3d5a5f3343558d1ccf8d9b9934d225c638606884db4a20d2fe6440a09605bca282af6b042ae8070a10490c0800d69e82e478f41e languageName: node linkType: hard "strict-uri-encode@npm:^2.0.0": version: 2.0.0 resolution: "strict-uri-encode@npm:2.0.0" - checksum: eaac4cf978b6fbd480f1092cab8b233c9b949bcabfc9b598dd79a758f7243c28765ef7639c876fa72940dac687181b35486ea01ff7df3e65ce3848c64822c581 + checksum: 10c0/010cbc78da0e2cf833b0f5dc769e21ae74cdc5d5f5bd555f14a4a4876c8ad2c85ab8b5bdf9a722dc71a11dcd3184085e1c3c0bd50ec6bb85fffc0f28cf82597d languageName: node linkType: hard -"string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: - emoji-regex: ^8.0.0 - is-fullwidth-code-point: ^3.0.0 - strip-ansi: ^6.0.1 - checksum: e52c10dc3fbfcd6c3a15f159f54a90024241d0f149cf8aed2982a2d801d2e64df0bf1dc351cf8e95c3319323f9f220c16e740b06faecd53e2462df1d2b5443fb + emoji-regex: "npm:^8.0.0" + is-fullwidth-code-point: "npm:^3.0.0" + strip-ansi: "npm:^6.0.1" + checksum: 10c0/1e525e92e5eae0afd7454086eed9c818ee84374bb80328fc41217ae72ff5f065ef1c9d7f72da41de40c75fa8bb3dee63d92373fd492c84260a552c636392a47b languageName: node linkType: hard -"string.prototype.trimend@npm:^1.0.6": - version: 1.0.6 - resolution: "string.prototype.trimend@npm:1.0.6" +"string-width@npm:^5.0.1, string-width@npm:^5.1.2": + version: 5.1.2 + resolution: "string-width@npm:5.1.2" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 0fdc34645a639bd35179b5a08227a353b88dc089adf438f46be8a7c197fc3f22f8514c1c9be4629b3cd29c281582730a8cbbad6466c60f76b5f99cf2addb132e + eastasianwidth: "npm:^0.2.0" + emoji-regex: "npm:^9.2.2" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/ab9c4264443d35b8b923cbdd513a089a60de339216d3b0ed3be3ba57d6880e1a192b70ae17225f764d7adbf5994e9bb8df253a944736c15a0240eff553c678ca languageName: node linkType: hard -"string.prototype.trimstart@npm:^1.0.6": - version: 1.0.6 - resolution: "string.prototype.trimstart@npm:1.0.6" +"string.prototype.trim@npm:^1.2.8": + version: 1.2.8 + resolution: "string.prototype.trim@npm:1.2.8" dependencies: - call-bind: ^1.0.2 - define-properties: ^1.1.4 - es-abstract: ^1.20.4 - checksum: 89080feef416621e6ef1279588994305477a7a91648d9436490d56010a1f7adc39167cddac7ce0b9884b8cdbef086987c4dcb2960209f2af8bac0d23ceff4f41 + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + checksum: 10c0/4f76c583908bcde9a71208ddff38f67f24c9ec8093631601666a0df8b52fad44dad2368c78895ce83eb2ae8e7068294cc96a02fc971ab234e4d5c9bb61ea4e34 languageName: node linkType: hard -"string_decoder@npm:^1.1.1": - version: 1.3.0 - resolution: "string_decoder@npm:1.3.0" +"string.prototype.trimend@npm:^1.0.7": + version: 1.0.7 + resolution: "string.prototype.trimend@npm:1.0.7" dependencies: - safe-buffer: ~5.2.0 - checksum: 8417646695a66e73aefc4420eb3b84cc9ffd89572861fe004e6aeb13c7bc00e2f616247505d2dbbef24247c372f70268f594af7126f43548565c68c117bdeb56 + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + checksum: 10c0/53c24911c7c4d8d65f5ef5322de23a3d5b6b4db73273e05871d5ab4571ae5638f38f7f19d71d09116578fb060e5a145cc6a208af2d248c8baf7a34f44d32ce57 languageName: node linkType: hard -"strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": +"string.prototype.trimstart@npm:^1.0.7": + version: 1.0.7 + resolution: "string.prototype.trimstart@npm:1.0.7" + dependencies: + call-bind: "npm:^1.0.2" + define-properties: "npm:^1.2.0" + es-abstract: "npm:^1.22.1" + checksum: 10c0/0bcf391b41ea16d4fda9c9953d0a7075171fe090d33b4cf64849af94944c50862995672ac03e0c5dba2940a213ad7f53515a668dac859ce22a0276289ae5cf4f + languageName: node + linkType: hard + +"strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" dependencies: - ansi-regex: ^5.0.1 - checksum: f3cd25890aef3ba6e1a74e20896c21a46f482e93df4a06567cebf2b57edabb15133f1f94e57434e0a958d61186087b1008e89c94875d019910a213181a14fc8c + ansi-regex: "npm:^5.0.1" + checksum: 10c0/1ae5f212a126fe5b167707f716942490e3933085a5ff6c008ab97ab2f272c8025d3aa218b7bd6ab25729ca20cc81cddb252102f8751e13482a5199e873680952 + languageName: node + linkType: hard + +"strip-ansi@npm:^7.0.1": + version: 7.1.0 + resolution: "strip-ansi@npm:7.1.0" + dependencies: + ansi-regex: "npm:^6.0.1" + checksum: 10c0/a198c3762e8832505328cbf9e8c8381de14a4fa50a4f9b2160138158ea88c0f5549fb50cb13c651c3088f47e63a108b34622ec18c0499b6c8c3a5ddf6b305ac4 languageName: node linkType: hard "strip-bom@npm:^3.0.0": version: 3.0.0 resolution: "strip-bom@npm:3.0.0" - checksum: 8d50ff27b7ebe5ecc78f1fe1e00fcdff7af014e73cf724b46fb81ef889eeb1015fc5184b64e81a2efe002180f3ba431bdd77e300da5c6685d702780fbf0c8d5b + checksum: 10c0/51201f50e021ef16672593d7434ca239441b7b760e905d9f33df6e4f3954ff54ec0e0a06f100d028af0982d6f25c35cd5cda2ce34eaebccd0250b8befb90d8f1 languageName: node linkType: hard -"strip-json-comments@npm:^3.1.0, strip-json-comments@npm:^3.1.1": +"strip-final-newline@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-final-newline@npm:3.0.0" + checksum: 10c0/a771a17901427bac6293fd416db7577e2bc1c34a19d38351e9d5478c3c415f523f391003b42ed475f27e33a78233035df183525395f731d3bfb8cdcbd4da08ce + languageName: node + linkType: hard + +"strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" - checksum: 492f73e27268f9b1c122733f28ecb0e7e8d8a531a6662efbd08e22cccb3f9475e90a1b82cab06a392f6afae6d2de636f977e231296400d0ec5304ba70f166443 + checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd languageName: node linkType: hard -"strip-literal@npm:^1.0.1": - version: 1.3.0 - resolution: "strip-literal@npm:1.3.0" +"strip-literal@npm:^2.0.0": + version: 2.0.0 + resolution: "strip-literal@npm:2.0.0" dependencies: - acorn: ^8.10.0 - checksum: f5fa7e289df8ebe82e90091fd393974faf8871be087ca50114327506519323cf15f2f8fee6ebe68b5e58bfc795269cae8bdc7cb5a83e27b02b3fe953f37b0a89 + js-tokens: "npm:^8.0.2" + checksum: 10c0/63a6e4224ac7088ff93fd19fc0f6882705020da2f0767dbbecb929cbf9d49022e72350420f47be635866823608da9b9a5caf34f518004721895b6031199fc3c8 languageName: node linkType: hard @@ -6327,18 +6473,18 @@ __metadata: version: 5.1.1 resolution: "stylehacks@npm:5.1.1" dependencies: - browserslist: ^4.21.4 - postcss-selector-parser: ^6.0.4 + browserslist: "npm:^4.21.4" + postcss-selector-parser: "npm:^6.0.4" peerDependencies: postcss: ^8.2.15 - checksum: 11175366ef52de65bf06cefba0ddc9db286dc3a1451fd2989e74c6ea47091a02329a4bf6ce10b1a36950056927b6bbbe47c5ab3a1f4c7032df932d010fbde5a2 + checksum: 10c0/402c2b545eeda0e972f125779adddc88df11bcf3a89de60c92026bd98cd49c1abffcd5bfe41766398835e0a1c7e5e72bdb6905809ecbb60716cd8d3a32ea7cd3 languageName: node linkType: hard "superstruct@npm:^0.15.3": version: 0.15.5 resolution: "superstruct@npm:0.15.5" - checksum: 6d1f5249fee789424b7178fa0a1ffb2ace629c5480c39505885bd8c0046a4ff8b267569a3442fa53b8c560a7ba6599cf3f8af94225aebeb2cf6023f7dd911050 + checksum: 10c0/73ae2043443dcc7868da6e8b4e4895410c79a88e021b514c665161199675ee920d5eadd85bb9dee5a9f515817e62f4b65a67ccb82d29f73259d012afcbcd3ce4 languageName: node linkType: hard @@ -6346,8 +6492,8 @@ __metadata: version: 5.5.0 resolution: "supports-color@npm:5.5.0" dependencies: - has-flag: ^3.0.0 - checksum: 95f6f4ba5afdf92f495b5a912d4abee8dcba766ae719b975c56c084f5004845f6f5a5f7769f52d53f40e21952a6d87411bafe34af4a01e65f9926002e38e1dac + has-flag: "npm:^3.0.0" + checksum: 10c0/6ae5ff319bfbb021f8a86da8ea1f8db52fac8bd4d499492e30ec17095b58af11f0c55f8577390a749b1c4dde691b6a0315dab78f5f54c9b3d83f8fb5905c1c05 languageName: node linkType: hard @@ -6355,15 +6501,15 @@ __metadata: version: 7.2.0 resolution: "supports-color@npm:7.2.0" dependencies: - has-flag: ^4.0.0 - checksum: 3dda818de06ebbe5b9653e07842d9479f3555ebc77e9a0280caf5a14fb877ffee9ed57007c3b78f5a6324b8dbeec648d9e97a24e2ed9fdb81ddc69ea07100f4a + has-flag: "npm:^4.0.0" + checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 languageName: node linkType: hard "supports-preserve-symlinks-flag@npm:^1.0.0": version: 1.0.0 resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 53b1e247e68e05db7b3808b99b892bd36fb096e6fba213a06da7fab22045e97597db425c724f2bbd6c99a3c295e1e73f3e4de78592289f38431049e1277ca0ae + checksum: 10c0/6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39 languageName: node linkType: hard @@ -6371,51 +6517,51 @@ __metadata: version: 2.8.0 resolution: "svgo@npm:2.8.0" dependencies: - "@trysound/sax": 0.2.0 - commander: ^7.2.0 - css-select: ^4.1.3 - css-tree: ^1.1.3 - csso: ^4.2.0 - picocolors: ^1.0.0 - stable: ^0.1.8 + "@trysound/sax": "npm:0.2.0" + commander: "npm:^7.2.0" + css-select: "npm:^4.1.3" + css-tree: "npm:^1.1.3" + csso: "npm:^4.2.0" + picocolors: "npm:^1.0.0" + stable: "npm:^0.1.8" bin: svgo: bin/svgo - checksum: b92f71a8541468ffd0b81b8cdb36b1e242eea320bf3c1a9b2c8809945853e9d8c80c19744267eb91cabf06ae9d5fff3592d677df85a31be4ed59ff78534fa420 + checksum: 10c0/0741f5d5cad63111a90a0ce7a1a5a9013f6d293e871b75efe39addb57f29a263e45294e485a4d2ff9cc260a5d142c8b5937b2234b4ef05efdd2706fb2d360ecc languageName: node linkType: hard "symbol-tree@npm:^3.2.4": version: 3.2.4 resolution: "symbol-tree@npm:3.2.4" - checksum: 6e8fc7e1486b8b54bea91199d9535bb72f10842e40c79e882fc94fb7b14b89866adf2fd79efa5ebb5b658bc07fb459ccce5ac0e99ef3d72f474e74aaf284029d + checksum: 10c0/dfbe201ae09ac6053d163578778c53aa860a784147ecf95705de0cd23f42c851e1be7889241495e95c37cabb058edb1052f141387bef68f705afc8f9dd358509 languageName: node linkType: hard "tar@npm:^6.1.11, tar@npm:^6.1.2": - version: 6.1.13 - resolution: "tar@npm:6.1.13" + version: 6.2.0 + resolution: "tar@npm:6.2.0" dependencies: - chownr: ^2.0.0 - fs-minipass: ^2.0.0 - minipass: ^4.0.0 - minizlib: ^2.1.1 - mkdirp: ^1.0.3 - yallist: ^4.0.0 - checksum: 8a278bed123aa9f53549b256a36b719e317c8b96fe86a63406f3c62887f78267cea9b22dc6f7007009738509800d4a4dccc444abd71d762287c90f35b002eb1c + chownr: "npm:^2.0.0" + fs-minipass: "npm:^2.0.0" + minipass: "npm:^5.0.0" + minizlib: "npm:^2.1.1" + mkdirp: "npm:^1.0.3" + yallist: "npm:^4.0.0" + checksum: 10c0/02ca064a1a6b4521fef88c07d389ac0936730091f8c02d30ea60d472e0378768e870769ab9e986d87807bfee5654359cf29ff4372746cc65e30cbddc352660d8 languageName: node linkType: hard "terser@npm:^5.0.0": - version: 5.16.3 - resolution: "terser@npm:5.16.3" + version: 5.28.1 + resolution: "terser@npm:5.28.1" dependencies: - "@jridgewell/source-map": ^0.3.2 - acorn: ^8.5.0 - commander: ^2.20.0 - source-map-support: ~0.5.20 + "@jridgewell/source-map": "npm:^0.3.3" + acorn: "npm:^8.8.2" + commander: "npm:^2.20.0" + source-map-support: "npm:~0.5.20" bin: terser: bin/terser - checksum: d3c2ac1c2723c37b698b25b68d76fd315a1277fddde113983d5783d1f2a01dd7b8ed83ba3f54e5e65f0b59dd971ed7be2fdf8d4be94ec694b2d27832d2e7561f + checksum: 10c0/e0d9a3cd260b4e35b49e828687658e36b0f50dce7cc2e18f024725846013ffa0e9eb8ac61a7a1bbf6684e6c14493ccf155a0f5937a47c746f534208f9000ac29 languageName: node linkType: hard @@ -6423,45 +6569,45 @@ __metadata: version: 6.0.0 resolution: "test-exclude@npm:6.0.0" dependencies: - "@istanbuljs/schema": ^0.1.2 - glob: ^7.1.4 - minimatch: ^3.0.4 - checksum: 3b34a3d77165a2cb82b34014b3aba93b1c4637a5011807557dc2f3da826c59975a5ccad765721c4648b39817e3472789f9b0fa98fc854c5c1c7a1e632aacdc28 + "@istanbuljs/schema": "npm:^0.1.2" + glob: "npm:^7.1.4" + minimatch: "npm:^3.0.4" + checksum: 10c0/019d33d81adff3f9f1bfcff18125fb2d3c65564f437d9be539270ee74b994986abb8260c7c2ce90e8f30162178b09dbbce33c6389273afac4f36069c48521f57 languageName: node linkType: hard "text-table@npm:^0.2.0": version: 0.2.0 resolution: "text-table@npm:0.2.0" - checksum: b6937a38c80c7f84d9c11dd75e49d5c44f71d95e810a3250bd1f1797fc7117c57698204adf676b71497acc205d769d65c16ae8fa10afad832ae1322630aef10a + checksum: 10c0/02805740c12851ea5982686810702e2f14369a5f4c5c40a836821e3eefc65ffeec3131ba324692a37608294b0fd8c1e55a2dd571ffed4909822787668ddbee5c languageName: node linkType: hard -"tinybench@npm:^2.5.0": - version: 2.5.0 - resolution: "tinybench@npm:2.5.0" - checksum: 284bb9428f197ec8b869c543181315e65e41ccfdad3c4b6c916bb1fdae1b5c6785661b0d90cf135b48d833b03cb84dc5357b2d33ec65a1f5971fae0ab2023821 +"tinybench@npm:^2.5.1": + version: 2.6.0 + resolution: "tinybench@npm:2.6.0" + checksum: 10c0/60ea35699bf8bac9bc8cf279fa5877ab5b335b4673dcd07bf0fbbab9d7953a02c0ccded374677213eaa13aa147f54eb75d3230139ddbeec3875829ebe73db310 languageName: node linkType: hard -"tinypool@npm:^0.7.0": - version: 0.7.0 - resolution: "tinypool@npm:0.7.0" - checksum: fdcccd5c750574fce51f8801a877f8284e145d12b79cd5f2d72bfbddfe20c895e915555bc848e122bb6aa968098e7ac4fe1e8e88104904d518dc01cccd18a510 +"tinypool@npm:^0.8.2": + version: 0.8.2 + resolution: "tinypool@npm:0.8.2" + checksum: 10c0/8998626614172fc37c394e9a14e701dc437727fc6525488a4d4fd42044a4b2b59d6f076d750cbf5c699f79c58dd4e40599ab09e2f1ae0df4b23516b98c9c3055 languageName: node linkType: hard -"tinyspy@npm:^2.1.1": - version: 2.1.1 - resolution: "tinyspy@npm:2.1.1" - checksum: cfe669803a7f11ca912742b84c18dcc4ceecaa7661c69bc5eb608a8a802d541c48aba220df8929f6c8cd09892ad37cb5ba5958ddbbb57940e91d04681d3cee73 +"tinyspy@npm:^2.2.0": + version: 2.2.1 + resolution: "tinyspy@npm:2.2.1" + checksum: 10c0/0b4cfd07c09871e12c592dfa7b91528124dc49a4766a0b23350638c62e6a483d5a2a667de7e6282246c0d4f09996482ddaacbd01f0c05b7ed7e0f79d32409bdc languageName: node linkType: hard "to-fast-properties@npm:^2.0.0": version: 2.0.0 resolution: "to-fast-properties@npm:2.0.0" - checksum: be2de62fe58ead94e3e592680052683b1ec986c72d589e7b21e5697f8744cdbf48c266fa72f6c15932894c10187b5f54573a3bcf7da0bfd964d5caf23d436168 + checksum: 10c0/b214d21dbfb4bce3452b6244b336806ffea9c05297148d32ebb428d5c43ce7545bdfc65a1ceb58c9ef4376a65c0cb2854d645f33961658b3e3b4f84910ddcdd7 languageName: node linkType: hard @@ -6469,20 +6615,20 @@ __metadata: version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" dependencies: - is-number: ^7.0.0 - checksum: f76fa01b3d5be85db6a2a143e24df9f60dd047d151062d0ba3df62953f2f697b16fe5dad9b0ac6191c7efc7b1d9dcaa4b768174b7b29da89d4428e64bc0a20ed + is-number: "npm:^7.0.0" + checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 languageName: node linkType: hard "tough-cookie@npm:^4.1.2": - version: 4.1.2 - resolution: "tough-cookie@npm:4.1.2" + version: 4.1.3 + resolution: "tough-cookie@npm:4.1.3" dependencies: - psl: ^1.1.33 - punycode: ^2.1.1 - universalify: ^0.2.0 - url-parse: ^1.5.3 - checksum: a7359e9a3e875121a84d6ba40cc184dec5784af84f67f3a56d1d2ae39b87c0e004e6ba7c7331f9622a7d2c88609032473488b28fe9f59a1fec115674589de39a + psl: "npm:^1.1.33" + punycode: "npm:^2.1.1" + universalify: "npm:^0.2.0" + url-parse: "npm:^1.5.3" + checksum: 10c0/4fc0433a0cba370d57c4b240f30440c848906dee3180bb6e85033143c2726d322e7e4614abb51d42d111ebec119c4876ed8d7247d4113563033eebbc1739c831 languageName: node linkType: hard @@ -6490,27 +6636,27 @@ __metadata: version: 4.1.1 resolution: "tr46@npm:4.1.1" dependencies: - punycode: ^2.3.0 - checksum: aeeb821ac2cd792e63ec84888b4fd6598ac6ed75d861579e21a5cf9d4ee78b2c6b94e7d45036f2ca2088bc85b9b46560ad23c4482979421063b24137349dbd96 + punycode: "npm:^2.3.0" + checksum: 10c0/92085dcf186f56a49ba4124a581d9ae6a5d0cd4878107c34e2e670b9ddc49da85e4950084bb3e75015195cc23f37ae1c02d45064e94dd6018f5e789aa51d93a8 languageName: node linkType: hard "true-myth@npm:^4.1.0": version: 4.1.1 resolution: "true-myth@npm:4.1.1" - checksum: 0b937bb215b78d0ccff8637ac1c49be7f08c04f32a7b755c45a1566a1d522f50b0cadac93ad869b6bea9b843f60479160d3382c2c91d2381ef3559915564ff82 + checksum: 10c0/ac83ac82f969129d5f002dcc489b86e28e59ee4149641b341b0176e9407786823c83702fe4b9ae9c0f9593f29a98c931ee175789d33e884f99c47e9c16e80adb languageName: node linkType: hard "ts-essentials@npm:^9.3.2": - version: 9.4.0 - resolution: "ts-essentials@npm:9.4.0" + version: 9.4.1 + resolution: "ts-essentials@npm:9.4.1" peerDependencies: typescript: ">=4.1.0" peerDependenciesMeta: typescript: optional: true - checksum: 50719782f9bfa31678fd1607de783a92b322ed8c26e6229bd0d1786c0649b9f1a7b9a6ac5bc60435053c4952bd3ef2356b5c930cb3a8d3519dc8f41c5576328f + checksum: 10c0/03f195f1f8935c5e72615e05d5ca160aeb987ba23e1f7ffad2dc4ac47604a6931621bf120279c3325513894a2040cee01070f4df95c1e3bac6435c25339eb519 languageName: node linkType: hard @@ -6518,9 +6664,9 @@ __metadata: version: 13.0.3 resolution: "ts-morph@npm:13.0.3" dependencies: - "@ts-morph/common": ~0.12.3 - code-block-writer: ^11.0.0 - checksum: 0983a7c4e0e1063e3900186bf2e85c5080621e31b754434136d2130a82bda6556985fdf012b766a87b9ae47d6f63732a562bb80854c34644f9352bea9a35b8ee + "@ts-morph/common": "npm:~0.12.3" + code-block-writer: "npm:^11.0.0" + checksum: 10c0/9d7fa1a29be3996b209e19d3e0c80eacd088afa76cd7c12b4b3d8a6a08d282d5f17e01cedf8bd841ad549a5df6580b876ea10597b3273e2bb49b85ffa2044d99 languageName: node linkType: hard @@ -6528,41 +6674,41 @@ __metadata: version: 0.10.3 resolution: "ts-prune@npm:0.10.3" dependencies: - commander: ^6.2.1 - cosmiconfig: ^7.0.1 - json5: ^2.1.3 - lodash: ^4.17.21 - true-myth: ^4.1.0 - ts-morph: ^13.0.1 + commander: "npm:^6.2.1" + cosmiconfig: "npm:^7.0.1" + json5: "npm:^2.1.3" + lodash: "npm:^4.17.21" + true-myth: "npm:^4.1.0" + ts-morph: "npm:^13.0.1" bin: ts-prune: lib/index.js - checksum: 2cbc4d64a2e50637d06691e7f962b913d87aba2419ba772a3a1cb6e4b7542412cd77af592ba7b376ed273f5e37d9be180613b479602b9f92693e4d72f0f5a373 + checksum: 10c0/fecb609e4c1f207a23f8d82946cd654242a818ca28d078cebf7b8408f0b20c2245e1482019745117b7ae0e015b76aaba8d7382cd5429ee9fa48829253981b448 languageName: node linkType: hard -"tsconfig-paths@npm:^3.14.1": - version: 3.14.1 - resolution: "tsconfig-paths@npm:3.14.1" +"tsconfig-paths@npm:^3.15.0": + version: 3.15.0 + resolution: "tsconfig-paths@npm:3.15.0" dependencies: - "@types/json5": ^0.0.29 - json5: ^1.0.1 - minimist: ^1.2.6 - strip-bom: ^3.0.0 - checksum: 8afa01c673ebb4782ba53d3a12df97fa837ce524f8ad38ee4e2b2fd57f5ac79abc21c574e9e9eb014d93efe7fe8214001b96233b5c6ea75bd1ea82afe17a4c6d + "@types/json5": "npm:^0.0.29" + json5: "npm:^1.0.2" + minimist: "npm:^1.2.6" + strip-bom: "npm:^3.0.0" + checksum: 10c0/5b4f301a2b7a3766a986baf8fc0e177eb80bdba6e396792ff92dc23b5bca8bb279fc96517dcaaef63a3b49bebc6c4c833653ec58155780bc906bdbcf7dda0ef5 languageName: node linkType: hard "tslib@npm:^1.8.1": version: 1.14.1 resolution: "tslib@npm:1.14.1" - checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd + checksum: 10c0/69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2 languageName: node linkType: hard "tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0": - version: 2.5.0 - resolution: "tslib@npm:2.5.0" - checksum: ae3ed5f9ce29932d049908ebfdf21b3a003a85653a9a140d614da6b767a93ef94f460e52c3d787f0e4f383546981713f165037dc2274df212ea9f8a4541004e1 + version: 2.6.2 + resolution: "tslib@npm:2.6.2" + checksum: 10c0/e03a8a4271152c8b26604ed45535954c0a45296e32445b4b87f8a5abdb2421f40b59b4ca437c4346af0f28179780d604094eb64546bee2019d903d01c6c19bdb languageName: node linkType: hard @@ -6570,10 +6716,10 @@ __metadata: version: 3.21.0 resolution: "tsutils@npm:3.21.0" dependencies: - tslib: ^1.8.1 + tslib: "npm:^1.8.1" peerDependencies: typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - checksum: 1843f4c1b2e0f975e08c4c21caa4af4f7f65a12ac1b81b3b8489366826259323feb3fc7a243123453d2d1a02314205a7634e048d4a8009921da19f99755cdc48 + checksum: 10c0/02f19e458ec78ead8fffbf711f834ad8ecd2cc6ade4ec0320790713dccc0a412b99e7fd907c4cda2a1dc602c75db6f12e0108e87a5afad4b2f9e90a24cabd5a2 languageName: node linkType: hard @@ -6581,42 +6727,74 @@ __metadata: version: 0.4.0 resolution: "type-check@npm:0.4.0" dependencies: - prelude-ls: ^1.2.1 - checksum: ec688ebfc9c45d0c30412e41ca9c0cdbd704580eb3a9ccf07b9b576094d7b86a012baebc95681999dd38f4f444afd28504cb3a89f2ef16b31d4ab61a0739025a + prelude-ls: "npm:^1.2.1" + checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58 languageName: node linkType: hard -"type-check@npm:~0.3.2": - version: 0.3.2 - resolution: "type-check@npm:0.3.2" - dependencies: - prelude-ls: ~1.1.2 - checksum: dd3b1495642731bc0e1fc40abe5e977e0263005551ac83342ecb6f4f89551d106b368ec32ad3fb2da19b3bd7b2d1f64330da2ea9176d8ddbfe389fb286eb5124 - languageName: node - linkType: hard - -"type-detect@npm:^4.0.0, type-detect@npm:^4.0.5": +"type-detect@npm:^4.0.0, type-detect@npm:^4.0.8": version: 4.0.8 resolution: "type-detect@npm:4.0.8" - checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15 + checksum: 10c0/8fb9a51d3f365a7de84ab7f73b653534b61b622aa6800aecdb0f1095a4a646d3f5eb295322127b6573db7982afcd40ab492d038cf825a42093a58b1e1353e0bd languageName: node linkType: hard "type-fest@npm:^0.20.2": version: 0.20.2 resolution: "type-fest@npm:0.20.2" - checksum: 4fb3272df21ad1c552486f8a2f8e115c09a521ad7a8db3d56d53718d0c907b62c6e9141ba5f584af3f6830d0872c521357e512381f24f7c44acae583ad517d73 + checksum: 10c0/dea9df45ea1f0aaa4e2d3bed3f9a0bfe9e5b2592bddb92eb1bf06e50bcf98dbb78189668cd8bc31a0511d3fc25539b4cd5c704497e53e93e2d40ca764b10bfc3 languageName: node linkType: hard -"typed-array-length@npm:^1.0.4": - version: 1.0.4 - resolution: "typed-array-length@npm:1.0.4" +"typed-array-buffer@npm:^1.0.2": + version: 1.0.2 + resolution: "typed-array-buffer@npm:1.0.2" dependencies: - call-bind: ^1.0.2 - for-each: ^0.3.3 - is-typed-array: ^1.1.9 - checksum: 2228febc93c7feff142b8c96a58d4a0d7623ecde6c7a24b2b98eb3170e99f7c7eff8c114f9b283085cd59dcd2bd43aadf20e25bba4b034a53c5bb292f71f8956 + call-bind: "npm:^1.0.7" + es-errors: "npm:^1.3.0" + is-typed-array: "npm:^1.1.13" + checksum: 10c0/9e043eb38e1b4df4ddf9dde1aa64919ae8bb909571c1cc4490ba777d55d23a0c74c7d73afcdd29ec98616d91bb3ae0f705fad4421ea147e1daf9528200b562da + languageName: node + linkType: hard + +"typed-array-byte-length@npm:^1.0.1": + version: 1.0.1 + resolution: "typed-array-byte-length@npm:1.0.1" + dependencies: + call-bind: "npm:^1.0.7" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-proto: "npm:^1.0.3" + is-typed-array: "npm:^1.1.13" + checksum: 10c0/fcebeffb2436c9f355e91bd19e2368273b88c11d1acc0948a2a306792f1ab672bce4cfe524ab9f51a0505c9d7cd1c98eff4235c4f6bfef6a198f6cfc4ff3d4f3 + languageName: node + linkType: hard + +"typed-array-byte-offset@npm:^1.0.2": + version: 1.0.2 + resolution: "typed-array-byte-offset@npm:1.0.2" + dependencies: + available-typed-arrays: "npm:^1.0.7" + call-bind: "npm:^1.0.7" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-proto: "npm:^1.0.3" + is-typed-array: "npm:^1.1.13" + checksum: 10c0/d2628bc739732072e39269389a758025f75339de2ed40c4f91357023c5512d237f255b633e3106c461ced41907c1bf9a533c7e8578066b0163690ca8bc61b22f + languageName: node + linkType: hard + +"typed-array-length@npm:^1.0.5": + version: 1.0.5 + resolution: "typed-array-length@npm:1.0.5" + dependencies: + call-bind: "npm:^1.0.7" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-proto: "npm:^1.0.3" + is-typed-array: "npm:^1.1.13" + possible-typed-array-names: "npm:^1.0.0" + checksum: 10c0/5cc0f79196e70a92f8f40846cfa62b3de6be51e83f73655e137116cf65e3c29a288502b18cc8faf33c943c2470a4569009e1d6da338441649a2db2f135761ad5 languageName: node linkType: hard @@ -6626,24 +6804,24 @@ __metadata: bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: ee000bc26848147ad423b581bd250075662a354d84f0e06eb76d3b892328d8d4440b7487b5a83e851b12b255f55d71835b008a66cbf8f255a11e4400159237db + checksum: 10c0/5f6cad2e728a8a063521328e612d7876e12f0d8a8390d3b3aaa452a6a65e24e9ac8ea22beb72a924fd96ea0a49ea63bb4e251fb922b12eedfb7f7a26475e5c56 languageName: node linkType: hard -"typescript@patch:typescript@^4.5.4#~builtin, typescript@patch:typescript@^4.9.5#~builtin": +"typescript@patch:typescript@npm%3A^4.5.4#optional!builtin, typescript@patch:typescript@npm%3A^4.9.5#optional!builtin": version: 4.9.5 - resolution: "typescript@patch:typescript@npm%3A4.9.5#~builtin::version=4.9.5&hash=23ec76" + resolution: "typescript@patch:typescript@npm%3A4.9.5#optional!builtin::version=4.9.5&hash=289587" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: ab417a2f398380c90a6cf5a5f74badd17866adf57f1165617d6a551f059c3ba0a3e4da0d147b3ac5681db9ac76a303c5876394b13b3de75fdd5b1eaa06181c9d + checksum: 10c0/e3333f887c6829dfe0ab6c1dbe0dd1e3e2aeb56c66460cb85c5440c566f900c833d370ca34eb47558c0c69e78ced4bfe09b8f4f98b6de7afed9b84b8d1dd06a1 languageName: node linkType: hard -"ufo@npm:^1.3.0": - version: 1.3.0 - resolution: "ufo@npm:1.3.0" - checksum: 01f0be86cd5c205ad1b49ebea985e000a4542c503ee75398302b0f5e4b9a6d9cd8e77af2dc614ab7bea08805fdfd9a85191fb3b5ee3df383cb936cf65e9db30d +"ufo@npm:^1.3.2": + version: 1.4.0 + resolution: "ufo@npm:1.4.0" + checksum: 10c0/d9a3cb8c5fd13356e0af661362244fd0a901edcdd08996f42553271007cae01e85dcec29a3303a87ddab6aa705cbd630332aaa8c268d037483536b198fa67a7c languageName: node linkType: hard @@ -6651,71 +6829,64 @@ __metadata: version: 1.0.2 resolution: "unbox-primitive@npm:1.0.2" dependencies: - call-bind: ^1.0.2 - has-bigints: ^1.0.2 - has-symbols: ^1.0.3 - which-boxed-primitive: ^1.0.2 - checksum: b7a1cf5862b5e4b5deb091672ffa579aa274f648410009c81cca63fed3b62b610c4f3b773f912ce545bb4e31edc3138975b5bc777fc6e4817dca51affb6380e9 + call-bind: "npm:^1.0.2" + has-bigints: "npm:^1.0.2" + has-symbols: "npm:^1.0.3" + which-boxed-primitive: "npm:^1.0.2" + checksum: 10c0/81ca2e81134167cc8f75fa79fbcc8a94379d6c61de67090986a2273850989dd3bae8440c163121b77434b68263e34787a675cbdcb34bb2f764c6b9c843a11b66 languageName: node linkType: hard -"unique-filename@npm:^2.0.0": - version: 2.0.1 - resolution: "unique-filename@npm:2.0.1" - dependencies: - unique-slug: ^3.0.0 - checksum: 807acf3381aff319086b64dc7125a9a37c09c44af7620bd4f7f3247fcd5565660ac12d8b80534dcbfd067e6fe88a67e621386dd796a8af828d1337a8420a255f +"undici-types@npm:~5.26.4": + version: 5.26.5 + resolution: "undici-types@npm:5.26.5" + checksum: 10c0/bb673d7876c2d411b6eb6c560e0c571eef4a01c1c19925175d16e3a30c4c428181fb8d7ae802a261f283e4166a0ac435e2f505743aa9e45d893f9a3df017b501 languageName: node linkType: hard -"unique-slug@npm:^3.0.0": +"unique-filename@npm:^3.0.0": version: 3.0.0 - resolution: "unique-slug@npm:3.0.0" + resolution: "unique-filename@npm:3.0.0" dependencies: - imurmurhash: ^0.1.4 - checksum: 49f8d915ba7f0101801b922062ee46b7953256c93ceca74303bd8e6413ae10aa7e8216556b54dc5382895e8221d04f1efaf75f945c2e4a515b4139f77aa6640c + unique-slug: "npm:^4.0.0" + checksum: 10c0/6363e40b2fa758eb5ec5e21b3c7fb83e5da8dcfbd866cc0c199d5534c42f03b9ea9ab069769cc388e1d7ab93b4eeef28ef506ab5f18d910ef29617715101884f + languageName: node + linkType: hard + +"unique-slug@npm:^4.0.0": + version: 4.0.0 + resolution: "unique-slug@npm:4.0.0" + dependencies: + imurmurhash: "npm:^0.1.4" + checksum: 10c0/cb811d9d54eb5821b81b18205750be84cb015c20a4a44280794e915f5a0a70223ce39066781a354e872df3572e8155c228f43ff0cce94c7cbf4da2cc7cbdd635 languageName: node linkType: hard "universalify@npm:^0.2.0": version: 0.2.0 resolution: "universalify@npm:0.2.0" - checksum: e86134cb12919d177c2353196a4cc09981524ee87abf621f7bc8d249dbbbebaec5e7d1314b96061497981350df786e4c5128dbf442eba104d6e765bc260678b5 + checksum: 10c0/cedbe4d4ca3967edf24c0800cfc161c5a15e240dac28e3ce575c689abc11f2c81ccc6532c8752af3b40f9120fb5e454abecd359e164f4f6aa44c29cd37e194fe languageName: node linkType: hard "universalify@npm:^2.0.0": - version: 2.0.0 - resolution: "universalify@npm:2.0.0" - checksum: 2406a4edf4a8830aa6813278bab1f953a8e40f2f63a37873ffa9a3bc8f9745d06cc8e88f3572cb899b7e509013f7f6fcc3e37e8a6d914167a5381d8440518c44 + version: 2.0.1 + resolution: "universalify@npm:2.0.1" + checksum: 10c0/73e8ee3809041ca8b818efb141801a1004e3fc0002727f1531f4de613ea281b494a40909596dae4a042a4fb6cd385af5d4db2e137b1362e0e91384b828effd3a languageName: node linkType: hard -"update-browserslist-db@npm:^1.0.10": - version: 1.0.10 - resolution: "update-browserslist-db@npm:1.0.10" +"update-browserslist-db@npm:^1.0.13": + version: 1.0.13 + resolution: "update-browserslist-db@npm:1.0.13" dependencies: - escalade: ^3.1.1 - picocolors: ^1.0.0 - peerDependencies: - browserslist: ">= 4.21.0" - bin: - browserslist-lint: cli.js - checksum: 12db73b4f63029ac407b153732e7cd69a1ea8206c9100b482b7d12859cd3cd0bc59c602d7ae31e652706189f1acb90d42c53ab24a5ba563ed13aebdddc5561a0 - languageName: node - linkType: hard - -"update-browserslist-db@npm:^1.0.11": - version: 1.0.11 - resolution: "update-browserslist-db@npm:1.0.11" - dependencies: - escalade: ^3.1.1 - picocolors: ^1.0.0 + escalade: "npm:^3.1.1" + picocolors: "npm:^1.0.0" peerDependencies: browserslist: ">= 4.21.0" bin: update-browserslist-db: cli.js - checksum: b98327518f9a345c7cad5437afae4d2ae7d865f9779554baf2a200fdf4bac4969076b679b1115434bd6557376bdd37ca7583d0f9b8f8e302d7d4cc1e91b5f231 + checksum: 10c0/e52b8b521c78ce1e0c775f356cd16a9c22c70d25f3e01180839c407a5dc787fb05a13f67560cbaf316770d26fa99f78f1acd711b1b54a4f35d4820d4ea7136e6 languageName: node linkType: hard @@ -6723,8 +6894,8 @@ __metadata: version: 4.4.1 resolution: "uri-js@npm:4.4.1" dependencies: - punycode: ^2.1.0 - checksum: 7167432de6817fe8e9e0c9684f1d2de2bb688c94388f7569f7dbdb1587c9f4ca2a77962f134ec90be0cc4d004c939ff0d05acc9f34a0db39a3c797dada262633 + punycode: "npm:^2.1.0" + checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c languageName: node linkType: hard @@ -6732,16 +6903,16 @@ __metadata: version: 1.5.10 resolution: "url-parse@npm:1.5.10" dependencies: - querystringify: ^2.1.1 - requires-port: ^1.0.0 - checksum: fbdba6b1d83336aca2216bbdc38ba658d9cfb8fc7f665eb8b17852de638ff7d1a162c198a8e4ed66001ddbf6c9888d41e4798912c62b4fd777a31657989f7bdf + querystringify: "npm:^2.1.1" + requires-port: "npm:^1.0.0" + checksum: 10c0/bd5aa9389f896974beb851c112f63b466505a04b4807cea2e5a3b7092f6fbb75316f0491ea84e44f66fed55f1b440df5195d7e3a8203f64fcefa19d182f5be87 languageName: node linkType: hard -"util-deprecate@npm:^1.0.1, util-deprecate@npm:^1.0.2": +"util-deprecate@npm:^1.0.2": version: 1.0.2 resolution: "util-deprecate@npm:1.0.2" - checksum: 474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 + checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 languageName: node linkType: hard @@ -6750,75 +6921,74 @@ __metadata: resolution: "uuid@npm:8.3.2" bin: uuid: dist/bin/uuid - checksum: 5575a8a75c13120e2f10e6ddc801b2c7ed7d8f3c8ac22c7ed0c7b2ba6383ec0abda88c905085d630e251719e0777045ae3236f04c812184b7c765f63a70e58df + checksum: 10c0/bcbb807a917d374a49f475fae2e87fdca7da5e5530820ef53f65ba1d12131bd81a92ecf259cc7ce317cbe0f289e7d79fdfebcef9bfa3087c8c8a2fa304c9be54 languageName: node linkType: hard -"vis-data@npm:^7.1.4": - version: 7.1.4 - resolution: "vis-data@npm:7.1.4" +"vis-data@npm:^7.1.9": + version: 7.1.9 + resolution: "vis-data@npm:7.1.9" peerDependencies: - uuid: ^7.0.0 || ^8.0.0 - vis-util: ^4.0.0 || ^5.0.0 - checksum: a1266eb678b7f75c422c070ebd579a99565de9b23deba2e75862afb9c15ef5fa67e34f002c8c7013751100c75d6fb76b25bdb9f1a309d9f0cda1bec0935b26ff + uuid: ^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + vis-util: ^5.0.1 + checksum: 10c0/2fce50e41862133e4fcdc92d216755b544936288a8586fc2f0afdc8b586ee75acb029e3fa9bbbb48a91e4c35ebc375bdba213e836926564f899ad80e0981d304 languageName: node linkType: hard -"vis-timeline@npm:^7.7.0": - version: 7.7.0 - resolution: "vis-timeline@npm:7.7.0" +"vis-timeline@npm:^7.7.3": + version: 7.7.3 + resolution: "vis-timeline@npm:7.7.3" peerDependencies: "@egjs/hammerjs": ^2.0.0 component-emitter: ^1.3.0 - keycharm: ^0.3.0 || ^0.4.0 + keycharm: ^0.2.0 || ^0.3.0 || ^0.4.0 moment: ^2.24.0 propagating-hammerjs: ^1.4.0 || ^2.0.0 - uuid: ^3.4.0 || ^7.0.0 || ^8.0.0 + uuid: ^3.4.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 vis-data: ^6.3.0 || ^7.0.0 - vis-util: ^3.0.0 || ^4.0.0 || ^5.0.0 + vis-util: ^5.0.1 xss: ^1.0.0 - checksum: 07d8618b7cf63ea64870c1404fb852d7b6e58df1b9fa429564225bd7a8f7f6ca047c109cee13c1501ee514abfed176699434be3f4fcf620731ca94aee525f8f8 + checksum: 10c0/82f5bdcc815e60e04562a071ef374d2e0d1d9387482faf8629471ce0de98ed75a593565af3b4db36d8c977d085b96b88afc51a967eb6f1f81031a3822d7f039d languageName: node linkType: hard "vis-util@npm:^5.0.2": - version: 5.0.3 - resolution: "vis-util@npm:5.0.3" + version: 5.0.7 + resolution: "vis-util@npm:5.0.7" peerDependencies: "@egjs/hammerjs": ^2.0.0 - component-emitter: ^1.3.0 - checksum: a6a809cca36fdebd2c9b06038c30980b21c346e10eba8b30b4cfac1495751adee8f7f5a10ca1842b352b3c1eb3051abc669dc8cf204ad391c52f8165b0ca274b + component-emitter: ^1.3.0 || ^2.0.0 + checksum: 10c0/8e460327b063335ade3a0ef9902c9fb93111036efcd13715513f075cd8972155388e84ccf1987ba8d947d671b257fb109d0cccbf0e18f061f0a303c9a46d0d92 languageName: node linkType: hard -"vite-node@npm:0.34.3": - version: 0.34.3 - resolution: "vite-node@npm:0.34.3" +"vite-node@npm:1.3.1": + version: 1.3.1 + resolution: "vite-node@npm:1.3.1" dependencies: - cac: ^6.7.14 - debug: ^4.3.4 - mlly: ^1.4.0 - pathe: ^1.1.1 - picocolors: ^1.0.0 - vite: ^3.0.0 || ^4.0.0 + cac: "npm:^6.7.14" + debug: "npm:^4.3.4" + pathe: "npm:^1.1.1" + picocolors: "npm:^1.0.0" + vite: "npm:^5.0.0" bin: vite-node: vite-node.mjs - checksum: 366c4f3fb7c038e2180abc6b18cfbac3b8684cd878eaf7ebf1ffb07d95d2ea325713fc575a7949a13bb00cfe264acbc28c02e2836b8647e1f443fe631c17805a + checksum: 10c0/b50665ef224f3527f856ab88a0cfabab36dd6e2dd1e3edca8f8f25d5d33754e1050495472c2c82147d0dcf7c5280971dae2f37a531c10f3941d8d3344e34ce0b languageName: node linkType: hard -"vite@npm:^3.0.0 || ^4.0.0": - version: 4.2.1 - resolution: "vite@npm:4.2.1" +"vite@npm:^5.0.0": + version: 5.1.4 + resolution: "vite@npm:5.1.4" dependencies: - esbuild: ^0.17.5 - fsevents: ~2.3.2 - postcss: ^8.4.21 - resolve: ^1.22.1 - rollup: ^3.18.0 + esbuild: "npm:^0.19.3" + fsevents: "npm:~2.3.3" + postcss: "npm:^8.4.35" + rollup: "npm:^4.2.0" peerDependencies: - "@types/node": ">= 14" + "@types/node": ^18.0.0 || >=20.0.0 less: "*" + lightningcss: ^1.21.0 sass: "*" stylus: "*" sugarss: "*" @@ -6831,6 +7001,8 @@ __metadata: optional: true less: optional: true + lightningcss: + optional: true sass: optional: true stylus: @@ -6841,62 +7013,58 @@ __metadata: optional: true bin: vite: bin/vite.js - checksum: 70eb162ffc299017a3c310e3adc95e9661def6b17aafd1f8e5e02e516766060435590dbe3df1e4e95acc3583c728a76e91f07c546221d1e701f1b2b021293f45 + checksum: 10c0/8f04c8bed33f266bde27f432412456a3b893b51fe1857f0b8cd259100b376c1393a7927db1dd6344a4376baed72ed179ec5b0428aef2ae8508f1f28f95acb908 languageName: node linkType: hard -"vitest-mock-extended@npm:^1.2.1": - version: 1.2.1 - resolution: "vitest-mock-extended@npm:1.2.1" +"vitest-mock-extended@npm:^1.3.1": + version: 1.3.1 + resolution: "vitest-mock-extended@npm:1.3.1" dependencies: - ts-essentials: ^9.3.2 + ts-essentials: "npm:^9.3.2" peerDependencies: typescript: 3.x || 4.x || 5.x vitest: ">=0.31.1" - checksum: d3dc3940513cc053166bc912b0b9fdda0b073c5a5d2c2deba4f87ddae7a3b8c53a31227030a9f0eeb9f48c443b6978c451946ef0d36eea6976ef77e5bb4d6c04 + checksum: 10c0/0d3b5f1b4f53d326b636931573801811a6fe5566ea8ea06a2b9e1037845b3049d045156a33b0916b3ef40b83b9076499142ac4a24490a96bbecf74b9770a780f languageName: node linkType: hard -"vitest@npm:^0.34.3": - version: 0.34.3 - resolution: "vitest@npm:0.34.3" +"vitest@npm:^1.3.1": + version: 1.3.1 + resolution: "vitest@npm:1.3.1" dependencies: - "@types/chai": ^4.3.5 - "@types/chai-subset": ^1.3.3 - "@types/node": "*" - "@vitest/expect": 0.34.3 - "@vitest/runner": 0.34.3 - "@vitest/snapshot": 0.34.3 - "@vitest/spy": 0.34.3 - "@vitest/utils": 0.34.3 - acorn: ^8.9.0 - acorn-walk: ^8.2.0 - cac: ^6.7.14 - chai: ^4.3.7 - debug: ^4.3.4 - local-pkg: ^0.4.3 - magic-string: ^0.30.1 - pathe: ^1.1.1 - picocolors: ^1.0.0 - std-env: ^3.3.3 - strip-literal: ^1.0.1 - tinybench: ^2.5.0 - tinypool: ^0.7.0 - vite: ^3.0.0 || ^4.0.0 - vite-node: 0.34.3 - why-is-node-running: ^2.2.2 + "@vitest/expect": "npm:1.3.1" + "@vitest/runner": "npm:1.3.1" + "@vitest/snapshot": "npm:1.3.1" + "@vitest/spy": "npm:1.3.1" + "@vitest/utils": "npm:1.3.1" + acorn-walk: "npm:^8.3.2" + chai: "npm:^4.3.10" + debug: "npm:^4.3.4" + execa: "npm:^8.0.1" + local-pkg: "npm:^0.5.0" + magic-string: "npm:^0.30.5" + pathe: "npm:^1.1.1" + picocolors: "npm:^1.0.0" + std-env: "npm:^3.5.0" + strip-literal: "npm:^2.0.0" + tinybench: "npm:^2.5.1" + tinypool: "npm:^0.8.2" + vite: "npm:^5.0.0" + vite-node: "npm:1.3.1" + why-is-node-running: "npm:^2.2.2" peerDependencies: "@edge-runtime/vm": "*" - "@vitest/browser": "*" - "@vitest/ui": "*" + "@types/node": ^18.0.0 || >=20.0.0 + "@vitest/browser": 1.3.1 + "@vitest/ui": 1.3.1 happy-dom: "*" jsdom: "*" - playwright: "*" - safaridriver: "*" - webdriverio: "*" peerDependenciesMeta: "@edge-runtime/vm": optional: true + "@types/node": + optional: true "@vitest/browser": optional: true "@vitest/ui": @@ -6905,15 +7073,9 @@ __metadata: optional: true jsdom: optional: true - playwright: - optional: true - safaridriver: - optional: true - webdriverio: - optional: true bin: vitest: vitest.mjs - checksum: 4535d080feede94db5015eb60c6ed5f7b0d8cd67f12072de5ae1faded133cc640043c0c2646ef51ab9b61c2f885589da57458a65e82cf91a25cf954470018a40 + checksum: 10c0/66d312a3dc12e67bba22d31332d939e89cd17d38531893c7b13b8826704564031c1dde795df2799b855660572c19a595301e920710c7775d072ee6332502efc5 languageName: node linkType: hard @@ -6921,8 +7083,8 @@ __metadata: version: 4.0.0 resolution: "w3c-xmlserializer@npm:4.0.0" dependencies: - xml-name-validator: ^4.0.0 - checksum: eba070e78deb408ae8defa4d36b429f084b2b47a4741c4a9be3f27a0a3d1845e277e3072b04391a138f7e43776842627d1334e448ff13ff90ad9fb1214ee7091 + xml-name-validator: "npm:^4.0.0" + checksum: 10c0/02cc66d6efc590bd630086cd88252444120f5feec5c4043932b0d0f74f8b060512f79dc77eb093a7ad04b4f02f39da79ce4af47ceb600f2bf9eacdc83204b1a8 languageName: node linkType: hard @@ -6930,15 +7092,15 @@ __metadata: version: 0.0.11 resolution: "web-dialog@npm:0.0.11" dependencies: - "@a11y/focus-trap": ^1.0.5 - checksum: bafe9ed971d30afb9db30ea23193ab941f236a8e8295b084b76463a4181310ccbc4c493d6317fdb2aff6dbb4d577c32f5e47f3750d2237e0396029ff47715613 + "@a11y/focus-trap": "npm:^1.0.5" + checksum: 10c0/b8c7ebe0264d6a0a5f5e02935bfb846e7275325192340f68dcb50207ea6aa559beec00ea6f757ec682d7e50675a4a352c21400e5cd1e0aebf13ccaeb76bb043a languageName: node linkType: hard "webidl-conversions@npm:^7.0.0": version: 7.0.0 resolution: "webidl-conversions@npm:7.0.0" - checksum: f05588567a2a76428515333eff87200fae6c83c3948a7482ebb109562971e77ef6dc49749afa58abb993391227c5697b3ecca52018793e0cb4620a48f10bd21b + checksum: 10c0/228d8cb6d270c23b0720cb2d95c579202db3aaf8f633b4e9dd94ec2000a04e7e6e43b76a94509cdb30479bd00ae253ab2371a2da9f81446cc313f89a4213a2c4 languageName: node linkType: hard @@ -6946,15 +7108,15 @@ __metadata: version: 2.0.0 resolution: "whatwg-encoding@npm:2.0.0" dependencies: - iconv-lite: 0.6.3 - checksum: 7087810c410aa9b689cbd6af8773341a53cdc1f3aae2a882c163bd5522ec8ca4cdfc269aef417a5792f411807d5d77d50df4c24e3abb00bb60192858a40cc675 + iconv-lite: "npm:0.6.3" + checksum: 10c0/91b90a49f312dc751496fd23a7e68981e62f33afe938b97281ad766235c4872fc4e66319f925c5e9001502b3040dd25a33b02a9c693b73a4cbbfdc4ad10c3e3e languageName: node linkType: hard "whatwg-mimetype@npm:^3.0.0": version: 3.0.0 resolution: "whatwg-mimetype@npm:3.0.0" - checksum: ce08bbb36b6aaf64f3a84da89707e3e6a31e5ab1c1a2379fd68df79ba712a4ab090904f0b50e6693b0dafc8e6343a6157e40bf18fdffd26e513cf95ee2a59824 + checksum: 10c0/323895a1cda29a5fb0b9ca82831d2c316309fede0365047c4c323073e3239067a304a09a1f4b123b9532641ab604203f33a1403b5ca6a62ef405bcd7a204080f languageName: node linkType: hard @@ -6962,16 +7124,16 @@ __metadata: version: 12.0.1 resolution: "whatwg-url@npm:12.0.1" dependencies: - tr46: ^4.1.1 - webidl-conversions: ^7.0.0 - checksum: 8698993b763c1e7eda5ed16c31dab24bca6489626aca7caf8b5a2b64684dda6578194786f10ec42ceb1c175feea16d0a915096e6419e08d154ce551c43176972 + tr46: "npm:^4.1.1" + webidl-conversions: "npm:^7.0.0" + checksum: 10c0/99f506b2c996704fa0fc5c70d8e5e27dce15492db2921c99cf319a8d56cb61641f5c06089f63e1ab1983de9fd6a63c3c112a90cdb5fe352d7a846979b10df566 languageName: node linkType: hard "wheel-gestures@npm:^2.2.5": - version: 2.2.5 - resolution: "wheel-gestures@npm:2.2.5" - checksum: d382de6d4e49ad753dfb22f49000923b30dba1b622ec80821435d1097af63cdf6a1904e2ab1963a3f580d7522d7ba6de02976233eeb99e387d9cfdbeb8a0f9bf + version: 2.2.45 + resolution: "wheel-gestures@npm:2.2.45" + checksum: 10c0/c1c5c657773ce7fcb731b85b3ecba57eafa17bee7b8627d7dedefbc7b29ea98abe66270486f439fcc03f6694478dc173d2ac63f26277ef11389e82a3bcff0f43 languageName: node linkType: hard @@ -6979,37 +7141,47 @@ __metadata: version: 1.0.2 resolution: "which-boxed-primitive@npm:1.0.2" dependencies: - is-bigint: ^1.0.1 - is-boolean-object: ^1.1.0 - is-number-object: ^1.0.4 - is-string: ^1.0.5 - is-symbol: ^1.0.3 - checksum: 53ce774c7379071729533922adcca47220228405e1895f26673bbd71bdf7fb09bee38c1d6399395927c6289476b5ae0629863427fd151491b71c4b6cb04f3a5e + is-bigint: "npm:^1.0.1" + is-boolean-object: "npm:^1.1.0" + is-number-object: "npm:^1.0.4" + is-string: "npm:^1.0.5" + is-symbol: "npm:^1.0.3" + checksum: 10c0/0a62a03c00c91dd4fb1035b2f0733c341d805753b027eebd3a304b9cb70e8ce33e25317add2fe9b5fea6f53a175c0633ae701ff812e604410ddd049777cd435e languageName: node linkType: hard -"which-typed-array@npm:^1.1.9": - version: 1.1.9 - resolution: "which-typed-array@npm:1.1.9" +"which-typed-array@npm:^1.1.14": + version: 1.1.14 + resolution: "which-typed-array@npm:1.1.14" dependencies: - available-typed-arrays: ^1.0.5 - call-bind: ^1.0.2 - for-each: ^0.3.3 - gopd: ^1.0.1 - has-tostringtag: ^1.0.0 - is-typed-array: ^1.1.10 - checksum: fe0178ca44c57699ca2c0e657b64eaa8d2db2372a4e2851184f568f98c478ae3dc3fdb5f7e46c384487046b0cf9e23241423242b277e03e8ba3dabc7c84c98ef + available-typed-arrays: "npm:^1.0.6" + call-bind: "npm:^1.0.5" + for-each: "npm:^0.3.3" + gopd: "npm:^1.0.1" + has-tostringtag: "npm:^1.0.1" + checksum: 10c0/0960f1e77807058819451b98c51d4cd72031593e8de990b24bd3fc22e176f5eee22921d68d852297c786aec117689f0423ed20aa4fde7ce2704d680677891f56 languageName: node linkType: hard -"which@npm:^2.0.1, which@npm:^2.0.2": +"which@npm:^2.0.1": version: 2.0.2 resolution: "which@npm:2.0.2" dependencies: - isexe: ^2.0.0 + isexe: "npm:^2.0.0" bin: node-which: ./bin/node-which - checksum: 1a5c563d3c1b52d5f893c8b61afe11abc3bab4afac492e8da5bde69d550de701cf9806235f20a47b5c8fa8a1d6a9135841de2596535e998027a54589000e66d1 + checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f + languageName: node + linkType: hard + +"which@npm:^4.0.0": + version: 4.0.0 + resolution: "which@npm:4.0.0" + dependencies: + isexe: "npm:^3.1.1" + bin: + node-which: bin/which.js + checksum: 10c0/449fa5c44ed120ccecfe18c433296a4978a7583bf2391c50abce13f76878d2476defde04d0f79db8165bdf432853c1f8389d0485ca6e8ebce3bbcded513d5e6a languageName: node linkType: hard @@ -7017,51 +7189,46 @@ __metadata: version: 2.2.2 resolution: "why-is-node-running@npm:2.2.2" dependencies: - siginfo: ^2.0.0 - stackback: 0.0.2 + siginfo: "npm:^2.0.0" + stackback: "npm:0.0.2" bin: why-is-node-running: cli.js - checksum: 50820428f6a82dfc3cbce661570bcae9b658723217359b6037b67e495255409b4c8bc7931745f5c175df71210450464517cab32b2f7458ac9c40b4925065200a + checksum: 10c0/805d57eb5d33f0fb4e36bae5dceda7fd8c6932c2aeb705e30003970488f1a2bc70029ee64be1a0e1531e2268b11e65606e88e5b71d667ea745e6dc48fc9014bd languageName: node linkType: hard -"wide-align@npm:^1.1.5": - version: 1.1.5 - resolution: "wide-align@npm:1.1.5" - dependencies: - string-width: ^1.0.2 || 2 || 3 || 4 - checksum: d5fc37cd561f9daee3c80e03b92ed3e84d80dde3365a8767263d03dacfc8fa06b065ffe1df00d8c2a09f731482fcacae745abfbb478d4af36d0a891fad4834d3 - languageName: node - linkType: hard - -"word-wrap@npm:^1.2.3, word-wrap@npm:~1.2.3": - version: 1.2.3 - resolution: "word-wrap@npm:1.2.3" - checksum: 30b48f91fcf12106ed3186ae4fa86a6a1842416df425be7b60485de14bec665a54a68e4b5156647dec3a70f25e84d270ca8bc8cd23182ed095f5c7206a938c1f - languageName: node - linkType: hard - -"wrap-ansi@npm:^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" dependencies: - ansi-styles: ^4.0.0 - string-width: ^4.1.0 - strip-ansi: ^6.0.0 - checksum: a790b846fd4505de962ba728a21aaeda189b8ee1c7568ca5e817d85930e06ef8d1689d49dbf0e881e8ef84436af3a88bc49115c2e2788d841ff1b8b5b51a608b + ansi-styles: "npm:^4.0.0" + string-width: "npm:^4.1.0" + strip-ansi: "npm:^6.0.0" + checksum: 10c0/d15fc12c11e4cbc4044a552129ebc75ee3f57aa9c1958373a4db0292d72282f54373b536103987a4a7594db1ef6a4f10acf92978f79b98c49306a4b58c77d4da + languageName: node + linkType: hard + +"wrap-ansi@npm:^8.1.0": + version: 8.1.0 + resolution: "wrap-ansi@npm:8.1.0" + dependencies: + ansi-styles: "npm:^6.1.0" + string-width: "npm:^5.0.1" + strip-ansi: "npm:^7.0.1" + checksum: 10c0/138ff58a41d2f877eae87e3282c0630fc2789012fc1af4d6bd626eeb9a2f9a65ca92005e6e69a75c7b85a68479fe7443c7dbe1eb8fbaa681a4491364b7c55c60 languageName: node linkType: hard "wrappy@npm:1": version: 1.0.2 resolution: "wrappy@npm:1.0.2" - checksum: 159da4805f7e84a3d003d8841557196034155008f817172d4e986bd591f74aa82aa7db55929a54222309e01079a65a92a9e6414da5a6aa4b01ee44a511ac3ee5 + checksum: 10c0/56fece1a4018c6a6c8e28fbc88c87e0fbf4ea8fd64fc6c63b18f4acc4bd13e0ad2515189786dd2c30d3eec9663d70f4ecf699330002f8ccb547e4a18231fc9f0 languageName: node linkType: hard "ws@npm:^8.13.0": - version: 8.13.0 - resolution: "ws@npm:8.13.0" + version: 8.16.0 + resolution: "ws@npm:8.16.0" peerDependencies: bufferutil: ^4.0.1 utf-8-validate: ">=5.0.2" @@ -7070,21 +7237,21 @@ __metadata: optional: true utf-8-validate: optional: true - checksum: 53e991bbf928faf5dc6efac9b8eb9ab6497c69feeb94f963d648b7a3530a720b19ec2e0ec037344257e05a4f35bd9ad04d9de6f289615ffb133282031b18c61c + checksum: 10c0/a7783bb421c648b1e622b423409cb2a58ac5839521d2f689e84bc9dc41d59379c692dd405b15a997ea1d4c0c2e5314ad707332d0c558f15232d2bc07c0b4618a languageName: node linkType: hard "xml-name-validator@npm:^4.0.0": version: 4.0.0 resolution: "xml-name-validator@npm:4.0.0" - checksum: af100b79c29804f05fa35aa3683e29a321db9b9685d5e5febda3fa1e40f13f85abc40f45a6b2bf7bee33f68a1dc5e8eaef4cec100a304a9db565e6061d4cb5ad + checksum: 10c0/c1bfa219d64e56fee265b2bd31b2fcecefc063ee802da1e73bad1f21d7afd89b943c9e2c97af2942f60b1ad46f915a4c81e00039c7d398b53cf410e29d3c30bd languageName: node linkType: hard "xmlchars@npm:^2.2.0": version: 2.2.0 resolution: "xmlchars@npm:2.2.0" - checksum: 8c70ac94070ccca03f47a81fcce3b271bd1f37a591bf5424e787ae313fcb9c212f5f6786e1fa82076a2c632c0141552babcd85698c437506dfa6ae2d58723062 + checksum: 10c0/b64b535861a6f310c5d9bfa10834cf49127c71922c297da9d4d1b45eeaae40bf9b4363275876088fbe2667e5db028d2cd4f8ee72eed9bede840a67d57dab7593 languageName: node linkType: hard @@ -7092,81 +7259,81 @@ __metadata: version: 1.0.14 resolution: "xss@npm:1.0.14" dependencies: - commander: ^2.20.3 - cssfilter: 0.0.10 + commander: "npm:^2.20.3" + cssfilter: "npm:0.0.10" bin: xss: bin/xss - checksum: 77c6a60a5f96490098ef837c3b49321c0f31963f323c748cb0a01bc02fc6e465a6accbe4c54cad62f8d6ffe647d984be173879433af861883f6213d9416d3f53 + checksum: 10c0/0a9b4d71781c8418a0327e86e5991dffe8d8b58d465d391ea74e3fa102168d1aa70a438c85d6af90e76f457bbb6041350b700bff7ad10077c5d816512f10ee0d languageName: node linkType: hard "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8" - checksum: 54f0fb95621ee60898a38c572c515659e51cc9d9f787fb109cef6fde4befbe1c4602dc999d30110feee37456ad0f1660fa2edcfde6a9a740f86a290999550d30 + checksum: 10c0/4df2842c36e468590c3691c894bc9cdbac41f520566e76e24f59401ba7d8b4811eb1e34524d57e54bc6d864bcb66baab7ffd9ca42bf1eda596618f9162b91249 languageName: node linkType: hard "yallist@npm:^3.0.2": version: 3.1.1 resolution: "yallist@npm:3.1.1" - checksum: 48f7bb00dc19fc635a13a39fe547f527b10c9290e7b3e836b9a8f1ca04d4d342e85714416b3c2ab74949c9c66f9cebb0473e6bc353b79035356103b47641285d + checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 languageName: node linkType: hard "yallist@npm:^4.0.0": version: 4.0.0 resolution: "yallist@npm:4.0.0" - checksum: 343617202af32df2a15a3be36a5a8c0c8545208f3d3dfbc6bb7c3e3b7e8c6f8e7485432e4f3b88da3031a6e20afa7c711eded32ddfb122896ac5d914e75848d5 + checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a languageName: node linkType: hard "yaml@npm:^1.10.0, yaml@npm:^1.10.2": version: 1.10.2 resolution: "yaml@npm:1.10.2" - checksum: ce4ada136e8a78a0b08dc10b4b900936912d15de59905b2bf415b4d33c63df1d555d23acb2a41b23cf9fb5da41c256441afca3d6509de7247daa062fd2c5ea5f + checksum: 10c0/5c28b9eb7adc46544f28d9a8d20c5b3cb1215a886609a2fd41f51628d8aaa5878ccd628b755dbcd29f6bb4921bd04ffbc6dcc370689bb96e594e2f9813d2605f languageName: node linkType: hard "yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" - checksum: ed2d96a616a9e3e1cc7d204c62ecc61f7aaab633dcbfab2c6df50f7f87b393993fe6640d017759fe112d0cb1e0119f2b4150a87305cc873fd90831c6a58ccf1c + checksum: 10c0/f84b5e48169479d2f402239c59f084cfd1c3acc197a05c59b98bab067452e6b3ea46d4dd8ba2985ba7b3d32a343d77df0debd6b343e5dae3da2aab2cdf5886b2 languageName: node linkType: hard "yargs@npm:^17.5.1": - version: 17.6.2 - resolution: "yargs@npm:17.6.2" + version: 17.7.2 + resolution: "yargs@npm:17.7.2" dependencies: - cliui: ^8.0.1 - escalade: ^3.1.1 - get-caller-file: ^2.0.5 - require-directory: ^2.1.1 - string-width: ^4.2.3 - y18n: ^5.0.5 - yargs-parser: ^21.1.1 - checksum: 47da1b0d854fa16d45a3ded57b716b013b2179022352a5f7467409da5a04a1eef5b3b3d97a2dfc13e8bbe5f2ffc0afe3bc6a4a72f8254e60f5a4bd7947138643 + cliui: "npm:^8.0.1" + escalade: "npm:^3.1.1" + get-caller-file: "npm:^2.0.5" + require-directory: "npm:^2.1.1" + string-width: "npm:^4.2.3" + y18n: "npm:^5.0.5" + yargs-parser: "npm:^21.1.1" + checksum: 10c0/ccd7e723e61ad5965fffbb791366db689572b80cca80e0f96aad968dfff4156cd7cd1ad18607afe1046d8241e6fb2d6c08bf7fa7bfb5eaec818735d8feac8f05 languageName: node linkType: hard "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0" - checksum: f77b3d8d00310def622123df93d4ee654fc6a0096182af8bd60679ddcdfb3474c56c6c7190817c84a2785648cdee9d721c0154eb45698c62176c322fb46fc700 + checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f languageName: node linkType: hard "yocto-queue@npm:^1.0.0": version: 1.0.0 resolution: "yocto-queue@npm:1.0.0" - checksum: 2cac84540f65c64ccc1683c267edce396b26b1e931aa429660aefac8fbe0188167b7aee815a3c22fa59a28a58d898d1a2b1825048f834d8d629f4c2a5d443801 + checksum: 10c0/856117aa15cf5103d2a2fb173f0ab4acb12b4b4d0ed3ab249fdbbf612e55d1cadfd27a6110940e24746fb0a78cf640b522cc8bca76f30a3b00b66e90cf82abe0 languageName: node linkType: hard "zod@npm:^3.21.4": - version: 3.21.4 - resolution: "zod@npm:3.21.4" - checksum: f185ba87342ff16f7a06686767c2b2a7af41110c7edf7c1974095d8db7a73792696bcb4a00853de0d2edeb34a5b2ea6a55871bc864227dace682a0a28de33e1f + version: 3.22.4 + resolution: "zod@npm:3.22.4" + checksum: 10c0/7578ab283dac0eee66a0ad0fc4a7f28c43e6745aadb3a529f59a4b851aa10872b3890398b3160f257f4b6817b4ce643debdda4fb21a2c040adda7862cab0a587 languageName: node linkType: hard From 8f3c6af38fc556f05c89a30dee145a76de62d558 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 3 Mar 2024 15:54:18 -0800 Subject: [PATCH 093/189] Update test thresholds. New vitest versions are much better at calculating the denominator, test coverage has actually improved in this PR, but much more code is detected. --- vite.config.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vite.config.ts b/vite.config.ts index c22c0b38..94aecf74 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -14,10 +14,10 @@ export default defineConfig({ // back-sliding. thresholds: { autoUpdate: true, - statements: 73.59, - branches: 63.6, - functions: 74.86, - lines: 73.48, + statements: 51.11, + branches: 43.04, + functions: 51.03, + lines: 51.91, }, }, }, From 89ddea69db82964a0b4c8a143bbb398cf2960d9d Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 3 Mar 2024 18:22:51 -0800 Subject: [PATCH 094/189] Fix obscure config merge bug. --- src/camera-manager/manager.ts | 14 ++++++--- src/utils/basic.ts | 5 +++ tests/camera-manager/manager.test.ts | 42 ++++++++++++++++++++----- tests/utils/basic.test.ts | 47 ++++++++++++++++++++++++++++ 4 files changed, 96 insertions(+), 12 deletions(-) diff --git a/src/camera-manager/manager.ts b/src/camera-manager/manager.ts index 18bf305b..82960b0f 100644 --- a/src/camera-manager/manager.ts +++ b/src/camera-manager/manager.ts @@ -1,12 +1,16 @@ import add from 'date-fns/add'; import cloneDeep from 'lodash-es/cloneDeep'; -import merge from 'lodash-es/merge.js'; import sum from 'lodash-es/sum'; import { CardCameraAPI } from '../card-controller/types.js'; import { CameraConfig, CamerasConfig, PTZAction, PTZPhase } from '../config/types.js'; import { MEDIA_CHUNK_SIZE_DEFAULT } from '../const.js'; import { localize } from '../localize/localize.js'; -import { allPromises, arrayify, setify } from '../utils/basic.js'; +import { + allPromises, + arrayify, + recursivelyMergeObjectsNotArrays, + setify, +} from '../utils/basic.js'; import { getCameraID } from '../utils/camera.js'; import { log } from '../utils/debug.js'; import { ViewMedia } from '../view/media.js'; @@ -141,7 +145,7 @@ export class CameraManager { // order, to ensure that the defaults in the cameras global config do not // override the values specified in the per-camera config. const cameras = config.cameras.map((camera) => - merge(cloneDeep(config?.cameras_global), camera), + recursivelyMergeObjectsNotArrays(cloneDeep(config?.cameras_global), camera), ); try { @@ -460,13 +464,13 @@ export class CameraManager { const latestResult = getTimeFromResults('latest'); if (latestResult) { newChunkQuery.start = latestResult; - delete(newChunkQuery.end); + delete newChunkQuery.end; } } else if (direction === 'earlier') { const earliestResult = getTimeFromResults('earliest'); if (earliestResult) { newChunkQuery.end = earliestResult; - delete(newChunkQuery.start); + delete newChunkQuery.start; } } newChunkQuery.limit = chunkSize; diff --git a/src/utils/basic.ts b/src/utils/basic.ts index 7209771a..a977e9e6 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -3,6 +3,7 @@ import differenceInMinutes from 'date-fns/differenceInMinutes'; import differenceInSeconds from 'date-fns/differenceInSeconds'; import format from 'date-fns/format'; import isEqual from 'lodash-es/isEqual'; +import mergeWith from 'lodash-es/mergeWith'; import { FrigateCardError } from '../types'; export type ModifyInterface = Omit & R; @@ -240,3 +241,7 @@ export const getChildrenFromElement = (parent: HTMLElement): HTMLElement[] => { : [...parent.children]; return children.filter(isHTMLElement); }; + +export const recursivelyMergeObjectsNotArrays = (src1: T, src2: T): T => { + return mergeWith({}, src1, src2, (_a, b) => (Array.isArray(b) ? b : undefined)); +}; diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts index 642a11e2..5aa825c9 100644 --- a/tests/camera-manager/manager.test.ts +++ b/tests/camera-manager/manager.test.ts @@ -1,3 +1,4 @@ +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import add from 'date-fns/add'; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; @@ -29,6 +30,7 @@ import { import { sortMedia } from '../../src/camera-manager/utils'; import { CardController } from '../../src/card-controller/controller'; import { CameraConfig } from '../../src/config/types'; +import { EntityRegistryManager } from '../../src/utils/ha/entity-registry'; import { ViewMedia } from '../../src/view/media'; import { TestViewMedia, @@ -222,7 +224,7 @@ describe('CameraManager', async () => { factory?: CameraManagerEngineFactory, ): CameraManager => { const camerasConfig = cameras?.map( - (camera) => camera.config ?? createCameraConfig({ engine: 'generic' }), + (camera) => camera.config ?? createCameraConfig(baseCameraConfig), ); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ @@ -238,12 +240,17 @@ describe('CameraManager', async () => { const engineType = camera.engineType === undefined ? Engine.Generic : camera.engineType; if (engineType) { - vi.mocked(mockEngine.createCamera).mockResolvedValueOnce( - createCamera( - camera.config ?? createCameraConfig(baseCameraConfig), - mockEngine, - camera.capabilties ?? createCameraCapabilities(), - ), + vi.mocked(mockEngine.createCamera).mockImplementationOnce( + async ( + _hass: HomeAssistant, + _entityRegistryManager: EntityRegistryManager, + cameraConfig: CameraConfig, + ): Promise => + createCamera( + cameraConfig, + mockEngine, + camera.capabilties ?? createCameraCapabilities(), + ), ); } vi.mocked(mockFactory.getEngineForCamera).mockResolvedValueOnce(engineType); @@ -484,6 +491,27 @@ describe('CameraManager', async () => { expect(manager.generateDefaultEventQueries('id')).toBeNull(); }); }); + + it('should merge defaults correctly', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const engine = mock(); + const manager = createCameraManager(api, engine, [ + { + config: createCameraConfig({ + ...baseCameraConfig, + triggers: { + events: ['snapshots'], + }, + }), + }, + ]); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + expect(manager.getStore().getCamera('id')?.getConfig().triggers.events).toEqual([ + 'snapshots', + ]); + }); }); describe('should get media metadata', () => { diff --git a/tests/utils/basic.test.ts b/tests/utils/basic.test.ts index 0a58c87c..4961b777 100644 --- a/tests/utils/basic.test.ts +++ b/tests/utils/basic.test.ts @@ -18,6 +18,7 @@ import { isTruthy, isValidDate, prettifyTitle, + recursivelyMergeObjectsNotArrays, runWhenIdleIfSupported, setOrRemoveAttribute, setify, @@ -291,3 +292,49 @@ describe('getChildrenFromElement', () => { expect(getChildrenFromElement(slot)).toEqual(children); }); }); + +describe('recursivelyMergeObjectsNotArrays', () => { + it('should recursively merge objects but replace arrays', () => { + expect( + recursivelyMergeObjectsNotArrays( + { + a: { + b: { + c: 3, + d: { + e: 4, + }, + array: [1, 2, 3], + }, + other: { + field: 7, + }, + }, + }, + { + a: { + b: { + array: [4], + d: { + e: 5, + }, + }, + }, + }, + ), + ).toEqual({ + a: { + b: { + c: 3, + array: [4], + d: { + e: 5, + }, + }, + other: { + field: 7, + }, + }, + }); + }); +}); From 2b9b237327b7cd881e69330783af113e841e2409 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 3 Mar 2024 21:09:10 -0800 Subject: [PATCH 095/189] Prevent test coverage backsliding for 100% coverage files. --- vite.config.ts | 88 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 78 insertions(+), 10 deletions(-) diff --git a/vite.config.ts b/vite.config.ts index 94aecf74..ca89f07f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -1,24 +1,92 @@ import { defineConfig } from 'vitest/config'; +// These globs are expected to have 100% coverage. +const FULL_COVERAGE_FILES_RELATIVE = [ + 'camera-manager/*.ts', + 'camera-manager/browse-media/camera.ts', + 'camera-manager/frigate/camera.ts', + 'camera-manager/frigate/icon.ts', + 'camera-manager/frigate/requests.ts', + 'camera-manager/frigate/util.ts', + 'camera-manager/generic/*.ts', + 'camera-manager/motioneye/icon.ts', + 'card-controller/*.ts', + 'components-lib/cached-value-controller.ts', + 'components-lib/media-filter-controller.ts', + 'components-lib/menu-button-controller.ts', + 'components-lib/menu-controller.ts', + 'components-lib/ptz-controller.ts', + 'components-lib/zoom-controller.ts', + 'config-mgmt.ts', + 'config/types.ts', + 'const.ts', + 'src/view/*.ts', + 'types.ts', + 'utils/action.ts', + 'utils/audio.ts', + 'utils/basic.ts', + 'utils/camera.ts', + 'utils/debug.ts', + 'utils/diagnostics.ts', + 'utils/download.ts', + 'utils/embla/**/*.ts', + 'utils/ha/entity-registry/types.ts', + 'utils/ha/types.ts', + 'utils/media-info.ts', + 'utils/media-to-view.ts', + 'utils/media.ts', + 'utils/ptz.ts', + 'utils/screenshot.ts', + 'utils/substream.ts', + 'utils/timer.ts', + 'utils/zod.ts', +]; + +interface Threshold { + statements: number; + branches: number; + functions: number; + lines: number; + perFile: boolean; +} + +const fullCoverage: Threshold = { + statements: 100, + branches: 100, + functions: 100, + lines: 100, + perFile: true, +}; + +const calculateFullCoverageThresholds = (): Record => { + return FULL_COVERAGE_FILES_RELATIVE.reduce( + (a, v) => ({ ...a, ['**/src/' + v]: fullCoverage }), + {}, + ); +}; + // ts-prune-ignore-next export default defineConfig({ test: { - include: [ - "tests/**/*.test.ts" - ], + include: ['tests/**/*.test.ts'], coverage: { // Favor istanbul for coverage over v8 due to better accuracy. provider: 'istanbul', - // Thresholds will automatically be updated as coverage improves to avoid - // back-sliding. thresholds: { + // Thresholds will automatically be updated as coverage improves to avoid + // back-sliding. autoUpdate: true, - statements: 51.11, - branches: 43.04, - functions: 51.03, - lines: 51.91, + + // Expected thresholds for anything that does not have 100% coverage + // yet. + statements: 15.54, + branches: 10.38, + functions: 16.18, + lines: 15.84, + + ...calculateFullCoverageThresholds(), }, }, }, -}); +}); \ No newline at end of file From 7d1260d122c26deffb27aa743d859f4244c1b994 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 3 Mar 2024 21:31:43 -0800 Subject: [PATCH 096/189] Remove remnants of old PTZ `auto` mode. --- src/editor.ts | 1 - src/localize/languages/en.json | 1 - src/localize/languages/it.json | 1 - src/localize/languages/pt-BR.json | 1 - src/localize/languages/pt-PT.json | 1 - 5 files changed, 5 deletions(-) diff --git a/src/editor.ts b/src/editor.ts index 250467b9..8c586f97 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -624,7 +624,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor { value: '', label: '' }, { value: 'on', label: localize('config.live.controls.ptz.modes.on') }, { value: 'off', label: localize('config.live.controls.ptz.modes.off') }, - { value: 'auto', label: localize('config.live.controls.ptz.modes.auto') }, ]; protected _ptzOrientations: EditorSelectOption[] = [ diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index c329ce44..ee928903 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -254,7 +254,6 @@ "hide_zoom": "Hide zoom control", "mode": "Mode", "modes": { - "auto": "Automatic", "off": "Off", "on": "On" }, diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index ef8c0706..97558030 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -254,7 +254,6 @@ "hide_zoom": "", "mode": "", "modes": { - "auto": "", "off": "", "on": "" }, diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 87dcb442..3041dd2f 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -254,7 +254,6 @@ "hide_zoom": "", "mode": "", "modes": { - "auto": "", "off": "", "on": "" }, diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 0ef522bc..78a11864 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -247,7 +247,6 @@ "hide_zoom": "", "mode": "", "modes": { - "auto": "", "off": "", "on": "" }, From 72eae2bf8859613f57fe705cc773da625d04df30 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 6 Mar 2024 23:08:32 -0800 Subject: [PATCH 097/189] Update dimensions and media layout options to be per camera. --- README.md | 161 +++++++------------- src/card-controller/style-manager.ts | 14 +- src/card.ts | 5 +- src/components/live/live.ts | 12 +- src/components/viewer.ts | 17 ++- src/config-mgmt.ts | 4 + src/config/types.ts | 52 ++++--- src/const.ts | 21 ++- src/editor.ts | 84 +++++----- src/localize/languages/en.json | 42 ++--- src/localize/languages/it.json | 37 ++--- src/localize/languages/pt-BR.json | 37 ++--- src/localize/languages/pt-PT.json | 37 ++--- src/scss/live-carousel.scss | 11 ++ src/scss/live-provider.scss | 2 +- src/utils/basic.ts | 23 +++ tests/card-controller/style-manager.test.ts | 20 +-- tests/config-mgmt.test.ts | 54 +++++++ tests/utils/basic.test.ts | 24 ++- vite.config.ts | 12 +- 20 files changed, 375 insertions(+), 294 deletions(-) diff --git a/README.md b/README.md index bb8359d3..88360996 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,7 @@ See the [fully expanded cameras configuration example](#config-expanded-cameras) | `triggers` | | :white_check_mark: | Define what should cause this camera to update/trigger. See [camera triggers](#camera-trigger-configuration) below. | | `webrtc_card` | | :white_check_mark: | The WebRTC entity/URL to use for this camera with the `webrtc-card` live provider. See below. | | `cast` | | :white_check_mark: | Configuration that controls how this camera is "casted" / sent to media players. See below. | +| `dimensions` | | :white_check_mark: | Controls the dimensions and layout for media from this camera. See below. | @@ -363,6 +364,39 @@ cameras: | `dashboard_path` | | :white_check_mark: | A required field that specifies the name of the dashboard to cast. You can see this name in your HA URL when you visit the dashboard. | | `view_path` | | :white_check_mark: | A required field that specifies view/"tab" on that dashboard to cast. This is the value you have specified in the `url` field of the view configuration on the dashboard. | +### Camera Dimensions Configuration + +The `dimensions` block configures the dimensions and layout of media from a given camera. + +```yaml +cameras: + - dimensions: +``` + +| Option | Default | Overridable | Description | +| - | - | - | - | +| `aspect_ratio` | | :white_check_mark: | An optional aspect ratio for media from this camera which will be used in `live` or media viewer related views (e.g. `clip`, `snapshot` and `recording`). Format is the same as the parameter of the same name under the [dimensions block](#dimensions) (which controls dimensions for the whole card), e.g. `16 / 9`. | +| `layout` | | :white_check_mark: | How the media should be laid out *within* the camera dimensions. See below. | + +### Camera Dimensions Layout Configuration + +The `layout` block configures the dimensions and layout of media from a given camera. + +```yaml +cameras: + - dimensions: + layout: +``` + +This block is used to control the fit and position of the media _within_ the camera dimensions (in order to control the dimensions for the whole card see [the card dimensions parameter](#dimensions) ). As the default behavior is to always expand to fit the media precisely, these options only make sense if the camera `dimensions.aspect_ratio` is set to a static value that forces a particular aspect ratio that does not match the camera media. + +| Option | Default | Overridable | Description | +| - | - | - | - | +| `fit` | `contain` | :white_check_mark: | If `contain`, the media is contained within the card and letterboxed if necessary. If `cover`, the media is expanded proportionally (i.e. maintaining the media aspect ratio) until the card is fully covered. If `fill`, the media is stretched to fill the card (i.e. ignoring the media aspect ratio). See [CSS object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) for technical details and a visualization. | +| `position` | | :white_check_mark: | A dictionary that contains an `x` and `y` percentage (`0` - `100`) to control the position of the media when the fit is `cover`. This can be effectively used to "pan" the media around. At any given time, only one of `x` and `y` will have an effect, depending on whether media width is larger than the card width (in which case `x` controls the position) or the media height is larger than the card height (in which case `y` controls the position). A value of `0` means maximally to the left or top of the media, a value of `100` means maximally to the right or bottom of the media. See [CSS object-position](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) for technical details and a visualization. | + +See [media layout examples](#media-layout-examples). + #### Camera IDs: Referring to cameras in card configuration @@ -533,7 +567,6 @@ See the [fully expanded live configuration example](#config-expanded-live) for h | `show_image_during_load` | `true` | :white_check_mark: | If `true`, during the initial stream load, the `image` live provider will be shown instead of the loading video stream. This still image will auto-refresh and is replaced with the live stream once loaded. | | `actions` | | :white_check_mark: | Actions to use for the `live` view. See [actions](#actions) below.| | `controls` | | :white_check_mark: | Configuration for the `live` view controls. See below. | -| `layout` | | :white_check_mark: | See [media layout](#media-layout) below.| | `microphone` | | :white_check_mark: | See [microphone](#microphone) below.| | `display` | | :white_check_mark: | See [display](#live-display) below.| @@ -721,7 +754,6 @@ See the [fully expanded Media viewer configuration example](#config-expanded-med | `transition_effect` | `slide` | :heavy_multiplication_x: | Effect to apply as a transition between event media. Accepted values: `slide` or `none`. | | `controls` | | :heavy_multiplication_x: | Configuration for the Media viewer controls. See below. | | `actions` | | :heavy_multiplication_x: | Actions to use for all views that use the `media_viewer` (e.g. `clip`, `snapshot`). See [actions](#actions) below.| -| `layout` | | :white_check_mark: | See [media layout](#media-layout) below.| #### Media Viewer Controls @@ -939,8 +971,6 @@ timeline: | `show_favorite_control` | `true` | :heavy_multiplication_x: | Whether to show the favorite ('star') control on each thumbnail.| | `show_timeline_control` | `true` | :heavy_multiplication_x: | Whether to show the timeline ('target') control on each thumbnail.| - - #### Timeline Seek Behavior The behavior of the timeline during seeking/dragging can be controlled by means of the icon on the bottom-right of the timeline. @@ -952,6 +982,8 @@ The behavior of the timeline during seeking/dragging can be controlled by means | camera-lock | Dragging the timeline will seek / select across all available media from the selected camera only, selecting the media item with the longest duration. | | pan-horizontal | Dragging the timeline will pan only without selected or seeking any media. | + + ### Dimensions Options These options control the aspect-ratio of the entire card to make placement in @@ -961,7 +993,6 @@ media. This only applies to the card in normal render mode -- when in fullscreen, or when in expanded (popup/dialog mode) the aspect ratio is chosen dynamically to maximize the amount of content shown. - All configuration is under: ```yaml @@ -1139,34 +1170,6 @@ automations: | `actions` | | :heavy_multiplication_x: | An optional list of actions that will be run when the conditions evaluate `true`. Actions can be [stock Home Assistant actions](https://www.home-assistant.io/dashboards/actions/) or [Frigate card actions](#frigate-card-actions).| | `actions_not` | | :heavy_multiplication_x: | An optional list of actions that will be run when the conditions evaluate `false`. Actions can be [stock Home Assistant actions](https://www.home-assistant.io/dashboards/actions/) or [Frigate card actions](#frigate-card-actions).| - - -### Media Layout - -The `live`, `media_viewer` and `image` sections all support `layout` option which is used to control the fit and position of the media _within_ the card dimensions (in order to control the card dimensions themselves see [the dimensions parameter](#dimensions) ). - -As the default card behavior is for the card to always expand to fit the media, these options only make sense if `dimensions.aspect_ratio_mode` is set to `static`. - -All configuration is under: - -```yaml -live: - layout: -image: - layout: -media_viewer: - layout: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `fit` | `contain` | :white_check_mark: | If `contain`, the media is contained within the card and letterboxed if necessary. If `cover`, the media is expanded proportionally (i.e. maintaining the media aspect ratio) until the card is fully covered. If `fill`, the media is stretched to fill the card (i.e. ignoring the media aspect ratio). See [CSS object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) for technical details and a visualization. | -| `position` | | :white_check_mark: | A dictionary that contains an `x` and `y` percentage (`0` - `100`) to control the position of the media when the fit is `cover`. This can be effectively used to "pan" the media around. At any given time, only one of `x` and `y` will have an effect, depending on whether media width is larger than the card width (in which case `x` controls the position) or the media height is larger than the card height (in which case `y` controls the position). A value of `0` means maximally to the left or top of the media, a value of `100` means maximally to the right or bottom of the media. See [CSS object-position](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) for technical details and a visualization. | - -If multiple cameras are configured in the card, use [overrides](#overrides) to configure different values per camera. - -See [media layout examples](#media-layout-examples). - ### Other Options @@ -1782,6 +1785,13 @@ cameras: - binary_sensor.front_door_sensor cast: method: standard + dimensions: + aspect_ratio: 16:9 + layout: + fit: contain + position: + x: 50 + y: 50 - camera_entity: camera.entrance live_provider: webrtc-card engine: auto @@ -2114,11 +2124,6 @@ live: title: mode: popup-bottom-right duration_seconds: 2 - layout: - fit: contain - position: - x: 50 - y: 50 microphone: always_connected: false disconnect_seconds: 90 @@ -2212,11 +2217,6 @@ media_viewer: title: mode: popup-bottom-right duration_seconds: 2 - layout: - fit: contain - position: - x: 50 - y: 50 display: mode: single grid_selected_width_factor: 2 @@ -2281,11 +2281,6 @@ image: mode: url refresh_seconds: 0 zoomable: true - layout: - fit: contain - position: - x: 50 - y: 50 actions: entity: light.office_main_lights tap_action: @@ -3738,20 +3733,16 @@ Change how the media fits and is positioned within the card dimensions.
Expand: Stretching an image -Stretch the stock Frigate card image into a 4:4 square. +Stretch a camera into a 4:4 square. ```yaml type: custom:frigate-card cameras: - camera_entity: camera.landing -view: - default: image -dimensions: - aspect_ratio_mode: static - aspect_ratio: '4:4' -image: - layout: - fit: fill + dimensions: + aspect_ratio: '4:4' + layout: + fit: fill ```
@@ -3764,56 +3755,12 @@ Take the left-hand side (position with x == `0` and use that as the basis of a ` type: custom:frigate-card cameras: - camera_entity: camera.landing -dimensions: - aspect_ratio_mode: static - aspect_ratio: '9:16' -live: - layout: - fit: cover - position: - x: 0 -``` - - -
- Expand: Complex example to vary the media layouts for different cameras - -Configure three cameras (all natively landscape): the first uses automatic expansion of dimensions (the default), the second uses a portrait (`9:16`) card focused on the left side (`x` == `0`) of the media, the third uses a portrait (`9:16`) card focused on the right side (`x` == `100`) of the media. - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.landing - - camera_entity: camera.living_room - - camera_entity: camera.sitting_room -overrides: - - conditions: - camera: - - camera.living_room - - camera.sitting_room - overrides: - dimensions: - aspect_ratio_mode: static - aspect_ratio: '9:16' - live: - layout: - fit: cover - - conditions: - camera: - - camera.living_room - overrides: - live: - layout: - position: - x: 0 - - conditions: - camera: - - camera.sitting_room - overrides: - live: - layout: - position: - x: 100 + dimensions: + aspect_ratio: '9:16' + layout: + fit: cover + position: + x: 0 ```
diff --git a/src/card-controller/style-manager.ts b/src/card-controller/style-manager.ts index d6185d5e..1a5763de 100644 --- a/src/card-controller/style-manager.ts +++ b/src/card-controller/style-manager.ts @@ -1,7 +1,8 @@ +import { StyleInfo } from 'lit/directives/style-map'; import { FrigateCardConfig } from '../config/types'; import { setPerformanceCSSStyles } from '../performance'; +import { aspectRatioToStyle, setOrRemoveAttribute } from '../utils/basic'; import { View } from '../view/view'; -import { setOrRemoveAttribute } from '../utils/basic'; import { CardStyleAPI } from './types'; export class StyleManager { @@ -103,24 +104,23 @@ export class StyleManager { * required). * @returns A padding percentage. */ - public getAspectRatioStyle(): string { + public getAspectRatioStyle(): StyleInfo { const config = this._api.getConfigManager().getConfig(); const view = this._api.getViewManager().getView(); if (config) { if (!this._isAspectRatioEnforced(config, view)) { - return 'auto'; + return aspectRatioToStyle(); } const aspectRatioMode = config.dimensions.aspect_ratio_mode; const lastKnown = this._api.getMediaLoadedInfoManager().getLastKnown(); if (lastKnown && aspectRatioMode === 'dynamic') { - return `${lastKnown.width} / ${lastKnown.height}`; + return aspectRatioToStyle({ ratio: [lastKnown.width, lastKnown.height] }); } - - return `${config.dimensions.aspect_ratio[0]} / ${config.dimensions.aspect_ratio[1]}`; + return aspectRatioToStyle({ ratio: config.dimensions.aspect_ratio }); } - return '16 / 9'; + return aspectRatioToStyle({ defaultStatic: true }); } } diff --git a/src/card.ts b/src/card.ts index 9370f2b1..e4973c99 100644 --- a/src/card.ts +++ b/src/card.ts @@ -242,9 +242,6 @@ class FrigateCard extends LitElement { return; } - const cardStyle = { - 'aspect-ratio': this._controller.getStyleManager().getAspectRatioStyle(), - }; const mainClasses = { main: true, 'curve-top': @@ -266,7 +263,7 @@ class FrigateCard extends LitElement { hasHold: frigateCardHasAction(actions.hold_action), hasDoubleClick: frigateCardHasAction(actions.double_tap_action), })} - style="${styleMap(cardStyle)}" + style="${styleMap(this._controller.getStyleManager().getAspectRatioStyle())}" @frigate-card:message=${(ev: CustomEvent) => this._controller.getMessageManager().setMessageIfHigherPriority(ev.detail)} @frigate-card:view:change=${(ev: CustomEvent) => diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 4f01c22e..38ab5c0b 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -41,7 +41,7 @@ import { Message, } from '../../types.js'; import { stopEventFromActivatingCardWideActions } from '../../utils/action.js'; -import { contentsChanged } from '../../utils/basic.js'; +import { aspectRatioToString, contentsChanged } from '../../utils/basic.js'; import { CarouselSelected } from '../../utils/embla/carousel-controller.js'; import { AutoLazyLoad } from '../../utils/embla/plugins/auto-lazy-load/auto-lazy-load.js'; import { AutoMediaActions } from '../../utils/embla/plugins/auto-media-actions/auto-media-actions.js'; @@ -900,7 +900,6 @@ export class FrigateCardLiveProvider } } if (changedProps.has('liveConfig')) { - updateElementStyleFromMediaLayoutConfig(this, this.liveConfig?.layout); if (this.liveConfig?.show_image_during_load) { this._importPromises.push(import('./live-image.js')); } @@ -908,6 +907,7 @@ export class FrigateCardLiveProvider this._importPromises.push(import('./../zoomer.js')); } } + if (changedProps.has('cameraConfig')) { const provider = this._getResolvedProvider(); if (provider === 'jsmpeg') { @@ -921,6 +921,14 @@ export class FrigateCardLiveProvider } else if (provider === 'go2rtc') { this._importPromises.push(import('./live-go2rtc.js')); } + + updateElementStyleFromMediaLayoutConfig( + this, + this.cameraConfig?.dimensions?.layout, + ); + this.style.aspectRatio = aspectRatioToString({ + ratio: this.cameraConfig?.dimensions?.aspect_ratio, + }); } } diff --git a/src/components/viewer.ts b/src/components/viewer.ts index 1b1791ab..e37a7df0 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -37,6 +37,7 @@ import { import { stopEventFromActivatingCardWideActions } from '../utils/action.js'; import { mayHaveAudio } from '../utils/audio.js'; import { + aspectRatioToString, contentsChanged, errorToConsole, setOrRemoveAttribute, @@ -396,10 +397,6 @@ export class FrigateCardViewerCarousel extends LitElement { * @param changedProps The changed properties */ protected willUpdate(changedProps: PropertyValues): void { - if (changedProps.has('viewerConfig')) { - updateElementStyleFromMediaLayoutConfig(this, this.viewerConfig?.layout); - } - if (changedProps.has('view')) { const newMedia = this.view?.queryResults?.getResults(this.viewFilterCameraID) ?? null; @@ -853,6 +850,18 @@ export class FrigateCardViewerProvider if (changedProps.has('viewerConfig') && this.viewerConfig?.zoomable) { import('./zoomer.js'); } + + if (changedProps.has('media') || changedProps.has('cameraManager')) { + const cameraID = this.media?.getCameraID(); + const cameraConfig = cameraID + ? this.cameraManager?.getStore().getCameraConfig(cameraID) + : null; + updateElementStyleFromMediaLayoutConfig(this, cameraConfig?.dimensions?.layout); + + this.style.aspectRatio = aspectRatioToString({ + ratio: cameraConfig?.dimensions?.aspect_ratio, + }); + } } protected _useZoomIfRequired(template: TemplateResult): TemplateResult { diff --git a/src/config-mgmt.ts b/src/config-mgmt.ts index dd13f89f..614ad149 100644 --- a/src/config-mgmt.ts +++ b/src/config-mgmt.ts @@ -6,6 +6,7 @@ import unset from 'lodash-es/unset'; import { RawFrigateCardConfig, RawFrigateCardConfigArray } from './config/types'; import { CONF_CAMERAS, + CONF_CAMERAS_GLOBAL_DIMENSIONS_LAYOUT, CONF_CAMERAS_GLOBAL_IMAGE, CONF_CAMERAS_GLOBAL_JSMPEG, CONF_CAMERAS_GLOBAL_WEBRTC_CARD, @@ -565,4 +566,7 @@ const UPGRADES = [ transform: (val) => (val ? 'default' : null), }, ), + upgradeMoveToWithOverrides('live.layout', CONF_CAMERAS_GLOBAL_DIMENSIONS_LAYOUT), + deleteWithOverrides('media_viewer.layout'), + deleteWithOverrides('image.layout'), ]; diff --git a/src/config/types.ts b/src/config/types.ts index 39d745cc..44bddb1d 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -524,19 +524,19 @@ export type FrigateConditional = z.infer; // Cannot use discriminatedUnion since customSchema uses a superRefine, which // causes false rejections. const pictureElementSchema = z.union([ - menuStateIconSchema, + conditionalSchema, + customSchema, + frigateConditionalSchema, + iconSchema, + imageSchema, menuIconSchema, + menuStateIconSchema, menuSubmenuSchema, menuSubmenuSelectSchema, - frigateConditionalSchema, + serviceCallButtonSchema, stateBadgeIconSchema, stateIconSchema, stateLabelSchema, - serviceCallButtonSchema, - iconSchema, - imageSchema, - conditionalSchema, - customSchema, ]); const pictureElementsSchema = pictureElementSchema.array().optional(); export type PictureElements = z.infer; @@ -556,6 +556,21 @@ const mediaLayoutConfigSchema = z.object({ }); export type MediaLayoutConfig = z.infer; +// ************************************************************************* +// Aspect Ratio Configuration +// ************************************************************************* + +const aspectRatioSchema = z + .number() + .array() + .length(2) + .or( + z + .string() + .regex(/^\s*\d+\.?\d*\s*[:/]\s*\d+\.?\d*\s*$/) + .transform((input) => input.split(/[:\/]/).map((d) => Number(d))), + ); + // ************************************************************************* // Image Configuration // Image config base options are used both for the `image` live provider and the @@ -581,7 +596,6 @@ const imageConfigDefault = { const imageConfigSchema = imageBaseConfigSchema .extend({ mode: z.enum(IMAGE_MODES).default(imageConfigDefault.mode), - layout: mediaLayoutConfigSchema.optional(), zoomable: z.boolean().default(imageConfigDefault.zoomable), }) .merge(actionsSchema) @@ -711,6 +725,7 @@ export type TimelineConfig = z.infer; // ************************************************************************* // Next/Previous Control Configuration // ************************************************************************* + const nextPreviousControlConfigSchema = z.object({ style: z.enum(['none', 'chevrons', 'icons', 'thumbnails']), size: z.number().min(BUTTON_SIZE_MIN), @@ -950,7 +965,6 @@ const liveOverridableConfigSchema = z show_image_during_load: z .boolean() .default(liveConfigDefault.show_image_during_load), - layout: mediaLayoutConfigSchema.optional(), microphone: microphoneConfigSchema.default(liveConfigDefault.microphone), zoomable: z.boolean().default(liveConfigDefault.zoomable), display: viewDisplaySchema, @@ -1138,6 +1152,13 @@ export const cameraConfigSchema = z webrtc_card: webrtcCardConfigSchema.optional(), cast: castSchema.optional(), + + dimensions: z + .object({ + aspect_ratio: aspectRatioSchema.optional(), + layout: mediaLayoutConfigSchema.optional(), + }) + .optional(), }) .default(cameraConfigDefault); export type CameraConfig = z.infer; @@ -1412,7 +1433,6 @@ const viewerConfigSchema = z title: titleControlConfigSchema.optional(), }) .default(viewerConfigDefault.controls), - layout: mediaLayoutConfigSchema.optional(), }) .merge(actionsSchema) .default(viewerConfigDefault); @@ -1477,17 +1497,7 @@ export const dimensionsConfigSchema = z aspect_ratio_mode: z .enum(['dynamic', 'static', 'unconstrained']) .default(dimensionsConfigDefault.aspect_ratio_mode), - aspect_ratio: z - .number() - .array() - .length(2) - .or( - z - .string() - .regex(/^\s*\d+\s*[:/]\s*\d+\s*$/) - .transform((input) => input.split(/[:\/]/).map((d) => Number(d))), - ) - .default(dimensionsConfigDefault.aspect_ratio), + aspect_ratio: aspectRatioSchema.default(dimensionsConfigDefault.aspect_ratio), max_height: z.string().default(dimensionsConfigDefault.max_height), min_height: z.string().default(dimensionsConfigDefault.min_height), }) diff --git a/src/const.ts b/src/const.ts index 5addcfae..e7c9e330 100644 --- a/src/const.ts +++ b/src/const.ts @@ -11,6 +11,8 @@ export const CONF_CAMERAS_ARRAY_CAST_DASHBOARD_DASHBOARD_PATH = `${CONF_CAMERAS}.#.cast.dashboard.dashboard_path` as const; export const CONF_CAMERAS_ARRAY_CAST_DASHBOARD_VIEW_PATH = `${CONF_CAMERAS}.#.cast.dashboard.view_path` as const; +export const CONF_CAMERAS_ARRAY_DIMENSIONS_ASPECT_RATIO = + `${CONF_CAMERAS}.#.dimensions.aspect_ratio` as const; export const CONF_CAMERAS_ARRAY_FRIGATE_CLIENT_ID = `${CONF_CAMERAS}.#.frigate.client_id` as const; export const CONF_CAMERAS_ARRAY_FRIGATE_LABELS = @@ -48,6 +50,12 @@ export const CONF_CAMERAS_ARRAY_DEPENDENCIES_CAMERAS = `${CONF_CAMERAS}.#.dependencies.cameras` as const; export const CONF_CAMERAS_ARRAY_DEPENDENCIES_ALL_CAMERAS = `${CONF_CAMERAS}.#.dependencies.all_cameras` as const; +export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_FIT = + `${CONF_CAMERAS}.#.dimensions.layout.fit` as const; +export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_X = + `${CONF_CAMERAS}.#.dimensions.layout.position.x` as const; +export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_Y = + `${CONF_CAMERAS}.#.dimensions.layout.position.y` as const; export const CONF_CAMERAS_ARRAY_TRIGGERS_MOTION = `${CONF_CAMERAS}.#.triggers.motion` as const; export const CONF_CAMERAS_ARRAY_TRIGGERS_OCCUPANCY = @@ -66,6 +74,8 @@ export const CONF_CAMERAS_GLOBAL_TRIGGERS_OCCUPANCY = `${CONF_CAMERAS_GLOBAL}.triggers.occupancy` as const; export const CONF_CAMERAS_GLOBAL_IMAGE_REFRESH_SECONDS = `${CONF_CAMERAS_GLOBAL}.image.refresh_seconds` as const; +export const CONF_CAMERAS_GLOBAL_DIMENSIONS_LAYOUT = + `${CONF_CAMERAS_GLOBAL}.dimensions.layout` as const; export const CONF_ELEMENTS = 'elements' as const; @@ -163,11 +173,6 @@ export const CONF_MEDIA_VIEWER_CONTROLS_TITLE_MODE = `${CONF_MEDIA_VIEWER}.controls.title.mode` as const; export const CONF_MEDIA_VIEWER_CONTROLS_TITLE_DURATION_SECONDS = `${CONF_MEDIA_VIEWER}.controls.title.duration_seconds` as const; -export const CONF_MEDIA_VIEWER_LAYOUT_FIT = `${CONF_MEDIA_VIEWER}.layout.fit` as const; -export const CONF_MEDIA_VIEWER_LAYOUT_POSITION_X = - `${CONF_MEDIA_VIEWER}.layout.position.x` as const; -export const CONF_MEDIA_VIEWER_LAYOUT_POSITION_Y = - `${CONF_MEDIA_VIEWER}.layout.position.y` as const; const CONF_LIVE = 'live' as const; export const CONF_LIVE_AUTO_PLAY = `${CONF_LIVE}.auto_play` as const; @@ -228,9 +233,6 @@ export const CONF_LIVE_DISPLAY_GRID_MAX_COLUMNS = `${CONF_LIVE}.display.grid_max_columns` as const; export const CONF_LIVE_DISPLAY_GRID_SELECTED_WIDTH_FACTOR = `${CONF_LIVE}.display.grid_selected_width_factor` as const; -export const CONF_LIVE_LAYOUT_FIT = `${CONF_LIVE}.layout.fit` as const; -export const CONF_LIVE_LAYOUT_POSITION_X = `${CONF_LIVE}.layout.position.x` as const; -export const CONF_LIVE_LAYOUT_POSITION_Y = `${CONF_LIVE}.layout.position.y` as const; export const CONF_LIVE_DRAGGABLE = `${CONF_LIVE}.draggable` as const; export const CONF_LIVE_LAZY_LOAD = `${CONF_LIVE}.lazy_load` as const; export const CONF_LIVE_LAZY_UNLOAD = `${CONF_LIVE}.lazy_unload` as const; @@ -247,9 +249,6 @@ export const CONF_LIVE_MICROPHONE_ALWAYS_CONNECTED = export const CONF_LIVE_ZOOMABLE = `${CONF_LIVE}.zoomable` as const; const CONF_IMAGE = 'image' as const; -export const CONF_IMAGE_LAYOUT_FIT = `${CONF_IMAGE}.layout.fit` as const; -export const CONF_IMAGE_LAYOUT_POSITION_X = `${CONF_IMAGE}.layout.position.x` as const; -export const CONF_IMAGE_LAYOUT_POSITION_Y = `${CONF_IMAGE}.layout.position.y` as const; export const CONF_IMAGE_MODE = `${CONF_IMAGE}.mode` as const; export const CONF_IMAGE_REFRESH_SECONDS = `${CONF_IMAGE}.refresh_seconds` as const; export const CONF_IMAGE_URL = `${CONF_IMAGE}.url` as const; diff --git a/src/editor.ts b/src/editor.ts index 8c586f97..b9f9493a 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -22,9 +22,9 @@ import { } from './config-mgmt.js'; import { BUTTON_SIZE_MIN, - FRIGATE_MENU_PRIORITY_MAX, FrigateCardConfig, frigateCardConfigDefaults, + FRIGATE_MENU_PRIORITY_MAX, RawFrigateCardConfig, RawFrigateCardConfigArray, THUMBNAIL_WIDTH_MAX, @@ -38,6 +38,10 @@ import { CONF_CAMERAS_ARRAY_CAST_METHOD, CONF_CAMERAS_ARRAY_DEPENDENCIES_ALL_CAMERAS, CONF_CAMERAS_ARRAY_DEPENDENCIES_CAMERAS, + CONF_CAMERAS_ARRAY_DIMENSIONS_ASPECT_RATIO, + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_FIT, + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_X, + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_Y, CONF_CAMERAS_ARRAY_FRIGATE_CAMERA_NAME, CONF_CAMERAS_ARRAY_FRIGATE_CLIENT_ID, CONF_CAMERAS_ARRAY_FRIGATE_LABELS, @@ -67,9 +71,6 @@ import { CONF_DIMENSIONS_ASPECT_RATIO_MODE, CONF_DIMENSIONS_MAX_HEIGHT, CONF_DIMENSIONS_MIN_HEIGHT, - CONF_IMAGE_LAYOUT_FIT, - CONF_IMAGE_LAYOUT_POSITION_X, - CONF_IMAGE_LAYOUT_POSITION_Y, CONF_IMAGE_MODE, CONF_IMAGE_REFRESH_SECONDS, CONF_IMAGE_URL, @@ -108,9 +109,6 @@ import { CONF_LIVE_DISPLAY_GRID_SELECTED_WIDTH_FACTOR, CONF_LIVE_DISPLAY_MODE, CONF_LIVE_DRAGGABLE, - CONF_LIVE_LAYOUT_FIT, - CONF_LIVE_LAYOUT_POSITION_X, - CONF_LIVE_LAYOUT_POSITION_Y, CONF_LIVE_LAZY_LOAD, CONF_LIVE_LAZY_UNLOAD, CONF_LIVE_MICROPHONE_ALWAYS_CONNECTED, @@ -152,16 +150,13 @@ import { CONF_MEDIA_VIEWER_DISPLAY_GRID_SELECTED_WIDTH_FACTOR, CONF_MEDIA_VIEWER_DISPLAY_MODE, CONF_MEDIA_VIEWER_DRAGGABLE, - CONF_MEDIA_VIEWER_LAYOUT_FIT, - CONF_MEDIA_VIEWER_LAYOUT_POSITION_X, - CONF_MEDIA_VIEWER_LAYOUT_POSITION_Y, CONF_MEDIA_VIEWER_LAZY_LOAD, CONF_MEDIA_VIEWER_SNAPSHOT_CLICK_PLAYS_CLIP, CONF_MEDIA_VIEWER_TRANSITION_EFFECT, CONF_MEDIA_VIEWER_ZOOMABLE, CONF_MENU_ALIGNMENT, - CONF_MENU_BUTTON_SIZE, CONF_MENU_BUTTONS, + CONF_MENU_BUTTON_SIZE, CONF_MENU_POSITION, CONF_MENU_STYLE, CONF_PERFORMANCE_FEATURES_ANIMATED_PROGRESS_INDICATOR, @@ -213,6 +208,8 @@ const MENU_BUTTONS = 'buttons'; const MENU_CAMERAS = 'cameras'; const MENU_CAMERAS_CAST = 'cameras.cast'; const MENU_CAMERAS_DEPENDENCIES = 'cameras.dependencies'; +const MENU_CAMERAS_DIMENSIONS = 'cameras.dimensions'; +const MENU_CAMERAS_DIMENSIONS_LAYOUT = 'cameras.dimensions.layout'; const MENU_CAMERAS_ENGINE = 'cameras.engine'; const MENU_CAMERAS_FRIGATE = 'cameras.frigate'; const MENU_CAMERAS_GO2RTC = 'cameras.go2rtc'; @@ -221,7 +218,6 @@ const MENU_CAMERAS_LIVE_PROVIDER = 'cameras.live_provider'; const MENU_CAMERAS_MOTIONEYE = 'cameras.motioneye'; const MENU_CAMERAS_TRIGGERS = 'cameras.triggers'; const MENU_CAMERAS_WEBRTC_CARD = 'cameras.webrtc_card'; -const MENU_IMAGE_LAYOUT = 'image.layout'; const MENU_LIVE_CONTROLS = 'live.controls'; const MENU_LIVE_CONTROLS_NEXT_PREVIOUS = 'live.controls.next_previous'; const MENU_LIVE_CONTROLS_PTZ = 'live.controls.ptz'; @@ -229,7 +225,6 @@ const MENU_LIVE_CONTROLS_THUMBNAILS = 'live.controls.thumbnails'; const MENU_LIVE_CONTROLS_TIMELINE = 'live.controls.timeline'; const MENU_LIVE_CONTROLS_TITLE = 'live.controls.title'; const MENU_LIVE_DISPLAY = 'live.display'; -const MENU_LIVE_LAYOUT = 'live.layout'; const MENU_LIVE_MICROPHONE = 'live.microphone'; const MENU_MEDIA_GALLERY_CONTROLS_FILTER = 'media_gallery.controls.filter'; const MENU_MEDIA_GALLERY_CONTROLS_THUMBNAILS = 'media_gallery.controls.thumbnails'; @@ -239,7 +234,6 @@ const MENU_MEDIA_VIEWER_CONTROLS_THUMBNAILS = 'media_viewer.controls.thumbnails' const MENU_MEDIA_VIEWER_CONTROLS_TIMELINE = 'media_viewer.controls.timeline'; const MENU_MEDIA_VIEWER_CONTROLS_TITLE = 'media_viewer.controls.title'; const MENU_MEDIA_VIEWER_DISPLAY = 'media_viewer.display'; -const MENU_MEDIA_VIEWER_LAYOUT = 'media_viewer.layout'; const MENU_OPTIONS = 'options'; const MENU_PERFORMANCE_FEATURES = 'performance.features'; const MENU_PERFORMANCE_STYLE = 'performance.style'; @@ -576,9 +570,12 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor protected _layoutFits: EditorSelectOption[] = [ { value: '', label: '' }, - { value: 'contain', label: localize('config.common.layout.fits.contain') }, - { value: 'cover', label: localize('config.common.layout.fits.cover') }, - { value: 'fill', label: localize('config.common.layout.fits.fill') }, + { + value: 'contain', + label: localize('config.cameras.dimensions.layout.fits.contain'), + }, + { value: 'cover', label: localize('config.cameras.dimensions.layout.fits.cover') }, + { value: 'fill', label: localize('config.cameras.dimensions.layout.fits.fill') }, ]; protected _miniTimelineModes: EditorSelectOption[] = [ @@ -1167,17 +1164,17 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor { name: 'mdi:page-layout-body' }, html` ${this._renderOptionSelector(configPathFit, this._layoutFits, { - label: localize('config.common.layout.fit'), + label: localize('config.cameras.dimensions.layout.fit'), })} ${this._renderNumberInput(configPathPositionX, { min: 0, max: 100, - label: localize('config.common.layout.position.x'), + label: localize('config.cameras.dimensions.layout.position.x'), })} ${this._renderNumberInput(configPathPositionY, { min: 0, max: 100, - label: localize('config.common.layout.position.y'), + label: localize('config.cameras.dimensions.layout.position.y'), })} `, ); @@ -1854,10 +1851,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor }, )} ${this._renderOptionSelector( - getArrayConfigPath( - CONF_CAMERAS_ARRAY_TRIGGERS_EVENTS, - cameraIndex, - ), + getArrayConfigPath(CONF_CAMERAS_ARRAY_TRIGGERS_EVENTS, cameraIndex), this._triggersEvents, { multiple: true, @@ -1890,6 +1884,27 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor )} `, )} + ${this._putInSubmenu( + MENU_CAMERAS_DIMENSIONS, + cameraIndex, + 'config.cameras.dimensions.editor_label', + { name: 'mdi:aspect-ratio' }, + html` + ${this._renderStringInput( + getArrayConfigPath( + CONF_CAMERAS_ARRAY_DIMENSIONS_ASPECT_RATIO, + cameraIndex, + ), + )} + ${this._renderMediaLayout( + MENU_CAMERAS_DIMENSIONS_LAYOUT, + 'config.cameras.dimensions.layout.editor_label', + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_FIT, + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_X, + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_Y, + )} + `, + )}
` : ``} @@ -2237,13 +2252,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor )} `, )} - ${this._renderMediaLayout( - MENU_LIVE_LAYOUT, - 'config.live.layout', - CONF_LIVE_LAYOUT_FIT, - CONF_LIVE_LAYOUT_POSITION_X, - CONF_LIVE_LAYOUT_POSITION_Y, - )} ${this._putInSubmenu( MENU_LIVE_MICROPHONE, true, @@ -2389,13 +2397,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor )} `, )} - ${this._renderMediaLayout( - MENU_MEDIA_VIEWER_LAYOUT, - 'config.media_viewer.layout', - CONF_MEDIA_VIEWER_LAYOUT_FIT, - CONF_MEDIA_VIEWER_LAYOUT_POSITION_X, - CONF_MEDIA_VIEWER_LAYOUT_POSITION_Y, - )} ` : ''} ${this._renderOptionSetHeader('image')} @@ -2405,13 +2406,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderStringInput(CONF_IMAGE_URL)} ${this._renderNumberInput(CONF_IMAGE_REFRESH_SECONDS)} ${this._renderSwitch(CONF_IMAGE_ZOOMABLE, this._defaults.image.zoomable)} - ${this._renderMediaLayout( - MENU_IMAGE_LAYOUT, - 'config.image.layout', - CONF_IMAGE_LAYOUT_FIT, - CONF_IMAGE_LAYOUT_POSITION_X, - CONF_IMAGE_LAYOUT_POSITION_Y, - )} ` : ''} ${this._renderOptionSetHeader('timeline')} diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index ee928903..6e41fb24 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -15,7 +15,7 @@ "dashboard_path": "Dashboard path", "view_path": "View path" }, - "editor_label": "Cast Options", + "editor_label": "Cast options", "method": "Cast method", "methods": { "dashboard": "Dashboard", @@ -25,7 +25,24 @@ "dependencies": { "all_cameras": "Show events for all cameras with this camera", "cameras": "Show events for specific cameras with this camera", - "editor_label": "Dependency Options" + "editor_label": "Dependency options" + }, + "dimensions": { + "aspect_ratio": "Static aspect ratio", + "editor_label": "Camera dimensions", + "layout": { + "editor_label": "Camera Layout", + "fit": "Layout fit", + "fits": { + "contain": "Media is contained/letterboxed", + "cover": "Media expands proportionally to cover the card", + "fill": "Media is stretched to fill the card" + }, + "position": { + "x": "Horizontal placement percentage", + "y": "Vertical placement percentage" + } + } }, "engines": { "editor_label": "Camera engine options" @@ -83,7 +100,7 @@ }, "title": "Title for this camera (Autodetected from entity)", "triggers": { - "editor_label": "Trigger Options", + "editor_label": "Trigger options", "entities": "Trigger from other entities", "events": { "clips": "Events with new clips", @@ -178,18 +195,6 @@ "grid_selected_width_factor": "Increase selected media width by this factor", "mode": "Mode" }, - "layout": { - "fit": "Layout fit", - "fits": { - "contain": "Media is contained/letterboxed", - "cover": "Media expands proportionally to cover the card", - "fill": "Media is stretched to fill the card" - }, - "position": { - "x": "Horizontal placement percentage", - "y": "Vertical placement percentage" - } - }, "media_action_conditions": { "all": "All opportunities", "hidden": "On browser/tab hiding", @@ -229,7 +234,6 @@ "min_height": "Minimum card height in CSS units (e.g. '100px')" }, "image": { - "layout": "Image Layout", "mode": "Image view mode", "modes": { "camera": "Home Assistant camera snapshot of camera entity", @@ -272,7 +276,6 @@ } }, "draggable": "Live cameras view can be dragged/swiped", - "layout": "Live Layout", "lazy_load": "Live cameras are lazily loaded", "lazy_unload": "Live cameras are lazily unloaded", "microphone": { @@ -296,7 +299,6 @@ "editor_label": "Media Viewer Controls" }, "draggable": "Media Viewer can be dragged/swiped", - "layout": "Media Viewer Layout", "lazy_load": "Media Viewer media is lazily loaded in carousel", "snapshot_click_plays_clip": "Clicking on a snapshot plays a related clip", "transition_effect": "Media Viewer transition effect", @@ -454,8 +456,8 @@ "cameras": "Cameras", "cameras_secondary": "What cameras to render on this card", "delete": "Delete", - "dimensions": "Dimensions", - "dimensions_secondary": "Dimensions & shape options", + "dimensions": "Card dimensions", + "dimensions_secondary": "Card dimensions & shape options", "image": "Image", "image_secondary": "Static image view options", "live": "Live", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 97558030..76f7fa6c 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -27,6 +27,22 @@ "cameras": "Mostra eventi per telecamere specifiche con questa telecamera", "editor_label": "Opzioni di dipendenza" }, + "dimensions": { + "editor_label": "", + "aspect_ratio": "", + "layout": { + "fit": "Adatta al layout", + "fits": { + "contain": "Il supporto è contenuto/in cassetta delle lettere", + "cover": "Il supporto si espande proporzionalmente per coprire la scheda", + "fill": "Il supporto viene allungato per riempire la scheda" + }, + "position": { + "x": "Percentuale di posizionamento orizzontale", + "y": "Percentuale di posizionamento verticale" + } + } + }, "engines": { "editor_label": "Opzioni del motore della fotocamera" }, @@ -178,18 +194,6 @@ "grid_selected_width_factor": "", "mode": "" }, - "layout": { - "fit": "Adatta al layout", - "fits": { - "contain": "Il supporto è contenuto/in cassetta delle lettere", - "cover": "Il supporto si espande proporzionalmente per coprire la scheda", - "fill": "Il supporto viene allungato per riempire la scheda" - }, - "position": { - "x": "Percentuale di posizionamento orizzontale", - "y": "Percentuale di posizionamento verticale" - } - }, "media_action_conditions": { "all": "Tutte le opportunità", "hidden": "Sul browser/nascondere le schede", @@ -229,7 +233,6 @@ "min_height": "" }, "image": { - "layout": "Disposizione dell'immagine", "mode": "Modalità Visualizza immagine", "modes": { "camera": "Istantanea della telecamera di Home Assistant dell'entità telecamera", @@ -272,7 +275,6 @@ } }, "draggable": "Il Visualizzatore eventi può essere trascinato oppure puoi scorrere", - "layout": "Disposizione dal vivo", "lazy_load": "Le telecamere dal vivo sono pigramente cariche", "lazy_unload": "Le telecamere dal vivo sono pigramente non caricate", "microphone": { @@ -296,7 +298,6 @@ "editor_label": "Controlli di visualizzatore multimediale" }, "draggable": "Il visualizzatore multimediale può essere trascinato oppure può scorrere", - "layout": "Layout del visualizzatore multimediale", "lazy_load": "Il media Viewer viene caricato pigramente nel carosello", "transition_effect": "Effetto di transizione del visualizzatore multimediale", "transition_effects": { @@ -448,8 +449,8 @@ "cameras": "Telecamere", "cameras_secondary": "Quali telecamere visualizzare su questa card", "delete": "Elimina", - "dimensions": "Dimensioni", - "dimensions_secondary": "Dimensioni e opzioni di forma", + "dimensions": "", + "dimensions_secondary": "", "image": "Immagine", "image_secondary": "Opzioni di visualizzazione dell'immagine statica", "live": "Live", @@ -584,4 +585,4 @@ }, "select_date": "Scegli la data" } -} \ No newline at end of file +} diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 3041dd2f..0243437f 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -27,6 +27,22 @@ "cameras": "Mostrar eventos para câmeras específicas nesta câmera", "editor_label": "Opções de dependência" }, + "dimensions": { + "editor_label": "", + "aspect_ratio": "", + "layout": { + "fit": "Ajuste de layout", + "fits": { + "contain": "A mídia é contida no cartão", + "cover": "A mídia se expande proporcionalmente para cobrir o cartão", + "fill": "A mídia é esticada para preencher o cartão" + }, + "position": { + "x": "Porcentagem do posicionamento horizontal", + "y": "Porcentagem do posicionamento vertical" + } + } + }, "engines": { "editor_label": "Opções do motor da câmera" }, @@ -178,18 +194,6 @@ "grid_selected_width_factor": "", "mode": "" }, - "layout": { - "fit": "Ajuste de layout", - "fits": { - "contain": "A mídia é contida no cartão", - "cover": "A mídia se expande proporcionalmente para cobrir o cartão", - "fill": "A mídia é esticada para preencher o cartão" - }, - "position": { - "x": "Porcentagem do posicionamento horizontal", - "y": "Porcentagem do posicionamento vertical" - } - }, "media_action_conditions": { "all": "Todas as oportunidades", "hidden": "Ao ocultar o navegador/aba", @@ -229,7 +233,6 @@ "min_height": "" }, "image": { - "layout": "Layout da imagem", "mode": "Modo de visualização de imagem", "modes": { "camera": "Instantâneo da câmera do Home Assistant, da entidade de câmera", @@ -272,7 +275,6 @@ } }, "draggable": "A visualização ao vivo das câmeras pode ser arrastada/deslizada", - "layout": "Layout dinâmico", "lazy_load": "As câmeras ao vivo são carregadas lentamente", "lazy_unload": "As câmeras ao vivo são descarregadas preguiçosamente", "microphone": { @@ -296,7 +298,6 @@ "editor_label": "Controles do visualizador de mídia" }, "draggable": "Visualizador de eventos pode ser arrastado/deslizado", - "layout": "Layout do visualizador de mídia", "lazy_load": "A mídia do Visualizador de eventos é carregada lentamente no carrossel", "snapshot_click_plays_clip": "Clicar em um instantâneo reproduz um clipe relacionado", "transition_effect": "Efeito de transição do Visualizador de eventos", @@ -453,8 +454,8 @@ "cameras": "Câmeras", "cameras_secondary": "Quais câmeras renderizar neste cartão", "delete": "Excluir", - "dimensions": "Dimensões", - "dimensions_secondary": "Dimensões e opções de forma", + "dimensions": "", + "dimensions_secondary": "", "image": "Imagem", "image_secondary": "Opções de visualização de imagem estática", "live": "Ao vivo", @@ -594,4 +595,4 @@ }, "select_date": "Escolha a data" } -} \ No newline at end of file +} diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 78a11864..00d9b704 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -27,6 +27,22 @@ "cameras": "Mostrar eventos para câmeras específicas nesta câmera", "editor_label": "Opções de dependência" }, + "dimensions": { + "editor_label": "", + "aspect_ratio": "", + "layout": { + "fit": "Fit", + "fits": { + "contain": "Conter", + "cover": "Tapar", + "fill": "Preencher" + }, + "position": { + "x": "Percentagem da localização horizontal", + "y": "Percentagem da localização vertical" + } + } + }, "engines": { "editor_label": "Editor de etiquetas" }, @@ -178,18 +194,6 @@ "grid_selected_width_factor": "", "mode": "" }, - "layout": { - "fit": "Fit", - "fits": { - "contain": "Conter", - "cover": "Tapar", - "fill": "Preencher" - }, - "position": { - "x": "Percentagem da localização horizontal", - "y": "Percentagem da localização vertical" - } - }, "media_action_conditions": { "all": "Todas as oportunidades", "hidden": "Ao ocultar o navegador/aba", @@ -222,7 +226,6 @@ } }, "image": { - "layout": "Layout", "mode": "Modo de visualização de imagem", "modes": { "camera": "Instantâneo da câmera do Home Assistant, da entidade de câmera", @@ -265,7 +268,6 @@ } }, "draggable": "A visualização ao vivo das câmeras pode ser arrastada/deslizada", - "layout": "layout", "lazy_load": "As câmeras ao vivo são carregadas lentamente", "lazy_unload": "As câmeras ao vivo são descarregadas preguiçosamente", "microphone": { @@ -289,7 +291,6 @@ "editor_label": "Controles do visualizador de mídia" }, "draggable": "Visualizador de eventos pode ser arrastado/deslizado", - "layout": "Layout", "lazy_load": "A mídia do Visualizador de eventos é carregada lentamente no carrossel", "transition_effect": "Efeito de transição do Visualizador de eventos", "transition_effects": { @@ -441,8 +442,8 @@ "cameras": "Câmeras", "cameras_secondary": "Câmeras para renderizar neste cartão", "delete": "Excluir", - "dimensions": "Dimensões", - "dimensions_secondary": "Dimensões e opções de forma", + "dimensions": "", + "dimensions_secondary": "", "image": "Imagem", "image_secondary": "Opções de visualização de imagem estática", "live": "Ao vivo", @@ -576,4 +577,4 @@ }, "select_date": "Selecionar a data" } -} \ No newline at end of file +} diff --git a/src/scss/live-carousel.scss b/src/scss/live-carousel.scss index 79c460f2..a6b9f29a 100644 --- a/src/scss/live-carousel.scss +++ b/src/scss/live-carousel.scss @@ -3,6 +3,12 @@ --video-max-height: none; } +// When the carousel is not part of a grid ensure its height matches its +// container. +:host(:not([grid-id])) { + height: 100%; +} + // If the carousel has an unselected attribute set on it, do not let the // pointer interact (e.g. hover, scroll) with underlying elements. This is used // when the carousel is part of a media-grid. Without this next/prev controls @@ -13,6 +19,11 @@ } .embla__slide { + // Center the content horizontally (for cases where the configured aspect + // ratio is a mismatch with the card). + display: flex; + justify-content: center; + height: 100%; flex: 0 0 100%; } diff --git a/src/scss/live-provider.scss b/src/scss/live-provider.scss index 3ac357c1..15c43662 100644 --- a/src/scss/live-provider.scss +++ b/src/scss/live-provider.scss @@ -1,7 +1,7 @@ :host { display: block; height: 100%; - width: 100; + width: 100%; } .hidden { diff --git a/src/utils/basic.ts b/src/utils/basic.ts index a977e9e6..9c074f54 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -2,6 +2,7 @@ import differenceInHours from 'date-fns/differenceInHours'; import differenceInMinutes from 'date-fns/differenceInMinutes'; import differenceInSeconds from 'date-fns/differenceInSeconds'; import format from 'date-fns/format'; +import { StyleInfo } from 'lit/directives/style-map'; import isEqual from 'lodash-es/isEqual'; import mergeWith from 'lodash-es/mergeWith'; import { FrigateCardError } from '../types'; @@ -245,3 +246,25 @@ export const getChildrenFromElement = (parent: HTMLElement): HTMLElement[] => { export const recursivelyMergeObjectsNotArrays = (src1: T, src2: T): T => { return mergeWith({}, src1, src2, (_a, b) => (Array.isArray(b) ? b : undefined)); }; + +export const aspectRatioToString = (options?: { + ratio?: number[]; + defaultStatic?: boolean; +}): string => { + if (options?.ratio && options.ratio.length === 2) { + return `${options.ratio[0]} / ${options.ratio[1]}`; + } else if (options?.defaultStatic) { + return '16 / 9'; + } else { + return 'auto'; + } +}; + +export const aspectRatioToStyle = (options?: { + ratio?: number[]; + defaultStatic?: boolean; +}): StyleInfo => { + return { + 'aspect-ratio': aspectRatioToString(options), + }; +}; diff --git a/tests/card-controller/style-manager.test.ts b/tests/card-controller/style-manager.test.ts index 475a3a9f..23a58bae 100644 --- a/tests/card-controller/style-manager.test.ts +++ b/tests/card-controller/style-manager.test.ts @@ -245,7 +245,7 @@ describe('StyleManager', () => { it('without config or view', () => { const api = createCardAPI(); const manager = new StyleManager(api); - expect(manager.getAspectRatioStyle()).toBe('16 / 9'); + expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': '16 / 9' }); }); it('should be auto with unconstrained aspect ratio', () => { @@ -260,7 +260,7 @@ describe('StyleManager', () => { }), ); const manager = new StyleManager(api); - expect(manager.getAspectRatioStyle()).toBe('auto'); + expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': 'auto' }); }); it('should be auto in fullscreen', () => { @@ -271,7 +271,7 @@ describe('StyleManager', () => { vi.mocked(api.getFullscreenManager().isInFullscreen).mockReturnValue(true); const manager = new StyleManager(api); - expect(manager.getAspectRatioStyle()).toBe('auto'); + expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': 'auto' }); }); it('should be auto when expanded', () => { @@ -282,7 +282,7 @@ describe('StyleManager', () => { vi.mocked(api.getExpandManager().isExpanded).mockReturnValue(true); const manager = new StyleManager(api); - expect(manager.getAspectRatioStyle()).toBe('auto'); + expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': 'auto' }); }); it('should be auto when there is yet to be a view', () => { @@ -291,7 +291,7 @@ describe('StyleManager', () => { vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); const manager = new StyleManager(api); - expect(manager.getAspectRatioStyle()).toBe('auto'); + expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': 'auto' }); }); describe('should be auto when dynamic in certain views', () => { @@ -317,7 +317,7 @@ describe('StyleManager', () => { ); const manager = new StyleManager(api); - expect(manager.getAspectRatioStyle()).toBe('auto'); + expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': 'auto' }); }); }); @@ -337,7 +337,7 @@ describe('StyleManager', () => { ); const manager = new StyleManager(api); - expect(manager.getAspectRatioStyle()).toBe('16 / 9'); + expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': '16 / 9' }); }, ); }); @@ -362,7 +362,9 @@ describe('StyleManager', () => { }); const manager = new StyleManager(api); - expect(manager.getAspectRatioStyle()).toBe('800 / 600'); + expect(manager.getAspectRatioStyle()).toEqual({ + 'aspect-ratio': '800 / 600', + }); }, ); }); @@ -381,7 +383,7 @@ describe('StyleManager', () => { ); const manager = new StyleManager(api); - expect(manager.getAspectRatioStyle()).toBe('4 / 3'); + expect(manager.getAspectRatioStyle()).toEqual({ 'aspect-ratio': '4 / 3' }); }); }); }); diff --git a/tests/config-mgmt.test.ts b/tests/config-mgmt.test.ts index 9ca34a98..1b3af522 100644 --- a/tests/config-mgmt.test.ts +++ b/tests/config-mgmt.test.ts @@ -1738,5 +1738,59 @@ describe('should handle version specific upgrades', () => { }); }); }); + + describe('should handle media layout changes', () => { + it('from live.layout to camera_global.dimensions', () => { + const config = { + live: { + layout: { + fit: 'cover', + position: { + x: 42, + y: 43, + }, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + live: {}, + cameras_global: { + dimensions: { + layout: { + fit: 'cover', + position: { + x: 42, + y: 43, + }, + }, + }, + }, + }); + }); + + describe('from delete old media layouts', () => { + it.each([['media_viewer' as const], ['image' as const]])( + '%s', + (section: string) => { + const config = { + [section]: { + layout: { + fit: 'cover', + position: { + x: 42, + y: 43, + }, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + [section]: {}, + }); + }, + ); + }); + }); }); }); diff --git a/tests/utils/basic.test.ts b/tests/utils/basic.test.ts index 4961b777..4bbadfe6 100644 --- a/tests/utils/basic.test.ts +++ b/tests/utils/basic.test.ts @@ -2,8 +2,9 @@ import { afterAll, describe, expect, it, vi } from 'vitest'; import { FrigateCardError } from '../../src/types'; import { allPromises, - arrayMove, arrayify, + arrayMove, + aspectRatioToStyle, contentsChanged, dayToDate, dispatchFrigateCardEvent, @@ -12,16 +13,16 @@ import { formatDateAndTime, getChildrenFromElement, getDurationString, - isHTMLElement, isHoverableDevice, + isHTMLElement, isSuperset, isTruthy, isValidDate, prettifyTitle, recursivelyMergeObjectsNotArrays, runWhenIdleIfSupported, - setOrRemoveAttribute, setify, + setOrRemoveAttribute, sleep, } from '../../src/utils/basic'; import { createSlot, createSlotHost } from '../test-utils'; @@ -338,3 +339,20 @@ describe('recursivelyMergeObjectsNotArrays', () => { }); }); }); + +describe('aspectRatioToStyle', () => { + it('default', () => { + expect(aspectRatioToStyle()).toEqual({ 'aspect-ratio': 'auto' }); + }); + it('default static', () => { + expect(aspectRatioToStyle({ defaultStatic: true })).toEqual({ + 'aspect-ratio': '16 / 9', + }); + }); + it('valid ratio', () => { + expect(aspectRatioToStyle({ ratio: [4, 3] })).toEqual({ 'aspect-ratio': '4 / 3' }); + }); + it('invalid ratio', () => { + expect(aspectRatioToStyle({ ratio: [4] })).toEqual({ 'aspect-ratio': 'auto' }); + }); +}); diff --git a/vite.config.ts b/vite.config.ts index ca89f07f..29404bb3 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -20,7 +20,6 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'config-mgmt.ts', 'config/types.ts', 'const.ts', - 'src/view/*.ts', 'types.ts', 'utils/action.ts', 'utils/audio.ts', @@ -40,6 +39,7 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'utils/substream.ts', 'utils/timer.ts', 'utils/zod.ts', + 'view/*.ts', ]; interface Threshold { @@ -80,13 +80,13 @@ export default defineConfig({ // Expected thresholds for anything that does not have 100% coverage // yet. - statements: 15.54, - branches: 10.38, - functions: 16.18, - lines: 15.84, + statements: 10.67, + branches: 4.9, + functions: 7.81, + lines: 10.92, ...calculateFullCoverageThresholds(), }, }, }, -}); \ No newline at end of file +}); From b08a8f55c3d3ab915423e82e6056b619ff977f7c Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Thu, 7 Mar 2024 06:46:02 -0800 Subject: [PATCH 098/189] Fix minor type errors. --- src/components/elements.ts | 6 +++--- src/components/image.ts | 2 -- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/elements.ts b/src/components/elements.ts index d8d7b563..9e3adf1d 100644 --- a/src/components/elements.ts +++ b/src/components/elements.ts @@ -70,7 +70,7 @@ interface HuiConditionalElement extends HTMLElement { @customElement('frigate-card-elements-core') export class FrigateCardElementsCore extends LitElement { @property({ attribute: false }) - public elements: PictureElements; + public elements?: PictureElements; /** * Need to ensure card re-renders when conditions change, hence having it as a @@ -275,10 +275,10 @@ export class FrigateCardElementsConditional extends LitElement { * Render the card. */ protected render(): TemplateResult | void { - if (evaluateConditionViaEvent(this, this._config.conditions)) { + if (evaluateConditionViaEvent(this, this._config?.conditions)) { return html` `; } diff --git a/src/components/image.ts b/src/components/image.ts index 5bdff165..0ba8bbcf 100644 --- a/src/components/image.ts +++ b/src/components/image.ts @@ -26,7 +26,6 @@ import { dispatchMediaPauseEvent, dispatchMediaPlayEvent, } from '../utils/media-info.js'; -import { updateElementStyleFromMediaLayoutConfig } from '../utils/media-layout.js'; import { View } from '../view/view.js'; import { dispatchErrorMessageEvent } from './message.js'; @@ -153,7 +152,6 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay () => dispatchMediaPauseEvent(this), ); } - updateElementStyleFromMediaLayoutConfig(this, this.imageConfig?.layout); if (changedProps.has('imageConfig') && this.imageConfig?.zoomable) { import('./zoomer.js'); From ecdd02c7ce513b340db696ccf219ee63177d7c37 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Fri, 8 Mar 2024 20:00:35 -0800 Subject: [PATCH 099/189] Always render a view even if default is unsupported. --- src/camera-manager/frigate/camera.ts | 2 +- src/camera-manager/store.ts | 5 ++ src/card-controller/initialization-manager.ts | 2 +- src/card-controller/view-manager.ts | 26 ++++++++-- tests/camera-manager/frigate/camera.test.ts | 8 ++- tests/camera-manager/store.test.ts | 11 ++++ tests/card-controller/view-manager.test.ts | 51 +++++++++++++++++++ 7 files changed, 98 insertions(+), 7 deletions(-) diff --git a/src/camera-manager/frigate/camera.ts b/src/camera-manager/frigate/camera.ts index 35eb4a29..50a62cca 100644 --- a/src/camera-manager/frigate/camera.ts +++ b/src/camera-manager/frigate/camera.ts @@ -128,7 +128,7 @@ export class FrigateCamera extends Camera { hass: HomeAssistant, cameraConfig: CameraConfig, ): Promise { - if (!cameraConfig.frigate.camera_name) { + if (!cameraConfig.frigate.camera_name || isBirdseye(cameraConfig)) { return null; } diff --git a/src/camera-manager/store.ts b/src/camera-manager/store.ts index c27e3ebe..1f5d2846 100644 --- a/src/camera-manager/store.ts +++ b/src/camera-manager/store.ts @@ -24,6 +24,7 @@ export interface CameraManagerReadOnlyConfigStore { getCameraIDs(): Set; getVisibleCameraIDs(): Set; + getDefaultCameraID(): string | null; getAllDependentCameras(cameraID: string): Set; } @@ -61,6 +62,10 @@ export class CameraManagerStore implements CameraManagerReadOnlyConfigStore { return this.getVisibleCameraIDs().size; } + public getDefaultCameraID(): string | null { + return this._cameras.keys().next().value ?? null; + } + public getCameras(): Map { return this._cameras; } diff --git a/src/card-controller/initialization-manager.ts b/src/card-controller/initialization-manager.ts index aba58c22..3c640198 100644 --- a/src/card-controller/initialization-manager.ts +++ b/src/card-controller/initialization-manager.ts @@ -98,7 +98,7 @@ export class InitializationManager { if (hasViewRelatedActions) { this._api.getQueryStringManager().executeViewRelated(); } else { - this._api.getViewManager().setViewDefault(); + this._api.getViewManager().setViewDefault({ failSafe: true }); } } diff --git a/src/card-controller/view-manager.ts b/src/card-controller/view-manager.ts index fe5c9657..a9a6e13f 100644 --- a/src/card-controller/view-manager.ts +++ b/src/card-controller/view-manager.ts @@ -1,13 +1,23 @@ import { ViewContext } from 'view'; -import { FrigateCardConfig, FrigateCardView, ViewDisplayMode } from '../config/types'; -import { View } from '../view/view'; +import { + FRIGATE_CARD_VIEW_DEFAULT, + FrigateCardConfig, + FrigateCardView, + ViewDisplayMode, +} from '../config/types'; import { log } from '../utils/debug'; import { executeMediaQueryForView } from '../utils/media-to-view'; +import { View } from '../view/view'; import { CardViewAPI } from './types'; interface ViewManagerSetViewDefaultParameters { cameraID?: string; substream?: string; + + // When failSafe is true, the view will be changed to an "always-works" view + // (e.g. `live`) if the proposed view is unsupported. By default the view will + // just not be changed. + failSafe?: boolean; } export interface ViewManagerSetViewParameters @@ -75,8 +85,16 @@ export class ViewManager { cameraID = cameras.keys().next().value; } } - const viewName = params?.viewName ?? this._view?.view ?? config.view.default; - if (cameraID && viewName && this.isViewSupportedByCamera(cameraID, viewName)) { + let viewName = params?.viewName ?? this._view?.view ?? config.view.default; + if (cameraID && viewName) { + if (!this.isViewSupportedByCamera(cameraID, viewName)) { + if (params.failSafe) { + viewName = FRIGATE_CARD_VIEW_DEFAULT; + } else { + return; + } + } + const displayMode = this._view?.displayMode ?? this._getDefaultDisplayModeForView(viewName, config); diff --git a/tests/camera-manager/frigate/camera.test.ts b/tests/camera-manager/frigate/camera.test.ts index f9698fcf..bfa8bdbe 100644 --- a/tests/camera-manager/frigate/camera.test.ts +++ b/tests/camera-manager/frigate/camera.test.ts @@ -143,13 +143,18 @@ describe('FrigateCamera', () => { it('basic non-birdseye', async () => { const camera = new FrigateCamera( - createCameraConfig(), + createCameraConfig({ + frigate: { + camera_name: 'front_door', + }, + }), mock(), ); await camera.initialize(createHASS(), mock()); expect(camera.getCapabilities()).toEqual(nonBirdseyeBaseCapabilities); + expect(vi.mocked(getPTZInfo)).toBeCalled(); }); it('basic birdseye', async () => { @@ -173,6 +178,7 @@ describe('FrigateCamera', () => { supportsRecordings: false, supportsTimeline: false, }); + expect(vi.mocked(getPTZInfo)).not.toBeCalled(); }); describe('with ptz', () => { diff --git a/tests/camera-manager/store.test.ts b/tests/camera-manager/store.test.ts index fa67beab..02b37e51 100644 --- a/tests/camera-manager/store.test.ts +++ b/tests/camera-manager/store.test.ts @@ -61,6 +61,17 @@ describe('CameraManagerStore', async () => { expect(store.getVisibleCameraCount()).toBe(1); }); + describe('getDefaultCameraID', () => { + it('with camera', async () => { + const store = setupStore(); + expect(store.getDefaultCameraID()).toBe('camera-visible'); + }); + it('without camera', async () => { + const store = new CameraManagerStore(); + expect(store.getDefaultCameraID()).toBeNull(); + }); + }); + describe('getCamera', async () => { it('present', async () => { const store = setupStore(); diff --git a/tests/card-controller/view-manager.test.ts b/tests/card-controller/view-manager.test.ts index 07844a7a..883954c7 100644 --- a/tests/card-controller/view-manager.test.ts +++ b/tests/card-controller/view-manager.test.ts @@ -324,6 +324,57 @@ describe('ViewManager.setViewByParameters', () => { expect(manager.getView()).toBeNull(); }); + describe('should handle unsupported view', () => { + it('without failsafe', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + }, + ]), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue(createCameraCapabilities({ + supportsSnapshots: false, + })); + + const manager = new ViewManager(api); + manager.setViewByParameters({ + viewName: 'snapshots', + }); + + expect(manager.hasView()).toBeFalsy(); + expect(manager.getView()).toBeNull(); + }); + + it('with failsafe', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + }, + ]), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue(createCameraCapabilities({ + supportsSnapshots: false, + })); + + const manager = new ViewManager(api); + manager.setViewByParameters({ + viewName: 'snapshots', + failSafe: true, + }); + + expect(manager.hasView()).toBeTruthy(); + expect(manager.getView()?.view).toBe('live'); + }); + }); + describe('should set view by parameters and respect display mode in config for view', () => { it.each([ ['media' as const], From 6ed1c90554ee265f0c8e9dfeaeeb2887027fe4c0 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 9 Mar 2024 19:57:14 -0800 Subject: [PATCH 100/189] Ensure timeline menu buttons shows up when it should. --- src/card-controller/actions-manager.ts | 9 +- src/card-controller/view-manager.ts | 28 +- src/card.ts | 1 + src/components-lib/menu-button-controller.ts | 36 +- tests/card-controller/actions-manager.test.ts | 31 +- tests/card-controller/view-manager.test.ts | 41 +- .../menu-button-controller.test.ts | 2132 +++++++++-------- 7 files changed, 1208 insertions(+), 1070 deletions(-) diff --git a/src/card-controller/actions-manager.ts b/src/card-controller/actions-manager.ts index a40ab535..89060699 100644 --- a/src/card-controller/actions-manager.ts +++ b/src/card-controller/actions-manager.ts @@ -3,7 +3,6 @@ import { ActionsConfig, ActionType, FrigateCardCustomAction, - FRIGATE_CARD_VIEW_DEFAULT, } from '../config/types.js'; import { convertActionToFrigateCardCustomAction, @@ -177,14 +176,10 @@ export class ActionsManager { const viewOnCameraSelect = config?.view.camera_select ?? 'current'; const targetViewName = viewOnCameraSelect === 'current' ? view.view : viewOnCameraSelect; - const verifiedViewName = this._api - .getViewManager() - .isViewSupportedByCamera(selectCameraID, targetViewName) - ? targetViewName - : FRIGATE_CARD_VIEW_DEFAULT; this._api.getViewManager().setViewByParameters({ - viewName: verifiedViewName, + viewName: targetViewName, cameraID: selectCameraID, + failSafe: true, }); } break; diff --git a/src/card-controller/view-manager.ts b/src/card-controller/view-manager.ts index a9a6e13f..463e626f 100644 --- a/src/card-controller/view-manager.ts +++ b/src/card-controller/view-manager.ts @@ -190,7 +190,17 @@ export class ViewManager { } public isViewSupportedByCamera(cameraID: string, view: FrigateCardView): boolean { - const capabilities = this._api.getCameraManager().getCameraCapabilities(cameraID); + const dependentCamerasCapabilities = this._api + .getCameraManager() + .getAggregateCameraCapabilities( + this._api.getCameraManager().getStore().getAllDependentCameras(cameraID), + ); + const allCamerasCapabilities = this._api + .getCameraManager() + .getAggregateCameraCapabilities( + this._api.getCameraManager().getStore().getCameraIDs(), + ); + switch (view) { case 'live': case 'image': @@ -198,20 +208,22 @@ export class ViewManager { return true; case 'clip': case 'clips': - return !!capabilities?.supportsClips; + return !!dependentCamerasCapabilities?.supportsClips; case 'snapshot': case 'snapshots': - return !!capabilities?.supportsSnapshots; + return !!dependentCamerasCapabilities?.supportsSnapshots; case 'recording': case 'recordings': - return !!capabilities?.supportsRecordings; + return !!dependentCamerasCapabilities?.supportsRecordings; case 'timeline': - return !!capabilities?.supportsTimeline; + // Show the timeline if any camera supports it, even cameras unrelated + // to the currently selected camera. + return !!allCamerasCapabilities?.supportsTimeline; case 'media': return ( - !!capabilities?.supportsClips || - !!capabilities?.supportsSnapshots || - !!capabilities?.supportsRecordings + !!dependentCamerasCapabilities?.supportsClips || + !!dependentCamerasCapabilities?.supportsSnapshots || + !!dependentCamerasCapabilities?.supportsRecordings ); } } diff --git a/src/card.ts b/src/card.ts index e4973c99..beb6ed21 100644 --- a/src/card.ts +++ b/src/card.ts @@ -209,6 +209,7 @@ class FrigateCard extends LitElement { showCameraUIButton: this._controller.getCameraURLManager().hasCameraURL(), mediaPlayerController: this._controller.getMediaPlayerManager(), microphoneManager: this._controller.getMicrophoneManager(), + viewManager: this._controller.getViewManager(), }, )} .entityRegistryManager=${this._controller.getEntityRegistryManager()} diff --git a/src/components-lib/menu-button-controller.ts b/src/components-lib/menu-button-controller.ts index 56639fb6..cfe3c385 100644 --- a/src/components-lib/menu-button-controller.ts +++ b/src/components-lib/menu-button-controller.ts @@ -3,10 +3,11 @@ import { StyleInfo } from 'lit/directives/style-map'; import { CameraManager } from '../camera-manager/manager'; import { MediaPlayerManager } from '../card-controller/media-player-manager'; import { MicrophoneManager } from '../card-controller/microphone-manager'; +import { ViewManager } from '../card-controller/view-manager'; import { + FRIGATE_CARD_VIEWS_USER_SPECIFIED, FrigateCardConfig, FrigateCardCustomAction, - FRIGATE_CARD_VIEWS_USER_SPECIFIED, MenuItem, } from '../config/types'; import { FRIGATE_BUTTON_MENU_ICON } from '../const'; @@ -31,6 +32,7 @@ export interface MenuButtonControllerOptions { inExpandedMode?: boolean; microphoneManager?: MicrophoneManager | null; mediaPlayerController?: MediaPlayerManager | null; + viewManager?: ViewManager | null; } export class MenuButtonController { @@ -62,18 +64,19 @@ export class MenuButtonController { ): MenuItem[] { const visibleCameraIDs = cameraManager.getStore().getVisibleCameraIDs(); const selectedCameraID = view.camera; + const substreamAwareCameraID = + view.context?.live?.overrides?.get(selectedCameraID) ?? selectedCameraID; const selectedCameraConfig = cameraManager .getStore() .getCameraConfig(selectedCameraID); const allSelectedCameraIDs = cameraManager .getStore() .getAllDependentCameras(selectedCameraID); - const selectedMedia = view.queryResults?.getSelectedResult(); - const selectedCameraCapabilities = - cameraManager.getCameraCapabilities(selectedCameraID); - const aggregateCapabilities = - cameraManager.getAggregateCameraCapabilities(allSelectedCameraIDs); + const substreamAwareCameraCapabilities = + cameraManager.getCameraCapabilities(substreamAwareCameraID); + + const selectedMedia = view.queryResults?.getSelectedResult(); const mediaCapabilities = selectedMedia ? cameraManager?.getMediaCapabilities(selectedMedia) : null; @@ -125,7 +128,6 @@ export class MenuButtonController { if (selectedCameraID && allSelectedCameraIDs && view.is('live')) { const dependencies = [...allSelectedCameraIDs]; - const override = view.context?.live?.overrides?.get(selectedCameraID); if (dependencies.length === 2) { // If there are only two dependencies (the main camera, and 1 other) @@ -133,7 +135,9 @@ export class MenuButtonController { buttons.push({ icon: 'mdi:video-input-component', style: - override && override !== selectedCameraID ? this._getEmphasizedStyle() : {}, + substreamAwareCameraID !== selectedCameraID + ? this._getEmphasizedStyle() + : {}, title: localize('config.menu.buttons.substreams'), ...config.menu.buttons.substreams, type: 'custom:frigate-card-menu-icon', @@ -166,7 +170,9 @@ export class MenuButtonController { icon: 'mdi:video-input-component', title: localize('config.menu.buttons.substreams'), style: - override && override !== selectedCameraID ? this._getEmphasizedStyle() : {}, + substreamAwareCameraID !== selectedCameraID + ? this._getEmphasizedStyle() + : {}, ...config.menu.buttons.substreams, type: 'custom:frigate-card-menu-submenu', items: menuItems, @@ -183,7 +189,7 @@ export class MenuButtonController { tap_action: createFrigateCardSimpleAction('live') as FrigateCardCustomAction, }); - if (aggregateCapabilities?.supportsClips) { + if (options?.viewManager?.isViewSupportedByCamera(selectedCameraID, 'clips')) { buttons.push({ icon: 'mdi:filmstrip', ...config.menu.buttons.clips, @@ -195,7 +201,7 @@ export class MenuButtonController { }); } - if (aggregateCapabilities?.supportsSnapshots) { + if (options?.viewManager?.isViewSupportedByCamera(selectedCameraID, 'snapshots')) { buttons.push({ icon: 'mdi:camera', ...config.menu.buttons.snapshots, @@ -211,7 +217,7 @@ export class MenuButtonController { }); } - if (aggregateCapabilities?.supportsRecordings) { + if (options?.viewManager?.isViewSupportedByCamera(selectedCameraID, 'recordings')) { buttons.push({ icon: 'mdi:album', ...config.menu.buttons.recordings, @@ -236,9 +242,7 @@ export class MenuButtonController { tap_action: createFrigateCardSimpleAction('image') as FrigateCardCustomAction, }); - // Don't show the timeline button unless there's at least one non-birdseye - // camera with a Frigate camera name. - if (aggregateCapabilities?.supportsTimeline) { + if (options?.viewManager?.isViewSupportedByCamera(selectedCameraID, 'timeline')) { buttons.push({ icon: 'mdi:chart-gantt', ...config.menu.buttons.timeline, @@ -419,7 +423,7 @@ export class MenuButtonController { }); } - if (hasUsablePTZ(selectedCameraCapabilities, config.live.controls.ptz)) { + if (hasUsablePTZ(substreamAwareCameraCapabilities, config.live.controls.ptz)) { const isOn = view.context?.live?.ptzVisible === false ? false diff --git a/tests/card-controller/actions-manager.test.ts b/tests/card-controller/actions-manager.test.ts index f864302c..02742759 100644 --- a/tests/card-controller/actions-manager.test.ts +++ b/tests/card-controller/actions-manager.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-non-null-assertion */ import { afterAll, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { @@ -382,6 +383,7 @@ describe('ActionsManager.executeAction', () => { expect.objectContaining({ viewName: 'live', cameraID: 'camera', + failSafe: true, }), ); }); @@ -409,6 +411,7 @@ describe('ActionsManager.executeAction', () => { expect.objectContaining({ viewName: 'timeline', cameraID: 'camera', + failSafe: true, }), ); }); @@ -442,6 +445,7 @@ describe('ActionsManager.executeAction', () => { expect.objectContaining({ viewName: 'clips', cameraID: 'camera', + failSafe: true, }), ); }); @@ -467,6 +471,7 @@ describe('ActionsManager.executeAction', () => { expect.objectContaining({ viewName: 'live', cameraID: 'camera', + failSafe: true, }), ); }); @@ -503,32 +508,6 @@ describe('ActionsManager.executeAction', () => { expect(api.getViewManager().setViewByParameters).not.toBeCalled(); }); - - it('with an unsupported view', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - vi.mocked(api.getViewManager().getView).mockReturnValue( - createView({ - view: 'timeline', - }), - ); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'camera_select', - camera: 'camera', - })!, - ); - - expect(api.getViewManager().setViewByParameters).toBeCalledWith( - expect.objectContaining({ - // Should have fallen back to the default view. - viewName: 'live', - cameraID: 'camera', - }), - ); - }); }); it('should handle live_substream_select action', async () => { diff --git a/tests/card-controller/view-manager.test.ts b/tests/card-controller/view-manager.test.ts index 883954c7..738b5919 100644 --- a/tests/card-controller/view-manager.test.ts +++ b/tests/card-controller/view-manager.test.ts @@ -7,6 +7,7 @@ import { EventMediaQueries } from '../../src/view/media-queries'; import { MediaQueriesResults } from '../../src/view/media-queries-results'; import { View } from '../../src/view/view'; import { + createAggregateCameraCapabilities, createCameraCapabilities, createCameraConfig, createCameraManager, @@ -15,7 +16,7 @@ import { createHASS, createStore, createView, - generateViewMediaArray + generateViewMediaArray, } from '../test-utils'; vi.mock('../../src/utils/media-to-view'); @@ -218,8 +219,8 @@ describe('ViewManager.setViewByParameters', () => { }, ]), ); - vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue( - createCameraCapabilities({ + vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsClips: true, }), ); @@ -247,8 +248,8 @@ describe('ViewManager.setViewByParameters', () => { }, ]), ); - vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue( - createCameraCapabilities({ + vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsClips: true, }), ); @@ -336,10 +337,12 @@ describe('ViewManager.setViewByParameters', () => { ]), ); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue(createCameraCapabilities({ - supportsSnapshots: false, - })); - + vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ + supportsSnapshots: false, + }), + ); + const manager = new ViewManager(api); manager.setViewByParameters({ viewName: 'snapshots', @@ -360,16 +363,18 @@ describe('ViewManager.setViewByParameters', () => { ]), ); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue(createCameraCapabilities({ - supportsSnapshots: false, - })); - + vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ + supportsSnapshots: false, + }), + ); + const manager = new ViewManager(api); manager.setViewByParameters({ viewName: 'snapshots', failSafe: true, }); - + expect(manager.hasView()).toBeTruthy(); expect(manager.getView()?.view).toBe('live'); }); @@ -392,8 +397,8 @@ describe('ViewManager.setViewByParameters', () => { }, ]), ); - vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue( - createCameraCapabilities({ + vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsClips: true, supportsRecordings: true, supportsSnapshots: true, @@ -443,8 +448,8 @@ describe('ViewManager.setViewByParameters', () => { }, ]), ); - vi.mocked(api.getCameraManager().getCameraCapabilities).mockReturnValue( - createCameraCapabilities({ + vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( + createAggregateCameraCapabilities({ supportsClips: true, supportsRecordings: true, supportsSnapshots: true, diff --git a/tests/components-lib/menu-button-controller.test.ts b/tests/components-lib/menu-button-controller.test.ts index 87f2c9ba..e72138f4 100644 --- a/tests/components-lib/menu-button-controller.test.ts +++ b/tests/components-lib/menu-button-controller.test.ts @@ -6,6 +6,7 @@ import { CameraManager } from '../../src/camera-manager/manager'; import { CameraManagerCameraMetadata } from '../../src/camera-manager/types'; import { MediaPlayerManager } from '../../src/card-controller/media-player-manager'; import { MicrophoneManager } from '../../src/card-controller/microphone-manager'; +import { ViewManager } from '../../src/card-controller/view-manager'; import { MenuButtonController, MenuButtonControllerOptions, @@ -17,7 +18,6 @@ import { ViewMedia } from '../../src/view/media'; import { MediaQueriesResults } from '../../src/view/media-queries-results'; import { View } from '../../src/view/view'; import { - createAggregateCameraCapabilities, createCameraCapabilities, createCameraConfig, createCameraManager, @@ -41,6 +41,7 @@ const calculateButtons = ( config?: FrigateCardConfig; cameraManager?: CameraManager; view?: View; + viewManager?: ViewManager; }, ): MenuItem[] => { let cameraManager: CameraManager | null = options?.cameraManager ?? null; @@ -71,618 +72,697 @@ describe('MenuButtonController', () => { controller = new MenuButtonController(); }); - it('should have frigate menu button with hidden menu style', () => { - const buttons = calculateButtons(controller); - expect(buttons).toContainEqual({ - icon: 'frigate', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Frigate menu / Default view', - tap_action: createFrigateCardSimpleAction('menu_toggle'), - hold_action: createFrigateCardSimpleAction('diagnostics'), + describe('should have frigate menu button', () => { + it('with hidden menu style', () => { + const buttons = calculateButtons(controller); + + expect(buttons).toContainEqual({ + icon: 'frigate', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Frigate menu / Default view', + tap_action: createFrigateCardSimpleAction('menu_toggle'), + hold_action: createFrigateCardSimpleAction('diagnostics'), + }); + }); + + it('without hidden menu style', () => { + const buttons = calculateButtons(controller, { + config: createConfig({ menu: { style: 'overlay' } }), + }); + + expect(buttons).toContainEqual({ + icon: 'frigate', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Frigate menu / Default view', + tap_action: createFrigateCardSimpleAction('default'), + hold_action: createFrigateCardSimpleAction('diagnostics'), + }); }); }); - it('should have frigate menu button without hidden menu style', () => { - const buttons = calculateButtons(controller, { - config: createConfig({ menu: { style: 'overlay' } }), + describe('should have cameras menu', () => { + it('with multiple cameras', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([{ cameraID: 'camera-1' }, { cameraID: 'camera-2' }]), + ); + vi.mocked(cameraManager).getCameraMetadata.mockReturnValue({ + title: 'title', + icon: 'icon', + }); + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + + expect(buttons).toContainEqual({ + icon: 'mdi:video-switch', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-submenu', + title: 'Cameras', + items: [ + { + enabled: true, + icon: 'icon', + entity: undefined, + state_color: true, + title: 'title', + selected: true, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + camera: 'camera-1', + }, + }, + { + enabled: true, + icon: 'icon', + entity: undefined, + state_color: true, + title: 'title', + selected: false, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + camera: 'camera-2', + }, + }, + ], + }); }); - expect(buttons).toContainEqual({ - icon: 'frigate', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Frigate menu / Default view', - tap_action: createFrigateCardSimpleAction('default'), - hold_action: createFrigateCardSimpleAction('diagnostics'), + + it('without a visible camera', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { cameraID: 'camera-1', config: createCameraConfig({ hide: true }) }, + ]), + ); + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + + expect(buttons).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ + title: 'Cameras', + }), + ]), + ); }); }); - it('should have cameras menu', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([{ cameraID: 'camera-1' }, { cameraID: 'camera-2' }]), - ); - vi.mocked(cameraManager).getCameraMetadata.mockReturnValue({ - title: 'title', - icon: 'icon', + describe('should have substream button', () => { + it('with single dependency', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), + }, + { cameraID: 'camera-2' }, + ]), + ); + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + + expect(buttons).toContainEqual({ + icon: 'mdi:video-input-component', + style: {}, + title: 'Substream(s)', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_on', + }, + }); }); - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - icon: 'mdi:video-switch', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-submenu', - title: 'Cameras', - items: [ - { - enabled: true, - icon: 'icon', - entity: undefined, - state_color: true, - title: 'title', - selected: true, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'camera_select', - camera: 'camera-1', + it('with substream selected and single dependency', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), + }, + { cameraID: 'camera-2' }, + ]), + ); + const view = createView({ + camera: 'camera-1', + context: { + live: { + overrides: new Map([['camera-1', 'camera-2']]), }, }, - { - enabled: true, - icon: 'icon', - entity: undefined, - state_color: true, - title: 'title', - selected: false, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'camera_select', - camera: 'camera-2', + }); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:video-input-component', + style: { color: 'var(--primary-color, white)' }, + title: 'Substream(s)', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_off', + }, + }); + }); + + it('with substream selected and multiple dependencies', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ + camera_entity: 'camera.1', + dependencies: { cameras: ['camera-2', 'camera-3'] }, + }), + }, + { + cameraID: 'camera-2', + config: createCameraConfig({ + camera_entity: 'camera.2', + }), + }, + { + cameraID: 'camera-3', + config: createCameraConfig({ + camera_entity: 'camera.3', + }), + }, + ]), + ); + + // Return different metadata depending on the camera to test multiple code + // paths. + mock(cameraManager).getCameraMetadata.mockImplementation( + (cameraID: string): CameraManagerCameraMetadata | null => { + return cameraID === 'camera-1' + ? { + title: 'title', + icon: 'icon', + } + : null; + }, + ); + + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + + expect(buttons).toContainEqual({ + icon: 'mdi:video-input-component', + title: 'Substream(s)', + style: {}, + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-submenu', + items: [ + { + enabled: true, + icon: 'icon', + entity: 'camera.1', + state_color: true, + title: 'title', + selected: true, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'camera-1', + }, + }, + { + enabled: true, + icon: undefined, + entity: 'camera.2', + state_color: true, + title: undefined, + selected: false, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'camera-2', + }, + }, + { + enabled: true, + icon: undefined, + entity: 'camera.3', + state_color: true, + title: undefined, + selected: false, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'camera-3', + }, + }, + ], + }); + }); + + it('with substream selected and with multiple dependencies', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ + camera_entity: 'camera.1', + dependencies: { cameras: ['camera-2', 'camera-3'] }, + }), + }, + { + cameraID: 'camera-2', + config: createCameraConfig({ + camera_entity: 'camera.2', + }), + }, + { + cameraID: 'camera-3', + config: createCameraConfig({ + camera_entity: 'camera.3', + }), + }, + ]), + ); + const view = createView({ + camera: 'camera-1', + context: { + live: { + overrides: new Map([['camera-1', 'camera-2']]), }, }, - ], + }); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:video-input-component', + title: 'Substream(s)', + style: { color: 'var(--primary-color, white)' }, + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-submenu', + items: [ + { + enabled: true, + icon: undefined, + entity: 'camera.1', + state_color: true, + title: undefined, + selected: false, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'camera-1', + }, + }, + { + enabled: true, + icon: undefined, + entity: 'camera.2', + state_color: true, + title: undefined, + // camera-2 is selected in this test scenario because of the view + // override. + selected: true, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'camera-2', + }, + }, + { + enabled: true, + icon: undefined, + entity: 'camera.3', + state_color: true, + title: undefined, + selected: false, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'camera-3', + }, + }, + ], + }); }); }); - it('should not have a cameras menu without a visible camera', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { cameraID: 'camera-1', config: createCameraConfig({ hide: true }) }, - ]), - ); + describe('should have live menu button', () => { + it('when in live view', () => { + const buttons = calculateButtons(controller); - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ - title: 'Cameras', + expect(buttons).toContainEqual({ + icon: 'mdi:cctv', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Live view', + style: { color: 'var(--primary-color, white)' }, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'live' }, + }); + }); + + it('when not in live view', () => { + const view = createView({ view: 'clips' }); + const buttons = calculateButtons(controller, { view: view }); + + expect(buttons).toContainEqual({ + icon: 'mdi:cctv', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Live view', + style: {}, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'live' }, + }); + }); + }); + + describe('should have clips menu button', () => { + it('when in clips view', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(true); + const buttons = calculateButtons(controller, { + view: createView({ view: 'clips' }), + viewManager: viewManager, + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:filmstrip', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Clips gallery', + style: { color: 'var(--primary-color, white)' }, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' }, + hold_action: { action: 'fire-dom-event', frigate_card_action: 'clip' }, + }); + }); + + it('when not in clips view', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(true); + const buttons = calculateButtons(controller, { + viewManager: viewManager, + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:filmstrip', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Clips gallery', + style: {}, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' }, + hold_action: { action: 'fire-dom-event', frigate_card_action: 'clip' }, + }); + }); + + it('when not supported', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(false); + const buttons = calculateButtons(controller, { + viewManager: viewManager, + }); + + expect(buttons).not.toEqual( + expect.arrayContaining([expect.objectContaining({ title: 'Clips gallery' })]), + ); + }); + }); + + describe('should have snapshots menu button', () => { + it('when in snapshots view', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(true); + const buttons = calculateButtons(controller, { + view: createView({ view: 'snapshots' }), + viewManager: viewManager, + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:camera', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Snapshots gallery', + style: { color: 'var(--primary-color, white)' }, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'snapshots' }, + hold_action: { action: 'fire-dom-event', frigate_card_action: 'snapshot' }, + }); + }); + + it('when not in snapshots view', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(true); + const buttons = calculateButtons(controller, { + viewManager: viewManager, + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:camera', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Snapshots gallery', + style: {}, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'snapshots' }, + hold_action: { action: 'fire-dom-event', frigate_card_action: 'snapshot' }, + }); + }); + + it('when not supported', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(false); + const buttons = calculateButtons(controller, { + viewManager: viewManager, + }); + + expect(buttons).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ title: 'Snapshots gallery' }), + ]), + ); + }); + }); + + describe('should have recordings menu button', () => { + it('when in recordings view', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(true); + const buttons = calculateButtons(controller, { + view: createView({ view: 'recordings' }), + viewManager: viewManager, + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:album', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Recordings gallery', + style: { color: 'var(--primary-color, white)' }, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'recordings' }, + hold_action: { action: 'fire-dom-event', frigate_card_action: 'recording' }, + }); + }); + + it('when not in recordings view', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(true); + const buttons = calculateButtons(controller, { + viewManager: viewManager, + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:album', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Recordings gallery', + style: {}, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'recordings' }, + hold_action: { action: 'fire-dom-event', frigate_card_action: 'recording' }, + }); + }); + + it('when not supported', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(false); + const buttons = calculateButtons(controller, { + viewManager: viewManager, + }); + + expect(buttons).not.toEqual( + expect.arrayContaining([ + expect.objectContaining({ title: 'Recordings gallery' }), + ]), + ); + }); + }); + + describe('should have image menu button', () => { + it('when in image view', () => { + const buttons = calculateButtons(controller, { + view: createView({ view: 'image' }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:image', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Static image', + style: { color: 'var(--primary-color, white)' }, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'image' }, + }); + }); + + it('when not in image view', () => { + const buttons = calculateButtons(controller); + + expect(buttons).toContainEqual({ + icon: 'mdi:image', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Static image', + style: {}, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'image' }, + }); + }); + }); + + describe('should have timeline button', () => { + it('when in timeline view', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(true); + const buttons = calculateButtons(controller, { + view: createView({ view: 'timeline' }), + viewManager: viewManager, + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:chart-gantt', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Timeline view', + style: { color: 'var(--primary-color, white)' }, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'timeline' }, + }); + }); + + it('when not in timeline view', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(true); + const buttons = calculateButtons(controller, { + view: createView({ view: 'live' }), + viewManager: viewManager, + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:chart-gantt', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Timeline view', + style: {}, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'timeline' }, + }); + }); + + it('when not supported', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(false); + const buttons = calculateButtons(controller, { + view: createView({ view: 'live' }), + viewManager: viewManager, + }); + + expect(buttons).not.toEqual( + expect.arrayContaining([expect.objectContaining({ title: 'Timeline view' })]), + ); + }); + }); + + describe('should have download button', () => { + it('when media available', () => { + vi.stubGlobal('navigator', { userAgent: 'foo' }); + + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getMediaCapabilities).mockReturnValue( + createMediaCapabilities({ canDownload: true }), + ); + const view = createView({ + queryResults: new MediaQueriesResults({ + results: [new ViewMedia('clip', 'camera-1')], + selectedIndex: 0, }), - ]), - ); - }); + }); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); - it('should have substream button with single dependency', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), - }, - { cameraID: 'camera-2' }, - ]), - ); - - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - icon: 'mdi:video-input-component', - style: {}, - title: 'Substream(s)', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_on', - }, - }); - }); - - it('should have substream button selected with single dependency', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), - }, - { cameraID: 'camera-2' }, - ]), - ); - - const view = createView({ - camera: 'camera-1', - context: { - live: { - overrides: new Map([['camera-1', 'camera-2']]), - }, - }, + expect(buttons).toContainEqual({ + icon: 'mdi:download', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Download', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'download' }, + }); }); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: view, - }); - expect(buttons).toContainEqual({ - icon: 'mdi:video-input-component', - style: { color: 'var(--primary-color, white)' }, - title: 'Substream(s)', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_off', - }, - }); - }); + it('not when being casted', () => { + vi.stubGlobal('navigator', { + userAgent: + 'Mozilla/5.0 (Fuchsia) AppleWebKit/537.36 (KHTML, like Gecko) ' + + 'Chrome/114.0.0.0 Safari/537.36 CrKey/1.56.500000', + }); - it('should have substream menu without substream on with multiple dependencies', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ - camera_entity: 'camera.1', - dependencies: { cameras: ['camera-2', 'camera-3'] }, - }), - }, - { - cameraID: 'camera-2', - config: createCameraConfig({ - camera_entity: 'camera.2', - }), - }, - { - cameraID: 'camera-3', - config: createCameraConfig({ - camera_entity: 'camera.3', - }), - }, - ]), - ); + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getMediaCapabilities).mockReturnValue( + createMediaCapabilities({ canDownload: true }), + ); + const view = createView({ + queryResults: new MediaQueriesResults({ + results: [new ViewMedia('clip', 'camera-1')], + selectedIndex: 0, + }), + }); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); - // Return different metadata depending on the camera to test multiple code - // paths. - mock(cameraManager).getCameraMetadata.mockImplementation( - (cameraID: string): CameraManagerCameraMetadata | null => { - return cameraID === 'camera-1' - ? { - title: 'title', - icon: 'icon', - } - : null; - }, - ); - - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - icon: 'mdi:video-input-component', - title: 'Substream(s)', - style: {}, - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-submenu', - items: [ - { - enabled: true, - icon: 'icon', - entity: 'camera.1', - state_color: true, - title: 'title', - selected: true, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_select', - camera: 'camera-1', - }, - }, - { - enabled: true, - icon: undefined, - entity: 'camera.2', - state_color: true, - title: undefined, - selected: false, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_select', - camera: 'camera-2', - }, - }, - { - enabled: true, - icon: undefined, - entity: 'camera.3', - state_color: true, - title: undefined, - selected: false, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_select', - camera: 'camera-3', - }, - }, - ], + expect(buttons).not.toEqual( + expect.arrayContaining([expect.objectContaining({ title: 'Download' })]), + ); }); }); - it('should have substream menu with substream on with multiple dependencies', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ - camera_entity: 'camera.1', - dependencies: { cameras: ['camera-2', 'camera-3'] }, - }), - }, - { - cameraID: 'camera-2', - config: createCameraConfig({ - camera_entity: 'camera.2', - }), - }, - { - cameraID: 'camera-3', - config: createCameraConfig({ - camera_entity: 'camera.3', - }), - }, - ]), - ); - - const view = createView({ - camera: 'camera-1', - context: { - live: { - overrides: new Map([['camera-1', 'camera-2']]), - }, - }, - }); - - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: view, - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:video-input-component', - title: 'Substream(s)', - style: { color: 'var(--primary-color, white)' }, - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-submenu', - items: [ - { - enabled: true, - icon: undefined, - entity: 'camera.1', - state_color: true, - title: undefined, - selected: false, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_select', - camera: 'camera-1', - }, - }, - { - enabled: true, - icon: undefined, - entity: 'camera.2', - state_color: true, - title: undefined, - // camera-2 is selected in this test scenario because of the view - // override. - selected: true, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_select', - camera: 'camera-2', - }, - }, - { - enabled: true, - icon: undefined, - entity: 'camera.3', - state_color: true, - title: undefined, - selected: false, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'live_substream_select', - camera: 'camera-3', - }, - }, - ], - }); - }); - - it('should have styled live menu button in live view', () => { - const buttons = calculateButtons(controller); - expect(buttons).toContainEqual({ - icon: 'mdi:cctv', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Live view', - style: { color: 'var(--primary-color, white)' }, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'live' }, - }); - }); - - it('should have unstyled live menu button in non-live views', () => { - const view = createView({ view: 'clips' }); - const buttons = calculateButtons(controller, { view: view }); - expect(buttons).toContainEqual({ - icon: 'mdi:cctv', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Live view', - style: {}, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'live' }, - }); - }); - - it('should have styled clips menu button in clips view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsClips: true }), - ); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: createView({ view: 'clips' }), - }); - expect(buttons).toContainEqual({ - icon: 'mdi:filmstrip', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Clips gallery', - style: { color: 'var(--primary-color, white)' }, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' }, - hold_action: { action: 'fire-dom-event', frigate_card_action: 'clip' }, - }); - }); - - it('should have unstyled clips menu button in non-clips view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsClips: true }), - ); - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - icon: 'mdi:filmstrip', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Clips gallery', - style: {}, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' }, - hold_action: { action: 'fire-dom-event', frigate_card_action: 'clip' }, - }); - }); - - it('should have styled snapshots menu button in snapshots view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsSnapshots: true }), - ); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: createView({ view: 'snapshots' }), - }); - expect(buttons).toContainEqual({ - icon: 'mdi:camera', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Snapshots gallery', - style: { color: 'var(--primary-color, white)' }, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'snapshots' }, - hold_action: { action: 'fire-dom-event', frigate_card_action: 'snapshot' }, - }); - }); - - it('should have unstyled snapshots menu button in non-snapshots view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsSnapshots: true }), - ); - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - icon: 'mdi:camera', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Snapshots gallery', - style: {}, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'snapshots' }, - hold_action: { action: 'fire-dom-event', frigate_card_action: 'snapshot' }, - }); - }); - - it('should have styled recordings menu button in recordings view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsRecordings: true }), - ); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: createView({ view: 'recordings' }), - }); - expect(buttons).toContainEqual({ - icon: 'mdi:album', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Recordings gallery', - style: { color: 'var(--primary-color, white)' }, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'recordings' }, - hold_action: { action: 'fire-dom-event', frigate_card_action: 'recording' }, - }); - }); - - it('should have unstyled recordings menu button in non-recordings view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsRecordings: true }), - ); - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - expect(buttons).toContainEqual({ - icon: 'mdi:album', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Recordings gallery', - style: {}, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'recordings' }, - hold_action: { action: 'fire-dom-event', frigate_card_action: 'recording' }, - }); - }); - - it('should have styled image menu button in image view', () => { - const buttons = calculateButtons(controller, { - view: createView({ view: 'image' }), - }); - expect(buttons).toContainEqual({ - icon: 'mdi:image', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Static image', - style: { color: 'var(--primary-color, white)' }, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'image' }, - }); - }); - - it('should have unstyled image menu button in non-image view', () => { - const buttons = calculateButtons(controller); - expect(buttons).toContainEqual({ - icon: 'mdi:image', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Static image', - style: {}, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'image' }, - }); - }); - - it('should have styled timeline menu button in timeline view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsTimeline: true }), - ); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: createView({ view: 'timeline' }), - }); - expect(buttons).toContainEqual({ - icon: 'mdi:chart-gantt', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Timeline view', - style: { color: 'var(--primary-color, white)' }, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'timeline' }, - }); - }); - - it('should have unstyled timeline menu button in non-timeline view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ supportsTimeline: true }), - ); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - }); - expect(buttons).toContainEqual({ - icon: 'mdi:chart-gantt', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Timeline view', - style: {}, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'timeline' }, - }); - }); - - it('should have download menu button', () => { - vi.stubGlobal('navigator', { userAgent: 'foo' }); - - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getMediaCapabilities).mockReturnValue( - createMediaCapabilities({ canDownload: true }), - ); - const view = createView({ - queryResults: new MediaQueriesResults({ - results: [new ViewMedia('clip', 'camera-1')], - selectedIndex: 0, - }), - }); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: view, - }); - expect(buttons).toContainEqual({ - icon: 'mdi:download', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Download', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'download' }, - }); - }); - - it('should not have download menu button when being casted', () => { - vi.stubGlobal('navigator', { - userAgent: - 'Mozilla/5.0 (Fuchsia) AppleWebKit/537.36 (KHTML, like Gecko) ' + - 'Chrome/114.0.0.0 Safari/537.36 CrKey/1.56.500000', - }); - - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getMediaCapabilities).mockReturnValue( - createMediaCapabilities({ canDownload: true }), - ); - const view = createView({ - queryResults: new MediaQueriesResults({ - results: [new ViewMedia('clip', 'camera-1')], - selectedIndex: 0, - }), - }); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - view: view, - }); - expect(buttons).not.toEqual( - expect.arrayContaining([expect.objectContaining({ title: 'Download' })]), - ); - }); - it('should have camera UI button', () => { const buttons = calculateButtons(controller, { showCameraUIButton: true, }); + expect(buttons).toContainEqual({ icon: 'mdi:web', enabled: true, @@ -693,322 +773,330 @@ describe('MenuButtonController', () => { }); }); - it('should have microphone button', () => { - const microphoneManager = new MicrophoneManager(createCardAPI()); - const buttons = calculateButtons(controller, { - microphoneManager: microphoneManager, - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supports2WayAudio: true, - }, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:microphone', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Microphone', - style: { - animation: 'pulse 3s infinite', - color: 'var(--error-color, white)', - }, - start_tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'microphone_unmute', - }, - end_tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'microphone_mute', - }, - }); - }); - - it('should not have microphone button when media does not support it', () => { - const microphoneManager = new MicrophoneManager(createCardAPI()); - const buttons = calculateButtons(controller, { - microphoneManager: microphoneManager, - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supports2WayAudio: false, - }, - }), - }); - - expect(buttons).not.toEqual( - expect.arrayContaining([expect.objectContaining({ title: 'Microphone' })]), - ); - }); - - it('should have microphone button when microphone forbidden', () => { - const microphoneManager = new MicrophoneManager(createCardAPI()); - mock(microphoneManager).isForbidden.mockReturnValue(true); - const buttons = calculateButtons(controller, { - microphoneManager: microphoneManager, - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supports2WayAudio: true, - }, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:microphone-message-off', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Microphone', - style: {}, - }); - }); - - it('should have microphone button when microphone muted', () => { - const microphoneManager = new MicrophoneManager(createCardAPI()); - mock(microphoneManager).isMuted.mockReturnValue(true); - const buttons = calculateButtons(controller, { - microphoneManager: microphoneManager, - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supports2WayAudio: true, - }, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:microphone-off', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Microphone', - style: {}, - start_tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'microphone_unmute', - }, - end_tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'microphone_mute', - }, - }); - }); - - it('should have microphone button when microphone muted with toggle type', () => { - const microphoneManager = new MicrophoneManager(createCardAPI()); - mock(microphoneManager).isMuted.mockReturnValue(true); - const buttons = calculateButtons(controller, { - microphoneManager: microphoneManager, - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supports2WayAudio: true, - }, - }), - config: createConfig({ - menu: { buttons: { microphone: { type: 'toggle' } } }, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:microphone-off', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Microphone', - style: {}, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'microphone_unmute', - }, - }); - }); - - it('should have microphone button when microphone unmuted with toggle type', () => { - const microphoneManager = new MicrophoneManager(createCardAPI()); - mock(microphoneManager).isMuted.mockReturnValue(false); - const buttons = calculateButtons(controller, { - microphoneManager: microphoneManager, - currentMediaLoadedInfo: createMediaLoadedInfo({ - capabilities: { - supports2WayAudio: true, - }, - }), - config: createConfig({ - menu: { buttons: { microphone: { type: 'toggle' } } }, - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:microphone', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Microphone', - style: { - animation: 'pulse 3s infinite', - color: 'var(--error-color, white)', - }, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'microphone_mute', - }, - }); - }); - - it('should have fullscreen button', () => { - // Need to write a readonly property. - vi.stubGlobal('navigator', { userAgent: 'foo' }); - const buttons = calculateButtons(controller, { inFullscreenMode: false }); - - expect(buttons).toContainEqual({ - icon: 'mdi:fullscreen', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Fullscreen', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' }, - style: {}, - }); - }); - - it('should have unfullscreen', () => { - vi.stubGlobal('navigator', { userAgent: 'foo' }); - const buttons = calculateButtons(controller, { inFullscreenMode: true }); - - expect(buttons).toContainEqual({ - icon: 'mdi:fullscreen-exit', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Fullscreen', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' }, - style: { color: 'var(--primary-color, white)' }, - }); - }); - - it('should have expand button', () => { - const buttons = calculateButtons(controller, { inExpandedMode: false }); - - expect(buttons).toContainEqual({ - icon: 'mdi:arrow-expand-all', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Expand', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'expand' }, - style: {}, - }); - }); - - it('should have unexpand button', () => { - const buttons = calculateButtons(controller, { inExpandedMode: true }); - - expect(buttons).toContainEqual({ - icon: 'mdi:arrow-collapse-all', - enabled: false, - priority: 50, - type: 'custom:frigate-card-menu-icon', - title: 'Expand', - tap_action: { action: 'fire-dom-event', frigate_card_action: 'expand' }, - style: { color: 'var(--primary-color, white)' }, - }); - }); - - it('should have media players button', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ - camera_entity: 'camera.1', - }), - }, - ]), - ); - - const mediaPlayerController = mock(); - mediaPlayerController.hasMediaPlayers.mockReturnValue(true); - mediaPlayerController.getMediaPlayers.mockReturnValue(['media_player.tv']); - - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - mediaPlayerController: mediaPlayerController, - hass: createHASS({ - 'media_player.tv': createStateEntity({ entity_id: 'media_player.tv' }), - }), - }); - - expect(buttons).toContainEqual({ - icon: 'mdi:cast', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-submenu', - title: 'Send to media player', - items: [ - { - enabled: true, - selected: false, - icon: 'mdi:cast', - entity: 'media_player.tv', - state_color: false, - title: 'media_player.tv', - disabled: false, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'media_player', - media_player: 'media_player.tv', - media_player_action: 'play', - }, - hold_action: { - action: 'fire-dom-event', - frigate_card_action: 'media_player', - media_player: 'media_player.tv', - media_player_action: 'stop', + describe('should have microphone button', () => { + it('with suitable loaded media', () => { + const microphoneManager = new MicrophoneManager(createCardAPI()); + const buttons = calculateButtons(controller, { + microphoneManager: microphoneManager, + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supports2WayAudio: true, }, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:microphone', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Microphone', + style: { + animation: 'pulse 3s infinite', + color: 'var(--error-color, white)', }, - ], + start_tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'microphone_unmute', + }, + end_tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'microphone_mute', + }, + }); + }); + + it('without suitable loaded media', () => { + const microphoneManager = new MicrophoneManager(createCardAPI()); + const buttons = calculateButtons(controller, { + microphoneManager: microphoneManager, + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supports2WayAudio: false, + }, + }), + }); + + expect(buttons).not.toEqual( + expect.arrayContaining([expect.objectContaining({ title: 'Microphone' })]), + ); + }); + + it('with forbidden microphone', () => { + const microphoneManager = new MicrophoneManager(createCardAPI()); + mock(microphoneManager).isForbidden.mockReturnValue(true); + const buttons = calculateButtons(controller, { + microphoneManager: microphoneManager, + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supports2WayAudio: true, + }, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:microphone-message-off', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Microphone', + style: {}, + }); + }); + + it('with muted microphone', () => { + const microphoneManager = new MicrophoneManager(createCardAPI()); + mock(microphoneManager).isMuted.mockReturnValue(true); + const buttons = calculateButtons(controller, { + microphoneManager: microphoneManager, + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supports2WayAudio: true, + }, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:microphone-off', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Microphone', + style: {}, + start_tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'microphone_unmute', + }, + end_tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'microphone_mute', + }, + }); + }); + + it('with muted toggle type microphone', () => { + const microphoneManager = new MicrophoneManager(createCardAPI()); + mock(microphoneManager).isMuted.mockReturnValue(true); + const buttons = calculateButtons(controller, { + microphoneManager: microphoneManager, + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supports2WayAudio: true, + }, + }), + config: createConfig({ + menu: { buttons: { microphone: { type: 'toggle' } } }, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:microphone-off', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Microphone', + style: {}, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'microphone_unmute', + }, + }); + }); + + it('with unmuted toggle type microphone', () => { + const microphoneManager = new MicrophoneManager(createCardAPI()); + mock(microphoneManager).isMuted.mockReturnValue(false); + const buttons = calculateButtons(controller, { + microphoneManager: microphoneManager, + currentMediaLoadedInfo: createMediaLoadedInfo({ + capabilities: { + supports2WayAudio: true, + }, + }), + config: createConfig({ + menu: { buttons: { microphone: { type: 'toggle' } } }, + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:microphone', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Microphone', + style: { + animation: 'pulse 3s infinite', + color: 'var(--error-color, white)', + }, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'microphone_mute', + }, + }); }); }); - it('should disable media players button when entity not found', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ - camera_entity: 'camera.1', - }), - }, - ]), - ); - const mediaPlayerController = mock(); - mediaPlayerController.hasMediaPlayers.mockReturnValue(true); - mediaPlayerController.getMediaPlayers.mockReturnValue(['not_a_real_player']); + describe('should have fullscreen button', () => { + it('when not in fullscreen mode', () => { + // Need to write a readonly property. + vi.stubGlobal('navigator', { userAgent: 'foo' }); + const buttons = calculateButtons(controller, { inFullscreenMode: false }); - const buttons = calculateButtons(controller, { - cameraManager: cameraManager, - mediaPlayerController: mediaPlayerController, - hass: createHASS(), + expect(buttons).toContainEqual({ + icon: 'mdi:fullscreen', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Fullscreen', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' }, + style: {}, + }); }); - expect(buttons).toContainEqual({ - icon: 'mdi:cast', - enabled: true, - priority: 50, - type: 'custom:frigate-card-menu-submenu', - title: 'Send to media player', - items: [ - { - enabled: true, - selected: false, - icon: 'mdi:bookmark', - entity: 'not_a_real_player', - state_color: false, - title: 'not_a_real_player', - disabled: true, - }, - ], + it('when in fullscreen mode', () => { + vi.stubGlobal('navigator', { userAgent: 'foo' }); + const buttons = calculateButtons(controller, { inFullscreenMode: true }); + + expect(buttons).toContainEqual({ + icon: 'mdi:fullscreen-exit', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Fullscreen', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' }, + style: { color: 'var(--primary-color, white)' }, + }); + }); + }); + + describe('should have expand button', () => { + it('when not expanded', () => { + const buttons = calculateButtons(controller, { inExpandedMode: false }); + + expect(buttons).toContainEqual({ + icon: 'mdi:arrow-expand-all', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Expand', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'expand' }, + style: {}, + }); + }); + + it('when expanded', () => { + const buttons = calculateButtons(controller, { inExpandedMode: true }); + + expect(buttons).toContainEqual({ + icon: 'mdi:arrow-collapse-all', + enabled: false, + priority: 50, + type: 'custom:frigate-card-menu-icon', + title: 'Expand', + tap_action: { action: 'fire-dom-event', frigate_card_action: 'expand' }, + style: { color: 'var(--primary-color, white)' }, + }); + }); + }); + + describe('should have media players button', () => { + it('with media players', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ + camera_entity: 'camera.1', + }), + }, + ]), + ); + + const mediaPlayerController = mock(); + mediaPlayerController.hasMediaPlayers.mockReturnValue(true); + mediaPlayerController.getMediaPlayers.mockReturnValue(['media_player.tv']); + + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + mediaPlayerController: mediaPlayerController, + hass: createHASS({ + 'media_player.tv': createStateEntity({ entity_id: 'media_player.tv' }), + }), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:cast', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-submenu', + title: 'Send to media player', + items: [ + { + enabled: true, + selected: false, + icon: 'mdi:cast', + entity: 'media_player.tv', + state_color: false, + title: 'media_player.tv', + disabled: false, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'media_player', + media_player: 'media_player.tv', + media_player_action: 'play', + }, + hold_action: { + action: 'fire-dom-event', + frigate_card_action: 'media_player', + media_player: 'media_player.tv', + media_player_action: 'stop', + }, + }, + ], + }); + }); + + it('when entity not found', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ + camera_entity: 'camera.1', + }), + }, + ]), + ); + const mediaPlayerController = mock(); + mediaPlayerController.hasMediaPlayers.mockReturnValue(true); + mediaPlayerController.getMediaPlayers.mockReturnValue(['not_a_real_player']); + + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + mediaPlayerController: mediaPlayerController, + hass: createHASS(), + }); + + expect(buttons).toContainEqual({ + icon: 'mdi:cast', + enabled: true, + priority: 50, + type: 'custom:frigate-card-menu-submenu', + title: 'Send to media player', + items: [ + { + enabled: true, + selected: false, + icon: 'mdi:bookmark', + entity: 'not_a_real_player', + state_color: false, + title: 'not_a_real_player', + disabled: true, + }, + ], + }); }); }); @@ -1124,6 +1212,7 @@ describe('MenuButtonController', () => { vi.mocked(cameraManager.getStore).mockReturnValue( createStore([{ cameraID: 'camera-1' }, { cameraID: 'camera-2' }]), ); + expect( calculateButtons(controller, { cameraManager: cameraManager, view: view }), ).toContainEqual({ @@ -1154,6 +1243,7 @@ describe('MenuButtonController', () => { ); const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).not.toContainEqual({ enabled: false, icon: 'mdi:pan', @@ -1176,8 +1266,8 @@ describe('MenuButtonController', () => { vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( createCameraCapabilities({ ptz: {} }), ); - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + expect(buttons).toContainEqual({ enabled: false, icon: 'mdi:pan', @@ -1204,11 +1294,11 @@ describe('MenuButtonController', () => { camera: 'camera-1', context: { live: { ptzVisible: false } }, }); - const buttons = calculateButtons(controller, { cameraManager: cameraManager, view: view, }); + expect(buttons).toContainEqual({ enabled: false, icon: 'mdi:pan', @@ -1223,129 +1313,181 @@ describe('MenuButtonController', () => { type: 'custom:frigate-card-menu-icon', }); }); - }); - it('should handle dynamic buttons', () => { - const button: MenuItem = { - ...dynamicButton, - style: {}, - }; - controller.addDynamicMenuButton(button); - expect( - calculateButtons(controller).filter((menuButton) => isEqual(button, menuButton)) - .length, - ).toBe(1); + it('when a substream is PTZ enabled', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), + }, + { cameraID: 'camera-2' }, + ]), + ); + vi.mocked(cameraManager.getCameraCapabilities).mockImplementation( + (cameraID: string) => { + if (cameraID === 'camera-2') { + return createCameraCapabilities({ ptz: {} }); + } + return createCameraCapabilities(); + }, + ); + const view = createView({ + camera: 'camera-1', + context: { + live: { + overrides: new Map([['camera-1', 'camera-2']]), + }, + }, + }); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); - // Adding it again will have no effect. - controller.addDynamicMenuButton(button); - expect( - calculateButtons(controller).filter((menuButton) => isEqual(button, menuButton)) - .length, - ).toBe(1); - - controller.removeDynamicMenuButton(button); - expect(calculateButtons(controller)).not.toContainEqual(button); - }); - - it('should not set style for dynamic button with stock action', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: { action: 'navigate', navigation_path: 'foo' }, - }; - controller.addDynamicMenuButton(button); - - expect(calculateButtons(controller)).toContainEqual({ - ...button, - style: {}, + expect(buttons).toContainEqual({ + enabled: false, + icon: 'mdi:pan', + priority: 50, + style: { + color: 'var(--primary-color, white)', + }, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'show_ptz', + show_ptz: false, + }, + title: 'Show PTZ controls', + type: 'custom:frigate-card-menu-icon', + }); }); }); - it('should not set style for dynamic button with non-Frigate fire-dom-event action', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: { action: 'fire-dom-event' }, - }; - controller.addDynamicMenuButton(button); + describe('should handle dynamic buttons', () => { + it('successfully', () => { + const button: MenuItem = { + ...dynamicButton, + style: {}, + }; + controller.addDynamicMenuButton(button); - controller.addDynamicMenuButton(dynamicButton); - expect(calculateButtons(controller)).toContainEqual({ - ...button, - style: {}, + expect( + calculateButtons(controller).filter((menuButton) => isEqual(button, menuButton)) + .length, + ).toBe(1); + + // Adding it again will have no effect. + controller.addDynamicMenuButton(button); + expect( + calculateButtons(controller).filter((menuButton) => isEqual(button, menuButton)) + .length, + ).toBe(1); + + controller.removeDynamicMenuButton(button); + expect(calculateButtons(controller)).not.toContainEqual(button); }); - }); - it('should set style for dynamic button with Frigate view action', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' }, - }; + it('with stock HA action', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: { action: 'navigate', navigation_path: 'foo' }, + }; + controller.addDynamicMenuButton(button); - const view = createView({ view: 'clips' }); - controller.addDynamicMenuButton(button); - expect(calculateButtons(controller, { view: view })).toContainEqual({ - ...button, - style: { color: 'var(--primary-color, white)' }, + expect(calculateButtons(controller)).toContainEqual({ + ...button, + style: {}, + }); }); - }); - it('should set style for dynamic button with Frigate default action', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'default' }, - }; + it('with non-Frigate fire-dom-event action', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: { action: 'fire-dom-event' }, + }; + controller.addDynamicMenuButton(button); + controller.addDynamicMenuButton(dynamicButton); - controller.addDynamicMenuButton(button); - expect(calculateButtons(controller)).toContainEqual({ - ...button, - style: { color: 'var(--primary-color, white)' }, + expect(calculateButtons(controller)).toContainEqual({ + ...button, + style: {}, + }); }); - }); - it('should set style for dynamic button with fullscreen action', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' }, - }; + it('with Frigate view action', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'clips' }, + }; + const view = createView({ view: 'clips' }); + controller.addDynamicMenuButton(button); - controller.addDynamicMenuButton(button); - expect(calculateButtons(controller, { inFullscreenMode: true })).toContainEqual({ - ...button, - style: { color: 'var(--primary-color, white)' }, + expect(calculateButtons(controller, { view: view })).toContainEqual({ + ...button, + style: { color: 'var(--primary-color, white)' }, + }); }); - }); - it('should set style for dynamic button with camera_select action', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'camera_select', - camera: 'foo', - }, - }; + it('with Frigate default action', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'default' }, + }; + controller.addDynamicMenuButton(button); - const view = createView({ camera: 'foo' }); - controller.addDynamicMenuButton(button); - expect(calculateButtons(controller, { view: view })).toContainEqual({ - ...button, - style: { color: 'var(--primary-color, white)' }, + expect(calculateButtons(controller)).toContainEqual({ + ...button, + style: { color: 'var(--primary-color, white)' }, + }); }); - }); - it('should set style for dynamic button with array of actions', () => { - const button: MenuItem = { - ...dynamicButton, - tap_action: [ - { action: 'fire-dom-event' }, - { action: 'fire-dom-event', frigate_card_action: 'clips' }, - ], - }; + it('with fullscreen action', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: { action: 'fire-dom-event', frigate_card_action: 'fullscreen' }, + }; + controller.addDynamicMenuButton(button); - const view = createView({ camera: 'clips' }); - controller.addDynamicMenuButton(button); - expect(calculateButtons(controller, { view: view })).toContainEqual({ - ...button, - style: {}, + expect(calculateButtons(controller, { inFullscreenMode: true })).toContainEqual({ + ...button, + style: { color: 'var(--primary-color, white)' }, + }); + }); + + it('with camera_select action', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + camera: 'foo', + }, + }; + const view = createView({ camera: 'foo' }); + controller.addDynamicMenuButton(button); + + expect(calculateButtons(controller, { view: view })).toContainEqual({ + ...button, + style: { color: 'var(--primary-color, white)' }, + }); + }); + + it('with array of actions', () => { + const button: MenuItem = { + ...dynamicButton, + tap_action: [ + { action: 'fire-dom-event' }, + { action: 'fire-dom-event', frigate_card_action: 'clips' }, + ], + }; + const view = createView({ camera: 'clips' }); + controller.addDynamicMenuButton(button); + + expect(calculateButtons(controller, { view: view })).toContainEqual({ + ...button, + style: {}, + }); }); }); }); From ff78cc51a1f9869402bc08d7d36ce4ac2eed14b0 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 10 Mar 2024 14:30:45 -0700 Subject: [PATCH 101/189] Add support for users and numeric_conditions. --- src/card-controller/conditions-manager.ts | 32 +- src/card-controller/hass-manager.ts | 5 +- src/config/types.ts | 53 +- .../conditions-manager.test.ts | 689 +++++++++++------- tests/card-controller/hass-manager.test.ts | 5 +- tests/config/types.test.ts | 2 + tests/test-utils.ts | 17 +- 7 files changed, 522 insertions(+), 281 deletions(-) diff --git a/src/card-controller/conditions-manager.ts b/src/card-controller/conditions-manager.ts index 848d2a1e..6d326d1f 100644 --- a/src/card-controller/conditions-manager.ts +++ b/src/card-controller/conditions-manager.ts @@ -1,3 +1,4 @@ +import { CurrentUser } from '@dermotduffy/custom-card-helpers'; import { HassEntities } from 'home-assistant-js-websocket'; import merge from 'lodash-es/merge'; import { copyConfig } from '../config-mgmt'; @@ -22,6 +23,7 @@ interface ConditionState { triggered?: Set; interaction?: boolean; microphone?: MicrophoneConditionState; + user?: CurrentUser; } export class ConditionEvaluateRequestEvent extends Event { @@ -174,7 +176,10 @@ export class ConditionsManager { const conditions = getAllConditions(); this._hasHAStateConditions = conditions.some( - (condition) => !!condition.state?.length, + (condition) => + !!condition.state?.length || + !!condition.numeric_state?.length || + !!condition.users?.length, ); conditions.forEach((condition) => { if (condition.media_query) { @@ -192,7 +197,7 @@ export class ConditionsManager { }; this._triggerChange(); } - + public getState(): ConditionState { return this._state; } @@ -235,11 +240,30 @@ export class ConditionsManager { ((!stateTest.state && !stateTest.state_not) || (stateTest.entity in state.state && (!stateTest.state || - state.state[stateTest.entity].state === stateTest.state) && + (Array.isArray(stateTest.state) + ? stateTest.state.includes(state.state[stateTest.entity].state) + : stateTest.state === state.state[stateTest.entity].state)) && (!stateTest.state_not || - state.state[stateTest.entity].state !== stateTest.state_not))); + (Array.isArray(stateTest.state_not) + ? !stateTest.state_not.includes(state.state[stateTest.entity].state) + : stateTest.state_not !== state.state[stateTest.entity].state)))); } } + if (condition.numeric_state?.length) { + for (const stateTest of condition.numeric_state) { + result &&= + !!state.state && + stateTest.entity in state.state && + state.state[stateTest.entity].state !== undefined && + (stateTest.above === undefined || + Number(state.state[stateTest.entity].state) > stateTest.above) && + (stateTest.below === undefined || + Number(state.state[stateTest.entity].state) < stateTest.below); + } + } + if (condition.users?.length) { + result &&= !!state.user && condition.users.includes(state.user.id); + } if (condition.media_loaded !== undefined) { result &&= state.media_loaded !== undefined && diff --git a/src/card-controller/hass-manager.ts b/src/card-controller/hass-manager.ts index db50c7c9..9c0d3503 100644 --- a/src/card-controller/hass-manager.ts +++ b/src/card-controller/hass-manager.ts @@ -66,7 +66,10 @@ export class HASSManager { } if (this._api.getConditionsManager().hasHAStateConditions()) { - this._api.getConditionsManager().setState({ state: this._hass.states }); + this._api.getConditionsManager().setState({ + state: this._hass.states, + user: this._hass.user, + }); } // Dark mode may depend on HASS. diff --git a/src/config/types.ts b/src/config/types.ts index 44bddb1d..d835eb1f 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -400,20 +400,47 @@ const imageSchema = elementsBaseSchema.extend({ aspect_ratio: z.string().optional(), }); -// This state condition is used both for the Picture elements conditional -// schema, and also in frigateCardConditionSchema. -const stateConditions = z - .object({ - entity: z.string(), - state: z.string().optional(), - state_not: z.string().optional(), - }) - .array(); +// https://www.home-assistant.io/dashboards/conditional/#state +const stateCondition = z.object({ + condition: z.literal('state'), + entity: z.string(), + state: z.string().or(z.string().array()).optional(), + state_not: z.string().or(z.string().array()).optional(), +}); + +// https://www.home-assistant.io/dashboards/conditional/#numeric-state +const numericCondition = z.object({ + condition: z.literal('numeric_state'), + entity: z.string(), + above: z.number().optional(), + below: z.number().optional(), +}); + +const mediaQuerySchema = z.string(); + +// https://www.home-assistant.io/dashboards/conditional/#screen +const screenCondition = z.object({ + condition: z.literal('screen'), + media_query: mediaQuerySchema, +}); + +// https://www.home-assistant.io/dashboards/conditional/#user +const usersCondition = z.object({ + condition: z.literal('user'), + users: z.string().array().min(1), +}); + +const stockCondition = z.union([ + stateCondition, + numericCondition, + screenCondition, + usersCondition, +]); // https://www.home-assistant.io/lovelace/picture-elements/#image-element export const conditionalSchema = z.object({ type: z.literal('conditional'), - conditions: stateConditions, + conditions: stockCondition.array(), elements: z.lazy(() => pictureElementsSchema), }); @@ -501,12 +528,14 @@ export const frigateCardConditionSchema = z.object({ expand: z.boolean().optional(), camera: z.string().array().optional(), media_loaded: z.boolean().optional(), - state: stateConditions.optional(), - media_query: z.string().optional(), + state: stateCondition.array().optional(), + numeric_state: numericCondition.array().optional(), + media_query: mediaQuerySchema.optional(), display_mode: viewDisplayModeSchema.optional(), triggered: z.string().array().optional(), interaction: z.boolean().optional(), microphone: microphoneConditionSchema.optional(), + users: z.string().array().optional() }); export type FrigateCardCondition = z.infer; diff --git a/tests/card-controller/conditions-manager.test.ts b/tests/card-controller/conditions-manager.test.ts index b40dffaf..a6f5fe9e 100644 --- a/tests/card-controller/conditions-manager.test.ts +++ b/tests/card-controller/conditions-manager.test.ts @@ -1,4 +1,4 @@ -import { afterEach, describe, expect, it, vi } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { FrigateCardCondition } from '../../src/config/types'; import { ConditionEvaluateRequestEvent, @@ -12,6 +12,7 @@ import { createCondition, createConfig, createStateEntity, + createUser, } from '../test-utils'; // @vitest-environment jsdom @@ -145,49 +146,6 @@ describe('getOverridesByKey', () => { }); describe('ConditionsManager', () => { - const config = { - type: 'custom:frigate-card', - cameras: [], - elements: [ - { - type: 'custom:frigate-card-conditional', - conditions: { - fullscreen: true, - }, - elements: [ - { - type: 'custom:nested-unknown-object', - unknown_key: { - type: 'custom:frigate-card-conditional', - conditions: { - media_query: 'media query goes here', - }, - elements: [], - }, - }, - ], - }, - ], - overrides: [ - { - overrides: { - menu: { - style: 'overlay', - }, - }, - conditions: { - fullscreen: true, - state: [ - { - entity: 'binary_sensor.foo', - state: 'on', - }, - ], - }, - }, - ], - }; - afterEach(() => { vi.restoreAllMocks(); }); @@ -214,252 +172,461 @@ describe('ConditionsManager', () => { expect(manager.getState()).toEqual(state); }); - it('should not return hasHAStateConditions without HA state conditions', () => { - const manager = new ConditionsManager(createCardAPI()); - expect(manager.hasHAStateConditions()).toBeFalsy(); - }); + describe('should handle hasHAStateConditions', () => { + beforeEach(() => { + vi.spyOn(window, 'matchMedia').mockReturnValueOnce({ + matches: false, + addEventListener: vi.fn(), + } as unknown as MediaQueryList); + }); - it('should return hasHAStateConditions with HA state conditions', () => { - vi.spyOn(window, 'matchMedia').mockReturnValueOnce({ - matches: false, - addEventListener: vi.fn(), - } as unknown as MediaQueryList); - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig(config)); - const manager = new ConditionsManager(api); + afterEach(() => { + vi.restoreAllMocks(); + }); - manager.setConditionsFromConfig(); - - expect(manager.hasHAStateConditions()).toBeTruthy(); - }); - - it('should evaluate conditions with a view', () => { - const manager = new ConditionsManager(createCardAPI()); - const condition = { view: ['foo'] }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ view: 'foo' }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - }); - - it('should evaluate conditions with fullscreen', () => { - const manager = new ConditionsManager(createCardAPI()); - const condition = { fullscreen: true }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ fullscreen: true }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ fullscreen: false }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - }); - - it('should evaluate conditions with expand', () => { - const manager = new ConditionsManager(createCardAPI()); - const condition = { expand: true }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ expand: true }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ expand: false }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - }); - - it('should evaluate conditions with camera', () => { - const manager = new ConditionsManager(createCardAPI()); - const condition = { camera: ['bar'] }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ camera: 'bar' }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ camera: 'will-not-match' }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - }); - - it('should evaluate conditions with ha state positive check', () => { - const manager = new ConditionsManager(createCardAPI()); - const condition = { - state: [ - { - entity: 'binary_sensor.foo', - state: 'on', - }, - ], + const createSuitableConfig = (conditions: FrigateCardCondition) => { + return createConfig({ + overrides: [ + { + overrides: {}, + conditions: conditions, + }, + ], + }); }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ state: { 'binary_sensor.foo': createStateEntity() } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ - state: { 'binary_sensor.foo': createStateEntity({ state: 'off' }) }, - }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - }); - it('should evaluate conditions with ha state negative check', () => { - const manager = new ConditionsManager(createCardAPI()); - const condition = { - state: [ - { - entity: 'binary_sensor.foo', - state_not: 'on', - }, - ], - }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ state: { 'binary_sensor.foo': createStateEntity() } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ - state: { 'binary_sensor.foo': createStateEntity({ state: 'off' }) }, - }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - }); - - it('should evaluate conditions with media_loaded', () => { - const manager = new ConditionsManager(createCardAPI()); - const condition = { media_loaded: true }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ media_loaded: true }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ media_loaded: false }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - }); - - it('should evaluate conditions with media query', () => { - vi.spyOn(window, 'matchMedia') - .mockReturnValueOnce({ matches: true }) - .mockReturnValueOnce({ matches: false }); - - const manager = new ConditionsManager(createCardAPI()); - const condition = { media_query: 'whatever' }; - expect(manager.evaluateCondition(condition)).toBeTruthy(); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - }); - - it('should trigger on changes to media query conditions', () => { - const addEventListener = vi.fn(); - const removeEventListener = vi.fn(); - vi.spyOn(window, 'matchMedia').mockReturnValueOnce({ - matches: true, - addEventListener: addEventListener, - removeEventListener: removeEventListener, - } as unknown as MediaQueryList); - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig(config)); - const callback = vi.fn(); - const manager = new ConditionsManager(api, callback); - - manager.setConditionsFromConfig(); - - expect(addEventListener).toHaveBeenCalledWith('change', expect.anything()); - - // Call the media query callback and use it to pretend a match happened. The - // callback is the 0th mock innvocation and the 1st argument. - addEventListener.mock.calls[0][1](); - - // This should result in a callback to our state listener. - expect(callback).toBeCalled(); - - // Remove the conditions, which should remove the media query listener. - manager.removeConditions(); - expect(removeEventListener).toBeCalled(); - }); - - it('should evaluate conditions with display mode', () => { - const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { display_mode: 'grid' }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ displayMode: 'grid' }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ displayMode: 'single' }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - }); - - it('should evaluate conditions with triggers', () => { - const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { triggered: ['camera_1', 'camera_2'] }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ triggered: new Set(['camera_1']) }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ triggered: new Set(['camera_2', 'camera_1', 'camera_3']) }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ triggered: new Set(['camera_3']) }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - }); - - it('should evaluate conditions with interaction', () => { - const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { interaction: true }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ interaction: true }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ interaction: false }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - }); - - describe('should evaluate conditions with microphone', () => { - it('empty', () => { + it('without HA state conditions', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { microphone: {} }; - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ microphone: { connected: true } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ microphone: { connected: false } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ microphone: { muted: true } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ microphone: { muted: false } }); + expect(manager.hasHAStateConditions()).toBeFalsy(); + }); + + it('with HA state conditions', () => { + const api = createCardAPI(); + const numericConfig = createSuitableConfig({ + state: [ + { + condition: 'state', + entity: 'binary_sensor.foo', + state: 'on', + }, + ], + }); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(numericConfig); + const manager = new ConditionsManager(api); + manager.setConditionsFromConfig(); + + expect(manager.hasHAStateConditions()).toBeTruthy(); + }); + + it('with HA numeric_state conditions', () => { + const api = createCardAPI(); + const stateConfig = createSuitableConfig({ + numeric_state: [ + { + entity: 'sensor.foo', + condition: 'numeric_state' as const, + above: 10, + }, + ], + }); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(stateConfig); + const manager = new ConditionsManager(api); + manager.setConditionsFromConfig(); + + expect(manager.hasHAStateConditions()).toBeTruthy(); + }); + + it('with HA user conditions', () => { + const api = createCardAPI(); + const userConfig = createSuitableConfig({ + users: ['user_1'], + }); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(userConfig); + const manager = new ConditionsManager(api); + manager.setConditionsFromConfig(); + + expect(manager.hasHAStateConditions()).toBeTruthy(); + }); + }); + + describe('should evaluate conditions', () => { + it('with a view', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition = { view: ['foo'] }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ view: 'foo' }); expect(manager.evaluateCondition(condition)).toBeTruthy(); }); - it('connected is true', () => { + it('with fullscreen', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { microphone: { connected: true } }; + const condition = { fullscreen: true }; expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ microphone: { connected: true } }); + manager.setState({ fullscreen: true }); expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ microphone: { connected: false } }); + manager.setState({ fullscreen: false }); expect(manager.evaluateCondition(condition)).toBeFalsy(); }); - it('connected is false', () => { + it('with expand', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { microphone: { connected: false } }; + const condition = { expand: true }; expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ microphone: { connected: true } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ microphone: { connected: false } }); + manager.setState({ expand: true }); expect(manager.evaluateCondition(condition)).toBeTruthy(); - }); - - it('muted is true', () => { - const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { microphone: { muted: true } }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ microphone: { muted: true } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); - manager.setState({ microphone: { muted: false } }); + manager.setState({ expand: false }); expect(manager.evaluateCondition(condition)).toBeFalsy(); }); - it('muted is false', () => { + it('camera', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { microphone: { muted: false } }; + const condition = { camera: ['bar'] }; expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ microphone: { muted: true } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ microphone: { muted: false } }); + manager.setState({ camera: 'bar' }); expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ camera: 'will-not-match' }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); }); - it('connected and muted', () => { + describe('with stock HA conditions', () => { + describe('state check', () => { + describe('positive', () => { + it('single', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition = { + state: [ + { + condition: 'state' as const, + entity: 'binary_sensor.foo', + state: 'on', + }, + ], + }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ state: { 'binary_sensor.foo': createStateEntity() } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ + state: { 'binary_sensor.foo': createStateEntity({ state: 'off' }) }, + }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + it('multiple', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition = { + state: [ + { + condition: 'state' as const, + entity: 'binary_sensor.foo', + state: ['active', 'on'], + }, + ], + }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ state: { 'binary_sensor.foo': createStateEntity() } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ + state: { 'binary_sensor.foo': createStateEntity({ state: 'active' }) }, + }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ + state: { 'binary_sensor.foo': createStateEntity({ state: 'off' }) }, + }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + }); + + describe('negative', () => { + it('single', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition = { + state: [ + { + condition: 'state' as const, + entity: 'binary_sensor.foo', + state_not: 'on', + }, + ], + }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ state: { 'binary_sensor.foo': createStateEntity() } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ + state: { 'binary_sensor.foo': createStateEntity({ state: 'off' }) }, + }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + }); + }); + + it('multiple', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition = { + state: [ + { + condition: 'state' as const, + entity: 'binary_sensor.foo', + state_not: ['active', 'on'], + }, + ], + }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ state: { 'binary_sensor.foo': createStateEntity() } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ + state: { 'binary_sensor.foo': createStateEntity({ state: 'active' }) }, + }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ + state: { 'binary_sensor.foo': createStateEntity({ state: 'off' }) }, + }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + }); + }); + + describe('numeric state check', () => { + it('above', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition = { + numeric_state: [ + { + condition: 'numeric_state' as const, + entity: 'sensor.foo', + above: 10, + }, + ], + }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ + state: { 'sensor.foo': createStateEntity({ state: '11' }) }, + }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ + state: { 'binary_sensor.foo': createStateEntity({ state: '9' }) }, + }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + it('below', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition = { + numeric_state: [ + { + condition: 'numeric_state' as const, + entity: 'sensor.foo', + below: 10, + }, + ], + }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ + state: { 'sensor.foo': createStateEntity({ state: '11' }) }, + }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ + state: { 'sensor.foo': createStateEntity({ state: '9' }) }, + }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + }); + }); + }); + + it('with users', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { - microphone: { muted: false, connected: true }, + const condition = { + users: ['user_1', 'user_2'], }; expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ microphone: { muted: true } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ microphone: { muted: false } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ microphone: { connected: false, muted: false } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); - manager.setState({ microphone: { connected: true, muted: false } }); + manager.setState({ + user: createUser({ id: 'user_1' }), + }); expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ + user: createUser({ id: 'user_WRONG' }), + }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + it('with media_loaded', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition = { media_loaded: true }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ media_loaded: true }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ media_loaded: false }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + describe('with media query', () => { + const mediaQueryConfig = { + type: 'custom:frigate-card', + cameras: [], + elements: [ + { + type: 'custom:frigate-card-conditional', + conditions: { + fullscreen: true, + }, + elements: [ + { + type: 'custom:nested-unknown-object', + unknown_key: { + type: 'custom:frigate-card-conditional', + conditions: { + media_query: 'media query goes here', + }, + elements: [], + }, + }, + ], + }, + ], + }; + + it('on evaluation', () => { + vi.spyOn(window, 'matchMedia') + .mockReturnValueOnce({ matches: true }) + .mockReturnValueOnce({ matches: false }); + + const manager = new ConditionsManager(createCardAPI()); + const condition = { media_query: 'whatever' }; + expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + it('on trigger', () => { + const addEventListener = vi.fn(); + const removeEventListener = vi.fn(); + vi.spyOn(window, 'matchMedia').mockReturnValueOnce({ + matches: true, + addEventListener: addEventListener, + removeEventListener: removeEventListener, + } as unknown as MediaQueryList); + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig(mediaQueryConfig), + ); + const callback = vi.fn(); + const manager = new ConditionsManager(api, callback); + + manager.setConditionsFromConfig(); + + expect(addEventListener).toHaveBeenCalledWith('change', expect.anything()); + + // Call the media query callback and use it to pretend a match happened. The + // callback is the 0th mock innvocation and the 1st argument. + addEventListener.mock.calls[0][1](); + + // This should result in a callback to our state listener. + expect(callback).toBeCalled(); + + // Remove the conditions, which should remove the media query listener. + manager.removeConditions(); + expect(removeEventListener).toBeCalled(); + }); + }); + + it('with display mode', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { display_mode: 'grid' }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ displayMode: 'grid' }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ displayMode: 'single' }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + it('with triggers', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { triggered: ['camera_1', 'camera_2'] }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ triggered: new Set(['camera_1']) }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ triggered: new Set(['camera_2', 'camera_1', 'camera_3']) }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ triggered: new Set(['camera_3']) }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + it('with interaction', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { interaction: true }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ interaction: true }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ interaction: false }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + describe('with microphone', () => { + it('empty', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { microphone: {} }; + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ microphone: { connected: true } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ microphone: { connected: false } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ microphone: { muted: true } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ microphone: { muted: false } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + }); + + it('connected is true', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { microphone: { connected: true } }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { connected: true } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ microphone: { connected: false } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + it('connected is false', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { microphone: { connected: false } }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { connected: true } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { connected: false } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + }); + + it('muted is true', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { microphone: { muted: true } }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { muted: true } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + manager.setState({ microphone: { muted: false } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + }); + + it('muted is false', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { microphone: { muted: false } }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { muted: true } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { muted: false } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + }); + + it('connected and muted', () => { + const manager = new ConditionsManager(createCardAPI()); + const condition: FrigateCardCondition = { + microphone: { muted: false, connected: true }, + }; + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { muted: true } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { muted: false } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { connected: false, muted: false } }); + expect(manager.evaluateCondition(condition)).toBeFalsy(); + manager.setState({ microphone: { connected: true, muted: false } }); + expect(manager.evaluateCondition(condition)).toBeTruthy(); + }); }); }); }); diff --git a/tests/card-controller/hass-manager.test.ts b/tests/card-controller/hass-manager.test.ts index 45205f0e..3d0a1fa3 100644 --- a/tests/card-controller/hass-manager.test.ts +++ b/tests/card-controller/hass-manager.test.ts @@ -9,6 +9,7 @@ import { createHASS, createStateEntity, createStore, + createUser, createView, } from '../test-utils'; @@ -44,13 +45,15 @@ describe('HASSManager', () => { vi.mocked(api.getConditionsManager().hasHAStateConditions).mockReturnValue(true); const states = { 'switch.foo': createStateEntity() }; - const hass = createHASS(states); + const user = createUser({ id: 'user_1' }); + const hass = createHASS(states, user); manager.setHASS(hass); expect(api.getConditionsManager().setState).toBeCalledWith( expect.objectContaining({ state: states, + user: user, }), ); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 632586a7..c3b2d4c2 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -381,6 +381,7 @@ describe('should lazy evaluate', () => { type: 'conditional', conditions: [ { + condition: 'state', entity: 'light.office_main_lights', state: 'on', state_not: 'off', @@ -401,6 +402,7 @@ describe('should lazy evaluate', () => { ).toEqual({ conditions: [ { + condition: 'state', entity: 'light.office_main_lights', state: 'on', state_not: 'off', diff --git a/tests/test-utils.ts b/tests/test-utils.ts index 773c3220..721c1439 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -1,4 +1,4 @@ -import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { CurrentUser, HomeAssistant } from '@dermotduffy/custom-card-helpers'; import { HassEntities, HassEntity } from 'home-assistant-js-websocket'; import { expect, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; @@ -80,15 +80,28 @@ export const createCamera = ( return new Camera(config, engine, { capabilities: capabilities }); }; -export const createHASS = (states?: HassEntities): ExtendedHomeAssistant => { +export const createHASS = (states?: HassEntities, user?: CurrentUser): ExtendedHomeAssistant => { const hass = mock(); if (states) { hass.states = states; } + if (user) { + hass.user = user; + } hass.connection.subscribeMessage = vi.fn(); return hass; }; +export const createUser = (user?: Partial): CurrentUser => ({ + id: 'user', + is_owner: false, + is_admin: false, + name: 'User', + credentials: [], + mfa_modules: [], + ...user, +}); + export const createRegistryEntity = (entity?: Partial): Entity => { return { config_entry_id: entity?.config_entry_id ?? null, From 829f411acc90bb47dcc15e413048e791593463a5 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 10 Mar 2024 18:09:17 -0700 Subject: [PATCH 102/189] Convert conditions to HA style. --- README.md | 277 +++++--- src/card-controller/automations-manager.ts | 2 +- src/card-controller/conditions-manager.ts | 188 ++--- src/card.ts | 6 +- src/config-mgmt.ts | 111 ++- src/config/types.ts | 99 ++- src/const.ts | 2 + .../automations-manager.test.ts | 22 +- .../conditions-manager.test.ts | 434 ++++++------ tests/config-mgmt.test.ts | 664 +++++++++++++++++- tests/test-utils.ts | 5 +- 11 files changed, 1334 insertions(+), 476 deletions(-) diff --git a/README.md b/README.md index 88360996..2ad37a81 100644 --- a/README.md +++ b/README.md @@ -186,7 +186,7 @@ See the [fully expanded cameras configuration example](#config-expanded-cameras) #### Camera Frigate configuration -The `frigate` block configures options for a Frigate camera. This configuration is included as part of a camera entry in the `cameras` array. +The `frigate` block configures options for a Frigate camera. This configuration is included as part of a camera entry in the `cameras` list. ```yaml cameras: @@ -197,13 +197,13 @@ cameras: | - | - | - | - | | `camera_name` | Autodetected from `camera_entity` if that is specified. | :white_check_mark: | The Frigate camera name to use when communicating with the Frigate server, e.g. for viewing clips/snapshots or the JSMPEG live view.| | `url` | | :white_check_mark: | The URL of the frigate server. If set, this value will be (exclusively) used for a `Camera UI` menu button. All other communication with Frigate goes via Home Assistant. | -| `labels` | | :white_check_mark: | An array of Frigate labels used to filter events (clips & snapshots), e.g. [`person`, `car`].| -| `zones` | | :white_check_mark: | An array of Frigates zones used to filter events (clips & snapshots), e.g. [`front_door`, `front_steps`].| +| `labels` | | :white_check_mark: | A list of Frigate labels used to filter events (clips & snapshots), e.g. [`person`, `car`].| +| `zones` | | :white_check_mark: | A list of Frigates zones used to filter events (clips & snapshots), e.g. [`front_door`, `front_steps`].| | `client_id` | `frigate` | :white_check_mark: | The Frigate client id to use. If this Home Assistant server has multiple Frigate server backends configured, this selects which server should be used. It should be set to the MQTT client id configured for this server, see [Frigate Integration Multiple Instance Support](https://docs.frigate.video/integrations/home-assistant/#multiple-instance-support).| #### Camera MotionEye configuration -The `motioneye` block configures options for a MotionEye camera. This configuration is included as part of a camera entry in the `cameras` array. +The `motioneye` block configures options for a MotionEye camera. This configuration is included as part of a camera entry in the `cameras` list. ```yaml cameras: @@ -241,7 +241,7 @@ cameras: #### Live Provider: Camera go2rtc configuration -The `go2rtc` block configures use of the `go2rtc` live provider. This configuration is included as part of a camera entry in the `cameras` array. +The `go2rtc` block configures use of the `go2rtc` live provider. This configuration is included as part of a camera entry in the `cameras` list. ```yaml cameras: @@ -250,7 +250,7 @@ cameras: | Option | Default | Overridable | Description | | - | - | - | - | -| `modes` | `[webrtc, mse, mp4, mjpeg]` | :white_check_mark: | An ordered array of `go2rtc` modes to use. Valid values are `webrtc`, `mse`, `mp4` or `mjpeg` values. | +| `modes` | `[webrtc, mse, mp4, mjpeg]` | :white_check_mark: | An ordered list of `go2rtc` modes to use. Valid values are `webrtc`, `mse`, `mp4` or `mjpeg` values. | | `stream` | Determined by camera engine (e.g. `frigate` camera name). | :white_check_mark: | A valid `go2rtc` stream name. | | `url` | Determined by camera engine (e.g. the `frigate` engine will automatically generate a URL for the go2rtc backend that runs in the Frigate container). | :white_check_mark: | The root `go2rtc` URL the card should stream the video from. This is only needed for non-Frigate usecases, or advanced Frigate usecases. Example: `http://my-custom-go2rtc:1984` | @@ -314,7 +314,7 @@ cameras: | Option | Default | Overridable | Description | | - | - | - | - | -| `cameras` | | :white_check_mark: | An optional array of other camera identifiers (see [camera IDs](#camera-ids)). If specified the card will fetch media for this camera and *also* recursively for the named cameras by default. Live views for the involved cameras will be available as 'substreams' of the main (depended upon) camera. All dependent cameras must themselves be a configured camera in the card. This can be useful to group events for cameras that are close together, to show multiple related live views, to always have clips/snapshots show fully merged events across all cameras or to show events for the `birdseye` camera that otherwise would not have events itself.| +| `cameras` | | :white_check_mark: | An optional list of other camera identifiers (see [camera IDs](#camera-ids)). If specified the card will fetch media for this camera and *also* recursively for the named cameras by default. Live views for the involved cameras will be available as 'substreams' of the main (depended upon) camera. All dependent cameras must themselves be a configured camera in the card. This can be useful to group events for cameras that are close together, to show multiple related live views, to always have clips/snapshots show fully merged events across all cameras or to show events for the `birdseye` camera that otherwise would not have events itself.| | `all_cameras` | `false` | :white_check_mark: | Shortcut to specify all other cameras as dependent cameras.| @@ -555,12 +555,12 @@ See the [fully expanded live configuration example](#config-expanded-live) for h | Option | Default | Overridable | Description | | - | - | - | - | | `preload` | `false` | :heavy_multiplication_x: | Whether or not to preload the live view. Preloading causes the live view to render in the background regardless of what view is actually shown, so it's instantly available when requested. This consumes additional network/CPU resources continually. | -| `auto_play` | `[selected, visible]` | :heavy_multiplication_x: | An array of conditions in which live camera feeds are automatically played.`selected` will automatically play when a camera is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play. Some live providers (e.g. `webrtc-card`, `jsmpeg`) do not support the prevention of automatic play on initial load, but should still respect the value of this flag on play-after-pause.| -| `auto_pause` | `[]` | :heavy_multiplication_x: | An array of conditions in which live camera feeds are automatically paused. `unselected` will automatically pause when a camera is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause. **Caution**: Some live providers (e.g. `jsmpeg`) may not offer human-accessible means to resume play if it is paused, unless the `auto_play` option (above) is used.| -| `auto_mute` | `[unselected, hidden, microphone]` | :heavy_multiplication_x: | An array of conditions in which live camera feeds are muted. `unselected` will automatically mute when a camera is unselected in the carousel, `hidden` will automatically mute when the browser/tab becomes hidden or `microphone` will automatically mute after the microphone is muted as long as the camera stays selected (see the `live.microphone.mute_after_microphone_mute_seconds` to control how long after). Use an empty list (`[]`) to never automatically mute. Note that if `auto_play` is enabled, the stream may mute itself automatically in order to honor the `auto_play` setting, as some browsers will not auto play media that is unmuted -- that is to say, where necessary, the `auto_play` parameter will take priority over the `auto_mute` parameter.| -| `auto_unmute` | `[microphone]` | :heavy_multiplication_x: | An array of conditions in which live camera feeds are unmuted. `selected` will automatically unmute when a camera is unselected in the carousel, `visible` will automatically unmute when the browser/tab becomes visible or `microphone` will automatically unmute after the microphone is unmuted. Use an empty list (`[]`) to never automatically unmute.| +| `auto_play` | `[selected, visible]` | :heavy_multiplication_x: | A list of conditions in which live camera feeds are automatically played.`selected` will automatically play when a camera is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play. Some live providers (e.g. `webrtc-card`, `jsmpeg`) do not support the prevention of automatic play on initial load, but should still respect the value of this flag on play-after-pause.| +| `auto_pause` | `[]` | :heavy_multiplication_x: | A list of conditions in which live camera feeds are automatically paused. `unselected` will automatically pause when a camera is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause. **Caution**: Some live providers (e.g. `jsmpeg`) may not offer human-accessible means to resume play if it is paused, unless the `auto_play` option (above) is used.| +| `auto_mute` | `[unselected, hidden, microphone]` | :heavy_multiplication_x: | A list of conditions in which live camera feeds are muted. `unselected` will automatically mute when a camera is unselected in the carousel, `hidden` will automatically mute when the browser/tab becomes hidden or `microphone` will automatically mute after the microphone is muted as long as the camera stays selected (see the `live.microphone.mute_after_microphone_mute_seconds` to control how long after). Use an empty list (`[]`) to never automatically mute. Note that if `auto_play` is enabled, the stream may mute itself automatically in order to honor the `auto_play` setting, as some browsers will not auto play media that is unmuted -- that is to say, where necessary, the `auto_play` parameter will take priority over the `auto_mute` parameter.| +| `auto_unmute` | `[microphone]` | :heavy_multiplication_x: | A list of conditions in which live camera feeds are unmuted. `selected` will automatically unmute when a camera is unselected in the carousel, `visible` will automatically unmute when the browser/tab becomes visible or `microphone` will automatically unmute after the microphone is unmuted. Use an empty list (`[]`) to never automatically unmute.| | `lazy_load` | `true` | :heavy_multiplication_x: | Whether or not to lazily load cameras in the camera carousel. Setting this will `false` will cause all cameras to load simultaneously when the `live` carousel is opened (or cause all cameras to load continually if both `lazy_load` and `preload` are `true`). This will result in a smoother carousel experience at a cost of (potentially) a substantial amount of continually streamed data. | -| `lazy_unload` | `[]` | :heavy_multiplication_x: | An array of conditions in which live camera feeds are unloaded. `unselected` will lazy-unload a camera when it is unselected in the carousel and `hidden` will lazy-unload all cameras when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically unload. This will cause a reloading delay on revisiting that camera in the carousel but will save the streaming network resources that are otherwise consumed. This option has no effect if `lazy_load` is false. Some live providers (e.g. `webrtc-card`) implement their own lazy unloading independently which may occur regardless of the value of this setting.| +| `lazy_unload` | `[]` | :heavy_multiplication_x: | A list of conditions in which live camera feeds are unloaded. `unselected` will lazy-unload a camera when it is unselected in the carousel and `hidden` will lazy-unload all cameras when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically unload. This will cause a reloading delay on revisiting that camera in the carousel but will save the streaming network resources that are otherwise consumed. This option has no effect if `lazy_load` is false. Some live providers (e.g. `webrtc-card`) implement their own lazy unloading independently which may occur regardless of the value of this setting.| | `draggable` | `true` | :heavy_multiplication_x: | Whether or not the live carousel can be dragged left or right, via touch/swipe and mouse dragging. | | `zoomable` | `true` | :white_check_mark: | Whether or not the live carousel can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | | `transition_effect` | `slide` | :heavy_multiplication_x: | Effect to apply as a transition between live cameras. Accepted values: `slide` or `none`. | @@ -743,10 +743,10 @@ See the [fully expanded Media viewer configuration example](#config-expanded-med | Option | Default | Overridable | Description | | - | - | - | - | -| `auto_play` | `[selected, visible]` | :heavy_multiplication_x: | An array of conditions in which media items are automatically played.`selected` will automatically play when a media item is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play.| -| `auto_pause` | `[unselected, hidden]` | :heavy_multiplication_x: | An array of conditions in which media items are automatically paused. `unselected` will automatically pause when a media item is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause.| -| `auto_mute` | `[unselected, hidden]` | :heavy_multiplication_x: | An array of conditions in which media items are muted. `unselected` will automatically mute when a media item is unselected in the carousel and `hidden` will automatically mute when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically mute.| -| `auto_unmute` | `[]` | :heavy_multiplication_x: | An array of conditions in which media items are unmuted. `selected` will automatically unmute when a media item is unselected in the carousel and `visible` will automatically unmute when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically unmute. Note that some browsers will not allow automated unmute until the user has interacted with the page in some way -- if the user has not then the browser may pause the media instead.| +| `auto_play` | `[selected, visible]` | :heavy_multiplication_x: | A list of conditions in which media items are automatically played.`selected` will automatically play when a media item is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play.| +| `auto_pause` | `[unselected, hidden]` | :heavy_multiplication_x: | A list of conditions in which media items are automatically paused. `unselected` will automatically pause when a media item is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause.| +| `auto_mute` | `[unselected, hidden]` | :heavy_multiplication_x: | A list of conditions in which media items are muted. `unselected` will automatically mute when a media item is unselected in the carousel and `hidden` will automatically mute when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically mute.| +| `auto_unmute` | `[]` | :heavy_multiplication_x: | A list of conditions in which media items are unmuted. `selected` will automatically unmute when a media item is unselected in the carousel and `visible` will automatically unmute when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically unmute. Note that some browsers will not allow automated unmute until the user has interacted with the page in some way -- if the user has not then the browser may pause the media instead.| | `lazy_load` | `true` | :heavy_multiplication_x: | Whether or not to lazily load media in the Media viewer carousel. Setting this will false will fetch all media immediately which may make the carousel experience smoother at a cost of (potentially) a substantial number of simultaneous media fetches on load. | | `draggable` | `true` | :heavy_multiplication_x: | Whether or not the Media viewer carousel can be dragged left or right, via touch/swipe and mouse dragging. | | `zoomable` | `true` | :heavy_multiplication_x: | Whether or not the Media Viewer can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | @@ -1148,7 +1148,7 @@ item, that has both of the following parameters set: | Option | Default | Overridable | Description | | - | - | - | - | -| `conditions` | | :heavy_multiplication_x: | A set of conditions that must evaluate to `true` in order for the overrides to be applied. See [Frigate Card Conditions](#frigate-card-conditions). | +| `conditions` | | :heavy_multiplication_x: | A list of conditions that must evaluate to `true` in order for the overrides to be applied. See [Frigate Card Conditions](#frigate-card-conditions). | | `overrides` | | :heavy_multiplication_x: |Configuration overrides to be applied. Any configuration parameter described in this documentation as 'Overridable' is supported. | @@ -1166,7 +1166,7 @@ automations: | Option | Default | Overridable | Description | | - | - | - | - | -| `conditions` | | :heavy_multiplication_x: | A set of conditions that will trigger the automation. See [Frigate Card Conditions](#frigate-card-conditions). | +| `conditions` | | :heavy_multiplication_x: | A list of conditions that must evaluate to `true` in order to trigger the automation. See [Frigate Card Conditions](#frigate-card-conditions). | | `actions` | | :heavy_multiplication_x: | An optional list of actions that will be run when the conditions evaluate `true`. Actions can be [stock Home Assistant actions](https://www.home-assistant.io/dashboards/actions/) or [Frigate card actions](#frigate-card-actions).| | `actions_not` | | :heavy_multiplication_x: | An optional list of actions that will be run when the conditions evaluate `false`. Actions can be [stock Home Assistant actions](https://www.home-assistant.io/dashboards/actions/) or [Frigate card actions](#frigate-card-actions).| @@ -1286,57 +1286,79 @@ Usage: ## Frigate Card Conditions -Conditions are used to apply certain configuration depending on runtime evaluations. Conditions may be used in `elements` configuration (as part of a `custom:frigate-card-conditional` element) or the `overrides` configuration (see below for both). - -All variables listed are under a `conditions:` section. - -| Condition | Description | -| ------------- | --------------------------------------------- | -| `view` | A list of [views](#views) in which this condition is satified (e.g. `clips`) | -| `camera` | A list of camera IDs in which this condition is satisfied. See [camera IDs](#camera-ids).| -| `fullscreen` | If `true` the condition is satisfied if the card is in fullscreen mode. If `false` the condition is satisfied if the card is **NOT** in fullscreen mode.| -| `expand` | If `true` the condition is satisfied if the card is in expanded mode (in a dialog/popup). If `false` the condition is satisfied if the card is **NOT** in expanded mode (in a dialog/popup).| -| `state` | A list of state conditions to compare with Home Assistant state. See below. | -| `media_loaded` | If `true` the condition is satisfied if there is media load**ED** (not load**ING**) in the card (e.g. a clip, snapshot or live view). This may be used to hide controls during media loading or when a message (not media) is being displayed. Note that if `true` this condition will never be satisfied for views that do not themselves load media directly (e.g. gallery).| -| `media_query` | Any valid [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries) string. Media queries must start and end with parentheses. This may be used to alter card configuration based on device/media properties (e.g. viewport width, orientation). Please note that `width` and `height` refer to the entire viewport not just the card. See the [media query example](#media-query-example).| -| `interacted` | If `true` the condition is satisfied if the card has had human interaction within `view.interaction_seconds` elapsed seconds. If `false` the condition is satisfied if the card has **NOT** had human interaction in that time. | -| `triggered` | A list of camera IDs which, if [triggered](#camera-triggers-configuration), satisfy the condition.| -| `microphone` | A object to include microphone state as part of the condition evaluation. See below.| +Conditions are used to apply certain configuration depending on runtime evaluations. Conditions may be used in `elements` configuration (as part of a `custom:frigate-card-conditional` element), or in `overrides` and `automations`. See the [example below](#frigate-card-conditional-example) for a real-world example of how these conditions can be used. -### State Conditions +Conditions is a list of conditions objects following the below schema: -```yaml -- conditions: - state: - - [entries] -``` - -The Frigate Card Condition can compare HA state against fixed string values. This is the same as the Home Assistant [Conditional Element](https://www.home-assistant.io/dashboards/picture-elements/#conditional-element) condition, but can be used outside of a Picture Element context (e.g. card configuration overrides). - -If multiple entries are provided, the results are `AND`ed. +### View Condition | Parameter | Description | | - | - | -| `entity` | The entity ID to check the state for | -| `state` | Condition will be met if state is equal to this optional string. | -| `state_not` | Condition will be met if state is unequal to this optional string. | +| `condition` | Must be `view`. | +| `views` | A list of [views](#views) in which this condition is satified (e.g. `clips`). | -See the [Menu override example below](#frigate-card-menu-override-example) for an illustration. +### Camera Condition + +| Parameter | Description | +| - | - | +| `condition` | Must be `camera`. | +| `cameras` | A list of camera IDs in which this condition is satisfied. See [camera IDs](#camera-ids). | + +### Fullscreen Condition + +| Parameter | Description | +| - | - | +| `condition` | Must be `fullscreen`. | +| `fullscreen` | If `true` the condition is satisfied if the card is in fullscreen mode. If `false` the condition is satisfied if the card is **NOT** in fullscreen mode. | + +### Expand Condition + +| Parameter | Description | +| - | - | +| `condition` | Must be `expand`. | +| `fullscreen` | If `true` the condition is satisfied if the card is in expanded mode (in a dialog/popup). If `false` the condition is satisfied if the card is **NOT** in expanded mode (in a dialog/popup). | + +### Media Loaded Condition + +| Parameter | Description | +| - | - | +| `condition` | Must be `media_loaded`. | +| `media_loaded` | If `true` the condition is satisfied if there is media load**ED** (not load**ING**) in the card (e.g. a clip, snapshot or live view). This may be used to hide controls during media loading or when a message (not media) is being displayed. Note that if `true` this + +### Screen Condition + +| Parameter | Description | +| - | - | +| `condition` | Must be `screen`. | +| `media_query` | Any valid [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries) string. Media queries must start and end with parentheses. This may be used to alter card configuration based on device/media properties (e.g. viewport width, orientation). Please note that `width` and `height` refer to the entire viewport not just the card. See the [media query example](#media-query-example). | + +### Interaction Condition + +| Parameter | Description | +| - | - | +| `condition` | Must be `screen`. | +| `interaction` | If `true` the condition is satisfied if the card has had human interaction within `view.interaction_seconds` elapsed seconds. If `false` the condition is satisfied if the card has **NOT** had human interaction in that time. | + +### Triggered Condition + +| Parameter | Description | +| - | - | +| `condition` | Must be `screen`. | +| `triggered` | A list of camera IDs which, if [triggered](#camera-triggers-configuration), satisfy the condition. | ### Microphone Conditions -```yaml -- conditions: - microphone: -``` - | Parameter | Description | | - | - | | `muted` | Optional: If `true` or `false` the condition is satisfied if the microphone is muted or unmuted respectively. | | `connected` | Optional: If `true` or `false` the condition is satisfied if the microphone is connected or disconnected respectively. | +### Stock Home Assistant Conditions + +The stock `state`, `numeric_state` and `user` condition from Home Assistant can also be used. See [their documentation](https://www.home-assistant.io/dashboards/conditional/#card-conditions). + ## Picture Elements / Menu Customizations @@ -1430,7 +1452,7 @@ Parameters for the `custom:frigate-card-conditional` element: | ------------- | --------------------------------------------- | | `type` | Must be `custom:frigate-card-conditional`. | `elements` | The elements to render. Can be any supported element, include additional condition or custom elements. | -| `conditions` | A set of conditions that must evaluate to true in order for the elements to be rendered. See [Frigate Card Conditions](#frigate-card-conditions). | +| `conditions` | A list of conditions that must evaluate to true in order for the elements to be rendered. See [Frigate Card Conditions](#frigate-card-conditions). | @@ -2367,9 +2389,17 @@ elements: width: 100px - type: conditional conditions: - - entity: light.office_main_lights + - condition: state + entity: light.office_main_lights state: on state_not: off + - condition: numeric_state + entity: sensor.light_level + above: 20 + below: 100 + - condition: user + users: + - 581fca7fdc014b8b894519cc531f9a04 elements: - type: icon icon: mdi:dog @@ -2493,7 +2523,7 @@ elements: scene.kitchen_tv_scene: icon: mdi:television title: TV! - # Show a pig icon if the card is in the live view, in fullscreen mode, light.office_main_lights is on and the media has been loaded. + # Show a pig icon if a variety of conditions are met. - type: custom:frigate-card-conditional elements: - type: icon @@ -2503,16 +2533,38 @@ elements: left: 300px top: 100px conditions: - view: - - live - fullscreen: true - camera: - - camera.front_door - state: - - entity: light.office_main_lights - state: on - state_not: off - media_loaded: true + - condition: view + views: + - live + - condition: fullscreen + fullscreen: true + - condition: expand + expand: true + - condition: camera + cameras: camera.front_door + - condition: media_loaded + media_loaded: true + - condition: display_mode + display_mode: single + - condition: triggered + triggered: + - camera.front_door + - condition: interaction + interaction: true + - condition: microphone + muted: true + connected: true + - condition: state + entity: light.office_main_lights + state: on + state_not: off + - condition: numeric_state + entity: sensor.light_level + above: 20 + below: 100 + - condition: user + users: + - 581fca7fdc014b8b894519cc531f9a04 ``` @@ -2685,26 +2737,20 @@ timeline: Reference: [Override Options](#overrides-options). Overrides allow overriding certain (many) configuration parameters when a given -condition is met. The below is a fully expanded set of those overridable -parameters. This is really just repeating the above expansions of the relevant -sections, rather than indicating new or different parameters, i.e. this -repetition is included for illustrative purposes of what is overridable. +list of conditions are met. The below is a fully expanded set of those +overridable parameters. This is really just repeating the above expansions of +the relevant sections, rather than indicating new or different parameters, i.e. +this repetition is included for illustrative purposes of what is overridable. ```yaml overrides: - conditions: - view: - - live - fullscreen: true - camera: - - camera.front_door - state: - - entity: light.office_main_lights - state: on - state_not: off + - condition: view + views: + - live overrides: cameras: - # As this is an array, we need to carefully ensure we are + # As this is a list, we need to carefully ensure we are # overridding the correct index. We do this by specifying # earlier indicies as being overridden with an empty object # (in YAML this is `{}`). In this example, overriddes will @@ -2940,7 +2986,8 @@ Reference: [Automation Options](#automation-options). ```yaml automations: - conditions: - fullscreen: true + - condition: fullscreen + fullscreen: true actions: - action: custom:frigate-card-action frigate_card_action: live_substream_on @@ -3111,8 +3158,9 @@ This example only adds the light entity to the menu if a light is on. elements: - type: conditional conditions: - - entity: light.kitchen - state: 'on' + - condition: state + entity: light.kitchen + state: on elements: - type: custom:frigate-card-menu-state-icon entity: light.kitchen @@ -3138,8 +3186,9 @@ This example shows a car icon that calls a service but only in the `live` view. elements: - type: custom:frigate-card-conditional conditions: - view: - - live + - condition: view + views: + - live elements: - type: icon icon: mdi:car @@ -3254,8 +3303,9 @@ This example shows submenus conditional on the camera selected. elements: - type: custom:frigate-card-conditional conditions: - camera: - - camera.front_door + - condition: camera + cameras: + - camera.front_door elements: - type: custom:frigate-card-menu-submenu icon: mdi:door @@ -3267,8 +3317,9 @@ elements: action: toggle - type: custom:frigate-card-conditional conditions: - camera: - - camera.living_room + - condition: camera + cameras: + - camera.living_room elements: - type: custom:frigate-card-menu-submenu icon: mdi:sofa @@ -3353,7 +3404,8 @@ view: frigate_card_action: fullscreen overrides: - conditions: - fullscreen: true + - condition: fullscreen + fullscreen: true overrides: menu: style: none @@ -3374,8 +3426,9 @@ cameras: [...] overrides: - conditions: - camera: - - camera.office + - condition: camera + cameras: + - camera.office overrides: live: webrtc_card: @@ -3390,9 +3443,9 @@ overrides: ```yaml overrides: - conditions: - state: - - entity: light.office_lights - state: 'on' + - condition: state + entity: light.office_lights + state: 'on' overrides: menu: position: bottom @@ -3420,9 +3473,9 @@ view: - binary_sensor.alarm_armed overrides: - conditions: - state: - - entity: binary_sensor.alarm_armed - state: 'off' + - condition: state + entity: binary_sensor.alarm_armed + state: 'off' overrides: view: default: image @@ -3441,7 +3494,8 @@ menu: style: hidden overrides: - conditions: - expand: true + - condition: expand + expand: true overrides: menu: style: overlay @@ -3719,8 +3773,9 @@ elements: data: entity_id: siren.siren conditions: - triggered: - - camera.office + - condition: triggered + triggered: + - camera.office ``` @@ -3766,7 +3821,7 @@ cameras: -### Using Media Query conditions +### Using `screen` / Media Query conditions Alter the card configuration based on device or viewport properties. @@ -3780,7 +3835,8 @@ cameras: - camera_entity: camera.sitting_room overrides: - conditions: - media_query: '(max-width: 300px)' + - condition: screen + media_query: '(max-width: 300px)' overrides: menu: style: none @@ -3805,7 +3861,8 @@ menu: style: overlay overrides: - conditions: - media_query: '(orientation: landscape)' + - condition: screen + media_query: '(orientation: landscape)' overrides: menu: position: left @@ -3985,7 +4042,8 @@ fullscreen mode. ```yaml automations: - conditions: - fullscreen: true + - condition: fullscreen + fullscreen: true actions: - action: custom:frigate-card-action frigate_card_action: live_substream_on @@ -4007,8 +4065,10 @@ auto-layout behavior will be used outside of fullscreen mode. ```yaml overrides: - conditions: - fullscreen: true - display_mode: grid + - condition: fullscreen + fullscreen: true + - condition: display_mode + display_mode: grid overrides: live: display: @@ -4095,7 +4155,8 @@ automations: - action: custom:frigate-card-action frigate_card_action: live_substream_off conditions: - interaction: true + - condition: interaction + interaction: true ``` diff --git a/src/card-controller/automations-manager.ts b/src/card-controller/automations-manager.ts index cede9ed1..1da364d8 100644 --- a/src/card-controller/automations-manager.ts +++ b/src/card-controller/automations-manager.ts @@ -38,7 +38,7 @@ export class AutomationsManager { for (const automation of this._automations ?? []) { const shouldExecute = this._api .getConditionsManager() - .evaluateCondition(automation.conditions); + .evaluateConditions(automation.conditions); const actions = shouldExecute ? automation.actions : automation.actions_not; const priorEvaluation = this._priorEvaluations.get(automation); this._priorEvaluations.set(automation, shouldExecute); diff --git a/src/card-controller/conditions-manager.ts b/src/card-controller/conditions-manager.ts index 6d326d1f..d38bf35b 100644 --- a/src/card-controller/conditions-manager.ts +++ b/src/card-controller/conditions-manager.ts @@ -5,13 +5,17 @@ import { copyConfig } from '../config-mgmt'; import { FrigateCardCondition, frigateConditionalSchema, - MicrophoneConditionState, OverrideConfigurationKey, RawFrigateCardConfig, ViewDisplayMode, } from '../config/types'; import { CardConditionAPI } from './types'; +interface MicrophoneConditionState { + connected?: boolean; + muted?: boolean; +} + interface ConditionState { view?: string; fullscreen?: boolean; @@ -26,13 +30,13 @@ interface ConditionState { user?: CurrentUser; } -export class ConditionEvaluateRequestEvent extends Event { - public condition: FrigateCardCondition; +export class ConditionsEvaluateRequestEvent extends Event { + public conditions: FrigateCardCondition[]; public evaluation?: boolean; - constructor(condition: FrigateCardCondition, eventInitDict?: EventInit) { - super('frigate-card:condition:evaluate', eventInitDict); - this.condition = condition; + constructor(conditions: FrigateCardCondition[], eventInitDict?: EventInit) { + super('frigate-card:conditions:evaluate', eventInitDict); + this.conditions = conditions; } } @@ -42,13 +46,13 @@ export class ConditionEvaluateRequestEvent extends Event { */ export function evaluateConditionViaEvent( element: HTMLElement, - condition?: FrigateCardCondition, + conditions?: FrigateCardCondition[], ): boolean { - if (!condition) { + if (!conditions) { return true; } - const evaluateEvent = new ConditionEvaluateRequestEvent(condition, { + const evaluateEvent = new ConditionsEvaluateRequestEvent(conditions, { bubbles: true, composed: true, }); @@ -70,7 +74,7 @@ export function evaluateConditionViaEvent( } type RawOverrides = { - conditions: FrigateCardCondition; + conditions: FrigateCardCondition[]; overrides: RawFrigateCardConfig; }[]; @@ -84,7 +88,7 @@ export function getOverriddenConfig( let overridden = false; if (configOverrides) { for (const override of configOverrides) { - if (manager.evaluateCondition(override.conditions, stateOverrides)) { + if (manager.evaluateConditions(override.conditions, stateOverrides)) { merge(output, override.overrides); overridden = true; } @@ -156,7 +160,7 @@ export class ConditionsManager { const getAllConditions = (): FrigateCardCondition[] => { const config = this._api.getConfigManager().getConfig(); const conditions: FrigateCardCondition[] = []; - config?.overrides?.forEach((override) => conditions.push(override.conditions)); + config?.overrides?.forEach((override) => conditions.push(...override.conditions)); // Element conditions can be arbitrarily nested underneath conditionals and // custom elements that this card may not known. Here we recursively parse @@ -164,7 +168,7 @@ export class ConditionsManager { const getElementsConditions = (data: unknown): void => { const parseResult = frigateConditionalSchema.safeParse(data); if (parseResult.success) { - conditions.push(parseResult.data.conditions); + conditions.push(...parseResult.data.conditions); parseResult.data.elements?.forEach(getElementsConditions); } else if (data && typeof data === 'object') { Object.keys(data).forEach((key) => getElementsConditions(data[key])); @@ -175,15 +179,12 @@ export class ConditionsManager { }; const conditions = getAllConditions(); - this._hasHAStateConditions = conditions.some( - (condition) => - !!condition.state?.length || - !!condition.numeric_state?.length || - !!condition.users?.length, + this._hasHAStateConditions = conditions.some((conditionObj) => + ['state', 'numeric_state', 'user'].includes(conditionObj.condition), ); - conditions.forEach((condition) => { - if (condition.media_query) { - const mql = window.matchMedia(condition.media_query); + conditions.forEach((conditionObj) => { + if (conditionObj.condition === 'screen') { + const mql = window.matchMedia(conditionObj.media_query); mql.addEventListener('change', this._mediaQueryTrigger); this._mediaQueries.push(mql); } @@ -210,8 +211,17 @@ export class ConditionsManager { return this._epoch; } - public evaluateCondition( - condition: Readonly, + public evaluateConditions( + conditions: Readonly[], + stateOverrides?: Partial, + ): boolean { + return conditions.every((conditionObj) => + this._evaluateCondition(conditionObj, stateOverrides), + ); + } + + protected _evaluateCondition( + conditionObj: Readonly, stateOverrides?: Partial, ): boolean { const state = { @@ -219,79 +229,71 @@ export class ConditionsManager { ...stateOverrides, }; - let result = true; - if (condition.view?.length) { - result &&= !!state?.view && condition.view.includes(state.view); - } - if (condition.fullscreen !== undefined) { - result &&= - state.fullscreen !== undefined && condition.fullscreen === state.fullscreen; - } - if (condition.expand !== undefined) { - result &&= state.expand !== undefined && condition.expand === state.expand; - } - if (condition.camera?.length) { - result &&= !!state.camera && condition.camera.includes(state.camera); - } - if (condition.state?.length) { - for (const stateTest of condition.state) { - result &&= + switch (conditionObj.condition) { + case 'view': + return !!state?.view && conditionObj.views.includes(state.view); + case 'fullscreen': + return ( + state.fullscreen !== undefined && conditionObj.fullscreen === state.fullscreen + ); + case 'expand': + return state.expand !== undefined && conditionObj.expand === state.expand; + case 'camera': + return !!state.camera && conditionObj.cameras.includes(state.camera); + case 'state': + return ( !!state.state && - ((!stateTest.state && !stateTest.state_not) || - (stateTest.entity in state.state && - (!stateTest.state || - (Array.isArray(stateTest.state) - ? stateTest.state.includes(state.state[stateTest.entity].state) - : stateTest.state === state.state[stateTest.entity].state)) && - (!stateTest.state_not || - (Array.isArray(stateTest.state_not) - ? !stateTest.state_not.includes(state.state[stateTest.entity].state) - : stateTest.state_not !== state.state[stateTest.entity].state)))); - } - } - if (condition.numeric_state?.length) { - for (const stateTest of condition.numeric_state) { - result &&= + ((!conditionObj.state && !conditionObj.state_not) || + (conditionObj.entity in state.state && + (!conditionObj.state || + (Array.isArray(conditionObj.state) + ? conditionObj.state.includes(state.state[conditionObj.entity].state) + : conditionObj.state === state.state[conditionObj.entity].state)) && + (!conditionObj.state_not || + (Array.isArray(conditionObj.state_not) + ? !conditionObj.state_not.includes( + state.state[conditionObj.entity].state, + ) + : conditionObj.state_not !== state.state[conditionObj.entity].state)))) + ); + case 'numeric_state': + return ( !!state.state && - stateTest.entity in state.state && - state.state[stateTest.entity].state !== undefined && - (stateTest.above === undefined || - Number(state.state[stateTest.entity].state) > stateTest.above) && - (stateTest.below === undefined || - Number(state.state[stateTest.entity].state) < stateTest.below); - } + conditionObj.entity in state.state && + state.state[conditionObj.entity].state !== undefined && + (conditionObj.above === undefined || + Number(state.state[conditionObj.entity].state) > conditionObj.above) && + (conditionObj.below === undefined || + Number(state.state[conditionObj.entity].state) < conditionObj.below) + ); + case 'user': + return !!state.user && conditionObj.users.includes(state.user.id); + case 'media_loaded': + return ( + state.media_loaded !== undefined && + conditionObj.media_loaded === state.media_loaded + ); + case 'screen': + return window.matchMedia(conditionObj.media_query).matches; + case 'display_mode': + return !!state.displayMode && conditionObj.display_mode === state.displayMode; + case 'triggered': + return conditionObj.triggered.some((triggeredCameraID) => + state.triggered?.has(triggeredCameraID), + ); + case 'interaction': + return ( + state.interaction !== undefined && + conditionObj.interaction === state.interaction + ); + case 'microphone': + return ( + (conditionObj.connected === undefined || + state.microphone?.connected === conditionObj.connected) && + (conditionObj.muted === undefined || + state.microphone?.muted === conditionObj.muted) + ); } - if (condition.users?.length) { - result &&= !!state.user && condition.users.includes(state.user.id); - } - if (condition.media_loaded !== undefined) { - result &&= - state.media_loaded !== undefined && - condition.media_loaded === state.media_loaded; - } - if (condition.media_query) { - result &&= window.matchMedia(condition.media_query).matches; - } - if (condition.display_mode) { - result &&= !!state.displayMode && condition.display_mode === state.displayMode; - } - if (condition.triggered?.length) { - result &&= condition.triggered.some((triggeredCameraID) => - state.triggered?.has(triggeredCameraID), - ); - } - if (condition.interaction !== undefined) { - result &&= - state.interaction !== undefined && condition.interaction === state.interaction; - } - if (condition.microphone) { - result &&= - (condition.microphone.connected === undefined || - state.microphone?.connected === condition.microphone.connected) && - (condition.microphone.muted === undefined || - state.microphone?.muted === condition.microphone.muted); - } - return result; } protected _createEpoch(): ConditionsManagerEpoch { diff --git a/src/card.ts b/src/card.ts index beb6ed21..517f5def 100644 --- a/src/card.ts +++ b/src/card.ts @@ -8,7 +8,7 @@ import { ViewContext } from 'view'; import 'web-dialog'; import pkg from '../package.json'; import { actionHandler } from './action-handler-directive.js'; -import { ConditionEvaluateRequestEvent } from './card-controller/conditions-manager.js'; +import { ConditionsEvaluateRequestEvent } from './card-controller/conditions-manager.js'; import { CardController } from './card-controller/controller'; import { MenuButtonController } from './components-lib/menu-button-controller'; import './components/elements.js'; @@ -341,10 +341,10 @@ class FrigateCard extends LitElement { this._menuButtonController.removeDynamicMenuButton(ev.detail); this.requestUpdate(); }} - @frigate-card:condition:evaluate=${(ev: ConditionEvaluateRequestEvent) => { + @frigate-card:conditions:evaluate=${(ev: ConditionsEvaluateRequestEvent) => { ev.evaluation = this._controller .getConditionsManager() - ?.evaluateCondition(ev.condition); + ?.evaluateConditions(ev.conditions); }} > ` diff --git a/src/config-mgmt.ts b/src/config-mgmt.ts index 614ad149..0c8d6f28 100644 --- a/src/config-mgmt.ts +++ b/src/config-mgmt.ts @@ -3,8 +3,13 @@ import get from 'lodash-es/get'; import isEqual from 'lodash-es/isEqual'; import set from 'lodash-es/set'; import unset from 'lodash-es/unset'; -import { RawFrigateCardConfig, RawFrigateCardConfigArray } from './config/types'; import { + FrigateCardCondition, + RawFrigateCardConfig, + RawFrigateCardConfigArray, +} from './config/types'; +import { + CONF_AUTOMATIONS, CONF_CAMERAS, CONF_CAMERAS_GLOBAL_DIMENSIONS_LAYOUT, CONF_CAMERAS_GLOBAL_IMAGE, @@ -342,6 +347,99 @@ const conditionMediaLoadedTransform = (data: unknown): boolean => { return false; }; +/** + * Transform a single object with multiple conditions to multiple objects with + * single conditions + * @param data Input data. + * @returns `true` if the configuration was modified. + */ +const conditionToConditionsTransform = (data: unknown): boolean => { + if ( + typeof data !== 'object' || + !data || + typeof data['conditions'] !== 'object' || + !data['conditions'] + ) { + return false; + } + + const oldConditions = data['conditions']; + const newConditions: FrigateCardCondition[] = []; + + if (oldConditions['view'] !== undefined) { + newConditions.push({ + condition: 'view' as const, + views: oldConditions['view'], + }); + } + if (oldConditions['fullscreen'] !== undefined) { + newConditions.push({ + condition: 'fullscreen' as const, + fullscreen: oldConditions['fullscreen'], + }); + } + if (oldConditions['expand'] !== undefined) { + newConditions.push({ + condition: 'expand' as const, + expand: oldConditions['expand'], + }); + } + if (oldConditions['camera'] !== undefined) { + newConditions.push({ + condition: 'camera' as const, + cameras: oldConditions['camera'], + }); + } + if (oldConditions['media_loaded'] !== undefined) { + newConditions.push({ + condition: 'media_loaded' as const, + media_loaded: oldConditions['media_loaded'], + }); + } + if (oldConditions['state'] !== undefined && Array.isArray(oldConditions['state'])) { + for (const stateCondition of oldConditions['state']) { + if ( + typeof stateCondition === 'object' && + stateCondition && + (stateCondition['state'] !== undefined || + stateCondition['state_not'] !== undefined || + stateCondition['entity'] !== undefined) + ) { + newConditions.push({ + condition: 'state' as const, + ...(stateCondition['state'] && { + state: stateCondition['state'], + }), + ...(stateCondition['state_not'] && { + state_not: stateCondition['state_not'], + }), + ...(stateCondition['entity'] && { + entity: stateCondition['entity'], + }), + }); + } + } + } + if (oldConditions['media_query'] !== undefined) { + newConditions.push({ + condition: 'screen' as const, + media_query: oldConditions['media_query'], + }); + } + + // These conditions did not exist prior to v6.0.0 and so are not converted: + // - display_mode + // - triggered + // - interaction + // - microphone + + if (newConditions.length) { + data['conditions'] = newConditions; + return true; + } + return false; +}; + /** * Transform service_data -> data * See: https://github.com/dermotduffy/frigate-hass-card/issues/1103 @@ -569,4 +667,15 @@ const UPGRADES = [ upgradeMoveToWithOverrides('live.layout', CONF_CAMERAS_GLOBAL_DIMENSIONS_LAYOUT), deleteWithOverrides('media_viewer.layout'), deleteWithOverrides('image.layout'), + upgradeArrayOfObjects(CONF_OVERRIDES, conditionToConditionsTransform), + (data: unknown): boolean => { + return upgradeObjectRecursively(conditionToConditionsTransform)( + typeof data === 'object' && data ? data[CONF_ELEMENTS] : {}, + ); + }, + (data: unknown): boolean => { + return upgradeObjectRecursively(conditionToConditionsTransform)( + typeof data === 'object' && data ? data[CONF_AUTOMATIONS] : {}, + ); + }, ]; diff --git a/src/config/types.ts b/src/config/types.ts index d835eb1f..c6086fa0 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -401,7 +401,7 @@ const imageSchema = elementsBaseSchema.extend({ }); // https://www.home-assistant.io/dashboards/conditional/#state -const stateCondition = z.object({ +const stateConditionSchema = z.object({ condition: z.literal('state'), entity: z.string(), state: z.string().or(z.string().array()).optional(), @@ -409,38 +409,36 @@ const stateCondition = z.object({ }); // https://www.home-assistant.io/dashboards/conditional/#numeric-state -const numericCondition = z.object({ +const numericStateConditionSchema = z.object({ condition: z.literal('numeric_state'), entity: z.string(), above: z.number().optional(), below: z.number().optional(), }); -const mediaQuerySchema = z.string(); - // https://www.home-assistant.io/dashboards/conditional/#screen -const screenCondition = z.object({ +const screenConditionSchema = z.object({ condition: z.literal('screen'), - media_query: mediaQuerySchema, + media_query: z.string(), }); // https://www.home-assistant.io/dashboards/conditional/#user -const usersCondition = z.object({ +const usersConditionSchema = z.object({ condition: z.literal('user'), users: z.string().array().min(1), }); -const stockCondition = z.union([ - stateCondition, - numericCondition, - screenCondition, - usersCondition, +const stockConditionSchema = z.discriminatedUnion('condition', [ + stateConditionSchema, + numericStateConditionSchema, + screenConditionSchema, + usersConditionSchema, ]); // https://www.home-assistant.io/lovelace/picture-elements/#image-element export const conditionalSchema = z.object({ type: z.literal('conditional'), - conditions: stockCondition.array(), + conditions: stockConditionSchema.array(), elements: z.lazy(() => pictureElementsSchema), }); @@ -516,32 +514,67 @@ export type MenuItem = MenuIcon | MenuStateIcon | MenuSubmenu | MenuSubmenuSelec // Custom Element Configuration: Conditions // ************************************************************************* +const viewConditionSchema = z.object({ + condition: z.literal('view'), + views: z.string().array(), +}); +const fullscreenConditionSchema = z.object({ + condition: z.literal('fullscreen'), + fullscreen: z.boolean(), +}); +const expandConditionSchema = z.object({ + condition: z.literal('expand'), + expand: z.boolean(), +}); +const cameraConditionSchema = z.object({ + condition: z.literal('camera'), + cameras: z.string().array(), +}); +const mediaLoadedConditionSchema = z.object({ + condition: z.literal('media_loaded'), + media_loaded: z.boolean(), +}); +const displayModeConditionSchema = z.object({ + condition: z.literal('display_mode'), + display_mode: viewDisplayModeSchema, +}); +const triggeredConditionSchema = z.object({ + condition: z.literal('triggered'), + triggered: z.string().array(), +}); +const interactionConditionSchema = z.object({ + condition: z.literal('interaction'), + interaction: z.boolean(), +}); const microphoneConditionSchema = z.object({ + condition: z.literal('microphone'), connected: z.boolean().optional(), muted: z.boolean().optional(), }); -export type MicrophoneConditionState = z.infer; -export const frigateCardConditionSchema = z.object({ - view: z.string().array().optional(), - fullscreen: z.boolean().optional(), - expand: z.boolean().optional(), - camera: z.string().array().optional(), - media_loaded: z.boolean().optional(), - state: stateCondition.array().optional(), - numeric_state: numericCondition.array().optional(), - media_query: mediaQuerySchema.optional(), - display_mode: viewDisplayModeSchema.optional(), - triggered: z.string().array().optional(), - interaction: z.boolean().optional(), - microphone: microphoneConditionSchema.optional(), - users: z.string().array().optional() -}); +export const frigateCardConditionSchema = z.discriminatedUnion('condition', [ + // Stock conditions: + stateConditionSchema, + numericStateConditionSchema, + screenConditionSchema, + usersConditionSchema, + + // Custom conditions: + viewConditionSchema, + fullscreenConditionSchema, + expandConditionSchema, + cameraConditionSchema, + mediaLoadedConditionSchema, + displayModeConditionSchema, + triggeredConditionSchema, + interactionConditionSchema, + microphoneConditionSchema, +]); export type FrigateCardCondition = z.infer; export const frigateConditionalSchema = z.object({ type: z.literal('custom:frigate-card-conditional'), - conditions: frigateCardConditionSchema, + conditions: frigateCardConditionSchema.array(), elements: z.lazy(() => pictureElementsSchema), }); export type FrigateConditional = z.infer; @@ -1034,7 +1067,7 @@ export type LiveConfig = z.infer; const liveOverridesSchema = z .object({ - conditions: frigateCardConditionSchema, + conditions: frigateCardConditionSchema.array(), overrides: liveOverridableConfigSchema, }) .array() @@ -1551,7 +1584,7 @@ export type OverrideConfigurationKey = keyof z.infer; const automationSchema = z.object({ - conditions: frigateCardConditionSchema, + conditions: frigateCardConditionSchema.array(), actions: automationActionSchema.optional(), actions_not: automationActionSchema.optional(), }); diff --git a/src/const.ts b/src/const.ts index e7c9e330..1dd10870 100644 --- a/src/const.ts +++ b/src/const.ts @@ -1,6 +1,8 @@ export const REPO_URL = 'https://github.com/dermotduffy/frigate-hass-card' as const; export const TROUBLESHOOTING_URL = `${REPO_URL}#troubleshooting` as const; +export const CONF_AUTOMATIONS = 'automations' as const; + export const CONF_CAMERAS = 'cameras' as const; export const CONF_CAMERAS_ARRAY_CAMERA_ENTITY = `${CONF_CAMERAS}.#.camera_entity` as const; diff --git a/tests/card-controller/automations-manager.test.ts b/tests/card-controller/automations-manager.test.ts index 450bb17d..b1e1e4ac 100644 --- a/tests/card-controller/automations-manager.test.ts +++ b/tests/card-controller/automations-manager.test.ts @@ -1,8 +1,6 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; +import { AutomationsManager } from '../../src/card-controller/automations-manager.js'; import { frigateCardHandleAction } from '../../src/utils/action.js'; -import { - AutomationsManager, -} from '../../src/card-controller/automations-manager.js'; import { createCardAPI, createConfig, createHASS } from '../test-utils.js'; vi.mock('../../src/utils/action.js'); @@ -14,7 +12,7 @@ describe('AutomationsManager', () => { frigate_card_action: 'clips', }, ]; - const conditions = { fullscreen: true }; + const conditions = [{ condition: 'fullscreen', fullscreen: true }]; afterEach(() => { vi.clearAllMocks(); @@ -58,7 +56,7 @@ describe('AutomationsManager', () => { automationsManager.execute(); expect(frigateCardHandleAction).not.toBeCalled(); - vi.mocked(api.getConditionsManager().evaluateCondition).mockReturnValue(true); + vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(true); automationsManager.execute(); expect(frigateCardHandleAction).toBeCalledTimes(1); @@ -68,12 +66,12 @@ describe('AutomationsManager', () => { automationsManager.execute(); expect(frigateCardHandleAction).toBeCalledTimes(1); - vi.mocked(api.getConditionsManager().evaluateCondition).mockReturnValue(false); + vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(false); automationsManager.execute(); expect(frigateCardHandleAction).toBeCalledTimes(1); - vi.mocked(api.getConditionsManager().evaluateCondition).mockReturnValue(true); + vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(true); automationsManager.execute(); expect(frigateCardHandleAction).toBeCalledTimes(2); @@ -92,7 +90,7 @@ describe('AutomationsManager', () => { const api = createCardAPI(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); vi.mocked(api.getConfigManager().getNonOverriddenConfig).mockReturnValue(config); - vi.mocked(api.getConditionsManager().evaluateCondition).mockReturnValue(false); + vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(false); const automationsManager = new AutomationsManager(api); automationsManager.setAutomationsFromConfig(); @@ -106,11 +104,11 @@ describe('AutomationsManager', () => { const config = createConfig({ automations: [ { - conditions: { fullscreen: true }, + conditions: [{ condition: 'fullscreen' as const, fullscreen: true }], actions: actions, }, { - conditions: { fullscreen: true }, + conditions: [{ condition: 'fullscreen' as const, fullscreen: true }], actions_not: actions, }, ], @@ -127,13 +125,13 @@ describe('AutomationsManager', () => { let evaluation = true; vi.mocked(frigateCardHandleAction).mockImplementation(() => { evaluation = !evaluation; - vi.mocked(api.getConditionsManager().evaluateCondition).mockReturnValue( + vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue( evaluation, ); automationsManager.execute(); }); - vi.mocked(api.getConditionsManager().evaluateCondition).mockReturnValue(evaluation); + vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(evaluation); automationsManager.execute(); diff --git a/tests/card-controller/conditions-manager.test.ts b/tests/card-controller/conditions-manager.test.ts index a6f5fe9e..eea42258 100644 --- a/tests/card-controller/conditions-manager.test.ts +++ b/tests/card-controller/conditions-manager.test.ts @@ -1,12 +1,12 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { FrigateCardCondition } from '../../src/config/types'; import { - ConditionEvaluateRequestEvent, + ConditionsEvaluateRequestEvent, ConditionsManager, evaluateConditionViaEvent, getOverriddenConfig, getOverridesByKey, } from '../../src/card-controller/conditions-manager'; +import { FrigateCardCondition } from '../../src/config/types'; import { createCardAPI, createCondition, @@ -18,14 +18,14 @@ import { // @vitest-environment jsdom describe('ConditionEvaluateRequestEvent', () => { it('should construct', () => { - const condition = createCondition({ fullscreen: true }); - const event = new ConditionEvaluateRequestEvent(condition, { + const conditions = [createCondition({ condition: 'fullscreen', fullscreen: true })]; + const event = new ConditionsEvaluateRequestEvent(conditions, { bubbles: true, composed: true, }); - expect(event.type).toBe('frigate-card:condition:evaluate'); - expect(event.condition).toBe(condition); + expect(event.type).toBe('frigate-card:conditions:evaluate'); + expect(event.conditions).toBe(conditions); expect(event.bubbles).toBeTruthy(); expect(event.composed).toBeTruthy(); }); @@ -38,35 +38,35 @@ describe('evaluateConditionViaEvent', () => { }); it('should dispatch event with condition and evaluate true', () => { const element = document.createElement('div'); - const condition = createCondition({ fullscreen: true }); - const handler = vi.fn().mockImplementation((ev: ConditionEvaluateRequestEvent) => { - expect(ev.condition).toBe(condition); + const conditions = [createCondition({ condition: 'fullscreen', fullscreen: true })]; + const handler = vi.fn().mockImplementation((ev: ConditionsEvaluateRequestEvent) => { + expect(ev.conditions).toBe(conditions); ev.evaluation = true; }); - element.addEventListener('frigate-card:condition:evaluate', handler); + element.addEventListener('frigate-card:conditions:evaluate', handler); - expect(evaluateConditionViaEvent(element, condition)).toBeTruthy(); + expect(evaluateConditionViaEvent(element, conditions)).toBeTruthy(); expect(handler).toBeCalled(); }); it('should dispatch event with condition and evaluate false', () => { const element = document.createElement('div'); - const condition = createCondition({ fullscreen: true }); - const handler = vi.fn().mockImplementation((ev: ConditionEvaluateRequestEvent) => { - expect(ev.condition).toBe(condition); + const conditions = [createCondition({ condition: 'fullscreen', fullscreen: true })]; + const handler = vi.fn().mockImplementation((ev: ConditionsEvaluateRequestEvent) => { + expect(ev.conditions).toBe(conditions); ev.evaluation = false; }); - element.addEventListener('frigate-card:condition:evaluate', handler); + element.addEventListener('frigate-card:conditions:evaluate', handler); - expect(evaluateConditionViaEvent(element, condition)).toBeFalsy(); + expect(evaluateConditionViaEvent(element, conditions)).toBeFalsy(); expect(handler).toBeCalled(); }); it('should dispatch event evaluate false if no evaluation', () => { const element = document.createElement('div'); - const condition = createCondition({ fullscreen: true }); + const conditions = [createCondition({ condition: 'fullscreen', fullscreen: true })]; const handler = vi.fn(); - element.addEventListener('frigate-card:condition:evaluate', handler); + element.addEventListener('frigate-card:conditions:evaluate', handler); - expect(evaluateConditionViaEvent(element, condition)).toBeFalsy(); + expect(evaluateConditionViaEvent(element, conditions)).toBeFalsy(); expect(handler).toBeCalled(); }); }); @@ -84,9 +84,12 @@ describe('getOverriddenConfig', () => { style: 'above', }, }, - conditions: { - fullscreen: true, - }, + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], }, ]; @@ -115,9 +118,12 @@ describe('getOverriddenConfig', () => { }); describe('getOverridesByKey', () => { - const condition = { - fullscreen: true, - }; + const conditions = [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ]; const override = { menu: { style: 'above', @@ -126,13 +132,13 @@ describe('getOverridesByKey', () => { const overrides = [ { overrides: override, - conditions: condition, + conditions: conditions, }, ]; it('should get overrides', () => { expect(getOverridesByKey('menu', overrides)).toEqual([ - { conditions: condition, overrides: { style: 'above' } }, + { conditions: conditions, overrides: { style: 'above' } }, ]); }); @@ -184,7 +190,7 @@ describe('ConditionsManager', () => { vi.restoreAllMocks(); }); - const createSuitableConfig = (conditions: FrigateCardCondition) => { + const createSuitableConfig = (conditions: FrigateCardCondition[]) => { return createConfig({ overrides: [ { @@ -202,15 +208,13 @@ describe('ConditionsManager', () => { it('with HA state conditions', () => { const api = createCardAPI(); - const numericConfig = createSuitableConfig({ - state: [ - { - condition: 'state', - entity: 'binary_sensor.foo', - state: 'on', - }, - ], - }); + const numericConfig = createSuitableConfig([ + { + condition: 'state' as const, + entity: 'binary_sensor.foo', + state: 'on', + }, + ]); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(numericConfig); const manager = new ConditionsManager(api); manager.setConditionsFromConfig(); @@ -220,16 +224,14 @@ describe('ConditionsManager', () => { it('with HA numeric_state conditions', () => { const api = createCardAPI(); - const stateConfig = createSuitableConfig({ - numeric_state: [ - { - entity: 'sensor.foo', - condition: 'numeric_state' as const, - above: 10, - }, - ], - }); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(stateConfig); + const numericStateConfig = createSuitableConfig([ + { + condition: 'numeric_state' as const, + entity: 'sensor.foo', + above: 10, + }, + ]); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(numericStateConfig); const manager = new ConditionsManager(api); manager.setConditionsFromConfig(); @@ -238,9 +240,12 @@ describe('ConditionsManager', () => { it('with HA user conditions', () => { const api = createCardAPI(); - const userConfig = createSuitableConfig({ - users: ['user_1'], - }); + const userConfig = createSuitableConfig([ + { + condition: 'user' as const, + users: ['user_1'], + }, + ]); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(userConfig); const manager = new ConditionsManager(api); manager.setConditionsFromConfig(); @@ -250,230 +255,227 @@ describe('ConditionsManager', () => { }); describe('should evaluate conditions', () => { - it('with a view', () => { + it('with a view condition', () => { const manager = new ConditionsManager(createCardAPI()); - const condition = { view: ['foo'] }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [{ condition: 'view' as const, views: ['foo'] }]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ view: 'foo' }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); }); - it('with fullscreen', () => { + it('with fullscreen condition', () => { const manager = new ConditionsManager(createCardAPI()); - const condition = { fullscreen: true }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [{ condition: 'fullscreen' as const, fullscreen: true }]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ fullscreen: true }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ fullscreen: false }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); - it('with expand', () => { + it('with expand condition', () => { const manager = new ConditionsManager(createCardAPI()); - const condition = { expand: true }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [{ condition: 'expand' as const, expand: true }]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ expand: true }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ expand: false }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); - it('camera', () => { + it('with camera condition', () => { const manager = new ConditionsManager(createCardAPI()); - const condition = { camera: ['bar'] }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [{ condition: 'camera' as const, cameras: ['bar'] }]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ camera: 'bar' }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ camera: 'will-not-match' }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); describe('with stock HA conditions', () => { - describe('state check', () => { + describe('with state condition', () => { describe('positive', () => { it('single', () => { const manager = new ConditionsManager(createCardAPI()); - const condition = { - state: [ - { - condition: 'state' as const, - entity: 'binary_sensor.foo', - state: 'on', - }, - ], - }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [ + { + condition: 'state' as const, + entity: 'binary_sensor.foo', + state: 'on', + }, + ]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ state: { 'binary_sensor.foo': createStateEntity() } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ state: { 'binary_sensor.foo': createStateEntity({ state: 'off' }) }, }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); it('multiple', () => { const manager = new ConditionsManager(createCardAPI()); - const condition = { - state: [ - { - condition: 'state' as const, - entity: 'binary_sensor.foo', - state: ['active', 'on'], - }, - ], - }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [ + { + condition: 'state' as const, + entity: 'binary_sensor.foo', + state: ['active', 'on'], + }, + ]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ state: { 'binary_sensor.foo': createStateEntity() } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ state: { 'binary_sensor.foo': createStateEntity({ state: 'active' }) }, }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ state: { 'binary_sensor.foo': createStateEntity({ state: 'off' }) }, }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); }); describe('negative', () => { it('single', () => { const manager = new ConditionsManager(createCardAPI()); - const condition = { - state: [ - { - condition: 'state' as const, - entity: 'binary_sensor.foo', - state_not: 'on', - }, - ], - }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [ + { + condition: 'state' as const, + entity: 'binary_sensor.foo', + state_not: 'on', + }, + ]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ state: { 'binary_sensor.foo': createStateEntity() } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ state: { 'binary_sensor.foo': createStateEntity({ state: 'off' }) }, }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); }); }); it('multiple', () => { const manager = new ConditionsManager(createCardAPI()); - const condition = { - state: [ - { - condition: 'state' as const, - entity: 'binary_sensor.foo', - state_not: ['active', 'on'], - }, - ], - }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [ + { + condition: 'state' as const, + entity: 'binary_sensor.foo', + state_not: ['active', 'on'], + }, + ]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ state: { 'binary_sensor.foo': createStateEntity() } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ state: { 'binary_sensor.foo': createStateEntity({ state: 'active' }) }, }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ state: { 'binary_sensor.foo': createStateEntity({ state: 'off' }) }, }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); }); }); - describe('numeric state check', () => { + describe('with numeric state condition', () => { it('above', () => { const manager = new ConditionsManager(createCardAPI()); - const condition = { - numeric_state: [ - { - condition: 'numeric_state' as const, - entity: 'sensor.foo', - above: 10, - }, - ], - }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [ + { + condition: 'numeric_state' as const, + entity: 'sensor.foo', + above: 10, + }, + ]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ state: { 'sensor.foo': createStateEntity({ state: '11' }) }, }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ state: { 'binary_sensor.foo': createStateEntity({ state: '9' }) }, }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); it('below', () => { const manager = new ConditionsManager(createCardAPI()); - const condition = { - numeric_state: [ - { - condition: 'numeric_state' as const, - entity: 'sensor.foo', - below: 10, - }, - ], - }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [ + { + condition: 'numeric_state' as const, + entity: 'sensor.foo', + below: 10, + }, + ]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ state: { 'sensor.foo': createStateEntity({ state: '11' }) }, }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ state: { 'sensor.foo': createStateEntity({ state: '9' }) }, }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); }); }); }); - it('with users', () => { + it('with user condition', () => { const manager = new ConditionsManager(createCardAPI()); - const condition = { - users: ['user_1', 'user_2'], - }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [ + { + condition: 'user' as const, + users: ['user_1', 'user_2'], + }, + ]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ user: createUser({ id: 'user_1' }), }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ user: createUser({ id: 'user_WRONG' }), }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); - it('with media_loaded', () => { + it('with media loaded condition', () => { const manager = new ConditionsManager(createCardAPI()); - const condition = { media_loaded: true }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [{ condition: 'media_loaded' as const, media_loaded: true }]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ media_loaded: true }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ media_loaded: false }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); - describe('with media query', () => { + describe('with screen condition', () => { const mediaQueryConfig = { type: 'custom:frigate-card', cameras: [], elements: [ { type: 'custom:frigate-card-conditional', - conditions: { - fullscreen: true, - }, + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], elements: [ { type: 'custom:nested-unknown-object', unknown_key: { type: 'custom:frigate-card-conditional', - conditions: { - media_query: 'media query goes here', - }, + conditions: [ + { + condition: 'screen' as const, + media_query: 'media query goes here', + }, + ], elements: [], }, }, @@ -488,9 +490,9 @@ describe('ConditionsManager', () => { .mockReturnValueOnce({ matches: false }); const manager = new ConditionsManager(createCardAPI()); - const condition = { media_query: 'whatever' }; - expect(manager.evaluateCondition(condition)).toBeTruthy(); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [{ condition: 'screen' as const, media_query: 'whatever' }]; + expect(manager.evaluateConditions(conditions)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); it('on trigger', () => { @@ -525,107 +527,111 @@ describe('ConditionsManager', () => { }); }); - it('with display mode', () => { + it('with display mode condition', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { display_mode: 'grid' }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [ + { condition: 'display_mode' as const, display_mode: 'grid' as const }, + ]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ displayMode: 'grid' }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ displayMode: 'single' }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); - it('with triggers', () => { + it('with triggered condition', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { triggered: ['camera_1', 'camera_2'] }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [ + { condition: 'triggered' as const, triggered: ['camera_1', 'camera_2'] }, + ]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ triggered: new Set(['camera_1']) }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ triggered: new Set(['camera_2', 'camera_1', 'camera_3']) }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ triggered: new Set(['camera_3']) }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); - it('with interaction', () => { + it('with interaction condition', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { interaction: true }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [{ condition: 'interaction' as const, interaction: true }]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ interaction: true }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ interaction: false }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); - describe('with microphone', () => { + describe('with microphone condition', () => { it('empty', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { microphone: {} }; - expect(manager.evaluateCondition(condition)).toBeTruthy(); + const conditions = [{ condition: 'microphone' as const }]; + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ microphone: { connected: true } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ microphone: { connected: false } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ microphone: { muted: true } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ microphone: { muted: false } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); }); it('connected is true', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { microphone: { connected: true } }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [{ condition: 'microphone' as const, connected: true }]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ microphone: { connected: true } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ microphone: { connected: false } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); it('connected is false', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { microphone: { connected: false } }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [{ condition: 'microphone' as const, connected: false }]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ microphone: { connected: true } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ microphone: { connected: false } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); }); it('muted is true', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { microphone: { muted: true } }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [{ condition: 'microphone' as const, muted: true }]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ microphone: { muted: true } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); manager.setState({ microphone: { muted: false } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); }); it('muted is false', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { microphone: { muted: false } }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [{ condition: 'microphone' as const, muted: false }]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ microphone: { muted: true } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ microphone: { muted: false } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); }); it('connected and muted', () => { const manager = new ConditionsManager(createCardAPI()); - const condition: FrigateCardCondition = { - microphone: { muted: false, connected: true }, - }; - expect(manager.evaluateCondition(condition)).toBeFalsy(); + const conditions = [ + { condition: 'microphone' as const, muted: false, connected: true }, + ]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ microphone: { muted: true } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ microphone: { muted: false } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ microphone: { connected: false, muted: false } }); - expect(manager.evaluateCondition(condition)).toBeFalsy(); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); manager.setState({ microphone: { connected: true, muted: false } }); - expect(manager.evaluateCondition(condition)).toBeTruthy(); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); }); }); }); diff --git a/tests/config-mgmt.test.ts b/tests/config-mgmt.test.ts index 1b3af522..424821cf 100644 --- a/tests/config-mgmt.test.ts +++ b/tests/config-mgmt.test.ts @@ -377,9 +377,12 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { - conditions: { - media_loaded: true, - }, + conditions: [ + { + condition: 'media_loaded' as const, + media_loaded: true, + }, + ], }, { conditions: 'not an object', @@ -411,9 +414,12 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], overrides: [ { - conditions: { - media_loaded: true, - }, + conditions: [ + { + condition: 'media_loaded' as const, + media_loaded: true, + }, + ], overrides: { view: { default: 'clips', @@ -1020,10 +1026,16 @@ describe('should handle version specific upgrades', () => { elements: [ { type: 'custom:frigate-card-conditional', - conditions: { - fullscreen: true, - media_loaded: true, - }, + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + { + condition: 'media_loaded' as const, + media_loaded: true, + }, + ], elements: [ { type: 'service-button', @@ -1793,4 +1805,636 @@ describe('should handle version specific upgrades', () => { }); }); }); + + describe('from condition object to condition array', () => { + describe('with view condition', () => { + it('elements', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: { + view: ['clips', 'snapshots'], + }, + }, + { + conditions: 'not an object', + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: [ + { + condition: 'view' as const, + views: ['clips', 'snapshots'], + }, + ], + }, + { + conditions: 'not an object', + }, + ], + }); + }); + + it('overrides', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: { + view: ['clips', 'snapshots'], + }, + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: [ + { + condition: 'view' as const, + views: ['clips', 'snapshots'], + }, + ], + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }); + }); + + it('automations', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: { + view: ['clips', 'snapshots'], + }, + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: [ + { + condition: 'view' as const, + views: ['clips', 'snapshots'], + }, + ], + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }); + }); + }); + + describe('with camera condition', () => { + it('elements', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: { + camera: ['camera_1', 'camera_2'], + }, + }, + { + conditions: 'not an object', + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: [ + { + condition: 'camera' as const, + cameras: ['camera_1', 'camera_2'], + }, + ], + }, + { + conditions: 'not an object', + }, + ], + }); + }); + + it('overrides', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: { + camera: ['camera_1', 'camera_2'], + }, + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: [ + { + condition: 'camera' as const, + cameras: ['camera_1', 'camera_2'], + }, + ], + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }); + }); + + it('automations', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: { + camera: ['camera_1', 'camera_2'], + }, + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: [ + { + condition: 'camera' as const, + cameras: ['camera_1', 'camera_2'], + }, + ], + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }); + }); + }); + + describe('with boolean conditions', () => { + describe.each([ + ['fullscreen' as const], + ['expand' as const], + ['media_loaded' as const], + ])('%s', (condition: string) => { + it('elements', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: { + [condition]: true, + }, + }, + { + conditions: 'not an object', + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: [ + { + condition: condition, + [condition]: true, + }, + ], + }, + { + conditions: 'not an object', + }, + ], + }); + }); + + it('overrides', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: { + [condition]: true, + }, + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: [ + { + condition: condition, + [condition]: true, + }, + ], + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }); + }); + + it('automations', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: { + [condition]: true, + }, + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: [ + { + condition: condition, + [condition]: true, + }, + ], + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }); + }); + }); + }); + + describe('with state condition', () => { + it('elements', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: { + state: [ + { + entity: 'binary_sensor.first', + state: 'on', + }, + { + entity: 'binary_sensor.second', + state_not: 'off', + }, + {}, + ], + }, + }, + { + conditions: 'not an object', + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: [ + { + condition: 'state' as const, + entity: 'binary_sensor.first', + state: 'on', + }, + { + condition: 'state' as const, + entity: 'binary_sensor.second', + state_not: 'off', + }, + ], + }, + { + conditions: 'not an object', + }, + ], + }); + }); + + it('overrides', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: { + state: [ + { + entity: 'binary_sensor.first', + state: 'on', + }, + { + entity: 'binary_sensor.second', + state_not: 'off', + }, + {}, + ], + }, + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: [ + { + condition: 'state' as const, + entity: 'binary_sensor.first', + state: 'on', + }, + { + condition: 'state' as const, + entity: 'binary_sensor.second', + state_not: 'off', + }, + ], + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }); + }); + + it('automations', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: { + state: [ + { + entity: 'binary_sensor.first', + state: 'on', + }, + { + entity: 'binary_sensor.second', + state_not: 'off', + }, + {}, + ], + }, + + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: [ + { + condition: 'state' as const, + entity: 'binary_sensor.first', + state: 'on', + }, + { + condition: 'state' as const, + entity: 'binary_sensor.second', + state_not: 'off', + }, + ], + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }); + }); + }); + + describe('with media query condition', () => { + it('elements', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: { + media_query: 'query', + }, + }, + { + conditions: 'not an object', + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: [ + { + condition: 'screen' as const, + media_query: 'query', + }, + ], + }, + { + conditions: 'not an object', + }, + ], + }); + }); + + it('overrides', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: { + media_query: 'query', + }, + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: [ + { + condition: 'screen' as const, + media_query: 'query', + }, + ], + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }); + }); + + it('automations', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: { + media_query: 'query', + }, + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: [ + { + condition: 'screen' as const, + media_query: 'query', + }, + ], + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }); + }); + }); + }); }); diff --git a/tests/test-utils.ts b/tests/test-utils.ts index 721c1439..ab941520 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -80,7 +80,10 @@ export const createCamera = ( return new Camera(config, engine, { capabilities: capabilities }); }; -export const createHASS = (states?: HassEntities, user?: CurrentUser): ExtendedHomeAssistant => { +export const createHASS = ( + states?: HassEntities, + user?: CurrentUser, +): ExtendedHomeAssistant => { const hass = mock(); if (states) { hass.states = states; From 463f4bf32a44ada9da5a657841ef964ef3f39be8 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 10 Mar 2024 20:40:18 -0700 Subject: [PATCH 103/189] Add ability to set timeline pan mode via config. --- README.md | 7 ++- src/components/timeline-core.ts | 61 ++++++++++++------------- src/config/types.ts | 12 +++++ src/const.ts | 4 ++ src/editor.ts | 74 ++++++++++++++++++++++--------- src/localize/languages/en.json | 15 ++++--- src/localize/languages/it.json | 15 ++++--- src/localize/languages/pt-BR.json | 15 ++++--- src/localize/languages/pt-PT.json | 17 +++---- tests/config/types.test.ts | 3 ++ vite.config.ts | 6 +-- 11 files changed, 144 insertions(+), 85 deletions(-) diff --git a/README.md b/README.md index 2ad37a81..eed4af83 100644 --- a/README.md +++ b/README.md @@ -632,6 +632,7 @@ live: | Option | Default | Overridable | Description | | - | - | - | - | | `mode` | `none` | :white_check_mark: | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| +| `pan_mode` | `pan`| :white_check_mark: | If set to `pan` then dragging the timeline will have no effect on the media. If set to `seek` will open media for that time and seek to that position . If set to `seek-in-media` will seek within the opened media only. If set to `seek-in-camera` will seek within the selected camera only. | | `style` | `ribbon` | :white_check_mark: | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold` (below). | | `window_seconds` | `3600` | :white_check_mark: | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | | `clustering_threshold` | `3` | :white_check_mark: | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | @@ -814,7 +815,9 @@ media_viewer: | Option | Default | Overridable | Description | | - | - | - | - | -| `mode` | `none` | :heavy_multiplication_x: | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| +| `mode` | `none` | :heavy_multiplication_x: | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the +`left` or `right` of the media or to hide it entirely (`none`).| +| `pan_mode` | `pan`| :white_check_mark: | If set to `pan` then dragging the timeline will have no effect on the media. If set to `seek` will open media for that time and seek to that position . If set to `seek-in-media` will seek within the opened media only. If set to `seek-in-camera` will seek within the selected camera only. | | `style` | `ribbon` | :heavy_multiplication_x: | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold` (below). | | `window_seconds` | `3600` | :heavy_multiplication_x: | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | | `clustering_threshold` | `3` | :heavy_multiplication_x: | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | @@ -2139,6 +2142,7 @@ live: timeline: style: ribbon mode: none + pan_mode: pan clustering_threshold: 3 events_media_type: all show_recordings: true @@ -2232,6 +2236,7 @@ media_viewer: timeline: style: ribbon mode: none + pan_mode: pan clustering_threshold: 3 events_media_type: all show_recordings: true diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index a7ed952d..ba20b89b 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -39,6 +39,7 @@ import { FrigateCardView, ThumbnailsControlBaseConfig, TimelineCoreConfig, + TimelinePanMode, } from '../config/types'; import { localize } from '../localize/localize'; import timelineCoreStyle from '../scss/timeline-core.scss'; @@ -86,11 +87,9 @@ interface TimelineRangeChange extends TimelineWindow { interface TimelineViewContext { window?: TimelineWindow; - panBehavior?: TimelinePanBehavior; } type TimelineItemClickAction = 'play' | 'select'; -type TimelinePanBehavior = 'pan' | 'seek' | 'seek-in-media' | 'seek-in-camera'; declare module 'view' { interface ViewContext { @@ -214,7 +213,7 @@ export class FrigateCardTimelineCore extends LitElement { public itemClickAction?: TimelineItemClickAction; @state() - protected _panBehavior: TimelinePanBehavior = 'seek'; + protected _panMode: TimelinePanMode | null = null; protected _targetBarVisible = false; @@ -288,20 +287,22 @@ export class FrigateCardTimelineCore extends LitElement { } const capabilities = this.cameraManager?.getAggregateCameraCapabilities(cameraIDs); + const panMode = this._getEffectivePanMode(); + const panTitle = - this._panBehavior === 'pan' - ? localize('timeline.pan_behavior.pan') - : this._panBehavior === 'seek' - ? localize('timeline.pan_behavior.seek') - : this._panBehavior === 'seek-in-media' - ? localize('timeline.pan_behavior.seek-in-media') - : localize('timeline.pan_behavior.seek-in-camera'); + panMode === 'pan' + ? localize('config.common.controls.timeline.pan_modes.pan') + : panMode === 'seek' + ? localize('config.common.controls.timeline.pan_modes.seek') + : panMode === 'seek-in-media' + ? localize('config.common.controls.timeline.pan_modes.seek-in-media') + : localize('config.common.controls.timeline.pan_modes.seek-in-camera'); const panIcon = - this._panBehavior === 'pan' + panMode === 'pan' ? 'mdi:pan-horizontal' - : this._panBehavior === 'seek' + : panMode === 'seek' ? 'mdi:filmstrip-box-multiple' - : this._panBehavior === 'seek-in-media' + : panMode === 'seek-in-media' ? 'mdi:play-box-lock' : 'mdi:camera-lock'; @@ -318,12 +319,12 @@ export class FrigateCardTimelineCore extends LitElement { ? html` { - this._panBehavior = - this._panBehavior === 'pan' + this._panMode = + panMode === 'pan' ? 'seek' - : this._panBehavior === 'seek' + : panMode === 'seek' ? 'seek-in-media' - : this._panBehavior === 'seek-in-media' + : panMode === 'seek-in-media' ? 'seek-in-camera' : 'pan'; }} @@ -404,15 +405,15 @@ export class FrigateCardTimelineCore extends LitElement { return; } + const panMode = this._getEffectivePanMode(); const targetBarOn = this._shouldSupportSeeking() && - (this._panBehavior === 'seek' || - this._panBehavior === 'seek-in-camera' || - (this._panBehavior === 'seek-in-media' && + (panMode === 'seek' || + ((panMode === 'seek-in-camera' || panMode === 'seek-in-media') && this._timeline.getSelection().some((id) => { const item = this._timelineSource?.dataset?.get(id); return ( - this._panBehavior !== 'seek-in-camera' || + panMode !== 'seek-in-camera' || item?.media?.getCameraID() === this.view?.camera, item && item.start && @@ -473,6 +474,7 @@ export class FrigateCardTimelineCore extends LitElement { ): Promise { const results = this.view?.queryResults; const media = results?.getResults(); + const panMode = this._getEffectivePanMode(); if ( !media || !results || @@ -480,7 +482,7 @@ export class FrigateCardTimelineCore extends LitElement { !this.view || !this.hass || !this.cameraManager || - this._panBehavior === 'pan' + panMode === 'pan' ) { return; } @@ -488,7 +490,7 @@ export class FrigateCardTimelineCore extends LitElement { const canSeek = this._shouldSupportSeeking(); let newResults: MediaQueriesResults | null = null; - if (this._panBehavior === 'seek') { + if (panMode === 'seek') { newResults = results .clone() .resetSelectedResult() @@ -499,7 +501,7 @@ export class FrigateCardTimelineCore extends LitElement { main: true, }, ); - } else if (this._panBehavior === 'seek-in-camera') { + } else if (panMode === 'seek-in-camera') { newResults = results .clone() .resetSelectedResult() @@ -507,7 +509,7 @@ export class FrigateCardTimelineCore extends LitElement { cameraID: this.view.camera, }) .promoteCameraSelectionToMainSelection(this.view.camera); - } else if (this._panBehavior === 'seek-in-media') { + } else if (panMode === 'seek-in-media') { newResults = results; } @@ -531,6 +533,10 @@ export class FrigateCardTimelineCore extends LitElement { .dispatchChangeEvent(this); } + protected _getEffectivePanMode(): TimelinePanMode { + return this._panMode ?? this.timelineConfig?.pan_mode ?? 'pan'; + } + /** * Called whenever the timeline is clicked. * @param properties The properties of the timeline click event. @@ -988,10 +994,6 @@ export class FrigateCardTimelineCore extends LitElement { : null; const context = this.view.context?.timeline; - if (context && context.panBehavior) { - this._panBehavior = context.panBehavior; - } - if (context && context.window) { desiredWindow = context.window; } else if (mediaWindow && !rangesOverlap(mediaWindow, timelineWindow)) { @@ -1107,7 +1109,6 @@ export class FrigateCardTimelineCore extends LitElement { return { timeline: { ...this.view?.context?.timeline, - panBehavior: this._panBehavior, ...(newWindow && { window: newWindow }), }, }; diff --git a/src/config/types.ts b/src/config/types.ts index c6086fa0..d241c793 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -727,8 +727,17 @@ const timelineCoreConfigDefault = { window_seconds: 60 * 60, show_recordings: true, style: 'stack' as const, + pan_mode: 'pan' as const, }; +export const timelinePanModeSchema = z.enum([ + 'pan', + 'seek', + 'seek-in-media', + 'seek-in-camera', +]); +export type TimelinePanMode = z.infer; + const timelineCoreConfigSchema = z.object({ clustering_threshold: z .number() @@ -748,6 +757,9 @@ const timelineCoreConfigSchema = z.object({ .optional() .default(timelineCoreConfigDefault.show_recordings), style: z.enum(['stack', 'ribbon']).optional().default(timelineCoreConfigDefault.style), + pan_mode: timelinePanModeSchema + .optional() + .default(timelineCoreConfigDefault.pan_mode), }); export type TimelineCoreConfig = z.infer; diff --git a/src/const.ts b/src/const.ts index 1dd10870..fdb6237c 100644 --- a/src/const.ts +++ b/src/const.ts @@ -163,6 +163,8 @@ export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE = `${CONF_MEDIA_VIEWER}.controls.timeline.events_media_type` as const; export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MODE = `${CONF_MEDIA_VIEWER}.controls.timeline.mode` as const; +export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_PAN_MODE = + `${CONF_MEDIA_VIEWER}.controls.timeline.pan_mode` as const; export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_SHOW_RECORDINGS = `${CONF_MEDIA_VIEWER}.controls.timeline.show_recordings` as const; export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_STYLE = @@ -219,6 +221,8 @@ export const CONF_LIVE_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE = `${CONF_LIVE}.controls.timeline.events_media_type` as const; export const CONF_LIVE_CONTROLS_TIMELINE_MODE = `${CONF_LIVE}.controls.timeline.mode` as const; +export const CONF_LIVE_CONTROLS_TIMELINE_PAN_MODE = + `${CONF_LIVE}.controls.timeline.pan_mode` as const; export const CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS = `${CONF_LIVE}.controls.timeline.show_recordings` as const; export const CONF_LIVE_CONTROLS_TIMELINE_STYLE = diff --git a/src/editor.ts b/src/editor.ts index b9f9493a..415d5e56 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -91,6 +91,7 @@ import { CONF_LIVE_CONTROLS_THUMBNAILS_EVENTS_MEDIA_TYPE, CONF_LIVE_CONTROLS_THUMBNAILS_MEDIA_TYPE, CONF_LIVE_CONTROLS_THUMBNAILS_MODE, + CONF_LIVE_CONTROLS_TIMELINE_PAN_MODE, CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DETAILS, CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DOWNLOAD_CONTROL, CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL, @@ -140,6 +141,7 @@ import { CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_CLUSTERING_THRESHOLD, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MODE, + CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_PAN_MODE, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_SHOW_RECORDINGS, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_STYLE, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_WINDOW_SECONDS, @@ -719,6 +721,26 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor }, ]; + protected _timelinePanModes: EditorSelectOption[] = [ + { value: '', label: '' }, + { + value: 'pan', + label: localize('config.common.controls.timeline.pan_modes.pan'), + }, + { + value: 'seek', + label: localize('config.common.controls.timeline.pan_modes.seek'), + }, + { + value: 'seek-in-media', + label: localize('config.common.controls.timeline.pan_modes.seek-in-media'), + }, + { + value: 'seek-in-camera', + label: localize('config.common.controls.timeline.pan_modes.seek-in-camera'), + }, + ]; + public setConfig(config: RawFrigateCardConfig): void { // Note: This does not use Zod to parse the configuration, so it may be // partially or completely invalid. It's more useful to have a partially @@ -1197,30 +1219,34 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor configPathTimelineEventsMediaType: string, configPathShowRecordings: string, defaultShowRecordings: boolean, + configPathPanMode?: string, ): TemplateResult { - return html` ${this._renderOptionSelector( - configPathStyle, - this._timelineStyleTypes, - { + return html` + ${this._renderOptionSelector(configPathStyle, this._timelineStyleTypes, { label: localize(`config.common.${CONF_TIMELINE_STYLE}`), - }, - )} - ${this._renderNumberInput(configPathWindowSeconds, { - label: localize(`config.common.${CONF_TIMELINE_WINDOW_SECONDS}`), - })} - ${this._renderNumberInput(configPathClusteringThreshold, { - label: localize(`config.common.${CONF_TIMELINE_CLUSTERING_THRESHOLD}`), - })} - ${this._renderOptionSelector( - configPathTimelineEventsMediaType, - this._timelineEventsMediaTypes, - { - label: localize(`config.common.${CONF_TIMELINE_EVENTS_MEDIA_TYPE}`), - }, - )} - ${this._renderSwitch(configPathShowRecordings, defaultShowRecordings, { - label: localize(`config.common.${CONF_TIMELINE_SHOW_RECORDINGS}`), - })}`; + })} + ${configPathPanMode + ? this._renderOptionSelector(configPathPanMode, this._timelinePanModes, { + label: localize(`config.common.controls.timeline.pan_mode`), + }) + : ``} + ${this._renderNumberInput(configPathWindowSeconds, { + label: localize(`config.common.${CONF_TIMELINE_WINDOW_SECONDS}`), + })} + ${this._renderNumberInput(configPathClusteringThreshold, { + label: localize(`config.common.${CONF_TIMELINE_CLUSTERING_THRESHOLD}`), + })} + ${this._renderOptionSelector( + configPathTimelineEventsMediaType, + this._timelineEventsMediaTypes, + { + label: localize(`config.common.${CONF_TIMELINE_EVENTS_MEDIA_TYPE}`), + }, + )} + ${this._renderSwitch(configPathShowRecordings, defaultShowRecordings, { + label: localize(`config.common.${CONF_TIMELINE_SHOW_RECORDINGS}`), + })} + `; } /** @@ -1241,6 +1267,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor configPathTimelineEventsMediaType: string, configPathShowRecordings: string, showRecordingsDefault: boolean, + configPathPanMode: string, ): TemplateResult | void { return this._putInSubmenu( domain, @@ -1257,6 +1284,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor configPathTimelineEventsMediaType, configPathShowRecordings, showRecordingsDefault, + configPathPanMode, )}`, ); } @@ -2208,6 +2236,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor CONF_LIVE_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS, this._defaults.live.controls.timeline.show_recordings, + CONF_LIVE_CONTROLS_TIMELINE_PAN_MODE, )} ${this._putInSubmenu( MENU_LIVE_CONTROLS_PTZ, @@ -2394,6 +2423,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_SHOW_RECORDINGS, this._defaults.media_viewer.controls.timeline.show_recordings, + CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_PAN_MODE, )} `, )} diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 6e41fb24..25407e9c 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -173,6 +173,13 @@ "above": "Above", "below": "Below", "none": "None" + }, + "pan_mode": "Default pan mode", + "pan_modes": { + "pan": "Pan", + "seek": "Pan seeks across all media", + "seek-in-camera": "Pan seeks within selected camera only", + "seek-in-media": "Pan seeks within selected media item only" } }, "title": { @@ -589,12 +596,6 @@ "timeline": "See media in timeline" }, "timeline": { - "pan_behavior": { - "pan": "Pan", - "seek": "Pan seeks across all media", - "seek-in-camera": "Pan seeks within selected camera only", - "seek-in-media": "Pan seeks within selected media item only" - }, "select_date": "Choose date" } -} \ No newline at end of file +} diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 76f7fa6c..94cb26f5 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -28,8 +28,8 @@ "editor_label": "Opzioni di dipendenza" }, "dimensions": { - "editor_label": "", "aspect_ratio": "", + "editor_label": "", "layout": { "fit": "Adatta al layout", "fits": { @@ -172,6 +172,13 @@ "above": "sopra", "below": "sotto", "none": "sessuna" + }, + "pan_mode": "", + "pan_modes": { + "pan": "", + "seek": "", + "seek-in-camera": "", + "seek-in-media": "" } }, "title": { @@ -577,12 +584,6 @@ "timeline": "Vedi evento nella timeline" }, "timeline": { - "pan_behavior": { - "pan": "", - "seek": "", - "seek-in-camera": "", - "seek-in-media": "" - }, "select_date": "Scegli la data" } } diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 0243437f..85ee08a3 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -28,8 +28,8 @@ "editor_label": "Opções de dependência" }, "dimensions": { - "editor_label": "", "aspect_ratio": "", + "editor_label": "", "layout": { "fit": "Ajuste de layout", "fits": { @@ -172,6 +172,13 @@ "above": "Acima", "below": "Abaixo", "none": "Nenhum" + }, + "pan_mode": "", + "pan_modes": { + "pan": "", + "seek": "", + "seek-in-camera": "", + "seek-in-media": "" } }, "title": { @@ -587,12 +594,6 @@ "timeline": "Ver evento na linha do tempo" }, "timeline": { - "pan_behavior": { - "pan": "", - "seek": "", - "seek-in-camera": "", - "seek-in-media": "" - }, "select_date": "Escolha a data" } } diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 00d9b704..859fa85f 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -28,8 +28,8 @@ "editor_label": "Opções de dependência" }, "dimensions": { - "editor_label": "", "aspect_ratio": "", + "editor_label": "", "layout": { "fit": "Fit", "fits": { @@ -102,9 +102,9 @@ "editor_label": "Opções de activação", "entities": "Activar a partir de outras entidades", "events": { + "clips": "", "editor_label": "", "events": "", - "clips": "", "snapshots": "" }, "motion": "Activar detectando automaticamente o sensor de movimento", @@ -172,6 +172,13 @@ "above": "Por cima", "below": "Abaixo", "none": "Nenhum" + }, + "pan_mode": "", + "pan_modes": { + "pan": "", + "seek": "", + "seek-in-camera": "", + "seek-in-media": "" } }, "title": { @@ -569,12 +576,6 @@ "timeline": "Ver evento na linha do tempo" }, "timeline": { - "pan_behavior": { - "pan": "", - "seek": "", - "seek-in-camera": "", - "seek-in-media": "" - }, "select_date": "Selecionar a data" } } diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index c3b2d4c2..9ce96b3e 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -91,6 +91,7 @@ describe('config defaults', () => { clustering_threshold: 3, events_media_type: 'all', mode: 'none', + pan_mode: 'pan', show_recordings: true, style: 'ribbon', window_seconds: 3600, @@ -147,6 +148,7 @@ describe('config defaults', () => { clustering_threshold: 3, events_media_type: 'all', mode: 'none', + pan_mode: 'pan', show_recordings: true, style: 'ribbon', window_seconds: 3600, @@ -271,6 +273,7 @@ describe('config defaults', () => { }, }, events_media_type: 'all', + pan_mode: 'pan', show_recordings: true, style: 'stack', window_seconds: 3600, diff --git a/vite.config.ts b/vite.config.ts index 29404bb3..2c0b04a2 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -80,13 +80,13 @@ export default defineConfig({ // Expected thresholds for anything that does not have 100% coverage // yet. - statements: 10.67, + statements: 10.69, branches: 4.9, functions: 7.81, - lines: 10.92, + lines: 10.94, ...calculateFullCoverageThresholds(), }, }, }, -}); +}); \ No newline at end of file From a0df7b72bd6e4482033cf1757d5aa34572512515 Mon Sep 17 00:00:00 2001 From: edurenye Date: Fri, 22 Mar 2024 12:02:07 +0100 Subject: [PATCH 104/189] Add catalan translations --- project.inlang.json | 1 + src/localize/languages/ca.json | 594 +++++++++++++++++++++++++++++++++ src/localize/localize.ts | 4 +- 3 files changed, 598 insertions(+), 1 deletion(-) create mode 100644 src/localize/languages/ca.json diff --git a/project.inlang.json b/project.inlang.json index 9f3af7ab..9122f183 100644 --- a/project.inlang.json +++ b/project.inlang.json @@ -2,6 +2,7 @@ "$schema": "https://inlang.com/schema/project-settings", "sourceLanguageTag": "en", "languageTags": [ + "ca", "en", "it", "pt-BR", diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json new file mode 100644 index 00000000..d44cab45 --- /dev/null +++ b/src/localize/languages/ca.json @@ -0,0 +1,594 @@ +{ + "common": { + "frigate_card": "Tarjeta Frigate", + "frigate_card_description": "Una targeta Lovelace per a utilitzar amb Frigate", + "live": "En directe", + "no_media": "No hi ha suport per mostrar", + "recordings": "Enregistraments", + "version": "Versió" + }, + "config": { + "cameras": { + "camera_entity": "Entitat de càmera", + "cast": { + "dashboard": { + "dashboard_path": "Ruta del tauler de control", + "view_path": "Ruta de la visualització" + }, + "editor_label": "Opcions d'emissió", + "method": "Mètode d'emissió", + "methods": { + "dashboard": "Tauler de control", + "standard": "Estàndard" + } + }, + "dependencies": { + "all_cameras": "Mostra els esdeveniments de totes les càmeres amb aquesta càmera", + "cameras": "Mostra esdeveniments per a càmeres específiques amb aquesta càmera", + "editor_label": "Opcions de dependències" + }, + "dimensions": { + "aspect_ratio": "Relació d'aspecte estàtica", + "editor_label": "Dimensions de la càmera", + "layout": { + "editor_label": "Maquetació de la càmera", + "fit": "Ajust de la maquetació", + "fits": { + "contain": "Els mitjans multimèdia estan continguts/en bústia", + "cover": "El suport s'expandeix proporcionalment per cobrir la targeta", + "fill": "El suport s'estira per omplir la targeta" + }, + "position": { + "x": "Percentatge d'emplaçament horitzontal", + "y": "Percentatge d'emplaçament vertical" + } + } + }, + "engines": { + "editor_label": "Opcions del motor de càmera" + }, + "frigate": { + "camera_name": "Nom de la càmera de Frigate (detecció automàtica de l'entitat)", + "client_id": "Identificador de client de Frigate (per a > 1 servidor de Frigate)", + "editor_label": "Opcions de Frigate", + "labels": "Etiquetes de Frigate/filtres d'objectes", + "url": "URL del servidor de Frigate", + "zones": "Zones de Frigate" + }, + "go2rtc": { + "editor_label": "Opcions de go2rtc", + "modes": { + "editor_label": "Modes de go2rtc" + }, + "stream": "nom del flux de go2rtc" + }, + "hide": "Amaga la càmera de la interfície d'usuari", + "icon": "Icona d'aquesta càmera (detecció automàtica des de l'entitat)", + "id": "Identificador únic per a aquesta càmera en aquesta targeta", + "image": { + "editor_label": "Opcions d'imatge", + "refresh_seconds": "Nombre de segons després dels quals actualitzar la imatge en directe (0=mai)", + "url": "URL de la imatge que cal utilitzar en lloc de la instantània de l'entitat de la càmera" + }, + "live_provider": "Proveïdor de visualització en directe per a aquesta càmera", + "live_provider_options": { + "editor_label": "Opcions de proveïdor en directe" + }, + "live_providers": { + "auto": "Automàtic", + "ha": "Transmissió de vídeo de Home Assistant (és a dir, HLS, LL-HLS, WebRTC mitjançant HA)", + "image": "Imatges de Home Assistant", + "webrtc-card": "Targeta WebRTC (és a dir, la targeta WebRTC d'AlexxIT)" + }, + "motioneye": { + "editor_label": "Opcions de MotionEye", + "images": { + "directory_pattern": "Patró del directori d'imatges", + "file_pattern": "Patró de fitxer d'imatges" + }, + "movies": { + "directory_pattern": "Patró del directori de pel·lícules", + "file_pattern": "Patró de fitxer de pel·lícules" + }, + "url": "URL de la interfície d'usuari de MotionEye" + }, + "title": "Títol d'aquesta càmera (detecció automàtica de l'entitat)", + "triggers": { + "editor_label": "Opcions d'activació", + "entities": "Activador d'altres entitats", + "events": { + "clips": "Esdeveniments amb nous clips", + "editor_label": "Activar esdeveniments", + "events": "Tots els esdeveniments", + "snapshots": "Esdeveniments amb noves instantànies" + }, + "motion": "Activa la detecció automàtica del sensor de moviment", + "occupancy": "Activa la detecció automàtica del sensor d'ocupació" + }, + "webrtc_card": { + "editor_label": "Opcions de la targeta WebRTC", + "entity": "Entitat de càmera de targeta WebRTC (no una càmera de Frigate)", + "url": "URL de la càmera de la targeta WebRTC" + } + }, + "common": { + "controls": { + "builtin": "Controls de vídeo integrats", + "filter": { + "editor_label": "Filtre multimèdia", + "mode": "Mode de filtre", + "modes": { + "left": "Filtre multimèdia en un calaix a l'esquerra", + "none": "Sense filtre multimèdia", + "right": "Filtre multimèdia en un calaix a la dreta" + } + }, + "next_previous": { + "editor_label": "Següent i anterior", + "size": "Mida del control següent i anterior en píxels", + "style": "Estil de control següent i anterior", + "styles": { + "chevrons": "Xebrons", + "icons": "Icones", + "none": "Cap", + "thumbnails": "Miniatures" + } + }, + "thumbnails": { + "editor_label": "Miniatures", + "events_media_type": "Si voleu mostrar miniatures d'esdeveniments de clips o instantànies", + "events_media_types": { + "clips": "Miniatures de clips", + "snapshots": "Miniatures d'instantànies" + }, + "media_type": "Si voleu mostrar miniatures d'esdeveniments o enregistraments", + "media_types": { + "events": "Esdeveniments", + "recordings": "Enregistraments" + }, + "mode": "Mode de miniatures", + "modes": { + "above": "Miniatures a dalt", + "below": "Miniatures a baix", + "left": "Miniatures en un calaix a l'esquerra", + "none": "Sense miniatures", + "right": "Miniatures en un calaix a la dreta" + }, + "show_details": "Mostra els detalls amb miniatures", + "show_download_control": "Mostra el control de descàrrega a les miniatures", + "show_favorite_control": "Mostra el control preferit a les miniatures", + "show_timeline_control": "Mostra el control de la línia de temps a les miniatures", + "size": "Mida de les miniatures en píxels" + }, + "timeline": { + "editor_label": "Mini cronologia", + "mode": "Mode", + "modes": { + "above": "A dalt", + "below": "Baix", + "none": "Cap" + }, + "pan_mode": "Mode d'escombratge predeterminat", + "pan_modes": { + "pan": "Escombratge", + "seek": "Cerca d'escombratge en tots els mitjans", + "seek-in-camera": "Cerca d'escombratge només a la càmera seleccionada", + "seek-in-media": "Cerca d'escombratge només dins de l'element multimèdia seleccionat" + } + }, + "title": { + "duration_seconds": "Segons per mostrar el títol emergent (0=per sempre)", + "editor_label": "Controls del títol emergent", + "mode": "Mode de visualització del títol emergent", + "modes": { + "none": "No es mostra el títol", + "popup-bottom-left": "Popup a la part inferior esquerra", + "popup-bottom-right": "Popup a la part inferior dreta", + "popup-top-left": "Popup a la part superior esquerra", + "popup-top-right": "Popup a la part superior dreta" + } + } + }, + "display": { + "editor_label": "Visualització", + "grid_columns": "Nombre exacte de columnes de la graella", + "grid_max_columns": "Nombre màxim de columnes de la graella", + "grid_selected_width_factor": "Augmenta l'amplada del suport multimèdia seleccionat en aquest factor", + "mode": "Mode" + }, + "media_action_conditions": { + "all": "Totes les oportunitats", + "hidden": "A l'amagat del navegador/pestanya", + "microphone_mute": "Si el micròfon està en silenci", + "microphone_unmute": "Si el micròfon no està en silenci", + "never": "Mai", + "selected": "A la selecció", + "unselected": "En desselecció", + "visible": "En la visualització del navegador/pestanya" + }, + "timeline": { + "clustering_threshold": "El recompte d'esdeveniments en què s'agrupen (0=sense agrupació)", + "events_media_type": "Els esdeveniments multimèdia que mostra la línia de temps", + "events_media_types": { + "all": "Tots els tipus de mitjans", + "clips": "Clips", + "snapshots": "Imatges instantànies" + }, + "show_recordings": "Mostra les gravacions", + "style": "Estil de cronologia", + "styles": { + "ribbon": "Esdeveniments en una sola cinta", + "stack": "Esdeveniments apilats i agrupats" + }, + "window_seconds": "La durada predeterminada de la visualització de la línia de temps en segons" + } + }, + "dimensions": { + "aspect_ratio": "Relació d'aspecte predeterminada (p. ex., '16:9')", + "aspect_ratio_mode": "Mode de relació d'aspecte", + "aspect_ratio_modes": { + "dynamic": "La relació d'aspecte s'ajusta al suport multimèdia", + "static": "Relació d'aspecte estàtica", + "unconstrained": "Relació d'aspecte sense restriccions" + }, + "max_height": "Alçada màxima de la targeta en unitats CSS (p. ex., '100vh')", + "min_height": "Alçada mínima de la targeta en unitats CSS (p. ex., '100 px')" + }, + "image": { + "mode": "Mode de visualització d'imatges", + "modes": { + "camera": "Instantània de l'entitat de la càmera de Home Assistant", + "screensaver": "Logotip de Frigate incrustat", + "url": "Imatge arbitrària especificada per URL" + }, + "refresh_seconds": "Nombre de segons després dels quals cal actualitzar (0=mai)", + "url": "URL d'imatge estàtica per a la visualització d'imatges", + "zoomable": "La imatge es pot ampliar/escombrar" + }, + "live": { + "auto_mute": "Silencia automàticament les càmeres en directe", + "auto_pause": "Posa en pausa automàticament les càmeres en directe", + "auto_play": "Reprodueix automàticament les càmeres en directe", + "auto_unmute": "Activa automàticament el so de les càmeres en directe", + "controls": { + "editor_label": "Controls del directe", + "ptz": { + "editor_label": "PTZ", + "hide_home": "Amaga el control de casa", + "hide_pan_tilt": "Amaga el control d'escombratge i inclinació", + "hide_zoom": "Amaga el control de zoom", + "mode": "Mode", + "modes": { + "off": "Desactivat", + "on": "Activat" + }, + "orientation": "Orientació", + "orientations": { + "horizontal": "Horitzontal", + "vertical": "Vertical" + }, + "position": "Posició", + "positions": { + "bottom-left": "Inferior esquerra", + "bottom-right": "Inferior dreta", + "top-left": "Superior left", + "top-right": "Superior dreta" + } + } + }, + "draggable": "La vista de càmeres en directe es pot arrossegar/lliscar", + "lazy_load": "Les càmeres en directe es carreguen amb mandra", + "lazy_unload": "Les càmeres en directe es descarreguen amb mandra", + "microphone": { + "always_connected": "Mantingueu sempre el micròfon connectat", + "disconnect_seconds": "Segons després dels quals desconnectar el micròfon (0=mai)", + "editor_label": "Micròfon", + "enabled": "El micròfon està activat", + "mute_after_microphone_mute_seconds": "Segons després de silenciar el micròfon per silenciar l'àudio entrant" + }, + "preload": "Carregueu prèviament la visualització en directe en segon pla", + "show_image_during_load": "Mostra la imatge fixa mentre es carrega la reproducció en directe", + "transition_effect": "Efecte de transició de càmera en directe", + "zoomable": "Les càmeres en directe es poden ampliar/escombrar" + }, + "media_viewer": { + "auto_mute": "Silencia automàticament els continguts multimèdia", + "auto_pause": "Atura automàticament el contingut multimèdia", + "auto_play": "Reprodueix automàticament els continguts multimèdia", + "auto_unmute": "Activa automàticament el so del contingut multimèdia", + "controls": { + "editor_label": "Controls del visualitzador de contingut multimèdia" + }, + "draggable": "El visualitzador de mitjans es pot arrossegar/lliscar", + "lazy_load": "El contingut multimèdia del visualitzador multimèdia es carreguen amb mandra al carrusel", + "snapshot_click_plays_clip": "Si feu clic a una instantània, es reprodueix un clip relacionat", + "transition_effect": "Efecte de transició del visualitzador multimèdia", + "transition_effects": { + "none": "Sense transició", + "slide": "Transició de diapositives" + }, + "zoomable": "El visualitzador de mitjans es pot ampliar/escombrar" + }, + "menu": { + "alignment": "Alineació del menú", + "alignments": { + "bottom": "Alineat a la part inferior", + "left": "Alineat a l'esquerra", + "right": "Alineat a la dreta", + "top": "Alineat a la part superior" + }, + "button_size": "Mida del botó del menú en píxels", + "buttons": { + "alignment": "Alineació de botons", + "alignments": { + "matching": "Coincideix amb l'alineació del menú", + "opposing": "Oposat a l'alineació del menú" + }, + "camera_ui": "Interfície d'usuari de la càmera", + "cameras": "Càmeres", + "clips": "Clips", + "display_mode": "Mode de visualització", + "download": "Descarregar", + "enabled": "Botó habilitat", + "expand": "Expandir", + "frigate": "Menú de Frigate / Vista per defecte", + "fullscreen": "Pantalla completa", + "icon": "Icona", + "image": "Imatge", + "live": "En directe", + "media_player": "Envia al reproductor multimèdia", + "microphone": "Micròfon", + "mute": "Silenciar / Activar el so", + "play": "Reproduir / Pausa", + "priority": "Prioritat", + "recordings": "Enregistraments", + "screenshot": "Captura de pantalla", + "snapshots": "Imatges instantànies", + "substreams": "Subfluxos", + "timeline": "Cronologia", + "type": "Tipus de botó", + "types": { + "momentary": "Momentani", + "toggle": "Commuta" + } + }, + "position": "Posició del menú", + "positions": { + "bottom": "Situat a la part inferior", + "left": "Situat a l'esquerra", + "right": "Situat a la dreta", + "top": "Situat a la part superior" + }, + "style": "Estil de menú", + "styles": { + "hidden": "Menú ocult", + "hover": "Menú passant el cursor", + "hover-card": "Menú passant el cursor (a tota la targeta)", + "none": "Sense menú", + "outside": "Menú exterior", + "overlay": "Menú superposat" + } + }, + "overrides": { + "info": "Aquesta configuració de targeta ha especificat manualment substitucions configurades que poden anul·lar els valors que es mostren a l'editor visual; consulteu l'editor de codi per veure/modificar aquestes substitucions." + }, + "performance": { + "features": { + "animated_progress_indicator": "Indicador animat del progrés", + "editor_label": "Opcions de característiques", + "media_chunk_size": "Mida del fragment multimèdia" + }, + "profile": "Perfil de rendiment", + "profiles": { + "high": "Alt rendiment", + "low": "Baix rendiment" + }, + "style": { + "border_radius": "Corbes", + "box_shadow": "Ombres", + "editor_label": "Opcions d'estil" + }, + "warning": "Aquesta targeta està en mode de perfil baix, de manera que els valors predeterminats han canviat per optimitzar el rendiment" + }, + "view": { + "camera_select": "Visualitza les càmeres seleccionades recentment", + "dark_mode": "Mode fosc", + "dark_modes": { + "auto": "Automàtic", + "off": "Desactivat", + "on": "Activat" + }, + "default": "Vista per defecte", + "interaction_seconds": "Segons després de l'acció de l'usuari per continuar interactuant (0=mai)", + "reset_after_interaction": "Restableix la vista predeterminada després de la interacció de l'usuari", + "triggers": { + "actions": { + "editor_label": "Activar accions", + "interaction_mode": "Com gestionar les accions quan la targeta té interacció humana", + "interaction_modes": { + "active": "Activa només accions quan la targeta té interacció humana", + "all": "Activa accions independentment de la interacció humana", + "inactive": "Només activa accions quan la targeta no té interacció humana" + }, + "trigger": "Activar l'acció", + "triggers": { + "default": "Canvia o actualitza la vista predeterminada", + "live": "Canvia o actualitza la visualització en directe", + "media": "Canvieu a la visualització de mitjans rellevants per als nous mitjans", + "none": "Sense acció" + }, + "untrigger": "Desactiva l'acció", + "untriggers": { + "default": "Canvia a la vista/càmera predeterminada", + "none": "Sense acció" + } + }, + "editor_label": "Comportament quan s'activa una càmera", + "filter_selected_camera": "Activa només a la càmera seleccionada", + "show_trigger_status": "Mostra la vora intermitent quan s'activa", + "untrigger_seconds": "Segons després del canvi d'estat inactiu a desactivat" + }, + "update_cycle_camera": "Passeu per les càmeres quan s'actualitzi la vista predeterminada", + "update_force": "Força les actualitzacions de la targeta (ignora la interacció de l'usuari)", + "update_seconds": "Actualitza la vista predeterminada cada X segons (0=mai)", + "views": { + "clip": "Clip més recent", + "clips": "Galeria de clips", + "current": "Vista actual", + "image": "Imatge estàtica", + "live": "Visualització en directe", + "recording": "Enregistrament més recent", + "recordings": "Galeria d'enregistraments", + "snapshot": "Instantània més recent", + "snapshots": "Galeria d'instantànies", + "timeline": "Vista cronològica" + } + } + }, + "display_modes": { + "grid": "Mostra el visualitzador multimèdia per a cada càmera d'una quadrícula", + "single": "Mostra un visualitzador multimèdia únic" + }, + "editor": { + "add_new_camera": "Afegeix una càmera nova", + "button": "Botó", + "camera": "Càmera", + "cameras": "Càmeres", + "cameras_secondary": "Quines càmeres renderitzar en aquesta targeta", + "delete": "Suprimeix", + "dimensions": "Dimensions", + "dimensions_secondary": "Opcions de dimensions i forma", + "image": "Imatge", + "image_secondary": "Opcions de visualització d'imatges estàtiques", + "live": "En directe", + "live_secondary": "Opcions de visualització de la càmera en directe", + "media_gallery": "Galeria multimèdia", + "media_gallery_secondary": "Opcions de la galeria multimèdia", + "media_viewer": "Visor multimèdia", + "media_viewer_secondary": "Visor de suports estàtics (clips, instantànies o enregistraments)", + "menu": "Menú", + "menu_secondary": "Opcions d'aspecte del menú", + "move_down": "Moure cap avall", + "move_up": "Moure cap amunt", + "overrides": "Les substitucions estan actives", + "overrides_secondary": "S'han detectat substitucions de configuració dinàmica", + "performance": "Rendiment", + "performance_secondary": "Opcions de rendiment de la targeta", + "timeline": "Cronologia", + "timeline_secondary": "Opcions de la cronologia d'esdeveniments", + "upgrade": "Upgrade", + "upgrade_available": "Hi ha disponible una actualització automàtica de la configuració de la targeta", + "view": "Vista", + "view_secondary": "Què ha de mostrar la targeta i com mostrar-la" + }, + "elements": { + "ptz": { + "down": "Avall", + "home": "Casa", + "left": "Esquerra", + "right": "Dreta", + "up": "Amunt", + "zoom_in": "Ampliar", + "zoom_out": "Reduir" + } + }, + "error": { + "awaiting_live": "S'està esperant que es carregui la transmissió en directe ...", + "could_not_render_elements": "No s'han pogut representar els elements de la imatge", + "could_not_resolve": "No s'ha pogut resoldre l'URL multimèdia", + "diagnostics": "Diagnòstic de targetes. Reviseu la informació confidencial abans de compartir-la", + "download_no_media": "No hi ha contingut multimèdia per descarregar", + "download_sign_failed": "No s'ha pogut signar l'URL multimèdia per baixar-la", + "duplicate_camera_id": "Duplica l'identificador de la càmera Frigate per a la següent càmera, utilitza el paràmetre 'id' per identificar les càmeres de manera única", + "empty_response": "S'ha rebut una resposta buida de Home Assistant per a la sol·licitud", + "failed_response": "No s'ha pogut rebre la resposta de Home Assistant per a la sol·licitud", + "failed_retain": "No s'ha pogut retenir l'esdeveniment", + "failed_sign": "No s'ha pogut signar l'URL de Home Assistant", + "image_load_error": "No s'ha pogut carregar la imatge", + "invalid_configuration": "Configuració no vàlida", + "invalid_configuration_no_hint": "No hi ha cap indicació d'ubicació disponible (tipus dolent o faltant?)", + "invalid_elements_config": "La configuració dels elements de la imatge no és vàlida", + "invalid_response": "S'ha rebut una resposta no vàlida de Home Assistant per a la sol·licitud", + "jsmpeg_no_player": "No s'ha pogut iniciar el reproductor JSMPEG", + "live_camera_no_endpoint": "No s'ha pogut obtenir el punt final de la càmera per a aquest proveïdor en directe (configuració incompleta?)", + "live_camera_not_found": "No s'ha trobat la 'camera_entity' (entitat de la càmera) configurada", + "live_camera_unavailable": "Càmera no disponible", + "no_camera_engine": "No s'ha pogut determinar el motor adequat per a la càmera", + "no_camera_entity": "No s'ha pogut trobar l'entitat de la càmera", + "no_camera_entity_for_triggers": "Es requereix una entitat de càmera per detectar automàticament els activadors", + "no_camera_id": "No s'ha pogut determinar l'identificador de la càmera per a la següent càmera, és possible que hagis d'establir el paràmetre 'id' manualment", + "no_camera_name": "No s'ha pogut determinar el nom de la càmera Frigate per a la càmera (o una de les seves dependències), especifiqueu 'camera_entity' o 'camera_name'", + "no_dashboard_or_view": "Tant els paràmetres 'dashboard_path' com 'view_path' són necessaris per al mètode d'emissió 'dashboard'", + "no_live_camera": "El paràmetre 'camera_entity' s'ha de configurar i validar per a aquest proveïdor en directe", + "no_visible_cameras": "No s'han trobat càmeres visibles, heu de configurar almenys una càmera no oculta", + "reconnecting": "Reconnectant", + "timeline_no_cameras": "No hi ha càmeres Frigate per mostrar a la línia de temps", + "too_many_automations": "Hi ha massa trucades d'automatització imbricades, comproveu la vostra configuració per veure si hi ha bucles", + "troubleshooting": "Comproveu la resolució de problemes", + "unknown": "Error desconegut", + "upgrade_available": "Hi ha disponible una actualització automàtica de la configuració de la targeta; visiteu l'editor de targetes visuals", + "webrtc_card_reported_error": "La targeta WebRTC ha informat d'un error", + "webrtc_card_waiting": "S'està esperant que es carregui la targeta WebRTC ..." + }, + "event": { + "camera": "Càmera", + "duration": "Durada", + "in_progress": "En procés", + "score": "Puntuació", + "seek": "Buscar", + "start": "Començar", + "tag": "Etiqueta", + "what": "Què", + "where": "On" + }, + "media_filter": { + "all": "Tots", + "camera": "Càmera", + "favorite": "Preferit", + "media_type": "Tipus de suport multimèdia", + "media_types": { + "clips": "Clips", + "recordings": "Enregistraments", + "snapshots": "Imatges instantànies" + }, + "not_favorite": "No preferit", + "select_camera": "Selecciona la càmera...", + "select_favorite": "Selecciona el preferit...", + "select_media_type": "Selecciona el tipus de suport multimèdia...", + "select_tag": "Selecciona l'etiqueta...", + "select_what": "Selecciona el què...", + "select_when": "Selecciona quan...", + "select_where": "Selecciona on...", + "tag": "Etiqueta", + "what": "Què", + "when": "Quan", + "whens": { + "custom": "Personalitzat", + "past_month": "El mes passat", + "past_week": "La setmana passada", + "today": "Avui", + "yesterday": "Ahir" + }, + "where": "On" + }, + "media_viewer": { + "unseekable": "Busqueu temps no trobat als mitjans multimèdia" + }, + "recording": { + "camera": "Càmera", + "duration": "Durada", + "events": "Esdeveniments", + "in_progress": "En procés", + "seek": "Buscar", + "start": "Començar" + }, + "thumbnail": { + "download": "Descarregar mitjans multimèdia", + "no_thumbnail": "No hi ha cap miniatura disponible", + "retain_indefinitely": "Els mitjans multimèdia es conservaran indefinidament", + "timeline": "Veure els mitjans multimèdia a la línia de temps" + }, + "timeline": { + "select_date": "Escolliu la data" + } +} diff --git a/src/localize/localize.ts b/src/localize/localize.ts index 76e67a72..efefeae5 100644 --- a/src/localize/localize.ts +++ b/src/localize/localize.ts @@ -54,7 +54,9 @@ export function getLanguage(hass?: HomeAssistant): string { */ export const loadLanguages = async (hass: HomeAssistant): Promise => { const lang = getLanguage(hass); - if (lang === 'it') { + if (lang === 'ca') { + languages[lang] = await import('./languages/ca.json'); + } else if (lang === 'it') { languages[lang] = await import('./languages/it.json'); } else if (lang === 'pt') { languages[lang] = await import('./languages/pt-PT.json'); From 95c44adcf1741fc6f54b0edd4e1e9f31a60c58b1 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 26 Mar 2024 20:59:42 -0700 Subject: [PATCH 105/189] Allow camera capabilities to be configured. --- README.md | 54 +- .../browse-media/engine-browse-media.ts | 27 +- src/camera-manager/camera.ts | 9 +- src/camera-manager/capabilities.ts | 60 + src/camera-manager/engine-factory.ts | 7 +- src/camera-manager/frigate/camera.ts | 33 +- src/camera-manager/frigate/engine-frigate.ts | 12 +- src/camera-manager/generic/engine-generic.ts | 30 +- src/camera-manager/manager.ts | 50 +- src/camera-manager/store.ts | 75 +- src/camera-manager/types.ts | 30 +- src/camera-manager/utils.ts | 84 -- .../utils/camera-entity-from-config.ts | 5 + src/camera-manager/utils/cap-end-date.ts | 4 + src/camera-manager/utils/go2rtc-endpoint.ts | 25 + .../utils/range-to-cache-friendly.ts | 35 + src/camera-manager/utils/sort-media.ts | 16 + src/card-controller/view-manager.ts | 175 +-- src/components-lib/media-filter-controller.ts | 25 +- src/components-lib/menu-button-controller.ts | 38 +- src/components-lib/ptz-controller.ts | 2 +- src/components-lib/timeline-source.ts | 7 +- src/components/live/live.ts | 18 +- src/components/surround.ts | 20 +- src/components/timeline-core.ts | 114 +- src/components/timeline.ts | 3 + src/config-mgmt.ts | 6 + src/config/types.ts | 23 +- src/const.ts | 5 +- src/editor.ts | 92 +- src/localize/languages/en.json | 25 +- src/localize/languages/it.json | 20 +- src/localize/languages/pt-BR.json | 20 +- src/localize/languages/pt-PT.json | 20 +- src/types.ts | 46 +- src/utils/media-to-view.ts | 17 +- src/utils/ptz.ts | 11 +- src/view/view-to-cameras.ts | 51 + tests/camera-manager/camera.test.ts | 4 +- tests/camera-manager/capabilities.test.ts | 118 ++ tests/camera-manager/frigate/camera.test.ts | 62 +- .../generic/engine-generic.test.ts | 16 +- tests/camera-manager/manager.test.ts | 101 +- tests/camera-manager/store.test.ts | 69 +- tests/camera-manager/utils.test.ts | 188 --- .../utils/camera-entity-from-config.test.ts | 23 + .../camera-manager/utils/cap-end-date.test.ts | 24 + .../utils/go2rtc-endpoint.test.ts | 41 + .../utils/range-to-cache-friendly.test.ts | 46 + tests/camera-manager/utils/sort-media.test.ts | 57 + tests/card-controller/view-manager.test.ts | 297 +++-- .../media-filter-controller.test.ts | 47 +- .../menu-button-controller.test.ts | 45 +- tests/components-lib/ptz-controller.test.ts | 12 +- tests/config-mgmt.test.ts | 1042 +++++++++-------- tests/config/types.test.ts | 1 - tests/test-utils.ts | 51 +- tests/utils/camera.test.ts | 2 +- tests/utils/endpoint.test.ts | 85 ++ tests/utils/media-to-view.test.ts | 23 +- tests/utils/ptz.test.ts | 12 +- tests/view/view-to-cameras.test.ts | 79 ++ vite.config.ts | 16 +- 63 files changed, 2308 insertions(+), 1447 deletions(-) create mode 100644 src/camera-manager/capabilities.ts delete mode 100644 src/camera-manager/utils.ts create mode 100644 src/camera-manager/utils/camera-entity-from-config.ts create mode 100644 src/camera-manager/utils/cap-end-date.ts create mode 100644 src/camera-manager/utils/go2rtc-endpoint.ts create mode 100644 src/camera-manager/utils/range-to-cache-friendly.ts create mode 100644 src/camera-manager/utils/sort-media.ts create mode 100644 src/view/view-to-cameras.ts create mode 100644 tests/camera-manager/capabilities.test.ts delete mode 100644 tests/camera-manager/utils.test.ts create mode 100644 tests/camera-manager/utils/camera-entity-from-config.test.ts create mode 100644 tests/camera-manager/utils/cap-end-date.test.ts create mode 100644 tests/camera-manager/utils/go2rtc-endpoint.test.ts create mode 100644 tests/camera-manager/utils/range-to-cache-friendly.test.ts create mode 100644 tests/camera-manager/utils/sort-media.test.ts create mode 100644 tests/utils/endpoint.test.ts create mode 100644 tests/view/view-to-cameras.test.ts diff --git a/README.md b/README.md index eed4af83..b38369f2 100644 --- a/README.md +++ b/README.md @@ -138,7 +138,6 @@ See the [fully expanded cameras configuration example](#config-expanded-cameras) | `live_provider` | `auto` | :white_check_mark: | The choice of live stream provider. See [Live Providers](#live-providers) below.| | `title` | Autodetected from `camera_entity` if that is specified. | :white_check_mark: | A friendly name for this camera to use in the card. | | `icon` | Autodetected from `camera_entity` if that is specified. | :white_check_mark: | The icon to use for this camera in the camera menu and in the next & previous controls when using the `icon` style. | -| `hide` | `false` | :white_check_mark: | Whether or not to hide this as an independent camera (e.g. hidden on the live carousel, media filter, camera menu, and triggers cannot trigger this camera). This may be useful if this camera is exclusively used as a dependency of another camera. | | `id` | `camera_entity`, `webrtc_card.entity` or `frigate.camera_name` if set (in that preference order). | :white_check_mark: | An optional identifier to use throughout the card configuration to refer unambiguously to this camera. See [camera IDs](#camera-ids). | | `engine` | `auto` | :white_check_mark: | Which camera engine to use for this camera. If `auto` the card will attempt to choose the correct engine from the specified options. See [engines](#engines) below for valid options.| | `frigate` | | :white_check_mark: | Options for a Frigate camera. See [Frigate configuration](#camera-frigate-configuration) below. | @@ -147,6 +146,7 @@ See the [fully expanded cameras configuration example](#config-expanded-cameras) | `webrtc_card` | | :white_check_mark: | The WebRTC entity/URL to use for this camera with the `webrtc-card` live provider. See below. | | `cast` | | :white_check_mark: | Configuration that controls how this camera is "casted" / sent to media players. See below. | | `dimensions` | | :white_check_mark: | Controls the dimensions and layout for media from this camera. See below. | +| `capabilities` | | :white_check_mark: | Allows selective disabling of camera capabilities. See below. | @@ -397,6 +397,35 @@ This block is used to control the fit and position of the media _within_ the cam See [media layout examples](#media-layout-examples). +### Camera Capabilities + +The `capabilities` block allows selected disabling of auto-detected camera capabilities. This is rarely used, with substreams being a notable exception. + +```yaml +cameras: + - capabilities: +``` + +| Option | Default | Overridable | Description | +| - | - | - | - | +| `disable` | | :white_check_mark: | A list of camera capabilities to disable. By default all capabilities supported by the camera are enabled. | +| `disable_except` | | :white_check_mark: | A list of camera capabilities to leave enabled if supported. Everything else will be disabled. | + +#### Capabilities + +| Capability | Purpose | +| - | - | +| `clips` | Clips can be fetched from the camera. | +| `favorite-events` | Events can be favorited. | +| `favorite-recordings` | Recordings can be favorited. | +| `live` | Live video can be received from the camera. | +| `menu` | The camera should show up in the card camera menu. | +| `ptz` | The camera can be PTZ controlled. | +| `recordings` | Recordings can be fetched from the camera. | +| `seek` | Clips can be seeked / scrubbed by the timeline. | +| `snapshots` | Snapshots can be fetched from the camera. | +| `substream` | The camera can be used as a substream on another camera. | + #### Camera IDs: Referring to cameras in card configuration @@ -1789,7 +1818,6 @@ cameras: - camera_entity: camera.front_Door live_provider: ha engine: auto - hide: false frigate: url: http://my.frigate.local client_id: frigate @@ -1832,8 +1860,6 @@ cameras: title: 'Front entrance' # Custom identifier for the camera to refer to it above. id: 'camera-2' - # Don't show this camera on the UI (will only be available as a dependent substream). - hide: true webrtc_card: entity: camera.entrance_rtsp url: 'rtsp://username:password@camera:554/av_stream/ch0' @@ -1905,7 +1931,6 @@ Reference: [Cameras Global Options](#camera-global-options). cameras_global: live_provider: ha engine: auto - hide: false frigate: url: http://my.frigate.local client_id: frigate @@ -2763,7 +2788,6 @@ overrides: - {} # No overrides for camera index 0. - live_provider: 'ha' # Overrides for camera index 1. engine: auto - hide: false frigate: url: http://my.frigate.local client_id: frigate @@ -3598,8 +3622,10 @@ cameras: title: Sitting Room HD live_provider: go2rtc id: sitting_room_hd - # Do not show the HD camera independently on the UI. - hide: true + # This camera serves only as a substream. + capabilities: + disable_except: + - substream menu: buttons: substreams: @@ -3625,13 +3651,17 @@ cameras: - camera_entity: camera.sitting_room live_provider: go2rtc id: sitting_room_go2rtc - hide: true + capabilities: + disable_except: + - substream title: Sitting Room go2rtc icon: mdi:alpha-g - camera_entity: camera.sitting_room live_provider: ha id: sitting_room_ha - hide: true + capabilities: + disable_except: + - substream title: Sitting Room HA icon: mdi:home ``` @@ -4151,7 +4181,9 @@ cameras: - camera.office_hd - camera_entity: camera.office_hd live_provider: go2rtc - hide: true + capabilities: + disable_except: + - substream automations: - actions: - action: custom:frigate-card-action diff --git a/src/camera-manager/browse-media/engine-browse-media.ts b/src/camera-manager/browse-media/engine-browse-media.ts index 74a4d9e1..d12d94f0 100644 --- a/src/camera-manager/browse-media/engine-browse-media.ts +++ b/src/camera-manager/browse-media/engine-browse-media.ts @@ -14,6 +14,7 @@ import { ResolvedMediaCache, resolveMedia } from '../../utils/ha/resolved-media' import { ViewMedia } from '../../view/media'; import { RequestCache } from '../cache'; import { Camera } from '../camera'; +import { Capabilities } from '../capabilities'; import { CameraManagerEngine } from '../engine'; import { GenericCameraManagerEngine } from '../generic/engine-generic'; import { rangesOverlap } from '../range'; @@ -142,15 +143,23 @@ export class BrowseMediaCameraManagerEngine cameraConfig: CameraConfig, ): Promise { const camera = new BrowseMediaCamera(cameraConfig, this, { - capabilities: { - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, - supportsClips: true, - supportsRecordings: false, - supportsSnapshots: true, - supportsTimeline: true, - }, + capabilities: new Capabilities( + { + 'favorite-events': false, + 'favorite-recordings': false, + clips: true, + live: true, + menu: true, + recordings: false, + seek: false, + snapshots: true, + substream: true, + }, + { + disable: cameraConfig.capabilities?.disable, + disableExcept: cameraConfig.capabilities?.disable_except, + }, + ), eventCallback: this._eventCallback, }); return await camera.initialize(hass, entityRegistryManager); diff --git a/src/camera-manager/camera.ts b/src/camera-manager/camera.ts index fd59026d..c1bf6b14 100644 --- a/src/camera-manager/camera.ts +++ b/src/camera-manager/camera.ts @@ -10,14 +10,15 @@ import { import { EntityRegistryManager } from '../utils/ha/entity-registry'; import { CameraManagerEngine } from './engine'; import { CameraNoIDError } from './error'; -import { CameraEventCallback, CameraManagerCameraCapabilities } from './types'; +import { CameraEventCallback } from './types'; +import { Capabilities } from './capabilities'; type DestroyCallback = () => Promise; export class Camera { protected _config: CameraConfig; protected _engine: CameraManagerEngine; - protected _capabilities?: CameraManagerCameraCapabilities; + protected _capabilities?: Capabilities; protected _eventCallback?: CameraEventCallback; protected _destroyCallbacks: DestroyCallback[] = []; @@ -25,7 +26,7 @@ export class Camera { config: CameraConfig, engine: CameraManagerEngine, options?: { - capabilities?: CameraManagerCameraCapabilities; + capabilities?: Capabilities; eventCallback?: CameraEventCallback; }, ) { @@ -97,7 +98,7 @@ export class Camera { return this._engine; } - public getCapabilities(): CameraManagerCameraCapabilities | null { + public getCapabilities(): Capabilities | null { return this._capabilities ?? null; } } diff --git a/src/camera-manager/capabilities.ts b/src/camera-manager/capabilities.ts new file mode 100644 index 00000000..29c79456 --- /dev/null +++ b/src/camera-manager/capabilities.ts @@ -0,0 +1,60 @@ +import { + CapabilitiesRaw, + CapabilityKey, + capabilityKeys, + PTZCapabilities, +} from '../types'; +import { CapabilitySearchOptions } from './types'; + +export class Capabilities { + private _capabilities: CapabilitiesRaw; + + constructor( + capabilities: CapabilitiesRaw, + options?: { + disable?: CapabilityKey[]; + disableExcept?: CapabilityKey[]; + }, + ) { + this._capabilities = capabilities; + + for (const key of options?.disable ?? []) { + this._disable(key); + } + for (const key of capabilityKeys) { + if (options?.disableExcept?.length && !options.disableExcept.includes(key)) { + this._disable(key); + } + } + } + + protected _disable(capability: CapabilityKey): void { + delete this._capabilities[capability]; + } + + public matches(capability: CapabilitySearchOptions): boolean { + let result = true; + if (typeof capability === 'string') { + result &&= this.has(capability); + } + if (typeof capability === 'object' && capability.allCapabilities) { + result &&= capability.allCapabilities.every((capability) => this.has(capability)); + } + if (typeof capability === 'object' && capability.anyCapabilities) { + result &&= capability.anyCapabilities.some((capability) => this.has(capability)); + } + return result; + } + + public has(capability: CapabilityKey): boolean { + return !!this._capabilities[capability]; + } + + public getPTZCapabilities(): PTZCapabilities | null { + return this._capabilities.ptz ?? null; + } + + public getRawCapabilities(): CapabilitiesRaw { + return this._capabilities; + } +} diff --git a/src/camera-manager/engine-factory.ts b/src/camera-manager/engine-factory.ts index 397f390f..39b7384c 100644 --- a/src/camera-manager/engine-factory.ts +++ b/src/camera-manager/engine-factory.ts @@ -10,7 +10,7 @@ import { MemoryRequestCache, RecordingSegmentsCache, RequestCache } from './cach import { CameraManagerEngine } from './engine'; import { CameraInitializationError } from './error'; import { CameraEventCallback, Engine } from './types'; -import { getCameraEntityFromConfig } from './utils'; +import { getCameraEntityFromConfig } from './utils/camera-entity-from-config'; export class CameraManagerEngineFactory { protected _entityRegistryManager: EntityRegistryManager; @@ -24,7 +24,10 @@ export class CameraManagerEngineFactory { this._resolvedMediaCache = resolvedMediaCache; } - public async createEngine(engine: Engine, eventCallback?: CameraEventCallback): Promise { + public async createEngine( + engine: Engine, + eventCallback?: CameraEventCallback, + ): Promise { let cameraManagerEngine: CameraManagerEngine; switch (engine) { case Engine.Generic: diff --git a/src/camera-manager/frigate/camera.ts b/src/camera-manager/frigate/camera.ts index 50a62cca..fdef3229 100644 --- a/src/camera-manager/frigate/camera.ts +++ b/src/camera-manager/frigate/camera.ts @@ -2,14 +2,15 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import uniq from 'lodash-es/uniq'; import { CameraConfig } from '../../config/types'; import { localize } from '../../localize/localize'; +import { PTZCapabilities, PTZMovementType } from '../../types'; import { errorToConsole } from '../../utils/basic'; import { subscribeToTrigger } from '../../utils/ha'; import { EntityRegistryManager } from '../../utils/ha/entity-registry'; import { Entity } from '../../utils/ha/entity-registry/types'; import { Camera } from '../camera'; +import { Capabilities } from '../capabilities'; import { CameraInitializationError } from '../error'; -import { PTZCapabilities, PTZMovementType } from '../types'; -import { getCameraEntityFromConfig } from '../utils.js'; +import { getCameraEntityFromConfig } from '../utils/camera-entity-from-config'; import { getPTZInfo } from './requests'; import { PTZInfo, frigateEventChangeTriggerResponseSchema } from './types'; @@ -98,16 +99,24 @@ export class FrigateCamera extends Camera { const config = this.getConfig(); const ptz = await this._getPTZCapabilities(hass, config); const birdseye = isBirdseye(config); - this._capabilities = { - canFavoriteEvents: !birdseye, - canFavoriteRecordings: !birdseye, - canSeek: true, - supportsClips: !birdseye, - supportsSnapshots: !birdseye, - supportsRecordings: !birdseye, - supportsTimeline: !birdseye, - ...(ptz && { ptz: ptz }), - }; + this._capabilities = new Capabilities( + { + 'favorite-events': !birdseye, + 'favorite-recordings': false, + seek: !birdseye, + clips: !birdseye, + snapshots: !birdseye, + recordings: !birdseye, + live: true, + menu: true, + substream: true, + ...(ptz && { ptz: ptz }), + }, + { + disable: config.capabilities?.disable, + disableExcept: config.capabilities?.disable_except, + }, + ); } protected _getFrigateCameraNameFromEntity(entity: Entity): string | null { diff --git a/src/camera-manager/frigate/engine-frigate.ts b/src/camera-manager/frigate/engine-frigate.ts index ea44df50..0a9da710 100644 --- a/src/camera-manager/frigate/engine-frigate.ts +++ b/src/camera-manager/frigate/engine-frigate.ts @@ -23,8 +23,8 @@ import { ViewMediaClassifier } from '../../view/media-classifier'; import { RecordingSegmentsCache, RequestCache } from '../cache'; import { Camera } from '../camera'; import { - CameraManagerEngine, CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT, + CameraManagerEngine, } from '../engine'; import { GenericCameraManagerEngine } from '../generic/engine-generic'; import { DateRange } from '../range'; @@ -59,18 +59,18 @@ import { RecordingSegmentsQuery, RecordingSegmentsQueryResultsMap, } from '../types'; -import { getDefaultGo2RTCEndpoint } from '../utils.js'; +import { getDefaultGo2RTCEndpoint } from '../utils/go2rtc-endpoint'; import frigateLogo from './assets/frigate-logo-dark.svg'; import { FrigateCamera, isBirdseye } from './camera'; import { FrigateViewMediaFactory } from './media'; import { FrigateViewMediaClassifier } from './media-classifier'; import { - getEvents, - getEventSummary, - getRecordingSegments, - getRecordingsSummary, NativeFrigateEventQuery, NativeFrigateRecordingSegmentsQuery, + getEventSummary, + getEvents, + getRecordingSegments, + getRecordingsSummary, retainEvent, } from './requests'; import { diff --git a/src/camera-manager/generic/engine-generic.ts b/src/camera-manager/generic/engine-generic.ts index 195ebedf..971aec8b 100644 --- a/src/camera-manager/generic/engine-generic.ts +++ b/src/camera-manager/generic/engine-generic.ts @@ -7,6 +7,7 @@ import { getEntityIcon, getEntityTitle } from '../../utils/ha'; import { EntityRegistryManager } from '../../utils/ha/entity-registry'; import { ViewMedia } from '../../view/media'; import { Camera } from '../camera'; +import { Capabilities } from '../capabilities'; import { CameraManagerEngine } from '../engine'; import { CameraManagerReadOnlyConfigStore } from '../store'; import { @@ -32,7 +33,8 @@ import { RecordingSegmentsQuery, RecordingSegmentsQueryResultsMap, } from '../types'; -import { getCameraEntityFromConfig, getDefaultGo2RTCEndpoint } from '../utils.js'; +import { getCameraEntityFromConfig } from '../utils/camera-entity-from-config'; +import { getDefaultGo2RTCEndpoint } from '../utils/go2rtc-endpoint'; export class GenericCameraManagerEngine implements CameraManagerEngine { protected _eventCallback?: CameraEventCallback; @@ -51,15 +53,23 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { cameraConfig: CameraConfig, ): Promise { return await new Camera(cameraConfig, this, { - capabilities: { - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, - supportsClips: false, - supportsRecordings: false, - supportsSnapshots: false, - supportsTimeline: false, - }, + capabilities: new Capabilities( + { + 'favorite-events': false, + 'favorite-recordings': false, + clips: false, + live: true, + menu: true, + recordings: false, + seek: false, + snapshots: false, + substream: true, + }, + { + disable: cameraConfig.capabilities?.disable, + disableExcept: cameraConfig.capabilities?.disable_except, + }, + ), eventCallback: this._eventCallback, }).initialize(hass, entityRegistryManager); } diff --git a/src/camera-manager/manager.ts b/src/camera-manager/manager.ts index 82960b0f..7f3968a6 100644 --- a/src/camera-manager/manager.ts +++ b/src/camera-manager/manager.ts @@ -8,12 +8,14 @@ import { localize } from '../localize/localize.js'; import { allPromises, arrayify, + isTruthy, recursivelyMergeObjectsNotArrays, setify, } from '../utils/basic.js'; import { getCameraID } from '../utils/camera.js'; import { log } from '../utils/debug.js'; import { ViewMedia } from '../view/media.js'; +import { Capabilities } from './capabilities.js'; import { CameraManagerEngineFactory } from './engine-factory.js'; import { CameraManagerEngine } from './engine.js'; import { CameraInitializationError } from './error.js'; @@ -22,9 +24,7 @@ import { CameraEndpoint, CameraEndpoints, CameraEndpointsContext, - CameraManagerCameraCapabilities, CameraManagerCameraMetadata, - CameraManagerCapabilities, CameraManagerMediaCapabilities, DataQuery, Engine, @@ -53,7 +53,7 @@ import { RecordingSegmentsQueryResultsMap, ResultsMap, } from './types.js'; -import { sortMedia } from './utils.js'; +import { sortMedia } from './utils/sort-media.js'; export class QueryClassifier { public static isEventQuery(query: DataQuery | PartialDataQuery): query is EventQuery { @@ -260,10 +260,6 @@ export class CameraManager { this._store.addCamera(camera); }); - if (!this._store.getVisibleCameraCount()) { - throw new CameraInitializationError(localize('error.no_visible_cameras')); - } - log( this._api.getConfigManager().getCardWideConfig(), 'Frigate Card CameraManager initialized (Cameras: ', @@ -739,33 +735,29 @@ export class CameraManager { return engine.getCameraMetadata(hass, cameraConfig); } - public getCameraCapabilities( - cameraID: string, - ): CameraManagerCameraCapabilities | null { + public getCameraCapabilities(cameraID: string): Capabilities | null { return this._store.getCamera(cameraID)?.getCapabilities() ?? null; } - public getAggregateCameraCapabilities( - cameraIDs?: Set, - ): CameraManagerCapabilities | null { - const perCameraCapabilities = [...(cameraIDs ?? this._store.getCameraIDs())].map( - (cameraID) => this.getCameraCapabilities(cameraID), - ); + public getAggregateCameraCapabilities(cameraIDs?: Set): Capabilities { + const cameras = [...(cameraIDs ?? this._store.getCameraIDs())] + .map((cameraID) => this._store.getCamera(cameraID)) + .filter(isTruthy); - return { - canFavoriteEvents: perCameraCapabilities.some((cap) => cap?.canFavoriteEvents), - canFavoriteRecordings: perCameraCapabilities.some( - (cap) => cap?.canFavoriteRecordings, + return new Capabilities({ + live: cameras.some((camera) => camera.getCapabilities()?.has('live')), + clips: cameras.some((camera) => camera.getCapabilities()?.has('clips')), + recordings: cameras.some((camera) => camera.getCapabilities()?.has('recordings')), + snapshots: cameras.some((camera) => camera.getCapabilities()?.has('snapshots')), + 'favorite-events': cameras.some((camera) => + camera.getCapabilities()?.has('favorite-events'), ), - canSeek: perCameraCapabilities.some((cap) => cap?.canSeek), - - supportsClips: perCameraCapabilities.some((cap) => cap?.supportsClips), - supportsRecordings: perCameraCapabilities.some((cap) => cap?.supportsRecordings), - supportsSnapshots: perCameraCapabilities.some((cap) => cap?.supportsSnapshots), - supportsTimeline: perCameraCapabilities.some((cap) => cap?.supportsTimeline), - - supportsPTZ: perCameraCapabilities.some((cap) => !!cap?.ptz), - }; + 'favorite-recordings': cameras.some((camera) => + camera.getCapabilities()?.has('favorite-recordings'), + ), + seek: cameras.some((camera) => camera.getCapabilities()?.has('seek')), + menu: cameras.some((camera) => camera.getCapabilities()?.has('menu')), + }); } public async executePTZAction( diff --git a/src/camera-manager/store.ts b/src/camera-manager/store.ts index 1f5d2846..1cc58742 100644 --- a/src/camera-manager/store.ts +++ b/src/camera-manager/store.ts @@ -1,9 +1,10 @@ import { CameraConfig } from '../config/types'; +import { CapabilityKey } from '../types'; import { allPromises } from '../utils/basic'; import { ViewMedia } from '../view/media'; import { Camera } from './camera'; import { CameraManagerEngine } from './engine'; -import { Engine } from './types'; +import { CapabilitySearchOptions, Engine } from './types'; type CameraManagerEngineCameraIDMap = Map>; @@ -14,8 +15,8 @@ export interface CameraManagerReadOnlyConfigStore { hasCameraID(cameraID: string): boolean; getCamera(cameraID: string): Camera | null; + getCameras(): Map; getCameraCount(): number; - getVisibleCameraCount(): number; getCameraConfigs(cameraIDs?: Iterable): IterableIterator; getCameraConfigEntries( @@ -23,10 +24,15 @@ export interface CameraManagerReadOnlyConfigStore { ): IterableIterator<[string, CameraConfig]>; getCameraIDs(): Set; - getVisibleCameraIDs(): Set; getDefaultCameraID(): string | null; - getAllDependentCameras(cameraID: string): Set; + getCameraIDsWithCapability( + capability: CapabilityKey | CapabilitySearchOptions, + ): Set; + getAllDependentCameras( + cameraID: string, + capability?: CapabilityKey | CapabilitySearchOptions, + ): Set; } export class CameraManagerStore implements CameraManagerReadOnlyConfigStore { @@ -47,6 +53,9 @@ export class CameraManagerStore implements CameraManagerReadOnlyConfigStore { public getCamera(cameraID: string): Camera | null { return this._cameras.get(cameraID) ?? null; } + public getCameras(): Map { + return this._cameras; + } public getCameraConfig(cameraID: string): CameraConfig | null { return this._cameras.get(cameraID)?.getConfig() ?? null; } @@ -58,18 +67,11 @@ export class CameraManagerStore implements CameraManagerReadOnlyConfigStore { public getCameraCount(): number { return this._cameras.size; } - public getVisibleCameraCount(): number { - return this.getVisibleCameraIDs().size; - } public getDefaultCameraID(): string | null { return this._cameras.keys().next().value ?? null; } - public getCameras(): Map { - return this._cameras; - } - public *getCameraConfigs( cameraIDs?: Iterable, ): IterableIterator { @@ -93,8 +95,17 @@ export class CameraManagerStore implements CameraManagerReadOnlyConfigStore { public getCameraIDs(): Set { return new Set(this._cameras.keys()); } - public getVisibleCameraIDs(): Set { - return this._getMatchingCameraIDs((camera) => !camera.getConfig().hide); + + public getCameraIDsWithCapability( + capability: CapabilityKey | CapabilitySearchOptions, + ): Set { + const output: Set = new Set(); + for (const camera of this._cameras.values()) { + if (camera.getCapabilities()?.matches(capability)) { + output.add(camera.getID()); + } + } + return output; } public getCameraConfigForMedia(media: ViewMedia): CameraConfig | null { @@ -138,35 +149,35 @@ export class CameraManagerStore implements CameraManagerReadOnlyConfigStore { * @returns A set of dependent cameraIDs or null (since JS sets guarantee order, * the first item in the set is guaranteed to be the cameraID itself). */ - public getAllDependentCameras(cameraID: string): Set { - const cameraIDs: Set = new Set(); + public getAllDependentCameras( + cameraID: string, + capability?: CapabilitySearchOptions, + ): Set { + const visitedCameraIDs = new Set(); + const matchingCameraIDs: Set = new Set(); const getDependentCameras = (cameraID: string): void => { - const cameraConfig = this.getCameraConfig(cameraID); - if (cameraConfig) { - cameraIDs.add(cameraID); + visitedCameraIDs.add(cameraID); + + const camera = this.getCamera(cameraID); + const cameraConfig = camera?.getConfig(); + + if (camera && cameraConfig) { + if (!capability || camera.getCapabilities()?.matches(capability)) { + matchingCameraIDs.add(cameraID); + } const dependentCameras: Set = new Set(); cameraConfig.dependencies.cameras.forEach((item) => dependentCameras.add(item)); if (cameraConfig.dependencies.all_cameras) { this.getCameraIDs().forEach((cameraID) => dependentCameras.add(cameraID)); } - for (const eventCameraID of dependentCameras) { - if (!cameraIDs.has(eventCameraID)) { - getDependentCameras(eventCameraID); + for (const dependentCameraID of dependentCameras) { + if (!visitedCameraIDs.has(dependentCameraID)) { + getDependentCameras(dependentCameraID); } } } }; getDependentCameras(cameraID); - return cameraIDs; - } - - protected _getMatchingCameraIDs(func: (camera: Camera) => boolean): Set { - const output = new Set(); - for (const [cameraID, camera] of this._cameras.entries()) { - if (func(camera)) { - output.add(cameraID); - } - } - return output; + return matchingCameraIDs; } } diff --git a/src/camera-manager/types.ts b/src/camera-manager/types.ts index 76d0f7bc..8a26450c 100644 --- a/src/camera-manager/types.ts +++ b/src/camera-manager/types.ts @@ -1,3 +1,4 @@ +import { CapabilityKey } from '../types'; import { FrigateCardView } from '../config/types'; import { ViewMedia } from '../view/media'; @@ -91,32 +92,11 @@ export interface MediaMetadata { what?: Set; } -export type PTZMovementType = 'relative' | 'continuous'; - -export interface PTZCapabilities { - panTilt?: PTZMovementType[]; - zoom?: PTZMovementType[]; - presets?: string[]; -} - -interface BaseCapabilities { - canFavoriteEvents: boolean; - canFavoriteRecordings: boolean; - canSeek: boolean; - - supportsClips: boolean; - supportsRecordings: boolean; - supportsSnapshots: boolean; - supportsTimeline: boolean; -} - -export interface CameraManagerCapabilities extends BaseCapabilities { - supportsPTZ: boolean; -} - -export interface CameraManagerCameraCapabilities extends BaseCapabilities { - ptz?: PTZCapabilities; +interface CapabilitySearchAllAny { + allCapabilities?: CapabilityKey[]; + anyCapabilities?: CapabilityKey[]; } +export type CapabilitySearchOptions = CapabilityKey | CapabilitySearchAllAny; export interface CameraManagerMediaCapabilities { canFavorite: boolean; diff --git a/src/camera-manager/utils.ts b/src/camera-manager/utils.ts deleted file mode 100644 index 89c9b2e7..00000000 --- a/src/camera-manager/utils.ts +++ /dev/null @@ -1,84 +0,0 @@ -import endOfDay from 'date-fns/endOfDay'; -import endOfHour from 'date-fns/endOfHour'; -import endOfMinute from 'date-fns/endOfMinute'; -import startOfDay from 'date-fns/startOfDay'; -import startOfHour from 'date-fns/startOfHour'; -import orderBy from 'lodash-es/orderBy'; -import uniqBy from 'lodash-es/uniqBy'; -import { CameraConfig } from '../config/types'; -import { ViewMedia } from '../view/media'; -import { DateRange } from './range'; -import { CameraEndpoint } from './types'; - -export const convertRangeToCacheFriendlyTimes = ( - range: DateRange, - options?: { - endCap?: boolean; - }, -): DateRange => { - const widthSeconds = (range.end.getTime() - range.start.getTime()) / 1000; - let cacheableStart: Date; - let cacheableEnd: Date; - - if (widthSeconds <= 60 * 60) { - cacheableStart = startOfHour(range.start); - cacheableEnd = endOfHour(range.end); - } else { - cacheableStart = startOfDay(range.start); - cacheableEnd = endOfDay(range.end); - } - - if (options?.endCap) { - cacheableEnd = endOfMinute(capEndDate(cacheableEnd)); - } - - return { - start: cacheableStart, - end: cacheableEnd, - }; -}; - -export const capEndDate = (end: Date): Date => { - const now = new Date(); - return end > now ? now : end; -}; - -export const sortMedia = (mediaArray: ViewMedia[]): ViewMedia[] => { - return orderBy( - // Ensure uniqueness by the ID (if specified), otherwise all elements - // are assumed to be unique. - uniqBy(mediaArray, (media) => media.getID() ?? media), - - // Sort all items leading oldest -> youngest (so media is loaded in this - // order in the viewer which matches the left-to-right timeline order). - (media) => media.getStartTime() ?? media.getID(), - 'asc', - ); -}; - -export const getCameraEntityFromConfig = (cameraConfig: CameraConfig): string | null => { - return cameraConfig.camera_entity ?? cameraConfig.webrtc_card?.entity ?? null; -}; - -export const getDefaultGo2RTCEndpoint = ( - cameraConfig: CameraConfig, - options?: { - url?: string; - stream?: string; - }, -): CameraEndpoint | null => { - const url = options?.url ?? cameraConfig.go2rtc?.url; - const stream = options?.stream ?? cameraConfig.go2rtc?.stream; - - if (!url || !stream) { - return null; - } - const endpoint = `${url}/api/ws?src=${stream}`; - - return { - endpoint: endpoint, - - // Only sign the endpoint if it's local to HA. - sign: endpoint.startsWith('/'), - }; -}; diff --git a/src/camera-manager/utils/camera-entity-from-config.ts b/src/camera-manager/utils/camera-entity-from-config.ts new file mode 100644 index 00000000..4319b467 --- /dev/null +++ b/src/camera-manager/utils/camera-entity-from-config.ts @@ -0,0 +1,5 @@ +import { CameraConfig } from '../../config/types'; + +export const getCameraEntityFromConfig = (cameraConfig: CameraConfig): string | null => { + return cameraConfig.camera_entity ?? cameraConfig.webrtc_card?.entity ?? null; +}; diff --git a/src/camera-manager/utils/cap-end-date.ts b/src/camera-manager/utils/cap-end-date.ts new file mode 100644 index 00000000..3634b29f --- /dev/null +++ b/src/camera-manager/utils/cap-end-date.ts @@ -0,0 +1,4 @@ +export const capEndDate = (end: Date): Date => { + const now = new Date(); + return end > now ? now : end; +}; diff --git a/src/camera-manager/utils/go2rtc-endpoint.ts b/src/camera-manager/utils/go2rtc-endpoint.ts new file mode 100644 index 00000000..398211b4 --- /dev/null +++ b/src/camera-manager/utils/go2rtc-endpoint.ts @@ -0,0 +1,25 @@ +import { CameraConfig } from '../../config/types'; +import { CameraEndpoint } from '../types'; + +export const getDefaultGo2RTCEndpoint = ( + cameraConfig: CameraConfig, + options?: { + url?: string; + stream?: string; + }, +): CameraEndpoint | null => { + const url = options?.url ?? cameraConfig.go2rtc?.url; + const stream = options?.stream ?? cameraConfig.go2rtc?.stream; + + if (!url || !stream) { + return null; + } + const endpoint = `${url}/api/ws?src=${stream}`; + + return { + endpoint: endpoint, + + // Only sign the endpoint if it's local to HA. + sign: endpoint.startsWith('/'), + }; +}; diff --git a/src/camera-manager/utils/range-to-cache-friendly.ts b/src/camera-manager/utils/range-to-cache-friendly.ts new file mode 100644 index 00000000..0b8464bd --- /dev/null +++ b/src/camera-manager/utils/range-to-cache-friendly.ts @@ -0,0 +1,35 @@ +import endOfDay from 'date-fns/endOfDay'; +import endOfHour from 'date-fns/endOfHour'; +import endOfMinute from 'date-fns/endOfMinute'; +import startOfDay from 'date-fns/startOfDay'; +import startOfHour from 'date-fns/startOfHour'; +import { DateRange } from '../range'; +import { capEndDate } from './cap-end-date'; + +export const convertRangeToCacheFriendlyTimes = ( + range: DateRange, + options?: { + endCap?: boolean; + }, +): DateRange => { + const widthSeconds = (range.end.getTime() - range.start.getTime()) / 1000; + let cacheableStart: Date; + let cacheableEnd: Date; + + if (widthSeconds <= 60 * 60) { + cacheableStart = startOfHour(range.start); + cacheableEnd = endOfHour(range.end); + } else { + cacheableStart = startOfDay(range.start); + cacheableEnd = endOfDay(range.end); + } + + if (options?.endCap) { + cacheableEnd = endOfMinute(capEndDate(cacheableEnd)); + } + + return { + start: cacheableStart, + end: cacheableEnd, + }; +}; diff --git a/src/camera-manager/utils/sort-media.ts b/src/camera-manager/utils/sort-media.ts new file mode 100644 index 00000000..9f503330 --- /dev/null +++ b/src/camera-manager/utils/sort-media.ts @@ -0,0 +1,16 @@ +import orderBy from 'lodash-es/orderBy'; +import uniqBy from 'lodash-es/uniqBy'; +import { ViewMedia } from '../../view/media'; + +export const sortMedia = (mediaArray: ViewMedia[]): ViewMedia[] => { + return orderBy( + // Ensure uniqueness by the ID (if specified), otherwise all elements + // are assumed to be unique. + uniqBy(mediaArray, (media) => media.getID() ?? media), + + // Sort all items leading oldest -> youngest (so media is loaded in this + // order in the viewer which matches the left-to-right timeline order). + (media) => media.getStartTime() ?? media.getID(), + 'asc', + ); +}; diff --git a/src/card-controller/view-manager.ts b/src/card-controller/view-manager.ts index 463e626f..2570fed9 100644 --- a/src/card-controller/view-manager.ts +++ b/src/card-controller/view-manager.ts @@ -1,3 +1,4 @@ +import isEqual from 'lodash-es/isEqual'; import { ViewContext } from 'view'; import { FRIGATE_CARD_VIEW_DEFAULT, @@ -5,18 +6,21 @@ import { FrigateCardView, ViewDisplayMode, } from '../config/types'; +import { localize } from '../localize/localize'; import { log } from '../utils/debug'; import { executeMediaQueryForView } from '../utils/media-to-view'; import { View } from '../view/view'; +import { getCameraIDsForViewName } from '../view/view-to-cameras'; import { CardViewAPI } from './types'; interface ViewManagerSetViewDefaultParameters { cameraID?: string; substream?: string; - // When failSafe is true, the view will be changed to an "always-works" view - // (e.g. `live`) if the proposed view is unsupported. By default the view will - // just not be changed. + // When failSafe is true, the view will be changed to the default view, or the + // `live` view if the default view is not supported, or failing that an error + // message is shown. Without `failSafe` the view will just not be changed if + // unsupported. failSafe?: boolean; } @@ -49,9 +53,11 @@ export class ViewManager { const config = this._api.getConfigManager().getConfig(); if (config) { let forceCameraID: string | null = params?.cameraID ?? null; + const viewName = config.view.default; + if (!forceCameraID && this._view?.camera && config.view.update_cycle_camera) { const cameraIDs = [ - ...this._api.getCameraManager().getStore().getVisibleCameraIDs(), + ...getCameraIDsForViewName(this._api.getCameraManager(), viewName), ]; const currentIndex = cameraIDs.indexOf(this._view.camera); const targetIndex = currentIndex + 1 >= cameraIDs.length ? 0 : currentIndex + 1; @@ -60,7 +66,7 @@ export class ViewManager { this.setViewByParameters({ ...params, - viewName: config.view.default, + viewName: viewName, ...(forceCameraID && { cameraID: forceCameraID }), }); @@ -76,38 +82,82 @@ export class ViewManager { if (config) { let cameraID: string | null = null; - const cameras = this._api.getCameraManager().getStore().getVisibleCameraIDs(); - if (cameras.size) { - if (params?.cameraID && cameras.has(params.cameraID)) { - cameraID = params.cameraID; - } else { - // Reset to the default camera. - cameraID = cameras.keys().next().value; - } - } let viewName = params?.viewName ?? this._view?.view ?? config.view.default; - if (cameraID && viewName) { - if (!this.isViewSupportedByCamera(cameraID, viewName)) { - if (params.failSafe) { + const allCameraIDs = this._api.getCameraManager().getStore().getCameraIDs(); + if (params?.cameraID && allCameraIDs.has(params.cameraID)) { + cameraID = params.cameraID; + } else { + const viewCameraIDs = getCameraIDsForViewName( + this._api.getCameraManager(), + viewName, + ); + + // Reset to the default camera. + cameraID = viewCameraIDs.keys().next().value; + } + + if (!cameraID) { + if (params.failSafe) { + const camerasToCapabilities = [ + ...this._api.getCameraManager().getStore().getCameras(), + ].reduce((acc, [cameraID, camera]) => { + const capabilities = camera.getCapabilities()?.getRawCapabilities(); + if (capabilities) { + acc[cameraID] = capabilities; + } + return acc; + }, {}); + + this._api.getMessageManager().setMessageIfHigherPriority({ + type: 'error', + message: localize('error.no_supported_cameras'), + context: { + view: viewName, + cameras_capabilities: camerasToCapabilities, + }, + }); + } + return; + } + + if (!this.isViewSupportedByCamera(cameraID, viewName)) { + if (params.failSafe) { + if (this.isViewSupportedByCamera(cameraID, FRIGATE_CARD_VIEW_DEFAULT)) { viewName = FRIGATE_CARD_VIEW_DEFAULT; } else { + const capabilities = this._api + .getCameraManager() + .getStore() + .getCamera(cameraID) + ?.getCapabilities() + ?.getRawCapabilities(); + this._api.getMessageManager().setMessageIfHigherPriority({ + type: 'error', + message: localize('error.no_supported_camera'), + context: { + view: viewName, + camera: cameraID, + ...(capabilities && { camera_capabilities: capabilities }), + }, + }); return; } + } else { + return; } - - const displayMode = - this._view?.displayMode ?? - this._getDefaultDisplayModeForView(viewName, config); - let view: View = new View({ - view: viewName, - camera: cameraID, - displayMode: displayMode, - }); - if (params.substream) { - view = this._createViewWithSelectedSubstream(view, params.substream); - } - this._setView(view); } + + const displayMode = + this._view?.displayMode ?? this._getDefaultDisplayModeForView(viewName, config); + let view: View = new View({ + view: viewName, + camera: cameraID, + displayMode: displayMode, + }); + if (params.substream) { + view = this._createViewWithSelectedSubstream(view, params.substream); + } + this._setView(view); } } @@ -121,6 +171,12 @@ export class ViewManager { this._view = null; } + protected _getCameraIDsInvolvedInView(view: View): Set { + return view.supportsMultipleDisplayModes() && view.isGrid() + ? getCameraIDsForViewName(this._api.getCameraManager(), view.view) + : getCameraIDsForViewName(this._api.getCameraManager(), view.view, view.camera); + } + public async setViewWithNewDisplayMode(displayMode: ViewDisplayMode): Promise { const hass = this._api.getHASSManager().getHASS(); @@ -129,18 +185,10 @@ export class ViewManager { displayMode: displayMode, }); - const cameraCount = this._api - .getCameraManager() - .getStore() - .getVisibleCameraCount(); - const queryCameraCount = view.query?.getQueryCameraIDs()?.size ?? 0; - const generateNewQuery = - view?.query && - queryCameraCount && - ((view.isGrid() && queryCameraCount < cameraCount) || - (!view.isGrid() && queryCameraCount > 1)); + const expectedCameraIDs = this._getCameraIDsInvolvedInView(view); + const queryCameraIDs = view.query?.getQueryCameraIDs(); - if (generateNewQuery && view && view.query) { + if (!isEqual(expectedCameraIDs, queryCameraIDs) && view && view.query) { // If the user requests a grid but the current query does not have a // query for more than one camera, reset the query results, change the // existing query to refer to all cameras and execute it to fetch new @@ -150,13 +198,7 @@ export class ViewManager { viewWithNewQuery = await executeMediaQueryForView( this._api.getCameraManager(), view, - view.query - .clone() - .setQueryCameraIDs( - view.isGrid() - ? this._api.getCameraManager().getStore().getVisibleCameraIDs() - : view.camera, - ), + view.query.clone().setQueryCameraIDs(expectedCameraIDs), ); } catch (e: unknown) { this._api.getMessageManager().setErrorIfHigherPriority(e); @@ -190,42 +232,7 @@ export class ViewManager { } public isViewSupportedByCamera(cameraID: string, view: FrigateCardView): boolean { - const dependentCamerasCapabilities = this._api - .getCameraManager() - .getAggregateCameraCapabilities( - this._api.getCameraManager().getStore().getAllDependentCameras(cameraID), - ); - const allCamerasCapabilities = this._api - .getCameraManager() - .getAggregateCameraCapabilities( - this._api.getCameraManager().getStore().getCameraIDs(), - ); - - switch (view) { - case 'live': - case 'image': - case 'diagnostics': - return true; - case 'clip': - case 'clips': - return !!dependentCamerasCapabilities?.supportsClips; - case 'snapshot': - case 'snapshots': - return !!dependentCamerasCapabilities?.supportsSnapshots; - case 'recording': - case 'recordings': - return !!dependentCamerasCapabilities?.supportsRecordings; - case 'timeline': - // Show the timeline if any camera supports it, even cameras unrelated - // to the currently selected camera. - return !!allCamerasCapabilities?.supportsTimeline; - case 'media': - return ( - !!dependentCamerasCapabilities?.supportsClips || - !!dependentCamerasCapabilities?.supportsSnapshots || - !!dependentCamerasCapabilities?.supportsRecordings - ); - } + return !!getCameraIDsForViewName(this._api.getCameraManager(), view, cameraID).size; } protected _getDefaultDisplayModeForView( diff --git a/src/components-lib/media-filter-controller.ts b/src/components-lib/media-filter-controller.ts index ef5bfbd2..bfb68e15 100644 --- a/src/components-lib/media-filter-controller.ts +++ b/src/components-lib/media-filter-controller.ts @@ -182,11 +182,11 @@ export class MediaFilterController { return null; }; - const visibleCameraIDs = cameraManager.getStore().getVisibleCameraIDs(); - if (!visibleCameraIDs.size || !values.mediaType) { + const cameraIDs = + getArrayValueAsSet(values.camera) ?? this._getAllCameraIDs(cameraManager); + if (!cameraIDs.size || !values.mediaType) { return; } - const cameraIDs = getArrayValueAsSet(values.camera) ?? visibleCameraIDs; const when = this._getWhen(values.when); const favorite = values.favorite @@ -280,10 +280,16 @@ export class MediaFilterController { this._host.requestUpdate(); } + protected _getAllCameraIDs(cameraManager: CameraManager): Set { + return cameraManager.getStore().getCameraIDsWithCapability({ + anyCapabilities: ['clips', 'snapshots', 'recordings'], + }); + } + public computeInitialDefaultsFromView(cameraManager: CameraManager, view: View): void { const queries = view.query?.getQueries(); - const visibleCameraIDs = cameraManager.getStore().getVisibleCameraIDs(); - if (!queries || !visibleCameraIDs.size) { + const allCameraIDs = this._getAllCameraIDs(cameraManager); + if (!queries || !allCameraIDs.size) { return; } @@ -300,7 +306,7 @@ export class MediaFilterController { ); // Special note: If all visible cameras are selected, this is the same as no // selector at all. - if (cameraIDSets.length === 1 && !isEqual(queries[0].cameraIDs, visibleCameraIDs)) { + if (cameraIDSets.length === 1 && !isEqual(queries[0].cameraIDs, allCameraIDs)) { cameraIDs = [...queries[0].cameraIDs]; } @@ -375,8 +381,7 @@ export class MediaFilterController { } public computeCameraOptions(cameraManager: CameraManager): void { - const cameras = cameraManager.getStore().getVisibleCameraIDs(); - this._cameraOptions = [...cameras].map((cameraID) => ({ + this._cameraOptions = [...this._getAllCameraIDs(cameraManager)].map((cameraID) => ({ value: cameraID, label: cameraManager.getCameraMetadata(cameraID)?.title ?? cameraID, })); @@ -451,9 +456,9 @@ export class MediaFilterController { events: events, recordings: recordings, favorites: events - ? !!managerCapabilities?.canFavoriteEvents + ? managerCapabilities?.has('favorite-events') : recordings - ? !!managerCapabilities?.canFavoriteRecordings + ? managerCapabilities?.has('favorite-recordings') : false, }; } diff --git a/src/components-lib/menu-button-controller.ts b/src/components-lib/menu-button-controller.ts index cfe3c385..6d0a7f73 100644 --- a/src/components-lib/menu-button-controller.ts +++ b/src/components-lib/menu-button-controller.ts @@ -24,6 +24,7 @@ import { getEntityIcon, getEntityTitle } from '../utils/ha'; import { hasUsablePTZ } from '../utils/ptz'; import { hasSubstream } from '../utils/substream'; import { View } from '../view/view'; +import { getCameraIDsForViewName } from '../view/view-to-cameras'; export interface MenuButtonControllerOptions { currentMediaLoadedInfo?: MediaLoadedInfo | null; @@ -62,16 +63,12 @@ export class MenuButtonController { view: View, options?: MenuButtonControllerOptions, ): MenuItem[] { - const visibleCameraIDs = cameraManager.getStore().getVisibleCameraIDs(); const selectedCameraID = view.camera; const substreamAwareCameraID = view.context?.live?.overrides?.get(selectedCameraID) ?? selectedCameraID; const selectedCameraConfig = cameraManager .getStore() .getCameraConfig(selectedCameraID); - const allSelectedCameraIDs = cameraManager - .getStore() - .getAllDependentCameras(selectedCameraID); const substreamAwareCameraCapabilities = cameraManager.getCameraCapabilities(substreamAwareCameraID); @@ -98,9 +95,12 @@ export class MenuButtonController { ) as FrigateCardCustomAction, }); - if (visibleCameraIDs.size) { + // Show all cameras in the menu rather than just cameras that support the + // current view for a less surprising UX. + const menuCameraIDs = cameraManager.getStore().getCameraIDsWithCapability('menu'); + if (menuCameraIDs.size) { const menuItems = Array.from( - cameraManager.getStore().getCameraConfigEntries(visibleCameraIDs), + cameraManager.getStore().getCameraConfigEntries(menuCameraIDs), ([cameraID, config]) => { const action = createFrigateCardCameraAction('camera_select', cameraID); const metadata = cameraManager.getCameraMetadata(cameraID); @@ -126,10 +126,15 @@ export class MenuButtonController { }); } - if (selectedCameraID && allSelectedCameraIDs && view.is('live')) { - const dependencies = [...allSelectedCameraIDs]; + const substreamCameraIDs = cameraManager + .getStore() + .getAllDependentCameras(selectedCameraID, 'substream'); - if (dependencies.length === 2) { + if (selectedCameraID && substreamCameraIDs && view.is('live')) { + const substreams = [...substreamCameraIDs].filter((cameraID) => cameraID !== selectedCameraID); + const streams = [selectedCameraID, ...substreams]; + + if (streams.length === 2) { // If there are only two dependencies (the main camera, and 1 other) // then use a button not a menu to toggle. buttons.push({ @@ -145,14 +150,14 @@ export class MenuButtonController { hasSubstream(view) ? 'live_substream_off' : 'live_substream_on', ) as FrigateCardCustomAction, }); - } else if (dependencies.length > 2) { - const menuItems = Array.from(dependencies, (cameraID) => { + } else if (streams.length > 2) { + const menuItems = Array.from(streams, (streamID) => { const action = createFrigateCardCameraAction( 'live_substream_select', - cameraID, + streamID, ); - const metadata = cameraManager.getCameraMetadata(cameraID) ?? undefined; - const cameraConfig = cameraManager.getStore().getCameraConfig(cameraID); + const metadata = cameraManager.getCameraMetadata(streamID) ?? undefined; + const cameraConfig = cameraManager.getStore().getCameraConfig(streamID); return { enabled: true, icon: metadata?.icon, @@ -161,7 +166,7 @@ export class MenuButtonController { title: metadata?.title, selected: (view.context?.live?.overrides?.get(selectedCameraID) ?? - selectedCameraID) === cameraID, + selectedCameraID) === streamID, ...(action && { tap_action: action }), }; }); @@ -409,7 +414,8 @@ export class MenuButtonController { }); } - if (view.supportsMultipleDisplayModes() && visibleCameraIDs.size > 1) { + const viewCameraIDs = getCameraIDsForViewName(cameraManager, view.view); + if (view.supportsMultipleDisplayModes() && viewCameraIDs.size > 1) { const isGrid = view.isGrid(); buttons.push({ icon: isGrid ? 'mdi:grid-off' : 'mdi:grid', diff --git a/src/components-lib/ptz-controller.ts b/src/components-lib/ptz-controller.ts index 1db58905..5399574a 100644 --- a/src/components-lib/ptz-controller.ts +++ b/src/components-lib/ptz-controller.ts @@ -137,7 +137,7 @@ export class PTZController { const ptzCapabilities = this._cameraManager.getCameraCapabilities( this._cameraID, - )?.ptz; + )?.getPTZCapabilities(); const defaultActions: FrigateCardPTZActions = {}; const panTilt = ptzCapabilities?.panTilt; diff --git a/src/components-lib/timeline-source.ts b/src/components-lib/timeline-source.ts index 823cce5c..6b4f9f62 100644 --- a/src/components-lib/timeline-source.ts +++ b/src/components-lib/timeline-source.ts @@ -4,14 +4,15 @@ import { DataSet } from 'vis-data'; import { IdType, TimelineItem, TimelineWindow } from 'vis-timeline/esnext'; import { CameraManager } from '../camera-manager/manager'; import { + compressRanges, ExpiringMemoryRangeSet, MemoryRangeSet, - compressRanges, } from '../camera-manager/range'; import { EventQuery, RecordingQuery, RecordingSegment } from '../camera-manager/types'; -import { capEndDate, convertRangeToCacheFriendlyTimes } from '../camera-manager/utils'; +import { capEndDate } from '../camera-manager/utils/cap-end-date'; +import { convertRangeToCacheFriendlyTimes } from '../camera-manager/utils/range-to-cache-friendly'; import { ClipsOrSnapshotsOrAll } from '../types'; -import { ModifyInterface, errorToConsole } from '../utils/basic.js'; +import { errorToConsole, ModifyInterface } from '../utils/basic.js'; import { ViewMedia } from '../view/media'; // Allow timeline freshness to be at least this number of seconds out of date diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 38ab5c0b..a5f79ad0 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -324,7 +324,7 @@ export class FrigateCardLiveGrid extends LitElement { } protected _needsGrid(): boolean { - const cameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); + const cameraIDs = this.cameraManager?.getStore().getCameraIDsWithCapability('live'); return ( !!this.view?.isGrid() && !!this.view?.supportsMultipleDisplayModes() && @@ -343,8 +343,8 @@ export class FrigateCardLiveGrid extends LitElement { if (!this.conditionsManagerEpoch || !this.nonOverriddenLiveConfig) { return; } - const cameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); - if (!cameraIDs || !this._needsGrid()) { + const cameraIDs = this.cameraManager?.getStore().getCameraIDsWithCapability('live'); + if (!cameraIDs?.size || !this._needsGrid()) { return this._renderCarousel(); } return html` @@ -416,8 +416,8 @@ export class FrigateCardLiveCarousel extends LitElement { } protected _getSelectedCameraIndex(): number { - const cameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); - if (!cameraIDs || !this.view || this.viewFilterCameraID) { + const cameraIDs = this.cameraManager?.getStore().getCameraIDsWithCapability('live'); + if (!cameraIDs?.size || !this.view || this.viewFilterCameraID) { // If the carousel is limited to a single cameraID, the first (only) // element is always the selected one. return 0; @@ -481,7 +481,7 @@ export class FrigateCardLiveCarousel extends LitElement { const cameraIDs = this.viewFilterCameraID ? new Set([this.viewFilterCameraID]) - : this.cameraManager.getStore().getVisibleCameraIDs(); + : this.cameraManager?.getStore().getCameraIDsWithCapability('live'); const slides: TemplateResult[] = []; const cameraToSlide: Record = {}; @@ -508,8 +508,8 @@ export class FrigateCardLiveCarousel extends LitElement { } protected _setViewHandler(ev: CustomEvent): void { - const cameraIDs = this.cameraManager?.getStore().getVisibleCameraIDs(); - if (cameraIDs && ev.detail.index !== this._getSelectedCameraIndex()) { + const cameraIDs = this.cameraManager?.getStore().getCameraIDsWithCapability('live'); + if (cameraIDs?.size && ev.detail.index !== this._getSelectedCameraIndex()) { this._setViewCameraID([...cameraIDs][ev.detail.index]); } } @@ -597,7 +597,7 @@ export class FrigateCardLiveCarousel extends LitElement { protected _getCameraIDsOfNeighbors(): [string | null, string | null] { const cameraIDs = this.cameraManager - ? [...this.cameraManager.getStore().getVisibleCameraIDs()] + ? [...this.cameraManager?.getStore().getCameraIDsWithCapability('live')] : []; if (this.viewFilterCameraID || cameraIDs.length <= 1 || !this.view || !this.hass) { return [null, null]; diff --git a/src/components/surround.ts b/src/components/surround.ts index c7cc0d5b..cab592b3 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -159,14 +159,22 @@ export class FrigateCardSurround extends LitElement { } protected _getCameraIDsForTimeline(): Set | null { - if (!this.view) { + if (!this.view || !this.cameraManager) { return null; } - if (this.view?.is('live')) { - return this.view.isGrid() - ? this.cameraManager?.getStore().getVisibleCameraIDs() ?? null - : this.cameraManager?.getStore().getAllDependentCameras(this.view.camera) ?? - null; + if (this.view.is('live')) { + const capabilitySearch = { + anyCapabilities: ['clips' as const, 'snapshots' as const, 'recordings' as const], + }; + if (this.view.supportsMultipleDisplayModes() && this.view.isGrid()) { + return this.cameraManager + .getStore() + .getCameraIDsWithCapability(capabilitySearch); + } else { + return this.cameraManager + .getStore() + .getAllDependentCameras(this.view.camera, capabilitySearch); + } } if (this.view.isViewerView()) { return this.view.query?.getQueryCameraIDs() ?? null; diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index ba20b89b..c46bc8f3 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -27,7 +27,7 @@ import { import { CameraManager } from '../camera-manager/manager'; import { rangesOverlap } from '../camera-manager/range'; import { MediaQuery } from '../camera-manager/types'; -import { convertRangeToCacheFriendlyTimes } from '../camera-manager/utils'; +import { convertRangeToCacheFriendlyTimes } from '../camera-manager/utils/range-to-cache-friendly'; import { FrigateCardTimelineItem, TimelineDataSource, @@ -72,7 +72,6 @@ import { MediaQueriesResults } from '../view/media-queries-results'; import { View } from '../view/view'; import './date-picker.js'; import { DatePickerEvent, FrigateCardDatePicker } from './date-picker.js'; -import { dispatchMessageEvent } from './message.js'; import './thumbnail.js'; interface FrigateCardGroupData { @@ -275,18 +274,11 @@ export class FrigateCardTimelineCore extends LitElement { request.detail.view = this.view; } - /** - * Master render method. - * @returns A rendered template. - */ protected render(): TemplateResult | void { - const cameraIDs = this._getTimelineCameraIDs(); - - if (!this.hass || !this.view || !this.timelineConfig || !cameraIDs) { + if (!this.hass || !this.view || !this.timelineConfig || !this.cameraIDs?.size) { return; } - const capabilities = this.cameraManager?.getAggregateCameraCapabilities(cameraIDs); const panMode = this._getEffectivePanMode(); const panTitle = @@ -306,55 +298,43 @@ export class FrigateCardTimelineCore extends LitElement { ? 'mdi:play-box-lock' : 'mdi:camera-lock'; - return html` ${capabilities?.supportsTimeline - ? html`
-
- ${this._shouldSupportSeeking() - ? html` { - this._panMode = - panMode === 'pan' - ? 'seek' - : panMode === 'seek' - ? 'seek-in-media' - : panMode === 'seek-in-media' - ? 'seek-in-camera' - : 'pan'; - }} - aria-label="${panTitle}" - title="${panTitle}" - > - ` - : ''} - ) => { - if (ev.detail.date) { - this._timeline?.moveTo(ev.detail.date); - } + return html`
+
+ ${this._shouldSupportSeeking() + ? html` { + this._panMode = + panMode === 'pan' + ? 'seek' + : panMode === 'seek' + ? 'seek-in-media' + : panMode === 'seek-in-media' + ? 'seek-in-camera' + : 'pan'; }} + aria-label="${panTitle}" + title="${panTitle}" > - -
-
` - : ''}`; - } - - /** - * Get all the keys of the cameras in scope for this timeline. - * @returns A set of camera ids (may be empty). - */ - protected _getTimelineCameraIDs(): Set | null { - return ( - this.cameraIDs ?? this.cameraManager?.getStore().getVisibleCameraIDs() ?? null - ); + ` + : ''} + ) => { + if (ev.detail.date) { + this._timeline?.moveTo(ev.detail.date); + } + }} + > + +
+
`; } /** @@ -555,7 +535,6 @@ export class FrigateCardTimelineCore extends LitElement { stopEventFromActivatingCardWideActions(properties.event); } - const timelineCameraIDs = this._getTimelineCameraIDs(); if ( this._ignoreClick || !this.hass || @@ -563,7 +542,8 @@ export class FrigateCardTimelineCore extends LitElement { !this.view || !this.cameraManager || !this.cardWideConfig || - !timelineCameraIDs || + !this.cameraIDs || + !this.cameraIDs.size || !this._timelineSource || !properties.what ) { @@ -767,14 +747,13 @@ export class FrigateCardTimelineCore extends LitElement { */ protected _getGroups(): DataGroupCollectionType { const groups: FrigateCardGroupData[] = []; - (this._getTimelineCameraIDs() ?? []).forEach((cameraID) => { + (this.cameraIDs ?? []).forEach((cameraID: string) => { if (!this.hass || !this.cameraManager) { return; } const cameraMetadata = this.cameraManager.getCameraMetadata(cameraID); - const cameraCapabilities = this.cameraManager.getCameraCapabilities(cameraID); - if (cameraMetadata && cameraCapabilities?.supportsTimeline) { + if (cameraMetadata) { groups.push({ id: cameraID, content: cameraMetadata.title, @@ -1142,11 +1121,10 @@ export class FrigateCardTimelineCore extends LitElement { changedProps.has('timelineConfig') || changedProps.has('cameraIDs') ) { - const cameraIDs = this._getTimelineCameraIDs(); - if (cameraIDs && this.cameraManager && this.timelineConfig) { + if (this.cameraIDs?.size && this.cameraManager && this.timelineConfig) { this._timelineSource = new TimelineDataSource( this.cameraManager, - cameraIDs, + this.cameraIDs, this.timelineConfig.events_media_type, this.timelineConfig.show_recordings, ); @@ -1191,12 +1169,6 @@ export class FrigateCardTimelineCore extends LitElement { const groups = this._getGroups(); if (!groups.length) { - if (!this.mini) { - // Don't show an empty timeline, show a message instead. - dispatchMessageEvent(this, localize('error.timeline_no_cameras'), 'info', { - icon: 'mdi:chart-gantt', - }); - } return; } diff --git a/src/components/timeline.ts b/src/components/timeline.ts index 01a324f5..08f737e6 100644 --- a/src/components/timeline.ts +++ b/src/components/timeline.ts @@ -37,6 +37,9 @@ export class FrigateCardTimeline extends LitElement { .timelineConfig=${this.timelineConfig} .thumbnailConfig=${this.timelineConfig.controls.thumbnails} .cameraManager=${this.cameraManager} + .cameraIDs=${this.cameraManager?.getStore().getCameraIDsWithCapability({ + anyCapabilities: ['clips', 'snapshots', 'recordings'], + })} .cardWideConfig=${this.cardWideConfig} .itemClickAction=${this.timelineConfig.controls.thumbnails.mode === 'none' ? 'play' diff --git a/src/config-mgmt.ts b/src/config-mgmt.ts index 0c8d6f28..28f379ab 100644 --- a/src/config-mgmt.ts +++ b/src/config-mgmt.ts @@ -678,4 +678,10 @@ const UPGRADES = [ typeof data === 'object' && data ? data[CONF_AUTOMATIONS] : {}, ); }, + upgradeArrayOfObjects( + CONF_CAMERAS, + upgradeMoveToWithOverrides('hide', 'capabilities', { + transform: (val) => (val === true ? { disable_except: 'substream' } : null), + }), + ), ]; diff --git a/src/config/types.ts b/src/config/types.ts index d241c793..67508e46 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -9,6 +9,7 @@ import { } from '@dermotduffy/custom-card-helpers'; import { z } from 'zod'; import { MEDIA_CHUNK_SIZE_DEFAULT, MEDIA_CHUNK_SIZE_MAX } from '../const.js'; +import { capabilityKeys } from '../types.js'; import { deepRemoveDefaults } from '../utils/zod.js'; // ************************************************************************* @@ -44,6 +45,8 @@ const FRIGATE_CARD_VIEWS = [ ] as const; export type FrigateCardView = (typeof FRIGATE_CARD_VIEWS)[number]; + +// The default view (may not be supported on all cameras). export const FRIGATE_CARD_VIEW_DEFAULT = 'live' as const; export const MEDIA_ACTION_NEGATIVE_CONDITIONS = ['unselected', 'hidden'] as const; @@ -730,12 +733,7 @@ const timelineCoreConfigDefault = { pan_mode: 'pan' as const, }; -export const timelinePanModeSchema = z.enum([ - 'pan', - 'seek', - 'seek-in-media', - 'seek-in-camera', -]); +const timelinePanModeSchema = z.enum(['pan', 'seek', 'seek-in-media', 'seek-in-camera']); export type TimelinePanMode = z.infer; const timelineCoreConfigSchema = z.object({ @@ -757,9 +755,7 @@ const timelineCoreConfigSchema = z.object({ .optional() .default(timelineCoreConfigDefault.show_recordings), style: z.enum(['stack', 'ribbon']).optional().default(timelineCoreConfigDefault.style), - pan_mode: timelinePanModeSchema - .optional() - .default(timelineCoreConfigDefault.pan_mode), + pan_mode: timelinePanModeSchema.optional().default(timelineCoreConfigDefault.pan_mode), }); export type TimelineCoreConfig = z.infer; @@ -1119,7 +1115,6 @@ const cameraConfigDefault = { frigate: { client_id: 'frigate' as const, }, - hide: false, image: { refresh_seconds: 1, }, @@ -1151,8 +1146,12 @@ export const cameraConfigSchema = z icon: z.string().optional(), title: z.string().optional(), - // Used to hide the camera (e.g. when used only as a dependency). - hide: z.boolean().optional(), + capabilities: z + .object({ + disable: z.enum(capabilityKeys).array().optional(), + disable_except: z.enum(capabilityKeys).array().optional(), + }) + .optional(), // Optional identifier to separate different camera configurations used in // this card. diff --git a/src/const.ts b/src/const.ts index fdb6237c..7471da29 100644 --- a/src/const.ts +++ b/src/const.ts @@ -8,6 +8,10 @@ export const CONF_CAMERAS_ARRAY_CAMERA_ENTITY = `${CONF_CAMERAS}.#.camera_entity` as const; export const CONF_CAMERAS_ARRAY_FRIGATE_CAMERA_NAME = `${CONF_CAMERAS}.#.frigate.camera_name` as const; +export const CONF_CAMERAS_ARRAY_CAPABILITIES_DISABLE = + `${CONF_CAMERAS}.#.capabilities.disable` as const; +export const CONF_CAMERAS_ARRAY_CAPABILITIES_DISABLE_EXCEPT = + `${CONF_CAMERAS}.#.capabilities.disable_except` as const; export const CONF_CAMERAS_ARRAY_CAST_METHOD = `${CONF_CAMERAS}.#.cast.method` as const; export const CONF_CAMERAS_ARRAY_CAST_DASHBOARD_DASHBOARD_PATH = `${CONF_CAMERAS}.#.cast.dashboard.dashboard_path` as const; @@ -25,7 +29,6 @@ export const CONF_CAMERAS_ARRAY_FRIGATE_ZONES = export const CONF_CAMERAS_ARRAY_GO2RTC_MODES = `${CONF_CAMERAS}.#.go2rtc.modes` as const; export const CONF_CAMERAS_ARRAY_GO2RTC_STREAM = `${CONF_CAMERAS}.#.go2rtc.stream` as const; -export const CONF_CAMERAS_ARRAY_HIDE = `${CONF_CAMERAS}.#.hide` as const; export const CONF_CAMERAS_ARRAY_ICON = `${CONF_CAMERAS}.#.icon` as const; export const CONF_CAMERAS_ARRAY_ID = `${CONF_CAMERAS}.#.id` as const; export const CONF_CAMERAS_ARRAY_IMAGE_REFRESH_SECONDS = diff --git a/src/editor.ts b/src/editor.ts index 415d5e56..b9865192 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -31,8 +31,9 @@ import { THUMBNAIL_WIDTH_MIN, } from './config/types.js'; import { - CONF_CAMERAS, CONF_CAMERAS_ARRAY_CAMERA_ENTITY, + CONF_CAMERAS_ARRAY_CAPABILITIES_DISABLE_EXCEPT, + CONF_CAMERAS_ARRAY_CAPABILITIES_DISABLE, CONF_CAMERAS_ARRAY_CAST_DASHBOARD_DASHBOARD_PATH, CONF_CAMERAS_ARRAY_CAST_DASHBOARD_VIEW_PATH, CONF_CAMERAS_ARRAY_CAST_METHOD, @@ -49,7 +50,6 @@ import { CONF_CAMERAS_ARRAY_FRIGATE_ZONES, CONF_CAMERAS_ARRAY_GO2RTC_MODES, CONF_CAMERAS_ARRAY_GO2RTC_STREAM, - CONF_CAMERAS_ARRAY_HIDE, CONF_CAMERAS_ARRAY_ICON, CONF_CAMERAS_ARRAY_ID, CONF_CAMERAS_ARRAY_IMAGE_REFRESH_SECONDS, @@ -67,8 +67,9 @@ import { CONF_CAMERAS_ARRAY_TRIGGERS_OCCUPANCY, CONF_CAMERAS_ARRAY_WEBRTC_CARD_ENTITY, CONF_CAMERAS_ARRAY_WEBRTC_CARD_URL, - CONF_DIMENSIONS_ASPECT_RATIO, + CONF_CAMERAS, CONF_DIMENSIONS_ASPECT_RATIO_MODE, + CONF_DIMENSIONS_ASPECT_RATIO, CONF_DIMENSIONS_MAX_HEIGHT, CONF_DIMENSIONS_MIN_HEIGHT, CONF_IMAGE_MODE, @@ -91,7 +92,6 @@ import { CONF_LIVE_CONTROLS_THUMBNAILS_EVENTS_MEDIA_TYPE, CONF_LIVE_CONTROLS_THUMBNAILS_MEDIA_TYPE, CONF_LIVE_CONTROLS_THUMBNAILS_MODE, - CONF_LIVE_CONTROLS_TIMELINE_PAN_MODE, CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DETAILS, CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_DOWNLOAD_CONTROL, CONF_LIVE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL, @@ -100,6 +100,7 @@ import { CONF_LIVE_CONTROLS_TIMELINE_CLUSTERING_THRESHOLD, CONF_LIVE_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, CONF_LIVE_CONTROLS_TIMELINE_MODE, + CONF_LIVE_CONTROLS_TIMELINE_PAN_MODE, CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS, CONF_LIVE_CONTROLS_TIMELINE_STYLE, CONF_LIVE_CONTROLS_TIMELINE_WINDOW_SECONDS, @@ -157,8 +158,8 @@ import { CONF_MEDIA_VIEWER_TRANSITION_EFFECT, CONF_MEDIA_VIEWER_ZOOMABLE, CONF_MENU_ALIGNMENT, - CONF_MENU_BUTTONS, CONF_MENU_BUTTON_SIZE, + CONF_MENU_BUTTONS, CONF_MENU_POSITION, CONF_MENU_STYLE, CONF_PERFORMANCE_FEATURES_ANIMATED_PROGRESS_INDICATOR, @@ -182,14 +183,14 @@ import { CONF_VIEW_DEFAULT, CONF_VIEW_INTERACTION_SECONDS, CONF_VIEW_RESET_AFTER_INTERACTION, - CONF_VIEW_TRIGGERS, - CONF_VIEW_TRIGGERS_ACTIONS, CONF_VIEW_TRIGGERS_ACTIONS_INTERACTION_MODE, CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER, CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER, + CONF_VIEW_TRIGGERS_ACTIONS, CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA, CONF_VIEW_TRIGGERS_SHOW_TRIGGER_STATUS, CONF_VIEW_TRIGGERS_UNTRIGGER_SECONDS, + CONF_VIEW_TRIGGERS, CONF_VIEW_UPDATE_CYCLE_CAMERA, CONF_VIEW_UPDATE_FORCE, CONF_VIEW_UPDATE_SECONDS, @@ -208,6 +209,7 @@ import { const MENU_BUTTONS = 'buttons'; const MENU_CAMERAS = 'cameras'; +const MENU_CAMERAS_CAPABILITIES = 'cameras.capabilities'; const MENU_CAMERAS_CAST = 'cameras.cast'; const MENU_CAMERAS_DEPENDENCIES = 'cameras.dependencies'; const MENU_CAMERAS_DIMENSIONS = 'cameras.dimensions'; @@ -741,6 +743,50 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor }, ]; + protected _capabilities: EditorSelectOption[] = [ + { value: '', label: '' }, + { + value: 'live', + label: localize('config.cameras.capabilities.capabilities.live'), + }, + { + value: 'substream', + label: localize('config.cameras.capabilities.capabilities.substream'), + }, + { + value: 'clips', + label: localize('config.cameras.capabilities.capabilities.clips'), + }, + { + value: 'recordings', + label: localize('config.cameras.capabilities.capabilities.recordings'), + }, + { + value: 'snapshots', + label: localize('config.cameras.capabilities.capabilities.snapshots'), + }, + { + value: 'favorite-events', + label: localize('config.cameras.capabilities.capabilities.favorite-events'), + }, + { + value: 'favorite-recordings', + label: localize('config.cameras.capabilities.capabilities.favorite-recordings'), + }, + { + value: 'seek', + label: localize('config.cameras.capabilities.capabilities.seek'), + }, + { + value: 'ptz', + label: localize('config.cameras.capabilities.capabilities.ptz'), + }, + { + value: 'menu', + label: localize('config.cameras.capabilities.capabilities.menu'), + }, + ]; + public setConfig(config: RawFrigateCardConfig): void { // Note: This does not use Zod to parse the configuration, so it may be // partially or completely invalid. It's more useful to have a partially @@ -1688,10 +1734,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderStringInput( getArrayConfigPath(CONF_CAMERAS_ARRAY_ID, cameraIndex), )} - ${this._renderSwitch( - getArrayConfigPath(CONF_CAMERAS_ARRAY_HIDE, cameraIndex), - this._defaults.cameras.hide, - )} ${this._putInSubmenu( MENU_CAMERAS_ENGINE, true, @@ -1933,6 +1975,34 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor )} `, )} + ${this._putInSubmenu( + MENU_CAMERAS_CAPABILITIES, + cameraIndex, + 'config.cameras.capabilities.editor_label', + { name: 'mdi:cog-stop' }, + html` + ${this._renderOptionSelector( + getArrayConfigPath( + CONF_CAMERAS_ARRAY_CAPABILITIES_DISABLE, + cameraIndex, + ), + this._capabilities, + { + multiple: true, + }, + )} + ${this._renderOptionSelector( + getArrayConfigPath( + CONF_CAMERAS_ARRAY_CAPABILITIES_DISABLE_EXCEPT, + cameraIndex, + ), + this._capabilities, + { + multiple: true, + }, + )} + `, + )} ` : ``} diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 25407e9c..6d4bfa88 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -10,6 +10,23 @@ "config": { "cameras": { "camera_entity": "Camera Entity", + "capabilities": { + "disable": "Disable", + "disable_except": "Disable except", + "editor_label": "Camera capabilities", + "capabilities": { + "clips": "Clips", + "favorite-events": "Favorite Events", + "favorite-recordings": "Favorite Recordings", + "live": "Live", + "menu": "Menu", + "ptz": "PTZ", + "recordings": "Recordings", + "seek": "Seeking", + "snapshots": "Snapshots", + "substream": "Substream" + } + }, "cast": { "dashboard": { "dashboard_path": "Dashboard path", @@ -50,7 +67,7 @@ "frigate": { "camera_name": "Frigate camera name (Autodetected from entity)", "client_id": "Frigate client id (For >1 Frigate server)", - "editor_label": "Frigate Options", + "editor_label": "Frigate options", "labels": "Frigate labels/object filters", "url": "Frigate server URL", "zones": "Frigate zones" @@ -87,7 +104,7 @@ "webrtc-card": "WebRTC Card (i.e. AlexxIT's WebRTC Card)" }, "motioneye": { - "editor_label": "MotionEye Options", + "editor_label": "MotionEye options", "images": { "directory_pattern": "Images directory pattern", "file_pattern": "Images file pattern" @@ -527,9 +544,9 @@ "no_camera_name": "Could not determine a Frigate camera name for camera (or one of its dependents), please specify either 'camera_entity' or 'camera_name'", "no_dashboard_or_view": "Both 'dashboard_path' and 'view_path' parameters are required for the 'dashboard' cast method", "no_live_camera": "The camera_entity parameter must be set and valid for this live provider", - "no_visible_cameras": "No visible cameras found, you must configure at least one non-hidden camera", + "no_supported_camera": "The selected camera does not support this view", + "no_supported_cameras": "No cameras support this view", "reconnecting": "Reconnecting", - "timeline_no_cameras": "No Frigate cameras to show in timeline", "too_many_automations": "Too many nested automation calls, please check your configuration for loops", "troubleshooting": "Check troubleshooting", "unknown": "Unknown error", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 94cb26f5..6af6a999 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -10,6 +10,23 @@ "config": { "cameras": { "camera_entity": "Entità della telecamera", + "capabilities": { + "disable": "", + "disable_except": "", + "editor_label": "", + "capabilities": { + "clips": "", + "favorite-events": "", + "favorite-recordings": "", + "live": "", + "menu": "", + "ptz": "", + "recordings": "", + "seek": "", + "snapshots": "", + "substream": "" + } + }, "cast": { "dashboard": { "dashboard_path": "", @@ -518,7 +535,8 @@ "no_camera_name": "Impossibile determinare un nome della telecamera in Frigate, si prega di specificare 'camera_enty' o 'camera_name'", "no_dashboard_or_view": "", "no_live_camera": "Il parametro fotocamera_enty deve essere impostato e valido per questo provider live", - "no_visible_cameras": "Nessuna telecamera visibile trovata, è necessario configurare almeno una telecamera non nascosta", + "no_supported_camera": "", + "no_supported_cameras": "", "reconnecting": "Riconnessione", "timeline_no_cameras": "Nessuna telecamera damostrare in Frigate nella timeline", "too_many_automations": "", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 85ee08a3..bec02933 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -10,6 +10,23 @@ "config": { "cameras": { "camera_entity": "Entidade da Câmera", + "capabilities": { + "disable": "", + "disable_except": "", + "editor_label": "", + "capabilities": { + "clips": "", + "favorite-events": "", + "favorite-recordings": "", + "live": "", + "menu": "", + "ptz": "", + "recordings": "", + "seek": "", + "snapshots": "", + "substream": "" + } + }, "cast": { "dashboard": { "dashboard_path": "", @@ -525,7 +542,8 @@ "no_camera_name": "Não foi possível determinar o nome da câmera da Frigate, especifique 'camera_entity' ou 'camera_name' para a câmera a seguir", "no_dashboard_or_view": "", "no_live_camera": "O parâmetro camera_entity deve ser definido e válido para este provedor ativo", - "no_visible_cameras": "Nenhuma câmera visível encontrada, você deve configurar pelo menos uma câmera não oculta", + "no_supported_camera": "", + "no_supported_cameras": "", "reconnecting": "Reconectando", "timeline_no_cameras": "Nenhuma câmera do Frigate para mostrar na linha do tempo", "too_many_automations": "", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 859fa85f..36460227 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -10,6 +10,23 @@ "config": { "cameras": { "camera_entity": "Entidade da Câmera", + "capabilities": { + "disable": "", + "disable_except": "", + "editor_label": "", + "capabilities": { + "clips": "", + "favorite-events": "", + "favorite-recordings": "", + "live": "", + "menu": "", + "ptz": "", + "recordings": "", + "seek": "", + "snapshots": "", + "substream": "" + } + }, "cast": { "dashboard": { "dashboard_path": "", @@ -511,7 +528,8 @@ "no_camera_name": "Não foi possível determinar o nome da câmera da Frigate, especifique 'camera_entity' ou 'camera_name' para a câmera a seguir", "no_dashboard_or_view": "", "no_live_camera": "O parâmetro camera_entity deve ser definido e válido para este serviço ativo", - "no_visible_cameras": "Sem camaras visiveis", + "no_supported_camera": "", + "no_supported_cameras": "", "reconnecting": "A voltar a ligar", "timeline_no_cameras": "Nenhuma câmera do Frigate para mostrar na linha do tempo", "too_many_automations": "", diff --git a/src/types.ts b/src/types.ts index d95880ed..40afdd63 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,4 +1,8 @@ -import { HomeAssistant, LovelaceCardConfig, Themes } from '@dermotduffy/custom-card-helpers'; +import { + HomeAssistant, + LovelaceCardConfig, + Themes, +} from '@dermotduffy/custom-card-helpers'; import { StyleInfo } from 'lit/directives/style-map.js'; import { z } from 'zod'; @@ -87,6 +91,46 @@ export interface CardHelpers { }>; } +export type PTZMovementType = 'relative' | 'continuous'; + +export interface PTZCapabilities { + panTilt?: PTZMovementType[]; + zoom?: PTZMovementType[]; + presets?: string[]; +} + +export interface CapabilitiesRaw { + live?: boolean; + substream?: boolean; + + clips?: boolean; + recordings?: boolean; + snapshots?: boolean; + + 'favorite-events'?: boolean; + 'favorite-recordings'?: boolean; + + seek?: boolean; + + ptz?: PTZCapabilities; + + menu?: boolean; +} + +export type CapabilityKey = keyof CapabilitiesRaw; +export const capabilityKeys: readonly [CapabilityKey, ...CapabilityKey[]] = [ + 'clips', + 'favorite-events', + 'favorite-recordings', + 'live', + 'menu', + 'ptz', + 'recordings', + 'seek', + 'snapshots', + 'substream', +] as const; + // ************************************************************************* // Home Assistant API types. // ************************************************************************* diff --git a/src/utils/media-to-view.ts b/src/utils/media-to-view.ts index e940c7c4..4fbe8fc8 100644 --- a/src/utils/media-to-view.ts +++ b/src/utils/media-to-view.ts @@ -1,6 +1,6 @@ import { ViewContext } from 'view'; import { CameraManager } from '../camera-manager/manager'; -import { MediaQuery } from '../camera-manager/types'; +import { CapabilitySearchOptions, MediaQuery } from '../camera-manager/types'; import { dispatchFrigateCardErrorEvent } from '../components/message'; import { CardWideConfig, FrigateCardView } from '../config/types'; import { MEDIA_CHUNK_SIZE_DEFAULT } from '../const'; @@ -30,9 +30,16 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( useCache?: boolean; }, ): Promise => { + const capabilitySearch: CapabilitySearchOptions = + !options?.eventsMediaType || options?.eventsMediaType === 'all' + ? { + anyCapabilities: ['clips', 'snapshots'], + } + : options.eventsMediaType; + const cameraIDs = options?.allCameras - ? cameraManager.getStore().getVisibleCameraIDs() - : cameraManager.getStore().getAllDependentCameras(view.camera); + ? cameraManager.getStore().getCameraIDsWithCapability(capabilitySearch) + : cameraManager.getStore().getAllDependentCameras(view.camera, capabilitySearch); if (!cameraIDs.size) { return; } @@ -99,8 +106,8 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( }, ): Promise => { const cameraIDs = options?.allCameras - ? cameraManager.getStore().getVisibleCameraIDs() - : cameraManager.getStore().getAllDependentCameras(view.camera); + ? cameraManager.getStore().getCameraIDsWithCapability('recordings') + : cameraManager.getStore().getAllDependentCameras(view.camera, 'recordings'); if (!cameraIDs.size) { return; } diff --git a/src/utils/ptz.ts b/src/utils/ptz.ts index 6d31e8a2..2cde0016 100644 --- a/src/utils/ptz.ts +++ b/src/utils/ptz.ts @@ -1,8 +1,8 @@ -import { CameraManagerCameraCapabilities } from '../camera-manager/types'; +import { Capabilities } from '../camera-manager/capabilities'; import { FrigateCardPTZConfig, PTZ_CONTROL_ACTIONS } from '../config/types'; export const hasUsablePTZ = ( - capabilities: CameraManagerCameraCapabilities | null, + capabilities: Capabilities | null, config: FrigateCardPTZConfig, ): boolean => { for (const actionName of PTZ_CONTROL_ACTIONS) { @@ -10,5 +10,10 @@ export const hasUsablePTZ = ( return true; } } - return !!capabilities?.ptz; + const ptzCapabilities = capabilities?.getPTZCapabilities(); + return ( + !!ptzCapabilities?.panTilt?.length || + !!ptzCapabilities?.zoom?.length || + !!ptzCapabilities?.presets?.length + ); }; diff --git a/src/view/view-to-cameras.ts b/src/view/view-to-cameras.ts new file mode 100644 index 00000000..3f669277 --- /dev/null +++ b/src/view/view-to-cameras.ts @@ -0,0 +1,51 @@ +import { CameraManager } from '../camera-manager/manager'; +import { FrigateCardView } from '../config/types'; + +/** + * Get cameraIDs that are relevant for a given view name based on camera + * capability (if camera specified). + */ +export const getCameraIDsForViewName = ( + cameraManager: CameraManager, + viewName: FrigateCardView, + cameraID?: string, +): Set => { + switch (viewName) { + case 'image': + case 'diagnostics': + return cameraManager.getStore().getCameraIDs(); + + case 'live': + case 'clip': + case 'clips': + case 'snapshot': + case 'snapshots': + case 'recording': + case 'recordings': + const capability = + viewName === 'clip' + ? 'clips' + : viewName === 'snapshot' + ? 'snapshots' + : viewName === 'recording' + ? 'recordings' + : viewName; + return cameraID + ? cameraManager.getStore().getAllDependentCameras(cameraID, capability) + : cameraManager.getStore().getCameraIDsWithCapability(capability); + + case 'timeline': + return cameraManager.getStore().getCameraIDsWithCapability({ + anyCapabilities: ['clips', 'snapshots', 'recordings'], + }); + + case 'media': + return cameraID + ? cameraManager.getStore().getAllDependentCameras(cameraID, { + anyCapabilities: ['clips', 'snapshots', 'recordings'], + }) + : cameraManager.getStore().getCameraIDsWithCapability({ + anyCapabilities: ['clips', 'snapshots', 'recordings'], + }); + } +}; diff --git a/tests/camera-manager/camera.test.ts b/tests/camera-manager/camera.test.ts index fc14557d..46e5196b 100644 --- a/tests/camera-manager/camera.test.ts +++ b/tests/camera-manager/camera.test.ts @@ -5,8 +5,8 @@ import { GenericCameraManagerEngine } from '../../src/camera-manager/generic/eng import { EntityRegistryManager } from '../../src/utils/ha/entity-registry/index.js'; import { callHASubscribeMessageHandler, - createCameraCapabilities, createCameraConfig, + createCapabilities, createHASS, } from '../test-utils.js'; @@ -19,7 +19,7 @@ describe('Camera', () => { describe('should get capabilities', async () => { it('when populated', async () => { - const capabilities = createCameraCapabilities(); + const capabilities = createCapabilities(); const camera = new Camera(createCameraConfig(), new GenericCameraManagerEngine(), { capabilities: capabilities, }); diff --git a/tests/camera-manager/capabilities.test.ts b/tests/camera-manager/capabilities.test.ts new file mode 100644 index 00000000..9710e489 --- /dev/null +++ b/tests/camera-manager/capabilities.test.ts @@ -0,0 +1,118 @@ +import { describe, expect, it } from 'vitest'; +import { Capabilities } from '../../src/camera-manager/capabilities'; +import { CapabilityKey, PTZCapabilities, capabilityKeys } from '../../src/types'; + +describe('Capabilities', () => { + it('default capabilities', () => { + const capabilities = new Capabilities({}); + for (const key of capabilityKeys) { + expect(capabilities.has(key)).toBeFalsy(); + } + }); + + describe('simple presence checks', () => { + it.each([ + 'clips', + 'favorite-events', + 'favorite-recordings', + 'live', + 'menu', + 'recordings', + 'seek', + 'snapshots', + 'substream', + ] as const)('%s', (capability: CapabilityKey) => { + const capabilities = new Capabilities({ + [capability]: true, + }); + expect(capabilities.has(capability)).toBeTruthy(); + }); + }); + + describe('complex matches', () => { + it('string matcher', () => { + const capabilities = new Capabilities({ + live: true, + }); + expect(capabilities.matches('live')).toBeTruthy(); + expect(capabilities.matches('clips')).toBeFalsy(); + }); + + it('allCapabilities matcher', () => { + const capabilities = new Capabilities({ + live: true, + clips: true, + }); + expect(capabilities.matches({ allCapabilities: ['live', 'clips'] })).toBeTruthy(); + expect( + capabilities.matches({ allCapabilities: ['live', 'snapshots'] }), + ).toBeFalsy(); + }); + + it('anyCapabilities matcher', () => { + const capabilities = new Capabilities({ + live: true, + clips: true, + }); + expect(capabilities.matches({ anyCapabilities: ['live', 'clips'] })).toBeTruthy(); + expect( + capabilities.matches({ anyCapabilities: ['live', 'snapshots'] }), + ).toBeTruthy(); + expect( + capabilities.matches({ anyCapabilities: ['snapshots', 'menu'] }), + ).toBeFalsy(); + }); + }); + + describe('getPTZCapabilities', () => { + it('when unset', () => { + const capabilities = new Capabilities({}); + expect(capabilities.getPTZCapabilities()).toBeNull(); + }); + + it('when set', () => { + const ptz: PTZCapabilities = { + panTilt: ['continuous' as const], + presets: ['1', '2'], + }; + const capabilities = new Capabilities({ + ptz: ptz, + }); + expect(capabilities.getPTZCapabilities()).toBe(ptz); + }); + }); + + describe('disable capabilities', () => { + it('disable', () => { + const capabilities = new Capabilities( + { + live: true, + clips: true, + snapshots: true, + }, + { + disable: ['live', 'clips'], + }, + ); + expect(capabilities.has('live')).toBeFalsy(); + expect(capabilities.has('clips')).toBeFalsy(); + expect(capabilities.has('snapshots')).toBeTruthy(); + }); + + it('disableExcept', () => { + const capabilities = new Capabilities( + { + live: true, + clips: true, + snapshots: true, + }, + { + disableExcept: ['live', 'clips'], + }, + ); + expect(capabilities.has('live')).toBeTruthy(); + expect(capabilities.has('clips')).toBeTruthy(); + expect(capabilities.has('snapshots')).toBeFalsy(); + }); + }); +}); diff --git a/tests/camera-manager/frigate/camera.test.ts b/tests/camera-manager/frigate/camera.test.ts index bfa8bdbe..7852ae52 100644 --- a/tests/camera-manager/frigate/camera.test.ts +++ b/tests/camera-manager/frigate/camera.test.ts @@ -131,16 +131,6 @@ describe('FrigateCamera', () => { }); describe('should detect capabilities', () => { - const nonBirdseyeBaseCapabilities = { - canFavoriteEvents: true, - canFavoriteRecordings: true, - canSeek: true, - supportsClips: true, - supportsSnapshots: true, - supportsRecordings: true, - supportsTimeline: true, - }; - it('basic non-birdseye', async () => { const camera = new FrigateCamera( createCameraConfig({ @@ -153,7 +143,13 @@ describe('FrigateCamera', () => { await camera.initialize(createHASS(), mock()); - expect(camera.getCapabilities()).toEqual(nonBirdseyeBaseCapabilities); + expect(camera.getCapabilities()?.has('favorite-events')).toBeTruthy(); + expect(camera.getCapabilities()?.has('favorite-recordings')).toBeFalsy(); + expect(camera.getCapabilities()?.has('seek')).toBeTruthy(); + expect(camera.getCapabilities()?.has('clips')).toBeTruthy(); + expect(camera.getCapabilities()?.has('live')).toBeTruthy(); + expect(camera.getCapabilities()?.has('snapshots')).toBeTruthy(); + expect(camera.getCapabilities()?.has('recordings')).toBeTruthy(); expect(vi.mocked(getPTZInfo)).toBeCalled(); }); @@ -169,15 +165,13 @@ describe('FrigateCamera', () => { await camera.initialize(createHASS(), mock()); - expect(camera.getCapabilities()).toEqual({ - ...nonBirdseyeBaseCapabilities, - canFavoriteEvents: false, - canFavoriteRecordings: false, - supportsClips: false, - supportsSnapshots: false, - supportsRecordings: false, - supportsTimeline: false, - }); + expect(camera.getCapabilities()?.has('favorite-events')).toBeFalsy(); + expect(camera.getCapabilities()?.has('favorite-recordings')).toBeFalsy(); + expect(camera.getCapabilities()?.has('seek')).toBeFalsy(); + expect(camera.getCapabilities()?.has('clips')).toBeFalsy(); + expect(camera.getCapabilities()?.has('live')).toBeTruthy(); + expect(camera.getCapabilities()?.has('snapshots')).toBeFalsy(); + expect(camera.getCapabilities()?.has('recordings')).toBeFalsy(); expect(vi.mocked(getPTZInfo)).not.toBeCalled(); }); @@ -196,9 +190,7 @@ describe('FrigateCamera', () => { vi.mocked(getPTZInfo).mockRejectedValue(new Error()); await camera.initialize(createHASS(), mock()); - expect(camera.getCapabilities()).toEqual({ - ...nonBirdseyeBaseCapabilities, - }); + expect(camera.getCapabilities()?.has('ptz')).toBeFalsy(); expect(consoleSpy).toBeCalled(); }); @@ -220,13 +212,11 @@ describe('FrigateCamera', () => { }); await camera.initialize(createHASS(), mock()); - expect(camera.getCapabilities()).toEqual({ - ...nonBirdseyeBaseCapabilities, - ptz: { - panTilt: ['continuous'], - zoom: ['continuous'], - presets: ['preset01'], - }, + expect(camera.getCapabilities()?.has('ptz')).toBeTruthy(); + expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({ + panTilt: ['continuous'], + zoom: ['continuous'], + presets: ['preset01'], }); }); @@ -248,13 +238,11 @@ describe('FrigateCamera', () => { }); await camera.initialize(createHASS(), mock()); - expect(camera.getCapabilities()).toEqual({ - ...nonBirdseyeBaseCapabilities, - ptz: { - panTilt: ['relative'], - zoom: ['relative'], - presets: ['preset01'], - }, + expect(camera.getCapabilities()?.has('ptz')).toBeTruthy(); + expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({ + panTilt: ['relative'], + zoom: ['relative'], + presets: ['preset01'], }); }); }); diff --git a/tests/camera-manager/generic/engine-generic.test.ts b/tests/camera-manager/generic/engine-generic.test.ts index f0edd57e..1acf663b 100644 --- a/tests/camera-manager/generic/engine-generic.test.ts +++ b/tests/camera-manager/generic/engine-generic.test.ts @@ -34,15 +34,13 @@ describe('GenericCameraManagerEngine', () => { ); expect(camera.getConfig()).toEqual(config); - expect(camera.getCapabilities()).toEqual({ - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, - supportsClips: false, - supportsRecordings: false, - supportsSnapshots: false, - supportsTimeline: false, - }); + expect(camera.getCapabilities()).toBeTruthy(); + expect(camera.getCapabilities()?.has('favorite-events')).toBeFalsy(); + expect(camera.getCapabilities()?.has('favorite-recordings')).toBeFalsy(); + expect(camera.getCapabilities()?.has('seek')).toBeFalsy(); + expect(camera.getCapabilities()?.has('clips')).toBeFalsy(); + expect(camera.getCapabilities()?.has('recordings')).toBeFalsy(); + expect(camera.getCapabilities()?.has('snapshots')).toBeFalsy(); }); it('should generate default event query', () => { diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts index 5aa825c9..282cf68e 100644 --- a/tests/camera-manager/manager.test.ts +++ b/tests/camera-manager/manager.test.ts @@ -3,6 +3,7 @@ import add from 'date-fns/add'; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { Camera } from '../../src/camera-manager/camera'; +import { Capabilities } from '../../src/camera-manager/capabilities'; import { CameraManagerEngine } from '../../src/camera-manager/engine'; import { CameraManagerEngineFactory } from '../../src/camera-manager/engine-factory.js'; import { @@ -16,7 +17,6 @@ import { CameraEndpoints, CameraEndpointsContext, CameraEvent, - CameraManagerCameraCapabilities, CameraManagerCameraMetadata, CameraManagerMediaCapabilities, Engine, @@ -27,7 +27,7 @@ import { QueryResultsType, QueryType, } from '../../src/camera-manager/types'; -import { sortMedia } from '../../src/camera-manager/utils'; +import { sortMedia } from '../../src/camera-manager/utils/sort-media'; import { CardController } from '../../src/card-controller/controller'; import { CameraConfig } from '../../src/config/types'; import { EntityRegistryManager } from '../../src/utils/ha/entity-registry'; @@ -35,8 +35,8 @@ import { ViewMedia } from '../../src/view/media'; import { TestViewMedia, createCamera, - createCameraCapabilities, createCameraConfig, + createCapabilities, createCardAPI, createConfig, createHASS, @@ -219,7 +219,7 @@ describe('CameraManager', async () => { cameras: { config?: CameraConfig; engineType?: Engine | null; - capabilties?: CameraManagerCameraCapabilities; + capabilties?: Capabilities; }[] = [{}], factory?: CameraManagerEngineFactory, ): CameraManager => { @@ -249,7 +249,7 @@ describe('CameraManager', async () => { createCamera( cameraConfig, mockEngine, - camera.capabilties ?? createCameraCapabilities(), + camera.capabilties ?? createCapabilities(), ), ); } @@ -367,19 +367,6 @@ describe('CameraManager', async () => { ); }); - it('with no cameras', async () => { - const api = createCardAPI(); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); - - const manager = createCameraManager(api, mock(), []); - expect(await manager.initializeCamerasFromConfig()).toBeFalsy(); - expect(api.getMessageManager().setErrorIfHigherPriority).toBeCalledWith( - new Error( - 'No visible cameras found, you must configure at least one non-hidden camera', - ), - ); - }); - it('should pass events to triggers manager', async () => { const api = createCardAPI(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); @@ -1043,74 +1030,72 @@ describe('CameraManager', async () => { vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); - expect(manager.getCameraCapabilities('id')).toEqual(createCameraCapabilities()); + expect(manager.getCameraCapabilities('id')).toEqual(createCapabilities()); }); }); describe('should get aggregate camera capabilities', () => { it('without camera', () => { const manager = createCameraManager(createCardAPI()); - expect(manager.getAggregateCameraCapabilities()).toEqual({ - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, + const capabilities = manager.getAggregateCameraCapabilities(); - supportsClips: false, - supportsRecordings: false, - supportsSnapshots: false, - supportsTimeline: false, + expect(capabilities.has('favorite-events')).toBeFalsy(); + expect(capabilities.has('favorite-recordings')).toBeFalsy(); + expect(capabilities.has('seek')).toBeFalsy(); - supportsPTZ: false, - }); + expect(capabilities.has('live')).toBeFalsy(); + expect(capabilities.has('clips')).toBeFalsy(); + expect(capabilities.has('recordings')).toBeFalsy(); + expect(capabilities.has('snapshots')).toBeFalsy(); }); it('successfully', async () => { const api = createCardAPI(); const manager = createCameraManager(api, mock(), [ { - capabilties: { - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, + capabilties: new Capabilities({ + 'favorite-events': false, + 'favorite-recordings': false, + seek: false, - supportsClips: false, - supportsRecordings: false, - supportsSnapshots: false, - supportsTimeline: false, - }, + live: false, + clips: false, + recordings: false, + snapshots: false, + }), }, { config: createCameraConfig({ baseCameraConfig, id: 'another' }), - capabilties: { - canFavoriteEvents: true, - canFavoriteRecordings: true, - canSeek: true, + capabilties: new Capabilities({ + 'favorite-events': true, + 'favorite-recordings': true, + seek: true, - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, - supportsTimeline: true, + live: true, + clips: true, + recordings: true, + snapshots: true, - ptz: {}, - }, + ptz: { + panTilt: ['continuous'], + }, + }), }, ]); const hass = createHASS(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); - expect(manager.getAggregateCameraCapabilities()).toEqual({ - canFavoriteEvents: true, - canFavoriteRecordings: true, - canSeek: true, + const capabilities = manager.getAggregateCameraCapabilities(); - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, - supportsTimeline: true, + expect(capabilities.has('favorite-events')).toBeTruthy(); + expect(capabilities.has('favorite-recordings')).toBeTruthy(); + expect(capabilities.has('seek')).toBeTruthy(); - supportsPTZ: true, - }); + expect(capabilities.has('live')).toBeTruthy(); + expect(capabilities.has('clips')).toBeTruthy(); + expect(capabilities.has('recordings')).toBeTruthy(); + expect(capabilities.has('snapshots')).toBeTruthy(); }); }); diff --git a/tests/camera-manager/store.test.ts b/tests/camera-manager/store.test.ts index 02b37e51..5c218ffb 100644 --- a/tests/camera-manager/store.test.ts +++ b/tests/camera-manager/store.test.ts @@ -1,12 +1,13 @@ import { describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { Camera } from '../../src/camera-manager/camera.js'; +import { Capabilities } from '../../src/camera-manager/capabilities.js'; import { CameraManagerEngineFactory } from '../../src/camera-manager/engine-factory.js'; import { CameraManagerStore } from '../../src/camera-manager/store.js'; import { Engine } from '../../src/camera-manager/types.js'; import { EntityRegistryManager } from '../../src/utils/ha/entity-registry/index.js'; import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media.js'; -import { createCameraConfig, TestViewMedia } from '../test-utils.js'; +import { TestViewMedia, createCameraConfig } from '../test-utils.js'; describe('CameraManagerStore', async () => { const configVisible = createCameraConfig({ @@ -56,11 +57,6 @@ describe('CameraManagerStore', async () => { expect(store.getCameraCount()).toBe(2); }); - it('getVisibleCameraCount', async () => { - const store = setupStore(); - expect(store.getVisibleCameraCount()).toBe(1); - }); - describe('getDefaultCameraID', () => { it('with camera', async () => { const store = setupStore(); @@ -127,11 +123,6 @@ describe('CameraManagerStore', async () => { expect(store.getCameraIDs()).toEqual(new Set(['camera-visible', 'camera-hidden'])); }); - it('getVisibleCameraIDs', async () => { - const store = setupStore(); - expect(store.getVisibleCameraIDs()).toEqual(new Set(['camera-visible'])); - }); - it('reset', async () => { const store = setupStore(); const cameras = [...store.getCameras().values()]; @@ -139,7 +130,6 @@ describe('CameraManagerStore', async () => { await store.reset(); expect(store.getCameraCount()).toBe(0); - expect(store.getVisibleCameraCount()).toBe(0); for (const camera of cameras) { expect(camera.destroy).toBeCalled(); } @@ -258,5 +248,60 @@ describe('CameraManagerStore', async () => { ); expect(store.getAllDependentCameras('one')).toEqual(new Set(['one', 'two'])); }); + + it('should return cameras with specific capabilities', () => { + const store = new CameraManagerStore(); + store.addCamera( + new Camera( + createCameraConfig({ + id: 'one', + dependencies: { + all_cameras: true, + }, + }), + engineGeneric, + ), + ); + store.addCamera( + new Camera( + createCameraConfig({ + id: 'two', + }), + engineGeneric, + { + capabilities: new Capabilities({ + clips: true, + }), + }, + ), + ); + expect(store.getAllDependentCameras('one', 'clips')).toEqual(new Set(['two'])); + }); + }); + + it('getCameraIDsWithCapability', () => { + const store = new CameraManagerStore(); + store.addCamera( + new Camera( + createCameraConfig({ + id: 'one', + }), + engineGeneric, + { + capabilities: new Capabilities({ + clips: true, + }), + }, + ), + ); + store.addCamera( + new Camera( + createCameraConfig({ + id: 'two', + }), + engineGeneric, + ), + ); + expect(store.getCameraIDsWithCapability('clips')).toEqual(new Set(['one'])); }); }); diff --git a/tests/camera-manager/utils.test.ts b/tests/camera-manager/utils.test.ts deleted file mode 100644 index 561d1df8..00000000 --- a/tests/camera-manager/utils.test.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { describe, expect, it, vi } from 'vitest'; -import { - capEndDate, - convertRangeToCacheFriendlyTimes, - getCameraEntityFromConfig, - getDefaultGo2RTCEndpoint, - sortMedia, -} from '../../src/camera-manager/utils.js'; -import { CameraConfig, cameraConfigSchema } from '../../src/config/types.js'; -import { TestViewMedia, createCameraConfig } from '../test-utils.js'; - -describe('convertRangeToCacheFriendlyTimes', () => { - it('should return cache friendly within hour range', () => { - expect( - convertRangeToCacheFriendlyTimes({ - start: new Date('2023-04-29T14:01:02'), - end: new Date('2023-04-29T14:11:03'), - }), - ).toEqual({ - start: new Date('2023-04-29T14:00:00'), - end: new Date('2023-04-29T14:59:59.999'), - }); - }); - - it('should return cache friendly within day range', () => { - expect( - convertRangeToCacheFriendlyTimes({ - start: new Date('2023-04-29T14:01:02'), - end: new Date('2023-04-29T15:11:03'), - }), - ).toEqual({ - start: new Date('2023-04-29T00:00:00'), - end: new Date('2023-04-29T23:59:59.999'), - }); - }); - - it('should cap end date', () => { - vi.useFakeTimers(); - vi.setSystemTime(new Date('2023-04-29T14:25')); - expect( - convertRangeToCacheFriendlyTimes( - { - start: new Date('2023-04-29T14:01:02'), - end: new Date('2023-04-29T14:11:03'), - }, - { endCap: true }, - ), - ).toEqual({ - start: new Date('2023-04-29T14:00:00'), - end: new Date('2023-04-29T14:25:59.999'), - }); - vi.useRealTimers(); - }); -}); - -describe('capEndDate', () => { - it('should cap end date', () => { - const fakeNow = new Date('2023-04-29T14:25'); - vi.useFakeTimers(); - vi.setSystemTime(fakeNow); - - expect(capEndDate(new Date('2023-04-29T15:02'))).toEqual(fakeNow); - - vi.useRealTimers(); - }); - - it('should not cap end date', () => { - vi.useFakeTimers(); - vi.setSystemTime(new Date('2023-04-29T14:25')); - - const testDate = new Date('2023-04-29T14:24'); - expect(capEndDate(testDate)).toEqual(testDate); - - vi.useRealTimers(); - }); -}); - -describe('sortMedia', () => { - const media_1 = new TestViewMedia({ - id: 'id-1', - startTime: new Date('2023-04-29T14:25'), - cameraID: 'camera-1', - }); - const media_2 = new TestViewMedia({ - id: 'id-2', - startTime: new Date('2023-04-29T14:26'), - cameraID: 'camera-1', - }); - const media_3_dup_id = new TestViewMedia({ - id: 'id-2', - startTime: new Date('2023-04-29T14:26'), - cameraID: 'camera-1', - }); - const media_4_no_id = new TestViewMedia({ - id: null, - startTime: new Date('2023-04-29T14:27'), - cameraID: 'camera-1', - }); - - it('should sort sorted media', () => { - const media = [media_1, media_2]; - expect(sortMedia(media)).toEqual(media); - }); - it('should sort unsorted media', () => { - expect(sortMedia([media_2, media_1])).toEqual([media_1, media_2]); - }); - it('should remove duplicate id', () => { - expect(sortMedia([media_1, media_2, media_3_dup_id])).toEqual([media_1, media_2]); - }); - it('should sort by id when time not available', () => { - expect( - sortMedia([ - new TestViewMedia({ id: 'snake' }), - new TestViewMedia({ id: 'zebra' }), - new TestViewMedia({ id: 'aardvark' }), - ]), - ).toEqual([ - new TestViewMedia({ id: 'aardvark' }), - new TestViewMedia({ id: 'snake' }), - new TestViewMedia({ id: 'zebra' }), - ]); - }); - it('should remove de-duplicate by object if no id', () => { - expect(sortMedia([media_1, media_2, media_4_no_id, media_4_no_id])).toEqual([ - media_1, - media_2, - media_4_no_id, - ]); - }); -}); - -describe('getCameraEntityFromConfig', () => { - const createCameraConfig = (config: Partial): CameraConfig => { - return cameraConfigSchema.parse(config); - }; - - it('should get camera_entity', () => { - expect(getCameraEntityFromConfig(createCameraConfig({ camera_entity: 'foo' }))).toBe( - 'foo', - ); - }); - it('should get camera_entity from webrtc_card config', () => { - expect( - getCameraEntityFromConfig(createCameraConfig({ webrtc_card: { entity: 'bar' } })), - ).toBe('bar'); - }); - it('should get no camera_entity', () => { - expect(getCameraEntityFromConfig(createCameraConfig({}))).toBeNull(); - }); -}); - -describe('getDefaultGo2RTCEndpoint', () => { - it('with local configuration', () => { - expect( - getDefaultGo2RTCEndpoint( - createCameraConfig({ - go2rtc: { - stream: 'stream', - url: '/local/path', - }, - }), - ), - ).toEqual({ - endpoint: '/local/path/api/ws?src=stream', - sign: true, - }); - }); - - it('with remote configuration', () => { - expect( - getDefaultGo2RTCEndpoint( - createCameraConfig({ - go2rtc: { - stream: 'stream', - url: 'https://my-custom-go2rtc', - }, - }), - ), - ).toEqual({ - endpoint: 'https://my-custom-go2rtc/api/ws?src=stream', - sign: false, - }); - }); - - it('without configuration', () => { - expect(getDefaultGo2RTCEndpoint(createCameraConfig())).toBeNull(); - }); -}); diff --git a/tests/camera-manager/utils/camera-entity-from-config.test.ts b/tests/camera-manager/utils/camera-entity-from-config.test.ts new file mode 100644 index 00000000..ab2a63c3 --- /dev/null +++ b/tests/camera-manager/utils/camera-entity-from-config.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, it } from 'vitest'; +import { getCameraEntityFromConfig } from '../../../src/camera-manager/utils/camera-entity-from-config.js'; +import { CameraConfig, cameraConfigSchema } from '../../../src/config/types.js'; + +describe('getCameraEntityFromConfig', () => { + const createCameraConfig = (config: Partial): CameraConfig => { + return cameraConfigSchema.parse(config); + }; + + it('should get camera_entity', () => { + expect(getCameraEntityFromConfig(createCameraConfig({ camera_entity: 'foo' }))).toBe( + 'foo', + ); + }); + it('should get camera_entity from webrtc_card config', () => { + expect( + getCameraEntityFromConfig(createCameraConfig({ webrtc_card: { entity: 'bar' } })), + ).toBe('bar'); + }); + it('should get no camera_entity', () => { + expect(getCameraEntityFromConfig(createCameraConfig({}))).toBeNull(); + }); +}); diff --git a/tests/camera-manager/utils/cap-end-date.test.ts b/tests/camera-manager/utils/cap-end-date.test.ts new file mode 100644 index 00000000..5976f8c1 --- /dev/null +++ b/tests/camera-manager/utils/cap-end-date.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it, vi } from 'vitest'; +import { capEndDate } from '../../../src/camera-manager/utils/cap-end-date'; + +describe('capEndDate', () => { + it('should cap end date', () => { + const fakeNow = new Date('2023-04-29T14:25'); + vi.useFakeTimers(); + vi.setSystemTime(fakeNow); + + expect(capEndDate(new Date('2023-04-29T15:02'))).toEqual(fakeNow); + + vi.useRealTimers(); + }); + + it('should not cap end date', () => { + vi.useFakeTimers(); + vi.setSystemTime(new Date('2023-04-29T14:25')); + + const testDate = new Date('2023-04-29T14:24'); + expect(capEndDate(testDate)).toEqual(testDate); + + vi.useRealTimers(); + }); +}); diff --git a/tests/camera-manager/utils/go2rtc-endpoint.test.ts b/tests/camera-manager/utils/go2rtc-endpoint.test.ts new file mode 100644 index 00000000..62d913fb --- /dev/null +++ b/tests/camera-manager/utils/go2rtc-endpoint.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, it } from 'vitest'; +import { getDefaultGo2RTCEndpoint } from '../../../src/camera-manager/utils/go2rtc-endpoint.js'; +import { createCameraConfig } from '../../test-utils.js'; + +describe('getDefaultGo2RTCEndpoint', () => { + it('with local configuration', () => { + expect( + getDefaultGo2RTCEndpoint( + createCameraConfig({ + go2rtc: { + stream: 'stream', + url: '/local/path', + }, + }), + ), + ).toEqual({ + endpoint: '/local/path/api/ws?src=stream', + sign: true, + }); + }); + + it('with remote configuration', () => { + expect( + getDefaultGo2RTCEndpoint( + createCameraConfig({ + go2rtc: { + stream: 'stream', + url: 'https://my-custom-go2rtc', + }, + }), + ), + ).toEqual({ + endpoint: 'https://my-custom-go2rtc/api/ws?src=stream', + sign: false, + }); + }); + + it('without configuration', () => { + expect(getDefaultGo2RTCEndpoint(createCameraConfig())).toBeNull(); + }); +}); diff --git a/tests/camera-manager/utils/range-to-cache-friendly.test.ts b/tests/camera-manager/utils/range-to-cache-friendly.test.ts new file mode 100644 index 00000000..0e87b064 --- /dev/null +++ b/tests/camera-manager/utils/range-to-cache-friendly.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, it, vi } from 'vitest'; +import { convertRangeToCacheFriendlyTimes } from '../../../src/camera-manager/utils/range-to-cache-friendly'; + +describe('convertRangeToCacheFriendlyTimes', () => { + it('should return cache friendly within hour range', () => { + expect( + convertRangeToCacheFriendlyTimes({ + start: new Date('2023-04-29T14:01:02'), + end: new Date('2023-04-29T14:11:03'), + }), + ).toEqual({ + start: new Date('2023-04-29T14:00:00'), + end: new Date('2023-04-29T14:59:59.999'), + }); + }); + + it('should return cache friendly within day range', () => { + expect( + convertRangeToCacheFriendlyTimes({ + start: new Date('2023-04-29T14:01:02'), + end: new Date('2023-04-29T15:11:03'), + }), + ).toEqual({ + start: new Date('2023-04-29T00:00:00'), + end: new Date('2023-04-29T23:59:59.999'), + }); + }); + + it('should cap end date', () => { + vi.useFakeTimers(); + vi.setSystemTime(new Date('2023-04-29T14:25')); + expect( + convertRangeToCacheFriendlyTimes( + { + start: new Date('2023-04-29T14:01:02'), + end: new Date('2023-04-29T14:11:03'), + }, + { endCap: true }, + ), + ).toEqual({ + start: new Date('2023-04-29T14:00:00'), + end: new Date('2023-04-29T14:25:59.999'), + }); + vi.useRealTimers(); + }); +}); diff --git a/tests/camera-manager/utils/sort-media.test.ts b/tests/camera-manager/utils/sort-media.test.ts new file mode 100644 index 00000000..f6cb8f80 --- /dev/null +++ b/tests/camera-manager/utils/sort-media.test.ts @@ -0,0 +1,57 @@ +import { describe, expect, it } from 'vitest'; +import { sortMedia } from '../../../src/camera-manager/utils/sort-media.js'; +import { TestViewMedia } from '../../test-utils.js'; + +describe('sortMedia', () => { + const media_1 = new TestViewMedia({ + id: 'id-1', + startTime: new Date('2023-04-29T14:25'), + cameraID: 'camera-1', + }); + const media_2 = new TestViewMedia({ + id: 'id-2', + startTime: new Date('2023-04-29T14:26'), + cameraID: 'camera-1', + }); + const media_3_dup_id = new TestViewMedia({ + id: 'id-2', + startTime: new Date('2023-04-29T14:26'), + cameraID: 'camera-1', + }); + const media_4_no_id = new TestViewMedia({ + id: null, + startTime: new Date('2023-04-29T14:27'), + cameraID: 'camera-1', + }); + + it('should sort sorted media', () => { + const media = [media_1, media_2]; + expect(sortMedia(media)).toEqual(media); + }); + it('should sort unsorted media', () => { + expect(sortMedia([media_2, media_1])).toEqual([media_1, media_2]); + }); + it('should remove duplicate id', () => { + expect(sortMedia([media_1, media_2, media_3_dup_id])).toEqual([media_1, media_2]); + }); + it('should sort by id when time not available', () => { + expect( + sortMedia([ + new TestViewMedia({ id: 'snake' }), + new TestViewMedia({ id: 'zebra' }), + new TestViewMedia({ id: 'aardvark' }), + ]), + ).toEqual([ + new TestViewMedia({ id: 'aardvark' }), + new TestViewMedia({ id: 'snake' }), + new TestViewMedia({ id: 'zebra' }), + ]); + }); + it('should remove de-duplicate by object if no id', () => { + expect(sortMedia([media_1, media_2, media_4_no_id, media_4_no_id])).toEqual([ + media_1, + media_2, + media_4_no_id, + ]); + }); +}); diff --git a/tests/card-controller/view-manager.test.ts b/tests/card-controller/view-manager.test.ts index 738b5919..9fd7b5d4 100644 --- a/tests/card-controller/view-manager.test.ts +++ b/tests/card-controller/view-manager.test.ts @@ -7,10 +7,9 @@ import { EventMediaQueries } from '../../src/view/media-queries'; import { MediaQueriesResults } from '../../src/view/media-queries-results'; import { View } from '../../src/view/view'; import { - createAggregateCameraCapabilities, - createCameraCapabilities, createCameraConfig, createCameraManager, + createCapabilities, createCardAPI, createConfig, createHASS, @@ -120,6 +119,7 @@ describe('ViewManager.setViewDefault', () => { createStore([ { cameraID: 'camera', + capabilities: createCapabilities({ live: true }), }, ]), ); @@ -150,9 +150,11 @@ describe('ViewManager.setViewDefault', () => { createStore([ { cameraID: 'camera_1', + capabilities: createCapabilities({ live: true }), }, { cameraID: 'camera_2', + capabilities: createCapabilities({ live: true }), }, ]), ); @@ -186,9 +188,11 @@ describe('ViewManager.setViewDefault', () => { createStore([ { cameraID: 'camera.kitchen', + capabilities: createCapabilities({ live: true }), }, { cameraID: 'camera.office', + capabilities: createCapabilities({ live: true }), }, ]), ); @@ -216,12 +220,13 @@ describe('ViewManager.setViewByParameters', () => { createStore([ { cameraID: 'camera.kitchen', + capabilities: createCapabilities({ clips: true }), }, ]), ); vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ - supportsClips: true, + createCapabilities({ + clips: true, }), ); @@ -242,15 +247,17 @@ describe('ViewManager.setViewByParameters', () => { createStore([ { cameraID: 'camera.kitchen', + capabilities: createCapabilities({ clips: true }), }, { cameraID: 'camera.office', + capabilities: createCapabilities({ clips: true }), }, ]), ); vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ - supportsClips: true, + createCapabilities({ + clips: true, }), ); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); @@ -276,6 +283,7 @@ describe('ViewManager.setViewByParameters', () => { createStore([ { cameraID: 'camera.kitchen', + capabilities: createCapabilities({ live: true }), }, ]), ); @@ -302,49 +310,102 @@ describe('ViewManager.setViewByParameters', () => { expect(manager.getView()).toBeNull(); }); - it('should not set view by parameters without visible cameras', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - config: createCameraConfig({ - hide: true, - }), - }, - ]), - ); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - - const manager = new ViewManager(api); - manager.setViewByParameters({ - viewName: 'live', - }); - - expect(manager.getView()).toBeNull(); - }); - describe('should handle unsupported view', () => { - it('without failsafe', () => { + it('without camera without failsafe', () => { const api = createCardAPI(); vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); vi.mocked(api.getCameraManager().getStore).mockReturnValue( createStore([ { cameraID: 'camera.kitchen', + capabilities: createCapabilities({ snapshots: false }), + }, + ]), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + + const manager = new ViewManager(api); + manager.setViewByParameters({ + // Since no camera is specified, and no camera supports the capabilities + // necessary for this view, the view will be null. + viewName: 'snapshots', + }); + + expect(manager.getView()).toBeNull(); + }); + + it('without camera with failsafe', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: createCapabilities({ snapshots: false }), + }, + { + cameraID: 'camera.office', + // No capabilities. + capabilities: null, + }, + ]), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + + const manager = new ViewManager(api); + manager.setViewByParameters({ + // Since no camera is specified, and no camera supports the capabilities + // necessary for this view, and since failSafe is specified, an error + // will be shown. + viewName: 'snapshots', + failSafe: true, + }); + + expect(manager.getView()).toBeNull(); + expect(manager.hasView()).toBeFalsy(); + expect(api.getMessageManager().setMessageIfHigherPriority).toBeCalledWith( + expect.objectContaining({ + type: 'error', + message: 'No cameras support this view', + context: { + view: 'snapshots', + cameras_capabilities: { + 'camera.kitchen': { + 'favorite-events': false, + 'favorite-recordings': false, + clips: false, + live: false, + recordings: false, + seek: false, + snapshots: false, + }, + }, + }, + }), + ); + }); + + it('with camera without failsafe', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: createCapabilities({ snapshots: false }), }, ]), ); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ - supportsSnapshots: false, + createCapabilities({ + snapshots: false, }), ); const manager = new ViewManager(api); manager.setViewByParameters({ + cameraID: 'camera.kitchen', viewName: 'snapshots', }); @@ -352,25 +413,28 @@ describe('ViewManager.setViewByParameters', () => { expect(manager.getView()).toBeNull(); }); - it('with failsafe', () => { + it('with camera with failsafe', () => { const api = createCardAPI(); vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); vi.mocked(api.getCameraManager().getStore).mockReturnValue( createStore([ { cameraID: 'camera.kitchen', + capabilities: createCapabilities({ snapshots: false, live: true }), }, ]), ); vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ - supportsSnapshots: false, + createCapabilities({ + snapshots: false, + live: true, }), ); const manager = new ViewManager(api); manager.setViewByParameters({ + cameraID: 'camera.kitchen', viewName: 'snapshots', failSafe: true, }); @@ -378,6 +442,55 @@ describe('ViewManager.setViewByParameters', () => { expect(manager.hasView()).toBeTruthy(); expect(manager.getView()?.view).toBe('live'); }); + + it('with camera with failsafe when live unsupported', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: createCapabilities({ snapshots: false, live: false }), + }, + ]), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( + createCapabilities({ + snapshots: false, + live: false, + }), + ); + + const manager = new ViewManager(api); + manager.setViewByParameters({ + cameraID: 'camera.kitchen', + viewName: 'snapshots', + failSafe: true, + }); + + expect(manager.hasView()).toBeFalsy(); + expect(manager.getView()).toBeNull(); + expect(api.getMessageManager().setMessageIfHigherPriority).toBeCalledWith( + expect.objectContaining({ + type: 'error', + message: 'The selected camera does not support this view', + context: { + view: 'snapshots', + camera: 'camera.kitchen', + camera_capabilities: { + 'favorite-events': false, + 'favorite-recordings': false, + clips: false, + live: false, + recordings: false, + seek: false, + snapshots: false, + }, + }, + }), + ); + }); }); describe('should set view by parameters and respect display mode in config for view', () => { @@ -394,14 +507,21 @@ describe('ViewManager.setViewByParameters', () => { createStore([ { cameraID: 'camera.kitchen', + capabilities: createCapabilities({ + live: true, + clips: true, + recordings: true, + snapshots: true, + }), }, ]), ); vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, + createCapabilities({ + live: true, + clips: true, + recordings: true, + snapshots: true, }), ); @@ -445,14 +565,21 @@ describe('ViewManager.setViewByParameters', () => { createStore([ { cameraID: 'camera.kitchen', + capabilities: createCapabilities({ + live: true, + clips: true, + recordings: true, + snapshots: true, + }), }, ]), ); vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, + createCapabilities({ + live: true, + clips: true, + recordings: true, + snapshots: true, }), ); @@ -502,18 +629,18 @@ describe('ViewManager.setViewWithNewDisplayMode', () => { createStore([ { cameraID: 'camera.kitchen', - capabilities: createCameraCapabilities({ - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, + capabilities: createCapabilities({ + clips: true, + recordings: true, + snapshots: true, }), }, { cameraID: 'camera.office', - capabilities: createCameraCapabilities({ - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, + capabilities: createCapabilities({ + clips: true, + recordings: true, + snapshots: true, }), }, ]), @@ -556,18 +683,18 @@ describe('ViewManager.setViewWithNewDisplayMode', () => { createStore([ { cameraID: 'camera.kitchen', - capabilities: createCameraCapabilities({ - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, + capabilities: createCapabilities({ + clips: true, + recordings: true, + snapshots: true, }), }, { cameraID: 'camera.office', - capabilities: createCameraCapabilities({ - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, + capabilities: createCapabilities({ + clips: true, + recordings: true, + snapshots: true, }), }, ]), @@ -614,18 +741,18 @@ describe('ViewManager.setViewWithNewDisplayMode', () => { createStore([ { cameraID: 'camera.kitchen', - capabilities: createCameraCapabilities({ - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, + capabilities: createCapabilities({ + clips: true, + recordings: true, + snapshots: true, }), }, { cameraID: 'camera.office', - capabilities: createCameraCapabilities({ - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, + capabilities: createCapabilities({ + clips: true, + recordings: true, + snapshots: true, }), }, ]), @@ -662,18 +789,18 @@ describe('ViewManager.setViewWithNewDisplayMode', () => { createStore([ { cameraID: 'camera.kitchen', - capabilities: createCameraCapabilities({ - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, + capabilities: createCapabilities({ + clips: true, + recordings: true, + snapshots: true, }), }, { cameraID: 'camera.office', - capabilities: createCameraCapabilities({ - supportsClips: true, - supportsRecordings: true, - supportsSnapshots: true, + capabilities: createCapabilities({ + clips: true, + recordings: true, + snapshots: true, }), }, ]), @@ -873,7 +1000,7 @@ describe('ViewManager.setViewWithSubstream', () => { describe('ViewManager.isViewSupportedByCamera', () => { it.each([ - ['live' as const, true], + ['live' as const, false], ['image' as const, true], ['diagnostics' as const, true], ['clip' as const, false], @@ -891,15 +1018,15 @@ describe('ViewManager.isViewSupportedByCamera', () => { createStore([ { cameraID: 'camera.kitchen', - capabilities: { - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, - supportsClips: false, - supportsRecordings: false, - supportsSnapshots: false, - supportsTimeline: false, - }, + capabilities: createCapabilities({ + live: false, + 'favorite-events': false, + 'favorite-recordings': false, + seek: false, + clips: false, + recordings: false, + snapshots: false, + }), }, ]), ); diff --git a/tests/components-lib/media-filter-controller.test.ts b/tests/components-lib/media-filter-controller.test.ts index 3ade7447..e88052e3 100644 --- a/tests/components-lib/media-filter-controller.test.ts +++ b/tests/components-lib/media-filter-controller.test.ts @@ -3,6 +3,7 @@ import startOfDay from 'date-fns/startOfDay'; import sub from 'date-fns/sub'; import { LitElement } from 'lit'; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { Capabilities } from '../../src/camera-manager/capabilities'; import { CameraManagerStore } from '../../src/camera-manager/store'; import { QueryType } from '../../src/camera-manager/types'; import { @@ -10,21 +11,21 @@ import { MediaFilterCoreDefaults, MediaFilterCoreFavoriteSelection, MediaFilterCoreWhen, - MediaFilterMediaType + MediaFilterMediaType, } from '../../src/components-lib/media-filter-controller'; import { executeMediaQueryForViewWithErrorDispatching } from '../../src/utils/media-to-view'; import { EventMediaQueries, MediaQueries, - RecordingMediaQueries + RecordingMediaQueries, } from '../../src/view/media-queries'; import { - createAggregateCameraCapabilities, createCameraConfig, createCameraManager, + createCapabilities, createPerformanceConfig, createStore, - createView + createView, } from '../test-utils'; vi.mock('../../src/utils/media-to-view'); @@ -35,13 +36,22 @@ const createHost = (): LitElement => { return host; }; -const createCameraStore = (): CameraManagerStore => { +const createCameraStore = (options?: { + capabilities: Capabilities; +}): CameraManagerStore => { return createStore([ { cameraID: 'camera.kitchen', config: createCameraConfig({ camera_entity: 'camera.kitchen', }), + capabilities: + options?.capabilities ?? + new Capabilities({ + clips: true, + snapshots: true, + recordings: true, + }), }, ]); }; @@ -152,6 +162,27 @@ describe('MediaFilterController', () => { ]); }); + it('with camera that does not support media', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getCameraMetadata).mockReturnValue({ + title: 'Kitchen Camera', + icon: 'mdi:camera', + }); + vi.mocked(cameraManager.getStore).mockReturnValue( + createCameraStore({ + capabilities: new Capabilities({ + clips: false, + snapshots: false, + recordings: false, + }), + }), + ); + + const controller = new MediaFilterController(createHost()); + controller.computeCameraOptions(cameraManager); + expect(controller.getCameraOptions()).toEqual([]); + }); + it('without camera metadata', () => { const cameraManager = createCameraManager(); vi.mocked(cameraManager.getCameraMetadata).mockReturnValue(null); @@ -297,7 +328,7 @@ describe('MediaFilterController', () => { const view = createView({ query: new EventMediaQueries() }); const cameraManager = createCameraManager(); vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ canFavoriteEvents: true }), + createCapabilities({ 'favorite-events': true }), ); const controller = new MediaFilterController(createHost()); @@ -310,7 +341,7 @@ describe('MediaFilterController', () => { const view = createView({ query: new RecordingMediaQueries() }); const cameraManager = createCameraManager(); vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( - createAggregateCameraCapabilities({ canFavoriteRecordings: true }), + createCapabilities({ 'favorite-recordings': true }), ); const controller = new MediaFilterController(createHost()); @@ -915,7 +946,7 @@ describe('MediaFilterController', () => { }, ]), { - mediaType: MediaFilterMediaType.Recordings + mediaType: MediaFilterMediaType.Recordings, }, ], ])( diff --git a/tests/components-lib/menu-button-controller.test.ts b/tests/components-lib/menu-button-controller.test.ts index e72138f4..305233f5 100644 --- a/tests/components-lib/menu-button-controller.test.ts +++ b/tests/components-lib/menu-button-controller.test.ts @@ -18,7 +18,7 @@ import { ViewMedia } from '../../src/view/media'; import { MediaQueriesResults } from '../../src/view/media-queries-results'; import { View } from '../../src/view/view'; import { - createCameraCapabilities, + createCapabilities, createCameraConfig, createCameraManager, createCardAPI, @@ -108,7 +108,11 @@ describe('MenuButtonController', () => { it('with multiple cameras', () => { const cameraManager = createCameraManager(); vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([{ cameraID: 'camera-1' }, { cameraID: 'camera-2' }]), + createStore([ + { cameraID: 'camera-1', capabilities: createCapabilities({ menu: true }) }, + { cameraID: 'camera-2', capabilities: createCapabilities({ menu: true }) }, + { cameraID: 'camera-3', capabilities: createCapabilities({ menu: false }) }, + ]), ); vi.mocked(cameraManager).getCameraMetadata.mockReturnValue({ title: 'title', @@ -181,7 +185,10 @@ describe('MenuButtonController', () => { cameraID: 'camera-1', config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), }, - { cameraID: 'camera-2' }, + { + cameraID: 'camera-2', + capabilities: createCapabilities({ substream: true }), + }, ]), ); const buttons = calculateButtons(controller, { cameraManager: cameraManager }); @@ -208,7 +215,10 @@ describe('MenuButtonController', () => { cameraID: 'camera-1', config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), }, - { cameraID: 'camera-2' }, + { + cameraID: 'camera-2', + capabilities: createCapabilities({ substream: true }), + }, ]), ); const view = createView({ @@ -248,18 +258,21 @@ describe('MenuButtonController', () => { camera_entity: 'camera.1', dependencies: { cameras: ['camera-2', 'camera-3'] }, }), + capabilities: createCapabilities({ substream: true }), }, { cameraID: 'camera-2', config: createCameraConfig({ camera_entity: 'camera.2', }), + capabilities: createCapabilities({ substream: true }), }, { cameraID: 'camera-3', config: createCameraConfig({ camera_entity: 'camera.3', }), + capabilities: createCapabilities({ substream: true }), }, ]), ); @@ -340,18 +353,21 @@ describe('MenuButtonController', () => { camera_entity: 'camera.1', dependencies: { cameras: ['camera-2', 'camera-3'] }, }), + capabilities: createCapabilities({ substream: true }), }, { cameraID: 'camera-2', config: createCameraConfig({ camera_entity: 'camera.2', }), + capabilities: createCapabilities({ substream: true }), }, { cameraID: 'camera-3', config: createCameraConfig({ camera_entity: 'camera.3', }), + capabilities: createCapabilities({ substream: true }), }, ]), ); @@ -1207,10 +1223,17 @@ describe('MenuButtonController', () => { it.each([['single' as const], ['grid' as const]])( '%s', (displayMode: ViewDisplayMode) => { - const view = createView({ view: 'live', displayMode: displayMode }); + const view = createView({ + camera: 'camera-1', + view: 'live', + displayMode: displayMode, + }); const cameraManager = createCameraManager(); vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([{ cameraID: 'camera-1' }, { cameraID: 'camera-2' }]), + createStore([ + { cameraID: 'camera-1', capabilities: createCapabilities({ live: true }) }, + { cameraID: 'camera-2', capabilities: createCapabilities({ live: true }) }, + ]), ); expect( @@ -1239,7 +1262,7 @@ describe('MenuButtonController', () => { it('when the selected camera is not PTZ enabled', () => { const cameraManager = createCameraManager(); vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( - createCameraCapabilities(), + createCapabilities(), ); const buttons = calculateButtons(controller, { cameraManager: cameraManager }); @@ -1264,7 +1287,7 @@ describe('MenuButtonController', () => { it('when the selected camera is PTZ enabled', () => { const cameraManager = createCameraManager(); vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( - createCameraCapabilities({ ptz: {} }), + createCapabilities({ ptz: { panTilt: ['relative'] } }), ); const buttons = calculateButtons(controller, { cameraManager: cameraManager }); @@ -1288,7 +1311,7 @@ describe('MenuButtonController', () => { it('when the context has PTZ visiblity turned off', () => { const cameraManager = createCameraManager(); vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( - createCameraCapabilities({ ptz: {} }), + createCapabilities({ ptz: { panTilt: ['relative'] } }), ); const view = createView({ camera: 'camera-1', @@ -1328,9 +1351,9 @@ describe('MenuButtonController', () => { vi.mocked(cameraManager.getCameraCapabilities).mockImplementation( (cameraID: string) => { if (cameraID === 'camera-2') { - return createCameraCapabilities({ ptz: {} }); + return createCapabilities({ ptz: { panTilt: ['relative'] } }); } - return createCameraCapabilities(); + return createCapabilities(); }, ); const view = createView({ diff --git a/tests/components-lib/ptz-controller.test.ts b/tests/components-lib/ptz-controller.test.ts index 11f047a4..c64b792f 100644 --- a/tests/components-lib/ptz-controller.test.ts +++ b/tests/components-lib/ptz-controller.test.ts @@ -10,7 +10,7 @@ import { getActionConfigGivenAction, } from '../../src/utils/action.js'; import { - createCameraCapabilities, + createCapabilities, createCameraManager, createHASS, } from '../test-utils'; @@ -145,7 +145,7 @@ describe('PTZController', () => { const cameraManager = createCameraManager(); vi.mocked(cameraManager).getCameraCapabilities.mockReturnValue( - createCameraCapabilities({ + createCapabilities({ ptz: { panTilt: ['continuous'], zoom: ['continuous'], @@ -185,7 +185,7 @@ describe('PTZController', () => { const cameraManager = createCameraManager(); vi.mocked(cameraManager).getCameraCapabilities.mockReturnValue( - createCameraCapabilities({ + createCapabilities({ ptz: { panTilt: ['relative'], zoom: ['relative'], @@ -210,7 +210,7 @@ describe('PTZController', () => { const cameraManager = createCameraManager(); vi.mocked(cameraManager).getCameraCapabilities.mockReturnValue( - createCameraCapabilities({ + createCapabilities({ ptz: { presets: ['preset-foo'], }, @@ -237,7 +237,7 @@ describe('PTZController', () => { ['down' as const], ['zoom_in' as const], ['zoom_out' as const], - ])('%s', (actionName: PTZControlAction) => { + ])('configured %s', (actionName: PTZControlAction) => { const controller = new PTZController(document.createElement('div')); controller.setConfig( createConfig({ @@ -253,7 +253,7 @@ describe('PTZController', () => { }); }); - it('home', () => { + it('configured home', () => { const controller = new PTZController(document.createElement('div')); controller.setConfig( createConfig({ diff --git a/tests/config-mgmt.test.ts b/tests/config-mgmt.test.ts index 424821cf..3961f0e0 100644 --- a/tests/config-mgmt.test.ts +++ b/tests/config-mgmt.test.ts @@ -1804,245 +1804,9 @@ describe('should handle version specific upgrades', () => { ); }); }); - }); - describe('from condition object to condition array', () => { - describe('with view condition', () => { - it('elements', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - conditions: { - view: ['clips', 'snapshots'], - }, - }, - { - conditions: 'not an object', - }, - ], - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - conditions: [ - { - condition: 'view' as const, - views: ['clips', 'snapshots'], - }, - ], - }, - { - conditions: 'not an object', - }, - ], - }); - }); - - it('overrides', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - overrides: [ - { - conditions: { - view: ['clips', 'snapshots'], - }, - overrides: { - view: { - default: 'clips', - }, - }, - }, - ], - }; - - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - overrides: [ - { - conditions: [ - { - condition: 'view' as const, - views: ['clips', 'snapshots'], - }, - ], - overrides: { - view: { - default: 'clips', - }, - }, - }, - ], - }); - }); - - it('automations', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - automations: [ - { - conditions: { - view: ['clips', 'snapshots'], - }, - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, - }, - ], - }; - - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - automations: [ - { - conditions: [ - { - condition: 'view' as const, - views: ['clips', 'snapshots'], - }, - ], - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, - }, - ], - }); - }); - }); - - describe('with camera condition', () => { - it('elements', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - conditions: { - camera: ['camera_1', 'camera_2'], - }, - }, - { - conditions: 'not an object', - }, - ], - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - conditions: [ - { - condition: 'camera' as const, - cameras: ['camera_1', 'camera_2'], - }, - ], - }, - { - conditions: 'not an object', - }, - ], - }); - }); - - it('overrides', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - overrides: [ - { - conditions: { - camera: ['camera_1', 'camera_2'], - }, - overrides: { - view: { - default: 'clips', - }, - }, - }, - ], - }; - - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - overrides: [ - { - conditions: [ - { - condition: 'camera' as const, - cameras: ['camera_1', 'camera_2'], - }, - ], - overrides: { - view: { - default: 'clips', - }, - }, - }, - ], - }); - }); - - it('automations', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - automations: [ - { - conditions: { - camera: ['camera_1', 'camera_2'], - }, - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, - }, - ], - }; - - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - automations: [ - { - conditions: [ - { - condition: 'camera' as const, - cameras: ['camera_1', 'camera_2'], - }, - ], - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, - }, - ], - }); - }); - }); - - describe('with boolean conditions', () => { - describe.each([ - ['fullscreen' as const], - ['expand' as const], - ['media_loaded' as const], - ])('%s', (condition: string) => { + describe('from condition object to condition array', () => { + describe('with view condition', () => { it('elements', () => { const config = { type: 'custom:frigate-card', @@ -2050,7 +1814,7 @@ describe('should handle version specific upgrades', () => { elements: [ { conditions: { - [condition]: true, + view: ['clips', 'snapshots'], }, }, { @@ -2066,8 +1830,8 @@ describe('should handle version specific upgrades', () => { { conditions: [ { - condition: condition, - [condition]: true, + condition: 'view' as const, + views: ['clips', 'snapshots'], }, ], }, @@ -2085,7 +1849,7 @@ describe('should handle version specific upgrades', () => { overrides: [ { conditions: { - [condition]: true, + view: ['clips', 'snapshots'], }, overrides: { view: { @@ -2104,8 +1868,8 @@ describe('should handle version specific upgrades', () => { { conditions: [ { - condition: condition, - [condition]: true, + condition: 'view' as const, + views: ['clips', 'snapshots'], }, ], overrides: { @@ -2125,7 +1889,7 @@ describe('should handle version specific upgrades', () => { automations: [ { conditions: { - [condition]: true, + view: ['clips', 'snapshots'], }, actions: { action: 'custom:frigate-card-action' as const, @@ -2143,9 +1907,524 @@ describe('should handle version specific upgrades', () => { { conditions: [ { - condition: condition, + condition: 'view' as const, + views: ['clips', 'snapshots'], + }, + ], + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }); + }); + }); + + describe('with camera condition', () => { + it('elements', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: { + camera: ['camera_1', 'camera_2'], + }, + }, + { + conditions: 'not an object', + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: [ + { + condition: 'camera' as const, + cameras: ['camera_1', 'camera_2'], + }, + ], + }, + { + conditions: 'not an object', + }, + ], + }); + }); + + it('overrides', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: { + camera: ['camera_1', 'camera_2'], + }, + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: [ + { + condition: 'camera' as const, + cameras: ['camera_1', 'camera_2'], + }, + ], + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }); + }); + + it('automations', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: { + camera: ['camera_1', 'camera_2'], + }, + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: [ + { + condition: 'camera' as const, + cameras: ['camera_1', 'camera_2'], + }, + ], + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }); + }); + }); + + describe('with boolean conditions', () => { + describe.each([ + ['fullscreen' as const], + ['expand' as const], + ['media_loaded' as const], + ])('%s', (condition: string) => { + it('elements', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: { [condition]: true, }, + }, + { + conditions: 'not an object', + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: [ + { + condition: condition, + [condition]: true, + }, + ], + }, + { + conditions: 'not an object', + }, + ], + }); + }); + + it('overrides', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: { + [condition]: true, + }, + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: [ + { + condition: condition, + [condition]: true, + }, + ], + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }); + }); + + it('automations', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: { + [condition]: true, + }, + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: [ + { + condition: condition, + [condition]: true, + }, + ], + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }); + }); + }); + }); + + describe('with state condition', () => { + it('elements', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: { + state: [ + { + entity: 'binary_sensor.first', + state: 'on', + }, + { + entity: 'binary_sensor.second', + state_not: 'off', + }, + {}, + ], + }, + }, + { + conditions: 'not an object', + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: [ + { + condition: 'state' as const, + entity: 'binary_sensor.first', + state: 'on', + }, + { + condition: 'state' as const, + entity: 'binary_sensor.second', + state_not: 'off', + }, + ], + }, + { + conditions: 'not an object', + }, + ], + }); + }); + + it('overrides', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: { + state: [ + { + entity: 'binary_sensor.first', + state: 'on', + }, + { + entity: 'binary_sensor.second', + state_not: 'off', + }, + {}, + ], + }, + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: [ + { + condition: 'state' as const, + entity: 'binary_sensor.first', + state: 'on', + }, + { + condition: 'state' as const, + entity: 'binary_sensor.second', + state_not: 'off', + }, + ], + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }); + }); + + it('automations', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: { + state: [ + { + entity: 'binary_sensor.first', + state: 'on', + }, + { + entity: 'binary_sensor.second', + state_not: 'off', + }, + {}, + ], + }, + + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: [ + { + condition: 'state' as const, + entity: 'binary_sensor.first', + state: 'on', + }, + { + condition: 'state' as const, + entity: 'binary_sensor.second', + state_not: 'off', + }, + ], + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }); + }); + }); + + describe('with media query condition', () => { + it('elements', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: { + media_query: 'query', + }, + }, + { + conditions: 'not an object', + }, + ], + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + conditions: [ + { + condition: 'screen' as const, + media_query: 'query', + }, + ], + }, + { + conditions: 'not an object', + }, + ], + }); + }); + + it('overrides', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: { + media_query: 'query', + }, + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + overrides: [ + { + conditions: [ + { + condition: 'screen' as const, + media_query: 'query', + }, + ], + overrides: { + view: { + default: 'clips', + }, + }, + }, + ], + }); + }); + + it('automations', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: { + media_query: 'query', + }, + actions: { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + automations: [ + { + conditions: [ + { + condition: 'screen' as const, + media_query: 'query', + }, ], actions: { action: 'custom:frigate-card-action' as const, @@ -2158,280 +2437,25 @@ describe('should handle version specific upgrades', () => { }); }); - describe('with state condition', () => { - it('elements', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - conditions: { - state: [ - { - entity: 'binary_sensor.first', - state: 'on', - }, - { - entity: 'binary_sensor.second', - state_not: 'off', - }, - {}, - ], - }, - }, - { - conditions: 'not an object', - }, - ], - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - conditions: [ - { - condition: 'state' as const, - entity: 'binary_sensor.first', - state: 'on', - }, - { - condition: 'state' as const, - entity: 'binary_sensor.second', - state_not: 'off', - }, - ], - }, - { - conditions: 'not an object', - }, - ], - }); - }); - + describe('from hide to substream capability disable', () => { it('overrides', () => { const config = { type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - overrides: [ - { - conditions: { - state: [ - { - entity: 'binary_sensor.first', - state: 'on', - }, - { - entity: 'binary_sensor.second', - state_not: 'off', - }, - {}, - ], - }, - overrides: { - view: { - default: 'clips', - }, - }, - }, + cameras: [ + { camera_entity: 'camera.office', hide: true }, + { camera_entity: 'camera.sitting_room', hide: false }, ], }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - overrides: [ + cameras: [ { - conditions: [ - { - condition: 'state' as const, - entity: 'binary_sensor.first', - state: 'on', - }, - { - condition: 'state' as const, - entity: 'binary_sensor.second', - state_not: 'off', - }, - ], - overrides: { - view: { - default: 'clips', - }, - }, - }, - ], - }); - }); - - it('automations', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - automations: [ - { - conditions: { - state: [ - { - entity: 'binary_sensor.first', - state: 'on', - }, - { - entity: 'binary_sensor.second', - state_not: 'off', - }, - {}, - ], - }, - - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, - }, - ], - }; - - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - automations: [ - { - conditions: [ - { - condition: 'state' as const, - entity: 'binary_sensor.first', - state: 'on', - }, - { - condition: 'state' as const, - entity: 'binary_sensor.second', - state_not: 'off', - }, - ], - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, - }, - ], - }); - }); - }); - - describe('with media query condition', () => { - it('elements', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - conditions: { - media_query: 'query', - }, - }, - { - conditions: 'not an object', - }, - ], - }; - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - elements: [ - { - conditions: [ - { - condition: 'screen' as const, - media_query: 'query', - }, - ], - }, - { - conditions: 'not an object', - }, - ], - }); - }); - - it('overrides', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - overrides: [ - { - conditions: { - media_query: 'query', - }, - overrides: { - view: { - default: 'clips', - }, - }, - }, - ], - }; - - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - overrides: [ - { - conditions: [ - { - condition: 'screen' as const, - media_query: 'query', - }, - ], - overrides: { - view: { - default: 'clips', - }, - }, - }, - ], - }); - }); - - it('automations', () => { - const config = { - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - automations: [ - { - conditions: { - media_query: 'query', - }, - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, - }, - ], - }; - - expect(upgradeConfig(config)).toBeTruthy(); - expect(config).toEqual({ - type: 'custom:frigate-card', - cameras: [{ camera_entity: 'camera.office' }], - automations: [ - { - conditions: [ - { - condition: 'screen' as const, - media_query: 'query', - }, - ], - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, + camera_entity: 'camera.office', + capabilities: { disable_except: 'substream' }, }, + { camera_entity: 'camera.sitting_room' }, ], }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 9ce96b3e..9ed3a817 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -22,7 +22,6 @@ describe('config defaults', () => { frigate: { client_id: 'frigate', }, - hide: false, image: { refresh_seconds: 1, }, diff --git a/tests/test-utils.ts b/tests/test-utils.ts index ab941520..0ae2a6f6 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -3,6 +3,7 @@ import { HassEntities, HassEntity } from 'home-assistant-js-websocket'; import { expect, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { Camera } from '../src/camera-manager/camera'; +import { Capabilities } from '../src/camera-manager/capabilities'; import { CameraManagerEngine } from '../src/camera-manager/engine'; import { FrigateEvent, FrigateRecording } from '../src/camera-manager/frigate/types'; import { GenericCameraManagerEngine } from '../src/camera-manager/generic/engine-generic'; @@ -10,10 +11,9 @@ import { CameraManager } from '../src/camera-manager/manager'; import { CameraManagerStore } from '../src/camera-manager/store'; import { CameraEventCallback, - CameraManagerCameraCapabilities, - CameraManagerCapabilities, CameraManagerMediaCapabilities, } from '../src/camera-manager/types'; +import { CapabilitiesRaw } from '../src/types'; import { ActionsManager } from '../src/card-controller/actions-manager'; import { AutoUpdateManager } from '../src/card-controller/auto-update-manager'; import { AutomationsManager } from '../src/card-controller/automations-manager'; @@ -75,7 +75,7 @@ export const createConfig = (config?: RawFrigateCardConfig): FrigateCardConfig = export const createCamera = ( config: CameraConfig, engine: CameraManagerEngine, - capabilities?: CameraManagerCameraCapabilities, + capabilities?: Capabilities, ): Camera => { return new Camera(config, engine, { capabilities: capabilities }); }; @@ -185,7 +185,7 @@ export const createStore = ( cameraID: string; engine?: CameraManagerEngine; config?: CameraConfig; - capabilities?: CameraManagerCameraCapabilities; + capabilities?: Capabilities | null; eventCallback?: CameraEventCallback; }[], ): CameraManagerStore => { @@ -196,7 +196,10 @@ export const createStore = ( cameraProps.config ?? createCameraConfig(), cameraProps.engine ?? new GenericCameraManagerEngine(eventCallback), { - capabilities: cameraProps.capabilities ?? createCameraCapabilities(), + capabilities: + cameraProps.capabilities === undefined + ? createCapabilities() + : cameraProps.capabilities ?? undefined, eventCallback: eventCallback, }, ); @@ -212,35 +215,17 @@ export const createCameraManager = (): CameraManager => { return cameraManager; }; -export const createAggregateCameraCapabilities = ( - capabilities?: Partial, -): CameraManagerCapabilities => { - return { - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, - supportsClips: false, - supportsRecordings: false, - supportsSnapshots: false, - supportsTimeline: false, - supportsPTZ: false, +export const createCapabilities = (capabilities?: CapabilitiesRaw): Capabilities => { + return new Capabilities({ + 'favorite-events': false, + 'favorite-recordings': false, + clips: false, + live: false, + recordings: false, + seek: false, + snapshots: false, ...capabilities, - }; -}; - -export const createCameraCapabilities = ( - capabilities?: Partial, -): CameraManagerCameraCapabilities => { - return { - canFavoriteEvents: false, - canFavoriteRecordings: false, - canSeek: false, - supportsClips: false, - supportsRecordings: false, - supportsSnapshots: false, - supportsTimeline: false, - ...capabilities, - }; + }); }; export const createMediaCapabilities = ( diff --git a/tests/utils/camera.test.ts b/tests/utils/camera.test.ts index c84b2d15..bdc32d48 100644 --- a/tests/utils/camera.test.ts +++ b/tests/utils/camera.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { getCameraID } from '../../src/utils/camera.js'; import { createCameraConfig } from '../test-utils.js'; diff --git a/tests/utils/endpoint.test.ts b/tests/utils/endpoint.test.ts new file mode 100644 index 00000000..31c169e7 --- /dev/null +++ b/tests/utils/endpoint.test.ts @@ -0,0 +1,85 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { getEndpointAddressOrDispatchError } from '../../src/utils/endpoint'; +import { homeAssistantSignPath } from '../../src/utils/ha'; +import { createHASS } from '../test-utils'; + +vi.mock('../../src/utils/ha'); + +// @vitest-environment jsdom +describe('getEndpointAddressOrDispatchError', () => { + it('without signing', async () => { + expect( + await getEndpointAddressOrDispatchError( + document.createElement('div'), + createHASS(), + { + endpoint: 'http://example.com', + sign: false, + }, + ), + ).toBe('http://example.com'); + }); + + describe('with signing', () => { + afterEach(() => { + vi.clearAllMocks(); + }); + + it('successful', async () => { + vi.mocked(homeAssistantSignPath).mockResolvedValue('http://signed.com'); + + expect( + await getEndpointAddressOrDispatchError( + document.createElement('div'), + createHASS(), + { + endpoint: 'http://example.com', + sign: true, + }, + ), + ).toBe('ws://signed.com'); + }); + + it('with null response', async () => { + const element = document.createElement('div'); + const listener = vi.fn(); + element.addEventListener('frigate-card:message', listener); + + vi.mocked(homeAssistantSignPath).mockResolvedValue(null); + + expect( + await getEndpointAddressOrDispatchError(element, createHASS(), { + endpoint: 'http://example.com', + sign: true, + }), + ).toBeNull(); + + expect(listener).toBeCalledWith( + expect.objectContaining({ + detail: expect.objectContaining({ + message: 'Could not sign Home Assistant URL', + }), + }), + ); + }); + + it('with exception on signing', async () => { + const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined); + + const element = document.createElement('div'); + const listener = vi.fn(); + element.addEventListener('frigate-card:message', listener); + + vi.mocked(homeAssistantSignPath).mockRejectedValue(new Error()); + + expect( + await getEndpointAddressOrDispatchError(element, createHASS(), { + endpoint: 'http://example.com', + sign: true, + }), + ).toBeNull(); + + expect(consoleSpy).toBeCalled(); + }); + }); +}); diff --git a/tests/utils/media-to-view.test.ts b/tests/utils/media-to-view.test.ts index 2a96605c..a8b06416 100644 --- a/tests/utils/media-to-view.test.ts +++ b/tests/utils/media-to-view.test.ts @@ -1,6 +1,6 @@ import add from 'date-fns/add'; import sub from 'date-fns/sub'; -import { beforeEach, describe, expect, it, Mock, vi } from 'vitest'; +import { beforeEach, describe, expect, it, Mock, MockedFunction, vi } from 'vitest'; import { QueryType } from '../../src/camera-manager/types'; import { changeViewToRecentEventsForCameraAndDependents, @@ -13,6 +13,7 @@ import { ViewMedia } from '../../src/view/media'; import { EventMediaQueries } from '../../src/view/media-queries'; import { createCameraManager, + createCapabilities, createPerformanceConfig, createStore, createView, @@ -21,8 +22,8 @@ import { const createElementListenForView = (): { element: HTMLElement; - viewHandler: Mock; - messageHandler: Mock; + viewHandler: EventListener; + messageHandler: EventListener; } => { const element = document.createElement('div'); @@ -114,6 +115,7 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { createStore([ { cameraID: 'camera', + capabilities: createCapabilities({ clips: true }), }, ]), ); @@ -138,7 +140,9 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { }, ); expect(elementHandler.viewHandler).toBeCalled(); - expect(getMediaFromHandlerCall(elementHandler.viewHandler)).toBe(mediaArray); + expect(getMediaFromHandlerCall(vi.mocked(elementHandler.viewHandler))).toBe( + mediaArray, + ); }); it('should dispatch error message on fail', async () => { @@ -150,6 +154,7 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { createStore([ { cameraID: 'camera', + capabilities: createCapabilities({ clips: true }), }, ]), ); @@ -177,6 +182,7 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { createStore([ { cameraID: 'camera', + capabilities: createCapabilities({ clips: true }), }, ]), ); @@ -208,6 +214,7 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { createStore([ { cameraID: 'camera', + capabilities: createCapabilities({ clips: true }), }, ]), ); @@ -246,6 +253,7 @@ describe('changeViewToRecentEventsForCameraAndDependents', () => { createStore([ { cameraID: 'camera', + capabilities: createCapabilities({ [mediaType]: true }), }, ]), ); @@ -440,6 +448,7 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => { createStore([ { cameraID: 'camera', + capabilities: createCapabilities({ recordings: true }), }, ]), ); @@ -464,7 +473,9 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => { }, ); expect(elementHandler.viewHandler).toBeCalled(); - expect(getMediaFromHandlerCall(elementHandler.viewHandler)).toBe(mediaArray); + expect(getMediaFromHandlerCall(vi.mocked(elementHandler.viewHandler))).toBe( + mediaArray, + ); }); it('should respect media chunk size', async () => { @@ -473,6 +484,7 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => { createStore([ { cameraID: 'camera', + capabilities: createCapabilities({ recordings: true }), }, ]), ); @@ -504,6 +516,7 @@ describe('changeViewToRecentRecordingForCameraAndDependents', () => { createStore([ { cameraID: 'camera', + capabilities: createCapabilities({ recordings: true }), }, ]), ); diff --git a/tests/utils/ptz.test.ts b/tests/utils/ptz.test.ts index 3aefcf1d..272882e5 100644 --- a/tests/utils/ptz.test.ts +++ b/tests/utils/ptz.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest'; import { FrigateCardPTZConfig, frigateCardPTZSchema } from '../../src/config/types'; import { hasUsablePTZ } from '../../src/utils/ptz'; -import { createCameraCapabilities } from '../test-utils'; +import { createCapabilities } from '../test-utils'; const createPTZConfig = ( config?: Partial, @@ -13,7 +13,7 @@ describe('hasUsablePTZ', () => { it('should return true with manual actions', () => { expect( hasUsablePTZ( - createCameraCapabilities(), + createCapabilities(), createPTZConfig({ actions_left: {}, }), @@ -23,14 +23,16 @@ describe('hasUsablePTZ', () => { it('should return true with capabilities', () => { expect( hasUsablePTZ( - createCameraCapabilities({ - ptz: {}, + createCapabilities({ + ptz: { + panTilt: ['continuous'], + }, }), createPTZConfig(), ), ).toBeTruthy(); }); it('should return false with manual actions or capabilities', () => { - expect(hasUsablePTZ(createCameraCapabilities(), createPTZConfig())).toBeFalsy(); + expect(hasUsablePTZ(createCapabilities(), createPTZConfig())).toBeFalsy(); }); }); diff --git a/tests/view/view-to-cameras.test.ts b/tests/view/view-to-cameras.test.ts new file mode 100644 index 00000000..0d90ad73 --- /dev/null +++ b/tests/view/view-to-cameras.test.ts @@ -0,0 +1,79 @@ +import { describe, expect, it, vi } from 'vitest'; +import { FrigateCardView } from '../../src/config/types'; +import { CapabilityKey } from '../../src/types'; +import { getCameraIDsForViewName } from '../../src/view/view-to-cameras'; +import { + createCameraConfig, + createCameraManager, + createCapabilities, + createStore, +} from '../test-utils'; + +describe('getCameraIDsForViewName', () => { + describe('views that are always supported', () => { + it.each([['image' as const], ['diagnostics' as const]])( + '%s', + (viewName: FrigateCardView) => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), + }, + { cameraID: 'camera-2' }, + ]), + ); + + expect(getCameraIDsForViewName(cameraManager, viewName)).toEqual( + new Set(['camera-1', 'camera-2']), + ); + expect(getCameraIDsForViewName(cameraManager, viewName, 'camera-1')).toEqual( + new Set(['camera-1', 'camera-2']), + ); + expect(getCameraIDsForViewName(cameraManager, viewName, 'camera-2')).toEqual( + new Set(['camera-1', 'camera-2']), + ); + }, + ); + }); + + describe('views that respect dependencies and need a capability', () => { + it.each([ + ['live' as const, 'live' as const], + ['clip' as const, 'clips' as const], + ['clips' as const, 'clips' as const], + ['snapshot' as const, 'snapshots' as const], + ['snapshots' as const, 'snapshots' as const], + ['recording' as const, 'recordings' as const], + ['recordings' as const, 'recordings' as const], + ['media' as const, 'clips' as const], + ['media' as const, 'snapshots' as const], + ['media' as const, 'recordings' as const], + ])('%s', (viewName: FrigateCardView, capabilityKey: CapabilityKey) => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), + }, + { + cameraID: 'camera-2', + capabilities: createCapabilities({ [capabilityKey]: true }), + }, + ]), + ); + + expect(getCameraIDsForViewName(cameraManager, viewName)).toEqual( + new Set(['camera-2']), + ); + expect(getCameraIDsForViewName(cameraManager, viewName, 'camera-1')).toEqual( + new Set(['camera-2']), + ); + expect(getCameraIDsForViewName(cameraManager, viewName, 'camera-2')).toEqual( + new Set(['camera-2']), + ); + }); + }); +}); diff --git a/vite.config.ts b/vite.config.ts index 2c0b04a2..afc7ade6 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -10,6 +10,7 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'camera-manager/frigate/util.ts', 'camera-manager/generic/*.ts', 'camera-manager/motioneye/icon.ts', + 'camera-manager/utils/*.ts', 'card-controller/*.ts', 'components-lib/cached-value-controller.ts', 'components-lib/media-filter-controller.ts', @@ -29,6 +30,7 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'utils/diagnostics.ts', 'utils/download.ts', 'utils/embla/**/*.ts', + 'utils/endpoint.ts', 'utils/ha/entity-registry/types.ts', 'utils/ha/types.ts', 'utils/media-info.ts', @@ -72,21 +74,9 @@ export default defineConfig({ coverage: { // Favor istanbul for coverage over v8 due to better accuracy. provider: 'istanbul', - thresholds: { - // Thresholds will automatically be updated as coverage improves to avoid - // back-sliding. - autoUpdate: true, - - // Expected thresholds for anything that does not have 100% coverage - // yet. - statements: 10.69, - branches: 4.9, - functions: 7.81, - lines: 10.94, - ...calculateFullCoverageThresholds(), }, }, }, -}); \ No newline at end of file +}); From 572c6b838da92e2ed03414fceb76fc0cb37948d1 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 26 Mar 2024 21:02:14 -0700 Subject: [PATCH 106/189] Fix CA language. --- src/localize/languages/ca.json | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json index d44cab45..a71d1545 100644 --- a/src/localize/languages/ca.json +++ b/src/localize/languages/ca.json @@ -10,6 +10,23 @@ "config": { "cameras": { "camera_entity": "Entitat de càmera", + "capabilities": { + "disable": "", + "disable_except": "", + "editor_label": "", + "capabilities": { + "clips": "", + "favorite-events": "", + "favorite-recordings": "", + "live": "", + "menu": "", + "ptz": "", + "recordings": "", + "seek": "", + "snapshots": "", + "substream": "" + } + }, "cast": { "dashboard": { "dashboard_path": "Ruta del tauler de control", @@ -520,7 +537,8 @@ "no_camera_name": "No s'ha pogut determinar el nom de la càmera Frigate per a la càmera (o una de les seves dependències), especifiqueu 'camera_entity' o 'camera_name'", "no_dashboard_or_view": "Tant els paràmetres 'dashboard_path' com 'view_path' són necessaris per al mètode d'emissió 'dashboard'", "no_live_camera": "El paràmetre 'camera_entity' s'ha de configurar i validar per a aquest proveïdor en directe", - "no_visible_cameras": "No s'han trobat càmeres visibles, heu de configurar almenys una càmera no oculta", + "no_supported_camera": "", + "no_supported_cameras": "", "reconnecting": "Reconnectant", "timeline_no_cameras": "No hi ha càmeres Frigate per mostrar a la línia de temps", "too_many_automations": "Hi ha massa trucades d'automatització imbricades, comproveu la vostra configuració per veure si hi ha bucles", From b23cea4ffefcbb47db3d371d23dd9f4482b1aabc Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 27 Mar 2024 20:55:56 -0700 Subject: [PATCH 107/189] Add French language. --- project.inlang.json | 37 +- project.inlang/project_id | 1 + src/localize/languages/ca.json | 19 +- src/localize/languages/en.json | 9 +- src/localize/languages/fr.json | 617 ++++++++++++++++++++++++++++++ src/localize/languages/it.json | 22 +- src/localize/languages/pt-BR.json | 12 +- src/localize/languages/pt-PT.json | 32 +- src/localize/localize.ts | 2 + 9 files changed, 697 insertions(+), 54 deletions(-) create mode 100644 project.inlang/project_id create mode 100644 src/localize/languages/fr.json diff --git a/project.inlang.json b/project.inlang.json index 9122f183..243d5659 100644 --- a/project.inlang.json +++ b/project.inlang.json @@ -1,25 +1,16 @@ { - "$schema": "https://inlang.com/schema/project-settings", - "sourceLanguageTag": "en", - "languageTags": [ - "ca", - "en", - "it", - "pt-BR", - "pt-PT" - ], - "modules": [ - "https://cdn.jsdelivr.net/npm/@inlang/plugin-json@4/dist/index.js", - "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-empty-pattern@1/dist/index.js", - "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-identical-pattern@1/dist/index.js", - "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-without-source@1/dist/index.js", - "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-missing-translation@1/dist/index.js" - ], - "plugin.inlang.json": { - "pathPattern": "./src/localize/languages/{languageTag}.json", - "variableReferencePattern": [ - "{", - "}" - ] - } + "$schema": "https://inlang.com/schema/project-settings", + "sourceLanguageTag": "en", + "languageTags": ["ca", "en", "fr", "it", "pt-BR", "pt-PT"], + "modules": [ + "https://cdn.jsdelivr.net/npm/@inlang/plugin-json@4/dist/index.js", + "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-empty-pattern@1/dist/index.js", + "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-identical-pattern@1/dist/index.js", + "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-without-source@1/dist/index.js", + "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-missing-translation@1/dist/index.js" + ], + "plugin.inlang.json": { + "pathPattern": "./src/localize/languages/{languageTag}.json", + "variableReferencePattern": ["{", "}"] + } } diff --git a/project.inlang/project_id b/project.inlang/project_id new file mode 100644 index 00000000..df02d4b8 --- /dev/null +++ b/project.inlang/project_id @@ -0,0 +1 @@ +d140b5c2bbb618a6441e874d987530122309f246beb56c7cc7db10099528a75b diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json index a71d1545..20f72390 100644 --- a/src/localize/languages/ca.json +++ b/src/localize/languages/ca.json @@ -11,9 +11,6 @@ "cameras": { "camera_entity": "Entitat de càmera", "capabilities": { - "disable": "", - "disable_except": "", - "editor_label": "", "capabilities": { "clips": "", "favorite-events": "", @@ -25,7 +22,10 @@ "seek": "", "snapshots": "", "substream": "" - } + }, + "disable": "", + "disable_except": "", + "editor_label": "" }, "cast": { "dashboard": { @@ -75,11 +75,14 @@ "go2rtc": { "editor_label": "Opcions de go2rtc", "modes": { - "editor_label": "Modes de go2rtc" + "editor_label": "Modes de go2rtc", + "mjpeg": "", + "mp4": "", + "mse": "", + "webrtc": "" }, "stream": "nom del flux de go2rtc" }, - "hide": "Amaga la càmera de la interfície d'usuari", "icon": "Icona d'aquesta càmera (detecció automàtica des de l'entitat)", "id": "Identificador únic per a aquesta càmera en aquesta targeta", "image": { @@ -93,8 +96,10 @@ }, "live_providers": { "auto": "Automàtic", + "go2rtc": "", "ha": "Transmissió de vídeo de Home Assistant (és a dir, HLS, LL-HLS, WebRTC mitjançant HA)", "image": "Imatges de Home Assistant", + "jsmpeg": "", "webrtc-card": "Targeta WebRTC (és a dir, la targeta WebRTC d'AlexxIT)" }, "motioneye": { @@ -358,6 +363,7 @@ "mute": "Silenciar / Activar el so", "play": "Reproduir / Pausa", "priority": "Prioritat", + "ptz": "", "recordings": "Enregistraments", "screenshot": "Captura de pantalla", "snapshots": "Imatges instantànies", @@ -540,7 +546,6 @@ "no_supported_camera": "", "no_supported_cameras": "", "reconnecting": "Reconnectant", - "timeline_no_cameras": "No hi ha càmeres Frigate per mostrar a la línia de temps", "too_many_automations": "Hi ha massa trucades d'automatització imbricades, comproveu la vostra configuració per veure si hi ha bucles", "troubleshooting": "Comproveu la resolució de problemes", "unknown": "Error desconegut", diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 6d4bfa88..d3bb0d23 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -11,9 +11,6 @@ "cameras": { "camera_entity": "Camera Entity", "capabilities": { - "disable": "Disable", - "disable_except": "Disable except", - "editor_label": "Camera capabilities", "capabilities": { "clips": "Clips", "favorite-events": "Favorite Events", @@ -25,7 +22,10 @@ "seek": "Seeking", "snapshots": "Snapshots", "substream": "Substream" - } + }, + "disable": "Disable", + "disable_except": "Disable except", + "editor_label": "Camera capabilities" }, "cast": { "dashboard": { @@ -83,7 +83,6 @@ }, "stream": "go2rtc stream name" }, - "hide": "Hide camera from UI", "icon": "Icon for this camera (Autodetected from entity)", "id": "Unique id for this camera in this card", "image": { diff --git a/src/localize/languages/fr.json b/src/localize/languages/fr.json new file mode 100644 index 00000000..041ed7eb --- /dev/null +++ b/src/localize/languages/fr.json @@ -0,0 +1,617 @@ +{ + "common": { + "frigate_card": "Carte Frigate", + "frigate_card_description": "Une carte Lovelace à utiliser avec Frigate", + "live": "En direct", + "no_media": "Aucun média à afficher", + "recordings": "Enregistrements", + "version": "Version" + }, + "config": { + "cameras": { + "camera_entity": "Entité caméra", + "capabilities": { + "capabilities": { + "clips": "", + "favorite-events": "", + "favorite-recordings": "", + "live": "", + "menu": "", + "ptz": "", + "recordings": "", + "seek": "", + "snapshots": "", + "substream": "" + }, + "disable": "", + "disable_except": "", + "editor_label": "" + }, + "cast": { + "dashboard": { + "dashboard_path": "", + "view_path": "" + }, + "editor_label": "", + "method": "", + "methods": { + "dashboard": "", + "standard": "" + } + }, + "dependencies": { + "all_cameras": "Afficher les événements pour toutes les caméras avec cette caméra", + "cameras": "Afficher les événements pour des caméras spécifiques avec cette caméra", + "editor_label": "Options de dépendance" + }, + "dimensions": { + "aspect_ratio": "", + "editor_label": "", + "layout": { + "editor_label": "", + "fit": "Adatta al layout", + "fits": { + "contain": "Il supporto è contenuto/in cassetta delle lettere", + "cover": "Il supporto si espande proporzionalmente per coprire la scheda", + "fill": "Il supporto viene allungato per riempire la scheda" + }, + "position": { + "x": "Percentuale di posizionamento orizzontale", + "y": "Percentuale di posizionamento verticale" + } + } + }, + "engines": { + "editor_label": "Options du moteur de caméra" + }, + "frigate": { + "camera_name": "Nom de la caméra de la frégate (détecté automatiquement par l'entité)", + "client_id": "ID client Frigate (pour plus 1 d'un serveur Frigate)", + "editor_label": "Options de Frigate", + "labels": "Étiquettes de Frigate/filtres d'objets", + "url": "URL du serveur Frigate", + "zones": "Zones Frigate" + }, + "go2rtc": { + "editor_label": "Options go2rtc", + "modes": { + "editor_label": "Modes go2rtc", + "mjpeg": "Motion JPEG (MJPEG)", + "mp4": "MPEG-4 (MP4)", + "mse": "Extensions de sources multimédias (MSE)", + "webrtc": "Web Real-Time Communication (WebRTC)" + }, + "stream": "nom du flux go2rtc" + }, + "icon": "Icône pour cette caméra (auto-détectée par l'entité)", + "id": "ID unique pour cette caméra dans cette carte", + "image": { + "editor_label": "Options d'images", + "refresh_seconds": "Nombre de secondes après lesquelles actualiser l'image en direct (0=jamais)", + "url": "URL de l'image à utiliser à la place de l'instantané de l'entité de la caméra" + }, + "live_provider": "Fournisseur de visualisation en direct pour cette caméra", + "live_provider_options": { + "editor_label": "Options du fournisseur en direct" + }, + "live_providers": { + "auto": "Automatique", + "go2rtc": "go2rtc", + "ha": "Flux vidéo Home Assistant (c'est-à-dire HLS, LL-HLS, WebRTC via HA)", + "image": "Images d'Home Assistant", + "jsmpeg": "JSMpeg", + "webrtc-card": "Carte WebRTC (c.-⁠à-⁠d. La cartte WebRTC d'AlexxIT)" + }, + "motioneye": { + "editor_label": "Options de MotionEye", + "images": { + "directory_pattern": "Modèle de répertoire d'images", + "file_pattern": "Modèle de fichier images" + }, + "movies": { + "directory_pattern": "Modèle de répertoire de films", + "file_pattern": "Modèle de fichier de films" + }, + "url": "URL de l’interface MotionEye" + }, + "title": "Titre de cette caméra (détection automatique à partir de l'entité)", + "triggers": { + "editor_label": "Modèle de répertoire des films", + "entities": "Déclencheur à partir d'autres entités", + "events": { + "clips": "", + "editor_label": "", + "events": "", + "snapshots": "" + }, + "motion": "Déclenchement par détection automatique du capteur de mouvement", + "occupancy": "Déclenchement par détection automatique du capteur de présence" + }, + "webrtc_card": { + "editor_label": "Options de la carte WebRTC", + "entity": "Entité de caméra de carte WebRTC (pas une caméra de Frigate)", + "url": "URL de la caméra de la carte WebRTC" + } + }, + "common": { + "controls": { + "builtin": "Commandes vidéo intégrées", + "filter": { + "editor_label": "Filtre multimédia", + "mode": "Mode de filtre", + "modes": { + "left": "Filtre média dans un menu à gauche", + "none": "Pas de filtre média", + "right": "Filtre média dans un menu à droite" + } + }, + "next_previous": { + "editor_label": "Suivant et précédent", + "size": "Taille des contrôles suivant et précédent en pixels", + "style": "Style de contrôle suivant et précédent", + "styles": { + "chevrons": "Chevrons", + "icons": "Icônes", + "none": "Aucun", + "thumbnails": "Miniatures" + } + }, + "thumbnails": { + "editor_label": "Miniatures", + "events_media_type": "S'il faut afficher des vignettes de clips ou des instantanés", + "events_media_types": { + "clips": "Miniatures de clips", + "snapshots": "Miniatures d'instantanés" + }, + "media_type": "", + "media_types": { + "events": "", + "recordings": "" + }, + "mode": "Mode vignettes", + "modes": { + "above": "Miniatures ci-dessus", + "below": "Miniatures ci-dessous", + "left": "Miniatures dans un menu à gauche", + "none": "Aucune vignette", + "right": "Miniatures dans un menu à droite" + }, + "show_details": "Afficher les détails avec des vignettes", + "show_download_control": "Afficher le contrôle de téléchargement sur les vignettes", + "show_favorite_control": "Afficher le contrôle favori sur les vignettes", + "show_timeline_control": "Afficher le contrôle de la chronologie sur les vignettes", + "size": "Taille des vignettes en pixels" + }, + "timeline": { + "editor_label": "Mini-chronologie", + "mode": "Mode", + "modes": { + "above": "Au-dessus", + "below": "En dessous", + "none": "Aucun" + }, + "pan_mode": "", + "pan_modes": { + "pan": "", + "seek": "", + "seek-in-camera": "", + "seek-in-media": "" + } + }, + "title": { + "duration_seconds": "Secondes pour afficher le titre de la fenêtre contextuelle (0 = toujours)", + "editor_label": "Contrôles de titre contextuel", + "mode": "Mode d'affichage du titre contextuel", + "modes": { + "none": "Pas d'affichage du titre", + "popup-bottom-left": "Popup en bas à gauche", + "popup-bottom-right": "Popup en bas à droite", + "popup-top-left": "Popup en haut à gauche", + "popup-top-right": "Popup en haut à droite" + } + } + }, + "display": { + "editor_label": "", + "grid_columns": "", + "grid_max_columns": "", + "grid_selected_width_factor": "", + "mode": "" + }, + "media_action_conditions": { + "all": "Toutes les opportunités", + "hidden": "Sur le navigateur/onglet masqué", + "microphone_mute": "", + "microphone_unmute": "", + "never": "Jamais", + "selected": "Sur sélection", + "unselected": "Lors de la désélection", + "visible": "Sur la visibilité du navigateur/onglet" + }, + "timeline": { + "clustering_threshold": "Le nombre d'événements pour lesquels ils sont regroupés (0 = pas de clustering)", + "events_media_type": "Les médias affichés par la chronologie", + "events_media_types": { + "all": "Tous types de médias", + "clips": "Extraits", + "snapshots": "Instantanés" + }, + "show_recordings": "Afficher les enregistrements", + "style": "Style de chronologie", + "styles": { + "ribbon": "Événements sur un seul ruban", + "stack": "Événements empilés et groupés" + }, + "window_seconds": "La durée par défaut de la vue chronologique en secondes" + } + }, + "dimensions": { + "aspect_ratio": "Format d'image par défaut (par exemple '16:9')", + "aspect_ratio_mode": "Mode rapport hauteur/largeur", + "aspect_ratio_modes": { + "dynamic": "Le rapport hauteur/largeur s'adapte au média", + "static": "Rapport hauteur/largeur statique", + "unconstrained": "Rapport hauteur/largeur sans contrainte" + }, + "max_height": "Hauteur maximale de la carte en unités CSS (par exemple '100vh')", + "min_height": "Hauteur minimale de la carte en unités CSS (par exemple « 100 px »)" + }, + "image": { + "mode": "Mode d'affichage des images", + "modes": { + "camera": "Instantané de la caméra Home Assistant de l'entité caméra", + "screensaver": "Logo Frigate intégré", + "url": "Image arbitraire spécifiée par URL" + }, + "refresh_seconds": "Nombre de secondes après lesquelles actualiser (0=jamais)", + "url": "URL d'image statique pour l'affichage de l'image", + "zoomable": "L'image peut être zoomée/panoramique" + }, + "live": { + "auto_mute": "Couper automatiquement le son des caméras en direct", + "auto_pause": "Mettre automatiquement en pause les caméras en direct", + "auto_play": "Lire automatiquement les caméras en direct", + "auto_unmute": "Activer automatiquement le son des caméras en direct", + "controls": { + "editor_label": "Contrôles en direct", + "ptz": { + "editor_label": "", + "hide_home": "", + "hide_pan_tilt": "", + "hide_zoom": "", + "mode": "", + "modes": { + "off": "", + "on": "" + }, + "orientation": "", + "orientations": { + "horizontal": "", + "vertical": "" + }, + "position": "", + "positions": { + "bottom-left": "", + "bottom-right": "", + "top-left": "", + "top-right": "" + } + } + }, + "draggable": "La vue des caméras en direct peut être glissée/glissée", + "lazy_load": "Les caméras en direct sont chargeés en différé", + "lazy_unload": "Les caméras en direct sont déchargés en différé", + "microphone": { + "always_connected": "Gardez toujours le microphone connecté", + "disconnect_seconds": "Secondes après quoi déconnecter le microphone (0=jamais)", + "editor_label": "Microphone", + "enabled": "Microphone activé", + "mute_after_microphone_mute_seconds": "" + }, + "preload": "Précharger la vue en direct en arrière-plan", + "show_image_during_load": "Afficher une image fixe pendant le chargement du flux en direct", + "transition_effect": "Effet de transition de caméra en direct", + "zoomable": "Les caméras en direct peuvent être zoomées/panoramiques" + }, + "media_viewer": { + "auto_mute": "Couper automatiquement le son des médias", + "auto_pause": "Mettre automatiquement en pause les médias", + "auto_play": "Lire automatiquement les médias", + "auto_unmute": "Activer automatiquement le son des médias", + "controls": { + "editor_label": "Commandes de la visionneuse multimédia" + }, + "draggable": "La visionneuse multimédia peut être glissée/glissée", + "lazy_load": "Les médias Media Viewer sont chargés paresseusement dans le carrousel", + "snapshot_click_plays_clip": "Cliquer sur un instantané lit un clip associé", + "transition_effect": "Effet de transition de la visionneuse multimédia", + "transition_effects": { + "none": "Pas de transition", + "slide": "Transition de diapositive" + }, + "zoomable": "La visionneuse multimédia peut être zoomée/panoramique" + }, + "menu": { + "alignment": "Alignement des menus", + "alignments": { + "bottom": "Aligné vers le bas", + "left": "Aligné à gauche", + "right": "Aligné à droite", + "top": "Aligné vers le haut" + }, + "button_size": "Taille du bouton de menu en pixels", + "buttons": { + "alignment": "Alignement des boutons", + "alignments": { + "matching": "Faire correspondre l'alignement du menu", + "opposing": "S'opposer à l'alignement des menus" + }, + "camera_ui": "Interface utilisateur de la caméra", + "cameras": "Appareils photo", + "clips": "Extraits", + "display_mode": "", + "download": "Télécharger", + "enabled": "Bouton activé", + "expand": "Développer", + "frigate": "Menu Frégate / Vue par défaut", + "fullscreen": "Plein écran", + "icon": "Icône", + "image": "Image", + "live": "En direct", + "media_player": "Envoyer au lecteur multimédia", + "microphone": "Microphone", + "mute": "Désactiver/Réactiver le son", + "play": "Jouer / Pause", + "priority": "Priorité", + "ptz": "", + "recordings": "Enregistrements", + "screenshot": "Capture d'écran", + "snapshots": "Instantanés", + "substreams": "Sous-flux", + "timeline": "Chronologie", + "type": "Type de bouton", + "types": { + "momentary": "Momentané", + "toggle": "Basculer" + } + }, + "position": "Emplacement des menus", + "positions": { + "bottom": "Positionné en bas", + "left": "Positionné à gauche", + "right": "Positionné à droite", + "top": "Positionné en haut" + }, + "style": "Style de menu", + "styles": { + "hidden": "Menu caché", + "hover": "Menu survolé", + "hover-card": "Menu survolé (à l'échelle de la carte)", + "none": "Pas de menu", + "outside": "Menu extérieur", + "overlay": "Menu superposé" + } + }, + "overrides": { + "info": "Cette configuration de carte comporte des remplacements spécifiés manuellement et configurés qui peuvent remplacer les valeurs affichées dans l'éditeur visuel. Veuillez consulter l'éditeur de code pour afficher/modifier ces remplacements." + }, + "performance": { + "features": { + "animated_progress_indicator": "Indicateur de progression animé", + "editor_label": "Options de fonctionnalités", + "media_chunk_size": "Taille du morceau de média" + }, + "profile": "Profil de performances", + "profiles": { + "high": "Performances élevées", + "low": "Performances faibles" + }, + "style": { + "border_radius": "Courbes", + "box_shadow": "Ombres", + "editor_label": "Options de style" + }, + "warning": "Cette carte est en mode profil bas, les paramètres par défaut ont donc été modifiés pour optimiser les performances." + }, + "view": { + "camera_select": "Afficher les caméras nouvellement sélectionnées", + "dark_mode": "Mode sombre", + "dark_modes": { + "auto": "Automatique", + "off": "Désactivé", + "on": "Activé" + }, + "default": "Vue par défaut", + "interaction_seconds": "", + "reset_after_interaction": "", + "triggers": { + "actions": { + "editor_label": "", + "interaction_mode": "", + "interaction_modes": { + "active": "", + "all": "", + "inactive": "" + }, + "trigger": "", + "triggers": { + "default": "", + "live": "", + "media": "", + "none": "" + }, + "untrigger": "", + "untriggers": { + "default": "", + "none": "" + } + }, + "editor_label": "", + "filter_selected_camera": "", + "show_trigger_status": "Afficher la bordure clignotante lors du déclenchement", + "untrigger_seconds": "Quelques secondes après le changement d'état inactif pour débloquer" + }, + "update_cycle_camera": "Parcourez les caméras lorsque la vue par défaut est mise à jour", + "update_force": "Forcer les mises à jour de la carte (ignorer l'interaction de l'utilisateur)", + "update_seconds": "Actualiser la vue par défaut toutes les X secondes (0=jamais)", + "views": { + "clip": "Clip le plus récent", + "clips": "Galerie de clips", + "current": "Vue actuelle", + "image": "Image statique", + "live": "Vue en direct", + "recording": "Enregistrement le plus récent", + "recordings": "Galerie d'enregistrements", + "snapshot": "Instantané le plus récent", + "snapshots": "Galerie d'instantanés", + "timeline": "Vue chronologique" + } + } + }, + "display_modes": { + "grid": "", + "single": "" + }, + "editor": { + "add_new_camera": "Ajouter une nouvelle caméra", + "button": "Bouton", + "camera": "Caméra", + "cameras": "Appareils photo", + "cameras_secondary": "Quelles caméras afficher sur cette carte", + "delete": "Supprimer", + "dimensions": "Dimensions", + "dimensions_secondary": "Options de dimensions et de forme", + "image": "Image", + "image_secondary": "Options d'affichage d'image statique", + "live": "En direct", + "live_secondary": "Options d'affichage de la caméra en direct", + "media_gallery": "Galerie des médias", + "media_gallery_secondary": "Options de la galerie multimédia", + "media_viewer": "Visionneuse de médias", + "media_viewer_secondary": "Visionneuse de médias statiques (clips, instantanés ou enregistrements)", + "menu": "Menu", + "menu_secondary": "Options d'apparence et de convivialité du menu", + "move_down": "Descendre", + "move_up": "Déplacer vers le haut", + "overrides": "Les remplacements sont actifs", + "overrides_secondary": "Remplacements de configuration dynamique détectés", + "performance": "Performance", + "performance_secondary": "Options de performances de la carte", + "timeline": "Chronologie", + "timeline_secondary": "Options de chronologie des événements", + "upgrade": "Mise à niveau", + "upgrade_available": "Une mise à niveau automatique de la configuration de la carte est disponible", + "view": "Voir", + "view_secondary": "Ce que la carte doit montrer et comment la montrer" + }, + "elements": { + "ptz": { + "down": "Bas", + "home": "Origine", + "left": "Gauche", + "right": "Droite", + "up": "Haut", + "zoom_in": "Zoomer", + "zoom_out": "Dézoomer" + } + }, + "error": { + "awaiting_live": "", + "could_not_render_elements": "Impossible de restituer les éléments de l'image", + "could_not_resolve": "", + "diagnostics": "Diagnostic de la carte. Veuillez enlever les informations confidentielles avant de les partager", + "download_no_media": "Aucun média à télécharger", + "download_sign_failed": "Impossible de signer l'URL du média à télécharger", + "duplicate_camera_id": "ID de caméra Frigate en double pour la caméra suivante, utilisez le paramètre « ID » pour identifier de manière unique les caméras", + "empty_response": "Réponse vide reçue de Home Assistant pour la demande", + "failed_response": "Échec de la réponse de Home Assistant à la demande", + "failed_retain": "Impossible de conserver l'événement", + "failed_sign": "Impossible de signer l'URL de Home Assistant", + "image_load_error": "L'image n'a pas pu être chargée", + "invalid_configuration": "Configuration invalide", + "invalid_configuration_no_hint": "Aucune indication de localisation disponible (type incorrect ou manquant ?)", + "invalid_elements_config": "Configuration des éléments d'image invalide", + "invalid_response": "Réponse non valide reçue de Home Assistant pour la demande", + "jsmpeg_no_player": "Impossible de démarrer le lecteur JSMPEG", + "live_camera_no_endpoint": "Impossible d'obtenir le point de terminaison de la caméra pour ce fournisseur en direct (configuration incomplète ?)", + "live_camera_not_found": "L'entité caméra configurée n'a pas été trouvée", + "live_camera_unavailable": "Caméra indisponible", + "no_camera_engine": "Impossible de déterminer le moteur approprié pour la caméra", + "no_camera_entity": "Impossible de trouver l'entité de caméra", + "no_camera_entity_for_triggers": "Une entité caméra est requise pour détecter automatiquement les déclencheurs", + "no_camera_id": "Impossible de déterminer l'identifiant de la caméra suivante. Il faudra peut-être définir le paramètre « ID » manuellement", + "no_camera_name": "Impossible de déterminer le nom de la caméra Frigate pour la caméra (ou l'une de ses dépendances). Veuillez spécifier soit « camera_entity » soit « camera_name ».", + "no_dashboard_or_view": "", + "no_live_camera": "Le paramètre camera_entity doit être défini et valide pour ce fournisseur en direct", + "no_supported_camera": "", + "no_supported_cameras": "", + "reconnecting": "Reconnexion", + "too_many_automations": "Trop d'appels d'automatisation imbriqués, veuillez vérifier votre configuration pour les boucles", + "troubleshooting": "Vérifier le dépannage", + "unknown": "Erreur inconnue", + "upgrade_available": "Une mise à niveau automatisée de la configuration de la carte est disponible, veuillez visiter l'éditeur visuel de la carte", + "webrtc_card_reported_error": "La carte WebRTC a signalé une erreur", + "webrtc_card_waiting": "En attente du chargement de la carte WebRTC..." + }, + "event": { + "camera": "Caméra", + "duration": "Durée", + "in_progress": "En cours", + "score": "Score", + "seek": "Chercher", + "start": "Commencer", + "tag": "Étiqueter", + "what": "Quoi", + "where": "Où" + }, + "media_filter": { + "all": "Tous", + "camera": "Caméra", + "favorite": "Préféré", + "media_type": "Type de support", + "media_types": { + "clips": "Extraits", + "recordings": "Enregistrements", + "snapshots": "Instantanés" + }, + "not_favorite": "Pas favori", + "select_camera": "Sélectionnez une caméra...", + "select_favorite": "Sélectionnez un favori...", + "select_media_type": "Sélectionnez le type de média...", + "select_tag": "Sélectionnez la balise...", + "select_what": "Sélectionnez quoi...", + "select_when": "Sélectionnez quand...", + "select_where": "Sélectionnez où...", + "tag": "Étiqueter", + "what": "Quoi", + "when": "Quand", + "whens": { + "custom": "", + "past_month": "Mois passé", + "past_week": "La semaine dernière", + "today": "Aujourd'hui", + "yesterday": "Hier" + }, + "where": "Où" + }, + "media_viewer": { + "unseekable": "" + }, + "recording": { + "camera": "Caméra", + "duration": "Durée", + "events": "Événements", + "in_progress": "En cours", + "seek": "Chercher", + "start": "Commencer" + }, + "thumbnail": { + "download": "Télécharger des médias", + "no_thumbnail": "Aucune vignette disponible", + "retain_indefinitely": "Les médias seront conservés indéfiniment", + "timeline": "Voir les médias dans la chronologie" + }, + "timeline": { + "select_date": "Choisir une date" + } +} diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 6af6a999..7acdea38 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -11,9 +11,6 @@ "cameras": { "camera_entity": "Entità della telecamera", "capabilities": { - "disable": "", - "disable_except": "", - "editor_label": "", "capabilities": { "clips": "", "favorite-events": "", @@ -25,7 +22,10 @@ "seek": "", "snapshots": "", "substream": "" - } + }, + "disable": "", + "disable_except": "", + "editor_label": "" }, "cast": { "dashboard": { @@ -48,6 +48,7 @@ "aspect_ratio": "", "editor_label": "", "layout": { + "editor_label": "", "fit": "Adatta al layout", "fits": { "contain": "Il supporto è contenuto/in cassetta delle lettere", @@ -82,7 +83,6 @@ }, "stream": "nome del flusso go2rtc" }, - "hide": "Nascondi la videocamera dall'interfaccia utente", "icon": "Icona per questa telecamera (Autoidentificato dall'entità)", "id": "ID univoco per questa telecamera in questa carta", "image": { @@ -323,6 +323,7 @@ }, "draggable": "Il visualizzatore multimediale può essere trascinato oppure può scorrere", "lazy_load": "Il media Viewer viene caricato pigramente nel carosello", + "snapshot_click_plays_clip": "", "transition_effect": "Effetto di transizione del visualizzatore multimediale", "transition_effects": { "none": "Nessuna transizione", @@ -358,10 +359,12 @@ "image": "Immagine", "live": "Abitare", "media_player": "Invia a Media Player", + "microphone": "", "mute": "", "play": "", "priority": "Priorità", "ptz": "", + "recordings": "", "screenshot": "", "snapshots": "Istantanee", "substreams": "Flusso/i secondario/i", @@ -383,6 +386,7 @@ "styles": { "hidden": "Menu nascosto", "hover": "Menu al passaggio del mouse", + "hover-card": "", "none": "Nessun menu", "outside": "Menu esterno", "overlay": "Menu di overlay" @@ -456,6 +460,8 @@ "current": "Vista corrente", "image": "Immagine statica", "live": "Dal vivo", + "recording": "", + "recordings": "", "snapshot": "Snapshot più recente", "snapshots": "Galleria delle istantanee", "timeline": "Vista della timeline" @@ -489,6 +495,8 @@ "move_up": "Sposta verso l'alto", "overrides": "La sovrascrittura è attiva", "overrides_secondary": "Rilevate sovrascritture della configurazione dinamica", + "performance": "", + "performance_secondary": "", "timeline": "Timeline", "timeline_secondary": "Opzioni della timeline degli eventi", "upgrade": "Aggiornamento", @@ -538,7 +546,6 @@ "no_supported_camera": "", "no_supported_cameras": "", "reconnecting": "Riconnessione", - "timeline_no_cameras": "Nessuna telecamera damostrare in Frigate nella timeline", "too_many_automations": "", "troubleshooting": "Controllare la risoluzione dei problemi", "unknown": "Errore sconosciuto", @@ -553,6 +560,7 @@ "score": "Punteggio", "seek": "Cercare", "start": "Avvia", + "tag": "", "what": "Che cosa", "where": "Dove" }, @@ -570,6 +578,7 @@ "select_camera": "Seleziona fotocamera...", "select_favorite": "Seleziona preferito...", "select_media_type": "Seleziona il tipo di supporto...", + "select_tag": "", "select_what": "Seleziona cosa...", "select_when": "Seleziona quando...", "select_where": "Seleziona dove...", @@ -597,6 +606,7 @@ "start": "Inizio" }, "thumbnail": { + "download": "", "no_thumbnail": "Nessuna miniatura disponibile", "retain_indefinitely": "L'evento sarà mantenuto indefinitamente", "timeline": "Vedi evento nella timeline" diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index bec02933..8e566333 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -11,9 +11,6 @@ "cameras": { "camera_entity": "Entidade da Câmera", "capabilities": { - "disable": "", - "disable_except": "", - "editor_label": "", "capabilities": { "clips": "", "favorite-events": "", @@ -25,7 +22,10 @@ "seek": "", "snapshots": "", "substream": "" - } + }, + "disable": "", + "disable_except": "", + "editor_label": "" }, "cast": { "dashboard": { @@ -48,6 +48,7 @@ "aspect_ratio": "", "editor_label": "", "layout": { + "editor_label": "", "fit": "Ajuste de layout", "fits": { "contain": "A mídia é contida no cartão", @@ -82,7 +83,6 @@ }, "stream": "Nome do stream do go2rtc" }, - "hide": "Ocultar câmera da interface do usuário", "icon": "Ícone para esta câmera (detectado automaticamente pela entidade)", "id": "ID exclusivo para esta câmera nesse cartão", "image": { @@ -359,6 +359,7 @@ "image": "Imagem", "live": "Ao vivo", "media_player": "Enviar para o reprodutor de mídia", + "microphone": "", "mute": "", "play": "", "priority": "Prioridade", @@ -545,7 +546,6 @@ "no_supported_camera": "", "no_supported_cameras": "", "reconnecting": "Reconectando", - "timeline_no_cameras": "Nenhuma câmera do Frigate para mostrar na linha do tempo", "too_many_automations": "", "troubleshooting": "Verifique a solução de problemas", "unknown": "Erro desconhecido", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 36460227..e153b660 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -11,9 +11,6 @@ "cameras": { "camera_entity": "Entidade da Câmera", "capabilities": { - "disable": "", - "disable_except": "", - "editor_label": "", "capabilities": { "clips": "", "favorite-events": "", @@ -25,7 +22,10 @@ "seek": "", "snapshots": "", "substream": "" - } + }, + "disable": "", + "disable_except": "", + "editor_label": "" }, "cast": { "dashboard": { @@ -48,6 +48,7 @@ "aspect_ratio": "", "editor_label": "", "layout": { + "editor_label": "", "fit": "Fit", "fits": { "contain": "Conter", @@ -82,7 +83,6 @@ }, "stream": "Stream" }, - "hide": "Esconder", "icon": "Ícone para esta câmera (detectado automaticamente pela entidade)", "id": "ID exclusivo para esta câmera nesse cartão", "image": { @@ -237,6 +237,11 @@ "snapshots": "Instantâneos" }, "show_recordings": "Mostrar gravações", + "style": "", + "styles": { + "ribbon": "", + "stack": "" + }, "window_seconds": "A duração padrão da visualização da linha do tempo em segundos" } }, @@ -247,7 +252,9 @@ "dynamic": "A proporção se ajusta à mídia", "static": "Proporção estática", "unconstrained": "Proporção irrestrita" - } + }, + "max_height": "", + "min_height": "" }, "image": { "mode": "Modo de visualização de imagem", @@ -316,6 +323,7 @@ }, "draggable": "Visualizador de eventos pode ser arrastado/deslizado", "lazy_load": "A mídia do Visualizador de eventos é carregada lentamente no carrossel", + "snapshot_click_plays_clip": "", "transition_effect": "Efeito de transição do Visualizador de eventos", "transition_effects": { "none": "Sem transição", @@ -351,10 +359,12 @@ "image": "Imagem", "live": "Ao vivo", "media_player": "Enviar para o reprodutor de mídia", + "microphone": "", "mute": "", "play": "", "priority": "Prioridade", "ptz": "", + "recordings": "", "screenshot": "", "snapshots": "Instantâneos", "substreams": "substreams", @@ -376,6 +386,7 @@ "styles": { "hidden": "Menu oculto", "hover": "Menu suspenso", + "hover-card": "", "none": "Sem menu", "outside": "Menu externo", "overlay": "Menu sobreposto" @@ -449,6 +460,8 @@ "current": "Visualização atual", "image": "Imagem estática", "live": "Visualização ao vivo", + "recording": "", + "recordings": "", "snapshot": "Snapshot mais recente", "snapshots": "Galeria de Snapshots", "timeline": "Visualização da linha do tempo" @@ -482,6 +495,8 @@ "move_up": "Subir", "overrides": "As substituições estão ativas", "overrides_secondary": "Substituições de configuração dinâmica detectadas", + "performance": "", + "performance_secondary": "", "timeline": "Linha do tempo", "timeline_secondary": "Opções do evento da linha do tempo", "upgrade": "Actualização", @@ -531,7 +546,6 @@ "no_supported_camera": "", "no_supported_cameras": "", "reconnecting": "A voltar a ligar", - "timeline_no_cameras": "Nenhuma câmera do Frigate para mostrar na linha do tempo", "too_many_automations": "", "troubleshooting": "Verifique a solução de problemas", "unknown": "Erro desconhecido", @@ -546,6 +560,7 @@ "score": "Pontuação", "seek": "Procurar", "start": "Início", + "tag": "", "what": "O quê", "where": "Onde" }, @@ -563,9 +578,11 @@ "select_camera": "Seleciona a camara", "select_favorite": "Seleciona o favorito", "select_media_type": "Seleciona o tipo de media", + "select_tag": "", "select_what": "Seleciona", "select_when": "Seleciona quando", "select_where": "Seleciona onde", + "tag": "", "what": "O que", "when": "Quando", "whens": { @@ -589,6 +606,7 @@ "start": "Começar" }, "thumbnail": { + "download": "", "no_thumbnail": "Nenhuma miniatura disponível", "retain_indefinitely": "Evento será retido por tempo indeterminado", "timeline": "Ver evento na linha do tempo" diff --git a/src/localize/localize.ts b/src/localize/localize.ts index efefeae5..76b8361a 100644 --- a/src/localize/localize.ts +++ b/src/localize/localize.ts @@ -62,6 +62,8 @@ export const loadLanguages = async (hass: HomeAssistant): Promise => { languages[lang] = await import('./languages/pt-PT.json'); } else if (lang === 'pt_BR') { languages[lang] = await import('./languages/pt-BR.json'); + } else if (lang === 'fr') { + languages[lang] = await import('./languages/fr.json'); } if (lang) { From bde4e6cd389ba9aa8ed0241f4b1dce2e4c1eea7d Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Thu, 28 Mar 2024 21:41:48 -0700 Subject: [PATCH 108/189] Add support for configuration profiles. --- src/card-controller/conditions-manager.ts | 2 +- src/card-controller/config-manager.ts | 9 +-- src/card-controller/style-manager.ts | 21 +++-- src/components/live/live.ts | 6 +- src/{config-mgmt.ts => config/management.ts} | 11 ++- src/config/profiles/index.ts | 51 +++++++++++++ .../profiles/low-performance.ts} | 76 +------------------ src/config/profiles/scrubbing.ts | 18 +++++ src/config/types.ts | 11 ++- src/const.ts | 4 + src/editor.ts | 59 +++++++------- src/localize/languages/ca.json | 12 +-- src/localize/languages/en.json | 12 +-- src/localize/languages/fr.json | 12 +-- src/localize/languages/it.json | 12 +-- src/localize/languages/pt-BR.json | 12 +-- src/localize/languages/pt-PT.json | 12 +-- tests/card-controller/config-manager.test.ts | 33 ++++---- tests/card-controller/style-manager.test.ts | 53 +++++++++---- .../management.test.ts} | 41 +++++++++- tests/config/profiles/index.test.ts | 58 ++++++++++++++ tests/config/profiles/low-performance.test.ts | 54 +++++++++++++ tests/config/profiles/scrubbing.test.ts | 13 ++++ tests/config/types.test.ts | 1 - vite.config.ts | 3 +- 25 files changed, 412 insertions(+), 184 deletions(-) rename src/{config-mgmt.ts => config/management.ts} (98%) create mode 100644 src/config/profiles/index.ts rename src/{performance.ts => config/profiles/low-performance.ts} (71%) create mode 100644 src/config/profiles/scrubbing.ts rename tests/{config-mgmt.test.ts => config/management.test.ts} (98%) create mode 100644 tests/config/profiles/index.test.ts create mode 100644 tests/config/profiles/low-performance.test.ts create mode 100644 tests/config/profiles/scrubbing.test.ts diff --git a/src/card-controller/conditions-manager.ts b/src/card-controller/conditions-manager.ts index d38bf35b..122a44b7 100644 --- a/src/card-controller/conditions-manager.ts +++ b/src/card-controller/conditions-manager.ts @@ -1,7 +1,7 @@ import { CurrentUser } from '@dermotduffy/custom-card-helpers'; import { HassEntities } from 'home-assistant-js-websocket'; import merge from 'lodash-es/merge'; -import { copyConfig } from '../config-mgmt'; +import { copyConfig } from '../config/management'; import { FrigateCardCondition, frigateConditionalSchema, diff --git a/src/card-controller/config-manager.ts b/src/card-controller/config-manager.ts index e597ad3a..a062944d 100644 --- a/src/card-controller/config-manager.ts +++ b/src/card-controller/config-manager.ts @@ -1,5 +1,5 @@ import isEqual from 'lodash-es/isEqual'; -import { isConfigUpgradeable } from '../config-mgmt'; +import { isConfigUpgradeable } from '../config/management'; import { CardWideConfig, FrigateCardConfig, @@ -7,7 +7,7 @@ import { RawFrigateCardConfig } from '../config/types'; import { localize } from '../localize/localize'; -import { setLowPerformanceProfile } from '../performance.js'; +import { setProfiles } from '../config/profiles'; import { getParseErrorPaths } from '../utils/zod.js'; import { getOverriddenConfig } from './conditions-manager'; import { InitializationAspect } from './initialization-manager'; @@ -70,10 +70,7 @@ export class ConfigManager { : localize('error.invalid_configuration_no_hint')), ); } - const config = - parseResult.data.performance.profile !== 'low' - ? parseResult.data - : setLowPerformanceProfile(inputConfig, parseResult.data); + const config = setProfiles(inputConfig, parseResult.data, parseResult.data.profiles); this._rawConfig = inputConfig; if (isEqual(this._config, config)) { diff --git a/src/card-controller/style-manager.ts b/src/card-controller/style-manager.ts index 1a5763de..02a95115 100644 --- a/src/card-controller/style-manager.ts +++ b/src/card-controller/style-manager.ts @@ -1,6 +1,5 @@ import { StyleInfo } from 'lit/directives/style-map'; import { FrigateCardConfig } from '../config/types'; -import { setPerformanceCSSStyles } from '../performance'; import { aspectRatioToStyle, setOrRemoveAttribute } from '../utils/basic'; import { View } from '../view/view'; import { CardStyleAPI } from './types'; @@ -69,10 +68,22 @@ export class StyleManager { } public setPerformance(): void { - setPerformanceCSSStyles( - this._api.getCardElementManager().getElement(), - this._api.getConfigManager().getCardWideConfig()?.performance, - ); + const STYLE_DISABLE_MAP = { + box_shadow: 'none', + border_radius: '0px', + }; + const element = this._api.getCardElementManager().getElement(); + const performance = this._api.getConfigManager().getCardWideConfig()?.performance; + + const styles = performance?.style ?? {}; + for (const configKey of Object.keys(styles)) { + const CSSKey = `--frigate-card-css-${configKey.replaceAll('_', '-')}`; + if (styles[configKey] === false) { + element.style.setProperty(CSSKey, STYLE_DISABLE_MAP[configKey]); + } else { + element.style.removeProperty(CSSKey); + } + } } protected _isAspectRatioEnforced( diff --git a/src/components/live/live.ts b/src/components/live/live.ts index a5f79ad0..4eacabfc 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -855,11 +855,7 @@ export class FrigateCardLiveProvider ) { return 'webrtc-card'; } else if (this.cameraConfig?.camera_entity) { - if (this.cardWideConfig?.performance?.profile === 'low') { - return 'image'; - } else { - return 'ha'; - } + return 'ha'; } else if (this.cameraConfig?.frigate.camera_name) { return 'jsmpeg'; } diff --git a/src/config-mgmt.ts b/src/config/management.ts similarity index 98% rename from src/config-mgmt.ts rename to src/config/management.ts index 28f379ab..146531f2 100644 --- a/src/config-mgmt.ts +++ b/src/config/management.ts @@ -7,7 +7,7 @@ import { FrigateCardCondition, RawFrigateCardConfig, RawFrigateCardConfigArray, -} from './config/types'; +} from './types'; import { CONF_AUTOMATIONS, CONF_CAMERAS, @@ -22,14 +22,15 @@ import { CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_EVENTS_MEDIA_TYPE, CONF_MENU_BUTTONS_CAMERA_UI, CONF_OVERRIDES, + CONF_PROFILES, CONF_TIMELINE_EVENTS_MEDIA_TYPE, CONF_VIEW_INTERACTION_SECONDS, CONF_VIEW_TRIGGERS, CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER, CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER, CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA, -} from './const'; -import { arrayify } from './utils/basic'; +} from '../const'; +import { arrayify } from '../utils/basic'; // ************************************************************************* // General Config Management Functions @@ -684,4 +685,8 @@ const UPGRADES = [ transform: (val) => (val === true ? { disable_except: 'substream' } : null), }), ), + upgradeMoveToWithOverrides('performance.profile', CONF_PROFILES, { + // Delete the value if it's set to the default. + transform: (val) => (val === 'low' ? ['low-performance'] : null), + }), ]; diff --git a/src/config/profiles/index.ts b/src/config/profiles/index.ts new file mode 100644 index 00000000..61460daf --- /dev/null +++ b/src/config/profiles/index.ts @@ -0,0 +1,51 @@ +import { getConfigValue, setConfigValue } from '../management.js'; +import { + ProfileType, + RawFrigateCardConfig, + frigateCardConfigSchema, +} from '../types.js'; +import { deepRemoveDefaults } from '../../utils/zod.js'; +import { LOW_PERFORMANCE_PROFILE } from './low-performance.js'; +import { SCRUBBING_PROFILE } from './scrubbing.js'; + +const PROFILES = { + 'low-performance': LOW_PERFORMANCE_PROFILE, + 'scrubbing': SCRUBBING_PROFILE, +}; + +/** + * Set a profile. Sets flags as defined in the relevant profile unless they are + * explicitly overriden in the configuration. + * @param inputConfig The raw unparsed input configuration. + * @param outputConfig The output config to write to. + * @returns A changed (in-place) parsed input configuration. + */ +export const setProfiles = ( + inputConfig: RawFrigateCardConfig, + outputConfig: T, + profiles?: ProfileType[], +): T => { + const defaultLessParseResult = deepRemoveDefaults(frigateCardConfigSchema).safeParse( + inputConfig, + ); + if (!defaultLessParseResult.success) { + return outputConfig; + } + const defaultLessConfig = defaultLessParseResult.data; + + const setIfNotSpecified = (key: string, value: unknown) => { + if (getConfigValue(defaultLessConfig, key) === undefined) { + setConfigValue(outputConfig, key, value); + } + }; + + for (const profile of profiles ?? []) { + if (profile in PROFILES) { + Object.entries(PROFILES[profile]).forEach(([k, v]: [string, unknown]) => + setIfNotSpecified(k, v), + ); + } + } + + return outputConfig; +}; diff --git a/src/performance.ts b/src/config/profiles/low-performance.ts similarity index 71% rename from src/performance.ts rename to src/config/profiles/low-performance.ts index 487de6fc..570c8771 100644 --- a/src/performance.ts +++ b/src/config/profiles/low-performance.ts @@ -1,11 +1,6 @@ -import { getConfigValue, setConfigValue } from './config-mgmt.js'; -import { - PerformanceConfig, - RawFrigateCardConfig, - frigateCardConfigSchema, -} from './config/types.js'; import { CONF_CAMERAS_GLOBAL_IMAGE_REFRESH_SECONDS, + CONF_CAMERAS_GLOBAL_LIVE_PROVIDER, CONF_CAMERAS_GLOBAL_TRIGGERS_OCCUPANCY, CONF_LIVE_AUTO_MUTE, CONF_LIVE_CONTROLS_THUMBNAILS_MODE, @@ -51,13 +46,9 @@ import { CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL, CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL, CONF_TIMELINE_SHOW_RECORDINGS, -} from './const.js'; -import { deepRemoveDefaults } from './utils/zod.js'; +} 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 = { +export const LOW_PERFORMANCE_PROFILE = { // Disable thumbnail carousels. [CONF_LIVE_CONTROLS_THUMBNAILS_MODE]: 'none' as const, [CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_MODE]: 'none' as const, @@ -138,68 +129,9 @@ const LOW_PROFILE_DEFAULTS = { [CONF_MEDIA_VIEWER_SNAPSHOT_CLICK_PLAYS_CLIP]: false, [CONF_CAMERAS_GLOBAL_TRIGGERS_OCCUPANCY]: false, + [CONF_CAMERAS_GLOBAL_LIVE_PROVIDER]: 'image', // Refresh the live camera image every 10 seconds (same as stock Home // Assistant Picture Glance). [CONF_CAMERAS_GLOBAL_IMAGE_REFRESH_SECONDS]: 10, }; - -/** - * 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 outputConfig The output config to write to. - * @returns A changed (in-place) parsed input configuration. - */ -export const setLowPerformanceProfile = ( - inputConfig: RawFrigateCardConfig, - outputConfig: T, -): T => { - const setIfNotSpecified = ( - defaultLessConfig: RawFrigateCardConfig, - outputConfig: T, - key: string, - value: unknown, - ) => { - if (getConfigValue(defaultLessConfig, key) === undefined) { - setConfigValue(outputConfig, key, value); - } - }; - - const defaultLessParseResult = deepRemoveDefaults(frigateCardConfigSchema).safeParse( - inputConfig, - ); - if (defaultLessParseResult.success) { - const defaultLessConfig = defaultLessParseResult.data; - Object.entries(LOW_PROFILE_DEFAULTS).forEach(([k, v]: [string, unknown]) => - setIfNotSpecified(defaultLessConfig, outputConfig, k, v), - ); - } - return outputConfig; -}; - -const STYLE_DISABLE_MAP = { - box_shadow: 'none', - border_radius: '0px', -}; - -/** - * Set card-wide CSS variables for performance. - * @param element The element to set the variables on. - * @param performance The performance configuration. - */ -export const setPerformanceCSSStyles = ( - element: HTMLElement, - performance?: PerformanceConfig, -): void => { - const styles = performance?.style ?? {}; - for (const configKey of Object.keys(styles)) { - const CSSKey = `--frigate-card-css-${configKey.replaceAll('_', '-')}`; - if (styles[configKey] === false) { - element.style.setProperty(CSSKey, STYLE_DISABLE_MAP[configKey]); - } else { - element.style.removeProperty(CSSKey); - } - } -}; diff --git a/src/config/profiles/scrubbing.ts b/src/config/profiles/scrubbing.ts new file mode 100644 index 00000000..b66fe0f7 --- /dev/null +++ b/src/config/profiles/scrubbing.ts @@ -0,0 +1,18 @@ +import { + CONF_LIVE_CONTROLS_TIMELINE_MODE, + CONF_LIVE_CONTROLS_TIMELINE_PAN_MODE, + CONF_LIVE_CONTROLS_TIMELINE_STYLE, + CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MODE, + CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_PAN_MODE, + CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_STYLE, +} from '../../const.js'; + +export const SCRUBBING_PROFILE = { + [CONF_LIVE_CONTROLS_TIMELINE_MODE]: 'below' as const, + [CONF_LIVE_CONTROLS_TIMELINE_STYLE]: 'ribbon' as const, + [CONF_LIVE_CONTROLS_TIMELINE_PAN_MODE]: 'seek' as const, + + [CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MODE]: 'below' as const, + [CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_STYLE]: 'ribbon' as const, + [CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_PAN_MODE]: 'seek' as const, +}; diff --git a/src/config/types.ts b/src/config/types.ts index 67508e46..d3ca5191 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -1623,7 +1623,6 @@ export type Automations = z.infer; // ************************************************************************* const performanceConfigDefault = { - profile: 'high' as const, features: { animated_progress_indicator: true, media_chunk_size: MEDIA_CHUNK_SIZE_DEFAULT, @@ -1636,7 +1635,6 @@ const performanceConfigDefault = { export const performanceConfigSchema = z .object({ - profile: z.enum(['low', 'high']).default(performanceConfigDefault.profile), features: z .object({ animated_progress_indicator: z @@ -1679,6 +1677,13 @@ export interface CardWideConfig { debug?: DebugConfig; } +// ************************************************************************* +// *** Profile Configuration *** +// ************************************************************************* +const PROFILES = ['low-performance', 'scrubbing'] as const; +export type ProfileType = (typeof PROFILES)[number]; +export const profilesSchema = z.enum(PROFILES).array().optional(); + // ************************************************************************* // *** Card Configuration *** // ************************************************************************* @@ -1705,6 +1710,8 @@ export const frigateCardConfigSchema = z.object({ debug: debugConfigSchema, automations: automationsSchema, + profiles: profilesSchema, + // Configuration overrides. overrides: overridesSchema, diff --git a/src/const.ts b/src/const.ts index 7471da29..6a497438 100644 --- a/src/const.ts +++ b/src/const.ts @@ -72,6 +72,8 @@ export const CONF_CAMERAS_ARRAY_TRIGGERS_EVENTS = const CONF_CAMERAS_GLOBAL = 'cameras_global' as const; export const CONF_CAMERAS_GLOBAL_IMAGE = `${CONF_CAMERAS_GLOBAL}.image` as const; +export const CONF_CAMERAS_GLOBAL_LIVE_PROVIDER = + `${CONF_CAMERAS_GLOBAL}.live_provider` as const; export const CONF_CAMERAS_GLOBAL_JSMPEG = `${CONF_CAMERAS_GLOBAL}.jsmpeg` as const; export const CONF_CAMERAS_GLOBAL_WEBRTC_CARD = `${CONF_CAMERAS_GLOBAL}.webrtc_card` as const; @@ -313,6 +315,8 @@ export const CONF_PERFORMANCE_PROFILE = `${CONF_PERFORMANCE}.profile`; export const CONF_PERFORMANCE_STYLE_BOX_SHADOW = `${CONF_PERFORMANCE}.style.box_shadow`; export const CONF_PERFORMANCE_STYLE_BORDER_RADIUS = `${CONF_PERFORMANCE}.style.border_radius`; +export const CONF_PROFILES = 'profiles' as const; + // Taken from https://github.dev/home-assistant/frontend/blob/b5861869e39290fd2e15737e89571dfc543b3ad3/src/data/media-player.ts#L93 export const MEDIA_PLAYER_SUPPORT_BROWSE_MEDIA = 131072; diff --git a/src/editor.ts b/src/editor.ts index b9865192..9502d69f 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -19,21 +19,24 @@ import { isConfigUpgradeable, setConfigValue, upgradeConfig, -} from './config-mgmt.js'; +} from './config/management.js'; +import { setProfiles } from './config/profiles/index.js'; import { BUTTON_SIZE_MIN, FrigateCardConfig, frigateCardConfigDefaults, FRIGATE_MENU_PRIORITY_MAX, + profilesSchema, RawFrigateCardConfig, RawFrigateCardConfigArray, THUMBNAIL_WIDTH_MAX, THUMBNAIL_WIDTH_MIN, } from './config/types.js'; import { + CONF_CAMERAS, CONF_CAMERAS_ARRAY_CAMERA_ENTITY, - CONF_CAMERAS_ARRAY_CAPABILITIES_DISABLE_EXCEPT, CONF_CAMERAS_ARRAY_CAPABILITIES_DISABLE, + CONF_CAMERAS_ARRAY_CAPABILITIES_DISABLE_EXCEPT, CONF_CAMERAS_ARRAY_CAST_DASHBOARD_DASHBOARD_PATH, CONF_CAMERAS_ARRAY_CAST_DASHBOARD_VIEW_PATH, CONF_CAMERAS_ARRAY_CAST_METHOD, @@ -67,9 +70,8 @@ import { CONF_CAMERAS_ARRAY_TRIGGERS_OCCUPANCY, CONF_CAMERAS_ARRAY_WEBRTC_CARD_ENTITY, CONF_CAMERAS_ARRAY_WEBRTC_CARD_URL, - CONF_CAMERAS, - CONF_DIMENSIONS_ASPECT_RATIO_MODE, CONF_DIMENSIONS_ASPECT_RATIO, + CONF_DIMENSIONS_ASPECT_RATIO_MODE, CONF_DIMENSIONS_MAX_HEIGHT, CONF_DIMENSIONS_MIN_HEIGHT, CONF_IMAGE_MODE, @@ -158,8 +160,8 @@ import { CONF_MEDIA_VIEWER_TRANSITION_EFFECT, CONF_MEDIA_VIEWER_ZOOMABLE, CONF_MENU_ALIGNMENT, - CONF_MENU_BUTTON_SIZE, CONF_MENU_BUTTONS, + CONF_MENU_BUTTON_SIZE, CONF_MENU_POSITION, CONF_MENU_STYLE, CONF_PERFORMANCE_FEATURES_ANIMATED_PROGRESS_INDICATOR, @@ -167,6 +169,7 @@ import { CONF_PERFORMANCE_PROFILE, CONF_PERFORMANCE_STYLE_BORDER_RADIUS, CONF_PERFORMANCE_STYLE_BOX_SHADOW, + CONF_PROFILES, CONF_TIMELINE_CLUSTERING_THRESHOLD, CONF_TIMELINE_CONTROLS_THUMBNAILS_MODE, CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_DETAILS, @@ -183,21 +186,20 @@ import { CONF_VIEW_DEFAULT, CONF_VIEW_INTERACTION_SECONDS, CONF_VIEW_RESET_AFTER_INTERACTION, + CONF_VIEW_TRIGGERS, + CONF_VIEW_TRIGGERS_ACTIONS, CONF_VIEW_TRIGGERS_ACTIONS_INTERACTION_MODE, CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER, CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER, - CONF_VIEW_TRIGGERS_ACTIONS, CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA, CONF_VIEW_TRIGGERS_SHOW_TRIGGER_STATUS, CONF_VIEW_TRIGGERS_UNTRIGGER_SECONDS, - CONF_VIEW_TRIGGERS, CONF_VIEW_UPDATE_CYCLE_CAMERA, CONF_VIEW_UPDATE_FORCE, CONF_VIEW_UPDATE_SECONDS, MEDIA_CHUNK_SIZE_MAX, } from './const.js'; import { localize } from './localize/localize.js'; -import { setLowPerformanceProfile } from './performance.js'; import frigate_card_editor_style from './scss/editor.scss'; import { arrayMove, prettifyTitle } from './utils/basic.js'; import { getCameraID } from './utils/camera.js'; @@ -315,6 +317,11 @@ const options: EditorOptions = { name: localize('editor.performance'), secondary: localize('editor.performance_secondary'), }, + profiles: { + icon: 'folder-wrench-outline', + name: localize('editor.profiles'), + secondary: localize('editor.profiles_secondary'), + }, overrides: { icon: 'file-replace', name: localize('editor.overrides'), @@ -589,10 +596,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor { value: 'below', label: localize('config.common.controls.timeline.modes.below') }, ]; - protected _performanceProfiles: EditorSelectOption[] = [ + protected _profiles: EditorSelectOption[] = [ { value: '', label: '' }, - { value: 'low', label: localize('config.performance.profiles.low') }, - { value: 'high', label: localize('config.performance.profiles.high') }, + { value: 'low-performance', label: localize('config.profiles.low-performance') }, + { value: 'scrubbing', label: localize('config.profiles.scrubbing') }, ]; protected _go2rtcModes: EditorSelectOption[] = [ @@ -788,25 +795,20 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ]; public setConfig(config: RawFrigateCardConfig): void { - // Note: This does not use Zod to parse the configuration, so it may be + // Note: This does not use Zod to parse the full configuration, so it may be // partially or completely invalid. It's more useful to have a partially // valid configuration here, to allow the user to fix the broken parts. As // such, RawFrigateCardConfig is used as the type. this._config = config; this._configUpgradeable = isConfigUpgradeable(config); - let unvalidatedProfile: string | null = null; - try { - // this._config may not be a valid FrigateCardConfig as it has not been - // parsed. Attempt to pull out the performance profile. - unvalidatedProfile = (this._config as FrigateCardConfig).performance?.profile; - } catch (_) {} + const profiles = profilesSchema.safeParse( + (this._config as FrigateCardConfig).profiles, + ); - if (unvalidatedProfile === 'high' || unvalidatedProfile === 'low') { + if (profiles.success) { const defaults = copyConfig(frigateCardConfigDefaults); - if (unvalidatedProfile === 'low') { - setLowPerformanceProfile(this._config, defaults); - } + setProfiles(this._config, defaults, profiles.data); this._defaults = defaults; } } @@ -2130,6 +2132,15 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ` : ''} + ${this._renderOptionSetHeader('profiles')} + ${this._expandedMenus[MENU_OPTIONS] === 'profiles' + ? html`
+ ${this._renderOptionSelector(CONF_PROFILES, this._profiles, { + multiple: true, + label: localize('config.profiles.editor_label'), + })} +
` + : ''} ${this._renderOptionSetHeader('view')} ${this._expandedMenus[MENU_OPTIONS] === 'view' ? html` @@ -2556,10 +2567,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${getConfigValue(this._config, CONF_PERFORMANCE_PROFILE) === 'low' ? this._renderInfo(localize('config.performance.warning')) : html``} - ${this._renderOptionSelector( - CONF_PERFORMANCE_PROFILE, - this._performanceProfiles, - )} ${this._putInSubmenu( MENU_PERFORMANCE_FEATURES, true, diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json index 20f72390..a822bf33 100644 --- a/src/localize/languages/ca.json +++ b/src/localize/languages/ca.json @@ -401,11 +401,6 @@ "editor_label": "Opcions de característiques", "media_chunk_size": "Mida del fragment multimèdia" }, - "profile": "Perfil de rendiment", - "profiles": { - "high": "Alt rendiment", - "low": "Baix rendiment" - }, "style": { "border_radius": "Corbes", "box_shadow": "Ombres", @@ -413,6 +408,11 @@ }, "warning": "Aquesta targeta està en mode de perfil baix, de manera que els valors predeterminats han canviat per optimitzar el rendiment" }, + "profiles": { + "editor_label": "", + "low-performance": "", + "scrubbing": "" + }, "view": { "camera_select": "Visualitza les càmeres seleccionades recentment", "dark_mode": "Mode fosc", @@ -497,6 +497,8 @@ "overrides_secondary": "S'han detectat substitucions de configuració dinàmica", "performance": "Rendiment", "performance_secondary": "Opcions de rendiment de la targeta", + "profiles": "", + "profiles_secondary": "", "timeline": "Cronologia", "timeline_secondary": "Opcions de la cronologia d'esdeveniments", "upgrade": "Upgrade", diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index d3bb0d23..f0c5df92 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -401,11 +401,6 @@ "editor_label": "Feature Options", "media_chunk_size": "Media chunk size" }, - "profile": "Performance profile", - "profiles": { - "high": "High/full performance", - "low": "Low performance" - }, "style": { "border_radius": "Curves", "box_shadow": "Shadows", @@ -413,6 +408,11 @@ }, "warning": "This card is in low profile mode so defaults have changed to optimize performance" }, + "profiles": { + "editor_label": "Configuration profiles", + "low-performance": "Low performance", + "scrubbing": "Video scrubbing" + }, "view": { "camera_select": "View for newly selected cameras", "dark_mode": "Dark mode", @@ -497,6 +497,8 @@ "overrides_secondary": "Dynamic configuration overrides detected", "performance": "Performance", "performance_secondary": "Card performance options", + "profiles": "Configuration profiles", + "profiles_secondary": "Choose pre-configured sets of defaults", "timeline": "Timeline", "timeline_secondary": "Event timeline options", "upgrade": "Upgrade", diff --git a/src/localize/languages/fr.json b/src/localize/languages/fr.json index 041ed7eb..fdc1107b 100644 --- a/src/localize/languages/fr.json +++ b/src/localize/languages/fr.json @@ -401,11 +401,6 @@ "editor_label": "Options de fonctionnalités", "media_chunk_size": "Taille du morceau de média" }, - "profile": "Profil de performances", - "profiles": { - "high": "Performances élevées", - "low": "Performances faibles" - }, "style": { "border_radius": "Courbes", "box_shadow": "Ombres", @@ -413,6 +408,11 @@ }, "warning": "Cette carte est en mode profil bas, les paramètres par défaut ont donc été modifiés pour optimiser les performances." }, + "profiles": { + "editor_label": "", + "low-performance": "", + "scrubbing": "" + }, "view": { "camera_select": "Afficher les caméras nouvellement sélectionnées", "dark_mode": "Mode sombre", @@ -497,6 +497,8 @@ "overrides_secondary": "Remplacements de configuration dynamique détectés", "performance": "Performance", "performance_secondary": "Options de performances de la carte", + "profiles": "", + "profiles_secondary": "", "timeline": "Chronologie", "timeline_secondary": "Options de chronologie des événements", "upgrade": "Mise à niveau", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 7acdea38..e515dc57 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -401,11 +401,6 @@ "editor_label": "Opzioni funzionalità", "media_chunk_size": "Dimensione del blocco multimediale" }, - "profile": "Profilo delle prestazioni", - "profiles": { - "high": "Prestazioni alte", - "low": "Prestazioni basse" - }, "style": { "border_radius": "Curve", "box_shadow": "Ombre", @@ -413,6 +408,11 @@ }, "warning": "Questa scheda è in modalità basso profilo, quindi le impostazioni predefinite sono state modificate per ottimizzare le prestazioni" }, + "profiles": { + "editor_label": "", + "low-performance": "", + "scrubbing": "" + }, "view": { "camera_select": "Visualizza per le telecamere appena selezionate", "dark_mode": "Tema scuro", @@ -497,6 +497,8 @@ "overrides_secondary": "Rilevate sovrascritture della configurazione dinamica", "performance": "", "performance_secondary": "", + "profiles": "", + "profiles_secondary": "", "timeline": "Timeline", "timeline_secondary": "Opzioni della timeline degli eventi", "upgrade": "Aggiornamento", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 8e566333..ad8fe495 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -401,11 +401,6 @@ "editor_label": "Opções de recursos", "media_chunk_size": "Tamanho do bloco de mídia" }, - "profile": "Perfil de desempenho", - "profiles": { - "high": "Alto desempenho/completo", - "low": "Baixo desempenho" - }, "style": { "border_radius": "Curvas", "box_shadow": "Sombras", @@ -413,6 +408,11 @@ }, "warning": "Este cartão está no modo de baixo desempenho, então os padrões foram alterados para otimizar o desempenho" }, + "profiles": { + "editor_label": "", + "low-performance": "", + "scrubbing": "" + }, "view": { "camera_select": "Visualização de câmeras recém-selecionadas", "dark_mode": "Modo escuro", @@ -497,6 +497,8 @@ "overrides_secondary": "Substituições de configuração dinâmica detectadas", "performance": "Desempenho", "performance_secondary": "Opções de desempenho do cartão", + "profiles": "", + "profiles_secondary": "", "timeline": "Linha do tempo", "timeline_secondary": "Opções do evento da linha do tempo", "upgrade": "Upgrade", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index e153b660..fb8f531c 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -401,11 +401,6 @@ "editor_label": "Editor de etiquetas", "media_chunk_size": "Tamanho do ficheiro" }, - "profile": "Perfil", - "profiles": { - "high": "Alto", - "low": "Baixo" - }, "style": { "border_radius": "Tamanho do bordo", "box_shadow": "Caixa de Fundo", @@ -413,6 +408,11 @@ }, "warning": "Avisos" }, + "profiles": { + "editor_label": "", + "low-performance": "", + "scrubbing": "" + }, "view": { "camera_select": "Visualização de câmeras recém-selecionadas", "dark_mode": "Modo escuro", @@ -497,6 +497,8 @@ "overrides_secondary": "Substituições de configuração dinâmica detectadas", "performance": "", "performance_secondary": "", + "profiles": "", + "profiles_secondary": "", "timeline": "Linha do tempo", "timeline_secondary": "Opções do evento da linha do tempo", "upgrade": "Actualização", diff --git a/tests/card-controller/config-manager.test.ts b/tests/card-controller/config-manager.test.ts index 6d063b27..7bbb2f2b 100644 --- a/tests/card-controller/config-manager.test.ts +++ b/tests/card-controller/config-manager.test.ts @@ -78,7 +78,7 @@ describe('ConfigManager', () => { manager.setConfig(config); - expect(manager.hasConfig()).toBeTruthy() + expect(manager.hasConfig()).toBeTruthy(); expect(manager.getRawConfig()).toBe(config); // Verify at least the camera is set. @@ -102,12 +102,12 @@ describe('ConfigManager', () => { expect(api.getCardElementManager().update).toBeCalled(); }); - it('should apply low performance defaults', () => { + it('should apply profiles', () => { const manager = new ConfigManager(createCardAPI()); const config = { type: 'custom:frigate-card', cameras: [{ camera_entity: 'camera.office' }], - performance: { profile: 'low' }, + profiles: ['low-performance'], }; manager.setConfig(config); @@ -143,7 +143,9 @@ describe('ConfigManager', () => { logging: true, }, performance: { - profile: 'low', + style: { + box_shadow: false, + }, }, }; @@ -155,12 +157,11 @@ describe('ConfigManager', () => { }, performance: { features: { - animated_progress_indicator: false, - media_chunk_size: 10, + animated_progress_indicator: true, + media_chunk_size: 50, }, - profile: 'low', style: { - border_radius: false, + border_radius: true, box_shadow: false, }, }, @@ -257,8 +258,8 @@ describe('ConfigManager', () => { const config_2 = { ...config_1, cameras_global: { - live_provider: 'jsmpeg' - } + live_provider: 'jsmpeg', + }, }; vi.mocked(getOverriddenConfig).mockReturnValue(createConfig(config_2)); manager.computeOverrideConfig(); @@ -276,9 +277,9 @@ describe('ConfigManager', () => { cameras: [{ camera_entity: 'camera.office' }], live: { microphone: { - always_connected: false - } - } + always_connected: false, + }, + }, }; vi.mocked(getOverriddenConfig).mockReturnValue(createConfig(config_1)); @@ -289,9 +290,9 @@ describe('ConfigManager', () => { ...config_1, live: { microphone: { - always_connected: true - } - } + always_connected: true, + }, + }, }; vi.mocked(getOverriddenConfig).mockReturnValue(createConfig(config_2)); manager.computeOverrideConfig(); diff --git a/tests/card-controller/style-manager.test.ts b/tests/card-controller/style-manager.test.ts index 23a58bae..c2920b70 100644 --- a/tests/card-controller/style-manager.test.ts +++ b/tests/card-controller/style-manager.test.ts @@ -1,11 +1,8 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { FrigateCardView } from '../../src/config/types'; -import { setPerformanceCSSStyles } from '../../src/performance'; import { StyleManager } from '../../src/card-controller/style-manager'; import { createCardAPI, createConfig, createHASS, createView } from '../test-utils'; -vi.mock('../../src/performance'); - // @vitest-environment jsdom describe('StyleManager', () => { beforeEach(() => { @@ -226,19 +223,49 @@ describe('StyleManager', () => { }); }); - it('setPerformance', () => { - const api = createCardAPI(); - const element = document.createElement('div'); - vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); - const config = createConfig(); - vi.mocked(api.getConfigManager().getCardWideConfig).mockReturnValue({ - performance: config.performance, + describe('setPerformance', () => { + it('no styles set', () => { + const api = createCardAPI(); + const element = document.createElement('div'); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); + vi.mocked(api.getConfigManager().getCardWideConfig).mockReturnValue({}); + const manager = new StyleManager(api); + + manager.setPerformance(); + + expect( + element.style.getPropertyValue('--frigate-card-css-box-shadow'), + ).toBeFalsy(); + expect( + element.style.getPropertyValue('--frigate-card-css-border-radius'), + ).toBeFalsy(); }); - const manager = new StyleManager(api); - manager.setPerformance(); + it('valid styles set', () => { + const api = createCardAPI(); + const element = document.createElement('div'); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); + vi.mocked(api.getConfigManager().getCardWideConfig).mockReturnValue( + createConfig({ + performance: { + style: { + box_shadow: false, + border_radius: true, + }, + }, + }), + ); + const manager = new StyleManager(api); - expect(setPerformanceCSSStyles).toBeCalledWith(element, config.performance); + manager.setPerformance(); + + expect(element.style.getPropertyValue('--frigate-card-css-box-shadow')).toEqual( + 'none', + ); + expect( + element.style.getPropertyValue('--frigate-card-css-border-radius'), + ).toBeFalsy(); + }); }); describe('getAspectRatioStyle', () => { diff --git a/tests/config-mgmt.test.ts b/tests/config/management.test.ts similarity index 98% rename from tests/config-mgmt.test.ts rename to tests/config/management.test.ts index 3961f0e0..e12e60e4 100644 --- a/tests/config-mgmt.test.ts +++ b/tests/config/management.test.ts @@ -16,8 +16,8 @@ import { upgradeMoveToWithOverrides, upgradeObjectRecursively, upgradeWithOverrides, -} from '../src/config-mgmt'; -import { RawFrigateCardConfig } from '../src/config/types'; +} from '../../src/config/management'; +import { RawFrigateCardConfig } from '../../src/config/types'; describe('general functions', () => { it('should set value', () => { @@ -2459,6 +2459,43 @@ describe('should handle version specific upgrades', () => { ], }); }); + + describe('from performance profile to generic profile', () => { + it('low performance', () => { + const config = { + type: 'custom:frigate-card', + cameras: [], + performance: { + profile: 'low', + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [], + profiles: ['low-performance'], + performance: {}, + }); + }); + + it('high performance', () => { + const config = { + type: 'custom:frigate-card', + cameras: [], + performance: { + profile: 'high', + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [], + performance: {}, + }); + }); + }); }); }); }); diff --git a/tests/config/profiles/index.test.ts b/tests/config/profiles/index.test.ts new file mode 100644 index 00000000..20fd2ad5 --- /dev/null +++ b/tests/config/profiles/index.test.ts @@ -0,0 +1,58 @@ +import { describe, expect, it } from 'vitest'; +import { ProfileType } from '../../../src/config/types'; +import { setProfiles } from '../../../src/config/profiles'; +import { createConfig } from '../../test-utils'; + +describe('setProfiles', () => { + it('should handle failed parse', () => { + expect(setProfiles({ cameras: 'not_an_array' }, {})).toEqual({}); + }); + + it('should handle no profiles', () => { + const input = createConfig(); + const output = createConfig(); + + expect(setProfiles(input, output)).toEqual(input); + }); + + it('should handle invalid profiles', () => { + const input = createConfig(); + const output = createConfig(); + + expect(setProfiles(input, output, ['bogus' as ProfileType])).toEqual(input); + }); + + it('should handle profiles', () => { + const input = { + type: 'frigate-hass-card', + cameras: [], + live: { + controls: { + timeline: { + // This will not be overridden. + style: 'stack', + }, + }, + }, + }; + expect(setProfiles(input, {}, ['scrubbing'])).toEqual({ + live: { + controls: { + timeline: { + mode: 'below', + pan_mode: 'seek', + }, + }, + }, + media_viewer: { + controls: { + timeline: { + mode: 'below', + style: 'ribbon', + pan_mode: 'seek', + }, + }, + }, + }); + }); +}); diff --git a/tests/config/profiles/low-performance.test.ts b/tests/config/profiles/low-performance.test.ts new file mode 100644 index 00000000..c048d020 --- /dev/null +++ b/tests/config/profiles/low-performance.test.ts @@ -0,0 +1,54 @@ +import { expect, it } from 'vitest'; +import { LOW_PERFORMANCE_PROFILE } from '../../../src/config/profiles/low-performance'; + +it('low performance profile', () => { + expect(LOW_PERFORMANCE_PROFILE).toEqual({ + 'cameras_global.image.refresh_seconds': 10, + 'cameras_global.live_provider': 'image', + 'cameras_global.triggers.occupancy': false, + 'live.auto_mute': 'never', + 'live.controls.thumbnails.mode': 'none', + 'live.controls.thumbnails.show_details': false, + 'live.controls.thumbnails.show_download_control': false, + 'live.controls.thumbnails.show_favorite_control': false, + 'live.controls.thumbnails.show_timeline_control': false, + 'live.controls.timeline.show_recordings': false, + 'live.controls.title.mode': 'none', + 'live.draggable': false, + 'live.lazy_unload': 'all', + 'live.show_image_during_load': false, + 'live.transition_effect': 'none', + 'media_gallery.controls.thumbnails.show_details': false, + 'media_gallery.controls.thumbnails.show_download_control': false, + 'media_gallery.controls.thumbnails.show_favorite_control': false, + 'media_gallery.controls.thumbnails.show_timeline_control': false, + 'media_viewer.auto_mute': 'never', + 'media_viewer.auto_pause': 'never', + 'media_viewer.auto_play': 'never', + 'media_viewer.controls.next_previous.style': 'chevrons', + 'media_viewer.controls.thumbnails.mode': 'none', + 'media_viewer.controls.thumbnails.show_details': false, + 'media_viewer.controls.thumbnails.show_download_control': false, + 'media_viewer.controls.thumbnails.show_favorite_control': false, + 'media_viewer.controls.thumbnails.show_timeline_control': false, + 'media_viewer.controls.timeline.show_recordings': false, + 'media_viewer.controls.title.mode': 'none', + 'media_viewer.draggable': false, + 'media_viewer.snapshot_click_plays_clip': false, + 'media_viewer.transition_effect': 'none', + 'menu.buttons.frigate.enabled': false, + 'menu.buttons.media_player.enabled': false, + 'menu.buttons.timeline.enabled': false, + 'menu.style': 'outside', + 'performance.features.animated_progress_indicator': false, + 'performance.features.media_chunk_size': 10, + 'performance.style.border_radius': false, + 'performance.style.box_shadow': false, + 'timeline.controls.thumbnails.mode': 'none', + 'timeline.controls.thumbnails.show_details': false, + 'timeline.controls.thumbnails.show_download_control': false, + 'timeline.controls.thumbnails.show_favorite_control': false, + 'timeline.controls.thumbnails.show_timeline_control': false, + 'timeline.show_recordings': false, + }); +}); diff --git a/tests/config/profiles/scrubbing.test.ts b/tests/config/profiles/scrubbing.test.ts new file mode 100644 index 00000000..b043dc0e --- /dev/null +++ b/tests/config/profiles/scrubbing.test.ts @@ -0,0 +1,13 @@ +import { expect, it } from 'vitest'; +import { SCRUBBING_PROFILE } from '../../../src/config/profiles/scrubbing'; + +it('scrubbing profile', () => { + expect(SCRUBBING_PROFILE).toEqual({ + 'live.controls.timeline.mode': 'below', + 'live.controls.timeline.style': 'ribbon', + 'live.controls.timeline.pan_mode': 'seek', + 'media_viewer.controls.timeline.mode': 'below', + 'media_viewer.controls.timeline.style': 'ribbon', + 'media_viewer.controls.timeline.pan_mode': 'seek', + }); +}); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 9ed3a817..76ec3350 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -253,7 +253,6 @@ describe('config defaults', () => { animated_progress_indicator: true, media_chunk_size: 50, }, - profile: 'high', style: { border_radius: true, box_shadow: true, diff --git a/vite.config.ts b/vite.config.ts index afc7ade6..0aaea85e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -18,8 +18,7 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'components-lib/menu-controller.ts', 'components-lib/ptz-controller.ts', 'components-lib/zoom-controller.ts', - 'config-mgmt.ts', - 'config/types.ts', + 'config/**/*.ts', 'const.ts', 'types.ts', 'utils/action.ts', From 955bcb3a9a323763c3de6bcb0ae93bbd44e9a690 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 1 Apr 2024 21:09:20 -0700 Subject: [PATCH 109/189] Complete documentation overhaul. --- README.md | 4521 +---------------- docs/.nojekyll | 0 docs/README.md | 58 + docs/_coverpage.md | 8 + docs/_sidebar.md | 10 + docs/advanced-installation.md | 51 + docs/configuration/README.md | 43 + docs/configuration/_sidebar.md | 26 + docs/configuration/actions.md | 521 ++ docs/configuration/automations.md | 38 + docs/configuration/cameras/README.md | 284 ++ docs/configuration/cameras/_sidebar.md | 27 + docs/configuration/cameras/engine.md | 82 + docs/configuration/cameras/live-provider.md | 86 + docs/configuration/common/expanded-warning.md | 1 + .../common/timeline-seek-info.md | 4 + docs/configuration/conditions.md | 206 + docs/configuration/dimensions.md | 45 + docs/configuration/elements.md | 356 ++ docs/configuration/grid-layout-algorithm.md | 10 + docs/configuration/image.md | 41 + docs/configuration/live.md | 269 + docs/configuration/media-gallery.md | 78 + docs/configuration/media-viewer.md | 194 + docs/configuration/menu.md | 171 + docs/configuration/overrides.md | 39 + docs/configuration/performance.md | 65 + docs/configuration/profiles.md | 47 + docs/configuration/timeline-pan-mode.md | 10 + docs/configuration/timeline.md | 79 + docs/configuration/view.md | 117 + docs/developing.md | 73 + docs/examples.md | 981 ++++ {images => docs/images}/camera-carousel.gif | Bin {images => docs/images}/card-on-nest-hub.jpg | Bin {images => docs/images}/cast-your-events.gif | Bin {images => docs/images}/dark-mode.gif | Bin {images => docs/images}/date-picker.gif | Bin {images => docs/images}/editor.gif | Bin {images => docs/images}/expanded.gif | Bin {images => docs/images}/frigate-logo.svg | 0 {images => docs/images}/gallery.png | Bin {images => docs/images}/grid-small.gif | Bin {images => docs/images}/image-view.png | Bin {images => docs/images}/live-thumbnails.gif | Bin {images => docs/images}/media-filtering.gif | Bin {images => docs/images}/media-layout-a.png | Bin {images => docs/images}/media-layout-b.png | Bin {images => docs/images}/menu-mode-above.png | Bin {images => docs/images}/menu-mode-below.png | Bin {images => docs/images}/menu-mode-hidden.png | Bin {images => docs/images}/menu-mode-none.png | Bin {images => docs/images}/menu-mode-overlay.png | Bin {images => docs/images}/microphone.gif | Bin {images => docs/images}/motioneye.gif | Bin .../images}/native-media-control.png | Bin {images => docs/images}/native-ptz.gif | Bin .../images}/navigate-picture-elements.gif | Bin .../images/picture-elements-temperature.png | Bin .../images}/recording-seek-all-cameras.gif | Bin {images => docs/images}/recording-seek.gif | Bin {images => docs/images}/ribbon-timeline.png | Bin {images => docs/images}/star.gif | Bin {images => docs/images}/submenu-select.gif | Bin {images => docs/images}/submenu.gif | Bin {images => docs/images}/substream.gif | Bin .../images}/thumbnails-in-drawer.gif | Bin {images => docs/images}/timeline.gif | Bin {images => docs/images}/triggered.gif | Bin {images => docs/images}/video-scrubbing.gif | Bin {images => docs/images}/viewer-thumbnails.gif | Bin .../viewer-with-thumbnail-next-prev.gif | Bin {images => docs/images}/webrtc.png | Bin {images => docs/images}/zoom.gif | Bin docs/index.html | 80 + docs/screenshots.md | 142 + docs/troubleshooting.md | 222 + docs/usage/2-way-audio.md | 53 + docs/usage/README.md | 16 + docs/usage/_sidebar.md | 13 + docs/usage/casting.md | 45 + docs/usage/url-actions.md | 77 + images/menu_clip.png | Bin 298125 -> 0 bytes images/performance.png | Bin 16856 -> 0 bytes markdown-link-check.json | 7 + package.json | 4 + yarn.lock | 1700 ++++++- 87 files changed, 6360 insertions(+), 4540 deletions(-) create mode 100644 docs/.nojekyll create mode 100644 docs/README.md create mode 100644 docs/_coverpage.md create mode 100644 docs/_sidebar.md create mode 100644 docs/advanced-installation.md create mode 100644 docs/configuration/README.md create mode 100644 docs/configuration/_sidebar.md create mode 100644 docs/configuration/actions.md create mode 100644 docs/configuration/automations.md create mode 100644 docs/configuration/cameras/README.md create mode 100644 docs/configuration/cameras/_sidebar.md create mode 100644 docs/configuration/cameras/engine.md create mode 100644 docs/configuration/cameras/live-provider.md create mode 100644 docs/configuration/common/expanded-warning.md create mode 100644 docs/configuration/common/timeline-seek-info.md create mode 100644 docs/configuration/conditions.md create mode 100644 docs/configuration/dimensions.md create mode 100644 docs/configuration/elements.md create mode 100644 docs/configuration/grid-layout-algorithm.md create mode 100644 docs/configuration/image.md create mode 100644 docs/configuration/live.md create mode 100644 docs/configuration/media-gallery.md create mode 100644 docs/configuration/media-viewer.md create mode 100644 docs/configuration/menu.md create mode 100644 docs/configuration/overrides.md create mode 100644 docs/configuration/performance.md create mode 100644 docs/configuration/profiles.md create mode 100644 docs/configuration/timeline-pan-mode.md create mode 100644 docs/configuration/timeline.md create mode 100644 docs/configuration/view.md create mode 100644 docs/developing.md create mode 100644 docs/examples.md rename {images => docs/images}/camera-carousel.gif (100%) rename {images => docs/images}/card-on-nest-hub.jpg (100%) rename {images => docs/images}/cast-your-events.gif (100%) rename {images => docs/images}/dark-mode.gif (100%) rename {images => docs/images}/date-picker.gif (100%) rename {images => docs/images}/editor.gif (100%) rename {images => docs/images}/expanded.gif (100%) rename {images => docs/images}/frigate-logo.svg (100%) rename {images => docs/images}/gallery.png (100%) rename {images => docs/images}/grid-small.gif (100%) rename {images => docs/images}/image-view.png (100%) rename {images => docs/images}/live-thumbnails.gif (100%) rename {images => docs/images}/media-filtering.gif (100%) rename {images => docs/images}/media-layout-a.png (100%) rename {images => docs/images}/media-layout-b.png (100%) rename {images => docs/images}/menu-mode-above.png (100%) rename {images => docs/images}/menu-mode-below.png (100%) rename {images => docs/images}/menu-mode-hidden.png (100%) rename {images => docs/images}/menu-mode-none.png (100%) rename {images => docs/images}/menu-mode-overlay.png (100%) rename {images => docs/images}/microphone.gif (100%) rename {images => docs/images}/motioneye.gif (100%) rename {images => docs/images}/native-media-control.png (100%) rename {images => docs/images}/native-ptz.gif (100%) rename {images => docs/images}/navigate-picture-elements.gif (100%) rename images/picture_elements_temperature.png => docs/images/picture-elements-temperature.png (100%) rename {images => docs/images}/recording-seek-all-cameras.gif (100%) rename {images => docs/images}/recording-seek.gif (100%) rename {images => docs/images}/ribbon-timeline.png (100%) rename {images => docs/images}/star.gif (100%) rename {images => docs/images}/submenu-select.gif (100%) rename {images => docs/images}/submenu.gif (100%) rename {images => docs/images}/substream.gif (100%) rename {images => docs/images}/thumbnails-in-drawer.gif (100%) rename {images => docs/images}/timeline.gif (100%) rename {images => docs/images}/triggered.gif (100%) rename {images => docs/images}/video-scrubbing.gif (100%) rename {images => docs/images}/viewer-thumbnails.gif (100%) rename {images => docs/images}/viewer-with-thumbnail-next-prev.gif (100%) rename {images => docs/images}/webrtc.png (100%) rename {images => docs/images}/zoom.gif (100%) create mode 100644 docs/index.html create mode 100644 docs/screenshots.md create mode 100644 docs/troubleshooting.md create mode 100644 docs/usage/2-way-audio.md create mode 100644 docs/usage/README.md create mode 100644 docs/usage/_sidebar.md create mode 100644 docs/usage/casting.md create mode 100644 docs/usage/url-actions.md delete mode 100644 images/menu_clip.png delete mode 100644 images/performance.png create mode 100644 markdown-link-check.json diff --git a/README.md b/README.md index 6f151554..7ec613f0 100644 --- a/README.md +++ b/README.md @@ -13,11 +13,11 @@ [![HACS](https://img.shields.io/badge/HACS-default-orange.svg?style=flat-square)](https://hacs.xyz) [![Sponsor](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86&style=flat-square)](https://github.com/sponsors/dermotduffy) -Frigate card example +Frigate Card -# Frigate Lovelace Card +# Frigate Card -A full-featured Frigate Lovelace card: +A comprehensive camera card for Home Assistant. * Live viewing of multiple cameras. * Clips and snapshot browsing via mini-gallery. @@ -25,4517 +25,8 @@ A full-featured Frigate Lovelace card: * Support for filtering events by zone and label. * Arbitrary entity access via menu (e.g. motion sensor access). * Fullscreen mode. -* Carousel/Swipeable media, thumbnails and cameras. +* Grid or carousel/swipeable media, thumbnails and cameras. * Direct media downloads. -* Lovelace visual editing support. +* Lovelace visual editing. * Full [Picture Elements](https://www.home-assistant.io/lovelace/picture-elements/) support. -* Theme friendly. - -## Screenshots Below! - -See more [screenshots](#screenshots) below. - -## Supported Browsers - -Modern Safari, Firefox and Chrome-based browsers are supported, as well as the Home Assistant App on Android and iOS. Other/older browsers may work, but are unsupported. - -## Installation - -* [HACS](https://hacs.xyz/) is **highly** recommended to install the card -- it works for all Home Assistant variants. If you don't have [HACS](https://hacs.xyz/) installed, start there -- then come back to these instructions. - -* Find the card in HACS: - -``` -Home Assistant > HACS > Frontend > "Explore & Add Integrations" > Frigate Card -``` - -* Click `Download this repository with HACS`. - -That's it! - -### Manual Resource Management - -For most users, HACS should automatically add the necessary resources. Should this auto-registration not work you will need to complete one additional step. - -#### Lovelace in "Storage mode" (default) - -* Navigate: - -``` -Three dots menu -> "Edit Dashboard" -> Three dots menu -> "Manage resources" -> "Add Resource" -``` - -* URL: `/hacsfiles/frigate-hass-card/frigate-hass-card.js` -* Resource type: `JavaScript Module` - -#### Lovelace in "YAML mode" (rare) - -You would see`mode: yaml` under `lovelace:` in your `configuration.yaml` if this applies to you. - -* Add the following to `configuration.yaml`: - -```yaml -lovelace: - resources: - - url: /hacsfiles/frigate-hass-card/frigate-hass-card.js - type: module -``` - -* Restart Home Assistant. - - - -### Advanced Users: Manual Installation - -**Note:** This is very rarely needed -- please consider HACS (above)! - -* Download the `frigate-hass-card.zip` attachment of the desired [release](https://github.com/dermotduffy/frigate-hass-card/releases) to a location accessible by Home Assistant. Note that the release will have a series of `.js` files (for HACS users) **and** a `frigate-hass-card.zip` for the convenience of manual installers. -* Unzip the file and move the contents of the `dist/` folder to any subfolder name you'd like, e.g. `frigate-card` is used in the below example. -* Add the location as a Lovelace resource via the UI, or via [YAML configuration](https://www.home-assistant.io/lovelace/dashboards/#resources) such as: - -```yaml -lovelace: - mode: yaml - resources: - - url: /local/frigate-card/frigate-hass-card.js - type: module -``` - -### Advanced Users: Installing Unreleased Versions - -You can install any unreleased version of the card by leveraging the GitHub Actions artifacts that are generated on every revision. Here is a video walkthrough installing the latest revision of the `release-4.1.0` branch: - -
- Click here to show - -https://user-images.githubusercontent.com/29582865/228320074-6a2607f5-c637-48d5-b833-a553f8df8f4f.mp4 - -
- -## Configuration - -At least 1 camera must be configured in the `cameras` section, but otherwise all configuration parameters are optional. - - - -### Camera Options - -The `cameras` block configures a list of cameras the card should support. The first listed camera is the default. Camera configuration is under: - -```yaml -cameras: - - [...camera 0 (default camera)...] - - [...camera 1...] - - [...camera 2...] -``` - -See the [fully expanded cameras configuration example](#config-expanded-cameras) for how these parameters are structured. - - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `camera_entity` | | :white_check_mark: | The Home Assistant camera entity to use with the `frigate` live provider view. Also used to automatically detect the name of the underlying Frigate camera, and the title/icon of the camera. | -| `live_provider` | `auto` | :white_check_mark: | The choice of live stream provider. See [Live Providers](#live-providers) below.| -| `title` | Autodetected from `camera_entity` if that is specified. | :white_check_mark: | A friendly name for this camera to use in the card. | -| `icon` | Autodetected from `camera_entity` if that is specified. | :white_check_mark: | The icon to use for this camera in the camera menu and in the next & previous controls when using the `icon` style. | -| `id` | `camera_entity`, `webrtc_card.entity` or `frigate.camera_name` if set (in that preference order). | :white_check_mark: | An optional identifier to use throughout the card configuration to refer unambiguously to this camera. See [camera IDs](#camera-ids). | -| `engine` | `auto` | :white_check_mark: | Which camera engine to use for this camera. If `auto` the card will attempt to choose the correct engine from the specified options. See [engines](#engines) below for valid options.| -| `frigate` | | :white_check_mark: | Options for a Frigate camera. See [Frigate configuration](#camera-frigate-configuration) below. | -| `dependencies` | | :white_check_mark: | Other cameras that this camera should depend upon. See [camera dependencies](#camera-dependencies-configuration) below. | -| `triggers` | | :white_check_mark: | Define what should cause this camera to update/trigger. See [camera triggers](#camera-trigger-configuration) below. | -| `webrtc_card` | | :white_check_mark: | The WebRTC entity/URL to use for this camera with the `webrtc-card` live provider. See below. | -| `cast` | | :white_check_mark: | Configuration that controls how this camera is "casted" / sent to media players. See below. | -| `dimensions` | | :white_check_mark: | Controls the dimensions and layout for media from this camera. See below. | -| `capabilities` | | :white_check_mark: | Allows selective disabling of camera capabilities. See below. | - - - -#### Available Live Providers - -|Live Provider|Latency|Frame Rate|Loading Time|Installation|Description| -| -- | -- | -- | -- | -- | -- | -|`ha` (default HA configuration)|Poor|High|Better|Builtin|Use the built-in Home Assistant camera stream. The camera doesn't even need to be a Frigate camera! | -|`ha` (when configured with LL-HLS)|Better|High|Better|Builtin|Use the built-in Home Assistant camera streams -- can be configured to use an [LL-HLS](https://www.home-assistant.io/integrations/stream/#ll-hls) feed for lower latency.| -|`ha` (Native WebRTC)|Best|High|Better|Builtin|Use the built-in Home Assistant camera streams -- can be configured to use [native WebRTC](https://www.home-assistant.io/integrations/rtsp_to_webrtc/) offering a very low-latency feed direct to your browser.| -|`image`|Poor|Poor|Best|Builtin|Use refreshing snapshots of the built-in Home Assistant camera streams.| -|`jsmpeg`|Better|Low|Poor|Builtin|Use a the JSMPEG stream.| -|`go2rtc`|Best|High|Better|Builtin|Uses [go2rtc](https://github.com/AlexxIT/go2rtc) to stream live feeds. This is supported by Frigate >= `0.12`.| -|`webrtc-card`|Best|High|Better|Separate installation required|Embed's [AlexxIT's WebRTC Card](https://github.com/AlexxIT/WebRTC) to stream live feed, requires manual extra setup, see [below](#webrtc). Not to be confused with native Home Assistant WebRTC (use `ha` provider above).| - - - -#### Available Camera Engines - -##### Engine Capabilities - -|Engine|Live|Supports clips|Supports Snapshots|Supports Recordings|Supports Timeline|Supports PTZ out of the box|Supports manually configured PTZ|Favorite events|Favorite recordings|Detect new events|Detect new snapshots|Detect new clips| -| - | - | - | - | - | - | - | - | - | - | - | - | - | -|`frigate`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -|`generic`| :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | -|`motioneye`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | - -##### Live providers supported per Engine - -|Engine / Live Provider|`ha`|`image`|`jsmpeg`|`go2rtc`|`webrtc-card`| -| - | - | - | - | - | - | -|`frigate`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -|`generic`| :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :white_check_mark: | -|`motioneye`| :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | - - - -#### Camera Frigate configuration - -The `frigate` block configures options for a Frigate camera. This configuration is included as part of a camera entry in the `cameras` list. - -```yaml -cameras: - - frigate: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `camera_name` | Autodetected from `camera_entity` if that is specified. | :white_check_mark: | The Frigate camera name to use when communicating with the Frigate server, e.g. for viewing clips/snapshots or the JSMPEG live view.| -| `url` | | :white_check_mark: | The URL of the frigate server. If set, this value will be (exclusively) used for a `Camera UI` menu button. All other communication with Frigate goes via Home Assistant. | -| `labels` | | :white_check_mark: | A list of Frigate labels used to filter events (clips & snapshots), e.g. [`person`, `car`].| -| `zones` | | :white_check_mark: | A list of Frigates zones used to filter events (clips & snapshots), e.g. [`front_door`, `front_steps`].| -| `client_id` | `frigate` | :white_check_mark: | The Frigate client id to use. If this Home Assistant server has multiple Frigate server backends configured, this selects which server should be used. It should be set to the MQTT client id configured for this server, see [Frigate Integration Multiple Instance Support](https://docs.frigate.video/integrations/home-assistant/#multiple-instance-support).| - -#### Camera MotionEye configuration - -The `motioneye` block configures options for a MotionEye camera. This configuration is included as part of a camera entry in the `cameras` list. - -```yaml -cameras: - - motioneye: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `url` | | :white_check_mark: | The URL of the MotionEye server. If set, this value will be (exclusively) used for a `Camera UI` menu button. | -| `images` | | :white_check_mark: | Configure how MotionEye images are consumed. See below. | -| `movies` | | :white_check_mark: | Configure how MotionEye movies are consumed. See below. | - -#### Camera MotionEye images and movies configuration - -The `images` and `movies` block configures options for a MotionEye camera. All -options for `images` and `movies` are under their respective blocks. The options -for both are the same. - -```yaml -cameras: - - motioneye: - images: -``` - -```yaml -cameras: - - motioneye: - movies: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `directory_pattern` | `%Y-%m-%d` | :white_check_mark: | The directory that motionEye is configured to store media into. May contain multiple sub-directories separated by `/`. Path must encode the date of the media using MotionEye patterns such as `%Y`, `%m`, `%d`, `%H`, `%M`, `%S` (at least one pattern is required). Consult MotionEye help text for information on these substitutions. | -| `file_pattern` | `%H-%M-%S` | :white_check_mark: | Within a directory (as matched by `directory_pattern`) the media items must exist and match this pattern. `file_pattern` must encode the time of the media using MotionEye patterns such as `%Y`, `%m`, `%d`, `%H`, `%M`, `%S` (at least one pattern is required). Consult MotionEye help text for information on these substitutions. | - -#### Live Provider: Camera go2rtc configuration - -The `go2rtc` block configures use of the `go2rtc` live provider. This configuration is included as part of a camera entry in the `cameras` list. - -```yaml -cameras: - - go2rtc: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `modes` | `[webrtc, mse, mp4, mjpeg]` | :white_check_mark: | An ordered list of `go2rtc` modes to use. Valid values are `webrtc`, `mse`, `mp4` or `mjpeg` values. | -| `stream` | Determined by camera engine (e.g. `frigate` camera name). | :white_check_mark: | A valid `go2rtc` stream name. | -| `url` | Determined by camera engine (e.g. the `frigate` engine will automatically generate a URL for the go2rtc backend that runs in the Frigate container). | :white_check_mark: | The root `go2rtc` URL the card should stream the video from. This is only needed for non-Frigate usecases, or advanced Frigate usecases. Example: `http://my-custom-go2rtc:1984` | - -#### Live Provider: Camera WebRTC Card configuration - -Configures the `webrtc_card` live provider: - -```yaml -cameras: - - webrtc_card: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `entity` | | :white_check_mark: | The RTSP entity to pass to the WebRTC Card for this camera. | -| `url` | Depends on the camera engine (e.g. Frigate will use the camera name by default since this is the [recommended setup](https://deploy-preview-4055--frigate-docs.netlify.app/guides/configuring_go2rtc/))| :white_check_mark: | The RTSP url to pass to the WebRTC Card. | -| `*`| | :white_check_mark: | Any options specified in the `webrtc_card:` YAML dictionary are silently passed through to the AlexxIT's WebRTC Card. See [WebRTC Configuration](https://github.com/AlexxIT/WebRTC#configuration) for full details this external card provides. | - - -See [Using the WebRTC Card](#webrtc) below for more details on how to use the WebRTC Card live provider. - -#### Live Provider: Image Configuration - -All configuration is under: - -```yaml -cameras: - - image: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `refresh_seconds` | 1 | :white_check_mark: | The image will be refreshed at least every `refresh_seconds`. `0` implies no refreshing. | -| `url` | | :white_check_mark: | **Advanced**: A static image URL to be fetched in lieu of the Home Assistant image for the given camera. This may be useful for advanced configurations where the camera image is being provided by some non-Home Assistant system. This will also set the temporary loading image used when `show_image_during_load` is set to true under the `live` configuration. | - -#### Live Provider: JSMPEG Configuration - -All configuration is under: - -```yaml -cameras: - - jsmpeg: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `options` | | :white_check_mark: | **Advanced users only**: Control the underlying [JSMPEG library options](https://github.com/phoboslab/jsmpeg#usage). Supports setting these JSMPEG options `{audio, video, pauseWhenHidden, disableGl, disableWebAssembly, preserveDrawingBuffer, progressive, throttled, chunkSize, maxAudioLag, videoBufferSize, audioBufferSize}`. This is not necessary for the vast majority of users: only set these flags if you know what you're doing, as you may entirely break video rendering in the card.| - - - - - -#### Camera Dependency Configuration - -The `dependencies` block configures other cameras as dependents of this camera. Dependent cameras have their media fetched and merged with this camera by default, and offer their respective live views as 'substreams' of the main (depended upon) camera. Configuration is under: - -```yaml -cameras: - - dependencies: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `cameras` | | :white_check_mark: | An optional list of other camera identifiers (see [camera IDs](#camera-ids)). If specified the card will fetch media for this camera and *also* recursively for the named cameras by default. Live views for the involved cameras will be available as 'substreams' of the main (depended upon) camera. All dependent cameras must themselves be a configured camera in the card. This can be useful to group events for cameras that are close together, to show multiple related live views, to always have clips/snapshots show fully merged events across all cameras or to show events for the `birdseye` camera that otherwise would not have events itself.| -| `all_cameras` | `false` | :white_check_mark: | Shortcut to specify all other cameras as dependent cameras.| - - - -#### Camera Trigger Configuration - -The `triggers` block configures what triggers a camera. Triggering can be used to activate an action (e.g. view a camera in live, reset the card to the default view). See [`view.triggers`](#view.triggers) to control what happens when a camera is triggered. - -```yaml -cameras: - - triggers: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `events` | `[events, clips, snapshots]` | :white_check_mark: | Whether to trigger the camera when `events` occur (whether or not media is available) or whenever updated `clips` or `snapshots` are detected. Detection support varies by camera engine, see [engine capabilities](#engines). | -| `motion` | `false` | :white_check_mark: | Whether to not to trigger the camera by automatically detecting and using the motion `binary_sensor` for this camera. This autodetection only works for Frigate cameras, and only when the motion `binary_sensor` entity has been enabled in Home Assistant.| -| `occupancy` | `false` | :white_check_mark: | Whether to not to trigger the camera by automatically detecting and using the occupancy `binary_sensor` for this camera and its configured zones and labels. This autodetection only works for Frigate cameras, and only when the occupancy `binary_sensor` entity has been enabled in Home Assistant. If this camera has configured zones, only occupancy sensors for those zones are used -- if the overall _camera_ occupancy sensor is also required, it can be manually added to `entities`. If this camera has configured labels, only occupancy sensors for those labels are used. | -| `entities` | | :white_check_mark: | Whether to not to trigger the camera when the state of any Home Assistant entity becomes active (i.e. state becomes `on` or `open`). This works for Frigate or non-Frigate cameras.| - -#### Camera Cast Configuration - -The `cast` block configures what how a camera is cast / sent to media players. - -```yaml -cameras: - - cast: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `method` | `standard` | :white_check_mark: | Whether to use `standard` media casting to send the live view to your media player, or to instead cast a `dashboard` you have manually setup. Casting a dashboard supports a much wider variety of video media, including low latency video providers (e.g. `go2rtc`). This setting has no effect on casting non-live media. | -| `dashboard` | | :white_check_mark: | Configuration for the dashboard to cast. See below. | - -See the [dashboard method cast example](#cast-dashboard-example). - -#### Camera Cast Dashboard Configuration - -```yaml -cameras: - - cast: - dashboard: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `dashboard_path` | | :white_check_mark: | A required field that specifies the name of the dashboard to cast. You can see this name in your HA URL when you visit the dashboard. | -| `view_path` | | :white_check_mark: | A required field that specifies view/"tab" on that dashboard to cast. This is the value you have specified in the `url` field of the view configuration on the dashboard. | - -### Camera Dimensions Configuration - -The `dimensions` block configures the dimensions and layout of media from a given camera. - -```yaml -cameras: - - dimensions: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `aspect_ratio` | | :white_check_mark: | An optional aspect ratio for media from this camera which will be used in `live` or media viewer related views (e.g. `clip`, `snapshot` and `recording`). Format is the same as the parameter of the same name under the [dimensions block](#dimensions) (which controls dimensions for the whole card), e.g. `16 / 9`. | -| `layout` | | :white_check_mark: | How the media should be laid out *within* the camera dimensions. See below. | - -### Camera Dimensions Layout Configuration - -The `layout` block configures the dimensions and layout of media from a given camera. - -```yaml -cameras: - - dimensions: - layout: -``` - -This block is used to control the fit and position of the media _within_ the camera dimensions (in order to control the dimensions for the whole card see [the card dimensions parameter](#dimensions) ). As the default behavior is to always expand to fit the media precisely, these options only make sense if the camera `dimensions.aspect_ratio` is set to a static value that forces a particular aspect ratio that does not match the camera media. - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `fit` | `contain` | :white_check_mark: | If `contain`, the media is contained within the card and letterboxed if necessary. If `cover`, the media is expanded proportionally (i.e. maintaining the media aspect ratio) until the card is fully covered. If `fill`, the media is stretched to fill the card (i.e. ignoring the media aspect ratio). See [CSS object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) for technical details and a visualization. | -| `position` | | :white_check_mark: | A dictionary that contains an `x` and `y` percentage (`0` - `100`) to control the position of the media when the fit is `cover`. This can be effectively used to "pan" the media around. At any given time, only one of `x` and `y` will have an effect, depending on whether media width is larger than the card width (in which case `x` controls the position) or the media height is larger than the card height (in which case `y` controls the position). A value of `0` means maximally to the left or top of the media, a value of `100` means maximally to the right or bottom of the media. See [CSS object-position](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) for technical details and a visualization. | - -See [media layout examples](#media-layout-examples). - -### Camera Capabilities - -The `capabilities` block allows selected disabling of auto-detected camera capabilities. This is rarely used, with substreams being a notable exception. - -```yaml -cameras: - - capabilities: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `disable` | | :white_check_mark: | A list of camera capabilities to disable. By default all capabilities supported by the camera are enabled. | -| `disable_except` | | :white_check_mark: | A list of camera capabilities to leave enabled if supported. Everything else will be disabled. | - -#### Capabilities - -| Capability | Purpose | -| - | - | -| `clips` | Clips can be fetched from the camera. | -| `favorite-events` | Events can be favorited. | -| `favorite-recordings` | Recordings can be favorited. | -| `live` | Live video can be received from the camera. | -| `menu` | The camera should show up in the card camera menu. | -| `ptz` | The camera can be PTZ controlled. | -| `recordings` | Recordings can be fetched from the camera. | -| `seek` | Clips can be seeked / scrubbed by the timeline. | -| `snapshots` | Snapshots can be fetched from the camera. | -| `substream` | The camera can be used as a substream on another camera. | - - - -#### Camera IDs: Referring to cameras in card configuration - -Each camera configured in the card has a single identifier (`id`). For a given camera, this will be one of the camera {`id`, `camera_entity`, `webrtc_card.entity` or `frigate.camera_name`} parameters for that camera -- in that order of precedence. These ids may be used in conditions, dependencies or custom actions to refer to a given camera unambiguously. - -#### Example - -See [the basic cameras configuration example](#basic-cameras-configuration) below. - - - -### Camera Global Options - -**Advanced:** The optional `cameras_global` block configures global options that -apply to all cameras from the `cameras` section. For large configs, this can -avoid significant repetition across cameras. The configuration is under: - -```yaml -cameras_global: -``` - -The configuration options are identical to a single [camera entry](#camera-options). - -### View Options - -All configuration is under: - - ```yaml -view: -``` - -See the [fully expanded view configuration example](#config-expanded-view) for how these parameters are structured. - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `default` | `live` | :white_check_mark: | The view to show in the card by default. The default camera is the first one listed. See [views](#views) below.| -| `camera_select` | `current` | :white_check_mark: | The view to show when a new camera is selected (e.g. in the camera menu). If `current` the view is unchanged when a new camera is selected. Other acceptable values may be seen at [views](#views) below.| -| `dark_mode` | `off` | :white_check_mark: | Whether or not to turn dark mode `on`, `off` or `auto` to automatically turn on if the card `interaction_seconds` has expired (i.e. card has been left unattended for that period of time) or if dark mode is enabled in the HA profile theme setting. Dark mode dims the brightness by `25%`.| -| `interaction_seconds` | `300` | :white_check_mark: | After a mouse/touch interaction with the Frigate card, it will be considered "interacted with" until this number of seconds elapses without further interaction. May be used in conditions with the `interaction` parameter of a [Frigate card condition](#frigate-card-condition) or with `reset_after_interaction` (below). `0` means no interactions are reported / acted upon. | -| `reset_after_interaction` | `true` | :white_check_mark: | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | -| `update_seconds` | `0` | :white_check_mark: | A number of seconds after which to automatically update/refresh the default view. If the default view occurs sooner (e.g. manually) the timer will start over. `0` disables this functionality.| -| `update_force` | `false` | :white_check_mark: | Whether automated card updates should ignore user interaction. | -| `update_entities` | | :white_check_mark: | **YAML only**: A card-wide list of entities that should cause the view to reset to the default (if the entity only pertains to a particular camera use `triggers` for the selected camera instead, see [Trigger Configuration](#camera-triggers-configuration)). | -| `update_cycle_camera` | `false` | :white_check_mark: | When set to `true` the selected camera is cycled on each default view change. | -| `render_entities` | | :white_check_mark: | **YAML only**: A list of entity ids that should cause the card to re-render 'in-place'. The view/camera is not changed. `update_*` flags do not pertain/relate to the behavior of this flag. This should **very** rarely be needed, but could be useful if the card is both setting and changing HA state of the same object as could be the case for some complex `card_mod` scenarios ([example](https://github.com/dermotduffy/frigate-hass-card/issues/343)). | -| `triggers` | | :white_check_mark: | How to react when a camera is [triggered](#view.triggers). | -| `actions` | | :white_check_mark: | Actions to use for all views, individual actions may be overriden by view-specific actions. See [actions](#actions) below.| - - - -#### View: Triggers configuration - -All configuration is under: - -```yaml -view: - triggers: -``` - -The `view.triggers` block controls how the card reacts when a camera is triggered (note that _what_ triggers the camera is controlled by the `triggers` block within the config for a given camera). This can be used for a variety of purposes, such as allowing the card to automatically "follow the action" (i.e. change to `live` for a camera that triggers). - -When a camera untriggers (e.g. an entity state returning to something other than `on` or `open`), an action can also be taken, with an optional number of seconds to wait prior to the acting (see `untrigger_seconds`). - -By default, triggering is only allowed when there is no ongoing human -interaction with the card. This behavior can be controlled by the -`interaction_mode` parameter. - -Triggers based on Home Assistant entities require state *changes* -- when the card is first started, it takes an active change in state to trigger (i.e. an already occupied room will not trigger, but a newly occupied room will). - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `filter_selected_camera` | `false` | :white_check_mark: | If set to `true` will only trigger on the currently selected camera.| -| `show_trigger_status` | `false` | :white_check_mark: | Whether or not the `live` view should show a visual indication that it is triggered (a pulsing border around the camera edge). | -| `untrigger_seconds` | `0` | :white_check_mark: | The number of seconds to wait after a camera untriggers before considering the card untriggered and taking the `untrigger` action. | -| `actions` | | :white_check_mark: | The actions to take when a camera is triggered (see below). | - -#### View: Triggers Action configuration - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `trigger` | `default` | :white_check_mark | If set to `default` the default view of the card will be reloaded. If set to `live` the triggered camera will be selected in `live` view. If set to `media` the appropriate media view (e.g. `clip` or `snapshot`) will be chosen to match a newly available media item (please note that only some camera engines support new media detection, e.g. `frigate`, see [engines](#engines)). If set to `none` no action is taken. | -| `untrigger` | `none` | :white_check_mark | If set to `default` the the default view of the card will be reloaded. If set to `none` no action will be taken. | -| `interaction_mode` | `inactive` | :white_check_mark: | Whether actions should be taken when the card is being interacted with. If `all`, actions will always left be taken regardless. If `inactive` actions will only be taken if the card has *not* had human interaction recently (as defined by `view.interaction_seconds`). If `active` actions will only be taken if the card *has* had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed. | - -### Menu Options - -All configuration is under: - - ```yaml -menu: -``` - -See the [fully expanded menu configuration example](#config-expanded-menu) for how these parameters are structured. - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `style` | `hidden` | :white_check_mark: | The menu style to show by default, one of `none`, `hidden`, `hover`, `hover-card`, `overlay`, or `outside`. See [menu styles](#menu-styles) below.| -| `position` | `top` | :white_check_mark: | Whether to show the menu on the `left`, `right`, `top` or `bottom` side of the card. Note that for the `outside` style only the `top` and `bottom` positions have an effect.| -| `alignment` | `left` | :white_check_mark: | Whether to align the menu buttons to the `left`, `right`, `top` or `bottom` of the menu. Some selections may have no effect depending on the value of `position` (e.g. it doesn't make sense to `left` align icons on a menu with `position` to the `left`).| -| `button_size` | 40 | :white_check_mark: | The size of the menu buttons in pixels. Must be >= `20`.| -| `buttons` | | :white_check_mark: | Whether to show or hide built-in buttons. See below. | - - - -#### Menu Options: Buttons - -All configuration is under: - -```yaml -menu: - buttons: - [button]: -``` - -##### Buttons - -| Option | Overridable | Description | -| - | - | - | -| `frigate` | :white_check_mark: | The `Frigate` menu button: brings the user to the default configured view (`view.default`), or collapses/expands the menu if the `menu.style` is `hidden` . | -| `cameras` | :white_check_mark: | The camera selection submenu. Will only appear if multiple cameras are configured. | -| `live` | :white_check_mark: | The `live` view menu button: brings the user to the `live` view. See [views](#views) below.| -| `clips` | :white_check_mark: | The `clips` view menu button: brings the user to the `clips` view on tap and the most-recent `clip` view on hold. See [views](#views) below. This button will never be shown if the `frigate.camera_name` for the selected camera is not auto-detected/specified (e.g. non-Frigate cameras), or if the `frigate.camera_name` is `birdseye`.| -| `snapshots` | :white_check_mark: | The `snapshots` view menu button: brings the user to the `clips` view on tap and the most-recent `snapshot` view on hold. See [views](#views) below. This button will never be shown if the `frigate.camera_name` for the selected camera is not auto-detected/specified (e.g. non-Frigate cameras), or if the `frigate.camera_name` is `birdseye`.| -| `recordings` | :white_check_mark: | The `recordings` view menu button: brings the user to the `recordings` view on tap and the most-recent `recording` view on hold. See [views](#views) below. This button will never be shown if the `frigate.camera_name` for the selected camera is not auto-detected/specified (e.g. non-Frigate cameras), or if the `frigate.camera_name` is `birdseye`.| -| `image` | :white_check_mark: | The `image` view menu button: brings the user to the static `image` view. See [views](#views) below.| -| `download` | :white_check_mark: | The `download` menu button: allow direct download of the media being displayed.| -| `camera_ui` | :white_check_mark: | The `camera_ui` menu button: brings the user to a context-appropriate page on the UI of their camera engine (e.g. the Frigate camera homepage). Will only appear if the camera engine supports a camera UI (e.g. if `frigate.url` option is set for `frigate` engine users).| -| `fullscreen` | :white_check_mark: | The `fullscreen` menu button: expand the card to consume the fullscreen. | -| `expand` | :white_check_mark: | The `expand` menu button: expand the card into a popup/dialog. | -| `screenshot` | :white_check_mark: | The `screenshot` menu button: take a screenshot of the loaded media (e.g. a still from a video). | -| `timeline` | :white_check_mark: | The `timeline` menu button: show the event timeline. | -| `media_player` | :white_check_mark: | The `media_player` menu button: sends the visible media to a remote media player. Supports Frigate clips, snapshots and live camera (only for cameras that specify a `camera_entity` and only using the default HA stream (equivalent to the `ha` live provider). `jsmpeg` or `webrtc-card` are not supported, although live can still be played as long as `camera_entity` is specified. In the player list, a `tap` will send the media to the player, a `hold` will stop the media on the player. | -| `microphone` | :white_check_mark: | The `microphone` button allows usage of 2-way audio in certain configurations. See [Using 2-way audio](#using-2-way-audio). | -| `show_ptz` | :white_check_mark: | The `show_ptz` button shows or hide the PTZ controls. | - -##### Configuration on each button - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `enabled` | `true` for all buttons except `image` | :white_check_mark: | Whether or not to show the button. | -| `priority` | `50` | :white_check_mark: | The button priority. Higher priority buttons are ordered closer to the start of the menu alignment (i.e. a button with priority `70` will order further to the left than a button with priority `60`, when the menu alignment is `left`). Minimum `0`, maximum `100`.| -| `icon` | | :white_check_mark: | An icon to overriding the default for that button, e.g. `mdi:camera-front`. | -| `alignment` | `matching` | :white_check_mark: | Whether this button should have an alignment that is `matching` the menu alignment or `opposing` the menu. Can be used to create two separate groups of buttons on the menu. `priority` orders buttons within a given `alignment`. | - -### Live Options - -All configuration is under: - - ```yaml -live: -``` - -See the [fully expanded live configuration example](#config-expanded-live) for how these parameters are structured. - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `preload` | `false` | :heavy_multiplication_x: | Whether or not to preload the live view. Preloading causes the live view to render in the background regardless of what view is actually shown, so it's instantly available when requested. This consumes additional network/CPU resources continually. | -| `auto_play` | `[selected, visible]` | :heavy_multiplication_x: | A list of conditions in which live camera feeds are automatically played.`selected` will automatically play when a camera is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play. Some live providers (e.g. `webrtc-card`, `jsmpeg`) do not support the prevention of automatic play on initial load, but should still respect the value of this flag on play-after-pause.| -| `auto_pause` | `[]` | :heavy_multiplication_x: | A list of conditions in which live camera feeds are automatically paused. `unselected` will automatically pause when a camera is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause. **Caution**: Some live providers (e.g. `jsmpeg`) may not offer human-accessible means to resume play if it is paused, unless the `auto_play` option (above) is used.| -| `auto_mute` | `[unselected, hidden, microphone]` | :heavy_multiplication_x: | A list of conditions in which live camera feeds are muted. `unselected` will automatically mute when a camera is unselected in the carousel, `hidden` will automatically mute when the browser/tab becomes hidden or `microphone` will automatically mute after the microphone is muted as long as the camera stays selected (see the `live.microphone.mute_after_microphone_mute_seconds` to control how long after). Use an empty list (`[]`) to never automatically mute. Note that if `auto_play` is enabled, the stream may mute itself automatically in order to honor the `auto_play` setting, as some browsers will not auto play media that is unmuted -- that is to say, where necessary, the `auto_play` parameter will take priority over the `auto_mute` parameter.| -| `auto_unmute` | `[microphone]` | :heavy_multiplication_x: | A list of conditions in which live camera feeds are unmuted. `selected` will automatically unmute when a camera is unselected in the carousel, `visible` will automatically unmute when the browser/tab becomes visible or `microphone` will automatically unmute after the microphone is unmuted. Use an empty list (`[]`) to never automatically unmute.| -| `lazy_load` | `true` | :heavy_multiplication_x: | Whether or not to lazily load cameras in the camera carousel. Setting this will `false` will cause all cameras to load simultaneously when the `live` carousel is opened (or cause all cameras to load continually if both `lazy_load` and `preload` are `true`). This will result in a smoother carousel experience at a cost of (potentially) a substantial amount of continually streamed data. | -| `lazy_unload` | `[]` | :heavy_multiplication_x: | A list of conditions in which live camera feeds are unloaded. `unselected` will lazy-unload a camera when it is unselected in the carousel and `hidden` will lazy-unload all cameras when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically unload. This will cause a reloading delay on revisiting that camera in the carousel but will save the streaming network resources that are otherwise consumed. This option has no effect if `lazy_load` is false. Some live providers (e.g. `webrtc-card`) implement their own lazy unloading independently which may occur regardless of the value of this setting.| -| `draggable` | `true` | :heavy_multiplication_x: | Whether or not the live carousel can be dragged left or right, via touch/swipe and mouse dragging. | -| `zoomable` | `true` | :white_check_mark: | Whether or not the live carousel can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | -| `transition_effect` | `slide` | :heavy_multiplication_x: | Effect to apply as a transition between live cameras. Accepted values: `slide` or `none`. | -| `show_image_during_load` | `true` | :white_check_mark: | If `true`, during the initial stream load, the `image` live provider will be shown instead of the loading video stream. This still image will auto-refresh and is replaced with the live stream once loaded. | -| `actions` | | :white_check_mark: | Actions to use for the `live` view. See [actions](#actions) below.| -| `controls` | | :white_check_mark: | Configuration for the `live` view controls. See below. | -| `microphone` | | :white_check_mark: | See [microphone](#microphone) below.| -| `display` | | :white_check_mark: | See [display](#live-display) below.| - -#### Live Controls - -All configuration is under: - -```yaml -live: - controls: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `builtin` | `true` | :white_check_mark: | Whether to show the built in (browser) video controls on live video. | - -#### Live Controls: Thumbnails - -All configuration is under: - -```yaml -live: - controls: - thumbnails: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `mode` | `none` | :white_check_mark: | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| -| `size` | 100 | :white_check_mark: | The size of the thumbnails in the thumbnail carousel in pixels. Must be >= `75` and <= `175`. | -| `show_details` | `false` | :white_check_mark: | Whether to show event details (e.g. duration, start time, object detected, etc) alongside the thumbnail.| -| `show_download_control` | `true` | :white_check_mark: | Whether to show the download control on each thumbnail.| -| `show_favorite_control` | `true` | :white_check_mark: | Whether to show the favorite ('star') control on each thumbnail.| -| `show_timeline_control` | `true` | :white_check_mark: | Whether to show the timeline ('target') control on each thumbnail.| -| `media_type` | `events` | :white_check_mark: | Whether to load `events` or `recordings` media.| -| `events_media_type` | `all` | :white_check_mark: | Whether to show `clips`, `snapshots` or `all` in the thumbnail carousel in the `live` view. This setting is only relevant when the `media_type` parameter (above) is set to `events`.| - -#### Live Controls: Next / Previous - -All configuration is under: - -```yaml -live: - controls: - next_previous: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `style` | `chevrons` | :white_check_mark: | When viewing live cameras, what kind of controls to show to move to the previous/next camera. Acceptable values: `chevrons`, `icons`, `none` . | -| `size` | 48 | :white_check_mark: | The size of the next/previous controls in pixels. Must be >= `20`. | - -#### Live Controls: Mini Timeline - -All configuration is under: - -```yaml -live: - controls: - timeline: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `mode` | `none` | :white_check_mark: | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| -| `pan_mode` | `pan`| :white_check_mark: | If set to `pan` then dragging the timeline will have no effect on the media. If set to `seek` will open media for that time and seek to that position . If set to `seek-in-media` will seek within the opened media only. If set to `seek-in-camera` will seek within the selected camera only. | -| `style` | `ribbon` | :white_check_mark: | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold` (below). | -| `window_seconds` | `3600` | :white_check_mark: | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | -| `clustering_threshold` | `3` | :white_check_mark: | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | -| `events_media_type` | `all` | :white_check_mark: | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot.| -| `show_recordings` | `true` | :white_check_mark: | Whether to show recordings on the timeline (specifically: which hours have any recorded content).| - -**Caution**: 🚩 For optimal UX, keep the settings for the mini-timeline in the `live` and `media_viewer` identical. Dragging the timeline may cause the card to change between the `live` view and `media_viewer` based views as the user pans between the past and present -- if the settings are different the timeline must "reset". - - - -#### Live Controls: Title - -All configuration is under: - -```yaml -live: - controls: - title: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `mode` | `popup-bottom-right` | :white_check_mark: | How to display the live camera title. Acceptable values: `none`, `popup-top-left`, `popup-top-right`, `popup-bottom-left`, `popup-bottom-right` . | -| `duration_seconds` | `2` | :white_check_mark: | The number of seconds to display the title popup. `0` implies forever.| - - - -#### Live: Microphone - -All configuration is under: - -```yaml -live: - microphone: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `always_connected` | `false` | :white_check_mark: | Whether or not to keep the microphone stream continually connected while the card is running, or only when microphone is used (default). In the latter case there'll be a connection reset when the microphone is first used -- using this option can avoid that reset.| -| `disconnect_seconds` | `90` | :white_check_mark: | The number of seconds after microphone usage to disconnect the microphone from the stream. `0` implies never. Not relevant if `always_connected` is `true`.| -| `mute_after_microphone_mute_seconds` | `60` | :white_check_mark: | The number of seconds after the microphone mutes to automatically mute the inbound audio when `live.auto_mute` includes `microphone`.| - -See [Using 2-way audio](#using-2-way-audio) for more information about the very particular requirements that must be followed for 2-way audio to work. - - - -#### Live: PTZ - -Controls a PTZ (Pan Tilt Zoom) controller overlay. All configuration is under: - -```yaml -live: - ptz: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `mode` | `on` | :white_check_mark: | When `on` will show a PTZ control if so configured (manually, or by the camera engine), if `off` will not show any control. | -| `position` | `bottom-right` | :white_check_mark: | Whether to position the control on the `top-left`, `top-right`, `bottom-left` or `bottom-right`. This may be overridden by using the `style` parameter to precisely control placement. | -| `actions_left`, `actions_right`, `actions_up`, `actions_down`, `actions_zoom_in`, `actions_zoom_out`, `actions_home` | Default is set by camera engine of the selected camera | :white_check_mark: | The [Home Assistant actions](https://www.home-assistant.io/dashboards/actions/) to call when this icon is interacted with. | -| `orientation` | `horizontal` | :white_check_mark: | Whether to show a `vertical` or `horizontal` PTZ control. | -| `hide_pan_tilt` | `false` | :white_check_mark: | When `true` the Pan & Tilt buttons of the control is hidden | -| `hide_zoom` | `false` | :white_check_mark: | When `true` the Zoom button of the control is hidden | -| `hide_home` | `false` | :white_check_mark: | When `true` the Home button of the control is hidden | -| `data_left`, `data_right`, `data_up`, `data_down`, `data_zoom_in`, `data_zoom_out`, `data_home` | | :white_check_mark: | Shorthand for a `tap_action` that calls the `service` with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[button]`. If both `actions_X` and `data_X` are specified, `actions_X` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). | -| `service` | | :white_check_mark: | An optional Home Assistant service to call when the `data_` parameters are used. | -| `style` | | :white_check_mark: | Optionally position and style the element using CSS. Similar to [Picture Element styling](https://www.home-assistant.io/dashboards/picture-elements/#how-to-use-the-style-object), except without any default, e.g. `left: 42%` | - - - -#### Live: Display - -All configuration is under: - -```yaml -live: - display: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `mode` | `single` | :white_check_mark: | Whether to display a `single` media item at a time, or a media item for all cameras in a `grid` configuration.| -| `grid_selected_width_factor` | `2` | :white_check_mark: | How much to scale up the selected media item in a grid. A value of `1` will not scale the selected item at all, the default value of `2` will scale the media item width to twice what it would otherwise be, etc. | -| `grid_columns` | | :white_check_mark: | If specified the grid will always have exactly this number of columns.| -| `grid_max_columns` | `4` | :white_check_mark: | If specified, and `grid_columns` is not specified, the grid will not render more than this number of columns. The precise number will be calculated based on the [grid layout algorithm](#grid-layout-algorith). | - - - -##### Grid Layout Algorithm - -The grid will lay out cameras roughly in the order they are specified in the config (items may be moved to optimize grid 'density'). The following algorithm is used to calculate the number of columns. This attempts to offers a balance between configurability, reasonable display in a typical Lovelace card width and reasonable display in a typical fullscreen display. - -* Use `grid_columns` if specified. -* Otherwise, use the largest number of columns in the range `[2 - grid_max_columns]` that will fit at least a `600px` column width. -* Otherwise, use the largest number of columns in the range `[2 - grid_max_columns]` that will fit at least a `190px` column width. -* Otherwise, there will be `1` column only. - -### Media Viewer Options - -The `media_viewer` is used for viewing all `clip`, `snapshot` or recording media, in a media carousel. - -All configuration is under: - -```yaml -media_viewer: -``` - -See the [fully expanded Media viewer configuration example](#config-expanded-media-viewer) for how these parameters are structured. - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `auto_play` | `[selected, visible]` | :heavy_multiplication_x: | A list of conditions in which media items are automatically played.`selected` will automatically play when a media item is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play.| -| `auto_pause` | `[unselected, hidden]` | :heavy_multiplication_x: | A list of conditions in which media items are automatically paused. `unselected` will automatically pause when a media item is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause.| -| `auto_mute` | `[unselected, hidden]` | :heavy_multiplication_x: | A list of conditions in which media items are muted. `unselected` will automatically mute when a media item is unselected in the carousel and `hidden` will automatically mute when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically mute.| -| `auto_unmute` | `[]` | :heavy_multiplication_x: | A list of conditions in which media items are unmuted. `selected` will automatically unmute when a media item is unselected in the carousel and `visible` will automatically unmute when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically unmute. Note that some browsers will not allow automated unmute until the user has interacted with the page in some way -- if the user has not then the browser may pause the media instead.| -| `lazy_load` | `true` | :heavy_multiplication_x: | Whether or not to lazily load media in the Media viewer carousel. Setting this will false will fetch all media immediately which may make the carousel experience smoother at a cost of (potentially) a substantial number of simultaneous media fetches on load. | -| `draggable` | `true` | :heavy_multiplication_x: | Whether or not the Media viewer carousel can be dragged left or right, via touch/swipe and mouse dragging. | -| `zoomable` | `true` | :heavy_multiplication_x: | Whether or not the Media Viewer can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | -| `snapshot_click_plays_clip` | `true` | :heavy_multiplication_x: | Whether clicking on a snapshot in the media viewer should play a related clip. | -| `transition_effect` | `slide` | :heavy_multiplication_x: | Effect to apply as a transition between event media. Accepted values: `slide` or `none`. | -| `controls` | | :heavy_multiplication_x: | Configuration for the Media viewer controls. See below. | -| `actions` | | :heavy_multiplication_x: | Actions to use for all views that use the `media_viewer` (e.g. `clip`, `snapshot`). See [actions](#actions) below.| - -#### Media Viewer Controls - -All configuration is under: - -```yaml -media_viewer: - controls: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `builtin` | `true` | :white_check_mark: | Whether to show the built in (browser) video controls on media viewer video. | - -#### Media Viewer Controls: Next / Previous - -All configuration is under: - -```yaml -media_viewer: - controls: - next_previous: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `style` | `thumbnails` | :heavy_multiplication_x: | When viewing media, what kind of controls to show to move to the previous/next media item. Acceptable values: `thumbnails`, `chevrons`, `none` . | -| `size` | 48 | :heavy_multiplication_x: | The size of the next/previous controls in pixels. Must be >= `20`.| - -#### Media Viewer Controls: Thumbnails - -All configuration is under: - -```yaml -media_viewer: - controls: - thumbnails: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `mode` | `none` | :heavy_multiplication_x: | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| -| `size` | 100 | :heavy_multiplication_x: | The size of the thumbnails in the thumbnail carousel pixels. Must be >= `75` and <= `175`.| -| `show_details` | `false` | :heavy_multiplication_x: | Whether to show event details (e.g. duration, start time, object detected, etc) alongside the thumbnail.| -| `show_download_control` | `true` | :heavy_multiplication_x: | Whether to show the download control on each thumbnail.| -| `show_favorite_control` | `true` | :heavy_multiplication_x: | Whether to show the favorite ('star') control on each thumbnail.| -| `show_timeline_control` | `true` | :heavy_multiplication_x: | Whether to show the timeline ('target') control on each thumbnail.| - -#### Media Viewer Controls: Mini Timeline - -All configuration is under: - -```yaml -media_viewer: - controls: - timeline: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `mode` | `none` | :heavy_multiplication_x: | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the -`left` or `right` of the media or to hide it entirely (`none`).| -| `pan_mode` | `pan`| :white_check_mark: | If set to `pan` then dragging the timeline will have no effect on the media. If set to `seek` will open media for that time and seek to that position . If set to `seek-in-media` will seek within the opened media only. If set to `seek-in-camera` will seek within the selected camera only. | -| `style` | `ribbon` | :heavy_multiplication_x: | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold` (below). | -| `window_seconds` | `3600` | :heavy_multiplication_x: | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | -| `clustering_threshold` | `3` | :heavy_multiplication_x: | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | -| `events_media_type` | `all` | :heavy_multiplication_x: | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot. | -| `show_recordings` | `true` | :heavy_multiplication_x: | Whether to show recordings on the timeline (specifically: which hours have any recorded content).| - -**Caution**: 🚩 For optimal UX, keep the settings for the mini-timeline in the `live` and `media_viewer` identical. Dragging the timeline may cause the card to change between the `live` view and `media_viewer` based views as the user pans between the past and present -- if the settings are different the timeline must "reset". - -#### Media Viewer Controls: Title - -All configuration is under: - -```yaml -media_viewer: - controls: - title: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `mode` | `popup-bottom-right` | :heavy_multiplication_x: | How to display the Media viewer media title. Acceptable values: `none`, `popup-top-left`, `popup-top-right`, `popup-bottom-left`, `popup-bottom-right` . | -| `duration_seconds` | `2` | :heavy_multiplication_x: | The number of seconds to display the title popup. `0` implies forever.| - - - -#### Media Viewer: Display - -All configuration is under: - -```yaml -media_viewer: - display: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `mode` | `single` | :white_check_mark: | Whether to display a `single` media item at a time, or a media item for all cameras in a `grid` configuration.| -| `grid_selected_width_factor` | `2` | :white_check_mark: | How much to scale up the selected media item in a grid. A value of `1` will not scale the selected item at all, the default value of `2` will scale the media item width to twice what it would otherwise be, etc. | -| `grid_columns` | | :white_check_mark: | If specified the grid will always have exactly this number of columns.| -| `grid_max_columns` | `4` | :white_check_mark: | If specified, and `grid_columns` is not specified, the grid will not render more than this number of columns. The precise number will be calculated based on the [grid layout algorithm](#grid-layout-algorith). | - - - -### Media Gallery Options - -The `media_gallery` is used for providing an overview of all `clips`, `snapshots` and `recordings` in a thumbnail gallery. - -All configuration is under: - -```yaml -media_gallery: -``` - -See the [fully expanded media gallery configuration example](#config-expanded-media-gallery) for how these parameters are structured. - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `controls` | | :heavy_multiplication_x: | Configuration for the Media viewer controls. See below. | -| `actions` | | :heavy_multiplication_x: | Actions to use for all views that use the `media_gallery` (e.g. `clips`, `snapshots`, `recordings`). See [actions](#actions) below.| - -#### Media Gallery Controls: Filter - -All configuration is under: - -```yaml -media_gallery: - controls: - filter: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `mode` | `right` | :heavy_multiplication_x: | Whether to show the gallery media filter to the `left`, to the `right` or `none` for no media filter. | - -#### Media Gallery Controls: Thumbnails - -All configuration is under: - -```yaml -media_gallery: - controls: - thumbnails: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `size` | 100 | :heavy_multiplication_x: | The size of the thumbnails in the gallery. Must be >= `75` and <= `175`.| -| `show_details` | `false` | :heavy_multiplication_x: | Whether to show media details (e.g. duration, start time, object detected, etc) alongside the thumbnail.| -| `show_download_control` | `true` | :heavy_multiplication_x: | Whether to show the download control on each thumbnail.| -| `show_favorite_control` | `true` | :heavy_multiplication_x: | Whether to show the favorite ('star') control on each thumbnail.| -| `show_timeline_control` | `true` | :heavy_multiplication_x: | Whether to show the timeline ('target') control on each thumbnail.| - -### Image Options - -All configuration is under: - -```yaml -image: -``` - -See the [fully expanded image configuration example](#config-expanded-image) for how these parameters are structured. - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `mode` | `url` | :white_check_mark: | Mode of the the `image` [view](#views). Value must be one of `url` (to fetch an arbitrary image URL), `camera` (to show a still of the currently selected camera using either `camera_entity` or `webrtc_card.entity` in that order of precedence), or `screensaver` (to show an [embedded stock Frigate card logo](https://github.com/dermotduffy/frigate-hass-card/blob/main/src/images/frigate-bird-in-sky.jpg)). In either `url` or `camera` mode, the `screensaver` content is used as a fallback if a URL is not specified or cannot be derived. | -| `url` | | :white_check_mark: | A static image URL to be used when the `mode` is set to `url` or when a temporary image is required (e.g. may appear momentarily prior to load of a camera snapshot in the `camera` mode). Note that a `_t=[timestsamp]` query parameter will be automatically added to all URLs such that the image will not be cached by the browser.| -| `refresh_seconds` | 0 | :white_check_mark: | The image will be refreshed at least every `refresh_seconds` (it may refresh more frequently, e.g. whenever Home Assistant updates its camera security token). `0` implies no refreshing. | -| `zoomable` | `true` | :white_check_mark: | Whether or not the image can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | -| `actions` | | :white_check_mark: | Actions to use for the `image` view. See [actions](#actions) below.| - -**Note**: When `mode` is set to `camera` this is effectively providing the same image as the `image` live provider would show in the live camera carousel. - -### Timeline Options - -The `timeline` is used to show the timing sequence of events and recordings across cameras. You can interact with the timeline in a number of ways: - -* Clicking on an event will take you to the media viewer for that event. -* Clicking on the "background", or a camera title, will take you to the recordings for that camera (seeking to the clicked time). -* Clicking on the time axis will take you to recordings for all cameras (seeking to the clicked time). - -All configuration is under: - -```yaml -timeline: -``` - -See the [fully expanded timeline configuration example](#config-expanded-timeline) for how these parameters are structured. - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `style` | `stack` | :heavy_multiplication_x: | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold` (below). | -| `window_seconds` | `3600` | :heavy_multiplication_x: | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | -| `clustering_threshold` | `3` | :heavy_multiplication_x: | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | -| `events_media_type` | `all` | :heavy_multiplication_x: | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot.| -| `show_recordings` | `true` | :heavy_multiplication_x: | Whether to show recordings on the timeline (specifically: which hours have any recorded content).| -| `controls` | | :heavy_multiplication_x: | Configuration for the timeline controls. See below.| - -#### Timeline Controls: Thumbnails - -All configuration is under: - -```yaml -timeline: - controls: - thumbnails: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `mode` | `none` | :heavy_multiplication_x: | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| -| `size` | 100 | :heavy_multiplication_x: | The size of the thumbnails in the thumbnail carousel in pixels. Must be >= `75` and <= `175`.| -| `show_details` | `false` | :heavy_multiplication_x: | Whether to show event details (e.g. duration, start time, object detected, etc) alongside the thumbnail.| -| `show_download_control` | `true` | :heavy_multiplication_x: | Whether to show the download control on each thumbnail.| -| `show_favorite_control` | `true` | :heavy_multiplication_x: | Whether to show the favorite ('star') control on each thumbnail.| -| `show_timeline_control` | `true` | :heavy_multiplication_x: | Whether to show the timeline ('target') control on each thumbnail.| - -#### Timeline Seek Behavior - -The behavior of the timeline during seeking/dragging can be controlled by means of the icon on the bottom-right of the timeline. - -| Option | Behavior | -| - | - | -| filmstrip-box-multiple | Dragging the timeline will seek / select across all available media from all cameras, selecting the media item with the longest duration whilst favoring (but not limited to) the currently selected camera. | -| play-box-lock | Dragging the timeline will seek within the selected media item only. | -| camera-lock | Dragging the timeline will seek / select across all available media from the selected camera only, selecting the media item with the longest duration. | -| pan-horizontal | Dragging the timeline will pan only without selected or seeking any media. | - - - -### Dimensions Options - -These options control the aspect-ratio of the entire card to make placement in -Home Assistant dashboards more stable. Aspect ratio configuration applies once -to the entire card (including the menu, thumbnails, etc), not just to displayed -media. This only applies to the card in normal render mode -- when in -fullscreen, or when in expanded (popup/dialog mode) the aspect ratio is chosen -dynamically to maximize the amount of content shown. - -All configuration is under: - -```yaml -dimensions: -``` - -See the [fully expanded dimensions configuration example](#config-expanded-dimensions) for how these parameters are structured. - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `aspect_ratio_mode` | `dynamic` | :white_check_mark: | The aspect ratio mode to use. Acceptable values: `dynamic`, `static`, `unconstrained`. See [aspect ratios](#aspect-ratios) below.| -| `aspect_ratio` | `16:9` | :white_check_mark: | The aspect ratio to use. Acceptable values: `:` or `/`. See [aspect ratios](#aspect-ratios) below.| -| `max_height` | `100vh` | :white_check_mark: | The maximum allowable height for the card. Specified in [CSS units](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units). Generally users should not need to change this setting unless they have set an `unconstrained` aspect ratio. | -| `min_height` | `100px` | :white_check_mark: | The minimum allowable height for the card. Specified in [CSS units](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units). Generally users should not need to change this setting. | - - -#### `dimensions.aspect_ratio_mode`: - -| Option | Description | -| ------------- | --------------------------------------------- | -| `dynamic` | The aspect-ratio of the card will match the aspect-ratio of the last loaded media. | -| `static` | A fixed aspect-ratio (as defined by `dimensions.aspect_ratio`) will be applied to all views. | -| `unconstrained` | No aspect ratio is enforced in any view, the card will expand with the content (may be especially useful for a panel-mode dashboard). | - -#### `dimensions.aspect_ratio`: - -* `16 / 9` or `16:9`: Default widescreen ratio. -* `4 / 3` or `4:3`: Default fullscreen ratio. -* `/` or `:`: Any arbitrary aspect-ratio. - - - -#### Aspect Ratio - -The card can show live cameras, stored events (clip or snapshot) and an event -gallery (clips or snapshots). Of these [views](#views), the gallery views have -no intrinsic aspect-ratio, whereas the other views have the aspect-ratio of the -media. - -The card aspect ratio can be changed with the `dimensions.aspect_ratio_mode` and -`dimensions.aspect_ratio` options described above. - -If no aspect ratio is specified or available, but one is needed then `16:9` will -be used by default. - - - -### Performance Options - -These options control the card performance settings to enable the card to run -(more) smoothly on lower end devices. - -All configuration is under: - -```yaml -performance: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `profile` | `high` | :heavy_multiplication_x: | Whether the card is configured in full `high` performance mode, or `low` performance defaults for lower end devices. See [low performance profile](#performance-profile-low) below.| - -#### Feature Options - -Controls card-wide central functionality that may impact performance but which is not configurable elsewhere. - -All configuration is under: - -```yaml -performance: - features: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `animated_progress_indicator` | `true` | :heavy_multiplication_x: | Will show the animated progress indicator 'spinner' when `true` or a simple loading icon when `false`.| -| `media_chunk_size` | `50` | :heavy_multiplication_x: | How many media items to fetch and render at a time (e.g. thumbnails under a live view, or number of snapshots to load in the media viewer). This may only make partial sense in some contexts (e.g. the 'infinite gallery' is still infinite, just loads thumbnails this many items at a time) or not at all (e.g. the timeline will show the number of events dictated by the time span the user navigates to).| - -#### Style Options - -Style performance options request the card minimize certain expensive CSS -stylings. This does not necessarily disable these stylings _entirely_ since that -may break the basic expected visuals of the card (e.g. menu icons need curves), -but rather avoids use of them in high item-count situations (e.g. avoiding -shadows on timeline items, or curves in the media gallery items). - -All configuration is under: - -```yaml -performance: - style: -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `border_radius` | `true` | :heavy_multiplication_x: | If `false` minimizes the usage of rounded corners.| -| `box_shadow` | `true` | :heavy_multiplication_x: | If `false` minimizes the usage of shadows.| - - - -#### Performance Profile `low` - -In the `low` performance profile, the card attempts to lower the CPU and network -consumption of the card by setting default option values when they have not been explicitly set by the user. - -Principles used in the selection of options set by `low` profile mode: - -* Get 'out of the box' performance similar to the basic "Home Assistant Picture Glance" card. -* Only change behavior that the user can case-by-case 'reset' by explicitly setting an option elsewhere. -* Do not break the visual aesthetic of the card. - -**Note:**: Since the performance profile changes the _default_ value of options, -setting the `low` profile on a pre-existing card could have no effect if there are -considerable options already set by the user. - -Please see the source code for an exhaustive list of options set by `low` profile mode. Summary: - -* The default live provider (`auto`) will resolve to the `image` live provider for cameras with a `camera_entity` specified. It will have a refresh period of 10 seconds (same as the stock Home Assistant Picture Glance card). -* No event thumbnails fetched. -* No recordings shown. -* No automated actions (e.g. mute, play, pause) except playing in live view. -* Always lazily unload anything that can be unloaded. -* Carousels are not draggable and have no 'slide' effects. -* Live image is not shown during stream loads. -* No title popups. -* Menu rendered outside the main body of the card, with reduced menu buttons. -* All optional performace features and performance styles (described above) disabled. - - - -### Overrides Options - -All configuration is a list under: - -```yaml -overrides: -``` - -See the [fully expanded overrides configuration example](#config-expanded-overrides) for how these parameters are structured. - -Various parts of this configuration may conditionally (see [Frigate Card -Conditions](#frigate-card-conditions)) be overridden, for example to use custom -WebRTC parameters for a particular camera or to hide the menu in fullscreen mode. - -Not all configuration parameters are overriddable (only those with check marks -in this documentation) -- some because it doesn't make sense for that parameter -to vary, and many because of the extra complexity of supporting overriding given -the lack of compelling usecases ([please request new overridable parameters -here!](https://github.com/dermotduffy/frigate-hass-card/issues/new/choose)). - -Each entry under the top-level `overrides` configuration block should be a list -item, that has both of the following parameters set: - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `conditions` | | :heavy_multiplication_x: | A list of conditions that must evaluate to `true` in order for the overrides to be applied. See [Frigate Card Conditions](#frigate-card-conditions). | -| `overrides` | | :heavy_multiplication_x: |Configuration overrides to be applied. Any configuration parameter described in this documentation as 'Overridable' is supported. | - - - -### Automation Options - -All configuration is a list under: - -```yaml -automations: - - [conditions:] - [actions:] - [actions_not:] -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `conditions` | | :heavy_multiplication_x: | A list of conditions that must evaluate to `true` in order to trigger the automation. See [Frigate Card Conditions](#frigate-card-conditions). | -| `actions` | | :heavy_multiplication_x: | An optional list of actions that will be run when the conditions evaluate `true`. Actions can be [stock Home Assistant actions](https://www.home-assistant.io/dashboards/actions/) or [Frigate card actions](#frigate-card-actions).| -| `actions_not` | | :heavy_multiplication_x: | An optional list of actions that will be run when the conditions evaluate `false`. Actions can be [stock Home Assistant actions](https://www.home-assistant.io/dashboards/actions/) or [Frigate card actions](#frigate-card-actions).| - - - -### Other Options - -All listed configuration options are under the top level, e.g.: - -```yaml -type: custom:frigate-card -... -``` - -| Option | Default | Overridable | Description | -| - | - | - | - | -| `card_id` | | :heavy_multiplication_x: | **Advanced users only**: An optional ID to uniquely identify this card. For use when actions are being sent to card(s) via the [query string](#query-string-actions). Must exclusively consist of these characters: `[a-zA-Z0-9_]`.| - - - -### Using AlexxIT's WebRTC Card - -WebRTC Card support blends the use of the ultra-realtime [WebRTC card live -view](https://github.com/AlexxIT/WebRTC) with convenient access to Frigate -events/snapshots/UI. A perfect combination! - -Live viewing - -**Note**: AlexxIT's WebRTC Integration/Card must be installed and configured separately (see [details](https://github.com/AlexxIT/WebRTC)) before it can be used with this card. - -#### Specifying The WebRTC Card Camera - -##### Frigate v0.12 and onwards - -If you have used the [recommended go2rtc setup](https://deploy-preview-4055--frigate-docs.netlify.app/guides/configuring_go2rtc/) for Frigate, no additional `webrtc_card` configuration is necessary. - -##### Frigate v0.11 and earlier - -The WebRTC Card live provider does **not** support use of Frigate-provided -camera entities, as it requires an RTSP stream which Frigate does not currently -provide. There are two ways to specify the WebRTC Card source camera: - -* Manual setup of separate RTSP camera entities in Home Assistant ([see - example](https://www.home-assistant.io/integrations/generic/#live-stream)). - These entities will then be available for selection in the GUI card editor for - the camera, or can be manually specified with a `webrtc_card.entity` option under - that particular cameras configuration: - -```yaml -cameras: - - webrtc_card: - entity: 'camera.front_door_rstp` -``` - -* OR manually entering the WebRTC Card camera URL parameter in the GUI card - editor, or configuring the `url` parameter as part of a manual Frigate card - configuration, as illustrated in the following example: - -```yaml -cameras: - - webrtc_card: - url: 'rtsp://USERNAME:PASSWORD@CAMERA:554/RTSP_PATH' -``` - -Other WebRTC Card options may be specified under the `webrtc_card` section, like so: - -```yaml -cameras: - - webrtc_card: - ui: true -``` - -See [the WebRTC Card live configuration](#webrtc-live-configuration) above, and the -[external WebRTC Card configuration -documentation](https://github.com/AlexxIT/WebRTC#configuration) for full -configuration options that can be used here. - - - -## Using 2-Way Audio - -This card supports 2-way audio (e.g. transmitting audio from a microphone to a suitably equipped camera). Requirements for 2-way audio to work: - -Environmental requirements: - * Must have a camera that supports audio out (otherwise what's the point!) - * Camera must be supported by `go2rtc` for 2-way audio (see [supported cameras](https://github.com/AlexxIT/go2rtc#two-way-audio)). - * Must be accessing your Home Assistant instance over `https`. The browser will enforce this. - -Card requirements: - * Only Frigate cameras are supported. - * Only the `go2rtc` live provider is supported. - * Only the `webrtc` mode supports 2-way audio: -```yaml -cameras: - - camera_entity: camera.front_door - live_provider: go2rtc - go2rtc: - modes: - - webrtc -``` - * Must have microphone menu button enabled: -```yaml -menu: - buttons: - microphone: - enabled: true -``` - -Usage: - * The camera will always load without the microphone connected. - * To speak, hold-down the microphone menu button. - * On first press, this will reset the `webrtc` connection to include 2-way audio (unless the `always_connected` microphone option is set to `true`). - * Thereafter hold the microphone button down to unmute/speak, let go to mute. - * The video will automatically reset to remove the microphone after the number of seconds specified by `disconnect_seconds` in the `microphone` configuration have elapsed since the last mute/unmute press. - - - -## Frigate Card Conditions - -Conditions are used to apply certain configuration depending on runtime evaluations. Conditions may be used in `elements` configuration (as part of a `custom:frigate-card-conditional` element), or in `overrides` and `automations`. - -See the [example below](#frigate-card-conditional-example) for a real-world example of how these conditions can be used. - -Conditions is a list of conditions objects following the below schema: - -### View Condition - -| Parameter | Description | -| - | - | -| `condition` | Must be `view`. | -| `views` | A list of [views](#views) in which this condition is satified (e.g. `clips`). | - -### Camera Condition - -| Parameter | Description | -| - | - | -| `condition` | Must be `camera`. | -| `cameras` | A list of camera IDs in which this condition is satisfied. See [camera IDs](#camera-ids). | - -### Fullscreen Condition - -| Parameter | Description | -| - | - | -| `condition` | Must be `fullscreen`. | -| `fullscreen` | If `true` the condition is satisfied if the card is in fullscreen mode. If `false` the condition is satisfied if the card is **NOT** in fullscreen mode. | - -### Expand Condition - -| Parameter | Description | -| - | - | -| `condition` | Must be `expand`. | -| `fullscreen` | If `true` the condition is satisfied if the card is in expanded mode (in a dialog/popup). If `false` the condition is satisfied if the card is **NOT** in expanded mode (in a dialog/popup). | - -### Media Loaded Condition - -| Parameter | Description | -| - | - | -| `condition` | Must be `media_loaded`. | -| `media_loaded` | If `true` the condition is satisfied if there is media load**ED** (not load**ING**) in the card (e.g. a clip, snapshot or live view). This may be used to hide controls during media loading or when a message (not media) is being displayed. Note that if `true` this - -### Screen Condition - -| Parameter | Description | -| - | - | -| `condition` | Must be `screen`. | -| `media_query` | Any valid [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries) string. Media queries must start and end with parentheses. This may be used to alter card configuration based on device/media properties (e.g. viewport width, orientation). Please note that `width` and `height` refer to the entire viewport not just the card. See the [media query example](#media-query-example). | - -### Interaction Condition - -| Parameter | Description | -| - | - | -| `condition` | Must be `screen`. | -| `interaction` | If `true` the condition is satisfied if the card has had human interaction within `view.interaction_seconds` elapsed seconds. If `false` the condition is satisfied if the card has **NOT** had human interaction in that time. | - -### Triggered Condition - -| Parameter | Description | -| - | - | -| `condition` | Must be `screen`. | -| `triggered` | A list of camera IDs which, if [triggered](#camera-triggers-configuration), satisfy the condition. | - -### Microphone Conditions - -| Parameter | Description | -| - | - | -| `muted` | Optional: If `true` or `false` the condition is satisfied if the microphone is muted or unmuted respectively. | -| `connected` | Optional: If `true` or `false` the condition is satisfied if the microphone is connected or disconnected respectively. | - -### Stock Home Assistant Conditions - -The stock `state`, `numeric_state` and `user` condition from Home Assistant can also be used. See [their documentation](https://www.home-assistant.io/dashboards/conditional/#card-conditions). - - - -## Picture Elements / Menu Customizations - -This card supports the [Picture Elements configuration -syntax](https://www.home-assistant.io/lovelace/picture-elements/) to seamlessly -allow the user to add custom elements to the card, which may be configured to -perform a variety of actions on interaction (see [actions](#actions) below). The configuration is fairly versatile and can be simple, or very complex depending on the desires of the user. - -All configuration is under: - -```yaml -elements: -``` - -See the [fully expanded elements configuration example](#config-expanded-elements) for how these parameters are structured. - -**Note**: The Frigate Card allows either a single action (as in stock Home -Assistant) or list of actions to be defined for each class of user interaction -(e.g. `tap`, `double_tap`, `hold`, etc). See [an example of multiple actions](#example-multiple-actions). - -### Special Elements - -This card supports all [Picture -Elements](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) -using compatible syntax. The card also supports a handful of custom special -elements to add special Frigate card functionality. - -| Element name | Description | -| ------------- | --------------------------------------------- | -| `custom:frigate-card-menu-icon` | Add an arbitrary icon to the Frigate Card menu. Configuration is ~identical to that of the [Picture Elements Icon](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) except with a type name of `custom:frigate-card-menu-icon`.| -| `custom:frigate-card-menu-state-icon` | Add a state icon to the Frigate Card menu that represents the state of a Home Assistant entity. Configuration is ~identical to that of the [Picture Elements State Icon](https://www.home-assistant.io/lovelace/picture-elements/#state-icon) except with a type name of `custom:frigate-card-menu-state-icon`.| -| `custom:frigate-card-menu-submenu` | Add a configurable submenu dropdown. See [configuration below](#frigate-card-menu-submenu).| -| `custom:frigate-card-menu-submenu-select` | Add a submenu based on a `select` or `input_select`. See [configuration below](#frigate-card-submenu-select).| -| `custom:frigate-card-conditional` | Restrict a set of elements to only render when the card is showing particular a particular [view](#views). See [configuration below](#frigate-card-conditional).| - -**Note**: ℹ️ Manual positioning of custom menu icons or submenus via the `style` -parameter is not supported as the menu buttons displayed are context sensitive -so manual positioning by the user is not feasible. - - - -#### `custom:frigate-card-menu-submenu` - -Parameters for the `custom:frigate-card-menu-submenu` element are identical to the parameters of the [stock Home Assistant Icon Element](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) with the exception of these parameters which differ: - -| Parameter | Description | -| - | - | -| `type` | Must be `custom:frigate-card-menu-submenu`. | -| `items` | A list of menu items, as described below. | - - - -##### Submenu Items - -| Parameter | Default | Description | -| - | - | - | -| `title` | | An optional title to display. | -| `icon` | | An optional item icon to display, e.g. `mdi:car` | -| `entity` | | An optional Home Assistant entity from which title, icon and style can be automatically computed. | -| `state_color` | `true` | Whether or not the title and icon should be stylized based on state. | -| `selected` | `false` | Whether or not to show this item as selected. | -| `enabled` | `true` | Whether or not to show this item as enabled / selectable. | -| `style` | | Position and style the element using CSS. | -| `tap_action`, `double_tap_action`, `hold_action`, `start_tap`, `end_tap` | | [Home Assistant action configuration](https://www.home-assistant.io/lovelace/actions) including the extended functionality described under [actions](#actions). | - -See the [Configuring a Submenu example](#configuring-a-submenu-example). - - - -#### `custom:frigate-card-menu-submenu-select` - -This element allows you to easily convert a [Home Assistant Select Entity](https://www.home-assistant.io/integrations/select/) or [Home Assistant Input Select Entity](https://www.home-assistant.io/integrations/input_select/) (an entity either starting with `select` or `input_select`) into an overridable submenu. This *could* be done by hand using a regular submenu (above) -- this element is a convenience. - -Parameters for the `custom:frigate-card-menu-submenu-select` element are identical to the parameters of the [stock Home Assistant State Icon Element](https://www.home-assistant.io/dashboards/picture-elements/#state-icon) with the exception of these parameters which differ: - -| Parameter | Description | -| - | - | -| `type` | Must be `custom:frigate-card-menu-submenu-select`. | -| `options` | An optional dictionary of overrides keyed by the option name that the given select entity supports. These options can be used to set or override submenu item parameters on a per-option basis. The format is as described in [Submenu Items](#frigate-card-submenu-items) above.| - -See the [Configuring a Select Submenu example](#configuring-a-select-submenu-example). - - - -#### `custom:frigate-card-conditional` - -Parameters for the `custom:frigate-card-conditional` element: - -| Parameter | Description | -| ------------- | --------------------------------------------- | -| `type` | Must be `custom:frigate-card-conditional`. | - `elements` | The elements to render. Can be any supported element, include additional condition or custom elements. | -| `conditions` | A list of conditions that must evaluate to true in order for the elements to be rendered. See [Frigate Card Conditions](#frigate-card-conditions). | - - - -### Special Actions - -#### `custom:frigate-card-action` - -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Call a Frigate Card action. Acceptable values are `default`, `clip`, `clips`, `image`, `live`, `recording`, `recordings`, `snapshot`, `snapshots`, `download`, `timeline`, `camera_ui`, `fullscreen`, `camera_select`, `menu_toggle`, `media_player`, `live_substream_on`, `live_substream_off`, `live_substream_select`, `expand`, `microphone_mute`, `microphone_unmute`, `mute`, `unmute`, `play`, `pause`, `screenshot`, `show_ptz`, `ptz`| - - - -##### Action descriptions - -| Value | Description | -| - | - | -| `default` | Trigger the default view. | -| `clip`, `clips`, `image`, `live`, `recording`, `recordings`, `snapshot`, `snapshots` | Trigger the named [view](#views).| -|`download`|Download the displayed media.| -|`camera_ui`|Open the Frigate UI at the configured URL.| -|`fullscreen`|Toggle fullscreen.| -|`camera_select`|Select a given camera. Takes an additional `camera` parameter with the [camera ID](#camera-ids) of the camera to select. Respects the value of `view.camera_select` to choose the appropriate view on the new camera. If a `triggered` parameter is set to `true` instead of `camera` being specified then a triggered camera (if any) is selected instead. | -|`menu_toggle` | Show/hide the menu (for the `hidden` mode style). | -|`media_player`| Perform a media player action. Takes a `media_player` parameter with the entity ID of the media_player on which to perform the action, and a `media_player_action` parameter which should be either `play` or `stop` to play or stop the media in question. | -|`live_substream_select`| Perform a media player action. Takes a `camera` parameter with the [camera ID](#camera-ids) of the substream camera. | -|`expand`| Expand the card into a dialog/popup. | -|`microphone_mute`, `microphone_unmute`| Mute or unmute the microphone. See [Using 2-way audio](#using-2-way-audio). | -|`mute`, `unmute`| Mute or unmute the loaded media. | -|`play`, `pause`| Play or pause the loaded media. | -|`screenshot`| Take a screenshot of the loaded media (e.g. a still from a video). | -|`show_ptz`| Show or hide the PTZ controls. Takes a `show_ptz` boolean parameter to indicate whether the controls show be shown or not. | -|`ptz`| Execute a native PTZ action (only for native out-of-the-box PTZ camera engines, e.g. Frigate). Takes a required `ptz_action` parameter that is one of `left`, `right`, `up`, `down`, `zoom_in`, `zoom_out` or `preset`. Takes an optional `ptz_phase` parameter that is one of `start` or `stop` to start or stop the movement discretely. Takes an optional `ptz_preset` parameter as the preset to execute when the `ptz_action` parameter is `preset`. | - - - -## Views - -This card supports several different views: - -| Key | Description | -| ------------- | --------------------------------------------- | -|`live` (default)| Shows the live camera view with the configured live provider.| -|`snapshots`|Shows a gallery of snapshots for this camera.| -|`snapshot`|Shows a viewer for the most recent snapshot for this camera. Can also be accessed by holding down the `snapshots` menu icon.| -|`clips`|Shows a gallery of clips for this camera.| -|`clip`|Shows a viewer for the most recent clip for this camera. Can also be accessed by holding down the `clips` menu icon.| -|`recordings`|Shows a gallery of recent (last day) recordings for this camera and its dependents.| -|`recording`|Shows a viewer for the most recent recording for this camera. Can also be accessed by holding down the `recordings` menu icon.| -|`image`|Shows a static image specified by the `image` parameter, can be used as a discrete default view or a screensaver (via `view.interaction_seconds`).| -|`timeline`|Shows an event timeline.| - -### Navigating From A Snapshot To A Clip - -Clicking on a snapshot will take the user to a clip that was taken at the ~same -time as the snapshot (if any). - - - -## Actions - -### Introduction to Actions - -Actions are pre-configured activities that can be triggered in response to a -variety of circumstances (e.g. tapping on a menu icon, double tapping on a -[picture element](#frigate-card-elements) or holding the mouse/tap down on a -particular [view](#views)). - -### Configuring Actions - -The format for actions is the standard Home Assistant [action -format](https://www.home-assistant.io/lovelace/actions/#tap-action), with the -exception of differences called out below. - -### Differences in actions between Frigate Card and Home Assistant - -Both the Home Assistant frontend and the Frigate card cooperate to provide -action functionality. In general, the Frigate Card functionality is a superset -of that offered by stock Home Assistant. - -Stock action functionality is used for Stock [Home Assistant picture -elements](https://www.home-assistant.io/lovelace/picture-elements/). Extended -Frigate card behavior covers all other interactions on the Frigate card (e.g. -menu icon elements, submenus and actions on the card or views). - -#### Custom action types: `start_tap` and `end_tap` - -The card has partial support for two special action types `start_tap` and -`end_tap` which occur when a tap is started (e.g. mouse is pressed down / -touch begins), and ended (e.g. mouse released / touch ends) respectively. This -might be useful for PTZ cameras cameras to start/stop movement on touch. Network -latency may introduce unavoidable imprecision between `end_tap` and action -actually occurring. - -#### Multiple actions - -Extended Frigate card behavior supports a list of actions which will be handled, -in addition to using a singular action. See [an example of multiple -actions](#example-multiple-actions) below. - -### Card & View Actions - -Actions may be attached to the card itself, to trigger action when the card -experiences a `tap`, `double_tap`, `hold`, `start_tap` or `end_tap` event. These -actions can be specified both for the overall card and for individual groups of -view. - -| Configuration path | Views to which it refers | -| - | - | -| `view.actions` | All (may be overriden by the below) | -| `media_gallery.actions` | `clips`, `snapshots`, `recordings` | -| `media_viewer.actions` | `clip`, `snapshot`, `recording` | -| `live.actions` | `live` | -| `image.actions` | `image` | - -If an action is configured for both the whole card (`view.actions`) and a more -specific view (e.g. `live.actions`) then the actions are merged, with the more -specific overriding the less specific (see example below). - -**Note:** The card itself relies on user interactions to function (e.g. `tap` on -the menu should activate that button, `tap` on a gallery thumbnail should open -that piece of media, etc). Efforts are taken to de-duplicate interactions (e.g. -card-wide actions will not be activated through interaction with menu buttons, -next/previous controls, thumbnails, etc), but in some cases this is not possible -(e.g. embedded WebRTC card controls) -- in these cases duplicate actions may -occur with certain configurations (e.g. `tap`). - -**Note:** Card-wide actions are not supported on the timeline view, nor when a -info/error message is being displayed. - -## Menu Styles - -This card supports several menu styles. - -| Key | Description | Screenshot | -| ------------- | --------------------------------------------- | - | -|`hidden`| Hide the menu by default, expandable upon clicking the Frigate button. | Menu hidden | -|`overlay`| Overlay the menu over the card contents. The Frigate button shows the default view. | Menu overlaid | -|`hover`| Overlay the menu over the card contents when the mouse is over the **menu**, otherwise it is not shown. The Frigate button shows the default view. | Menu overlaid | -|`hover-card`| Overlay the menu over the card contents when the mouse is over the **card**, otherwise it is not shown. The Frigate button shows the default view. | Menu overlaid | -|`outside`| Render the menu outside the card (i.e. above it if `position` is `top`, or below it if `position` is `bottom`). The Frigate button shows the default view. | Menu above | -|`none`| No menu is shown. | No Menu | - - - -## Screenshots - -### Live Viewing of Multiple Cameras - -Scroll through your live cameras, or choose from a menu. Seamlessly supports -cameras of different dimensions, and custom submenus per camera. - -Gallery - -### Full Viewing Of Events - -Gallery - -### Live Viewing With Thumbnail Carousel - -Live view with event thumbnails - -### Clip Viewing With Thumbnail Carousel - -Viewer with event thumbnails - -### Hover Menu / Thumbnail Next & Previous Controls - -Viewer with event thumbnails - -### Card Editing - -This card supports full editing via the Lovelace card editor. Additional arbitrary configuration for WebRTC Card may be specified in YAML mode. - -Live viewing - -### Configurable Submenus - -This card supports fully configurable submenus. - -Configurable submenus - -### Select Entity Submenus - -Automatically generate submenus from `select` entities. - -Select based submenus - -### Cast media from the card - -Cast media from the card to a local player. - -Cast media - -### Triggered! - -Automatically choose the camera with the action! - -Triggered! - -### Thumbnail Drawers - -View thumbnails in side-drawers. - -Thumbnail drawers - -### Event Timeline - -View events in the timeline. - -Event Timeline - -### Single Camera Recordings - -View recordings for a camera across time: - -Recording for single camera - -### Multiple Camera Recordings - -View recordings for multiple cameras at a given time: - -Recording for multiple cameras - -### Dark Mode - -Dim the card when not used. - -Card dark mode - - - -### Card Casting - -A dashboard with the card can be cast onto a suitable device (such as the Nest Hub shown below). - -Card on Nest Hub - -### Event starring - -Retain interesting Frigate events forever: - -Retain events - -### PTZ Control - -Control a PTZ camera: - -PTZ Control - -### Media Layout - -Pan around a large camera view to only show part of the video feed in the card at a different aspect ratio: - -#### Before - -Media Layout A - -#### After - -Media Layout B - -### Video Scrubbing - -Video Scrubbing - -### Media filtering - -Media Filtering - -### Seamless integration of different camera sources/engines - -MotionEye Support - -### Expanded mode - -Expanded Mode - -### Substream Support - -Substream Support - -### Timeline Date Picking - -Timeline Date Picking - -### Low performance mode - -Low Performance Mode - -### Ribbon timeline - -Ribbon Timeline - -### In-menu media / mute control - -In-Menu Media Control - -### 2-way Audio Support - -2-way Audio - -### Zoom Support - -Zoom Support - -### Taking card actions via the URL - -Taking card actions via the URL - -### Interacting with a camera grid - -Interacting with a camera grid - -## Examples - -### Illustrative Expanded Configuration Reference - -**Caution**: 🚩 Just copying this full reference into your configuration will cause you a significant maintenance burden. Don't do it! Please only specify what you need as defaults can / do change continually as this card develops. Almost all the values shown here are the defaults (except in cases where is no default, parameters are added here for illustrative purposes). - - - -
- Expand: Cameras section - -Reference: [Camera Options](#camera-options). - -```yaml -cameras: - - camera_entity: camera.front_Door - live_provider: ha - engine: auto - frigate: - url: http://my.frigate.local - client_id: frigate - camera_name: front_door - labels: - - person - zones: - - steps - # Show events for camera-2 when this camera is viewed. - dependencies: - all_cameras: false - cameras: - - camera-2 - triggers: - motion: false - occupancy: true - entities: - - binary_sensor.front_door_sensor - cast: - method: standard - dimensions: - aspect_ratio: 16:9 - layout: - fit: contain - position: - x: 50 - y: 50 - - camera_entity: camera.entrance - live_provider: webrtc-card - engine: auto - frigate: - url: http://my-other.frigate.local - client_id: frigate-other - camera_name: entrance - labels: - - car - zones: - - driveway - icon: 'mdi:car' - title: 'Front entrance' - # Custom identifier for the camera to refer to it above. - id: 'camera-2' - webrtc_card: - entity: camera.entrance_rtsp - url: 'rtsp://username:password@camera:554/av_stream/ch0' - triggers: - motion: false - occupancy: true - entities: - - binary_sensor.entrance_sensor - dependencies: - all_cameras: false - - camera_entity: camera.sitting_room - live_provider: go2rtc - go2rtc: - modes: - - webrtc - - mse - - mp4 - - mjpeg - stream: sitting_room - url: 'https://my.custom.go2rtc.backend' - cast: - method: dashboard - dashboard: - dashboard_path: cast - view_path: front-door - - camera_entity: camera.sitting_room_webrtc_card - live_provider: webrtc_card - webrtc_card: - # Arbitrary WebRTC Card options, see https://github.com/AlexxIT/WebRTC#configuration . - entity: camera.sitting_room_rtsp - ui: true - - camera_entity: camera.kitchen - live_provider: jsmpeg - jsmpeg: - options: - audio: false - video: true - pauseWhenHidden: false - disableGl: false - disableWebAssembly: false - preserveDrawingBuffer: false - progressive: true - throttled: true - chunkSize: 1048576 - maxAudioLag: 10 - videoBufferSize: 524288 - audioBufferSize: 131072 - - camera_entity: camera.back_yard - live_provider: image - image: - refresh_seconds: 1 - - camera_entity: camera.office_motioneye - motioneye: - images: - directory_pattern: '%Y-%m-%d' - file_pattern: '%H-%M-%S' - movies: - directory_pattern: '%Y-%m-%d' - file_pattern: '%H-%M-%S' -``` -
- -
- Expand: Cameras Global section - -Reference: [Cameras Global Options](#camera-global-options). - -```yaml -cameras_global: - live_provider: ha - engine: auto - frigate: - url: http://my.frigate.local - client_id: frigate - camera_name: front_door - labels: - - person - zones: - - steps - dependencies: - all_cameras: false - cameras: - - camera-2 - triggers: - motion: false - occupancy: true - entities: - - binary_sensor.front_door_sensor - go2rtc: - modes: - - webrtc - - mse - - mp4 - - mjpeg - stream: sitting_room - url: 'https://my.custom.go2rtc.backend' - webrtc_card: - # Arbitrary WebRTC Card options, see https://github.com/AlexxIT/WebRTC#configuration . - entity: camera.sitting_room_rtsp - ui: true - jsmpeg: - options: - audio: false - video: true - pauseWhenHidden: false - disableGl: false - disableWebAssembly: false - preserveDrawingBuffer: false - progressive: true - throttled: true - chunkSize: 1048576 - maxAudioLag: 10 - videoBufferSize: 524288 - audioBufferSize: 131072 - image: - refresh_seconds: 1 -``` -
- - - -
- Expand: View section - -Reference: [View Options](#view-options). - -```yaml -view: - default: live - camera_select: current - interaction_seconds: 300 - update_seconds: 0 - update_force: false - update_cycle_camera: false - update_entities: - - binary_sensor.my_motion_sensor - render_entities: - - switch.render_card - dark_mode: 'off' - triggers: - show_trigger_status: false - filter_selected_camera: true - untrigger_seconds: 0 - actions: - interaction_mode: inactive - trigger: default - untrigger: none - actions: - entity: light.office_main_lights - tap_action: - action: none - hold_action: - action: none - double_tap_action: - action: none - start_tap_action: - action: none - end_tap_action: - action: none -``` -
- - - -
- Expand: Menu section - -Reference: [Menu Options](#menu-options). - -```yaml -menu: - style: hidden - position: top - alignment: left - buttons: - frigate: - priority: 50 - enabled: true - alignment: matching - # Default icon is an internal coded Frigate icon. Note - # absence of 'mdi' here (mdi has no Frigate icon). - icon: frigate - cameras: - priority: 50 - enabled: true - alignment: matching - icon: mdi:video-switch - substreams: - priority: 50 - enabled: true - icon: mdi:video-input-component - live: - priority: 50 - enabled: true - alignment: matching - icon: mdi:cctv - clips: - priority: 50 - enabled: true - alignment: matching - icon: mdi:filmstrip - snapshots: - priority: 50 - enabled: true - alignment: matching - icon: mdi:camera - image: - priority: 50 - enabled: false - alignment: matching - icon: mdi:image - timeline: - priority: 50 - enabled: true - alignment: matching - icon: mdi:chart-gantt - download: - priority: 50 - enabled: true - alignment: matching - icon: mdi:download - camera_ui: - priority: 50 - enabled: true - alignment: matching - icon: mdi:web - fullscreen: - priority: 50 - enabled: true - alignment: matching - icon: mdi:fullscreen - expand: - priority: 50 - enabled: true - alignment: matching - icon: mdi:arrow-expand-all - media_player: - priority: 50 - enabled: false - alignment: matching - icon: mdi:cast - microphone: - priority: 50 - enabled: false - alignment: matching - icon: mdi:microphone - type: momentary - mute: - priority: 50 - enabled: false - alignment: matching - icon: mdi:volume-off - play: - priority: 50 - enabled: false - alignment: matching - icon: mdi:play - show_ptz: - priority: 50 - enabled: false - alignment: matching - icon: mdi:pan - button_size: 40 -``` -
- - - -
- Expand: Live section - -Reference: [Live Options](#live-options). - -```yaml -live: - auto_play: - - selected - - visible - auto_pause: [] - auto_mute: - - unselected - - hidden - auto_unmute: - - microphone - preload: false - lazy_load: true - lazy_unload: [] - draggable: true - zoomable: true - transition_effect: slide - controls: - builtin: true - next_previous: - style: chevrons - size: 48 - thumbnails: - media_type: events - events_media_type: all - size: 100 - show_details: false - show_download_control: true - show_favorite_control: true - show_timeline_control: true - mode: none - timeline: - style: ribbon - mode: none - pan_mode: pan - clustering_threshold: 3 - events_media_type: all - show_recordings: true - window_seconds: 3600 - title: - mode: popup-bottom-right - duration_seconds: 2 - microphone: - always_connected: false - disconnect_seconds: 90 - mute_after_microphone_mute_seconds: 60 - ptz: - mode: on - position: bottom-right - orientation: horizontal - hide_pan_tilt: false - hide_zoom: false - hide_home: false - style: - # Optionally override the default style. - right: 5% - # Manually specifying actions. - actions_left: - tap_action: - action: call-service - service: sonoff.send_command - service_data: - device: '048123' - cmd: left - # Equivalent short form PTZ actions (only right button shown) - service: sonoff.send_command - data_right: - device: '048123' - cmd: right - display: - mode: single - grid_selected_width_factor: 2 - grid_max_columns: 4 - actions: - entity: light.office_main_lights - tap_action: - action: none - hold_action: - action: none - double_tap_action: - action: none - start_tap_action: - action: none - end_tap_action: - action: none - -``` -
- - - -
- Expand: Media Viewer section - -Reference: [Media Viewer Options](#event-viewer-options). - -```yaml -media_viewer: - auto_play: - - selected - - visible - auto_pause: - - unselected - - hidden - auto_mute: - - unselected - - hidden - auto_unmute: [] - lazy_load: true - draggable: true - zoomable: true - snapshot_click_plays_clip: true - transition_effect: slide - controls: - builtin: true - next_previous: - size: 48 - style: thumbnails - thumbnails: - size: 100 - mode: none - show_details: false - show_download_control: true - show_favorite_control: true - show_timeline_control: true - timeline: - style: ribbon - mode: none - pan_mode: pan - clustering_threshold: 3 - events_media_type: all - show_recordings: true - window_seconds: 3600 - title: - mode: popup-bottom-right - duration_seconds: 2 - display: - mode: single - grid_selected_width_factor: 2 - grid_max_columns: 4 - actions: - entity: light.office_main_lights - tap_action: - action: none - hold_action: - action: none - double_tap_action: - action: none - start_tap_action: - action: none - end_tap_action: - action: none -``` -
- - - -
- Expand: Media Gallery section - -Reference: [Media Gallery Options](#media-gallery-options). - -```yaml -media_gallery: - controls: - filter: - mode: 'right' - thumbnails: - size: 100 - show_details: false - show_download_control: true - show_favorite_control: true - show_timeline_control: true - actions: - entity: light.office_main_lights - tap_action: - action: none - hold_action: - action: none - double_tap_action: - action: none - start_tap_action: - action: none - end_tap_action: - action: none -``` -
- - - -
- Expand: Image section - -Reference: [Image Options](#image-options). - -```yaml -image: - mode: url - refresh_seconds: 0 - zoomable: true - actions: - entity: light.office_main_lights - tap_action: - action: none - hold_action: - action: none - double_tap_action: - action: none - start_tap_action: - action: none - end_tap_action: - action: none -``` -
- - - -
- Expand: Elements section (stock Home Assistant elements) - -Reference: [Home Assistant Picture Elements](https://www.home-assistant.io/dashboards/picture-elements/) - -Actions are omitted for simplicity, see the next section for action examples. - -```yaml -elements: - - type: state-badge - entity: sensor.kitchen_dining_multisensor_air_temperature - style: - left: 100px - top: 50px - title: "Temperature" - - type: state-icon - entity: light.office_main_lights - icon: mdi:lamp - state_color: true - style: - left: 100px - top: 100px - - type: state-label - entity: sensor.kitchen_motion_sensor_battery - attribute: battery_voltage - prefix: Volts - title: Battery Voltage - style: - left: 100px - top: 150px - - type: state-label - entity: sensor.kitchen_motion_sensor_battery - attribute: battery_voltage - prefix: 'Volts: ' - title: Battery Voltage - style: - background-color: black - left: 100px - top: 200px - - type: service-button - title: Light on - service: homeassistant.turn_on - service_data: - entity: light.office_main_lights - style: - left: 100px - top: 250px - - type: icon - icon: mdi:cow - title: Moo - style: - left: 100px - top: 300px - - type: image - entity: light.office_main_lights - title: Image - state_image: - on: "https://picsum.photos/id/1003/1181/1772" - off: "https://picsum.photos/id/102/4320/3240" - state_filter: - "on": brightness(110%) saturate(1.2) - "off": brightness(50%) hue-rotate(45deg) - style: - left: 100px - top: 350px - height: 50px - width: 100px - - type: conditional - conditions: - - condition: state - entity: light.office_main_lights - state: on - state_not: off - - condition: numeric_state - entity: sensor.light_level - above: 20 - below: 100 - - condition: user - users: - - 581fca7fdc014b8b894519cc531f9a04 - elements: - - type: icon - icon: mdi:dog - title: Woof - style: - left: 100px - top: 400px -``` -
- -
- Expand: Elements section (stock Home Assistant actions) - -Reference: [Home Assistant Actions](https://www.home-assistant.io/dashboards/actions/), [Frigate Card Actions](#actions). - -```yaml -elements: - - type: icon - icon: mdi:numeric-1-box - title: More info action - style: - left: 200px - top: 50px - entity: light.office_main_lights - tap_action: - action: more-info - - type: icon - icon: mdi:numeric-2-box - title: Toggle action - style: - left: 200px - top: 100px - entity: light.office_main_lights - tap_action: - action: toggle - - type: icon - icon: mdi:numeric-3-box - title: Call Service action - style: - left: 200px - top: 150px - tap_action: - action: call-service - service: homeassistant.toggle - service_data: - entity_id: light.office_main_lights - - type: icon - icon: mdi:numeric-4-box - title: Navigate action - style: - left: 200px - top: 200px - tap_action: - action: navigate - navigation_path: /lovelace/2 - - type: icon - icon: mdi:numeric-5-box - title: URL action - style: - left: 200px - top: 250px - tap_action: - action: url - url_path: https://www.home-assistant.io/ - - type: icon - icon: mdi:numeric-6-box - title: None action - style: - left: 200px - top: 300px - tap_action: - action: none - - type: icon - icon: mdi:numeric-7-box - title: Custom action - style: - left: 200px - top: 350px - tap_action: - action: fire-dom-event - key: value -``` -
- -
- Expand: Elements section (custom elements) - -Reference: [Custom Frigate Card Elements](#special-elements) - -```yaml -elements: - - type: custom:frigate-card-menu-icon - icon: mdi:car - title: Vroom - - type: custom:frigate-card-menu-state-icon - entity: light.office_main_lights - title: Office lights - icon: mdi:chair-rolling - state_color: true - - type: custom:frigate-card-menu-submenu - icon: mdi:menu - items: - - title: Lights - icon: mdi:lightbulb - entity: light.office_main_lights - tap_action: - action: toggle - - title: Google - icon: mdi:google - enabled: false - tap_action: - action: url - url_path: https://www.google.com - - type: custom:frigate-card-menu-submenu-select - icon: mdi:lamps - entity: input_select.kitchen_scene - options: - scene.kitchen_cooking_scene: - icon: mdi:chef-hat - title: Cooking time! - scene.kitchen_tv_scene: - icon: mdi:television - title: TV! - # Show a pig icon if a variety of conditions are met. - - type: custom:frigate-card-conditional - elements: - - type: icon - icon: mdi:pig - title: Oink - style: - left: 300px - top: 100px - conditions: - - condition: view - views: - - live - - condition: fullscreen - fullscreen: true - - condition: expand - expand: true - - condition: camera - cameras: camera.front_door - - condition: media_loaded - media_loaded: true - - condition: display_mode - display_mode: single - - condition: triggered - triggered: - - camera.front_door - - condition: interaction - interaction: true - - condition: microphone - muted: true - connected: true - - condition: state - entity: light.office_main_lights - state: on - state_not: off - - condition: numeric_state - entity: sensor.light_level - above: 20 - below: 100 - - condition: user - users: - - 581fca7fdc014b8b894519cc531f9a04 -``` -
- -
- Expand: Elements section (custom actions) - -Reference: [Custom Frigate Card Actions](#special-actions) - -```yaml -elements: - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-a-circle - title: Show default view - tap_action: - action: custom:frigate-card-action - frigate_card_action: default - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-b-circle - title: Show most recent clip - tap_action: - action: custom:frigate-card-action - frigate_card_action: clip - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-c-circle - title: Show clips - tap_action: - action: custom:frigate-card-action - frigate_card_action: clips - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-d-circle - title: Show image view - tap_action: - action: custom:frigate-card-action - frigate_card_action: image - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-e-circle - title: Show live view - tap_action: - action: custom:frigate-card-action - frigate_card_action: live - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-f-circle - title: Show most recent snapshot - tap_action: - action: custom:frigate-card-action - frigate_card_action: snapshot - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-g-circle - title: Show snapshots - tap_action: - action: custom:frigate-card-action - frigate_card_action: snapshots - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-h-circle - title: Download media - tap_action: - action: custom:frigate-card-action - frigate_card_action: download - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-i-circle - title: Open Frigate UI - tap_action: - action: custom:frigate-card-action - frigate_card_action: camera_ui - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-j-circle - title: Change to fullscreen - tap_action: - action: custom:frigate-card-action - frigate_card_action: fullscreen - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-k-circle - title: Toggle hidden menu - tap_action: - action: custom:frigate-card-action - frigate_card_action: menu_toggle - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-l-circle - title: Select Front Door - tap_action: - action: custom:frigate-card-action - frigate_card_action: camera_select - camera: camera.front_door - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-m-circle - title: Media player play - tap_action: - action: custom:frigate-card-action - frigate_card_action: media_player - media_player: media_player.nesthub50be - media_player_action: play - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-n-circle - title: Media player stop - tap_action: - action: custom:frigate-card-action - frigate_card_action: media_player - media_player: media_player.nesthub - media_player_action: stop - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-o-circle - title: Screenshot - tap_action: - action: custom:frigate-card-action - frigate_card_action: screenshot - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-p-circle - title: Show PTZ - tap_action: - action: custom:frigate-card-action - frigate_card_action: show_ptz - show_ptz: true - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-q-circle - title: Native PTZ Preset - tap_action: - action: custom:frigate-card-action - frigate_card_action: ptz - ptz_action: preset - ptz_preset: 'doorway -``` -
- - - -
- Expand: Dimensions section - -Reference: [Dimension Options](#dimensions-options). - -```yaml -dimensions: - aspect_ratio_mode: dynamic - aspect_ratio: 16:9 - max_height: 100vh - min_height: 100px -``` -
- - - -
- Expand: Timeline section - -Reference: [Timeline Options](#timeline-options). - -```yaml -timeline: - style: stack - clustering_threshold: 3 - events_media_type: all - show_recordings: true - window_seconds: 3600 - controls: - thumbnails: - mode: left - size: 100 - show_details: true - show_download_control: true - show_favorite_control: true - show_timeline_control: true -``` -
- - - -
- Expand: Overrides section - -Reference: [Override Options](#overrides-options). - -Overrides allow overriding certain (many) configuration parameters when a given -list of conditions are met. The below is a fully expanded set of those -overridable parameters. This is really just repeating the above expansions of -the relevant sections, rather than indicating new or different parameters, i.e. -this repetition is included for illustrative purposes of what is overridable. - -```yaml -overrides: - - conditions: - - condition: view - views: - - live - overrides: - cameras: - # As this is a list, we need to carefully ensure we are - # overridding the correct index. We do this by specifying - # earlier indicies as being overridden with an empty object - # (in YAML this is `{}`). In this example, overriddes will - # only apply to the 2nd camera: - - {} # No overrides for camera index 0. - - live_provider: 'ha' # Overrides for camera index 1. - engine: auto - frigate: - url: http://my.frigate.local - client_id: frigate - camera_name: front_door - labels: - - person - zones: - - steps - dependencies: - all_cameras: false - cameras: - - camera-2 - triggers: - motion: false - occupancy: true - entities: - - binary_sensor.front_door_sensor - go2rtc: - modes: - - webrtc - - mse - - mp4 - - mjpeg - stream: sitting_room - webrtc_card: - # Arbitrary WebRTC Card options, see https://github.com/AlexxIT/WebRTC#configuration . - entity: camera.sitting_room_rtsp - ui: true - jsmpeg: - options: - audio: false - video: true - pauseWhenHidden: false - disableGl: false - disableWebAssembly: false - preserveDrawingBuffer: false - progressive: true - throttled: true - chunkSize: 1048576 - maxAudioLag: 10 - videoBufferSize: 524288 - audioBufferSize: 131072 - image: - refresh_seconds: 1 - live: - webrtc_card: - ui: true - jsmpeg: - options: - audio: false - video: true - pauseWhenHidden: false - disableGl: false - disableWebAssembly: false - preserveDrawingBuffer: false - progressive: true - throttled: true - chunkSize: 1048576 - maxAudioLag: 10 - videoBufferSize: 524288 - audioBufferSize: 131072 - controls: - next_previous: - style: chevrons - size: 48 - thumbnails: - media_type: events - events_media_type: all - size: 100 - show_details: false - show_download_control: true - show_favorite_control: true - show_timeline_control: true - mode: none - title: - mode: popup-bottom-right - duration_seconds: 2 - actions: - entity: light.office_main_lights - tap_action: - action: none - hold_action: - action: none - double_tap_action: - action: none - start_tap_action: - action: none - end_tap_action: - action: none - menu: - style: hidden - position: top - alignment: left - buttons: - frigate: - priority: 50 - enabled: true - alignment: matching - # Default icon is an internal coded Frigate icon. Note - # absence of 'mdi' here (mdi has no Frigate icon). - icon: frigate - cameras: - priority: 50 - enabled: true - alignment: matching - icon: mdi:video-switch - live: - priority: 50 - enabled: true - alignment: matching - icon: mdi:cctv - clips: - priority: 50 - enabled: true - alignment: matching - icon: mdi:filmstrip - snapshots: - priority: 50 - enabled: true - alignment: matching - icon: mdi:camera - recordings: - priority: 50 - enabled: false - alignment: matching - icon: mdi:album - image: - priority: 50 - # Disable the image button. - enabled: false - alignment: matching - icon: mdi:image - timeline: - # Ensure the timeline button is ordered earlier. - priority: 100 - enabled: true - alignment: matching - icon: mdi:chart-gantt - download: - priority: 50 - enabled: true - alignment: matching - icon: mdi:download - camera_ui: - priority: 50 - enabled: true - alignment: matching - icon: mdi:web - fullscreen: - priority: 50 - enabled: true - alignment: matching - icon: mdi:fullscreen - media_player: - priority: 50 - enabled: false - alignment: matching - icon: mdi:cast - button_size: 40 - image: - mode: url - refresh_seconds: 0 - actions: - entity: light.office_main_lights - tap_action: - action: none - hold_action: - action: none - double_tap_action: - action: none - start_tap_action: - action: none - end_tap_action: - action: none - view: - default: live - camera_select: current - interaction_seconds: 300 - update_seconds: 0 - update_force: false - update_cycle_camera: false - update_entities: - - binary_sensor.my_motion_sensor - render_entities: - - switch.render_card - dark_mode: 'off' - actions: - entity: light.office_main_lights - tap_action: - action: none - hold_action: - action: toggle - double_tap_action: - action: none - start_tap_action: - action: none - end_tap_action: - action: none -``` -
- - -
- Expand: Performance section - -Reference: [Performance Options](#performance-options). - -```yaml -performance: - profile: high - features: - animated_progress_indicator: true - media_chunk_size: 50 - style: - border_radius: true - box_shadow: true -``` -
- -
- Expand: Automation section - -Reference: [Automation Options](#automation-options). - -```yaml -automations: - - conditions: - - condition: fullscreen - fullscreen: true - actions: - - action: custom:frigate-card-action - frigate_card_action: live_substream_on - actions_not: - - action: custom:frigate-card-action - frigate_card_action: live_substream_off -``` -
- -
- Expand: Other options - -Reference: [Other Options](#other-options). - -```yaml -card_id: main -``` -
- -### Basic cameras configuration - -
- Expand: Basic cameras configuration - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.sitting_room - - camera_entity: camera.front_door -``` -
- - -
- Expand: Different providers for a single camera - -Cameras can be repeated with different providers (note the required use of `id` -to provide a separate unambiguous way of referring to that camera, since the -`camera_entity` is shared between the two cameras). - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.front_door - live_provider: jsmpeg - title: Front Door (JSMPEG) - - camera_entity: camera.front_door - live_provider: webrtc-card - title: Front Door (WebRTC) - webrtc_card: - entity: camera.front_door_rtsp - id: front-door-webrtc -``` -
- -### WebRTC Card Provider - -
- Expand: Basic WebRTC Card configuration with UI enabled - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.front_door - live_provider: webrtc-card - title: Front Door - webrtc_card: - entity: camera.front_door_rtsp -live: - webrtc_card: - ui: true -``` -
- - - -### Static Aspect Ratios - -You can set a static aspect ratio. - -
- Expand: Static 4:3 aspect ratios - -```yaml -[...] -dimensions: - aspect_ratio_mode: static - aspect_ratio: '4:3' -``` -
- -### Adding Menu Icons - -You can add custom icons to the menu with arbitrary actions. - -
- Expand: Custom menu icon - -This example adds an icon that navigates the browser to the releases page for this -card: - -```yaml -[...] -elements: - - type: custom:frigate-card-menu-icon - icon: mdi:book - tap_action: - action: url - url_path: https://github.com/dermotduffy/frigate-hass-card/releases -``` -
- -### Adding Menu State Icons - -You can add custom state icons to the menu to show the state of an entity and complete arbitrary actions. - -
- Expand: Custom menu state icon - -This example adds an icon that represents the state of the -`light.office_main_lights` entity, that toggles the light on double click. - -```yaml -[...] -elements: - - type: custom:frigate-card-menu-state-icon - entity: light.office_main_lights - tap_action: - action: toggle -``` -
- -### Adding State Badges - -You can add a state badge to the card showing arbitrary entity states. - -
- Expand: State badge - -This example adds a state badge showing the temperature and hides the label text: - -```yaml -[...] -elements: - - type: state-badge - entity: sensor.kitchen_temperature - style: - right: '-20px' - top: 100px - color: rgba(0,0,0,0) - opacity: 0.5 -``` - -Picture elements temperature example -
- -### Adding State Badges - -You can have icons conditionally added to the menu based on entity state. - -
- Expand: Conditional menu icons - -This example only adds the light entity to the menu if a light is on. - -```yaml -[...] -elements: - - type: conditional - conditions: - - condition: state - entity: light.kitchen - state: on - elements: - - type: custom:frigate-card-menu-state-icon - entity: light.kitchen - tap_action: - action: toggle -``` -
- - - -### Restricting Icons To Certain Views - -You can restrict icons to only show for certain [views](#views) using a -`custom:frigate-card-conditional` element - -
- Expand: View-based conditions - -This example shows a car icon that calls a service but only in the `live` view. - -```yaml -[...] -elements: - - type: custom:frigate-card-conditional - conditions: - - condition: view - views: - - live - elements: - - type: icon - icon: mdi:car - style: - background: rgba(255, 255, 255, 0.25) - border-radius: 5px - right: 25px - bottom: 50px - tap_action: - action: call-service - service: amcrest.ptz_control - service_data: - entity_id: camera.kitchen - movement: up -``` -
- - - -### Triggering Card Actions - -You can control the card itself with the `custom:frigate-card-action` action. - -
- Expand: Custom fullscreen button - -This example shows an icon that toggles the card fullscreen mode. - -```yaml -[...] -elements: - - type: icon - icon: mdi:fullscreen - style: - left: 40px - top: 40px - tap_action: - action: custom:frigate-card-action - frigate_card_action: fullscreen -``` -
- -### Adding Card-wide Actions - -You can add actions to the card to be trigger on `tap`, `double_tap`, `hold`, `start_tap` or `end_tap`. See [actions](#actions) above. - -
- Expand: Adding a card-wide action - -In this example double clicking the card in any view will cause the card to go -into fullscreen mode, **except** when the view is `live` in which case the -office lights are toggled. - -```yaml -[...] -view: - actions: - double_tap_action: - action: custom:frigate-card-action - frigate_card_action: fullscreen -live: - actions: - entity: light.office_main_lights - double_tap_action: - action: toggle -``` -
- - - -### Configuring a submenu - -You can add submenus to the menu -- buttons that when pressed reveal a dropdown submenu of configurable options. - -
- Expand: Adding a submenu - -This example shows a submenu that illustrates a variety of actions. - -```yaml -[...] -elements: - - type: custom:frigate-card-menu-submenu - icon: mdi:menu - items: - - title: Lights - icon: mdi:lightbulb - entity: light.office_main_lights - tap_action: - action: toggle - - title: Google - icon: mdi:google - tap_action: - action: url - url_path: https://www.google.com - - title: Fullscreen - icon: mdi:fullscreen - tap_action: - action: custom:frigate-card-action - frigate_card_action: fullscreen -``` - -
- -
- Expand: Custom submenus per camera - -This example shows submenus conditional on the camera selected. - -```yaml -[...] -elements: - - type: custom:frigate-card-conditional - conditions: - - condition: camera - cameras: - - camera.front_door - elements: - - type: custom:frigate-card-menu-submenu - icon: mdi:door - items: - - title: Front Door Lights - icon: mdi:lightbulb - entity: light.front_door_lights - tap_action: - action: toggle - - type: custom:frigate-card-conditional - conditions: - - condition: camera - cameras: - - camera.living_room - elements: - - type: custom:frigate-card-menu-submenu - icon: mdi:sofa - items: - - title: Living Room Lights - icon: mdi:lightbulb - entity: light.living_room_lights - tap_action: - action: toggle - - title: Living Room Lamp - icon: mdi:lightbulb - entity: light.living_room_lamp - tap_action: - action: toggle -``` - -
- - - -### Configuring a `select` submenu - -You can easily add a submenu to the menu based on a `select` or `input_select` entity. - -
- Expand: Adding a select submenu - -This example imagines the user has an `input_select` entity configured in their Home Assistant configuration like so: - -```yaml -input_select: - kitchen_scene: - name: Kitchen Scene Select - options: - - scene.kitchen_cooking_scene - - scene.kitchen_tv_scene - icon: mdi:lightbulb -``` - -The following will convert this entity into a submenu: - -```yaml -[...] -elements: - - type: custom:frigate-card-menu-submenu-select - entity: input_select.kitchen_scene -``` - -To override 1 or more individual options (e.g. to set custom icons and titles) - -```yaml -[...] -elements: - - type: custom:frigate-card-menu-submenu-select - icon: mdi:lamps - entity: input_select.kitchen_scene - options: - scene.kitchen_cooking_scene: - icon: mdi:chef-hat - title: Cooking time! - scene.kitchen_tv_scene: - icon: mdi:television - title: TV! -``` -
- -### Overriding card behavior - -You can override card configuration when certain [conditions](#frigate-card-conditions) are met. - -
- Expand: Hiding the menu in fullscreen mode - -This example disables the menu unless the card is in fullscreen mode, and uses a -card-wide action to enable fullscreen mode on `double_tap`: - -```yaml -view: - actions: - double_tap_action: - action: custom:frigate-card-action - frigate_card_action: fullscreen -overrides: - - conditions: - - condition: fullscreen - fullscreen: true - overrides: - menu: - style: none -``` - -
- -
- Expand: Enable WebRTC Card UI only for a selected camera - -This example enables WebRTC Card UI mode for a particular camera. - -```yaml -cameras: - - camera_entity: camera.office - live_provider: webrtc-card - - camera_entity: camera.a-different-camera -[...] -overrides: - - conditions: - - condition: camera - cameras: - - camera.office - overrides: - live: - webrtc_card: - ui: true -``` - -
- -
- Expand: Change the menu position based on HA state - -```yaml -overrides: - - conditions: - - condition: state - entity: light.office_lights - state: 'on' - overrides: - menu: - position: bottom -``` -
- -
- Expand: Change the default view based on HA state - -This example changes the default card view from `live` to `image` depending on -the value of the `binary_sensor.alarm_armed` sensor. Note that the override -alone will only change the _default_ when the card next is requested to change -to the default view. By also including the `update_entities` parameter, we ask -the card to trigger a card update based on that entity -- which causes it to use -the new overriden default immediately. Alternatives to trigger the card to -change view but without `update_entities` would just be having an -`update_seconds` parameter which reloads the default view that many seconds -after user interaction stops or through the use of the `triggers` option for a -given camera (see [Trigger Configuration](#camera-triggers-configuration)). - -```yaml -view: - default: live - update_entities: - - binary_sensor.alarm_armed -overrides: - - conditions: - - condition: state - entity: binary_sensor.alarm_armed - state: 'off' - overrides: - view: - default: image -``` -
- - -
- Expand: Change the menu style in expanded mode - -This example changes the menu style to `overlay` in expanded mode in order to take -advantage of the extra horizontal space of the dialog/popup. - -```yaml -menu: - style: hidden -overrides: - - conditions: - - condition: expand - expand: true - overrides: - menu: - style: overlay -``` -
- -### Refreshing a static image - -
- Expand: Auto-refreshing a static image - -This example fetches a static image every 10 seconds (in this case the latest image saved on the Frigate server for a given camera). - -```yaml -[...] -view: - default: image -image: - src: https://my-friage-server/api/living_room/latest.jpg - refresh_seconds: 10 -``` -
- - - -### Defining multiple actions for Elements - -
- Expand: Changing camera and view simultaneously - -This example shows how to configure multiple actions for a single Frigate card user interaction, in this case both selecting a different camera and changing the view on `tap`. Note that multiple actions are not supported on stock Picture Elements, see [actions](#actions) for more information. - -```yaml -[...] -elements: - - type: custom:frigate-card-menu-icon - icon: mdi:chair-rolling - tap_action: - - action: custom:frigate-card-action - frigate_card_action: camera_select - camera: camera.office - - action: custom:frigate-card-action - frigate_card_action: live -``` -
- -### Using a PTZ control - -The card supports using PTZ controls to conveniently control pan, tilt and zoom for cameras. - -
- Expand: Using the PTZ controls - -This example shows the PTZ controls of the `live` view. Note that if your camera engine supports it (e.g. `frigate`) this will just work out of the box with no configuration at all. - -```yaml -[...] -live: - ptz: - orientation: horizontal - service: sonoff.send_command - data_left: - device: '048123' - cmd: left - data_right: - device: '048123' - cmd: right - data_up: - device: '048123' - cmd: up - data_down: - device: '048123' - cmd: down -``` -
- -### Using live substreams - -The card supports configuring 'substreams' to show up for a given live camera through the use of [camera dependencies](#camera-dependencies-configuration). - -
- Expand: Having an SD and HD substream - -This example shows two substreams for a single live camera, and uses the 'HD' icon. - -```yaml -[...] -cameras: - - camera_entity: camera.sitting_room - live_provider: image - dependencies: - cameras: - - sitting_room_hd - - camera_entity: camera.sitting_room - title: Sitting Room HD - live_provider: go2rtc - id: sitting_room_hd - # This camera serves only as a substream. - capabilities: - disable_except: - - substream -menu: - buttons: - substreams: - icon: mdi:high-definition -``` -
- -
- Expand: Having a substream menu with different live providers - -This example shows a substream menu for three different live providers for a given camera. - -```yaml -[...] -cameras: - - camera_entity: camera.sitting_room - live_provider: image - dependencies: - cameras: - - sitting_room_go2rtc - - sitting_room_ha - icon: mdi:image - - camera_entity: camera.sitting_room - live_provider: go2rtc - id: sitting_room_go2rtc - capabilities: - disable_except: - - substream - title: Sitting Room go2rtc - icon: mdi:alpha-g - - camera_entity: camera.sitting_room - live_provider: ha - id: sitting_room_ha - capabilities: - disable_except: - - substream - title: Sitting Room HA - icon: mdi:home -``` -
- -### Using `card-mod` to style the card - -This card allows the use of -[card-mod](https://github.com/thomasloven/lovelace-card-mod) to style arbitrary -card contents. `card-mod` can be complex to use and relies on the underlying -internal DOM structure to style elements -- as such, while its use is possible -it's not officially supported and no attempt is made to preserve backwards -compatability of the internal DOM between any versions. It'll look good, but you're on your own! - -
- Expand: Use card-mod to style a Picture elements label - -This example changes the color and removes the padding around a [Picture -Elements state -label](https://www.home-assistant.io/lovelace/picture-elements/#state-label). - -```yaml -[...] -card_mod: - style: - frigate-card-elements $: - hui-state-label-element $: | - div { - padding: 0px !important; - color: blue; - } -``` -
- -### Overriding default menu behavior - -
- Expand: Overriding default menu behavior - -This example moves the fullscreen button into its own group aligned to the `left`, enables the `image` button and orders it furthest to the `right`. - -```yaml -[...] -menu: - alignment: right - buttons: - image: - enabled: true - priority: 100 - fullscreen: - alignment: opposing -``` -
- -### Using a dependent camera - -`dependencies.cameras` allows events/recordings for other cameras to be shown along with the currently selected camera. For example, this can be used to show events with the `birdseye` camera (since it will not have events of its own). - -
- Expand: Using dependent cameras with birdseye - -This example shows events for two other cameras when `birdseye` is selected. - -```yaml -[...] -cameras: - - camera_entity: camera.kitchen - - camera_entity: camera.sitting_room - - camera_name: birdseye - dependencies: - cameras: - - camera.kitchen - - camera.sitting_room -``` -
- -
- Expand: Using all dependent cameras with birdseye - -This example shows events for all other cameras when `birdseye` is selected. This is just a shortcut for naming all other cameras. - -```yaml -[...] -cameras: - - camera_entity: camera.kitchen - - camera_entity: camera.sitting_room - - frigate: - camera_name: birdseye - dependencies: - all_cameras: true -``` -
- -### Taking action when a camera is triggered! - -Have your card follow the action when a camera is triggered. - -
- Expand: Changing to `live` when a camera is triggered - -```yaml -type: custom:frigate-card -cameras: - # This is a Frigate camera which will automatically be triggered when events occur. - - camera_entity: camera.back_yard - # This is a Frigate camera which will only be triggered by motion entity changes or a door being opened. - - camera_entity: camera.front_door - triggers: - occupancy: false - motion: true - entities: - - binary_sensor.door_opened - events: [] -view: - triggers: - show_trigger_status: true - filter_selected_camera: false - actions: - trigger: live - untrigger: default -``` -
- -
- Expand: Showing an alarm menu button when a camera is triggered - -This example adds a menu button to optionally activate a siren when the camera is triggered. - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.office -elements: - - type: custom:frigate-card-conditional - elements: - - type: custom:frigate-card-menu-icon - icon: mdi:alarm-bell - title: Activate alarm - style: - color: red - tap_action: - action: call-service - service: homeassistant.toggle - data: - entity_id: siren.siren - conditions: - - condition: triggered - triggered: - - camera.office -``` -
- - - -### Changing the Media Layout - -Change how the media fits and is positioned within the card dimensions. - -
- Expand: Stretching an image - -Stretch a camera into a 4:4 square. - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.landing - dimensions: - aspect_ratio: '4:4' - layout: - fit: fill -``` -
- -
- Expand: Convert a landscape camera to a portrait live view - -Take the left-hand side (position with x == `0` and use that as the basis of a `9:16` (i.e. portrait) live view. - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.landing - dimensions: - aspect_ratio: '9:16' - layout: - fit: cover - position: - x: 0 -``` -
- - - -### Using `screen` / Media Query conditions - -Alter the card configuration based on device or viewport properties. - -
- Expand: Hide menu & controls when viewport width <= 300 (e.g. PIP mode) - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.back_yard - - camera_entity: camera.sitting_room -overrides: - - conditions: - - condition: screen - media_query: '(max-width: 300px)' - overrides: - menu: - style: none - live: - controls: - next_previous: - style: none - thumbnails: - mode: none -``` -
- -
- Expand: Change menu position when orientation changes - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.back_yard - - camera_entity: camera.sitting_room -menu: - style: overlay -overrides: - - conditions: - - condition: screen - media_query: '(orientation: landscape)' - overrides: - menu: - position: left -``` -
- -### Using menu-based video controls instead of browser builtin controls - -
- Expand: Using menu-based video controls - -Disable the stock video controls and add menu button equivalents. - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.back_yard -live: - controls: - builtin: false -media_viewer: - controls: - builtin: false -menu: - buttons: - play: - enabled: true - mute: - enabled: true -``` -
- -### Automatically trigger "fullscreen" mode - -The card cannot automatically natively trigger fullscreen mode without the user -clicking, since Javascript (understandbly) prevents random websites from -triggering fullscreen mode without the user having activated it. - -There is a potential workaround: - -
- Expand: Use "browser_mod" to show a popup with a Frigate Card - -This workaround uses -[hass-browser_mod](https://github.com/thomasloven/hass-browser_mod) with an -automation to trigger a popup. Thanks to -[conorlap@](https://github.com/conorlap) for the following example: - -```yaml -alias: >- - Doorbell Pressed OR Human Detected - Firefox browser full screen video feed - for 15 seconds -description: "" -trigger: - - platform: state - from: "off" - to: "on" - entity_id: - - binary_sensor.frontdoor_person_occupancy - - platform: state - entity_id: - - binary_sensor.front_door_dahua_button_pressed - to: "on" -condition: [] -action: - - service: browser_mod.popup - data: - size: wide - timeout: 15000 - content: - type: custom:frigate-card - aspect_ratio: 55% - cameras: - - camera_entity: camera.frontdoor - live_provider: ha - menu: - style: none - live: - controls: - title: - mode: none - target: - device_id: - - d0e93101edfg44y3yt35y5y45y54y -mode: single -``` -
- - - -### Passing the card actions from the URL - -The card can respond to actions in the query string (see [below](#query-string-actions)). - -
- Expand: Selecting the kitchen camera and opening the expanded view - -This example assumes the dashboard URL is `https://ha.mydomain.org/lovelace-test/0`. - -``` -https://ha.mydomain.org/lovelace-test/0?frigate-card-action.camera_select=kitchen&frigate-card-action.expand -``` -
- -
- Expand: Choosing the clips view on a named card - -This example assumes the dashboard URL is `https://ha.mydomain.org/lovelace-test/0`. - -It assumes that one card (of potentially multiple Frigate Cards on the dashboard) is configured with a `card_id` parameter: - -```yaml -type: custom:frigate-card -card_id: main -cameras: -[...] -``` - -``` -https://ha.mydomain.org/lovelace-test/0?frigate-card-action.main.clips -``` -
- -
- Expand: Choosing the camera from a separate picture elements card - -In this example, the card will select a given camera when the user navigates from a *separate* Picture Elements card: - -Taking card actions via the URL - -Frigate Card configuration: - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.living_room - - camera_entity: camera.landing -``` - -Picture Elements configuration (assumes the dashboard is `/lovelace-frigate/map`): - -```yaml -type: picture-elements -image: https://demo.home-assistant.io/stub_config/floorplan.png -elements: - - type: icon - icon: mdi:cctv - style: - top: 22% - left: 30% - tap_action: - action: navigate - navigation_path: /lovelace-frigate/map?frigate-card-action.camera_select=camera.living_room - - type: icon - icon: mdi:cctv - style: - top: 71% - left: 42% - tap_action: - action: navigate - navigation_path: /lovelace-frigate/map?frigate-card-action.camera_select=camera.landing -``` - -
- -### Automation actions - -The card can automatically execute actions when certain conditions are met. - -
- Expand: Automatically selecting a high-definition substream in fullscreen mode - -This example will automatically turn on the first configured substream when the -card is put in fullscreen mode, and turn off the substream when exiting -fullscreen mode. - -```yaml -automations: - - conditions: - - condition: fullscreen - fullscreen: true - actions: - - action: custom:frigate-card-action - frigate_card_action: live_substream_on - actions_not: - - action: custom:frigate-card-action - frigate_card_action: live_substream_off -``` -
- -### Grid display overrides - -
- Expand: Change the grid layout configuration in fullscreen mode - -This example will always render 5 columns in fullscreen mode in both the live -and media viewer views, and will not enlarge the selected item. The normal -auto-layout behavior will be used outside of fullscreen mode. - -```yaml -overrides: - - conditions: - - condition: fullscreen - fullscreen: true - - condition: display_mode - display_mode: grid - overrides: - live: - display: - grid_columns: 5 - grid_selected_width_factor: 1 - media_viewer: - display: - grid_columns: 5 - grid_selected_width_factor: 1 -``` -
- - - -### `dashboard` cast method - -
- Expand: Using the `dashboard` cast method to cast a low latency live provider - -This example will configure a Frigate card that can cast a dashboard view to a media player, which has a second Frigate card in panel mode with a low-latency live provider. - -#### Source card - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.front_door - cast: - method: dashboard - dashboard: - dashboard_path: cast - view_path: front-door -``` - -#### Dashboard configuration - -This dashboard is configured at the path `/cast/` (path referred to in `dashboard_path` above). - -```yaml -title: Frigate Card Casting -views: - - title: Casting - # This path is referred to in `view_path` above. - path: front-door - # Ensure the video is "maximized" - type: panel - cards: - - type: custom:frigate-card - cameras: - - camera_entity: camera.front_door - live_provider: go2rtc -``` - -
- -### Interaction conditions - -The card can automatically execute actions when the card is interacted with (mouse or touch). - -
- Expand: Automatically show a high-bandwidth stream on interaction - -This example will automatically use a HD live substream when the mouse cursor interacts with the card. - -```yaml -type: custom:frigate-card -cameras: - - live_provider: go2rtc - camera_entity: camera.office - triggers: - entities: - - switch.office_detect - dependencies: - cameras: - - camera.office_hd - - camera_entity: camera.office_hd - live_provider: go2rtc - capabilities: - disable_except: - - substream -automations: - - actions: - - action: custom:frigate-card-action - frigate_card_action: live_substream_on - actions_not: - - action: custom:frigate-card-action - frigate_card_action: live_substream_off - conditions: - - condition: interaction - interaction: true -``` -
- - - -### Passing the card actions from the URL - -It is possible to pass the Frigate card one or more actions from the URL (e.g. select a particular camera, open the live view in expanded mode, etc). - -The Frigate card will execute these actions in the following circumstances: - -* On initial card load. -* On 'tab' change in a dashboard. -* When a `navigate` [action](https://www.home-assistant.io/dashboards/actions/) is called on the dashboard (e.g. a button click requests navigation). -* When the user uses the `back` / `forward` browser buttons whilst viewing a dashboard. - -To send an action to *all* Frigate cards: - -``` -[PATH_TO_YOUR_HA_DASHBOARD]?frigate-card-action.[ACTION]=[VALUE] -``` - -To send an action to a named Frigate card: - -``` -[PATH_TO_YOUR_HA_DASHBOARD]?frigate-card-action.[CARD_ID].[ACTION]=[VALUE] -``` - -| Parameter | Description | -| - | - | -| `ACTION` | One of the supported Frigate Card custom actions (see below). | -| `CARD_ID` | When specified only cards that have a `card_id` parameter will act. | -| `VALUE` | An optional value to use with the `camera_select` and `live_substream_select` actions. | - -**Note**: Both `.` and `:` may be used as the delimiter. If you use `:` some browsers may require it be escaped to `%3A`. - -**Note**: If a dashboard has multiple Frigate cards on it, even if they are on -different 'tabs' within that dashboard, they will all respond to the actions -unless the action is targeted with a `CARD_ID` as shown above. - -#### Actions - -| Action | Supported in query string | Explanation | -| - | - | - | -| `camera_select` | :white_check_mark: | | -| `camera_ui`| :white_check_mark: | | -| `clip` | :white_check_mark: | | -| `clips` | :white_check_mark: | | -| `default` | :white_check_mark: | | -| `download`| :heavy_multiplication_x: | Latest media information is not available on initial render. | -| `expand` | :white_check_mark: | | -| `fullscreen` | :heavy_multiplication_x: | Javascript does not support activating fullscreen without direct human interaction. Use `expand` as an alternative. | -| `image` | :white_check_mark: | | -| `live_substream_select` | :white_check_mark: | | -| `live` | :white_check_mark: | | -| `media_player`| :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/frigate-hass-card/issues) if you need this. | -| `menu_toggle` | :white_check_mark: | | -| `microphone_mute`, `microphone_unmute`| :heavy_multiplication_x: | | -| `mute`, `unmute` | :heavy_multiplication_x: | | -| `play`, `pause` | :heavy_multiplication_x: | | -| `recording` | :white_check_mark: | | -| `recordings` | :white_check_mark: | | -| `screenshot`| :heavy_multiplication_x: | Latest media information is not available on initial render. | -| `snapshot` | :white_check_mark: | | -| `snapshots` | :white_check_mark: | | - -See [custom actions](#custom-actions) for a description of what the actions do. - -#### Examples - -See [query string examples](#query-string-examples) for examples of usage. - -### Casting the Card - -This card can be (Chrome) casted to a device (such as a [Nest Hub](https://store.google.com/us/product/nest_hub_2nd_gen)) through the use of [Home Assistant Cast](https://cast.home-assistant.io/). - -#### Instructions to Cast - -* Visit [Home Assistant Cast](https://cast.home-assistant.io/) and click `Start Casting` -* Enter your Home Assistant URL, and authorize your account. -* Click `Start Casting` and choose the device to cast to from the browser menu. -* Choose which view/dashboard to display. -* If successful, the view will be cast to the device. - -#### Limitations - -Casting Home Assistant dashboards comes with a number of caveats: - -* Home Assistant Casting does not support the HA `streaming` component ([source](https://cast.home-assistant.io/faq.html)). This means clips playing and the `ha` live provider can not work. Other live providers such as `jsmpeg` and `webrtc-card` function correctly. -* The Javascript fullscreen API does not work (so the fullscreen button does not work, but see below for an equivalent). - -#### Recommended configuration for a Nest Hub - -Using a `panel` dashboard with the following base configuration will result in the card consuming the entire device screen: - -```yaml -type: custom:frigate-card -cameras: - - camera_entity: camera.front_door - live_provider: jsmpeg -dimensions: - aspect_ratio: 1024:600 - aspect_ratio_mode: static -``` - -See [screenshot above](#screenshots-card-casting). - -## Troubleshooting - - - -### Small circular logo/watermark continually shown on livestream - -If the `live.show_image_during_load` option is enabled (the default), a temporary image from Home Assistant is rendered and refreshed every `1s` while the full stream is loading. When this temporary image is being shown, a small circular icon is rendered on the top-right of the livestream to indicate to the user that this is not the true stream. If the icon persists, it means your underlying stream is not actually loading and may be misconfigured / broken. - -### `Forbidden media source identifier` - -* If you are using a custom `client_id` setting in your `frigate.yml` file (the configuration file for the Frigate backend itself), you must tell the card about it. See [camera configuration](#camera-frigate-configuration"). -* You must have the `Enable the media browser` option enabled for the Frigate integration, in order for media fetches to work for the card. Media fetches are used to fetch events / clips / snapshots, etc. If you just wish to use live streams without media fetches, you can use the following configuration: - -```yaml -live: - controls: - thumbnails: - mode: none -``` - -### Title "Popups" are annoying / continually popping up - -Title popups can be disabled for live or media viewer views with this configuration: - -```yaml -live: - controls: - title: - mode: none -media_viewer: - controls: - title: - mode: none -``` - -### Microphone / 2-way audio doesn't work - -There are many requirements for 2-way audio to work. See [Using 2-way -audio](#using-2-way-audio) for more information about these. If your microphone -still does not work and you believe you meet all the requirements try -eliminating the card from the picture by going directly to the `go2rtc` UI, -navigating to `links` for your given stream, then to `webrtc.html` with a -microphone. If this does not work correctly with 2-way audio then your issue is -with `go2rtc` not with the card. In this case, you could file an issue in [that -repo](https://github.com/AlexxIT/go2rtc/issues) with debugging information as -appropriate. - -### Microphone menu button does not appear - -The microphone menu button will only appear if both enabled (see [Menu Button Options](#menu-buttons)) -and if the media that is currently loaded supports 2-way audio. See -[Using 2-way audio](#using-2-way-audio) for more information about the requirements that must be followed. - -### Static image URL with credentials doesn't load - -Your browser will not allow a page/script (like this card) to pass credentials to a cross-origin (different host) image URL for security reasons. There is no way around this unless you could also control the webserver that is serving the image to specifically allow `crossorigin` requests (which is typically not the case for an image served from a camera, for example). The stock Home Assistant Picture Glance card has the same limitation, for the same reasons. - -### Chrome autoplays when a tab becomes visible again - -Even if `live.auto_play` or `media_viewer.auto_play` is set to `[]`, Chrome itself will still auto play a video that was previously playing prior to the tab being hidden, once that tab is visible again. This behavior cannot be influenced by the card. Other browsers (e.g. Firefox, Safari) do not exhibit this behavior. - -### The `live` view just shows a blank white image during loading - -For some slowly loading cameras, for which [Home Assistant stream preloading](https://www.home-assistant.io/integrations/camera/) is not enabled, Home Assistant may return a blank white image when asked for a still. These stills are used during initial Frigate card load of the `live` view if the `live.show_image_during_load` option is enabled. Disabling this option should show the default media loading controls (e.g. a spinner or empty video player) instead of the blank white image. - - - -### Timeline shows error message - -If the timeline shows a message such as `Failed to receive response from Home -Assistant for request.` make sure you are running a version of the [Frigate -integration](https://github.com/blakeblackshear/frigate-hass-integration) >= -3.0.0-rc.1. - -### Fullscreen Button Does Not Appear On iPhone - -Unfortunately, [iOS does not support the Javascript fullscreen -API](https://caniuse.com/fullscreen). As a result, card-level fullscreen support -for the iPhone is not currently possible. - -### Large downloads don't work - -Downloads are assembled by the Frigate backend out of ~10s segment files. You -must have enough cache space in your Frigate instance to allow this assembly to -happen -- if downloads don't work, especially for recordings, check your Frigate -backend logs to see if it's running out of space. You can increase your cache -size with the `tmpfs` `size` argument, see [Frigate -documentation](https://docs.frigate.video/frigate/installation#docker). - -Large downloads may take a few seconds to assemble, so there may be a delay -between clicking the download button and the download starting. - -### Android Will Not Render >4 JSMPEG Live Views - -Android Webview (as used by Android Chrome / Android Home Assistant Companion) -appears to severely limit the number of simultaneous OpenGL contexts that can be -opened. The JSMPEG player (that this card uses), consumes 1 OpenGL context per -rendering. - -This limitation may be worked around (at a performance penalty) by disabling -OpenGL for JSMPEG live views: - -```yaml -live: - jsmpeg: - options: - disableGl: true -``` - -[This bug](https://github.com/dermotduffy/frigate-hass-card/issues/191) has some -more discussion on this topic. New ideas to address this underlying limitation -most welcome! - -### Carousels with video players cannot be dragged in Firefox - -The Firefox video player swallows mouse interactions, so dragging is not -possible in carousels that use the Firefox video player (e.g. `clips` carousel, -or live views that use the `frigate` or `webrtc-card` provider). The next and -previous buttons may be used to navigate in these instances. - -Dragging works as expected for snapshots, or for the `jsmpeg` provider. - -### Progress bar cannot be dragged in Safari - -Dragging the Safari video controls "progress bar" conflicts with carousel "dragging", meaning the video controls progress bar cannot be moved left or right. Turning off carousel dragging (and using next/previous controls) will return full video controls in Safari: - -```yaml -live: - draggable: false -media_viewer: - draggable: false -``` - -### `webrtc_card` unloads in the background - -[AlexxIT's WebRTC Card](https://github.com/AlexxIT/WebRTC) which is embedded by the `webrtc_card` live provider internally disconnects the stream when the browser tab is changed (regardless of any Frigate card configuration settings, e.g. `lazy_unload`). To allow the stream to continue running in the background, pass the `background` argument to the `webrtc_card` live provider as shown below. This effectively allows the Frigate card to decide whether or not to unload the stream. - -```yaml -live: - webrtc_card: - background: true -``` - -### `double_tap` does not work for [card-wide actions](#actions) on Android - -The Android video player swallows `double_tap` interactions in order to -rewind or fast-forward. Workarounds: - -* Use `hold` instead of `double_tap` for your card-wide action. -* Use a [Frigate Card Element](#frigate-card-elements) or menu icon to trigger - the action instead. - -### Home Assistant iOS App not updating after card version change - -Try resetting the app frontend cache: - -* `Configuration -> Companion App -> Debugging -> Reset frontend cache` - -### Chrome does not update card version after upgrade - -When upgrading the card it's recommended to reset the frontend cache. Sometimes clearing site data in Chrome settings isn't enough. - -* Press F12 to display `Dev Console` in Chrome then right click on the refresh icon and select `Empty Cache and Hard Reload` - -### Casting to a remote media player does not work - -This could be for any number of reasons. Chromecast devices can be quite picky on network, DNS and certificate issues, as well as audio and video codecs. Check your Home Assistant log as there may be more information in there. - -**NOTE**: In particular, for Frigate to support casting of clips, the default ffmpeg settings for Frigate must be modified, i.e. Frigate does not encode clips in a Chromecast compatible format out of the box (specifically: audio must be enabled in the AAC codec, whether your camera supports audio or not). See the [Frigate Home Assistant documentation](https://docs.frigate.video/integrations/home-assistant) or [this issue](https://github.com/blakeblackshear/frigate/issues/3175) for more. - -### Javascript console shows `[Violation] Added non-passive event listener to a scroll-blocking [...] event` - -This card uses [visjs](https://github.com/visjs/vis-timeline) -- a timeline library -- to show camera timelines. This library currently uses non-passive event-listeners. These warnings can be safely ignored in this instance and cannot easily be fixed in the underlying library. - -### Custom element does not exist - -This is usually a sign that the card is not correctly installed (i.e. the browser cannot find the Javascript). In cases where it works in some browsers / devices but not in others it may simply be an old browser / webview that does not support modern Javascript (this is occasionally seen on old Android hardware). In this latter case, you are out of luck. - -## Development - -### Building - -This project uses [Volta](https://github.com/volta-cli/volta) to ensure a consistent version of Node and Yarn are used during development. If you install Volta in your environment, you should not need to worry about which version of both to choose. **Note:** the dev container already comes with Volta installed. - -However, if you are not using Volta, you can check the `volta` key in the [`package.json`](./package.json) for a reference on which version of Node and Yarn should be used. - -```sh -$ git clone https://github.com/dermotduffy/frigate-hass-card -$ cd frigate-hass-card -$ yarn install -$ yarn run build -``` - -Resultant build will be at `dist/frigate-hass-card.js`. This could be installed via the [manual installation instructions above](#manual-installation). - -### Dev Container - -[![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/dermotduffy/frigate-hass-card) - -You can use the [VS Code Dev Containers](https://code.visualstudio.com/docs/remote/containers) extension to speed up the development environment creation. Simply: - -1. Clone the repository to your machine -1. Open VS Code on it -1. Reopen the folder in the Dev Container -1. Once done, press `F5` to start debugging - -Everything should just work without any additional configuration. Under the hood, the dev container setup takes care of bringing up: - -* Home Assistant (port `8123` or the next available one) -* Frigate (ports `5000` or the next available one) -* MQTT (port `1883` or the next available one) - -As docker-compose containers. - -* The Frigate Home Assistant Integration is registered as a `git submodule` at `.devcontainer/frigate-hass-integration`, and VS Code will initialize/clone it for you before opening the dev container. - -Some environment variables are supported in a `.env` file: - -* `FRIGATE_VERSION`: The version of Frigate to use. Defaults to the latest stable version. -* `HA_VERSION`: The version of Home Assistant to use. Defaults to the latest stable version. - -> **NOTE**: When not specifying any version, it's recommended that you `docker-compose pull` the stack from time to time to ensure you have the latest versions of the images. - -The Home Assistant container will get preconfigured during first initialization, therefore, if you changed the Home Assistant configuration, you will need to remove the HA container and start another. - -### Releasing - -1. Merge a PR that contains only a `package.json` and `const.ts` version number bump (see [this example](https://github.com/dermotduffy/frigate-hass-card/commit/a854187d4a354f8841ad284d75b0afbed7b634c4)). -1. Go to the [releases page](https://github.com/dermotduffy/frigate-hass-card/releases). -1. A release draft will automatically have been created, click 'Edit'. -1. Use the same version number for the release title and tag. -1. Choose 'This is a pre-release' for a beta version. -1. Hit 'Publish release'. - -### Translations -[![translation badge](https://badge.inlang.com/?url=github.com/dermotduffy/frigate-hass-card)](https://fink.inlang.com/github.com/dermotduffy/frigate-hass-card?ref=badge) - -To add translations, you can manually edit the JSON translation files in `src/localize/languages`, use the [inlang](https://inlang.com/) online editor, or run `yarn machine-translate` to add missing translations using AI from Inlang. +* Theme friendly. \ No newline at end of file diff --git a/docs/.nojekyll b/docs/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..7db2c4de --- /dev/null +++ b/docs/README.md @@ -0,0 +1,58 @@ +# Getting Started + +## Installation + +- [HACS](https://hacs.xyz/) is **highly** recommended to install the card -- it works for all Home Assistant variants. If you don't have [HACS](https://hacs.xyz/) installed, start there -- then come back to these instructions. + +- Find the card in HACS: + +``` +Home Assistant > HACS > Frontend > "Explore & Add Integrations" > Frigate Card +``` + +- Click `Download this repository with HACS`. + +See [Advanced Installation](advanced-installation.md) for other installation resources. + +## Adding your card + + - On a Home Assistant dashboard, choose: +``` +[Three dots menu] > Edit dashboard +``` + - Click `+ Add Card` shown on the bottom of the screen + - Choose `Custom: Frigate card` from the list + +## Initial configuration + +### Minimal configuration + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +``` + +### Video scrubbing configuration + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +profiles: + - scrubbing +``` + +### Multi-camera grid configuration + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + - camera_entity: camera.kitchen +live: + display: + mode: grid +``` + +See [Configuration](configuration/README.md) for full details on supported configuration options. \ No newline at end of file diff --git a/docs/_coverpage.md b/docs/_coverpage.md new file mode 100644 index 00000000..e203eaa3 --- /dev/null +++ b/docs/_coverpage.md @@ -0,0 +1,8 @@ +![logo](images/frigate-logo.svg) + +# Frigate Card 6.0.0 + +> A comprehensive camera card for Home Assistant. + +[GitHub](https://github.com/dermotduffy/frigate-hass-card/) +[Documentation](README.md) \ No newline at end of file diff --git a/docs/_sidebar.md b/docs/_sidebar.md new file mode 100644 index 00000000..658fb3d9 --- /dev/null +++ b/docs/_sidebar.md @@ -0,0 +1,10 @@ +* [Getting Started](README.md) +* [Configuration](configuration/README.md) +* [Examples](examples.md) +* [Screenshots](screenshots.md) +* [Troubleshooting](troubleshooting.md) +* [Usage](usage/README.md) + +--- + +* [Developing](developing.md) \ No newline at end of file diff --git a/docs/advanced-installation.md b/docs/advanced-installation.md new file mode 100644 index 00000000..d9451941 --- /dev/null +++ b/docs/advanced-installation.md @@ -0,0 +1,51 @@ +# Advanced Installation + +For most users, the installation instructions in the [Getting Started](README.md) section will install the card successfully. In some rarer situations, additional steps may need to be taken. + +### Manual resource management + +For most users, HACS should automatically add the necessary resources. Should this auto-registration not work you will need to complete one additional step. + +#### Lovelace in "Storage Mode" (default) + +- Navigate: + +``` +Three dots menu -> "Edit Dashboard" -> Three dots menu -> "Manage resources" -> "Add Resource" +``` + +- URL: `/hacsfiles/frigate-hass-card/frigate-hass-card.js` +- Resource type: `JavaScript Module` + +#### Lovelace in "YAML mode" (rare) + +You would see`mode: yaml` under `lovelace:` in your `configuration.yaml` if this applies to you. + +- Add the following to `configuration.yaml`: + +```yaml +lovelace: + resources: + - url: /hacsfiles/frigate-hass-card/frigate-hass-card.js + type: module +``` + +- Restart Home Assistant. + +### Manual installation + +- Download the `frigate-hass-card.zip` attachment of the desired [release](https://github.com/dermotduffy/frigate-hass-card/releases) to a location accessible by Home Assistant. Note that the release will have a series of `.js` files (for HACS users) **and** a `frigate-hass-card.zip` for the convenience of manual installers. +- Unzip the file and move the contents of the `dist/` folder to any subfolder name you'd like, e.g. `frigate-card` is used in the below example. +- Add the location as a Lovelace resource via the UI, or via [YAML configuration](https://www.home-assistant.io/lovelace/dashboards/#resources) such as: + +```yaml +lovelace: + mode: yaml + resources: + - url: /local/frigate-card/frigate-hass-card.js + type: module +``` + +### Unreleased versions + +You can install any unreleased version of the card by leveraging the GitHub Actions artifacts that are generated on every revision. See a [video walkthrough](https://user-images.githubusercontent.com/29582865/228320074-6a2607f5-c637-48d5-b833-a553f8df8f4f.mp4) installing the latest revision of the `release-4.1.0` branch. \ No newline at end of file diff --git a/docs/configuration/README.md b/docs/configuration/README.md new file mode 100644 index 00000000..7104216b --- /dev/null +++ b/docs/configuration/README.md @@ -0,0 +1,43 @@ +# Configuration + +The card supports a myriad of configuration options for simple or complex setups. + +### Minimal configuration + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +``` + +### Configuration blocks + +#### Top-level configuration blocks + +Only the `cameras` option is required, all other parameters are optional. + +| Option | Description | +| - | - | +| [`automations`](automations.md) | Take action when conditions are met. | +| [`cameras`](cameras/README.md) | Configures the cameras to be used in the card. At least one camera must be specified. | +| [`cameras_global`](cameras/README.md) | Global defaults that apply to all cameras from the `cameras` section. | +| `card_id` | An optional ID to uniquely identify this card. For use when actions are being sent to card(s) via [URL actions](../usage/url-actions.md). Must exclusively consist of these characters: `[a-zA-Z0-9_]`.| +| [`dimensions`](dimensions.md) | Configures the overall card dimensions. | +| [`elements`](elements.md) | Add custom elements to the card. | +| [`image`](image.md) | Configures the `image` view. | +| [`live`](live.md) | Configures the `live` view. | +| [`media_gallery`](media-gallery.md) | Configures the media gallery. | +| [`media_viewer`](media-viewer.md) | Configures the media viewer. | +| [`menu`](menu.md) | Configures the card menu. | +| [`overrides`](overrides.md) | Override card configuration when conditions are met. | +| [`performance`](performance.md) | Configures the card performance. | +| [`profiles`](profiles.md) | Apply pre-configured sets of defaults to ease card configuration. | +| [`timeline`](timeline.md) | Configures the `timeline` view. | +| [`view`](view.md) | Configures the default view and behavior of the card. | + +#### Common configuration blocks + +| Option | Description | +| - | - | +| [`actions`](actions.md) | Configure actions. | +| [`conditions`](conditions.md) | Configure conditions. | diff --git a/docs/configuration/_sidebar.md b/docs/configuration/_sidebar.md new file mode 100644 index 00000000..c07b3bbb --- /dev/null +++ b/docs/configuration/_sidebar.md @@ -0,0 +1,26 @@ +* [Getting Started](../README.md) +* [Configuration](README.md) + * [`actions`](actions.md) + * [`automations`](automations.md) + * [`cameras`](cameras/README.md) + * [`conditions`](conditions.md) + * [`dimensions`](dimensions.md) + * [`elements`](elements.md) + * [`image`](image.md) + * [`live`](live.md) + * [`media_gallery`](media-gallery.md) + * [`media_viewer`](media-viewer.md) + * [`menu`](menu.md) + * [`overrides`](overrides.md) + * [`performance`](performance.md) + * [`profiles`](profiles.md) + * [`timeline`](timeline.md) + * [`view`](view.md) +* [Examples](../examples.md) +* [Screenshots](../screenshots.md) +* [Troubleshooting](../troubleshooting.md) +* [Usage](../usage/README.md) + +--- + +* [Developing](../developing.md) \ No newline at end of file diff --git a/docs/configuration/actions.md b/docs/configuration/actions.md new file mode 100644 index 00000000..2d0af42d --- /dev/null +++ b/docs/configuration/actions.md @@ -0,0 +1,521 @@ +# `actions` + +## Introduction to actions + +`actions` is not a top-level configuration block, but can be used as part of +multiple other blocks. + +Actions are pre-configured activities that can be triggered in response to a +variety of circumstances (e.g. tapping on a menu icon, double tapping on an +[element](./elements.md) or holding the mouse/tap down on a particular +[view](./view.md?id=supported-views)). + +### Differences in actions between Frigate Card and Home Assistant + +Both the Home Assistant frontend and the Frigate card cooperate to provide +action functionality. In general, the Frigate Card functionality is a superset +of that offered by stock Home Assistant. + +Stock action functionality is used for Stock [Home Assistant picture +elements](https://www.home-assistant.io/lovelace/picture-elements/). Extended +Frigate card behavior covers all other interactions on the Frigate card (e.g. +menu icon elements, submenus and actions on the card or views). + +#### Custom action types: `start_tap` and `end_tap` + +The card has partial support for two special action types `start_tap` and +`end_tap` which occur when a tap is started (e.g. mouse is pressed down / +touch begins), and ended (e.g. mouse released / touch ends) respectively. This +might be useful for PTZ cameras cameras to start/stop movement on touch. Network +latency may introduce unavoidable imprecision between `end_tap` and action +actually occurring. + +#### Multiple actions + +Extended Frigate card behavior supports a list of actions instead of a single +action, all of which will be handled. See [an example of multiple +actions](../examples.md?id=multiple-actions). + +## Card and view actions + +Actions may be attached to the card itself, to trigger action when the card +experiences a `tap`, `double_tap`, `hold`, `start_tap` or `end_tap` event. +Alternatively they can be configured on a per group-of-views basis, e.g. only +when `live` view is tapped. + +| Configuration path | Views to which it refers | +| - | - | +| `image.actions` | `image` | +| `live.actions` | `live` | +| `media_gallery.actions` | `clips`, `snapshots`, `recordings` | +| `media_viewer.actions` | `clip`, `snapshot`, `recording` | +| `view.actions` | All | + +If an action is configured for both the whole card (`view.actions`) and a more +specific view (e.g. `live.actions`) then the actions are merged, with the more +specific overriding the less specific. + +!> The card itself relies on user interactions to function (e.g. `tap` on +the menu should activate that button). Card or View actions are prevented from +being activated through standard interaction with menu buttons, next/previous +controls, thumbnails, etc, but in some cases this prevention is not possible +(e.g. embedded WebRTC card controls) -- in these cases duplicate actions may +occur with certain configurations (e.g. `tap`). + +!> Card-wide actions are not supported on timelines nor when a info/error message +is being displayed. + +## `call-service` + +Call a service. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). + +```yaml +action: call-service +[...] +``` + +## `custom:frigate-card-action` + +Execute a Frigate Card action. + +```yaml +action: custom:frigate-card-action +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | A supported Frigate Card action. See below. | + +### `camera_select` + +Select a given camera. + +```yaml +action: custom:frigate-card-action +frigate_card_action: camera_select +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `camera_select`. | +| `camera` | The [camera ID](cameras/README.md?id=cameras) of the camera to select. | +| `triggered` | If `true` instead of `camera` being specified then a triggered camera (if any) is selected instead. | + +This action will respect the value of the `view.camera_select` to choose the appropriate view on the new camera. See [`view` configuration](view.md). + +### `camera_ui` + +Download the displayed media. + +```yaml +action: custom:frigate-card-action +frigate_card_action: camera_ui +``` + +Open the UI for the selected camera engine (e.g. the Frigate UI). + +### `default` + +Change to the default view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: default +``` + +### `clip`, `clips`, `image`, `live`, `recording`, `recordings`, `snapshot`, `snapshots` + +Change to the specified view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: [view] +``` + +### `download` + +Download the displayed media. + +```yaml +action: custom:frigate-card-action +frigate_card_action: download +``` + +### `expand` + +Expand the card into a dialog/popup. + +```yaml +action: custom:frigate-card-action +frigate_card_action: expand +``` + +### `fullscreen` + +Toggle fullscreen. + +```yaml +action: custom:frigate-card-action +frigate_card_action: fullscreen +``` + +### `live_substream_select` + +Select a substream. + +```yaml +action: custom:frigate-card-action +frigate_card_action: live_substream_select +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `live_substream_select`. | +| `camera` | The [camera ID](cameras/README.md?id=cameras) of the substream to select. | + +### `media_player` + +Perform a media player action. + +```yaml +action: custom:frigate-card-action +frigate_card_action: media_player +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `media_player`. | +| `media_player` | The entity ID of the media_player on which to perform the action. | +| `media_player_action` | Either `play` or `stop` to play or stop the media in question. | + +### `menu_toggle` + +Show/hide the menu (for the `hidden` mode style). + +```yaml +action: custom:frigate-card-action +frigate_card_action: menu_toggle +``` + +### `microphone_mute`, `microphone_unmute` + +Mute/Unmute the microphone during [2-way audio](../usage/2-way-audio.md). + +```yaml +action: custom:frigate-card-action +frigate_card_action: microphone_mute +``` + +```yaml +action: custom:frigate-card-action +frigate_card_action: microphone_unmute +``` + +### `mute`, `unmute` + +Mute/Unmute the selected media. + +```yaml +action: custom:frigate-card-action +frigate_card_action: mute +``` + +```yaml +action: custom:frigate-card-action +frigate_card_action: unmute +``` + +### `play`, `pause` + +Play/Pause the selected media. + +```yaml +action: custom:frigate-card-action +frigate_card_action: play +``` + +```yaml +action: custom:frigate-card-action +frigate_card_action: pause +``` + +### `ptz` + +Execute a native PTZ action (only for native out-of-the-box PTZ camera engines, e.g. Frigate). + + Takes a required `ptz_action` parameter that is one of . + +```yaml +action: custom:frigate-card-action +frigate_card_action: ptz +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `ptz`. | +| `ptz_action` | One of `left`, `right`, `up`, `down`, `zoom_in`, `zoom_out` or `preset`. | +| `ptz_phase` | Optional parameter that is one of `start` or `stop` to start or stop the movement separately. | +| `ptz_preset` | Optional preset to execute when the `ptz_action` is `preset`. | + +### `screenshot` + +Take a screenshot of the selected media (e.g. a still from a video). + +```yaml +action: custom:frigate-card-action +frigate_card_action: screenshot +``` + +### `show_ptz` + +Show or hide the PTZ controls. + +```yaml +action: custom:frigate-card-action +frigate_card_action: show_ptz +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `show_ptz`. | +| `show_ptz` | If `true` shows the PTZ controls, if `false` hides them. | + +## `more-info` + +Open the "more-info" dialog for an entity. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). + +```yaml +action: more-info +[...] +``` + +## `navigate` + +Navigate to a particular dashboard path. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). + +```yaml +action: navigate +[...] +``` + +## `toggle` + +Toggle an entity. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). + +```yaml +action: toggle +[...] +``` + +## `url` + +Navigate to an arbitrary URL. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). + +```yaml +action: url +[...] +``` + +## Fully expanded reference + +[](common/expanded-warning.md ':include') + +### Stock Home Assistant actions + +Reference: [Home Assistant Actions](https://www.home-assistant.io/dashboards/actions/). + +```yaml +elements: + - type: icon + icon: mdi:numeric-1-box + title: More info action + style: + left: 200px + top: 50px + entity: light.office_main_lights + tap_action: + action: more-info + - type: icon + icon: mdi:numeric-2-box + title: Toggle action + style: + left: 200px + top: 100px + entity: light.office_main_lights + tap_action: + action: toggle + - type: icon + icon: mdi:numeric-3-box + title: Call Service action + style: + left: 200px + top: 150px + tap_action: + action: call-service + service: homeassistant.toggle + service_data: + entity_id: light.office_main_lights + - type: icon + icon: mdi:numeric-4-box + title: Navigate action + style: + left: 200px + top: 200px + tap_action: + action: navigate + navigation_path: /lovelace/2 + - type: icon + icon: mdi:numeric-5-box + title: URL action + style: + left: 200px + top: 250px + tap_action: + action: url + url_path: https://www.home-assistant.io/ + - type: icon + icon: mdi:numeric-6-box + title: None action + style: + left: 200px + top: 300px + tap_action: + action: none + - type: icon + icon: mdi:numeric-7-box + title: Custom action + style: + left: 200px + top: 350px + tap_action: + action: fire-dom-event + key: value +``` + +### Frigate Card actions + +```yaml +elements: + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-a-circle + title: Show default view + tap_action: + action: custom:frigate-card-action + frigate_card_action: default + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-b-circle + title: Show most recent clip + tap_action: + action: custom:frigate-card-action + frigate_card_action: clip + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-c-circle + title: Show clips + tap_action: + action: custom:frigate-card-action + frigate_card_action: clips + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-d-circle + title: Show image view + tap_action: + action: custom:frigate-card-action + frigate_card_action: image + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-e-circle + title: Show live view + tap_action: + action: custom:frigate-card-action + frigate_card_action: live + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-f-circle + title: Show most recent snapshot + tap_action: + action: custom:frigate-card-action + frigate_card_action: snapshot + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-g-circle + title: Show snapshots + tap_action: + action: custom:frigate-card-action + frigate_card_action: snapshots + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-h-circle + title: Download media + tap_action: + action: custom:frigate-card-action + frigate_card_action: download + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-i-circle + title: Open Frigate UI + tap_action: + action: custom:frigate-card-action + frigate_card_action: camera_ui + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-j-circle + title: Change to fullscreen + tap_action: + action: custom:frigate-card-action + frigate_card_action: fullscreen + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-k-circle + title: Toggle hidden menu + tap_action: + action: custom:frigate-card-action + frigate_card_action: menu_toggle + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-l-circle + title: Select Front Door + tap_action: + action: custom:frigate-card-action + frigate_card_action: camera_select + camera: camera.front_door + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-m-circle + title: Media player play + tap_action: + action: custom:frigate-card-action + frigate_card_action: media_player + media_player: media_player.nesthub50be + media_player_action: play + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-n-circle + title: Media player stop + tap_action: + action: custom:frigate-card-action + frigate_card_action: media_player + media_player: media_player.nesthub + media_player_action: stop + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-o-circle + title: Screenshot + tap_action: + action: custom:frigate-card-action + frigate_card_action: screenshot + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-p-circle + title: Show PTZ + tap_action: + action: custom:frigate-card-action + frigate_card_action: show_ptz + show_ptz: true + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-q-circle + title: Native PTZ Preset + tap_action: + action: custom:frigate-card-action + frigate_card_action: ptz + ptz_action: preset + ptz_preset: doorway +``` diff --git a/docs/configuration/automations.md b/docs/configuration/automations.md new file mode 100644 index 00000000..19580ab1 --- /dev/null +++ b/docs/configuration/automations.md @@ -0,0 +1,38 @@ +# `automations` + +Automatically take [actions](actions.md) based on [conditions](conditions.md) being met. + +?> To change configuration conditionally use [overrides](overrides.md). + +```yaml +automations: + - conditions: + - [condition] + actions: + - [action] + actions_not: + - [action] +``` + +| Option | Default | Description | +| - | - | - | +| `conditions` | | A list of [conditions](conditions.md) that must evaluate to `true` in order to trigger the automation. | +| `actions` | | An optional list of [actions](actions.md) that will be run when the [conditions](conditions.md) evaluate `true`. | +| `actions_not` | | An optional list of [actions](actions.md) that will be run when the [conditions](conditions.md) evaluate `false`. | + +# Fully expanded reference + +[](common/expanded-warning.md ':include') + +```yaml +automations: + - conditions: + - condition: fullscreen + fullscreen: true + actions: + - action: custom:frigate-card-action + frigate_card_action: live_substream_on + actions_not: + - action: custom:frigate-card-action + frigate_card_action: live_substream_off +``` diff --git a/docs/configuration/cameras/README.md b/docs/configuration/cameras/README.md new file mode 100644 index 00000000..1036071b --- /dev/null +++ b/docs/configuration/cameras/README.md @@ -0,0 +1,284 @@ +# Cameras + +The `cameras` block configures a list of cameras the card should support. The first listed camera is the default. + +```yaml +cameras: + - [...camera 0 (default camera)...] + - [...camera 1...] + - [...camera 2...] +``` + +The `cameras_global` block can be used to set defaults across multiple cameras. + +```yaml +cameras_global: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `camera_entity` | | The Home Assistant camera entity to use with the `frigate` live provider view. Also used to automatically detect the name of the underlying Frigate camera, and the title/icon of the camera. | +| `capabilities` | | Allows selective disabling of camera capabilities. See below. | +| `cast` | | Configuration that controls how this camera is "casted" / sent to media players. See below. | +| `dependencies` | | Other cameras that this camera should depend upon. See below. | +| `dimensions` | | Controls the dimensions and layout for media from this camera. See below. | +| `engine` | `auto` | The camera engine to use. If `auto` the card will attempt to choose the correct engine from the specified options. See [Engine](engine.md). | +| `frigate` | | Options for Frigate cameras. See [Frigate camera engine configuration](engine.md?id=frigate). | +| `icon` | Autodetected from `camera_entity` if that is specified. | The icon to use for this camera in the camera menu and in the next & previous controls when using the `icon` style. | +| `id` | `camera_entity`, `webrtc_card.entity` or `frigate.camera_name` if set (in that preference order). | An optional identifier to use throughout the card configuration to refer unambiguously to this camera. This `id` may be used in [conditions](../conditions.md), dependencies or custom [actions](../actions.md) to refer to a given camera unambiguously. | +| `live_provider` | `auto` | The choice of live stream provider. See [Live Provider](live-provider.md).| +| `title` | Autodetected from `camera_entity` if that is specified. | A friendly name for this camera to use in the card. | +| `triggers` | | Define what should cause this camera to update/trigger. See below. | +| `webrtc_card` | | The WebRTC entity/URL to use for this camera with the `webrtc-card` live provider. See below. | + +## `capabilities` + +The `capabilities` block allows selected disabling of auto-detected camera capabilities. This is rarely used, with substreams being a notable exception. + +```yaml +cameras: + - camera_entity: camera.office + capabilities: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `disable` | | A list of camera capabilities to disable. By default all capabilities supported by the camera are enabled. | +| `disable_except` | | A list of camera capabilities to leave enabled if supported. Everything else will be disabled. | + +### Capabilities + +| Capability | Purpose | +| - | - | +| `clips` | Clips can be fetched from the camera. | +| `favorite-events` | Events can be favorited. | +| `favorite-recordings` | Recordings can be favorited. | +| `live` | Live video can be received from the camera. | +| `menu` | The camera should show up in the card camera menu. | +| `ptz` | The camera can be PTZ controlled. | +| `recordings` | Recordings can be fetched from the camera. | +| `seek` | Clips can be seeked / scrubbed by the timeline. | +| `snapshots` | Snapshots can be fetched from the camera. | +| `substream` | The camera can be used as a substream on another camera. | + +## `cast` + +The `cast` block configures how a camera is cast / sent to media players. + +```yaml +cameras: + - camera_entity: camera.office + cast: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `dashboard` | | Configuration for the dashboard to cast. See below. | +| `method` | `standard` | Whether to use `standard` media casting to send the live view to your media player, or to instead cast a `dashboard` you have manually setup. Casting a dashboard supports a much wider variety of video media, including low latency video providers (e.g. `go2rtc`). This setting has no effect on casting non-live media. | + +See the [dashboard method cast example](../../examples.md?id=cast-a-dashboard). + +### Dashboard Configuration + +```yaml +cameras: + - camera_entity: camera.office + cast: + dashboard: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `dashboard_path` | | A required field that specifies the name of the dashboard to cast. You can see this name in your HA URL when you visit the dashboard. | +| `view_path` | | A required field that specifies view/"tab" on that dashboard to cast. This is the value you have specified in the `url` field of the view configuration on the dashboard. | + +## `dependencies` + +The `dependencies` block configures other cameras as dependents of this camera. Dependent cameras have their media fetched and merged with this camera by default, and offer their respective live views as 'substreams' of the main (depended upon) camera. Configuration is under: + +```yaml +cameras: + - camera_entity: camera.office + dependencies: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `all_cameras` | `false` | Shortcut to specify all other cameras as dependent cameras. | +| `cameras` | | An optional list of other camera identifiers (see `id` parameter). If specified the card will fetch media for this camera and *also* recursively for the named cameras by default. Live views for the involved cameras will be available as 'substreams' of the main (depended upon) camera. All dependent cameras must themselves be a configured camera in the card. This can be useful to group events for cameras that are close together, to show multiple related live views, to always have clips/snapshots show fully merged events across all cameras or to show events for the `birdseye` camera that otherwise would not have events itself. | + +## `dimensions` + +The `dimensions` block configures the dimensions and layout of media of a given camera. + +```yaml +cameras: + - camera_entity: camera.office + dimensions: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `aspect_ratio` | | An optional aspect ratio for media from this camera which will be used in `live` or media viewer related views (e.g. `clip`, `snapshot` and `recording`). Format is the same as the parameter of the same name under the [dimensions block](../dimensions.md) (which controls dimensions for the whole card), e.g. `16 / 9`. | +| `layout` | | How the media should be laid out *within* the camera dimensions. See below. | + +### Layout Configuration + +The `layout` block configures the fit and position of the media _within_ the camera dimensions (in order to control the dimensions for the whole card see [the card dimensions configuration](../dimensions.md) ). As the default behavior is to always expand to fit the media precisely, these options only make sense if the camera `dimensions.aspect_ratio` is set to a static value that forces a particular aspect ratio that does not match the camera media. + + +```yaml +cameras: + - camera_entity: camera.office + dimensions: + layout: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `fit` | `contain` | If `contain`, the media is contained within the card and letterboxed if necessary. If `cover`, the media is expanded proportionally (i.e. maintaining the media aspect ratio) until the card is fully covered. If `fill`, the media is stretched to fill the card (i.e. ignoring the media aspect ratio). See [CSS object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) for technical details and a visualization. | +| `position` | | A dictionary that contains an `x` and `y` percentage (`0` - `100`) to control the position of the media when the fit is `cover`. This can be effectively used to "pan" the media around. At any given time, only one of `x` and `y` will have an effect, depending on whether media width is larger than the card width (in which case `x` controls the position) or the media height is larger than the card height (in which case `y` controls the position). A value of `0` means maximally to the left or top of the media, a value of `100` means maximally to the right or bottom of the media. See [CSS object-position](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) for technical details and a visualization. | + +See [media layout examples](../../examples.md?id=media-layout). + +## `triggers` + +The `triggers` block configures what triggers a camera. Triggering can be used +to activate an action (e.g. view a camera in live, reset the card to the default +view). See [`view.triggers`](../view.md?id=triggers) to control what happens when a +camera is triggered. + +```yaml +cameras: + - camera_entity: camera.office + triggers: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `entities` | | Whether to not to trigger the camera when the state of any Home Assistant entity becomes active (i.e. state becomes `on` or `open`). This works for Frigate or non-Frigate cameras.| +| `events` | `[events, clips, snapshots]` | Whether to trigger the camera when `events` occur (whether or not media is available) or whenever updated `clips` or `snapshots` are detected. Detection support varies by camera [engine](engine.md). | +| `motion` | `false` | Whether to not to trigger the camera by automatically detecting and using the motion `binary_sensor` for this camera. This autodetection only works for Frigate cameras, and only when the motion `binary_sensor` entity has been enabled in Home Assistant.| +| `occupancy` | `false` | Whether to not to trigger the camera by automatically detecting and using the occupancy `binary_sensor` for this camera and its configured zones and labels. This autodetection only works for Frigate cameras, and only when the occupancy `binary_sensor` entity has been enabled in Home Assistant. If this camera has configured zones, only occupancy sensors for those zones are used -- if the overall _camera_ occupancy sensor is also required, it can be manually added to `entities`. If this camera has configured labels, only occupancy sensors for those labels are used. | + +## Fully expanded reference + +[](../common/expanded-warning.md ':include') + +```yaml +cameras: + - camera_entity: camera.front_Door + live_provider: ha + engine: auto + frigate: + url: http://my.frigate.local + client_id: frigate + camera_name: front_door + labels: + - person + zones: + - steps + # Show events for camera-2 when this camera is viewed. + dependencies: + all_cameras: false + cameras: + - camera-2 + triggers: + motion: false + occupancy: true + entities: + - binary_sensor.front_door_sensor + cast: + method: standard + dimensions: + aspect_ratio: 16:9 + layout: + fit: contain + position: + x: 50 + y: 50 + - camera_entity: camera.entrance + live_provider: webrtc-card + engine: auto + frigate: + url: http://my-other.frigate.local + client_id: frigate-other + camera_name: entrance + labels: + - car + zones: + - driveway + icon: 'mdi:car' + title: 'Front entrance' + # Custom identifier for the camera to refer to it above. + id: 'camera-2' + webrtc_card: + entity: camera.entrance_rtsp + url: 'rtsp://username:password@camera:554/av_stream/ch0' + triggers: + motion: false + occupancy: true + entities: + - binary_sensor.entrance_sensor + dependencies: + all_cameras: false + - camera_entity: camera.sitting_room + live_provider: go2rtc + go2rtc: + modes: + - webrtc + - mse + - mp4 + - mjpeg + stream: sitting_room + url: 'https://my.custom.go2rtc.backend' + cast: + method: dashboard + dashboard: + dashboard_path: cast + view_path: front-door + - camera_entity: camera.sitting_room_webrtc_card + live_provider: webrtc_card + webrtc_card: + # Arbitrary WebRTC Card options, see https://github.com/AlexxIT/WebRTC#configuration . + entity: camera.sitting_room_rtsp + ui: true + - camera_entity: camera.kitchen + live_provider: jsmpeg + jsmpeg: + options: + audio: false + video: true + pauseWhenHidden: false + disableGl: false + disableWebAssembly: false + preserveDrawingBuffer: false + progressive: true + throttled: true + chunkSize: 1048576 + maxAudioLag: 10 + videoBufferSize: 524288 + audioBufferSize: 131072 + - camera_entity: camera.back_yard + live_provider: image + image: + refresh_seconds: 1 + - camera_entity: camera.office_motioneye + motioneye: + images: + directory_pattern: '%Y-%m-%d' + file_pattern: '%H-%M-%S' + movies: + directory_pattern: '%Y-%m-%d' + file_pattern: '%H-%M-%S' +cameras_global: + live_provider: ha +``` diff --git a/docs/configuration/cameras/_sidebar.md b/docs/configuration/cameras/_sidebar.md new file mode 100644 index 00000000..07620600 --- /dev/null +++ b/docs/configuration/cameras/_sidebar.md @@ -0,0 +1,27 @@ +* [Getting Started](../../README.md) +* [Configuration](../README.md) + * [`actions`](../actions.md) + * [`automations`](../automations.md) + * [`cameras`](README.md) + * [`live_provider`](live-provider.md) + * [`engine`](engine.md) + * [`conditions`](../conditions.md) + * [`dimensions`](../dimensions.md) + * [`elements`](../elements.md) + * [`image`](../image.md) + * [`live`](../live.md) + * [`media_gallery`](../media-gallery.md) + * [`media_viewer`](../media-viewer.md) + * [`menu`](../menu.md) + * [`overrides`](../overrides.md) + * [`performance`](../performance.md) + * [`profiles`](../profiles.md) + * [`timeline`](../timeline.md) + * [`view`](../view.md) +* [Screenshots](../../screenshots.md) +* [Troubleshooting](../../troubleshooting.md) +* [Usage](../../usage/README.md) + +--- + +* [Developing](../../developing.md) \ No newline at end of file diff --git a/docs/configuration/cameras/engine.md b/docs/configuration/cameras/engine.md new file mode 100644 index 00000000..b5fb173e --- /dev/null +++ b/docs/configuration/cameras/engine.md @@ -0,0 +1,82 @@ +# `engine` + +## Overview + +A "Camera Engine" defines what "type" of camera is being configured (e.g. `frigate`), each engine offers different capabilities: + +|Engine|Live|Supports clips|Supports Snapshots|Supports Recordings|Supports Timeline|Supports PTZ out of the box|Supports manually configured PTZ|Favorite events|Favorite recordings|Detect new events|Detect new snapshots|Detect new clips| +| - | - | - | - | - | - | - | - | - | - | - | - | - | +|`frigate`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +|`generic`| :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | +|`motioneye`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | + +#### Live providers supported per Engine + +|Engine / Live Provider|`ha`|`image`|`jsmpeg`|`go2rtc`|`webrtc-card`| +| - | - | - | - | - | - | +|`frigate`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +|`generic`| :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :white_check_mark: | +|`motioneye`| :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | + +See [Live Provider Configuration](live-provider.md) for more details on live providers. + +## `frigate` + +The `frigate` block configures options for a Frigate camera. + +```yaml +cameras: + - camera_entity: camera.office + frigate: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `camera_name` | Autodetected from `camera_entity` if that is specified. | The Frigate camera name to use when communicating with the Frigate server, e.g. for viewing clips/snapshots or the JSMPEG live view.| +| `client_id` | `frigate` | The Frigate client id to use. If this Home Assistant server has multiple Frigate server backends configured, this selects which server should be used. It should be set to the MQTT client id configured for this server, see [Frigate Integration Multiple Instance Support](https://docs.frigate.video/integrations/home-assistant/#multiple-instance-support).| +| `labels` | | A list of Frigate labels used to filter events (clips & snapshots), e.g. [`person`, `car`].| +| `url` | | The URL of the frigate server. If set, this value will be (exclusively) used for a `Camera UI` menu button. All other communication with Frigate goes via Home Assistant. | +| `zones` | | A list of Frigates zones used to filter events (clips & snapshots), e.g. [`front_door`, `front_steps`].| + +## `motioneye` + +The `motioneye` block configures options for a MotionEye camera. + +```yaml +cameras: + - camera_entity: camera.office + motioneye: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `images` | | Configure how MotionEye images are consumed. See below. | +| `movies` | | Configure how MotionEye movies are consumed. See below. | +| `url` | | The URL of the MotionEye server. If set, this value will be (exclusively) used for a `Camera UI` menu button. | + +### `images` / `movies` + +The `images` and `movies` block configures how images and movies respectively are fetched from motionEye. The options for both blocks are the same. + +```yaml +cameras: + - camera_entity: camera.office + motioneye: + images: + [...] +``` + +```yaml +cameras: + - camera_entity: camera.office + motioneye: + movies: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `directory_pattern` | `%Y-%m-%d` | The directory that motionEye is configured to store media into. May contain multiple sub-directories separated by `/`. Path must encode the date of the media using MotionEye patterns such as `%Y`, `%m`, `%d`, `%H`, `%M`, `%S` (at least one pattern is required). Consult MotionEye help text for information on these substitutions. | +| `file_pattern` | `%H-%M-%S` | Within a directory (as matched by `directory_pattern`) the media items must exist and match this pattern. `file_pattern` must encode the time of the media using MotionEye patterns such as `%Y`, `%m`, `%d`, `%H`, `%M`, `%S` (at least one pattern is required). Consult MotionEye help text for information on these substitutions. | diff --git a/docs/configuration/cameras/live-provider.md b/docs/configuration/cameras/live-provider.md new file mode 100644 index 00000000..b775e3b6 --- /dev/null +++ b/docs/configuration/cameras/live-provider.md @@ -0,0 +1,86 @@ +# `live_provider` + +## Overview + +The `live_provider` parameter determines what provides the live stream for a camera. Each provider offers different capabilities: + +|Live Provider|Latency|Frame Rate|Loading Time|Installation|Description| +| -- | -- | -- | -- | -- | -- | +|`go2rtc`|Best|High|Better|Builtin|Uses [go2rtc](https://github.com/AlexxIT/go2rtc) to stream live feeds. This is supported by Frigate >= `0.12`. | +|`ha` (default HA configuration)|Poor|High|Better|Builtin|Use the built-in Home Assistant camera stream. The camera doesn't even need to be a Frigate camera! | +|`ha` (Native WebRTC)|Best|High|Better|Builtin|Use the built-in Home Assistant camera streams -- can be configured to use [native WebRTC](https://www.home-assistant.io/integrations/rtsp_to_webrtc/) offering a very low-latency feed direct to your browser. | +|`ha` (when configured with LL-HLS)|Better|High|Better|Builtin|Use the built-in Home Assistant camera streams -- can be configured to use an [LL-HLS](https://www.home-assistant.io/integrations/stream/#ll-hls) feed for lower latency. | +|`image`|Poor|Poor|Best|Builtin|Use refreshing snapshots of the built-in Home Assistant camera streams.| +|`jsmpeg`|Better|Low|Poor|Builtin|Use a the JSMPEG stream. | +|`webrtc-card`|Best|High|Better|Separate installation required|Embed's [AlexxIT's WebRTC Card](https://github.com/AlexxIT/WebRTC) to stream live feed, requires manual extra setup. See below. Not to be confused with native Home Assistant WebRTC (use the `ha` provider). | + +## `go2rtc` + +The `go2rtc` block configures use of the `go2rtc` live provider. This configuration is included as part of a camera entry in the `cameras` list. + +```yaml +cameras: + - camera_entity: camera.office + live_provider: go2rtc + go2rtc: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `modes` | `[webrtc, mse, mp4, mjpeg]` | An ordered list of `go2rtc` modes to use. Valid values are `webrtc`, `mse`, `mp4` or `mjpeg` values. | +| `stream` | Determined by camera engine (e.g. `frigate` camera name). | A valid `go2rtc` stream name. | +| `url` | Determined by camera engine (e.g. the `frigate` engine will automatically generate a URL for the go2rtc backend that runs in the Frigate container). | The root `go2rtc` URL the card should stream the video from. This is only needed for non-Frigate usecases, or advanced Frigate usecases. Example: `http://my-custom-go2rtc:1984` | + +## `image` + +All configuration is under: + +```yaml +cameras: + - camera_entity: camera.office + live_provider: image + image: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `refresh_seconds` | 1 | The image will be refreshed at least every `refresh_seconds`. `0` implies no refreshing. | +| `url` | | **Advanced**: A static image URL to be fetched in lieu of the Home Assistant image for the given camera. This may be useful for advanced configurations where the camera image is being provided by some non-Home Assistant system. This will also set the temporary loading image used when `show_image_during_load` is set to true under the `live` configuration. | + +## `jsmpeg` + +All configuration is under: + +```yaml +cameras: + - camera_entity: camera.office + live_provider: jsmpeg + jsmpeg: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `options` | | **Advanced users only**: Control the underlying [JSMPEG library options](https://github.com/phoboslab/jsmpeg#usage). Supports setting these JSMPEG options `{audio, video, pauseWhenHidden, disableGl, disableWebAssembly, preserveDrawingBuffer, progressive, throttled, chunkSize, maxAudioLag, videoBufferSize, audioBufferSize}`. This is not necessary for the vast majority of users: only set these flags if you know what you're doing, as you may entirely break video rendering in the card.| + +## `webrtc_card` + +WebRTC Card support blends the use of the ultra-realtime [WebRTC card live +view](https://github.com/AlexxIT/WebRTC) with convenient access to Frigate +events/snapshots/UI. AlexxIT's WebRTC Integration/Card must be installed and configured separately (see [details](https://github.com/AlexxIT/WebRTC)) before it can be used with this card. + +```yaml +cameras: + - camera_entity: camera.office + live_provider: webrtc-card + webrtc_card: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `entity` | | The RTSP camera entity to pass to the WebRTC Card for this camera. | +| `url` | Depends on the camera engine (e.g. Frigate cameras will automatically use the camera name since this is the [recommended setup](https://deploy-preview-4055--frigate-docs.netlify.app/guides/configuring_go2rtc/)). | The RTSP url to pass to the WebRTC Card, e.g. `rtsp://USERNAME:PASSWORD@CAMERA:554/RTSP_PATH` | +| `*`| | Any options specified in the `webrtc_card:` YAML dictionary are silently passed through to the AlexxIT's WebRTC Card. See [WebRTC Configuration](https://github.com/AlexxIT/WebRTC#configuration) for full details this external card provides, e.g. `ui: true` will enable the WebRTC Card UI. | diff --git a/docs/configuration/common/expanded-warning.md b/docs/configuration/common/expanded-warning.md new file mode 100644 index 00000000..ba915b1c --- /dev/null +++ b/docs/configuration/common/expanded-warning.md @@ -0,0 +1 @@ +!> Just copying this full reference into your configuration will cause you a significant maintenance burden. Don't do it! Only specify what you need, everything shown here are either default or illustrative values. \ No newline at end of file diff --git a/docs/configuration/common/timeline-seek-info.md b/docs/configuration/common/timeline-seek-info.md new file mode 100644 index 00000000..f184386b --- /dev/null +++ b/docs/configuration/common/timeline-seek-info.md @@ -0,0 +1,4 @@ +?> For optimal UX, keep the settings for the mini-timeline in the `live` and +`media_viewer` identical. Dragging the timeline may cause the card to change +between the `live` view and `media_viewer` based views as the user pans between +the past and present -- if the settings are different the timeline must "reset". \ No newline at end of file diff --git a/docs/configuration/conditions.md b/docs/configuration/conditions.md new file mode 100644 index 00000000..23620cf2 --- /dev/null +++ b/docs/configuration/conditions.md @@ -0,0 +1,206 @@ +# `conditions` + +`conditions` is not a top-level configuration block, but can be used as part of +multiple other blocks. + +Conditions are used to conditionally take action (in `automations`), to apply +certain configurations (in `overrides`) or to display "picture elements" (in +`elements`) depending on runtime evaluation. + +```yaml +[used as part of other configuration] + conditions: + - [condition_1] + - [condition_2] +``` + +## `camera` + +```yaml +conditions: + - condition: camera + [...] +``` + +| Parameter | Description | +| - | - | +| `condition` | Must be `camera`. | +| `cameras` | A list of camera IDs in which this condition is satisfied. See the camera [id](cameras/README.md) parameter. | + +## `expand` + +```yaml +conditions: + - condition: expand + [...] +``` + +| Parameter | Description | +| - | - | +| `condition` | Must be `expand`. | +| `expand` | If `true` the condition is satisfied if the card is in expanded mode (in a dialog/popup). If `false` the condition is satisfied if the card is **NOT** in expanded mode (in a dialog/popup). | + +## `fullscreen` + +```yaml +conditions: + - condition: fullscreen + [...] +``` + +| Parameter | Description | +| - | - | +| `condition` | Must be `fullscreen`. | +| `fullscreen` | If `true` the condition is satisfied if the card is in fullscreen mode. If `false` the condition is satisfied if the card is **NOT** in fullscreen mode. | + +## `interaction` + +```yaml +conditions: + - condition: interaction + [...] +``` + +| Parameter | Description | +| - | - | +| `condition` | Must be `interaction`. | +| `interaction` | If `true` the condition is satisfied if the card has had human interaction within `view.interaction_seconds` elapsed seconds. If `false` the condition is satisfied if the card has **NOT** had human interaction in that time. | + +## `media_loaded` + +```yaml +conditions: + - condition: media_loaded + [...] +``` + +| Parameter | Description | +| - | - | +| `condition` | Must be `media_loaded`. | +| `media_loaded` | If `true` the condition is satisfied if there is media load**ED** (not load**ING**) in the card (e.g. a clip, snapshot or live view). This may be used to hide controls during media loading or when a message (not media) is being displayed. Note that if `true` this + +## `microphone` + +```yaml +conditions: + - condition: microphone + [...] +``` + +| Parameter | Description | +| - | - | +| `condition` | Must be `microphone`. | +| `connected` | Optional: If `true` or `false` the condition is satisfied if the microphone is connected or disconnected respectively. | +| `muted` | Optional: If `true` or `false` the condition is satisfied if the microphone is muted or unmuted respectively. | + +## `numeric_state` + +```yaml +conditions: + - condition: numeric_state + [...] +``` + +This stock Home Assistant condition works out of the box. See [Home Assistant conditions documentation](https://www.home-assistant.io/dashboards/conditional/#numeric-state). + +## `screen` + +```yaml +conditions: + - condition: screen + [...] +``` + +| Parameter | Description | +| - | - | +| `condition` | Must be `screen`. | +| `media_query` | Any valid [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries) string. Media queries must start and end with parentheses. This may be used to alter card configuration based on device/media properties (e.g. viewport width, orientation). Please note that `width` and `height` refer to the entire viewport not just the card. | + +See the [screen conditions examples](../examples.md?id=screen-conditions). + +## `state` + +```yaml +conditions: + - condition: state + [...] +``` + +This stock Home Assistant condition works out of the box. See [Home Assistant conditions documentation](https://www.home-assistant.io/dashboards/conditional/#state). + +## `triggered` + +```yaml +conditions: + - condition: triggered + [...] +``` + +| Parameter | Description | +| - | - | +| `condition` | Must be `triggered`. | +| `triggered` | A list of camera IDs which, if [triggered](cameras/README.md?id=triggers), satisfy the condition. | + +## `user` + +```yaml +conditions: + - condition: user + [...] +``` + +This stock Home Assistant condition works out of the box. See [Home Assistant conditions documentation](https://www.home-assistant.io/dashboards/conditional/#user). + +## `view` + +```yaml +conditions: + - condition: view + [...] +``` + +| Parameter | Description | +| - | - | +| `condition` | Must be `view`. | +| `views` | A list of [views](view.md?id=supported-views) in which this condition is satified (e.g. `clips`). | + +# Fully expanded reference + +[](common/expanded-warning.md ':include') + +```yaml +conditions: + - condition: camera + cameras: + - camera.office + - condition: expand + expand: true + - condition: fullscreen + fullscreen: true + - condition: interaction + interaction: true + - condition: media_loaded + media_loaded: true + - condition: microphone + connected: true + muted: true + - condition: numeric_state + entity: sensor.office_temperature + above: 10 + below: 20 + - condition: screen + media_query: '(orientation: landscape)' + - condition: state + entity: climate.office + state: heat + state_not: off + - condition: triggered + triggered: + - camera.office + - condition: user + users: + - 581fca7fdc014b8b894519cc531f9a04 + - condition: view + views: + - live +``` diff --git a/docs/configuration/dimensions.md b/docs/configuration/dimensions.md new file mode 100644 index 00000000..2e60fdd8 --- /dev/null +++ b/docs/configuration/dimensions.md @@ -0,0 +1,45 @@ +# `dimensions` + +These options control the dimensions and aspect-ratio of the card. These options +configuration applies once to the entire card (including the menu, thumbnails, +etc), not just to displayed media. This only applies to the card in normal +render mode -- when in fullscreen, or when in expanded (popup/dialog mode) the +aspect ratio is chosen dynamically to maximize the amount of content shown. + +```yaml +dimensions: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `aspect_ratio_mode` | `dynamic` | The aspect ratio mode to use. Acceptable values: `dynamic`, `static`, `unconstrained`. See below. | +| `aspect_ratio` | `16:9` | The aspect ratio to use. Acceptable values: `[W]:[H]` or `[W]/[H]`. See below. | +| `max_height` | `100vh` | The maximum allowable height for the card. Specified in [CSS units](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units). Generally users should not need to change this setting unless they have set an `unconstrained` aspect ratio. | +| `min_height` | `100px` | The minimum allowable height for the card. Specified in [CSS units](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units). Generally users should not need to change this setting. | + +### `aspect_ratio_mode` + +| Option | Description | +| - | - | +| `dynamic` | The aspect-ratio of the entire card will match the aspect-ratio of the last selected media item. | +| `static` | A fixed aspect-ratio (as defined by `aspect_ratio`) will be applied to the card. | +| `unconstrained` | No aspect ratio is enforced in any view, the card will expand with the content. This may be especially useful for a panel-mode dashboard, or in views that have no intrinsic aspect-ratio (e.g. the media gallery). | + +### `aspect_ratio` + +* `16 / 9` or `16:9`: Default widescreen ratio. +* `4 / 3` or `4:3`: Default fullscreen ratio. +* `[W]/[H]` or `[W]:[H]`: Any arbitrary aspect-ratio. + +## Fully expanded reference + +[](common/expanded-warning.md ':include') + +```yaml +dimensions: + aspect_ratio_mode: dynamic + aspect_ratio: 16:9 + max_height: 100vh + min_height: 100px +``` diff --git a/docs/configuration/elements.md b/docs/configuration/elements.md new file mode 100644 index 00000000..c98e48ef --- /dev/null +++ b/docs/configuration/elements.md @@ -0,0 +1,356 @@ +# `elements` + +This card supports the [Picture Elements configuration +syntax](https://www.home-assistant.io/lovelace/picture-elements/) to seamlessly +allow the user to add custom elements to the card. + +```yaml +elements: + - [element_1] + - [element_2] +``` + +?> The Frigate Card allows either a single [action](actions.md) (as in stock Home +Assistant) or list of [actions](actions.md) to be defined for each class of user interaction +(e.g. `tap`, `double_tap`, `hold`, etc). See [an example of multiple actions](../examples.md?id=multiple-actions). + +## `conditional` + +This element will let you show its sub-elements based on entity states. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#conditional-element). + +```yaml +elements: + - type: conditional + [...] +``` + +## `custom` + +Custom elements provided by a card. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#custom-elements). + +```yaml +elements: + - type: custom + [...] +``` + +## `custom:frigate-card-menu-icon` + +Add an arbitrary icon to the Frigate Card menu. Configuration is ~identical to that of the [Picture Elements Icon](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) except with a type name of `custom:frigate-card-menu-icon`. + +```yaml +elements: + - type: custom:frigate-card-menu-icon + [...] +``` + +## `custom:frigate-card-menu-state-icon` + +Add a state icon to the Frigate Card menu that represents the state of a Home Assistant entity. Configuration is ~identical to that of the [Picture Elements State Icon](https://www.home-assistant.io/lovelace/picture-elements/#state-icon) except with a type name of `custom:frigate-card-menu-state-icon`. + +```yaml +elements: + - type: custom:frigate-card-menu-icon + [...] +``` + +## `custom:frigate-card-menu-submenu` + +Add a configurable submenu dropdown. + +```yaml +elements: + - type: custom:frigate-card-menu-submenu + [...] +``` + +Parameters for this element are identical to the parameters of the [stock Home Assistant Icon Element](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) with the exception of these parameters which differ: + +| Parameter | Description | +| - | - | +| `type` | Must be `custom:frigate-card-menu-submenu`. | +| `items` | A list of menu items, as described below. | + +### Submenu items + +| Parameter | Default | Description | +| - | - | - | +| `enabled` | `true` | Whether or not to show this item as enabled / selectable. | +| `entity` | | An optional Home Assistant entity from which title, icon and style can be automatically computed. | +| `icon` | | An optional item icon to display, e.g. `mdi:car` | +| `selected` | `false` | Whether or not to show this item as selected. | +| `state_color` | `true` | Whether or not the title and icon should be stylized based on state. | +| `style` | | Position and style the element using CSS. | +| `tap_action`, `double_tap_action`, `hold_action`, `start_tap`, `end_tap` | | The [actions](actions.md) to take when this item is interacted with. | +| `title` | | An optional title to display. | + +## `custom:frigate-card-menu-submenu-select` + +Add a submenu based on a `select` or `input_select`. This element allows you to convert a [Home Assistant Select Entity](https://www.home-assistant.io/integrations/select/) or [Home Assistant Input Select Entity](https://www.home-assistant.io/integrations/input_select/) (an entity either starting with `select` or `input_select`) into an overridable submenu. This *could* be done by hand using a regular submenu (above) -- this element is a convenience. + +```yaml +elements: + - type: custom:frigate-card-menu-submenu-select + [...] +``` + +Parameters for the `custom:frigate-card-menu-submenu-select` element are identical to the parameters of the [stock Home Assistant State Icon Element](https://www.home-assistant.io/dashboards/picture-elements/#state-icon) with the exception of these parameters which differ: + +| Parameter | Description | +| - | - | +| `type` | Must be `custom:frigate-card-menu-submenu-select`. | +| `options` | An optional dictionary of overrides keyed by the option name that the given select entity supports. These options can be used to set or override submenu item parameters on a per-option basis. The format is as described in [Submenu Items](elements.md?id=submenu-items) above. | + +See the `select` [submenu example](../examples.md?id=select-submenu). + +## `custom:frigate-card-conditional` + +Restrict a set of elements to only render when the card is matches a set of [conditions](conditions.md). This is analogous to [`conditional`](elements.md?id=conditional) element above, except supporting a rich set of Frigate Card [conditions](conditions.md). + +```yaml +elements: + - type: custom:frigate-card-conditional + [...] +``` + +Parameters for the `custom:frigate-card-conditional` element: + +| Parameter | Description | +| - | - | +| `type` | Must be `custom:frigate-card-conditional`. | +| `conditions` | A list of [conditions](conditions.md) that must evaluate to true in order for the elements to be rendered. | +| `elements` | The elements to render. Can be any supported element. | + +See the [conditional elements example](../examples.md?id=conditional-elements). + +## `icon` + +This element creates a static icon that is not linked to the state of an entity. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#icon-element). + +```yaml +elements: + - type: icon + [...] +``` + +## `image` + +This creates an image element that overlays the background image. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#image-element). + +```yaml +elements: + - type: image + [...] +``` + +## `service-button` + +This entity creates a button (with arbitrary text) that can be used to call a service. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#service-call-button). + +```yaml +elements: + - type: service-button + [...] +``` + +## `state-badge` + +This element creates a badge representing the state of an entity. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#state-badge). + +```yaml +elements: + - type: state-badge + [...] +``` + +## `state-icon` + +This element represents an entity state using an icon. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#state-icon). + +```yaml +elements: + - type: state-icon + [...] +``` + +## `state-label` + +This element represents an entity’s state via text. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#state-label). + +```yaml +elements: + - type: state-label + [...] +``` + +## Fully expanded reference + +> [Actions](actions.md) are omitted for simplicity. + +[](common/expanded-warning.md ':include') + +### Stock Home Assistant elements + +Reference: [Home Assistant Picture Elements](https://www.home-assistant.io/dashboards/picture-elements/) + +```yaml +elements: + - type: state-badge + entity: sensor.kitchen_dining_multisensor_air_temperature + style: + left: 100px + top: 50px + title: "Temperature" + - type: state-icon + entity: light.office_main_lights + icon: mdi:lamp + state_color: true + style: + left: 100px + top: 100px + - type: state-label + entity: sensor.kitchen_motion_sensor_battery + attribute: battery_voltage + prefix: Volts + title: Battery Voltage + style: + left: 100px + top: 150px + - type: state-label + entity: sensor.kitchen_motion_sensor_battery + attribute: battery_voltage + prefix: 'Volts: ' + title: Battery Voltage + style: + background-color: black + left: 100px + top: 200px + - type: service-button + title: Light on + service: homeassistant.turn_on + service_data: + entity: light.office_main_lights + style: + left: 100px + top: 250px + - type: icon + icon: mdi:cow + title: Moo + style: + left: 100px + top: 300px + - type: image + entity: light.office_main_lights + title: Image + state_image: + on: "https://picsum.photos/id/1003/1181/1772" + off: "https://picsum.photos/id/102/4320/3240" + state_filter: + "on": brightness(110%) saturate(1.2) + "off": brightness(50%) hue-rotate(45deg) + style: + left: 100px + top: 350px + height: 50px + width: 100px + - type: conditional + conditions: + - condition: state + entity: light.office_main_lights + state: on + state_not: off + - condition: numeric_state + entity: sensor.light_level + above: 20 + below: 100 + - condition: user + users: + - 581fca7fdc014b8b894519cc531f9a04 + elements: + - type: icon + icon: mdi:dog + title: Woof + style: + left: 100px + top: 400px +``` + +### Frigate Card elements + +```yaml +elements: + - type: custom:frigate-card-menu-icon + icon: mdi:car + title: Vroom + - type: custom:frigate-card-menu-state-icon + entity: light.office_main_lights + title: Office lights + icon: mdi:chair-rolling + state_color: true + - type: custom:frigate-card-menu-submenu + icon: mdi:menu + items: + - title: Lights + icon: mdi:lightbulb + entity: light.office_main_lights + tap_action: + action: toggle + - title: Google + icon: mdi:google + enabled: false + tap_action: + action: url + url_path: https://www.google.com + - type: custom:frigate-card-menu-submenu-select + icon: mdi:lamps + entity: input_select.kitchen_scene + options: + scene.kitchen_cooking_scene: + icon: mdi:chef-hat + title: Cooking time! + scene.kitchen_tv_scene: + icon: mdi:television + title: TV! + # Show a pig icon if a variety of conditions are met. + - type: custom:frigate-card-conditional + elements: + - type: icon + icon: mdi:pig + title: Oink + style: + left: 300px + top: 100px + conditions: + - condition: view + views: + - live + - condition: fullscreen + fullscreen: true + - condition: expand + expand: true + - condition: camera + cameras: camera.front_door + - condition: media_loaded + media_loaded: true + - condition: display_mode + display_mode: single + - condition: triggered + triggered: + - camera.front_door + - condition: interaction + interaction: true + - condition: microphone + muted: true + connected: true + - condition: state + entity: light.office_main_lights + state: on + state_not: off + - condition: numeric_state + entity: sensor.light_level + above: 20 + below: 100 + - condition: user + users: + - 581fca7fdc014b8b894519cc531f9a04 +``` diff --git a/docs/configuration/grid-layout-algorithm.md b/docs/configuration/grid-layout-algorithm.md new file mode 100644 index 00000000..f870dc0d --- /dev/null +++ b/docs/configuration/grid-layout-algorithm.md @@ -0,0 +1,10 @@ +# Grid Layout Algorithm + +When display mode (in `live` or `media_viewer` views) is set to `grid`, it will lay out cameras roughly in the order they are specified in the config (items may be moved to optimize grid 'density'). + +The following algorithm is used to calculate the number of columns. This attempts to offers a balance between configurability, reasonable display in a typical Lovelace card width and reasonable display in a typical fullscreen display. + +- Use `grid_columns` if specified. +- Otherwise, use the largest number of columns in the range `[2 - grid_max_columns]` that will fit at least a `600px` column width. +- Otherwise, use the largest number of columns in the range `[2 - grid_max_columns]` that will fit at least a `190px` column width. +- Otherwise, there will be `1` column only. diff --git a/docs/configuration/image.md b/docs/configuration/image.md new file mode 100644 index 00000000..2800033d --- /dev/null +++ b/docs/configuration/image.md @@ -0,0 +1,41 @@ +# `image` + +Configure the `image` view. + +```yaml +image: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `actions` | | [Actions](actions.md) to use for the `image` view.| +| `mode` | `url` | Mode of the the `image` view. Value must be one of `url` (to fetch an arbitrary image URL), `camera` (to show a still of the currently selected camera using either `camera_entity` or `webrtc_card.entity` in that order of precedence), or `screensaver` (to show an [embedded stock Frigate card logo](https://github.com/dermotduffy/frigate-hass-card/blob/main/src/images/frigate-bird-in-sky.jpg)). In either `url` or `camera` mode, the `screensaver` content is used as a fallback if a URL is not specified or cannot be derived. | +| `refresh_seconds` | 0 | The image will be refreshed at least every `refresh_seconds` (it may refresh more frequently, e.g. whenever Home Assistant updates its camera security token). `0` implies no refreshing. | +| `url` | | A static image URL to be used when the `mode` is set to `url` or when a temporary image is required (e.g. may appear momentarily prior to load of a camera snapshot in the `camera` mode). Note that a `_t=[timestsamp]` query parameter will be automatically added to all URLs such that the image will not be cached by the browser. | +| `zoomable` | `true` | Whether or not the image can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | + +?> When `mode` is set to `camera` this is effectively providing the same image as the `image` [live provider](cameras/live-provider.md) would show in the live camera carousel. + +# Fully expanded reference + +[](common/expanded-warning.md ':include') + +```yaml +image: + mode: url + refresh_seconds: 0 + zoomable: true + actions: + entity: light.office_main_lights + tap_action: + action: none + hold_action: + action: none + double_tap_action: + action: none + start_tap_action: + action: none + end_tap_action: + action: none +``` diff --git a/docs/configuration/live.md b/docs/configuration/live.md new file mode 100644 index 00000000..acd7f509 --- /dev/null +++ b/docs/configuration/live.md @@ -0,0 +1,269 @@ +# `live` + +Configures the behavior of the `live` view. + + ```yaml +live: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `actions` | | [Actions](actions.md) to use for the `live` view. | +| `auto_mute` | `[unselected, hidden, microphone]` | A list of conditions in which live camera feeds are muted. `unselected` will automatically mute when a camera is unselected in the carousel, `hidden` will automatically mute when the browser/tab becomes hidden or `microphone` will automatically mute after the microphone is muted as long as the camera stays selected (see the `live.microphone.mute_after_microphone_mute_seconds` to control how long after). Use an empty list (`[]`) to never automatically mute. Note that if `auto_play` is enabled, the stream may mute itself automatically in order to honor the `auto_play` setting, as some browsers will not auto play media that is unmuted -- that is to say, where necessary, the `auto_play` parameter will take priority over the `auto_mute` parameter.| +| `auto_pause` | `[]` | A list of conditions in which live camera feeds are automatically paused. `unselected` will automatically pause when a camera is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause. **Caution**: Some live providers (e.g. `jsmpeg`) may not offer human-accessible means to resume play if it is paused, unless the `auto_play` option is used.| +| `auto_play` | `[selected, visible]` | A list of conditions in which live camera feeds are automatically played.`selected` will automatically play when a camera is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play. Some live providers (e.g. `webrtc-card`, `jsmpeg`) do not support the prevention of automatic play on initial load, but should still respect the value of this flag on play-after-pause.| +| `auto_unmute` | `[microphone]` | A list of conditions in which live camera feeds are unmuted. `selected` will automatically unmute when a camera is unselected in the carousel, `visible` will automatically unmute when the browser/tab becomes visible or `microphone` will automatically unmute after the microphone is unmuted. Use an empty list (`[]`) to never automatically unmute.| +| `controls` | | Configuration for the `live` view controls. See below. | +| `display` | | Controls whether to show a single or grid `live` view. See below. | +| `draggable` | `true` | Whether or not the live carousel can be dragged left or right, via touch/swipe and mouse dragging. | +| `lazy_load` | `true` | Whether or not to lazily load cameras in the camera carousel. Setting this will `false` will cause all cameras to load simultaneously when the `live` carousel is opened (or cause all cameras to load continually if both `lazy_load` and `preload` are `true`). This will result in a smoother carousel experience at a cost of (potentially) a substantial amount of continually streamed data. | +| `lazy_unload` | `[]` | A list of conditions in which live camera feeds are unloaded. `unselected` will lazy-unload a camera when it is unselected in the carousel and `hidden` will lazy-unload all cameras when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically unload. This will cause a reloading delay on revisiting that camera in the carousel but will save the streaming network resources that are otherwise consumed. This option has no effect if `lazy_load` is false. Some live providers (e.g. `webrtc-card`) implement their own lazy unloading independently which may occur regardless of the value of this setting.| +| `microphone` | | See below. | +| `preload` | `false` | Whether or not to preload the live view. Preloading causes the live view to render in the background regardless of what view is actually shown, so it's instantly available when requested. This consumes additional network/CPU resources continually. | +| `show_image_during_load` | `true` | If `true`, during the initial stream load, the `image` live provider will be shown instead of the loading video stream. This still image will auto-refresh and is replaced with the live stream once loaded. | +| `transition_effect` | `slide` | Effect to apply as a transition between live cameras. Accepted values: `slide` or `none`. | +| `zoomable` | `true` | Whether or not the live carousel can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | + +## `controls` + +Configure the controls for the `live` view. + +```yaml +live: + controls: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `builtin` | `true` | Whether to show the built in (browser) video controls on live video. | +| `next_previous` | | Configures how the "Next & Previous" controls are shown on the `live` view. See below. | +| `thumbnails` | | | Configures how thumbnails are shown on the `live` view. See below. | +| `timeline` | | | Configures how the mini-timeline is shown on the `live` view. See below. | +| `title` | | Configures how the camera title is shown on the `live` view. See below. | + +### `next_previous` + +Configures how the "Next & Previous" controls are shown on the live view. + +```yaml +live: + controls: + next_previous: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `size` | `48` | The size of the next/previous controls in pixels. Must be >= `20`. | +| `style` | `chevrons` | When viewing live cameras, what kind of controls to show to move to the previous/next camera. Acceptable values: `chevrons`, `icons`, `none` . | + +### `thumbnails` + +Configures how thumbnails are shown on the live view. + +```yaml +live: + controls: + thumbnails: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `events_media_type` | `all` | Whether to show `clips`, `snapshots` or `all` in the thumbnail carousel in the `live` view. This setting is only relevant when the `media_type` parameter is set to `events`.| +| `media_type` | `events` | Whether to load `events` or `recordings` media.| +| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| +| `show_details` | `false` | Whether to show event details (e.g. duration, start time, object detected, etc) alongside the thumbnail.| +| `show_download_control` | `true` | Whether to show the download control on each thumbnail.| +| `show_favorite_control` | `true` | Whether to show the favorite ('star') control on each thumbnail.| +| `show_timeline_control` | `true` | Whether to show the timeline ('target') control on each thumbnail.| +| `size` | `100` | The size of the thumbnails in the thumbnail carousel in pixels. Must be >= `75` and <= `175`. | + +### `timeline` + +Configures how the mini-timeline is shown on the live view. + +```yaml +live: + controls: + timeline: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `clustering_threshold` | `3` | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | +| `events_media_type` | `all` | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot.| +| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| +| `pan_mode` | `pan`| See [timeline pan mode](timeline-pan-mode.md). | +| `show_recordings` | `true` | Whether to show recordings on the timeline (specifically: which hours have any recorded content).| +| `style` | `ribbon` | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold`. | +| `window_seconds` | `3600` | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | + +[](common/timeline-seek-info.md ':include') + +### `title` + +Configures how the camera title is shown on the live view. + +```yaml +live: + controls: + title: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `duration_seconds` | `2` | The number of seconds to display the title popup. `0` implies forever.| +| `mode` | `popup-bottom-right` | How to display the live camera title. Acceptable values: `none`, `popup-top-left`, `popup-top-right`, `popup-bottom-left`, `popup-bottom-right` . | + +## `display` + +Controls whether to show a single or grid `live` view. + +```yaml +live: + display: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `grid_columns` | | If specified the grid will always have exactly this number of columns.| +| `grid_max_columns` | `4` | If specified, and `grid_columns` is not specified, the grid will not render more than this number of columns. The precise number will be calculated based on the [grid layout algorithm](grid-layout-algorithm.md). | +| `grid_selected_width_factor` | `2` | How much to scale up the selected media item in a grid. A value of `1` will not scale the selected item at all, the default value of `2` will scale the media item width to twice what it would otherwise be, etc. | +| `mode` | `single` | Whether to display a `single` live camera in a carousel, or all cameras in a `grid` configuration.| + +## `microphone` + +Controls the behavior of the microphone in the `live` view. + +```yaml +live: + microphone: +``` + +| Option | Default | Description | +| - | - | - | +| `always_connected` | `false` | Whether or not to keep the microphone stream continually connected while the card is running, or only when microphone is used (default). In the latter case there'll be a connection reset when the microphone is first used -- using this option can avoid that reset.| +| `disconnect_seconds` | `90` | The number of seconds after microphone usage to disconnect the microphone from the stream. `0` implies never. Not relevant if `always_connected` is `true`.| +| `mute_after_microphone_mute_seconds` | `60` | The number of seconds after the microphone mutes to automatically mute the inbound audio when `live.auto_mute` includes `microphone`.| + +See [Using 2-way audio](../usage/2-way-audio.md) for more information about the very particular requirements that must be followed for 2-way audio to work. + +## `ptz` + +Controls a PTZ (Pan Tilt Zoom) overlay on the `live` view. + +```yaml +live: + ptz: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `actions_left`, `actions_right`, `actions_up`, `actions_down`, `actions_zoom_in`, `actions_zoom_out`, `actions_home` | Set by camera [engine](cameras/engine.md) of the selected camera | The [actions](actions.md) to call when this icon is interacted with. | +| `data_left`, `data_right`, `data_up`, `data_down`, `data_zoom_in`, `data_zoom_out`, `data_home` | | Shorthand for a `tap_action` that calls the `service` with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[button]`. If both `actions_X` and `data_X` are specified, `actions_X` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). | +| `hide_home` | `false` | When `true` the Home button of the control is hidden | +| `hide_pan_tilt` | `false` | When `true` the Pan & Tilt buttons of the control is hidden | +| `hide_zoom` | `false` | When `true` the Zoom button of the control is hidden | +| `mode` | `on` | When `on` will show a PTZ control if so configured (manually, or by the camera engine), if `off` will not show any control. | +| `orientation` | `horizontal` | Whether to show a `vertical` or `horizontal` PTZ control. | +| `position` | `bottom-right` | Whether to position the control on the `top-left`, `top-right`, `bottom-left` or `bottom-right`. This may be overridden by using the `style` parameter to precisely control placement. | +| `service` | | An optional Home Assistant service to call when the `data_` parameters are used. | +| `style` | | Optionally position and style the element using CSS. Similar to [Picture Element styling](https://www.home-assistant.io/dashboards/picture-elements/#how-to-use-the-style-object), except without any default, e.g. `left: 42%` | + +## Fully expanded reference + +[](common/expanded-warning.md ':include') + +```yaml +live: + auto_play: + - selected + - visible + auto_pause: [] + auto_mute: + - unselected + - hidden + auto_unmute: + - microphone + preload: false + lazy_load: true + lazy_unload: [] + draggable: true + zoomable: true + transition_effect: slide + controls: + builtin: true + next_previous: + style: chevrons + size: 48 + thumbnails: + media_type: events + events_media_type: all + size: 100 + show_details: false + show_download_control: true + show_favorite_control: true + show_timeline_control: true + mode: none + timeline: + style: ribbon + mode: none + pan_mode: pan + clustering_threshold: 3 + events_media_type: all + show_recordings: true + window_seconds: 3600 + title: + mode: popup-bottom-right + duration_seconds: 2 + microphone: + always_connected: false + disconnect_seconds: 90 + mute_after_microphone_mute_seconds: 60 + ptz: + mode: on + position: bottom-right + orientation: horizontal + hide_pan_tilt: false + hide_zoom: false + hide_home: false + style: + # Optionally override the default style. + right: 5% + # Manually specifying actions. + actions_left: + tap_action: + action: call-service + service: sonoff.send_command + service_data: + device: '048123' + cmd: left + # Equivalent short form PTZ actions (only right button shown) + service: sonoff.send_command + data_right: + device: '048123' + cmd: right + display: + mode: single + grid_selected_width_factor: 2 + grid_max_columns: 4 + actions: + entity: light.office_main_lights + tap_action: + action: none + hold_action: + action: none + double_tap_action: + action: none + start_tap_action: + action: none + end_tap_action: + action: none +``` diff --git a/docs/configuration/media-gallery.md b/docs/configuration/media-gallery.md new file mode 100644 index 00000000..8a24347b --- /dev/null +++ b/docs/configuration/media-gallery.md @@ -0,0 +1,78 @@ +# `media_gallery` + +The `media_gallery` is used for providing an overview of all `clips`, `snapshots` and `recordings` in a thumbnail gallery. + +```yaml +media_gallery: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `actions` | | [Actions](actions.md) to use for all views that use the `media_gallery` (e.g. `clips`, `snapshots`, `recordings`). | +| `controls` | | Configuration for the Media viewer controls. See below. | + +## `controls` + +### `filter` + +Configure the media gallery filter. + +```yaml +media_gallery: + controls: + filter: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `mode` | `right` | Whether to show the gallery media filter to the `left`, to the `right` or `none` for no media filter. | + +### `thumbnails` + +Configure the media gallery thumbnails. + +```yaml +media_gallery: + controls: + thumbnails: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `show_details` | `false` | Whether to show media details (e.g. duration, start time, object detected, etc) alongside the thumbnail.| +| `show_download_control` | `true` | Whether to show the download control on each thumbnail.| +| `show_favorite_control` | `true` | Whether to show the favorite ('star') control on each thumbnail.| +| `show_timeline_control` | `true` | Whether to show the timeline ('target') control on each thumbnail.| +| `size` | `100` | The size of the thumbnails in the gallery. Must be >= `75` and <= `175`.| + +## Fully expanded reference + +[](common/expanded-warning.md ':include') + +```yaml +media_gallery: + controls: + filter: + mode: 'right' + thumbnails: + size: 100 + show_details: false + show_download_control: true + show_favorite_control: true + show_timeline_control: true + actions: + entity: light.office_main_lights + tap_action: + action: none + hold_action: + action: none + double_tap_action: + action: none + start_tap_action: + action: none + end_tap_action: + action: none +``` diff --git a/docs/configuration/media-viewer.md b/docs/configuration/media-viewer.md new file mode 100644 index 00000000..e17074a2 --- /dev/null +++ b/docs/configuration/media-viewer.md @@ -0,0 +1,194 @@ +# `media_viewer` + +The `media_player` section configures viewing all `clip`, `snapshot` or `recording` media, in either a media carousel or grid. + +```yaml +media_viewer: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `actions` | | [Actions](actions.md) to use for all views that use the `media_viewer` (e.g. `clip`, `snapshot`). | +| `auto_mute` | `[unselected, hidden]` | A list of conditions in which media items are muted. `unselected` will automatically mute when a media item is unselected in the carousel and `hidden` will automatically mute when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically mute.| +| `auto_pause` | `[unselected, hidden]` | A list of conditions in which media items are automatically paused. `unselected` will automatically pause when a media item is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause.| +| `auto_play` | `[selected, visible]` | A list of conditions in which media items are automatically played.`selected` will automatically play when a media item is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play.| +| `auto_unmute` | `[]` | A list of conditions in which media items are unmuted. `selected` will automatically unmute when a media item is unselected in the carousel and `visible` will automatically unmute when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically unmute. Note that some browsers will not allow automated unmute until the user has interacted with the page in some way -- if the user has not then the browser may pause the media instead.| +| `controls` | | Configuration for the Media viewer controls. See below. | +| `draggable` | `true` | Whether or not the Media viewer carousel can be dragged left or right, via touch/swipe and mouse dragging. | +| `lazy_load` | `true` | Whether or not to lazily load media in the Media viewer carousel. Setting this will false will fetch all media immediately which may make the carousel experience smoother at a cost of (potentially) a substantial number of simultaneous media fetches on load. | +| `snapshot_click_plays_clip` | `true` | Whether clicking on a snapshot in the media viewer should play a related clip. | +| `transition_effect` | `slide` | Effect to apply as a transition between event media. Accepted values: `slide` or `none`. | +| `zoomable` | `true` | Whether or not the Media Viewer can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | + +## `controls` + +Configure the controls for the media player views. + +```yaml +media_viewer: + controls: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `builtin` | `true` | Whether to show the built in (browser) video controls on media viewer videos. | +| `next_previous` | | Configures how the "Next & Previous" controls are shown on the media viewer. See below. | +| `thumbnails` | | Configures how thumbnails are shown on the media viewer. See below. | +| `timeline` | | Configures how the mini-timeline is shown on the media viewer. See below. | +| `title` | | Configures how the media title is shown on the media viewer. See below. | + +### `next_previous` + +Configures how the "Next & Previous" controls are shown on the media viewer. + +```yaml +media_viewer: + controls: + next_previous: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `size` | `48` | The size of the next/previous controls in pixels. Must be >= `20`.| +| `style` | `thumbnails` | When viewing media, what kind of controls to show to move to the previous/next media item. Acceptable values: `thumbnails`, `chevrons`, `none` . | + +### `thumbnails` + +Configures how thumbnails are shown on the media viewer. + +```yaml +media_viewer: + controls: + thumbnails: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| +| `show_details` | `false` | Whether to show event details (e.g. duration, start time, object detected, etc) alongside the thumbnail.| +| `show_download_control` | `true` | Whether to show the download control on each thumbnail.| +| `show_favorite_control` | `true` | Whether to show the favorite ('star') control on each thumbnail.| +| `show_timeline_control` | `true` | Whether to show the timeline ('target') control on each thumbnail.| +| `size` | `100` | The size of the thumbnails in the thumbnail carousel pixels. Must be >= `75` and <= `175`.| + +### `timeline` + +Configures how the mini-timeline is shown on the media viewer. + +```yaml +media_viewer: + controls: + timeline: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `clustering_threshold` | `3` | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | +| `events_media_type` | `all` | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot. | +| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| +| `pan_mode` | `pan`| See [timeline pan mode](timeline-pan-mode.md). | +| `show_recordings` | `true` | Whether to show recordings on the timeline (specifically: which hours have any recorded content).| +| `style` | `ribbon` | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold`. | +| `window_seconds` | `3600` | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | + +[](common/timeline-seek-info.md ':include') + +### `title` + +Configures how the media title is shown on the media viewer. + +```yaml +media_viewer: + controls: + title: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `duration_seconds` | `2` | The number of seconds to display the title popup. `0` implies forever.| +| `mode` | `popup-bottom-right` | How to display the Media viewer media title. Acceptable values: `none`, `popup-top-left`, `popup-top-right`, `popup-bottom-left`, `popup-bottom-right` . | + +## `display` + +Controls whether to show a single media item or grid in the media viewer. + +```yaml +media_viewer: + display: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `grid_columns` | | If specified the grid will always have exactly this number of columns.| +| `grid_max_columns` | `4` | If specified, and `grid_columns` is not specified, the grid will not render more than this number of columns. The precise number will be calculated based on the [grid layout algorithm](grid-layout-algorithm.md). | +| `grid_selected_width_factor` | `2` | How much to scale up the selected media item in a grid. A value of `1` will not scale the selected item at all, the default value of `2` will scale the media item width to twice what it would otherwise be, etc. | +| `mode` | `single` | Whether to display a `single` media item at a time, or a media item for all cameras in a `grid` configuration.| + +## Fully expanded reference + +[](common/expanded-warning.md ':include') + +```yaml +media_viewer: + auto_play: + - selected + - visible + auto_pause: + - unselected + - hidden + auto_mute: + - unselected + - hidden + auto_unmute: [] + lazy_load: true + draggable: true + zoomable: true + snapshot_click_plays_clip: true + transition_effect: slide + controls: + builtin: true + next_previous: + size: 48 + style: thumbnails + thumbnails: + size: 100 + mode: none + show_details: false + show_download_control: true + show_favorite_control: true + show_timeline_control: true + timeline: + style: ribbon + mode: none + pan_mode: pan + clustering_threshold: 3 + events_media_type: all + show_recordings: true + window_seconds: 3600 + title: + mode: popup-bottom-right + duration_seconds: 2 + display: + mode: single + grid_selected_width_factor: 2 + grid_max_columns: 4 + actions: + entity: light.office_main_lights + tap_action: + action: none + hold_action: + action: none + double_tap_action: + action: none + start_tap_action: + action: none + end_tap_action: + action: none +``` diff --git a/docs/configuration/menu.md b/docs/configuration/menu.md new file mode 100644 index 00000000..1348e516 --- /dev/null +++ b/docs/configuration/menu.md @@ -0,0 +1,171 @@ +# `menu` + +Configures how the card menu behaves. + + ```yaml +menu: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `alignment` | `left` | Whether to align the menu buttons to the `left`, `right`, `top` or `bottom` of the menu. Some selections may have no effect depending on the value of `position` (e.g. it doesn't make sense to `left` align icons on a menu with `position` to the `left`).| +| `button_size` | `40` | The size of the menu buttons in pixels. Must be >= `20`.| +| `buttons` | | Whether to show or hide built-in buttons. See below. | +| `position` | `top` | Whether to show the menu on the `left`, `right`, `top` or `bottom` side of the card. Note that for the `outside` style only the `top` and `bottom` positions have an effect.| +| `style` | `hidden` | The menu style to show by default, one of `none`, `hidden`, `hover`, `hover-card`, `overlay`, or `outside`. See below. | + +## `buttons` + +All configuration is under: + +```yaml +menu: + buttons: + [button]: + [...] +``` + +### Available Buttons + +| Button name | Description | +| - | - | +| `camera_ui` | The `camera_ui` menu button: brings the user to a context-appropriate page on the UI of their camera engine (e.g. the Frigate camera homepage). Will only appear if the camera engine supports a camera UI (e.g. if `frigate.url` option is set for `frigate` engine users).| +| `cameras` | The camera selection submenu. Will only appear if multiple cameras are configured. | +| `clips` | The `clips` view menu button: brings the user to the `clips` view on tap and the most-recent `clip` view on hold. | +| `display_mode` | The `display_mode` button allows changing between single and grid views. | +| `download` | The `download` menu button: allow direct download of the media being displayed.| +| `expand` | The `expand` menu button: expand the card into a popup/dialog. | +| `frigate` | The `Frigate` menu button: brings the user to the default configured view (`view.default`), or collapses/expands the menu if the `menu.style` is `hidden` . | +| `fullscreen` | The `fullscreen` menu button: expand the card to consume the fullscreen. | +| `image` | The `image` view menu button: brings the user to the static `image` view. | +| `live` | The `live` view menu button: brings the user to the `live` view. | +| `media_player` | The `media_player` menu button: sends the visible media to a remote media player. Supports Frigate clips, snapshots and live camera (only for cameras that specify a `camera_entity` and only using the default HA stream (equivalent to the `ha` live provider). `jsmpeg` or `webrtc-card` are not supported, although live can still be played as long as `camera_entity` is specified. In the player list, a `tap` will send the media to the player, a `hold` will stop the media on the player. | +| `microphone` | The `microphone` button allows usage of 2-way audio in certain configurations. See [Using 2-way audio](../usage/2-way-audio.md). | +| `ptz` | The `show_ptz` button shows or hide the PTZ controls. | +| `recordings` | The `recordings` view menu button: brings the user to the `recordings` view on tap and the most-recent `recording` view on hold. | +| `screenshot` | The `screenshot` menu button: take a screenshot of the loaded media (e.g. a still from a video). | +| `snapshots` | The `snapshots` view menu button: brings the user to the `clips` view on tap and the most-recent `snapshot` view on hold. | +| `timeline` | The `timeline` menu button: show the event timeline. | + +### Options for each button + +| Option | Default | Description | +| - | - | - | +| `alignment` | `matching` | Whether this button should have an alignment that is `matching` the menu alignment or `opposing` the menu. Can be used to create two separate groups of buttons on the menu. `priority` orders buttons within a given `alignment`. | +| `enabled` | `true` for `frigate`, `cameras`, `substreams`, `live`, `clips`, `snapshots`, `timeline`, `download`, `camera_ui`, `fullscreen`, `media_player`, `display_mode`. `false` for `image`, `expand`, `microphone`, `mute`, `play`, `recordings`, `screenshot`, `ptz` | Whether or not to show the button. | +| `icon` | | An icon to overriding the default for that button, e.g. `mdi:camera-front`. | +| `priority` | `50` | The button priority. Higher priority buttons are ordered closer to the start of the menu alignment (i.e. a button with priority `70` will order further to the left than a button with priority `60`, when the menu alignment is `left`). Minimum `0`, maximum `100`.| + +## `style` + +This card supports several menu styles. + +| Key | Description | Screenshot | +| - | - | - | +|`hidden`| Hide the menu by default, expandable upon clicking the Frigate button. | ![](../images/menu-mode-hidden.png "Menu hidden :size=400") | +|`hover-card`| Overlay the menu over the card contents when the mouse is over the **card**, otherwise it is not shown. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png "Menu hover-card :size=400") | +|`hover`| Overlay the menu over the card contents when the mouse is over the **menu**, otherwise it is not shown. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png "Menu hover :size=400") | +|`none`| No menu is shown. | ![](../images/menu-mode-none.png "No menu :size=400") | +|`outside`| Render the menu outside the card (i.e. above it if `position` is `top`, or below it if `position` is `bottom`). The Frigate button shows the default view. | ![](../images/menu-mode-above.png "Menu outside :size=400") | +|`overlay`| Overlay the menu over the card contents. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png "Menu hidden :size=400") | + +## Fully expanded reference + +[](common/expanded-warning.md ':include') + +```yaml +menu: + alignment: left + buttons: + frigate: + priority: 50 + enabled: true + alignment: matching + # Default icon is an internal coded Frigate icon. Note + # absence of 'mdi' here (mdi has no Frigate icon). + icon: frigate + cameras: + priority: 50 + enabled: true + alignment: matching + icon: mdi:video-switch + substreams: + priority: 50 + enabled: true + icon: mdi:video-input-component + live: + priority: 50 + enabled: true + alignment: matching + icon: mdi:cctv + clips: + priority: 50 + enabled: true + alignment: matching + icon: mdi:filmstrip + snapshots: + priority: 50 + enabled: true + alignment: matching + icon: mdi:camera + image: + priority: 50 + enabled: false + alignment: matching + icon: mdi:image + timeline: + priority: 50 + enabled: true + alignment: matching + icon: mdi:chart-gantt + download: + priority: 50 + enabled: true + alignment: matching + icon: mdi:download + camera_ui: + priority: 50 + enabled: true + alignment: matching + icon: mdi:web + fullscreen: + priority: 50 + enabled: true + alignment: matching + icon: mdi:fullscreen + expand: + priority: 50 + enabled: true + alignment: matching + icon: mdi:arrow-expand-all + media_player: + priority: 50 + enabled: false + alignment: matching + icon: mdi:cast + microphone: + priority: 50 + enabled: false + alignment: matching + icon: mdi:microphone + type: momentary + mute: + priority: 50 + enabled: false + alignment: matching + icon: mdi:volume-off + play: + priority: 50 + enabled: false + alignment: matching + icon: mdi:play + show_ptz: + priority: 50 + enabled: false + alignment: matching + icon: mdi:pan + button_size: 40 + position: top + style: hidden +``` diff --git a/docs/configuration/overrides.md b/docs/configuration/overrides.md new file mode 100644 index 00000000..59873789 --- /dev/null +++ b/docs/configuration/overrides.md @@ -0,0 +1,39 @@ +# `overrides` + +Various parts of card configuration may [conditionally](conditions.md) be +overridden (e.g. to hide the menu in fullscreen mode). + +```yaml +overrides: + - conditions: + [condition] + overrides: + [override] +``` + +Not all configuration parameters are overriddable, some because it doesn't make +sense for that parameter to vary, and many because of the extra complexity of +supporting overriding given the lack of compelling usecases ([please request new +overridable parameters +here!](https://github.com/dermotduffy/frigate-hass-card/issues/new/choose)). + +Each entry under the top-level `overrides` configuration block should be a list +item, that has both of the following parameters set: + +| Option | Default | Description | +| - | - | - | +| `conditions` | | A list of [conditions](conditions.md) that must evaluate to `true` in order for the overrides to be applied. | +| `overrides` | | Configuration overrides to be applied. Any configuration parameter matching [Overrideable parameters](overrides.md?id=overrideable-parameters) can be overridden. | + +## Overrideable parameters + +| Configuration Key | Overrideable | +| - | - | +| [`cameras.*`](cameras/README.md) | :white_check_mark: | +| [`cameras_global.*`](cameras/README.md) | :white_check_mark: | +| [`dimensions.*`](dimensions.md) | :white_check_mark: | +| [`image.*`](image.md) | :white_check_mark: | +| [`live.controls.*`](live.md?id=controls), [`live.display.*`](live.md?id=display), [`live.microphone.*`](live.md?id=microphone), [`live.show_image_during_load`](live.md), [`live.zoomable`](live.md) | :white_check_mark: | +| [`menu.*`](menu.md) | :white_check_mark: | +| [`view.*`](view.md) | :white_check_mark: | +| *(Everything else)* | :heavy_multiplication_x: | diff --git a/docs/configuration/performance.md b/docs/configuration/performance.md new file mode 100644 index 00000000..a83b922a --- /dev/null +++ b/docs/configuration/performance.md @@ -0,0 +1,65 @@ +# `performance` + +Configure the card performance settings to enable the card to run (more) smoothly on lower end devices. + +```yaml +performance: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `features` | | Configure feature settings that impact performance. | +| `style` | | Configure style settings that impact performance. | + +### `features` + +Controls card-wide functionality that may impact performance. + +```yaml +performance: + features: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `animated_progress_indicator` | `true` | Will show the animated progress indicator 'spinner' when `true` or a simple loading icon when `false`.| +| `media_chunk_size` | `50` | How many media items to fetch and render at a time (e.g. thumbnails under a live view, or number of snapshots to load in the media viewer). This may only make partial sense in some contexts (e.g. the 'infinite gallery' is still infinite, it just loads thumbnails this many items at a time) or not at all (e.g. the timeline will show the number of events dictated by the time span the user navigates to).| + +### `style` + +Style performance options request the card minimize certain expensive CSS +stylings. This does not necessarily disable these stylings _entirely_ since that +may break the basic expected visuals of the card (e.g. menu icons need curves), +but rather avoids use of them in high item-count situations (e.g. avoiding +shadows on timeline items, or curves in the media gallery items). + +```yaml +performance: + style: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `border_radius` | `true` | If `false` minimizes the usage of rounded corners.| +| `box_shadow` | `true` | If `false` minimizes the usage of shadows.| + +### The `low-performance` profile + +For low end devices, the `low-performance` profile will adjust card defaults to attempt to improve performance. See the [profiles](profiles.md) configuration option for details on how to select profiles. + +## Fully expanded reference + +[](common/expanded-warning.md ':include') + +```yaml +performance: + features: + animated_progress_indicator: true + media_chunk_size: 50 + style: + border_radius: true + box_shadow: true +``` \ No newline at end of file diff --git a/docs/configuration/profiles.md b/docs/configuration/profiles.md new file mode 100644 index 00000000..00aac819 --- /dev/null +++ b/docs/configuration/profiles.md @@ -0,0 +1,47 @@ +# `profiles` + +Apply pre-configured sets of defaults to ease card configuration. + +```yaml +profiles: + - [profile_1] + - [profile_2] +``` + +?> Since the profiles change the _default_ value of options, setting a profile +on a pre-existing card could have limited effect if there are options already set by +the user. + +?> Profiles are applied top to bottom. If multiple profiles change a configuration default, then the last one "wins" + +| Profile name | Purpose | +| - | - | +| `low-performance` | Increase card performance. | +| `scrubbing` | Allow media "scrubbing". | + +## `low-performance` + +For low end devices, the `low-performance` profile will adjust card defaults to attempt to increase performance. + +Principles used in the selection of options set by `low-profile` profile mode: + +* Get 'out of the box' performance similar to the basic "Home Assistant Picture Glance" card. +* Do not break the visual aesthetic of the card. + +See the [source code](https://github.com/dermotduffy/frigate-hass-card/blob/dev/src/config/profiles/low-performance.ts) for an exhaustive list of options set by this profile. + +## `scrubbing` + +Configures the `live` view and media viewer to allow media "scrubbing" as the timeline is dragged back and forth. + +See the [source code](https://github.com/dermotduffy/frigate-hass-card/blob/dev/src/config/profiles/scrubbing.ts) for an exhaustive list of options set by this profile. + +## Fully expanded reference + +[](common/expanded-warning.md ':include') + +```yaml +profiles: + - low-performance + - scrubbing +``` \ No newline at end of file diff --git a/docs/configuration/timeline-pan-mode.md b/docs/configuration/timeline-pan-mode.md new file mode 100644 index 00000000..160e1cba --- /dev/null +++ b/docs/configuration/timeline-pan-mode.md @@ -0,0 +1,10 @@ +# Timeline Pan Mode + +The behavior of the timeline during seeking/dragging can be controlled by means of the icon on the bottom-right of the timeline, or by using the `pan_mode` configuration variable for the relevant timeline controls (e.g. `live.controls.timeline.pan_mode`). + +| Configuration name | UI Icon | Behavior | +| - | - | - | +| `pan`| pan-horizontal | Dragging the timeline will pan only without selected or seeking any media. | +| `seek-in-camera` | camera-lock | Dragging the timeline will seek / select across all available media from the selected camera only, selecting the media item with the longest duration. | +| `seek-in-media` | play-box-lock | Dragging the timeline will seek within the selected media item only. | +| `seek` | filmstrip-box-multiple | Dragging the timeline will seek / select across all available media from all cameras, selecting the media item with the longest duration whilst favoring (but not limited to) the currently selected camera. | diff --git a/docs/configuration/timeline.md b/docs/configuration/timeline.md new file mode 100644 index 00000000..3edea8d7 --- /dev/null +++ b/docs/configuration/timeline.md @@ -0,0 +1,79 @@ +# `timeline` + +Configures a `timeline` view used to show the timing sequence of events and +recordings across multiple cameras. + +```yaml +timeline: + [...] +``` + +You can interact with the timeline in a number of ways: + +* Clicking on an event will take you to the media viewer for that event. +* Clicking on the "background", or a camera title, will take you to the recordings for that camera (seeking to the clicked time). +* Clicking on the time axis will take you to recordings for all cameras (seeking to the clicked time). + +| Option | Default | Description | +| - | - | - | +| `clustering_threshold` | `3` | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | +| `controls` | | Configuration for the timeline controls. See below. | +| `events_media_type` | `all` | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot.| +| `show_recordings` | `true` | Whether to show recordings on the timeline (specifically: which hours have any recorded content).| +| `style` | `stack` | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold`. | +| `window_seconds` | `3600` | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | + +## `controls` + +Configure the controls for the `timeline` view. + +```yaml +timeline: + controls: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `thumbnails` | | Configures how thumbnails are shown on the `timeline` view. See below. | + +### `thumbnails` + +Configures how thumbnails are shown on the timeline. + +```yaml +timeline: + controls: + thumbnails: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| +| `show_details` | `false` | Whether to show event details (e.g. duration, start time, object detected, etc) alongside the thumbnail.| +| `show_download_control` | `true` | Whether to show the download control on each thumbnail.| +| `show_favorite_control` | `true` | Whether to show the favorite ('star') control on each thumbnail.| +| `show_timeline_control` | `true` | Whether to show the timeline ('target') control on each thumbnail.| +| `size` | `100` | The size of the thumbnails in the thumbnail carousel in pixels. Must be >= `75` and <= `175`.| + +## Fully expanded reference + +[](common/expanded-warning.md ':include') + +```yaml +timeline: + style: stack + clustering_threshold: 3 + events_media_type: all + show_recordings: true + window_seconds: 3600 + controls: + thumbnails: + mode: left + size: 100 + show_details: true + show_download_control: true + show_favorite_control: true + show_timeline_control: true +``` \ No newline at end of file diff --git a/docs/configuration/view.md b/docs/configuration/view.md new file mode 100644 index 00000000..cd3d2b1e --- /dev/null +++ b/docs/configuration/view.md @@ -0,0 +1,117 @@ +# `view` + +The `view` configuration options control how the default view of the card behaves. + + ```yaml +view: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `actions` | | [Actions](actions.md) to use for all views, individual actions may be overriden by view-specific actions. | +| `camera_select` | `current` | The [view](view.md?id=supported-views) to show when a new camera is selected (e.g. in the camera menu). If `current` the view is unchanged when a new camera is selected. | +| `dark_mode` | `off` | Whether or not to turn dark mode `on`, `off` or `auto` to automatically turn on if the card `interaction_seconds` has expired (i.e. card has been left unattended for that period of time) or if dark mode is enabled in the HA profile theme setting. Dark mode dims the brightness by `25%`.| +| `default` | `live` | The view to show in the card by default. The default camera is the first one listed. See [Supported Views](view.md?id=supported-views) below. | +| `interaction_seconds` | `300` | After a mouse/touch interaction with the card, it will be considered "interacted with" until this number of seconds elapses without further interaction. May be used as part of an [interaction condition](conditions.md?id=interaction) or with `reset_after_interaction` to reset the view after the interaction is complete. `0` means no interactions are reported / acted upon. | +| `render_entities` | | **YAML only**: A list of entity ids that should cause the card to re-render 'in-place'. The view/camera is not changed. `update_*` flags do not pertain/relate to the behavior of this flag. This should **very** rarely be needed, but could be useful if the card is both setting and changing HA state of the same object as could be the case for some complex `card_mod` scenarios ([example](https://github.com/dermotduffy/frigate-hass-card/issues/343)). | +| `reset_after_interaction` | `true` | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | +| `triggers` | | How to react when a camera is [triggered](cameras/README.md?id=triggers). | +| `update_cycle_camera` | `false` | When set to `true` the selected camera is cycled on each default view change. | +| `update_entities` | | **YAML only**: A card-wide list of entities that should cause the view to reset to the default (if the entity only pertains to a particular camera use [`triggers`](cameras/README.md?id=triggers) for the selected camera instead. | +| `update_force` | `false` | Whether automated card updates should ignore user interaction. | +| `update_seconds` | `0` | A number of seconds after which to automatically update/refresh the default view. If the default view occurs sooner (e.g. manually) the timer will start over. `0` disables this functionality.| + +## `triggers` + +The `triggers` block controls how the card reacts when a camera is triggered (note that _what_ triggers the camera is controlled by the [`triggers`](cameras/README.md?id=triggers) block within the config for a given camera). This can be used for a variety of purposes, such as allowing the card to automatically change to `live` for a camera that triggers. + +All configuration is under: + +```yaml +view: + triggers: + [...] +``` + +When a camera untriggers (e.g. an entity state returning to something other than +`on` or `open`), an action can also be taken with an optional number of seconds +to wait prior to the acting (see `untrigger_seconds`). By default, triggering is +only allowed when there is no ongoing human interaction with the card. This +behavior can be controlled by the `interaction_mode` parameter. + +Triggers based on Home Assistant entities require state *changes* -- when the +card is first started, it takes an active change in state to trigger (i.e. an +already occupied room will not trigger, but a newly occupied room will). + +| Option | Default | Description | +| - | - | - | +| `actions` | | The actions to take when a camera is triggered. See below. | +| `filter_selected_camera` | `false` | If set to `true` will only trigger on the currently selected camera.| +| `show_trigger_status` | `false` | Whether or not the `live` view should show a visual indication that it is triggered (a pulsing border around the camera edge). | +| `untrigger_seconds` | `0` | The number of seconds to wait after a camera untriggers before considering the card untriggered and taking the `untrigger` action. | + +### Trigger action configuration + +| Option | Default | Description | +| - | - | - | +| `interaction_mode` | `inactive` | Whether actions should be taken when the card is being interacted with. If `all`, actions will always left be taken regardless. If `inactive` actions will only be taken if the card has *not* had human interaction recently (as defined by `view.interaction_seconds`). If `active` actions will only be taken if the card *has* had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed. | +| `trigger` | `default` | If set to `default` the default view of the card will be reloaded. If set to `live` the triggered camera will be selected in `live` view. If set to `media` the appropriate media view (e.g. `clip` or `snapshot`) will be chosen to match a newly available media item (please note that only some [camera engines](cameras/engine.md) support new media detection, e.g. `frigate`). If set to `none` no action is taken. | +| `untrigger` | `none` | If set to `default` the the default view of the card will be reloaded. If set to `none` no action will be taken. | + +## Supported views + +This card supports several different views. + +| Key | Description | +| - | - | +|`clip`|Shows a viewer for the most recent clip for this camera. Can also be accessed by holding down the `clips` menu icon.| +|`clips`|Shows a gallery of clips for this camera.| +|`image`|Shows a static image specified by the `image` parameter, can be used as a discrete default view or a screensaver (via `view.interaction_seconds`).| +|`live`| Shows the live camera view with the configured [live provider]().| +|`recording`|Shows a viewer for the most recent recording for this camera. Can also be accessed by holding down the `recordings` menu icon.| +|`recordings`|Shows a gallery of recent (last day) recordings for this camera and its dependents.| +|`snapshot`|Shows a viewer for the most recent snapshot for this camera. Can also be accessed by holding down the `snapshots` menu icon.| +|`snapshots`|Shows a gallery of snapshots for this camera.| +|`timeline`|Shows an event timeline.| + +The default view is `live`, but can be configured by the `view.default` parameter. + +## Fully expanded reference + +[](common/expanded-warning.md ':include') + +```yaml +view: + default: live + camera_select: current + interaction_seconds: 300 + update_seconds: 0 + update_force: false + update_cycle_camera: false + update_entities: + - binary_sensor.my_motion_sensor + render_entities: + - switch.render_card + dark_mode: 'off' + triggers: + show_trigger_status: false + filter_selected_camera: true + untrigger_seconds: 0 + actions: + interaction_mode: inactive + trigger: default + untrigger: none + actions: + entity: light.office_main_lights + tap_action: + action: none + hold_action: + action: none + double_tap_action: + action: none + start_tap_action: + action: none + end_tap_action: + action: none +``` diff --git a/docs/developing.md b/docs/developing.md new file mode 100644 index 00000000..a87a603e --- /dev/null +++ b/docs/developing.md @@ -0,0 +1,73 @@ +# Developing + +?> Want to contribute? Development help [**welcome**](https://github.com/dermotduffy/frigate-hass-card/issues/1248)! + +## Building + +This project uses [Volta](https://github.com/volta-cli/volta) to ensure a +consistent version of Node and Yarn are used during development. If you install +Volta in your environment, you should not need to worry about which version of +both to choose. **Note:** the dev container already comes with Volta installed. + +However, if you are not using Volta, you can check the `volta` key in the +`package.json` to see which version of Node and Yarn should be used. + +```sh +$ git clone https://github.com/dermotduffy/frigate-hass-card +$ cd frigate-hass-card +$ yarn install +$ yarn run build +``` + +Resultant build entry file will be in `dist/frigate-hass-card.js`. This could be +installed via the [manual installation +instructions](advanced-installation.md?id=manual-installation). + +## Releasing + +1. Merge a PR that contains only a `package.json` and `const.ts` version number bump (see [this example](https://github.com/dermotduffy/frigate-hass-card/commit/a854187d4a354f8841ad284d75b0afbed7b634c4)). +1. Go to the [releases page](https://github.com/dermotduffy/frigate-hass-card/releases). +1. A release draft will automatically have been created, click 'Edit'. +1. Use the same version number for the release title and tag. +1. Choose 'This is a pre-release' for a beta version. +1. Hit 'Publish release'. + +## Translations +[![translation badge](https://badge.inlang.com/?url=github.com/dermotduffy/frigate-hass-card)](https://fink.inlang.com/github.com/dermotduffy/frigate-hass-card?ref=badge) + +To add translations, you can manually edit the JSON translation files in +`src/localize/languages` or use the [inlang](https://inlang.com/) online editor. + +## Using a dev container + +[![Open in Dev Containers](https://img.shields.io/static/v1?label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/dermotduffy/frigate-hass-card) + +You can use the [VS Code Dev Containers](https://code.visualstudio.com/docs/remote/containers) extension to +speed up the development environment creation. Simply: + +1. Clone the repository to your machine +2. Open VS Code on it +3. Reopen the folder in the Dev Container +4. Once done, press `F5` to start debugging + +Everything should just work without any additional configuration. Under the +hood, the dev container setup takes care of bringing up: + +* Home Assistant (port `8123` or the next available one) +* Frigate (ports `5000` or the next available one) +* MQTT (port `1883` or the next available one) + +As docker-compose containers. + +* The Frigate Home Assistant Integration is registered as a `git submodule` at `.devcontainer/frigate-hass-integration`, and VS Code will initialize/clone it for you before opening the dev container. + +Some environment variables are supported in a `.env` file: + +* `FRIGATE_VERSION`: The version of Frigate to use. Defaults to the latest stable version. +* `HA_VERSION`: The version of Home Assistant to use. Defaults to the latest stable version. + +?> When not specifying any version, it's recommended that you `docker-compose pull` the stack from time to time to ensure you have the latest versions of the images. + +The Home Assistant container will get preconfigured during first initialization, +therefore, if you changed the Home Assistant configuration, you will need to +remove the HA container and start another. diff --git a/docs/examples.md b/docs/examples.md new file mode 100644 index 00000000..d2859a8d --- /dev/null +++ b/docs/examples.md @@ -0,0 +1,981 @@ +# Examples + +## Actions on `tap` + +You can add actions to the card to be trigger on `tap`, `double_tap`, `hold`, `start_tap` or `end_tap`. + +In this example double clicking the card in any view will cause the card to go +into fullscreen mode, **except** when the view is `live` in which case the +office lights are toggled. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +view: + actions: + double_tap_action: + action: custom:frigate-card-action + frigate_card_action: fullscreen +live: + actions: + entity: light.office_main_lights + double_tap_action: + action: toggle +``` + +## Aspect ratios + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +dimensions: + aspect_ratio_mode: static + aspect_ratio: '4:3' +``` + +## Automation + +This example will automatically turn on the first configured substream when the +card is put in fullscreen mode, and turn off the substream when exiting +fullscreen mode. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + live_provider: image + dependencies: + cameras: + - office_hd + - camera_entity: camera.office + title: Office HD + live_provider: go2rtc + id: office_hd + capabilities: + disable_except: + - substream +automations: + - conditions: + - condition: fullscreen + fullscreen: true + actions: + - action: custom:frigate-card-action + frigate_card_action: live_substream_on + actions_not: + - action: custom:frigate-card-action + frigate_card_action: live_substream_off +``` + +## `card-mod` + +This card allows the use of +[card-mod](https://github.com/thomasloven/lovelace-card-mod) to style arbitrary +card contents. + +!> `card-mod` relies on the underlying internal DOM structure to style elements +-- as such, while its use is possible, it's not officially supported and zero +attempt is made to preserve backwards compatability of the internal DOM between +any versions. It may look good, but you're on your own! + +This example changes the color and removes the padding around a [Picture +Elements state +label](https://www.home-assistant.io/lovelace/picture-elements/#state-label). + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +card_mod: + style: + frigate-card-elements $: + hui-state-label-element $: | + div { + padding: 0px !important; + color: blue; + } +``` + +## Cast a `dashboard` + +This example will configure a Frigate card that can cast a dashboard view to a media player, which has a second Frigate card in panel mode with a low-latency live provider. + +### Source card + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + live_provider: image + cast: + method: dashboard + dashboard: + dashboard_path: cast + view_path: office +``` + +### Dashboard configuration + +?> This dashboard is configured at the path `/cast/` (path referred to in `dashboard_path` above). + +```yaml +title: Frigate Card Casting +views: + - title: Casting + # This path is referred to in `view_path` above. + path: office + # Ensure the video is "maximized" / dashboard in "panel" mode. + type: panel + cards: + - type: custom:frigate-card + cameras: + - camera_entity: camera.office + live_provider: go2rtc +``` + +## Conditional elements + +You can restrict elements to only show for certain +[views](configuration/view.md?id=supported-views) using a +`custom:frigate-card-conditional` element. This example shows a car icon that +calls a service but only in the `live` view. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: custom:frigate-card-conditional + conditions: + - condition: view + views: + - live + elements: + - type: icon + icon: mdi:car + style: + background: rgba(255, 255, 255, 0.25) + border-radius: 5px + right: 25px + bottom: 50px + tap_action: + action: call-service + service: amcrest.ptz_control + service_data: + entity_id: camera.kitchen + movement: up +``` + +## Conditional menu icons + +You can have icons conditionally added to the menu based on entity state. + +### Show a menu icon based on state + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: conditional + conditions: + - condition: state + entity: light.office_main_lights + state: on + elements: + - type: custom:frigate-card-menu-state-icon + entity: light.office + tap_action: + action: toggle +``` + +### Show a menu icon based on camera triggering + +This example adds a menu button to optionally activate a siren when the camera is triggered. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: custom:frigate-card-conditional + elements: + - type: custom:frigate-card-menu-icon + icon: mdi:alarm-bell + title: Activate alarm + style: + color: red + tap_action: + action: call-service + service: homeassistant.toggle + data: + entity_id: siren.siren + conditions: + - condition: triggered + triggered: + - camera.office +``` + +## Events from other cameras + +`dependencies.cameras` allows events/recordings for other cameras to be shown +along with the currently selected camera. For example, this can be used to show +events with the `birdseye` camera (since it will not have events of its own). + +### Using dependent cameras with birdseye + +This example shows events for two other cameras when `birdseye` is selected. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + - camera_entity: camera.kitchen + - frigate: + camera_name: birdseye + dependencies: + cameras: + - camera.office + - camera.kitchen +``` + +### Using dependent cameras with birdseye for all cameras + +This example shows events for *all* other cameras when `birdseye` is selected. +This is just a shortcut for naming all other cameras. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.kitchen + - camera_entity: camera.sitting_room + - frigate: + camera_name: birdseye + dependencies: + all_cameras: true +``` + +## Human interaction + +This example will automatically use a HD live substream when +the mouse cursor interacts with the card. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + live_provider: image + dependencies: + cameras: + - camera.office_hd + - camera_entity: camera.office_hd + live_provider: go2rtc + capabilities: + disable_except: + - substream +automations: + - actions: + - action: custom:frigate-card-action + frigate_card_action: live_substream_on + actions_not: + - action: custom:frigate-card-action + frigate_card_action: live_substream_off + conditions: + - condition: interaction + interaction: true +``` + +## Media layout + +These examples change how the media fits and is positioned within the card dimensions. + +### Stretch a camera into a 4:4 square + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.landing + dimensions: + aspect_ratio: '4:4' + layout: + fit: fill +``` + +### Convert a landscape camera to a portrait live view + +Take the left-hand side (position with x == `0`) and use that as the basis of a `9:16` (i.e. portrait) live view. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + dimensions: + aspect_ratio: '9:16' + layout: + fit: cover + position: + x: 0 +``` + +## Menu alignment + +This example moves the fullscreen button into its own group aligned to the +`left`, enables the `image` button and orders it furthest to the `right`. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +menu: + alignment: right + buttons: + image: + enabled: true + priority: 100 + fullscreen: + alignment: opposing +``` + +## Menu icons + +You can add custom icons to the menu with arbitrary actions. This example adds +an icon that navigates the browser to the releases page for this card: + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: custom:frigate-card-menu-icon + icon: mdi:book + tap_action: + action: url + url_path: https://github.com/dermotduffy/frigate-hass-card/releases +``` + +## Menu state icons + +You can add custom state icons to the menu to show the state of an entity and +complete arbitrary actions. This example adds an icon that represents the state +of the `light.office_main_lights` entity, that toggles the light on double +click. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: custom:frigate-card-menu-state-icon + entity: light.office_main_lights + tap_action: + action: toggle +``` + +## Multiple actions + +This example shows how to configure multiple actions for a single Frigate card user interaction, in this case both selecting a different camera and changing the view on `tap`. Note that multiple actions are not supported on stock Picture Elements, see [actions](configuration/actions.md) for more information. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: custom:frigate-card-menu-icon + icon: mdi:chair-rolling + tap_action: + - action: custom:frigate-card-action + frigate_card_action: camera_select + camera: camera.office + - action: custom:frigate-card-action + frigate_card_action: live +``` + +## Multiple providers + +Cameras can be repeated with different providers (note the required use of `id` +to provide a separate unambiguous way of referring to that camera, since the +`camera_entity` is shared between the two cameras). + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + live_provider: jsmpeg + title: Office (JSMPEG) + - camera_entity: camera.office + live_provider: webrtc-card + title: Office (WebRTC) + id: office-webrtc +``` + +## Overriding configuration + +You can override card configuration when certain [conditions](configuration/conditions.md) are met. + +### Change menu position based on HA state + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +overrides: + - conditions: + - condition: state + entity: light.office_main_lights + state: 'on' + overrides: + menu: + position: bottom +``` + +### Change default view based on HA state + +This example changes the default card view from `live` to `image` depending on +the value of the `binary_sensor.alarm_armed` sensor. The override alone will +only change the _default_ when the card next is requested to change to the +default view. By also including the `update_entities` parameter, we ask the card +to trigger a card update based on that entity -- which causes it to use the new +overriden default immediately. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +view: + default: live + update_entities: + - binary_sensor.alarm_armed +overrides: + - conditions: + - condition: state + entity: binary_sensor.alarm_armed + state: 'off' + overrides: + view: + default: image +``` + +### Change grid behavior in full screen + +This example will always render 5 columns in fullscreen mode in both the live +and media viewer views, and will not enlarge the selected item. The [normal auto-layout behavior](configuration/grid-layout-algorithm.md) will be used outside of fullscreen mode. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +overrides: + - conditions: + - condition: fullscreen + fullscreen: true + - condition: display_mode + display_mode: grid + overrides: + live: + display: + grid_columns: 5 + grid_selected_width_factor: 1 + media_viewer: + display: + grid_columns: 5 + grid_selected_width_factor: 1 +``` + +### Change menu style when expanded + +This example changes the menu style to `overlay` in expanded mode in order to +take advantage of the extra horizontal space of the dialog/popup. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +menu: + style: hidden +overrides: + - conditions: + - condition: expand + expand: true + overrides: + menu: + style: overlay +``` + +### Hide menu in fullscreen + +This example disables the menu unless the card is in fullscreen mode, and uses a +card-wide action to enable fullscreen mode on `double_tap`. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +view: + actions: + double_tap_action: + action: custom:frigate-card-action + frigate_card_action: fullscreen +overrides: + - conditions: + - condition: fullscreen + fullscreen: true + overrides: + menu: + style: none +``` + +## PTZ control + +The card supports using PTZ controls to conveniently control pan, tilt and zoom for cameras. This example shows the PTZ controls on the `live` view. Note that if your camera engine supports it (e.g. `frigate`) this will just work out of the box with no configuration at all. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +live: + ptz: + orientation: horizontal + service: sonoff.send_command + data_left: + device: '048123' + cmd: left + data_right: + device: '048123' + cmd: right + data_up: + device: '048123' + cmd: up + data_down: + device: '048123' + cmd: down +``` + +## `screen` conditions + +These examples show altering the card configuration based on device or viewport properties. + +### Change menu position when orientation changes + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + - camera_entity: camera.kitchen +menu: + style: overlay +overrides: + - conditions: + - condition: screen + media_query: '(orientation: landscape)' + overrides: + menu: + position: left +``` + +### Hide menu & controls when viewport width <= 300 (e.g. PIP mode) + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + - camera_entity: camera.kitchen +overrides: + - conditions: + - condition: screen + media_query: '(max-width: 300px)' + overrides: + menu: + style: none + live: + controls: + next_previous: + style: none + thumbnails: + mode: none +``` + +## State Badges + +You can add a state badge to the card showing arbitrary entity states. This +example adds a state badge showing the temperature and hides the label text: + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: state-badge + entity: sensor.office_temperature + style: + right: '-20px' + top: 100px + color: rgba(0,0,0,0) + opacity: 0.5 +``` + +![](images/picture-elements-temperature.png 'Picture elements temperature example :size=400') + +## Static images + +This example fetches a static image every 10 seconds (in this case the latest image saved on the Frigate server for a given camera). + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +view: + default: image +image: + src: https://my-friage-server/api/living_room/latest.jpg + refresh_seconds: 10 +``` + +## Submenus + +You can add submenus to the menu -- buttons that when pressed reveal a dropdown submenu of configurable options. + +### Basic submenu + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: custom:frigate-card-menu-submenu + icon: mdi:menu + items: + - title: Lights + icon: mdi:lightbulb + entity: light.office_main_lights + tap_action: + action: toggle + - title: Google + icon: mdi:google + tap_action: + action: url + url_path: https://www.google.com + - title: Fullscreen + icon: mdi:fullscreen + tap_action: + action: custom:frigate-card-action + frigate_card_action: fullscreen +``` + +### Conditional submenu + +This example shows submenus conditional on the camera selected. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: custom:frigate-card-conditional + conditions: + - condition: camera + cameras: + - camera.office + elements: + - type: custom:frigate-card-menu-submenu + icon: mdi:door + items: + - title: Office Lights + icon: mdi:lightbulb + entity: light.office_main_lights + tap_action: + action: toggle + - type: custom:frigate-card-conditional + conditions: + - condition: camera + cameras: + - camera.kitchen + elements: + - type: custom:frigate-card-menu-submenu + icon: mdi:sofa + items: + - title: Kitchen Lights + icon: mdi:lightbulb + entity: light.kitchen_lights + tap_action: + action: toggle + - title: Kitchen Lamp + icon: mdi:lightbulb + entity: light.kitchen_lamp + tap_action: + action: toggle +``` + +### `select` submenu + +You can easily add a submenu to the menu based on a `select` or `input_select` entity. This example imagines the user has an `input_select` entity configured in their Home Assistant configuration like so: + +```yaml +input_select: + office_scene: + name: Office Scene Select + options: + - scene.office_quiet_scene + - scene.office_party_scene + icon: mdi:lightbulb +``` + +The following will convert this entity into a submenu: + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: custom:frigate-card-menu-submenu-select + entity: input_select.office_scene +``` + +To override 1 or more individual options (e.g. to set custom icons and titles) + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: custom:frigate-card-menu-submenu-select + icon: mdi:lamps + entity: input_select.office_scene + options: + scene.office_quiet_scene: + icon: mdi:volume-off + title: Ssssssh + scene.office_party_scene: + icon: mdi:party-popper + title: Party! +``` + +## Substreams + +The card supports configuring 'substreams' (alternative live views) a given +camera through the use of [camera dependencies](configuration/cameras/README.md?id=dependencies). + +This example shows two substreams for a single live camera, and uses the 'HD' icon. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + live_provider: image + dependencies: + cameras: + - office_hd + - camera_entity: camera.office + title: Office HD + live_provider: go2rtc + id: office_hd + # This camera serves only as a substream. + capabilities: + disable_except: + - substream +menu: + buttons: + substreams: + icon: mdi:high-definition +``` + +## Trigger actions + +You can control the card itself with the `custom:frigate-card-action` action. +This example shows an icon that toggles the card fullscreen mode. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +elements: + - type: icon + icon: mdi:fullscreen + style: + left: 40px + top: 40px + tap_action: + action: custom:frigate-card-action + frigate_card_action: fullscreen +``` + +## Trigger fullscreen + +The card cannot automatically natively trigger fullscreen mode without the user +clicking, since Javascript (understandbly) prevents random websites from +triggering fullscreen mode without the user having activated it. + +This example uses +[hass-browser_mod](https://github.com/thomasloven/hass-browser_mod) with an +automation to trigger a popup. Thanks to +[conorlap@](https://github.com/conorlap) for the following example: + +```yaml +alias: >- + Doorbell Pressed OR Human Detected - Firefox browser full screen video feed + for 15 seconds +description: "" +trigger: + - platform: state + from: "off" + to: "on" + entity_id: + - binary_sensor.frontdoor_person_occupancy + - platform: state + entity_id: + - binary_sensor.front_door_dahua_button_pressed + to: "on" +condition: [] +action: + - service: browser_mod.popup + data: + size: wide + timeout: 15000 + content: + type: custom:frigate-card + aspect_ratio: 55% + cameras: + - camera_entity: camera.frontdoor + live_provider: ha + menu: + style: none + live: + controls: + title: + mode: none + target: + device_id: + - d0e93101edfg44y3yt35y5y45y54y +mode: single +``` + +## Trigger `live` + +This example will change to `live` when a camera is triggered, using different +trigger conditions per camera. It will change back to the `default` view when +untriggered. + +```yaml +type: custom:frigate-card +cameras: + # This is a Frigate camera which will automatically + # be triggered when events occur. + - camera_entity: camera.office + # This is a Frigate camera which will only be triggered + # by motion entity changes or a door being opened. + - camera_entity: camera.kitchen + triggers: + occupancy: false + motion: true + entities: + - binary_sensor.kitchen_door_opened + events: [] +view: + triggers: + show_trigger_status: true + filter_selected_camera: false + actions: + trigger: live + untrigger: default +``` + +## Video control from menu + +Disable the stock video controls and add menu button equivalents. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +live: + controls: + builtin: false +media_viewer: + controls: + builtin: false +menu: + buttons: + play: + enabled: true + mute: + enabled: true +``` + +## URL actions + +The card can respond to actions in the query string. See [URL Actions](usage/url-actions.md). + +?> These examples assume the dashboard URL is `https://ha.mydomain.org/lovelace-test/0` . + +### Choosing `clips` view on a named card + +This example assumes that one card (of potentially multiple Frigate Cards on the dashboard) is configured with a `card_id` parameter: + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +card_id: main +``` + +``` +https://ha.mydomain.org/lovelace-test/0?frigate-card-action.main.clips + +``` + +### Choosing the camera from a separate picture elements card + +In this example, the card will select a given camera when the user navigates from a *separate* Picture Elements card: + +Frigate Card configuration: + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + - camera_entity: camera.kitchen +``` + +Picture Elements configuration: + +```yaml +type: picture-elements +image: https://demo.home-assistant.io/stub_config/floorplan.png +elements: + - type: icon + icon: mdi:cctv + style: + top: 22% + left: 30% + tap_action: + action: navigate + navigation_path: /lovelace-test/0?frigate-card-action.camera_select=camera.office + - type: icon + icon: mdi:cctv + style: + top: 71% + left: 42% + tap_action: + action: navigate + navigation_path: /lovelace-test/0?frigate-card-action.camera_select=camera.kitchen +``` + +![](images/navigate-picture-elements.gif "Taking card actions via the URL :size=400" ) + + +### Selecting a camera in expanded mode via query string + +``` +https://ha.mydomain.org/lovelace-test/0?frigate-card-action.camera_select=kitchen&frigate-card-action.expand +``` + +## WebRTC Card configuration + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + live_provider: webrtc-card + webrtc_card: + ui: true +``` diff --git a/images/camera-carousel.gif b/docs/images/camera-carousel.gif similarity index 100% rename from images/camera-carousel.gif rename to docs/images/camera-carousel.gif diff --git a/images/card-on-nest-hub.jpg b/docs/images/card-on-nest-hub.jpg similarity index 100% rename from images/card-on-nest-hub.jpg rename to docs/images/card-on-nest-hub.jpg diff --git a/images/cast-your-events.gif b/docs/images/cast-your-events.gif similarity index 100% rename from images/cast-your-events.gif rename to docs/images/cast-your-events.gif diff --git a/images/dark-mode.gif b/docs/images/dark-mode.gif similarity index 100% rename from images/dark-mode.gif rename to docs/images/dark-mode.gif diff --git a/images/date-picker.gif b/docs/images/date-picker.gif similarity index 100% rename from images/date-picker.gif rename to docs/images/date-picker.gif diff --git a/images/editor.gif b/docs/images/editor.gif similarity index 100% rename from images/editor.gif rename to docs/images/editor.gif diff --git a/images/expanded.gif b/docs/images/expanded.gif similarity index 100% rename from images/expanded.gif rename to docs/images/expanded.gif diff --git a/images/frigate-logo.svg b/docs/images/frigate-logo.svg similarity index 100% rename from images/frigate-logo.svg rename to docs/images/frigate-logo.svg diff --git a/images/gallery.png b/docs/images/gallery.png similarity index 100% rename from images/gallery.png rename to docs/images/gallery.png diff --git a/images/grid-small.gif b/docs/images/grid-small.gif similarity index 100% rename from images/grid-small.gif rename to docs/images/grid-small.gif diff --git a/images/image-view.png b/docs/images/image-view.png similarity index 100% rename from images/image-view.png rename to docs/images/image-view.png diff --git a/images/live-thumbnails.gif b/docs/images/live-thumbnails.gif similarity index 100% rename from images/live-thumbnails.gif rename to docs/images/live-thumbnails.gif diff --git a/images/media-filtering.gif b/docs/images/media-filtering.gif similarity index 100% rename from images/media-filtering.gif rename to docs/images/media-filtering.gif diff --git a/images/media-layout-a.png b/docs/images/media-layout-a.png similarity index 100% rename from images/media-layout-a.png rename to docs/images/media-layout-a.png diff --git a/images/media-layout-b.png b/docs/images/media-layout-b.png similarity index 100% rename from images/media-layout-b.png rename to docs/images/media-layout-b.png diff --git a/images/menu-mode-above.png b/docs/images/menu-mode-above.png similarity index 100% rename from images/menu-mode-above.png rename to docs/images/menu-mode-above.png diff --git a/images/menu-mode-below.png b/docs/images/menu-mode-below.png similarity index 100% rename from images/menu-mode-below.png rename to docs/images/menu-mode-below.png diff --git a/images/menu-mode-hidden.png b/docs/images/menu-mode-hidden.png similarity index 100% rename from images/menu-mode-hidden.png rename to docs/images/menu-mode-hidden.png diff --git a/images/menu-mode-none.png b/docs/images/menu-mode-none.png similarity index 100% rename from images/menu-mode-none.png rename to docs/images/menu-mode-none.png diff --git a/images/menu-mode-overlay.png b/docs/images/menu-mode-overlay.png similarity index 100% rename from images/menu-mode-overlay.png rename to docs/images/menu-mode-overlay.png diff --git a/images/microphone.gif b/docs/images/microphone.gif similarity index 100% rename from images/microphone.gif rename to docs/images/microphone.gif diff --git a/images/motioneye.gif b/docs/images/motioneye.gif similarity index 100% rename from images/motioneye.gif rename to docs/images/motioneye.gif diff --git a/images/native-media-control.png b/docs/images/native-media-control.png similarity index 100% rename from images/native-media-control.png rename to docs/images/native-media-control.png diff --git a/images/native-ptz.gif b/docs/images/native-ptz.gif similarity index 100% rename from images/native-ptz.gif rename to docs/images/native-ptz.gif diff --git a/images/navigate-picture-elements.gif b/docs/images/navigate-picture-elements.gif similarity index 100% rename from images/navigate-picture-elements.gif rename to docs/images/navigate-picture-elements.gif diff --git a/images/picture_elements_temperature.png b/docs/images/picture-elements-temperature.png similarity index 100% rename from images/picture_elements_temperature.png rename to docs/images/picture-elements-temperature.png diff --git a/images/recording-seek-all-cameras.gif b/docs/images/recording-seek-all-cameras.gif similarity index 100% rename from images/recording-seek-all-cameras.gif rename to docs/images/recording-seek-all-cameras.gif diff --git a/images/recording-seek.gif b/docs/images/recording-seek.gif similarity index 100% rename from images/recording-seek.gif rename to docs/images/recording-seek.gif diff --git a/images/ribbon-timeline.png b/docs/images/ribbon-timeline.png similarity index 100% rename from images/ribbon-timeline.png rename to docs/images/ribbon-timeline.png diff --git a/images/star.gif b/docs/images/star.gif similarity index 100% rename from images/star.gif rename to docs/images/star.gif diff --git a/images/submenu-select.gif b/docs/images/submenu-select.gif similarity index 100% rename from images/submenu-select.gif rename to docs/images/submenu-select.gif diff --git a/images/submenu.gif b/docs/images/submenu.gif similarity index 100% rename from images/submenu.gif rename to docs/images/submenu.gif diff --git a/images/substream.gif b/docs/images/substream.gif similarity index 100% rename from images/substream.gif rename to docs/images/substream.gif diff --git a/images/thumbnails-in-drawer.gif b/docs/images/thumbnails-in-drawer.gif similarity index 100% rename from images/thumbnails-in-drawer.gif rename to docs/images/thumbnails-in-drawer.gif diff --git a/images/timeline.gif b/docs/images/timeline.gif similarity index 100% rename from images/timeline.gif rename to docs/images/timeline.gif diff --git a/images/triggered.gif b/docs/images/triggered.gif similarity index 100% rename from images/triggered.gif rename to docs/images/triggered.gif diff --git a/images/video-scrubbing.gif b/docs/images/video-scrubbing.gif similarity index 100% rename from images/video-scrubbing.gif rename to docs/images/video-scrubbing.gif diff --git a/images/viewer-thumbnails.gif b/docs/images/viewer-thumbnails.gif similarity index 100% rename from images/viewer-thumbnails.gif rename to docs/images/viewer-thumbnails.gif diff --git a/images/viewer-with-thumbnail-next-prev.gif b/docs/images/viewer-with-thumbnail-next-prev.gif similarity index 100% rename from images/viewer-with-thumbnail-next-prev.gif rename to docs/images/viewer-with-thumbnail-next-prev.gif diff --git a/images/webrtc.png b/docs/images/webrtc.png similarity index 100% rename from images/webrtc.png rename to docs/images/webrtc.png diff --git a/images/zoom.gif b/docs/images/zoom.gif similarity index 100% rename from images/zoom.gif rename to docs/images/zoom.gif diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 00000000..486a91cf --- /dev/null +++ b/docs/index.html @@ -0,0 +1,80 @@ + + + + + Frigate Card + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/screenshots.md b/docs/screenshots.md new file mode 100644 index 00000000..9feec540 --- /dev/null +++ b/docs/screenshots.md @@ -0,0 +1,142 @@ +# Screenshots + +## 2-way audio + +![](images/microphone.gif "2-way audio support :size=400") + +## Cast media from card + +![](images/cast-your-events.gif "Cast media from the card :size=400") + +## Cast whole card + +A dashboard with the card can be cast onto a suitable device (such as the Nest Hub shown below). + +![](images/card-on-nest-hub.jpg "Card casting :size=400") + +## Dark mode + +![](images/dark-mode.gif "Dark mode :size=400") + +## Editing + +![](images/editor.gif "Card editing :size=400") + +## Events + +![](images/gallery.png "Full Viewing Of Events :size=400") + +## Expanded mode + +![](images/expanded.gif "Expanded mode :size=400") + +## Favoriting events + +![](images/star.gif "Card casting :size=400") + +## Filtering + +![](images/media-filtering.gif "Media filtering :size=400") + +## Grid + +![](images/grid-small.gif "Interacting with a camera grid :size=400") + +## Media layout + +Pan around a large camera view to only show part of the video feed in the card at a different aspect ratio: + +### Before + +![](images/media-layout-a.png "Before :size=400") + +### After + +![](images/media-layout-b.png "After :size=400") + +## Menu hovering + +![](images/viewer-with-thumbnail-next-prev.gif "Hover menu / Next & Previous controls :size=400") + +## Menu media control + +![](images/native-media-control.png "In-menu media / mute control :size=400") + +## Mixed engines + +![](images/motioneye.gif "Different camera sources/engines :size=400") + +## Multiple cameras + +Scroll through your live cameras, or choose from a menu. Seamlessly supports +cameras of different dimensions, and custom submenus per camera. + +![](images/camera-carousel.gif "Live viewing of multiple cameras :size=400") + +## PTZ + +![](images/native-ptz.gif "PTZ control :size=400") + +## Recordings + +### Recordings single + +![](images/recording-seek.gif "Single camera recordings :size=400") + +### Recordings multiple + +![](images/recording-seek-all-cameras.gif "Multiple camera recordings :size=400") + +## Scrubbing + +![](images/video-scrubbing.gif "Video scrubbing :size=400") + +## Submenus + +![](images/submenu.gif "Configurable submenus :size=400") + +## Submenus with `select` entities + +![](images/submenu-select.gif "select entity submenus :size=400") + +## Substreams + +![](images/substream.gif "Substreams :size=400") + +## Thumbnail drawers + +![](images/thumbnails-in-drawer.gif "Thumbnail drawers :size=400") + +## Thumbnails in live + +![](images/live-thumbnails.gif "Live viewing with thumbnail carousel :size=400") + +## Thumbnails in media viewer + +![](images/viewer-thumbnails.gif "Clip viewing with thumbnail carousel :size=400") + +## Timeline + +![](images/timeline.gif "Event timeline :size=400") + +## Timeline date picking + +![](images/date-picker.gif "Timeline date picking :size=400") + +## Timeline `ribbon` + +![](images/ribbon-timeline.png "Ribbon timeline :size=400") + +## Triggering + +Automatically choose the camera with the action! + +![](images/triggered.gif "Triggered! :size=400") + +## URL actions + +![](images/navigate-picture-elements.gif "Taking card actions via the URL :size=400") + +## Zoom + +![](images/zoom.gif "Zoom support :size=400") diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 00000000..b6841665 --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,222 @@ +# Troubleshooting + +### 2-way audio doesn't work + +There are many requirements for 2-way audio to work. See [Using 2-way +audio](usage/2-way-audio.md) for more information about these. If your +microphone still does not work and you believe you meet all the requirements try +eliminating the card from the picture by going directly to the `go2rtc` UI, +navigating to `links` for your given stream, then to `webrtc.html` with a +microphone. If this does not work correctly with 2-way audio then your issue is +with `go2rtc` not with the card. In this case, you could file an issue in [that +repo](https://github.com/AlexxIT/go2rtc/issues) with debugging information as +appropriate. + +### Android will not render >4 JSMPEG live views + +Android Webview (as used by Android Chrome / Android Home Assistant Companion) +appears to severely limit the number of simultaneous OpenGL contexts that can be +opened. The JSMPEG player (that this card uses), consumes 1 OpenGL context per +rendering. + +This limitation may be worked around (at a performance penalty) by disabling +OpenGL for JSMPEG live views: + +```yaml +live: + jsmpeg: + options: + disableGl: true +``` + +[This bug](https://github.com/dermotduffy/frigate-hass-card/issues/191) has some +more discussion on this topic. New ideas to address this underlying limitation +most welcome! + +### Autoplay in Chrome when a tab becomes visible again + +Even if `live.auto_play` or `media_viewer.auto_play` is set to `[]`, Chrome +itself will still auto play a video that was previously playing prior to the tab +being hidden, once that tab is visible again. This behavior cannot be influenced +by the card. Other browsers (e.g. Firefox, Safari) do not exhibit this behavior. + +### Blank white image on `live` view + +For some slowly loading cameras, for which [Home Assistant stream +preloading](https://www.home-assistant.io/integrations/camera/) is not enabled, +Home Assistant may return a blank white image when asked for a still. These +stills are used during initial Frigate card load of the `live` view if the +`live.show_image_during_load` option is enabled. Disabling this option should +show the default media loading controls (e.g. a spinner or empty video player) +instead of the blank white image. + +### Casting to Chromecast broken + +This could be for any number of reasons. Chromecast devices can be quite picky +on network, DNS and certificate issues, as well as audio and video codecs. Check +your Home Assistant log as there may be more information in there. + +!>: In particular, for Frigate to support casting of clips, the default ffmpeg +settings for Frigate must be modified, i.e. Frigate does not encode clips in a +Chromecast compatible format out of the box (specifically: audio must be enabled +in the AAC codec, whether your camera supports audio or not). See the [Frigate +Home Assistant +documentation](https://docs.frigate.video/integrations/home-assistant) or [this +issue](https://github.com/blakeblackshear/frigate/issues/3175) for more. + +### Custom element does not exist + +This is usually a sign that the card is not correctly installed (i.e. the +browser cannot find the Javascript). In cases where it works in some browsers / +devices but not in others it may simply be an old browser / webview that does +not support modern Javascript (this is occasionally seen on old Android +hardware). In this latter case, you are out of luck. + +### `double_tap` does not work in Android + +The Android video player swallows `double_tap` interactions in order to +rewind or fast-forward. Workarounds: + +* Use `hold` instead of `double_tap` for your card-wide action. +* Use a [Frigate Card Element](configuration/elements.md) or menu icon to trigger + the action instead. + +### Dragging in carousels broken in Firefox + +The Firefox video player swallows mouse interactions, so dragging is not +possible in carousels that use the Firefox video player (e.g. `clips` carousel, +or live views that use the `frigate` or `webrtc-card` provider). The next and +previous buttons may be used to navigate in these instances. + +Dragging works as expected for snapshots, or for the `jsmpeg` provider. + +### Dragging video control doesn't work in Safari + +Dragging the Safari video controls "progress bar" conflicts with carousel +"dragging", meaning the video controls progress bar cannot be moved left or +right. Turning off carousel dragging (and using next/previous controls) will +return full video controls in Safari: + +```yaml +live: + draggable: false +media_viewer: + draggable: false +``` + +### Downloads don't work + +Downloads are assembled by the Frigate backend out of ~10s segment files. You +must have enough cache space in your Frigate instance to allow this assembly to +happen -- if large downloads don't work, especially for recordings, check your +Frigate backend logs to see if it's running out of space. You can increase your +cache size with the `tmpfs` `size` argument, see [Frigate +documentation](https://docs.frigate.video/frigate/installation#docker). + +Large downloads may take a few seconds to assemble, so there may be a delay +between clicking the download button and the download starting. + +### `Forbidden media source identifier` + +* If you are using a custom `client_id` setting in your `frigate.yml` file (the + configuration file for the Frigate backend itself), you must tell the card + about it. See [Frigate engine + configuration](configuration/cameras/engine.md?id=frigate). +* You must have the `Enable the media browser` option enabled for the Frigate + integration, in order for media fetches to work for the card. Media fetches + are used to fetch events / clips / snapshots, etc. If you just wish to use + live streams without media fetches, you can use the following configuration: + +```yaml +live: + controls: + thumbnails: + mode: none +``` + +### Fullscreen doesn't work on iPhone + +Unfortunately, [iOS does not support the Javascript fullscreen +API](https://caniuse.com/fullscreen). As a result, card-level fullscreen support +for the iPhone is not currently possible. + +### iOS App not updating after card version change + +Try resetting the app frontend cache: + +* `Configuration -> Companion App -> Debugging -> Reset frontend cache` + +### Javascript console errors + +#### `[Violation] Added non-passive event listener to a scroll-blocking [...] event` + +This card uses [visjs](https://github.com/visjs/vis-timeline) -- a timeline +library -- to show camera timelines. This library currently uses non-passive +event-listeners. These warnings can be safely ignored in this instance and +cannot easily be fixed in the underlying library. + +### Microphone menu button not shown + +The microphone menu button will only appear if both enabled (see [Menu Button +configuration](configuration/menu.md?id=available-buttons)) and if the media +that is currently loaded supports 2-way audio. See [Using 2-way +audio](usage/2-way-audio.md) for more information about the requirements that +must be followed. + +### New version not working in Chrome + +When upgrading the card it's recommended to reset the frontend cache. Sometimes +clearing site data in Chrome settings isn't enough. + +* Press F12 to display `Dev Console` in Chrome then right click on the refresh + icon and select `Empty Cache and Hard Reload` + +### Static image URL with credentials doesn't load + +Your browser will not allow a page/script (like this card) to pass credentials +to a cross-origin (different host) image URL for security reasons. There is no +way around this unless you could also control the webserver that is serving the +image to specifically allow `crossorigin` requests (which is typically not the +case for an image served from a camera, for example). The stock Home Assistant +Picture Glance card has the same limitation, for the same reasons. + +### Title "Popups" continually popping up + +Title popups can be disabled for live or media viewer views with this +configuration: + +```yaml +live: + controls: + title: + mode: none +media_viewer: + controls: + title: + mode: none +``` + +### Watermark shown on livestream + +If the `live.show_image_during_load` option is enabled (the default), a +temporary image from Home Assistant is rendered and refreshed every `1s` while +the full stream is loading. When this temporary image is being shown, a small +circular icon is rendered on the top-right of the livestream to indicate to the +user that this is not the true stream. If the icon persists, it means your +underlying stream is not actually loading and may be misconfigured / broken. + +### `webrtc_card` unloads in the background + +[AlexxIT's WebRTC Card](https://github.com/AlexxIT/WebRTC) which is embedded by +the `webrtc_card` live provider internally disconnects the stream when the +browser tab is changed (regardless of any Frigate card configuration settings, +e.g. `lazy_unload`). To allow the stream to continue running in the background, +pass the `background` argument to the `webrtc_card` live provider as shown +below. This effectively allows the Frigate card to decide whether or not to +unload the stream. + +```yaml +live: + webrtc_card: + background: true +``` diff --git a/docs/usage/2-way-audio.md b/docs/usage/2-way-audio.md new file mode 100644 index 00000000..2dbd366c --- /dev/null +++ b/docs/usage/2-way-audio.md @@ -0,0 +1,53 @@ +# 2-way Audio + +This card supports 2-way audio (e.g. transmitting audio from a microphone to a +suitably equipped camera). In general, due to the myriad of different cameras, +security requirements and browser limitations getting 2-way to work may be +challenging. + +## Requirements + +### Environmental requirements + + * Must have a camera that supports audio out (otherwise what's the point!) + * Camera must be supported by `go2rtc` for 2-way audio (see [supported cameras](https://github.com/AlexxIT/go2rtc#two-way-audio)). + * Must be accessing your Home Assistant instance over `https`. The browser will enforce this. + +### Card requirements + + * Only Frigate cameras are supported. + * Only the `go2rtc` live provider is supported. + * Only the `webrtc` mode supports 2-way audio: + * Must have microphone menu button enabled: + +## Example configuration + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + live_provider: go2rtc + go2rtc: + modes: + - webrtc +menu: + buttons: + microphone: + enabled: true +``` + +## Usage + + * The camera will always load *without* the microphone connected, unless the + [`always_connected`](../configuration/live.md?id=microphone) microphone option is + set to `true`. + * To speak, hold-down the microphone menu button. + * On first press, this will reset the `webrtc` connection to include 2-way + audio unless [`always_connected`](../configuration/live.md?id=microphone) has + been used. + * Thereafter hold the microphone button down to unmute/speak, let go to + mute. + * The video will automatically reset to remove the microphone after the number + of seconds specified by + [`disconnect_seconds`](../configuration/live.md?id=microphone) configuration have + elapsed since the last mute/unmute press. diff --git a/docs/usage/README.md b/docs/usage/README.md new file mode 100644 index 00000000..e0b8ac79 --- /dev/null +++ b/docs/usage/README.md @@ -0,0 +1,16 @@ +# Usage + +The usage of the card is intended to be reasonably self-explanatory. Some more +complex situations / requirements are discussed here. + +### 2-way audio + +See [2-way audio](2-way-audio.md) for documentation on using 2-way audio. + +### Casting + +See [Casting](casting.md) for documentation on casting the card. + +### URL Actions + +See [URL Actions](url-actions.md) for documentation on acting based on URL contents. diff --git a/docs/usage/_sidebar.md b/docs/usage/_sidebar.md new file mode 100644 index 00000000..9b69f6a3 --- /dev/null +++ b/docs/usage/_sidebar.md @@ -0,0 +1,13 @@ +* [Getting Started](../README.md) +* [Configuration](../configuration/README.md) +* [Examples](../examples.md) +* [Screenshots](../screenshots.md) +* [Troubleshooting](../troubleshooting.md) +* [Usage](README.md) + * [2-way audio](2-way-audio.md) + * [Casting](casting.md) + * [URL Actions](url-actions.md) + +--- + +* [Developing](../developing.md) \ No newline at end of file diff --git a/docs/usage/casting.md b/docs/usage/casting.md new file mode 100644 index 00000000..d136944b --- /dev/null +++ b/docs/usage/casting.md @@ -0,0 +1,45 @@ +# Casting the Card + +This card can be (Chrome) casted to a device (such as a [Nest +Hub](https://store.google.com/us/product/nest_hub_2nd_gen)) through the use of +[Home Assistant Cast](https://cast.home-assistant.io/). + +## Instructions + +* Visit [Home Assistant Cast](https://cast.home-assistant.io/) and click `Start Casting` +* Enter your Home Assistant URL, and authorize your account. +* Click `Start Casting` and choose the device to cast to from the browser menu. +* Choose which view/dashboard to display. +* If successful, the view will be cast to the device. + +## Limitations + +Casting Home Assistant dashboards comes with a number of caveats: + +* Home Assistant Casting does not support the HA `streaming` component + ([source](https://cast.home-assistant.io/faq.html)). This means clips playing + and the `ha` live provider can not work. Other live providers such as `jsmpeg` + and `webrtc-card` function correctly. +* The Javascript fullscreen API does not work (so the fullscreen button does not + work, but see below for an equivalent). + +## Recommended configuration for Nest Hub + +Using a `panel` dashboard with the following base configuration will result in +the card consuming the entire device screen: + +### Configuration + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + live_provider: go2rtc +dimensions: + aspect_ratio: 1024:600 + aspect_ratio_mode: static +``` + +### Result + +![](../images/card-on-nest-hub.jpg "Casting on a Nest Hub :size=400") diff --git a/docs/usage/url-actions.md b/docs/usage/url-actions.md new file mode 100644 index 00000000..0dbbcbd8 --- /dev/null +++ b/docs/usage/url-actions.md @@ -0,0 +1,77 @@ +# URL Actions + +It is possible to pass the Frigate card one or more +[actions](../configuration/actions.md) from the URL (e.g. select a particular +camera, open the live view in expanded mode, etc). + +### When actions are executed + +The Frigate card will execute these actions in the following circumstances: + +* On initial card load. +* On 'tab' change in a dashboard. +* When a `navigate` [action](https://www.home-assistant.io/dashboards/actions/) + is called on the dashboard (e.g. a button click requests navigation). +* When the user uses the `back` / `forward` browser buttons whilst viewing a + dashboard. + +## Instructions + +To send an action to *all* Frigate Cards on a dashboard: + +``` +[PATH_TO_YOUR_HA_DASHBOARD]?frigate-card-action.[ACTION]=[VALUE] +``` + +To send an action to a specific named Frigate Card: + +``` +[PATH_TO_YOUR_HA_DASHBOARD]?frigate-card-action.[CARD_ID].[ACTION]=[VALUE] +``` + +| Parameter | Description | +| - | - | +| `ACTION` | One of the supported Frigate Card custom actions. See below. | +| `CARD_ID` | When specified only cards that have a [`card_id`](../configuration/README.md) parameter will act. | +| `VALUE` | An optional value to use with the `camera_select` and `live_substream_select` actions. | + +?> Both `.` and `:` may be used as the delimiter. If you use `:` some +browsers may require it be escaped to `%3A`. + +!> If a dashboard has multiple Frigate cards on it, even if they are on +different 'tabs' within that dashboard, they will all respond to the actions +unless the action is targeted with a `CARD_ID` as shown above. + +## Supported Actions + +Only a subset of all [actions](../configuration/actions.md) are supported in URL form. + +| Action | Supported in URL | Explanation | +| - | - | - | +| `camera_select` | :white_check_mark: | | +| `camera_ui`| :white_check_mark: | | +| `clip` | :white_check_mark: | | +| `clips` | :white_check_mark: | | +| `default` | :white_check_mark: | | +| `download`| :heavy_multiplication_x: | Latest media information is not available on initial render. | +| `expand` | :white_check_mark: | | +| `fullscreen` | :heavy_multiplication_x: | Javascript does not support activating fullscreen without direct human interaction. Use `expand` as an alternative. | +| `image` | :white_check_mark: | | +| `live_substream_select` | :white_check_mark: | | +| `live` | :white_check_mark: | | +| `media_player`| :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/frigate-hass-card/issues) if you need this. | +| `menu_toggle` | :white_check_mark: | | +| `microphone_mute`, `microphone_unmute`| :heavy_multiplication_x: | | +| `mute`, `unmute` | :heavy_multiplication_x: | | +| `play`, `pause` | :heavy_multiplication_x: | | +| `ptz` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/frigate-hass-card/issues) if you need this. | +| `recording` | :white_check_mark: | | +| `recordings` | :white_check_mark: | | +| `screenshot`| :heavy_multiplication_x: | Latest media information is not available on initial render. | +| `show_ptz` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/frigate-hass-card/issues) if you need this. | +| `snapshot` | :white_check_mark: | | +| `snapshots` | :white_check_mark: | | + +## Examples + +See [URL actions examples](../examples.md?id=url-actions). diff --git a/images/menu_clip.png b/images/menu_clip.png deleted file mode 100644 index 3c818d95196f5f6858e5870b5028fe75fb556d8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 298125 zcmXtYF!j(4o@eDsSGr{RjLLA|nBxWUPDyK6r!ZEDBXa z2L61IO~ZlrL@pAVE~@tCF78H7W^XL)>}}1MolTs~%27kBsz|DLiw**?hm_LGVX;+fn7u;miBj)UT@oZQsl+ z#HDW4%+$>~ZuvSpPfxkKZ+)}DCLIJY^autdsOQ7k$Kvi!{=KWA1N1FY+#@09+%O+;uvsXDd4rfG#&ddlJ zlZ5lurOmfKw9AmKH4F@omq~wwp1OI^s-OmAS)v=^8Pk8Dr#2$oYQ=ySp!8r((iKb2 zr`vFfA{QkUPP}v6@E(l^qacfbBq(k)giHKC&_lO8UY`(dpGuC*?cUTQQBFeHAF`w- zGzz7-_&B`msB4%rDbSDuzqyQ5GewEh($P=7zcIU$>r;vM5fsA<`B`Pp#?3v_Cz~2x znAR62%f!O0%7iavlh6xoRY!p`kQ?D`K`<<1l2F%g<5i58xgr##6A)#!4qQ4fL-?Ty z)opdMI65FcH_-a+`4g8w)j%?%MzhNM8#2~<70oUjd;;iW}mR;}aCc!R+l5hs+0eo#+PMQm<3!Q=C1&<^4?XLoGWwAvhkB zmu8N%e(uvfmI`4eg)o$4#7UCDeNrC{Q@;D3T{2rV#OW%0Dmj0F8h-$uowo>cIJutJ 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
  • hmPLrv-+>@D{0 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 diff --git a/images/performance.png b/images/performance.png deleted file mode 100644 index c59f21bcdc6b50fd6f27f3d7d92cd87018068506..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16856 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

    6DtCJ#_gkQVSgY)*QfFPUD^JMNx~$@k;soj*I+S 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.0.0 <4.0.0": +"cheerio-select@npm:^2.1.0": + version: 2.1.0 + resolution: "cheerio-select@npm:2.1.0" + dependencies: + boolbase: "npm:^1.0.0" + css-select: "npm:^5.1.0" + css-what: "npm:^6.1.0" + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + domutils: "npm:^3.0.1" + checksum: 10c0/2242097e593919dba4aacb97d7b8275def8b9ec70b00aa1f43335456870cfc9e284eae2080bdc832ed232dabb9eefcf56c722d152da4a154813fb8814a55d282 + languageName: node + linkType: hard + +"cheerio@npm:^1.0.0-rc.10": + version: 1.0.0-rc.12 + resolution: "cheerio@npm:1.0.0-rc.12" + dependencies: + cheerio-select: "npm:^2.1.0" + dom-serializer: "npm:^2.0.0" + domhandler: "npm:^5.0.3" + domutils: "npm:^3.0.1" + htmlparser2: "npm:^8.0.1" + parse5: "npm:^7.0.0" + parse5-htmlparser2-tree-adapter: "npm:^7.0.0" + checksum: 10c0/c85d2f2461e3f024345b78e0bb16ad8e41492356210470dd1e7d5a91391da9fcf6c0a7cb48a9ba8820330153f0cedb4d0a60c7af15d96ecdb3092299b9d9c0cc + languageName: node + linkType: hard + +"chokidar@npm:>=3.0.0 <4.0.0, chokidar@npm:^3.5.0": version: 3.6.0 resolution: "chokidar@npm:3.6.0" dependencies: @@ -1984,6 +2184,13 @@ __metadata: languageName: node linkType: hard +"ci-info@npm:^2.0.0": + version: 2.0.0 + resolution: "ci-info@npm:2.0.0" + checksum: 10c0/8c5fa3830a2bcee2b53c2e5018226f0141db9ec9f7b1e27a5c57db5512332cde8a0beb769bcbaf0d8775a78afbf2bb841928feca4ea6219638a5b088f9884b46 + languageName: node + linkType: hard + "clean-stack@npm:^2.0.0": version: 2.2.0 resolution: "clean-stack@npm:2.2.0" @@ -1991,6 +2198,24 @@ __metadata: languageName: node linkType: hard +"cli-boxes@npm:^2.2.0": + version: 2.2.1 + resolution: "cli-boxes@npm:2.2.1" + checksum: 10c0/6111352edbb2f62dbc7bfd58f2d534de507afed7f189f13fa894ce5a48badd94b2aa502fda28f1d7dd5f1eb456e7d4033d09a76660013ef50c7f66e7a034f050 + languageName: node + linkType: hard + +"cliui@npm:^6.0.0": + version: 6.0.0 + resolution: "cliui@npm:6.0.0" + dependencies: + string-width: "npm:^4.2.0" + strip-ansi: "npm:^6.0.0" + wrap-ansi: "npm:^6.2.0" + checksum: 10c0/35229b1bb48647e882104cac374c9a18e34bbf0bace0e2cf03000326b6ca3050d6b59545d91e17bfe3705f4a0e2988787aa5cde6331bf5cbbf0164732cef6492 + languageName: node + linkType: hard + "cliui@npm:^8.0.1": version: 8.0.1 resolution: "cliui@npm:8.0.1" @@ -2002,6 +2227,15 @@ __metadata: languageName: node linkType: hard +"clone-response@npm:^1.0.2": + version: 1.0.3 + resolution: "clone-response@npm:1.0.3" + dependencies: + mimic-response: "npm:^1.0.0" + checksum: 10c0/06a2b611824efb128810708baee3bd169ec9a1bf5976a5258cd7eb3f7db25f00166c6eee5961f075c7e38e194f373d4fdf86b8166ad5b9c7e82bbd2e333a6087 + languageName: node + linkType: hard + "code-block-writer@npm:^11.0.0": version: 11.0.3 resolution: "code-block-writer@npm:11.0.3" @@ -2057,6 +2291,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^10.0.1": + version: 10.0.1 + resolution: "commander@npm:10.0.1" + checksum: 10c0/53f33d8927758a911094adadda4b2cbac111a5b377d8706700587650fd8f45b0bbe336de4b5c3fe47fd61f420a3d9bd452b6e0e6e5600a7e74d7bf0174f6efe3 + languageName: node + linkType: hard + "commander@npm:^2.20.0, commander@npm:^2.20.3": version: 2.20.3 resolution: "commander@npm:2.20.3" @@ -2099,6 +2340,20 @@ __metadata: languageName: node linkType: hard +"configstore@npm:^5.0.1": + version: 5.0.1 + resolution: "configstore@npm:5.0.1" + dependencies: + dot-prop: "npm:^5.2.0" + graceful-fs: "npm:^4.1.2" + make-dir: "npm:^3.0.0" + unique-string: "npm:^2.0.0" + write-file-atomic: "npm:^3.0.0" + xdg-basedir: "npm:^4.0.0" + checksum: 10c0/5af23830e78bdc56cbe92a2f81e87f1d3a39e96e51a0ab2a8bc79bbbc5d4440a48d92833b3fd9c6d34b4a9c4c5853c8487b8e6e68593e7ecbc7434822f7aced3 + languageName: node + linkType: hard + "confusing-browser-globals@npm:^1.0.10": version: 1.0.11 resolution: "confusing-browser-globals@npm:1.0.11" @@ -2106,6 +2361,32 @@ __metadata: languageName: node linkType: hard +"connect-history-api-fallback@npm:^1.6.0": + version: 1.6.0 + resolution: "connect-history-api-fallback@npm:1.6.0" + checksum: 10c0/6d59c68070fcb2f6d981992f88d050d7544e8e1af6600c23ad680d955e316216794a742a1669d1f14ed5171fc628b916f8a4e15c5a1e55bffc8ccc60bfeb0b2c + languageName: node + linkType: hard + +"connect-livereload@npm:^0.6.0": + version: 0.6.1 + resolution: "connect-livereload@npm:0.6.1" + checksum: 10c0/703b36996ed6ff928744dd35881d624574dcd7c56e8e5a800fa6125e7892daa80f400a48d74a004ca514c666e9e94cdf5043648059181f3579dd51e3e2c19b36 + languageName: node + linkType: hard + +"connect@npm:^3.6.0": + version: 3.7.0 + resolution: "connect@npm:3.7.0" + dependencies: + debug: "npm:2.6.9" + finalhandler: "npm:1.1.2" + parseurl: "npm:~1.3.3" + utils-merge: "npm:1.0.1" + checksum: 10c0/f120c6116bb16a0a7d2703c0b4a0cd7ed787dc5ec91978097bf62aa967289020a9f41a9cd3c3276a7b92aaa36f382d2cd35fed7138fd466a55c8e9fdbed11ca8 + languageName: node + linkType: hard + "convert-source-map@npm:^2.0.0": version: 2.0.0 resolution: "convert-source-map@npm:2.0.0" @@ -2126,6 +2407,18 @@ __metadata: languageName: node linkType: hard +"cp-file@npm:^7.0.0": + version: 7.0.0 + resolution: "cp-file@npm:7.0.0" + dependencies: + graceful-fs: "npm:^4.1.2" + make-dir: "npm:^3.0.0" + nested-error-stacks: "npm:^2.0.0" + p-event: "npm:^4.1.0" + checksum: 10c0/db3ef3e3e466742f392ae71edb9b2cdbb314e855d97630a65de57bc1097bacf6e844f6d9d44882b8678c0de26ba7e656c2c915960435970067823372e807eafa + languageName: node + linkType: hard + "cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3": version: 7.0.3 resolution: "cross-spawn@npm:7.0.3" @@ -2137,6 +2430,13 @@ __metadata: languageName: node linkType: hard +"crypto-random-string@npm:^2.0.0": + version: 2.0.0 + resolution: "crypto-random-string@npm:2.0.0" + checksum: 10c0/288589b2484fe787f9e146f56c4be90b940018f17af1b152e4dde12309042ff5a2bf69e949aab8b8ac253948381529cc6f3e5a2427b73643a71ff177fa122b37 + languageName: node + linkType: hard + "crypto@npm:^1.0.1": version: 1.0.1 resolution: "crypto@npm:1.0.1" @@ -2166,6 +2466,19 @@ __metadata: languageName: node linkType: hard +"css-select@npm:^5.1.0": + version: 5.1.0 + resolution: "css-select@npm:5.1.0" + dependencies: + boolbase: "npm:^1.0.0" + css-what: "npm:^6.1.0" + domhandler: "npm:^5.0.2" + domutils: "npm:^3.0.1" + nth-check: "npm:^2.0.1" + checksum: 10c0/551c60dba5b54054741032c1793b5734f6ba45e23ae9e82761a3c0ed1acbb8cfedfa443aaba3a3c1a54cac12b456d2012a09d2cd5f0e82e430454c1b9d84d500 + languageName: node + linkType: hard + "css-tree@npm:^1.1.2, css-tree@npm:^1.1.3": version: 1.1.3 resolution: "css-tree@npm:1.1.3" @@ -2176,7 +2489,7 @@ __metadata: languageName: node linkType: hard -"css-what@npm:^6.0.1": +"css-what@npm:^6.0.1, css-what@npm:^6.1.0": version: 6.1.0 resolution: "css-what@npm:6.1.0" checksum: 10c0/a09f5a6b14ba8dcf57ae9a59474722e80f20406c53a61e9aedb0eedc693b135113ffe2983f4efc4b5065ae639442e9ae88df24941ef159c218b231011d733746 @@ -2278,6 +2591,13 @@ __metadata: languageName: node linkType: hard +"data-uri-to-buffer@npm:^6.0.2": + version: 6.0.2 + resolution: "data-uri-to-buffer@npm:6.0.2" + checksum: 10c0/f76922bf895b3d7d443059ff278c9cc5efc89d70b8b80cd9de0aa79b3adc6d7a17948eefb8692e30398c43635f70ece1673d6085cc9eba2878dbc6c6da5292ac + languageName: node + linkType: hard + "data-urls@npm:^4.0.0": version: 4.0.0 resolution: "data-urls@npm:4.0.0" @@ -2307,7 +2627,16 @@ __metadata: languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4": +"debug@npm:2.6.9": + version: 2.6.9 + resolution: "debug@npm:2.6.9" + dependencies: + ms: "npm:2.0.0" + checksum: 10c0/121908fb839f7801180b69a7e218a40b5a0b718813b886b7d6bdb82001b931c938e2941d1e4450f33a1b1df1da653f5f7a0440c197f29fbf8a6e9d45ff6ef589 + languageName: node + linkType: hard + +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": version: 4.3.4 resolution: "debug@npm:4.3.4" dependencies: @@ -2328,6 +2657,13 @@ __metadata: languageName: node linkType: hard +"decamelize@npm:^1.2.0": + version: 1.2.0 + resolution: "decamelize@npm:1.2.0" + checksum: 10c0/85c39fe8fbf0482d4a1e224ef0119db5c1897f8503bcef8b826adff7a1b11414972f6fef2d7dec2ee0b4be3863cf64ac1439137ae9e6af23a3d8dcbe26a5b4b2 + languageName: node + linkType: hard + "decimal.js@npm:^10.4.3": version: 10.4.3 resolution: "decimal.js@npm:10.4.3" @@ -2342,6 +2678,15 @@ __metadata: languageName: node linkType: hard +"decompress-response@npm:^3.3.0": + version: 3.3.0 + resolution: "decompress-response@npm:3.3.0" + dependencies: + mimic-response: "npm:^1.0.0" + checksum: 10c0/5ffaf1d744277fd51c68c94ddc3081cd011b10b7de06637cccc6ecba137d45304a09ba1a776dee1c47fccc60b4a056c4bc74468eeea798ff1f1fca0024b45c9d + languageName: node + linkType: hard + "deep-eql@npm:^4.1.3": version: 4.1.3 resolution: "deep-eql@npm:4.1.3" @@ -2351,6 +2696,13 @@ __metadata: languageName: node linkType: hard +"deep-extend@npm:^0.6.0": + version: 0.6.0 + resolution: "deep-extend@npm:0.6.0" + checksum: 10c0/1c6b0abcdb901e13a44c7d699116d3d4279fdb261983122a3783e7273844d5f2537dc2e1c454a23fcf645917f93fbf8d07101c1d03c015a87faa662755212566 + languageName: node + linkType: hard + "deep-is@npm:^0.1.3": version: 0.1.4 resolution: "deep-is@npm:0.1.4" @@ -2365,6 +2717,13 @@ __metadata: languageName: node linkType: hard +"defer-to-connect@npm:^1.0.1": + version: 1.1.3 + resolution: "defer-to-connect@npm:1.1.3" + checksum: 10c0/9feb161bd7d21836fdff31eba79c2b11b7aaf844be58faf727121f8b0d9c2e82b494560df0903f41b52dd75027dc7c9455c11b3739f3202b28ca92b56c8f960e + languageName: node + linkType: hard + "define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.2, define-data-property@npm:^1.1.4": version: 1.1.4 resolution: "define-data-property@npm:1.1.4" @@ -2394,6 +2753,17 @@ __metadata: languageName: node linkType: hard +"degenerator@npm:^5.0.0": + version: 5.0.1 + resolution: "degenerator@npm:5.0.1" + dependencies: + ast-types: "npm:^0.13.4" + escodegen: "npm:^2.1.0" + esprima: "npm:^4.0.1" + checksum: 10c0/e48d8a651edeb512a648711a09afec269aac6de97d442a4bb9cf121a66877e0eec11b9727100a10252335c0666ae1c84a8bc1e3a3f47788742c975064d2c7b1c + languageName: node + linkType: hard + "delayed-stream@npm:~1.0.0": version: 1.0.0 resolution: "delayed-stream@npm:1.0.0" @@ -2401,6 +2771,13 @@ __metadata: languageName: node linkType: hard +"depd@npm:2.0.0": + version: 2.0.0 + resolution: "depd@npm:2.0.0" + checksum: 10c0/58bd06ec20e19529b06f7ad07ddab60e504d9e0faca4bd23079fac2d279c3594334d736508dc350e06e510aba5e22e4594483b3a6562ce7c17dd797f4cc4ad2c + languageName: node + linkType: hard + "desandro-matches-selector@npm:^2.0.0": version: 2.0.2 resolution: "desandro-matches-selector@npm:2.0.2" @@ -2408,6 +2785,13 @@ __metadata: languageName: node linkType: hard +"destroy@npm:1.2.0": + version: 1.2.0 + resolution: "destroy@npm:1.2.0" + checksum: 10c0/bd7633942f57418f5a3b80d5cb53898127bcf53e24cdf5d5f4396be471417671f0fee48a4ebe9a1e9defbde2a31280011af58a57e090ff822f589b443ed4e643 + languageName: node + linkType: hard + "diff-sequences@npm:^29.6.3": version: 29.6.3 resolution: "diff-sequences@npm:29.6.3" @@ -2424,6 +2808,60 @@ __metadata: languageName: node linkType: hard +"docsify-cli@npm:^4.4.4": + version: 4.4.4 + resolution: "docsify-cli@npm:4.4.4" + dependencies: + chalk: "npm:^2.4.2" + connect: "npm:^3.6.0" + connect-history-api-fallback: "npm:^1.6.0" + connect-livereload: "npm:^0.6.0" + cp-file: "npm:^7.0.0" + docsify: "npm:^4.12.2" + docsify-server-renderer: "npm:>=4.10.0" + enquirer: "npm:^2.3.6" + fs-extra: "npm:^8.1.0" + get-port: "npm:^5.0.0" + livereload: "npm:^0.9.2" + lru-cache: "npm:^5.1.1" + open: "npm:^6.4.0" + serve-static: "npm:^1.12.1" + update-notifier: "npm:^4.1.0" + yargonaut: "npm:^1.1.2" + yargs: "npm:^15.3.0" + bin: + docsify: bin/docsify + checksum: 10c0/2c5666e14fbf1906161c98441392be817e77ff7a6d70e5091b5f9c176a1bab5f65f2267596b468faaa55ca6025a7ab9186bc5156b363514949cdbc769e1b8bdf + languageName: node + linkType: hard + +"docsify-server-renderer@npm:>=4.10.0": + version: 4.13.1 + resolution: "docsify-server-renderer@npm:4.13.1" + dependencies: + debug: "npm:^4.3.3" + docsify: "npm:^4.12.4" + node-fetch: "npm:^2.6.6" + resolve-pathname: "npm:^3.0.0" + checksum: 10c0/1ce3db14d92553467eea31165c9ea48a0148f294be62eb4d04e147ac8e47fd0a469eda79bae34d29f0ceaef6d5f9a9d1a5efa835a9422e1b839a3ebac9ca9034 + languageName: node + linkType: hard + +"docsify@npm:^4.12.2, docsify@npm:^4.12.4": + version: 4.13.1 + resolution: "docsify@npm:4.13.1" + dependencies: + marked: "npm:^1.2.9" + medium-zoom: "npm:^1.0.6" + opencollective-postinstall: "npm:^2.0.2" + prismjs: "npm:^1.27.0" + strip-indent: "npm:^3.0.0" + tinydate: "npm:^1.3.0" + tweezer.js: "npm:^1.4.0" + checksum: 10c0/6767a9e5aa68da0fdf2de94cd27443bc067266a388e5d1104659c011821c3bdd51c6cf25c6186f2b2de057d75401b17ea73f1bd29ad5450201d57af63ae0c734 + languageName: node + linkType: hard + "doctrine@npm:^2.1.0": version: 2.1.0 resolution: "doctrine@npm:2.1.0" @@ -2453,7 +2891,18 @@ __metadata: languageName: node linkType: hard -"domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0": +"dom-serializer@npm:^2.0.0": + version: 2.0.0 + resolution: "dom-serializer@npm:2.0.0" + dependencies: + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.2" + entities: "npm:^4.2.0" + checksum: 10c0/d5ae2b7110ca3746b3643d3ef60ef823f5f078667baf530cec096433f1627ec4b6fa8c072f09d079d7cda915fd2c7bc1b7b935681e9b09e591e1e15f4040b8e2 + languageName: node + linkType: hard + +"domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0, domelementtype@npm:^2.3.0": version: 2.3.0 resolution: "domelementtype@npm:2.3.0" checksum: 10c0/686f5a9ef0fff078c1412c05db73a0dce096190036f33e400a07e2a4518e9f56b1e324f5c576a0a747ef0e75b5d985c040b0d51945ce780c0dd3c625a18cd8c9 @@ -2478,6 +2927,15 @@ __metadata: languageName: node linkType: hard +"domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": + version: 5.0.3 + resolution: "domhandler@npm:5.0.3" + dependencies: + domelementtype: "npm:^2.3.0" + checksum: 10c0/bba1e5932b3e196ad6862286d76adc89a0dbf0c773e5ced1eb01f9af930c50093a084eff14b8de5ea60b895c56a04d5de8bbc4930c5543d029091916770b2d2a + languageName: node + linkType: hard + "domutils@npm:^2.8.0": version: 2.8.0 resolution: "domutils@npm:2.8.0" @@ -2489,6 +2947,33 @@ __metadata: languageName: node linkType: hard +"domutils@npm:^3.0.1": + version: 3.1.0 + resolution: "domutils@npm:3.1.0" + dependencies: + dom-serializer: "npm:^2.0.0" + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + checksum: 10c0/342d64cf4d07b8a0573fb51e0a6312a88fb520c7fefd751870bf72fa5fc0f2e0cb9a3958a573610b1d608c6e2a69b8e9b4b40f0bfb8f87a71bce4f180cca1887 + languageName: node + linkType: hard + +"dot-prop@npm:^5.2.0": + version: 5.3.0 + resolution: "dot-prop@npm:5.3.0" + dependencies: + is-obj: "npm:^2.0.0" + checksum: 10c0/93f0d343ef87fe8869320e62f2459f7e70f49c6098d948cc47e060f4a3f827d0ad61e83cb82f2bd90cd5b9571b8d334289978a43c0f98fea4f0e99ee8faa0599 + languageName: node + linkType: hard + +"duplexer3@npm:^0.1.4": + version: 0.1.5 + resolution: "duplexer3@npm:0.1.5" + checksum: 10c0/02195030d61c4d6a2a34eca71639f2ea5e05cb963490e5bd9527623c2ac7f50c33842a34d14777ea9cbfd9bc2be5a84065560b897d9fabb99346058a5b86ca98 + languageName: node + linkType: hard + "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -2496,6 +2981,13 @@ __metadata: languageName: node linkType: hard +"ee-first@npm:1.1.1": + version: 1.1.1 + resolution: "ee-first@npm:1.1.1" + checksum: 10c0/b5bb125ee93161bc16bfe6e56c6b04de5ad2aa44234d8f644813cc95d861a6910903132b05093706de2b706599367c4130eb6d170f6b46895686b95f87d017b7 + languageName: node + linkType: hard + "electron-to-chromium@npm:^1.4.668": version: 1.4.690 resolution: "electron-to-chromium@npm:1.4.690" @@ -2542,6 +3034,13 @@ __metadata: languageName: node linkType: hard +"encodeurl@npm:~1.0.2": + version: 1.0.2 + resolution: "encodeurl@npm:1.0.2" + checksum: 10c0/f6c2387379a9e7c1156c1c3d4f9cb7bb11cf16dd4c1682e1f6746512564b053df5781029b6061296832b59fb22f459dbe250386d217c2f6e203601abb2ee0bec + languageName: node + linkType: hard + "encoding@npm:^0.1.13": version: 0.1.13 resolution: "encoding@npm:0.1.13" @@ -2551,6 +3050,25 @@ __metadata: languageName: node linkType: hard +"end-of-stream@npm:^1.1.0": + version: 1.4.4 + resolution: "end-of-stream@npm:1.4.4" + dependencies: + once: "npm:^1.4.0" + checksum: 10c0/870b423afb2d54bb8d243c63e07c170409d41e20b47eeef0727547aea5740bd6717aca45597a9f2745525667a6b804c1e7bede41f856818faee5806dd9ff3975 + languageName: node + linkType: hard + +"enquirer@npm:^2.3.6": + version: 2.4.1 + resolution: "enquirer@npm:2.4.1" + dependencies: + ansi-colors: "npm:^4.1.1" + strip-ansi: "npm:^6.0.1" + checksum: 10c0/43850479d7a51d36a9c924b518dcdc6373b5a8ae3401097d336b7b7e258324749d0ad37a1fcaa5706f04799baa05585cd7af19ebdf7667673e7694435fcea918 + languageName: node + linkType: hard + "entities@npm:^2.0.0": version: 2.2.0 resolution: "entities@npm:2.2.0" @@ -2558,7 +3076,7 @@ __metadata: languageName: node linkType: hard -"entities@npm:^4.4.0": +"entities@npm:^4.2.0, entities@npm:^4.4.0": version: 4.5.0 resolution: "entities@npm:4.5.0" checksum: 10c0/5b039739f7621f5d1ad996715e53d964035f75ad3b9a4d38c6b3804bb226e282ffeae2443624d8fdd9c47d8e926ae9ac009c54671243f0c3294c26af7cc85250 @@ -2778,7 +3296,21 @@ __metadata: languageName: node linkType: hard -"escape-string-regexp@npm:^1.0.5": +"escape-goat@npm:^2.0.0": + version: 2.1.1 + resolution: "escape-goat@npm:2.1.1" + checksum: 10c0/fc0ad656f89c05e86a9641a21bdc5ea37b258714c057430b68a834854fa3e5770cda7d41756108863fc68b1e36a0946463017b7553ac39eaaf64815be07816fc + languageName: node + linkType: hard + +"escape-html@npm:~1.0.3": + version: 1.0.3 + resolution: "escape-html@npm:1.0.3" + checksum: 10c0/524c739d776b36c3d29fa08a22e03e8824e3b2fd57500e5e44ecf3cc4707c34c60f9ca0781c0e33d191f2991161504c295e98f68c78fe7baa6e57081ec6ac0a3 + languageName: node + linkType: hard + +"escape-string-regexp@npm:^1.0.2, escape-string-regexp@npm:^1.0.5": version: 1.0.5 resolution: "escape-string-regexp@npm:1.0.5" checksum: 10c0/a968ad453dd0c2724e14a4f20e177aaf32bb384ab41b674a8454afe9a41c5e6fe8903323e0a1052f56289d04bd600f81278edf140b0fcc02f5cac98d0f5b5371 @@ -2792,7 +3324,7 @@ __metadata: languageName: node linkType: hard -"escodegen@npm:^2.0.0": +"escodegen@npm:^2.0.0, escodegen@npm:^2.1.0": version: 2.1.0 resolution: "escodegen@npm:2.1.0" dependencies: @@ -3059,6 +3591,13 @@ __metadata: languageName: node linkType: hard +"etag@npm:~1.8.1": + version: 1.8.1 + resolution: "etag@npm:1.8.1" + checksum: 10c0/12be11ef62fb9817314d790089a0a49fae4e1b50594135dcb8076312b7d7e470884b5100d249b28c18581b7fd52f8b485689ffae22a11ed9ec17377a33a08f84 + languageName: node + linkType: hard + "ev-emitter@npm:^1.0.0": version: 1.1.1 resolution: "ev-emitter@npm:1.1.1" @@ -3147,6 +3686,15 @@ __metadata: languageName: node linkType: hard +"figlet@npm:^1.1.1": + version: 1.7.0 + resolution: "figlet@npm:1.7.0" + bin: + figlet: bin/index.js + checksum: 10c0/bedd97fe5fa604002ae8c6bc0b08dea6f9701e0b268f42e601668956f50ff377ef592e24e182a6174a775abde9e2aa77697e324b8681619ae23bc85078439393 + languageName: node + linkType: hard + "file-entry-cache@npm:^6.0.1": version: 6.0.1 resolution: "file-entry-cache@npm:6.0.1" @@ -3172,6 +3720,21 @@ __metadata: languageName: node linkType: hard +"finalhandler@npm:1.1.2": + version: 1.1.2 + resolution: "finalhandler@npm:1.1.2" + dependencies: + debug: "npm:2.6.9" + encodeurl: "npm:~1.0.2" + escape-html: "npm:~1.0.3" + on-finished: "npm:~2.3.0" + parseurl: "npm:~1.3.3" + statuses: "npm:~1.5.0" + unpipe: "npm:~1.0.0" + checksum: 10c0/6a96e1f5caab085628c11d9fdceb82ba608d5e426c6913d4d918409baa271037a47f28fbba73279e8ad614f0b8fa71ea791d265e408d760793829edd8c2f4584 + languageName: node + linkType: hard + "find-cache-dir@npm:^3.3.2": version: 3.3.2 resolution: "find-cache-dir@npm:3.3.2" @@ -3183,7 +3746,7 @@ __metadata: languageName: node linkType: hard -"find-up@npm:^4.0.0": +"find-up@npm:^4.0.0, find-up@npm:^4.1.0": version: 4.1.0 resolution: "find-up@npm:4.1.0" dependencies: @@ -3260,6 +3823,13 @@ __metadata: languageName: node linkType: hard +"fresh@npm:0.5.2": + version: 0.5.2 + resolution: "fresh@npm:0.5.2" + checksum: 10c0/c6d27f3ed86cc5b601404822f31c900dd165ba63fff8152a3ef714e2012e7535027063bc67ded4cb5b3a49fa596495d46cacd9f47d6328459cf570f08b7d9e5a + languageName: node + linkType: hard + "frigate-hass-card@workspace:.": version: 0.0.0-use.local resolution: "frigate-hass-card@workspace:." @@ -3290,6 +3860,7 @@ __metadata: crypto: "npm:^1.0.1" date-fns: "npm:^2.29.2" date-fns-tz: "npm:^1.3.7" + docsify-cli: "npm:^4.4.4" embla-carousel: "npm:8.0.0-rc14" embla-carousel-wheel-gestures: "npm:8.0.0-rc04" eslint: "npm:^8.23.0" @@ -3302,6 +3873,7 @@ __metadata: keycharm: "npm:^0.4.0" lit: "npm:^3.1.2" lodash-es: "npm:^4.17.21" + markdown-link-check: "npm:^3.12.1" masonry-layout: "npm:^4.2.2" moment: "npm:^2.29.4" prettier: "npm:^2.6.0" @@ -3342,6 +3914,28 @@ __metadata: languageName: node linkType: hard +"fs-extra@npm:^11.2.0": + version: 11.2.0 + resolution: "fs-extra@npm:11.2.0" + dependencies: + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^6.0.1" + universalify: "npm:^2.0.0" + checksum: 10c0/d77a9a9efe60532d2e790e938c81a02c1b24904ef7a3efb3990b835514465ba720e99a6ea56fd5e2db53b4695319b644d76d5a0e9988a2beef80aa7b1da63398 + languageName: node + linkType: hard + +"fs-extra@npm:^8.1.0": + version: 8.1.0 + resolution: "fs-extra@npm:8.1.0" + dependencies: + graceful-fs: "npm:^4.2.0" + jsonfile: "npm:^4.0.0" + universalify: "npm:^0.1.0" + checksum: 10c0/259f7b814d9e50d686899550c4f9ded85c46c643f7fe19be69504888e007fcbc08f306fae8ec495b8b998635e997c9e3e175ff2eeed230524ef1c1684cc96423 + languageName: node + linkType: hard + "fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" @@ -3419,7 +4013,7 @@ __metadata: languageName: node linkType: hard -"get-caller-file@npm:^2.0.5": +"get-caller-file@npm:^2.0.1, get-caller-file@npm:^2.0.5": version: 2.0.5 resolution: "get-caller-file@npm:2.0.5" checksum: 10c0/c6c7b60271931fa752aeb92f2b47e355eac1af3a2673f47c9589e8f8a41adc74d45551c1bc57b5e66a80609f10ffb72b6f575e4370d61cc3f7f3aaff01757cde @@ -3446,6 +4040,13 @@ __metadata: languageName: node linkType: hard +"get-port@npm:^5.0.0": + version: 5.1.1 + resolution: "get-port@npm:5.1.1" + checksum: 10c0/2873877a469b24e6d5e0be490724a17edb39fafc795d1d662e7bea951ca649713b4a50117a473f9d162312cb0e946597bd0e049ed2f866e79e576e8e213d3d1c + languageName: node + linkType: hard + "get-size@npm:^2.0.2": version: 2.0.3 resolution: "get-size@npm:2.0.3" @@ -3453,6 +4054,24 @@ __metadata: languageName: node linkType: hard +"get-stream@npm:^4.1.0": + version: 4.1.0 + resolution: "get-stream@npm:4.1.0" + dependencies: + pump: "npm:^3.0.0" + checksum: 10c0/294d876f667694a5ca23f0ca2156de67da950433b6fb53024833733975d32582896dbc7f257842d331809979efccf04d5e0b6b75ad4d45744c45f193fd497539 + languageName: node + linkType: hard + +"get-stream@npm:^5.1.0": + version: 5.2.0 + resolution: "get-stream@npm:5.2.0" + dependencies: + pump: "npm:^3.0.0" + checksum: 10c0/43797ffd815fbb26685bf188c8cfebecb8af87b3925091dd7b9a9c915993293d78e3c9e1bce125928ff92f2d0796f3889b92b5ec6d58d1041b574682132e0a80 + languageName: node + linkType: hard + "get-stream@npm:^8.0.1": version: 8.0.1 resolution: "get-stream@npm:8.0.1" @@ -3471,6 +4090,18 @@ __metadata: languageName: node linkType: hard +"get-uri@npm:^6.0.1": + version: 6.0.3 + resolution: "get-uri@npm:6.0.3" + dependencies: + basic-ftp: "npm:^5.0.2" + data-uri-to-buffer: "npm:^6.0.2" + debug: "npm:^4.3.4" + fs-extra: "npm:^11.2.0" + checksum: 10c0/8d801c462cd5b9c171d4d9e5f17afce3d9ebfbbfb006a88e3e768ce0071a8e2e59ee1ce822915fc43b9d6b83fde7b8d1c9648330ae89778fa41ad774df8ee0ac + languageName: node + linkType: hard + "glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": version: 5.1.2 resolution: "glob-parent@npm:5.1.2" @@ -3518,6 +4149,15 @@ __metadata: languageName: node linkType: hard +"global-dirs@npm:^2.0.1": + version: 2.1.0 + resolution: "global-dirs@npm:2.1.0" + dependencies: + ini: "npm:1.3.7" + checksum: 10c0/2041e590e9d3af313a8a0c9d99eb751c187b4247701322b55786f524879046f4071d5930733f4e172d45ce064a986ecf13b965468e74e4e598cca3b130369c3c + languageName: node + linkType: hard + "globals@npm:^11.1.0": version: 11.12.0 resolution: "globals@npm:11.12.0" @@ -3566,7 +4206,26 @@ __metadata: languageName: node linkType: hard -"graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": +"got@npm:^9.6.0": + version: 9.6.0 + resolution: "got@npm:9.6.0" + dependencies: + "@sindresorhus/is": "npm:^0.14.0" + "@szmarczak/http-timer": "npm:^1.1.2" + cacheable-request: "npm:^6.0.0" + decompress-response: "npm:^3.3.0" + duplexer3: "npm:^0.1.4" + get-stream: "npm:^4.1.0" + lowercase-keys: "npm:^1.0.1" + mimic-response: "npm:^1.0.1" + p-cancelable: "npm:^1.0.0" + to-readable-stream: "npm:^1.0.0" + url-parse-lax: "npm:^3.0.0" + checksum: 10c0/5cb3111e14b48bf4fb8b414627be481ebfb14151ec867e80a74b6d1472489965b9c4f4ac5cf4f3b1f9b90c60a2ce63584d9072b16efd9a3171553e00afc5abc8 + languageName: node + linkType: hard + +"graceful-fs@npm:^4.1.2, graceful-fs@npm:^4.1.6, graceful-fs@npm:^4.2.0, graceful-fs@npm:^4.2.6": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 @@ -3580,6 +4239,15 @@ __metadata: languageName: node linkType: hard +"has-ansi@npm:^2.0.0": + version: 2.0.0 + resolution: "has-ansi@npm:2.0.0" + dependencies: + ansi-regex: "npm:^2.0.0" + checksum: 10c0/f54e4887b9f8f3c4bfefd649c48825b3c093987c92c27880ee9898539e6f01aed261e82e73153c3f920fde0db5bf6ebd58deb498ed1debabcb4bc40113ccdf05 + languageName: node + linkType: hard + "has-bigints@npm:^1.0.1, has-bigints@npm:^1.0.2": version: 1.0.2 resolution: "has-bigints@npm:1.0.2" @@ -3633,6 +4301,13 @@ __metadata: languageName: node linkType: hard +"has-yarn@npm:^2.1.0": + version: 2.1.0 + resolution: "has-yarn@npm:2.1.0" + checksum: 10c0/b5cab61b4129c2fc0474045b59705371b7f5ddf2aab8ba8725011e52269f017e06f75059a2c8a1d8011e9779c2885ad987263cfc6d1280f611c396b45fd5d74a + languageName: node + linkType: hard + "hasown@npm:^2.0.0, hasown@npm:^2.0.1": version: 2.0.1 resolution: "hasown@npm:2.0.1" @@ -3672,13 +4347,47 @@ __metadata: languageName: node linkType: hard -"http-cache-semantics@npm:^4.1.1": +"html-link-extractor@npm:^1.0.5": + version: 1.0.5 + resolution: "html-link-extractor@npm:1.0.5" + dependencies: + cheerio: "npm:^1.0.0-rc.10" + checksum: 10c0/04473e792c756323792d151845e9b859bf6cb7783182f23c2850223164d6914d969b752f56d728dd6f642ec348efbbfe64b556d387d232f63a24890ac00e192e + languageName: node + linkType: hard + +"htmlparser2@npm:^8.0.1": + version: 8.0.2 + resolution: "htmlparser2@npm:8.0.2" + dependencies: + domelementtype: "npm:^2.3.0" + domhandler: "npm:^5.0.3" + domutils: "npm:^3.0.1" + entities: "npm:^4.4.0" + checksum: 10c0/609cca85886d0bf2c9a5db8c6926a89f3764596877492e2caa7a25a789af4065bc6ee2cdc81807fe6b1d03a87bf8a373b5a754528a4cc05146b713c20575aab4 + languageName: node + linkType: hard + +"http-cache-semantics@npm:^4.0.0, http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" checksum: 10c0/ce1319b8a382eb3cbb4a37c19f6bfe14e5bb5be3d09079e885e8c513ab2d3cd9214902f8a31c9dc4e37022633ceabfc2d697405deeaf1b8f3552bb4ed996fdfc languageName: node linkType: hard +"http-errors@npm:2.0.0": + version: 2.0.0 + resolution: "http-errors@npm:2.0.0" + dependencies: + depd: "npm:2.0.0" + inherits: "npm:2.0.4" + setprototypeof: "npm:1.2.0" + statuses: "npm:2.0.1" + toidentifier: "npm:1.0.1" + checksum: 10c0/fc6f2715fe188d091274b5ffc8b3657bd85c63e969daa68ccb77afb05b071a4b62841acb7a21e417b5539014dff2ebf9550f0b14a9ff126f2734a7c1387f8e19 + languageName: node + linkType: hard + "http-proxy-agent@npm:^5.0.0": version: 5.0.0 resolution: "http-proxy-agent@npm:5.0.0" @@ -3690,7 +4399,7 @@ __metadata: languageName: node linkType: hard -"http-proxy-agent@npm:^7.0.0": +"http-proxy-agent@npm:^7.0.0, http-proxy-agent@npm:^7.0.1": version: 7.0.2 resolution: "http-proxy-agent@npm:7.0.2" dependencies: @@ -3710,7 +4419,7 @@ __metadata: languageName: node linkType: hard -"https-proxy-agent@npm:^7.0.1": +"https-proxy-agent@npm:^7.0.1, https-proxy-agent@npm:^7.0.2, https-proxy-agent@npm:^7.0.3": version: 7.0.4 resolution: "https-proxy-agent@npm:7.0.4" dependencies: @@ -3727,7 +4436,7 @@ __metadata: languageName: node linkType: hard -"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2": +"iconv-lite@npm:0.6.3, iconv-lite@npm:^0.6.2, iconv-lite@npm:^0.6.3": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" dependencies: @@ -3769,6 +4478,13 @@ __metadata: languageName: node linkType: hard +"import-lazy@npm:^2.1.0": + version: 2.1.0 + resolution: "import-lazy@npm:2.1.0" + checksum: 10c0/c5e5f507d26ee23c5b2ed64577155810361ac37863b322cae0c17f16b6a8cdd15adf370288384ddd95ef9de05602fb8d87bf76ff835190eb037333c84db8062c + languageName: node + linkType: hard + "imurmurhash@npm:^0.1.4": version: 0.1.4 resolution: "imurmurhash@npm:0.1.4" @@ -3793,13 +4509,27 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2": +"inherits@npm:2, inherits@npm:2.0.4": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2 languageName: node linkType: hard +"ini@npm:1.3.7": + version: 1.3.7 + resolution: "ini@npm:1.3.7" + checksum: 10c0/eec367cd86ed23ebd97a94a4fd6a5d82d87509ef3c4367d3fcab96fc1f4cd9f1ab766ffde82a774b9892d24e0b3c6418782c9f77cf9123785d4e2bb9c2d689b6 + languageName: node + linkType: hard + +"ini@npm:~1.3.0": + version: 1.3.8 + resolution: "ini@npm:1.3.8" + checksum: 10c0/ec93838d2328b619532e4f1ff05df7909760b6f66d9c9e2ded11e5c1897d6f2f9980c54dd638f88654b00919ce31e827040631eab0a3969e4d1abefa0719516a + languageName: node + linkType: hard + "internal-slot@npm:^1.0.7": version: 1.0.7 resolution: "internal-slot@npm:1.0.7" @@ -3833,6 +4563,13 @@ __metadata: languageName: node linkType: hard +"is-absolute-url@npm:^4.0.1": + version: 4.0.1 + resolution: "is-absolute-url@npm:4.0.1" + checksum: 10c0/6f8f603945bd9f2c6031758bbc12352fc647bd5d807cad10d96cc6300fd0e15240cc091521a61db767e4ec0bacff257b4f1015fd5249c147bbb4a4497356c72e + languageName: node + linkType: hard + "is-array-buffer@npm:^3.0.4": version: 3.0.4 resolution: "is-array-buffer@npm:3.0.4" @@ -3894,6 +4631,17 @@ __metadata: languageName: node linkType: hard +"is-ci@npm:^2.0.0": + version: 2.0.0 + resolution: "is-ci@npm:2.0.0" + dependencies: + ci-info: "npm:^2.0.0" + bin: + is-ci: bin.js + checksum: 10c0/17de4e2cd8f993c56c86472dd53dd9e2c7f126d0ee55afe610557046cdd64de0e8feadbad476edc9eeff63b060523b8673d9094ed2ab294b59efb5a66dd05a9a + languageName: node + linkType: hard + "is-core-module@npm:^2.13.0, is-core-module@npm:^2.13.1": version: 2.13.1 resolution: "is-core-module@npm:2.13.1" @@ -3944,6 +4692,16 @@ __metadata: languageName: node linkType: hard +"is-installed-globally@npm:^0.3.1": + version: 0.3.2 + resolution: "is-installed-globally@npm:0.3.2" + dependencies: + global-dirs: "npm:^2.0.1" + is-path-inside: "npm:^3.0.1" + checksum: 10c0/97e40bc2b4765cd5a71292fe63c671ee01ed72646b7c0b8f945b16d7b149bc5c9f6f522b5a2954a0eea2b2cb5b8faf5c5a6c0b0ff1e593e7131c8bb0e3dbb9e0 + languageName: node + linkType: hard + "is-lambda@npm:^1.0.1": version: 1.0.1 resolution: "is-lambda@npm:1.0.1" @@ -3965,6 +4723,13 @@ __metadata: languageName: node linkType: hard +"is-npm@npm:^4.0.0": + version: 4.0.0 + resolution: "is-npm@npm:4.0.0" + checksum: 10c0/865d406b25b8840298d9715130e063776c654b865dfa311178f4b0d1b338296083a419bd1f1d52db7d1dec2debda8e5562db58abde692052b143c9d16d0c3fc7 + languageName: node + linkType: hard + "is-number-object@npm:^1.0.4": version: 1.0.7 resolution: "is-number-object@npm:1.0.7" @@ -3981,7 +4746,14 @@ __metadata: languageName: node linkType: hard -"is-path-inside@npm:^3.0.3": +"is-obj@npm:^2.0.0": + version: 2.0.0 + resolution: "is-obj@npm:2.0.0" + checksum: 10c0/85044ed7ba8bd169e2c2af3a178cacb92a97aa75de9569d02efef7f443a824b5e153eba72b9ae3aca6f8ce81955271aa2dc7da67a8b720575d3e38104208cb4e + languageName: node + linkType: hard + +"is-path-inside@npm:^3.0.1, is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" checksum: 10c0/cf7d4ac35fb96bab6a1d2c3598fe5ebb29aafb52c0aaa482b5a3ed9d8ba3edc11631e3ec2637660c44b3ce0e61a08d54946e8af30dec0b60a7c27296c68ffd05 @@ -4014,6 +4786,15 @@ __metadata: languageName: node linkType: hard +"is-relative-url@npm:^4.0.0": + version: 4.0.0 + resolution: "is-relative-url@npm:4.0.0" + dependencies: + is-absolute-url: "npm:^4.0.1" + checksum: 10c0/73dffa89682088dbb3c5c46e19ac5d9c86963f9f456b6531fc6d0e92abc75a285cd3098ad180671a1ff3a9980fd5a4f66aa0e84a832db36439b1a7bc69397de9 + languageName: node + linkType: hard + "is-shared-array-buffer@npm:^1.0.2, is-shared-array-buffer@npm:^1.0.3": version: 1.0.3 resolution: "is-shared-array-buffer@npm:1.0.3" @@ -4057,6 +4838,13 @@ __metadata: languageName: node linkType: hard +"is-typedarray@npm:^1.0.0": + version: 1.0.0 + resolution: "is-typedarray@npm:1.0.0" + checksum: 10c0/4c096275ba041a17a13cca33ac21c16bc4fd2d7d7eb94525e7cd2c2f2c1a3ab956e37622290642501ff4310601e413b675cf399ad6db49855527d2163b3eeeec + languageName: node + linkType: hard + "is-weakref@npm:^1.0.2": version: 1.0.2 resolution: "is-weakref@npm:1.0.2" @@ -4066,6 +4854,13 @@ __metadata: languageName: node linkType: hard +"is-wsl@npm:^1.1.0": + version: 1.1.0 + resolution: "is-wsl@npm:1.1.0" + checksum: 10c0/7ad0012f21092d6f586c7faad84755a8ef0da9b9ec295e4dc82313cce4e1a93a3da3c217265016461f9b141503fe55fa6eb1fd5457d3f05e8d1bdbb48e50c13a + languageName: node + linkType: hard + "is-wsl@npm:^2.2.0": version: 2.2.0 resolution: "is-wsl@npm:2.2.0" @@ -4075,6 +4870,13 @@ __metadata: languageName: node linkType: hard +"is-yarn-global@npm:^0.3.0": + version: 0.3.0 + resolution: "is-yarn-global@npm:0.3.0" + checksum: 10c0/9f1ab6f28e6e7961c4b97e564791d1decf2886a0dbe9b92b2176d76156adbb42b4c06c0f33d7107b270c207cbcfe0b2293b7cc4a0ec6774ac6d37af9503d51e1 + languageName: node + linkType: hard + "isarray@npm:^2.0.5": version: 2.0.5 resolution: "isarray@npm:2.0.5" @@ -4082,6 +4884,15 @@ __metadata: languageName: node linkType: hard +"isemail@npm:^3.2.0": + version: 3.2.0 + resolution: "isemail@npm:3.2.0" + dependencies: + punycode: "npm:2.x.x" + checksum: 10c0/de836d3231337175bc46cf882c59d2ef090381df1e265c6a3afdbb3d510ea169fb22ebea937429f73a41b24e39decf17d8d6d23463bda2f428b066c8fb13f14d + languageName: node + linkType: hard + "isexe@npm:^2.0.0": version: 2.0.0 resolution: "isexe@npm:2.0.0" @@ -4252,6 +5063,13 @@ __metadata: languageName: node linkType: hard +"json-buffer@npm:3.0.0": + version: 3.0.0 + resolution: "json-buffer@npm:3.0.0" + checksum: 10c0/118c060d84430a8ad8376d0c60250830f350a6381bd56541a1ef257ce7ba82d109d1f71a4c4e92e0be0e7ab7da568fad8f7bf02905910a76e8e0aa338621b944 + languageName: node + linkType: hard + "json-buffer@npm:3.0.1": version: 3.0.1 resolution: "json-buffer@npm:3.0.1" @@ -4307,6 +5125,18 @@ __metadata: languageName: node linkType: hard +"jsonfile@npm:^4.0.0": + version: 4.0.0 + resolution: "jsonfile@npm:4.0.0" + dependencies: + graceful-fs: "npm:^4.1.6" + dependenciesMeta: + graceful-fs: + optional: true + checksum: 10c0/7dc94b628d57a66b71fb1b79510d460d662eb975b5f876d723f81549c2e9cd316d58a2ddf742b2b93a4fa6b17b2accaf1a738a0e2ea114bdfb13a32e5377e480 + languageName: node + linkType: hard + "jsonfile@npm:^6.0.1": version: 6.1.0 resolution: "jsonfile@npm:6.1.0" @@ -4327,6 +5157,15 @@ __metadata: languageName: node linkType: hard +"keyv@npm:^3.0.0": + version: 3.1.0 + resolution: "keyv@npm:3.1.0" + dependencies: + json-buffer: "npm:3.0.0" + checksum: 10c0/6ad784361b4c0213333a8c5bc0bcc59cf46cb7cbbe21fb2f1539ffcc8fe18b8f1562ff913b40552278fdea5f152a15996dfa61ce24ce1a22222560c650be4a1b + languageName: node + linkType: hard + "keyv@npm:^4.5.3": version: 4.5.4 resolution: "keyv@npm:4.5.4" @@ -4336,6 +5175,15 @@ __metadata: languageName: node linkType: hard +"latest-version@npm:^5.0.0": + version: 5.1.0 + resolution: "latest-version@npm:5.1.0" + dependencies: + package-json: "npm:^6.3.0" + checksum: 10c0/6219631d8651467c54c58ef1b5d5c5c53e146f5ae2b0ecbb78b202da3eaad55b05b043db2d2d6f1d4230ee071b2ae8c2f85089e01377e4338bad97fa76a963b7 + languageName: node + linkType: hard + "levn@npm:^0.4.1": version: 0.4.1 resolution: "levn@npm:0.4.1" @@ -4360,6 +5208,19 @@ __metadata: languageName: node linkType: hard +"link-check@npm:^5.3.0": + version: 5.3.0 + resolution: "link-check@npm:5.3.0" + dependencies: + is-relative-url: "npm:^4.0.0" + isemail: "npm:^3.2.0" + ms: "npm:^2.1.3" + needle: "npm:^3.3.1" + proxy-agent: "npm:^6.4.0" + checksum: 10c0/2eeec47c9e2efe80b7164a5b2c15e127853baedaf886b73153ddf1b628334193aaf8d40143e0fa7eb213057ebd3af942d60dd5f0356dd5d5aa7d4c0abc7b5cfb + languageName: node + linkType: hard + "lit-element@npm:^3.3.0": version: 3.3.3 resolution: "lit-element@npm:3.3.3" @@ -4422,6 +5283,27 @@ __metadata: languageName: node linkType: hard +"livereload-js@npm:^3.3.1": + version: 3.4.1 + resolution: "livereload-js@npm:3.4.1" + checksum: 10c0/d1353824eb50ae2291d6c92c419f0fc147c2b661837b078aded61f75c42d69dd50e6f6ca8b1990b19f522007fef88e5240ee528ace910ca9e2922bda4784bbc2 + languageName: node + linkType: hard + +"livereload@npm:^0.9.2": + version: 0.9.3 + resolution: "livereload@npm:0.9.3" + dependencies: + chokidar: "npm:^3.5.0" + livereload-js: "npm:^3.3.1" + opts: "npm:>= 1.2.0" + ws: "npm:^7.4.3" + bin: + livereload: bin/livereload.js + checksum: 10c0/ad17eb1af3bcd1f687050c1e3ffb0b750533e17e529537b2a7715b01eaa6f727eec34384246cd4ec25d0d45e92ec4112fa07eae0d46e806796bbec66b6ad511d + languageName: node + linkType: hard + "local-pkg@npm:^0.5.0": version: 0.5.0 resolution: "local-pkg@npm:0.5.0" @@ -4494,6 +5376,20 @@ __metadata: languageName: node linkType: hard +"lowercase-keys@npm:^1.0.0, lowercase-keys@npm:^1.0.1": + version: 1.0.1 + resolution: "lowercase-keys@npm:1.0.1" + checksum: 10c0/56776a8e1ef1aca98ecf6c19b30352ae1cf257b65b8ac858b7d8a0e8b348774d12a9b41aa7f59bfea51bff44bc7a198ab63ba4406bfba60dba008799618bef66 + languageName: node + linkType: hard + +"lowercase-keys@npm:^2.0.0": + version: 2.0.0 + resolution: "lowercase-keys@npm:2.0.0" + checksum: 10c0/f82a2b3568910509da4b7906362efa40f5b54ea14c2584778ddb313226f9cbf21020a5db35f9b9a0e95847a9b781d548601f31793d736b22a2b8ae8eb9ab1082 + languageName: node + linkType: hard + "lru-cache@npm:^10.0.1, lru-cache@npm:^9.1.1 || ^10.0.0": version: 10.2.0 resolution: "lru-cache@npm:10.2.0" @@ -4519,6 +5415,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^7.14.1": + version: 7.18.3 + resolution: "lru-cache@npm:7.18.3" + checksum: 10c0/b3a452b491433db885beed95041eb104c157ef7794b9c9b4d647be503be91769d11206bb573849a16b4cc0d03cbd15ffd22df7960997788b74c1d399ac7a4fed + languageName: node + linkType: hard + "magic-string@npm:^0.25.7": version: 0.25.9 resolution: "magic-string@npm:0.25.9" @@ -4548,7 +5451,7 @@ __metadata: languageName: node linkType: hard -"make-dir@npm:^3.0.2": +"make-dir@npm:^3.0.0, make-dir@npm:^3.0.2": version: 3.1.0 resolution: "make-dir@npm:3.1.0" dependencies: @@ -4585,6 +5488,53 @@ __metadata: languageName: node linkType: hard +"markdown-link-check@npm:^3.12.1": + version: 3.12.1 + resolution: "markdown-link-check@npm:3.12.1" + dependencies: + async: "npm:^3.2.5" + chalk: "npm:^5.2.0" + commander: "npm:^10.0.1" + link-check: "npm:^5.3.0" + lodash: "npm:^4.17.21" + markdown-link-extractor: "npm:^4.0.2" + needle: "npm:^3.3.1" + progress: "npm:^2.0.3" + proxy-agent: "npm:^6.4.0" + bin: + markdown-link-check: markdown-link-check + checksum: 10c0/25d45459dc8b948f75cfea23efb4ba3fbab210d9aa67ab5090dd2d2185b93c5debe43d4c07da1a717e70e3becfd0e84a60f52733990ebf8800f821f2213cb317 + languageName: node + linkType: hard + +"markdown-link-extractor@npm:^4.0.2": + version: 4.0.2 + resolution: "markdown-link-extractor@npm:4.0.2" + dependencies: + html-link-extractor: "npm:^1.0.5" + marked: "npm:^12.0.1" + checksum: 10c0/e9433dc3e1bdf26165b3daf644998fc84933efb6f74289b3f7637c4e36411a269f67992769032817c8821248ebf34ed97091fb91340b88fa1ffc50ad63163e16 + languageName: node + linkType: hard + +"marked@npm:^1.2.9": + version: 1.2.9 + resolution: "marked@npm:1.2.9" + bin: + marked: bin/marked + checksum: 10c0/463813869d58321dec4ee4532dae6ccbb373f0112eb09e03fb681ccfb66f8354aef24a9e02e7569e4321f0713986c4a622c18b141147bbb7b7427f47e414e50e + languageName: node + linkType: hard + +"marked@npm:^12.0.1": + version: 12.0.1 + resolution: "marked@npm:12.0.1" + bin: + marked: bin/marked.js + checksum: 10c0/e5c2a4da12dc59351e3e8acd0ca36c11a49f9a538bd0c3bda2dc3c71868f168dd678907184308e6f458eafad0c14146d01841b0644b6ccfcab920c73b814f8d8 + languageName: node + linkType: hard + "masonry-layout@npm:^4.2.2": version: 4.2.2 resolution: "masonry-layout@npm:4.2.2" @@ -4602,6 +5552,13 @@ __metadata: languageName: node linkType: hard +"medium-zoom@npm:^1.0.6": + version: 1.1.0 + resolution: "medium-zoom@npm:1.1.0" + checksum: 10c0/7d1f05e8eab045c33d7c04d4ee7bf04f5246cf7a720d7b5f5a51c36ab23666e363bcbb6bffae50b5948d5eb19361914cb0e26a1fce5c1fff7a266bc0217893f3 + languageName: node + linkType: hard + "merge-stream@npm:^2.0.0": version: 2.0.0 resolution: "merge-stream@npm:2.0.0" @@ -4642,6 +5599,15 @@ __metadata: languageName: node linkType: hard +"mime@npm:1.6.0": + version: 1.6.0 + resolution: "mime@npm:1.6.0" + bin: + mime: cli.js + checksum: 10c0/b92cd0adc44888c7135a185bfd0dddc42c32606401c72896a842ae15da71eb88858f17669af41e498b463cd7eb998f7b48939a25b08374c7924a9c8a6f8a81b0 + languageName: node + linkType: hard + "mime@npm:^3": version: 3.0.0 resolution: "mime@npm:3.0.0" @@ -4658,6 +5624,20 @@ __metadata: languageName: node linkType: hard +"mimic-response@npm:^1.0.0, mimic-response@npm:^1.0.1": + version: 1.0.1 + resolution: "mimic-response@npm:1.0.1" + checksum: 10c0/c5381a5eae997f1c3b5e90ca7f209ed58c3615caeee850e85329c598f0c000ae7bec40196580eef1781c60c709f47258131dab237cad8786f8f56750594f27fa + languageName: node + linkType: hard + +"min-indent@npm:^1.0.0": + version: 1.0.1 + resolution: "min-indent@npm:1.0.1" + checksum: 10c0/7e207bd5c20401b292de291f02913230cb1163abca162044f7db1d951fa245b174dc00869d40dd9a9f32a885ad6a5f3e767ee104cf278f399cb4e92d3f582d5c + languageName: node + linkType: hard + "mini-svg-data-uri@npm:^1.4.4": version: 1.4.4 resolution: "mini-svg-data-uri@npm:1.4.4" @@ -4804,6 +5784,13 @@ __metadata: languageName: node linkType: hard +"ms@npm:2.0.0": + version: 2.0.0 + resolution: "ms@npm:2.0.0" + checksum: 10c0/f8fda810b39fd7255bbdc451c46286e549794fcc700dc9cd1d25658bbc4dc2563a5de6fe7c60f798a16a60c6ceb53f033cb353f493f0cf63e5199b702943159d + languageName: node + linkType: hard + "ms@npm:2.1.2": version: 2.1.2 resolution: "ms@npm:2.1.2" @@ -4811,7 +5798,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:^2.1.1": +"ms@npm:2.1.3, ms@npm:^2.1.1, ms@npm:^2.1.3": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 @@ -4841,6 +5828,18 @@ __metadata: languageName: node linkType: hard +"needle@npm:^3.3.1": + version: 3.3.1 + resolution: "needle@npm:3.3.1" + dependencies: + iconv-lite: "npm:^0.6.3" + sax: "npm:^1.2.4" + bin: + needle: bin/needle + checksum: 10c0/233b9315d47b735867d03e7a018fb665ee6cacf3a83b991b19538019cf42b538a3e85ca745c840b4c5e9a0ffdca76472f941363bf7c166214ae8cbc650fd4d39 + languageName: node + linkType: hard + "negotiator@npm:^0.6.3": version: 0.6.3 resolution: "negotiator@npm:0.6.3" @@ -4848,6 +5847,34 @@ __metadata: languageName: node linkType: hard +"nested-error-stacks@npm:^2.0.0": + version: 2.1.1 + resolution: "nested-error-stacks@npm:2.1.1" + checksum: 10c0/feec00417e4778661cfbbe657e6add6ca9918dcc026cd697ac330b4a56a79e4882b36dde8abc138167566b1ce4c5baa17d2d4df727a96f8b96aebace1c3ffca7 + languageName: node + linkType: hard + +"netmask@npm:^2.0.2": + version: 2.0.2 + resolution: "netmask@npm:2.0.2" + checksum: 10c0/cafd28388e698e1138ace947929f842944d0f1c0b87d3fa2601a61b38dc89397d33c0ce2c8e7b99e968584b91d15f6810b91bef3f3826adf71b1833b61d4bf4f + languageName: node + linkType: hard + +"node-fetch@npm:^2.6.6": + version: 2.7.0 + resolution: "node-fetch@npm:2.7.0" + dependencies: + whatwg-url: "npm:^5.0.0" + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + checksum: 10c0/b55786b6028208e6fbe594ccccc213cab67a72899c9234eb59dba51062a299ea853210fcf526998eaa2867b0963ad72338824450905679ff0fa304b8c5093ae8 + languageName: node + linkType: hard + "node-gyp@npm:latest": version: 10.0.1 resolution: "node-gyp@npm:10.0.1" @@ -4893,6 +5920,13 @@ __metadata: languageName: node linkType: hard +"normalize-url@npm:^4.1.0": + version: 4.5.1 + resolution: "normalize-url@npm:4.5.1" + checksum: 10c0/6362e9274fdcc310f8b17e20de29754c94e1820d864114f03d3bfd6286a0028fc51705fb3fd4e475013357b5cd7421fc17f3aba93f2289056779a9bb23bccf59 + languageName: node + linkType: hard + "normalize-url@npm:^6.0.1": version: 6.1.0 resolution: "normalize-url@npm:6.1.0" @@ -4997,7 +6031,25 @@ __metadata: languageName: node linkType: hard -"once@npm:^1.3.0": +"on-finished@npm:2.4.1": + version: 2.4.1 + resolution: "on-finished@npm:2.4.1" + dependencies: + ee-first: "npm:1.1.1" + checksum: 10c0/46fb11b9063782f2d9968863d9cbba33d77aa13c17f895f56129c274318b86500b22af3a160fe9995aa41317efcd22941b6eba747f718ced08d9a73afdb087b4 + languageName: node + linkType: hard + +"on-finished@npm:~2.3.0": + version: 2.3.0 + resolution: "on-finished@npm:2.3.0" + dependencies: + ee-first: "npm:1.1.1" + checksum: 10c0/c904f9e518b11941eb60279a3cbfaf1289bd0001f600a950255b1dede9fe3df8cd74f38483550b3bb9485165166acb5db500c3b4c4337aec2815c88c96fcc2ea + languageName: node + linkType: hard + +"once@npm:^1.3.0, once@npm:^1.3.1, once@npm:^1.4.0": version: 1.4.0 resolution: "once@npm:1.4.0" dependencies: @@ -5015,6 +6067,15 @@ __metadata: languageName: node linkType: hard +"open@npm:^6.4.0": + version: 6.4.0 + resolution: "open@npm:6.4.0" + dependencies: + is-wsl: "npm:^1.1.0" + checksum: 10c0/447115632b4f3939fa0d973c33e17f28538fd268fd8257fc49763f7de6e76d29d65585b15998bbd2137337cfb70a92084a0e1b183a466e53a4829f704f295823 + languageName: node + linkType: hard + "open@npm:^8.4.0": version: 8.4.2 resolution: "open@npm:8.4.2" @@ -5026,6 +6087,15 @@ __metadata: languageName: node linkType: hard +"opencollective-postinstall@npm:^2.0.2": + version: 2.0.3 + resolution: "opencollective-postinstall@npm:2.0.3" + bin: + opencollective-postinstall: index.js + checksum: 10c0/8a0104a218bc1afaae943f0af378461eeb2836f9848bad872bbd067ec5d1d9791636f307454ab77d0746f10341366f295384656a340ebdb87a2585058e8567e5 + languageName: node + linkType: hard + "opener@npm:1": version: 1.5.2 resolution: "opener@npm:1.5.2" @@ -5049,6 +6119,13 @@ __metadata: languageName: node linkType: hard +"opts@npm:>= 1.2.0": + version: 2.0.2 + resolution: "opts@npm:2.0.2" + checksum: 10c0/c6056d5c959f8f3e221c16cf5cf16eae0ed6cc36c6944d3bd0e8affa1dd7c8c9da47343a62bb1a98cfe3b3dce3c088f9cbb90d97b6b0286372a5c7c2281c8ebb + languageName: node + linkType: hard + "outlayer@npm:^2.1.0": version: 2.1.1 resolution: "outlayer@npm:2.1.1" @@ -5060,6 +6137,22 @@ __metadata: languageName: node linkType: hard +"p-cancelable@npm:^1.0.0": + version: 1.1.0 + resolution: "p-cancelable@npm:1.1.0" + checksum: 10c0/9f16d7d58897edb07b1a9234b2bfce3665c747f0f13886e25e2144ecab4595412017cc8cc3b0042f89864b997d6dba76c130724e1c0923fc41ff3c9399b87449 + languageName: node + linkType: hard + +"p-event@npm:^4.1.0": + version: 4.2.0 + resolution: "p-event@npm:4.2.0" + dependencies: + p-timeout: "npm:^3.1.0" + checksum: 10c0/f1b6a2fb13d47f2a8afc00150da5ece0d28940ce3d8fa562873e091d3337d298e78fee9cb18b768598ff1d11df608b2ae23868309ff6405b864a2451ccd6d25a + languageName: node + linkType: hard + "p-finally@npm:^1.0.0": version: 1.0.0 resolution: "p-finally@npm:1.0.0" @@ -5131,7 +6224,7 @@ __metadata: languageName: node linkType: hard -"p-timeout@npm:^3.2.0": +"p-timeout@npm:^3.1.0, p-timeout@npm:^3.2.0": version: 3.2.0 resolution: "p-timeout@npm:3.2.0" dependencies: @@ -5147,6 +6240,44 @@ __metadata: languageName: node linkType: hard +"pac-proxy-agent@npm:^7.0.1": + version: 7.0.1 + resolution: "pac-proxy-agent@npm:7.0.1" + dependencies: + "@tootallnate/quickjs-emscripten": "npm:^0.23.0" + agent-base: "npm:^7.0.2" + debug: "npm:^4.3.4" + get-uri: "npm:^6.0.1" + http-proxy-agent: "npm:^7.0.0" + https-proxy-agent: "npm:^7.0.2" + pac-resolver: "npm:^7.0.0" + socks-proxy-agent: "npm:^8.0.2" + checksum: 10c0/95b07e2a409511262d6e29be3d50f2e18ac387ef99664687ab4e92741d1d20fae97309722c37841583b024d1cde1790dd263a9b915d5241751b77f1e8003c418 + languageName: node + linkType: hard + +"pac-resolver@npm:^7.0.0": + version: 7.0.1 + resolution: "pac-resolver@npm:7.0.1" + dependencies: + degenerator: "npm:^5.0.0" + netmask: "npm:^2.0.2" + checksum: 10c0/5f3edd1dd10fded31e7d1f95776442c3ee51aa098c28b74ede4927d9677ebe7cebb2636750c24e945f5b84445e41ae39093d3a1014a994e5ceb9f0b1b88ebff5 + languageName: node + linkType: hard + +"package-json@npm:^6.3.0": + version: 6.5.0 + resolution: "package-json@npm:6.5.0" + dependencies: + got: "npm:^9.6.0" + registry-auth-token: "npm:^4.0.0" + registry-url: "npm:^5.0.0" + semver: "npm:^6.2.0" + checksum: 10c0/60c29fe357af43f96c92c334aa0160cebde44e8e65c1e5f9b065efb3f501af812f268ec967a07757b56447834ef7f71458ebbab94425a9f09c271f348f9b764f + languageName: node + linkType: hard + "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -5156,6 +6287,13 @@ __metadata: languageName: node linkType: hard +"parent-require@npm:^1.0.0": + version: 1.0.0 + resolution: "parent-require@npm:1.0.0" + checksum: 10c0/58eb17553192027a596bb3b13f567e4933894964ad47a9f9054a5dc4776e60e13903e937b2eec6e7afff8a34a4fc91b5397fdc6206aa2d50ba95b87059b4f2e0 + languageName: node + linkType: hard + "parse-json@npm:^5.0.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" @@ -5168,7 +6306,17 @@ __metadata: languageName: node linkType: hard -"parse5@npm:^7.1.2": +"parse5-htmlparser2-tree-adapter@npm:^7.0.0": + version: 7.0.0 + resolution: "parse5-htmlparser2-tree-adapter@npm:7.0.0" + dependencies: + domhandler: "npm:^5.0.2" + parse5: "npm:^7.0.0" + checksum: 10c0/e820cacb8486e6f7ede403327d18480df086d70e32ede2f6654d8c3a8b4b8dc4a4d5c21c03c18a92ba2466c513b93ca63be4a138dd73cd0995f384eb3b9edf11 + languageName: node + linkType: hard + +"parse5@npm:^7.0.0, parse5@npm:^7.1.2": version: 7.1.2 resolution: "parse5@npm:7.1.2" dependencies: @@ -5177,6 +6325,13 @@ __metadata: languageName: node linkType: hard +"parseurl@npm:~1.3.3": + version: 1.3.3 + resolution: "parseurl@npm:1.3.3" + checksum: 10c0/90dd4760d6f6174adb9f20cf0965ae12e23879b5f5464f38e92fce8073354341e4b3b76fa3d878351efe7d01e617121955284cfd002ab087fba1a0726ec0b4f5 + languageName: node + linkType: hard + "path-browserify@npm:^1.0.1": version: 1.0.1 resolution: "path-browserify@npm:1.0.1" @@ -5675,6 +6830,13 @@ __metadata: languageName: node linkType: hard +"prepend-http@npm:^2.0.0": + version: 2.0.0 + resolution: "prepend-http@npm:2.0.0" + checksum: 10c0/b023721ffd967728e3a25e3a80dd73827e9444e586800ab90a21b3a8e67f362d28023085406ad53a36db1e4d98cb10e43eb37d45c6b733140a9165ead18a0987 + languageName: node + linkType: hard + "prettier-linter-helpers@npm:^1.0.0": version: 1.0.0 resolution: "prettier-linter-helpers@npm:1.0.0" @@ -5704,6 +6866,13 @@ __metadata: languageName: node linkType: hard +"prismjs@npm:^1.27.0": + version: 1.29.0 + resolution: "prismjs@npm:1.29.0" + checksum: 10c0/d906c4c4d01b446db549b4f57f72d5d7e6ccaca04ecc670fb85cea4d4b1acc1283e945a9cbc3d81819084a699b382f970e02f9d1378e14af9808d366d9ed7ec6 + languageName: node + linkType: hard + "proc-log@npm:^3.0.0": version: 3.0.0 resolution: "proc-log@npm:3.0.0" @@ -5711,6 +6880,13 @@ __metadata: languageName: node linkType: hard +"progress@npm:^2.0.3": + version: 2.0.3 + resolution: "progress@npm:2.0.3" + checksum: 10c0/1697e07cb1068055dbe9fe858d242368ff5d2073639e652b75a7eb1f2a1a8d4afd404d719de23c7b48481a6aa0040686310e2dac2f53d776daa2176d3f96369c + languageName: node + linkType: hard + "promise-retry@npm:^2.0.1": version: 2.0.1 resolution: "promise-retry@npm:2.0.1" @@ -5730,6 +6906,29 @@ __metadata: languageName: node linkType: hard +"proxy-agent@npm:^6.4.0": + version: 6.4.0 + resolution: "proxy-agent@npm:6.4.0" + dependencies: + agent-base: "npm:^7.0.2" + debug: "npm:^4.3.4" + http-proxy-agent: "npm:^7.0.1" + https-proxy-agent: "npm:^7.0.3" + lru-cache: "npm:^7.14.1" + pac-proxy-agent: "npm:^7.0.1" + proxy-from-env: "npm:^1.1.0" + socks-proxy-agent: "npm:^8.0.2" + checksum: 10c0/0c5b85cacf67eec9d8add025a5e577b2c895672e4187079ec41b0ee2a6dacd90e69a837936cb3ac141dd92b05b50a325b9bfe86ab0dc3b904011aa3bcf406fc0 + languageName: node + linkType: hard + +"proxy-from-env@npm:^1.1.0": + version: 1.1.0 + resolution: "proxy-from-env@npm:1.1.0" + checksum: 10c0/fe7dd8b1bdbbbea18d1459107729c3e4a2243ca870d26d34c2c1bcd3e4425b7bcc5112362df2d93cc7fb9746f6142b5e272fd1cc5c86ddf8580175186f6ad42b + languageName: node + linkType: hard + "psl@npm:^1.1.33": version: 1.9.0 resolution: "psl@npm:1.9.0" @@ -5737,13 +6936,32 @@ __metadata: languageName: node linkType: hard -"punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.0": +"pump@npm:^3.0.0": + version: 3.0.0 + resolution: "pump@npm:3.0.0" + dependencies: + end-of-stream: "npm:^1.1.0" + once: "npm:^1.3.1" + checksum: 10c0/bbdeda4f747cdf47db97428f3a135728669e56a0ae5f354a9ac5b74556556f5446a46f720a8f14ca2ece5be9b4d5d23c346db02b555f46739934cc6c093a5478 + languageName: node + linkType: hard + +"punycode@npm:2.x.x, punycode@npm:^2.1.0, punycode@npm:^2.1.1, punycode@npm:^2.3.0": version: 2.3.1 resolution: "punycode@npm:2.3.1" checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 languageName: node linkType: hard +"pupa@npm:^2.0.1": + version: 2.1.1 + resolution: "pupa@npm:2.1.1" + dependencies: + escape-goat: "npm:^2.0.0" + checksum: 10c0/d2346324780ebae4be847cad052b830e004d816851dd4750fc73faa6cd360f443e358f6b1c83641fd4c904c6055dcb545807f55259a20a52ad86d9477746c724 + languageName: node + linkType: hard + "query-string@npm:^7.1.0": version: 7.1.3 resolution: "query-string@npm:7.1.3" @@ -5786,6 +7004,27 @@ __metadata: languageName: node linkType: hard +"range-parser@npm:~1.2.1": + version: 1.2.1 + resolution: "range-parser@npm:1.2.1" + checksum: 10c0/96c032ac2475c8027b7a4e9fe22dc0dfe0f6d90b85e496e0f016fbdb99d6d066de0112e680805075bd989905e2123b3b3d002765149294dce0c1f7f01fcc2ea0 + languageName: node + linkType: hard + +"rc@npm:1.2.8, rc@npm:^1.2.8": + version: 1.2.8 + resolution: "rc@npm:1.2.8" + dependencies: + deep-extend: "npm:^0.6.0" + ini: "npm:~1.3.0" + minimist: "npm:^1.2.0" + strip-json-comments: "npm:~2.0.1" + bin: + rc: ./cli.js + checksum: 10c0/24a07653150f0d9ac7168e52943cc3cb4b7a22c0e43c7dff3219977c2fdca5a2760a304a029c20811a0e79d351f57d46c9bde216193a0f73978496afc2b85b15 + languageName: node + linkType: hard + "react-is@npm:^18.0.0": version: 18.2.0 resolution: "react-is@npm:18.2.0" @@ -5821,6 +7060,24 @@ __metadata: languageName: node linkType: hard +"registry-auth-token@npm:^4.0.0": + version: 4.2.2 + resolution: "registry-auth-token@npm:4.2.2" + dependencies: + rc: "npm:1.2.8" + checksum: 10c0/1d0000b8b65e7141a4cc4594926e2551607f48596e01326e7aa2ba2bc688aea86b2aa0471c5cb5de7acc9a59808a3a1ddde9084f974da79bfc67ab67aa48e003 + languageName: node + linkType: hard + +"registry-url@npm:^5.0.0": + version: 5.1.0 + resolution: "registry-url@npm:5.1.0" + dependencies: + rc: "npm:^1.2.8" + checksum: 10c0/c2c455342b5836cbed5162092eba075c7a02c087d9ce0fde8aeb4dc87a8f4a34a542e58bf4d8ec2d4cb73f04408cb3148ceb1f76647f76b978cfec22047dc6d6 + languageName: node + linkType: hard + "require-directory@npm:^2.1.1": version: 2.1.1 resolution: "require-directory@npm:2.1.1" @@ -5828,6 +7085,13 @@ __metadata: languageName: node linkType: hard +"require-main-filename@npm:^2.0.0": + version: 2.0.0 + resolution: "require-main-filename@npm:2.0.0" + checksum: 10c0/db91467d9ead311b4111cbd73a4e67fa7820daed2989a32f7023785a2659008c6d119752d9c4ac011ae07e537eb86523adff99804c5fdb39cd3a017f9b401bb6 + languageName: node + linkType: hard + "requires-port@npm:^1.0.0": version: 1.0.0 resolution: "requires-port@npm:1.0.0" @@ -5842,6 +7106,13 @@ __metadata: languageName: node linkType: hard +"resolve-pathname@npm:^3.0.0": + version: 3.0.0 + resolution: "resolve-pathname@npm:3.0.0" + checksum: 10c0/c6ec49b670dc35b9a303c47fa83ba9348a71e92d64a4c4bb85e1b659a29b407aa1ac1cb14a9b5b502982132ca77482bd80534bca147439d66880d35a137fe723 + languageName: node + linkType: hard + "resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.21.0, resolve@npm:^1.22.4": version: 1.22.8 resolution: "resolve@npm:1.22.8" @@ -5868,6 +7139,15 @@ __metadata: languageName: node linkType: hard +"responselike@npm:^1.0.2": + version: 1.0.2 + resolution: "responselike@npm:1.0.2" + dependencies: + lowercase-keys: "npm:^1.0.0" + checksum: 10c0/1c2861d1950790da96159ca490eda645130eaf9ccc4d76db20f685ba944feaf30f45714b4318f550b8cd72990710ad68355ff15c41da43ed9a93c102c0ffa403 + languageName: node + linkType: hard + "retry@npm:^0.12.0": version: 0.12.0 resolution: "retry@npm:0.12.0" @@ -6122,6 +7402,13 @@ __metadata: languageName: node linkType: hard +"sax@npm:^1.2.4": + version: 1.3.0 + resolution: "sax@npm:1.3.0" + checksum: 10c0/599dbe0ba9d8bd55e92d920239b21d101823a6cedff71e542589303fa0fa8f3ece6cf608baca0c51be846a2e88365fac94a9101a9c341d94b98e30c4deea5bea + languageName: node + linkType: hard + "saxes@npm:^6.0.0": version: 6.0.0 resolution: "saxes@npm:6.0.0" @@ -6138,7 +7425,16 @@ __metadata: languageName: node linkType: hard -"semver@npm:^6.0.0, semver@npm:^6.3.0, semver@npm:^6.3.1": +"semver-diff@npm:^3.1.1": + version: 3.1.1 + resolution: "semver-diff@npm:3.1.1" + dependencies: + semver: "npm:^6.3.0" + checksum: 10c0/7d350f1450b9577d538ef866a9bc4cd97bfbf1f1d92070291495a31d0ec3aa808e826c223e5454ea9877cc06eaa886ffd71bb3a1f331b44bc210f9ff525c68d2 + languageName: node + linkType: hard + +"semver@npm:^6.0.0, semver@npm:^6.2.0, semver@npm:^6.3.0, semver@npm:^6.3.1": version: 6.3.1 resolution: "semver@npm:6.3.1" bin: @@ -6158,6 +7454,27 @@ __metadata: languageName: node linkType: hard +"send@npm:0.18.0": + version: 0.18.0 + resolution: "send@npm:0.18.0" + dependencies: + debug: "npm:2.6.9" + depd: "npm:2.0.0" + destroy: "npm:1.2.0" + encodeurl: "npm:~1.0.2" + escape-html: "npm:~1.0.3" + etag: "npm:~1.8.1" + fresh: "npm:0.5.2" + http-errors: "npm:2.0.0" + mime: "npm:1.6.0" + ms: "npm:2.1.3" + on-finished: "npm:2.4.1" + range-parser: "npm:~1.2.1" + statuses: "npm:2.0.1" + checksum: 10c0/0eb134d6a51fc13bbcb976a1f4214ea1e33f242fae046efc311e80aff66c7a43603e26a79d9d06670283a13000e51be6e0a2cb80ff0942eaf9f1cd30b7ae736a + languageName: node + linkType: hard + "serialize-javascript@npm:^4.0.0": version: 4.0.0 resolution: "serialize-javascript@npm:4.0.0" @@ -6167,6 +7484,25 @@ __metadata: languageName: node linkType: hard +"serve-static@npm:^1.12.1": + version: 1.15.0 + resolution: "serve-static@npm:1.15.0" + dependencies: + encodeurl: "npm:~1.0.2" + escape-html: "npm:~1.0.3" + parseurl: "npm:~1.3.3" + send: "npm:0.18.0" + checksum: 10c0/fa9f0e21a540a28f301258dfe1e57bb4f81cd460d28f0e973860477dd4acef946a1f41748b5bd41c73b621bea2029569c935faa38578fd34cd42a9b4947088ba + languageName: node + linkType: hard + +"set-blocking@npm:^2.0.0": + version: 2.0.0 + resolution: "set-blocking@npm:2.0.0" + checksum: 10c0/9f8c1b2d800800d0b589de1477c753492de5c1548d4ade52f57f1d1f5e04af5481554d75ce5e5c43d4004b80a3eb714398d6907027dc0534177b7539119f4454 + languageName: node + linkType: hard + "set-function-length@npm:^1.2.1": version: 1.2.1 resolution: "set-function-length@npm:1.2.1" @@ -6193,6 +7529,13 @@ __metadata: languageName: node linkType: hard +"setprototypeof@npm:1.2.0": + version: 1.2.0 + resolution: "setprototypeof@npm:1.2.0" + checksum: 10c0/68733173026766fa0d9ecaeb07f0483f4c2dc70ca376b3b7c40b7cda909f94b0918f6c5ad5ce27a9160bdfb475efaa9d5e705a11d8eaae18f9835d20976028bc + languageName: node + linkType: hard + "shebang-command@npm:^2.0.0": version: 2.0.0 resolution: "shebang-command@npm:2.0.0" @@ -6235,6 +7578,13 @@ __metadata: languageName: node linkType: hard +"signal-exit@npm:^3.0.2": + version: 3.0.7 + resolution: "signal-exit@npm:3.0.7" + checksum: 10c0/25d272fa73e146048565e08f3309d5b942c1979a6f4a58a8c59d5fa299728e9c2fcd1a759ec870863b1fd38653670240cd420dad2ad9330c71f36608a6a1c912 + languageName: node + linkType: hard + "signal-exit@npm:^4.0.1, signal-exit@npm:^4.1.0": version: 4.1.0 resolution: "signal-exit@npm:4.1.0" @@ -6267,6 +7617,17 @@ __metadata: languageName: node linkType: hard +"socks-proxy-agent@npm:^8.0.2": + version: 8.0.3 + resolution: "socks-proxy-agent@npm:8.0.3" + dependencies: + agent-base: "npm:^7.1.1" + debug: "npm:^4.3.4" + socks: "npm:^2.7.1" + checksum: 10c0/4950529affd8ccd6951575e21c1b7be8531b24d924aa4df3ee32df506af34b618c4e50d261f4cc603f1bfd8d426915b7d629966c8ce45b05fb5ad8c8b9a6459d + languageName: node + linkType: hard + "socks@npm:^2.7.1": version: 2.8.1 resolution: "socks@npm:2.8.1" @@ -6352,6 +7713,20 @@ __metadata: languageName: node linkType: hard +"statuses@npm:2.0.1": + version: 2.0.1 + resolution: "statuses@npm:2.0.1" + checksum: 10c0/34378b207a1620a24804ce8b5d230fea0c279f00b18a7209646d5d47e419d1cc23e7cbf33a25a1e51ac38973dc2ac2e1e9c647a8e481ef365f77668d72becfd0 + languageName: node + linkType: hard + +"statuses@npm:~1.5.0": + version: 1.5.0 + resolution: "statuses@npm:1.5.0" + checksum: 10c0/e433900956357b3efd79b1c547da4d291799ac836960c016d10a98f6a810b1b5c0dcc13b5a7aa609a58239b5190e1ea176ad9221c2157d2fd1c747393e6b2940 + languageName: node + linkType: hard + "std-env@npm:^3.5.0": version: 3.7.0 resolution: "std-env@npm:3.7.0" @@ -6366,7 +7741,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -6430,6 +7805,15 @@ __metadata: languageName: node linkType: hard +"strip-ansi@npm:^3.0.0": + version: 3.0.1 + resolution: "strip-ansi@npm:3.0.1" + dependencies: + ansi-regex: "npm:^2.0.0" + checksum: 10c0/f6e7fbe8e700105dccf7102eae20e4f03477537c74b286fd22cfc970f139002ed6f0d9c10d0e21aa9ed9245e0fa3c9275930e8795c5b947da136e4ecb644a70f + languageName: node + linkType: hard + "strip-ansi@npm:^7.0.1": version: 7.1.0 resolution: "strip-ansi@npm:7.1.0" @@ -6453,6 +7837,15 @@ __metadata: languageName: node linkType: hard +"strip-indent@npm:^3.0.0": + version: 3.0.0 + resolution: "strip-indent@npm:3.0.0" + dependencies: + min-indent: "npm:^1.0.0" + checksum: 10c0/ae0deaf41c8d1001c5d4fbe16cb553865c1863da4fae036683b474fa926af9fc121e155cb3fc57a68262b2ae7d5b8420aa752c97a6428c315d00efe2a3875679 + languageName: node + linkType: hard + "strip-json-comments@npm:^3.1.1": version: 3.1.1 resolution: "strip-json-comments@npm:3.1.1" @@ -6460,6 +7853,13 @@ __metadata: languageName: node linkType: hard +"strip-json-comments@npm:~2.0.1": + version: 2.0.1 + resolution: "strip-json-comments@npm:2.0.1" + checksum: 10c0/b509231cbdee45064ff4f9fd73609e2bcc4e84a4d508e9dd0f31f70356473fde18abfb5838c17d56fb236f5a06b102ef115438de0600b749e818a35fbbc48c43 + languageName: node + linkType: hard + "strip-literal@npm:^2.0.0": version: 2.0.0 resolution: "strip-literal@npm:2.0.0" @@ -6488,6 +7888,13 @@ __metadata: languageName: node linkType: hard +"supports-color@npm:^2.0.0": + version: 2.0.0 + resolution: "supports-color@npm:2.0.0" + checksum: 10c0/570e0b63be36cccdd25186350a6cb2eaad332a95ff162fa06d9499982315f2fe4217e69dd98e862fbcd9c81eaff300a825a1fe7bf5cc752e5b84dfed042b0dda + languageName: node + linkType: hard + "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -6551,6 +7958,13 @@ __metadata: languageName: node linkType: hard +"term-size@npm:^2.1.0": + version: 2.2.1 + resolution: "term-size@npm:2.2.1" + checksum: 10c0/89f6bba1d05d425156c0910982f9344d9e4aebf12d64bfa1f460d93c24baa7bc4c4a21d355fbd7153c316433df0538f64d0ae6e336cc4a69fdda4f85d62bc79d + languageName: node + linkType: hard + "terser@npm:^5.0.0": version: 5.28.1 resolution: "terser@npm:5.28.1" @@ -6590,6 +8004,13 @@ __metadata: languageName: node linkType: hard +"tinydate@npm:^1.3.0": + version: 1.3.0 + resolution: "tinydate@npm:1.3.0" + checksum: 10c0/06e3f273f36d04f6195c8ff58ba3a69db27f5e077ca8b08b073a9b816669a54e477f0086f3af84d33d525cf8876fb0021be9d6fd928dc43bfe9ea3945927168e + languageName: node + linkType: hard + "tinypool@npm:^0.8.2": version: 0.8.2 resolution: "tinypool@npm:0.8.2" @@ -6611,6 +8032,13 @@ __metadata: languageName: node linkType: hard +"to-readable-stream@npm:^1.0.0": + version: 1.0.0 + resolution: "to-readable-stream@npm:1.0.0" + checksum: 10c0/79cb836e2fb4f2885745a8c212eab7ebc52e93758ff0737feceaed96df98e4d04b8903fe8c27f2e9f3f856a5068ac332918b235c5d801b3efe02a51a3fa0eb36 + languageName: node + linkType: hard + "to-regex-range@npm:^5.0.1": version: 5.0.1 resolution: "to-regex-range@npm:5.0.1" @@ -6620,6 +8048,13 @@ __metadata: languageName: node linkType: hard +"toidentifier@npm:1.0.1": + version: 1.0.1 + resolution: "toidentifier@npm:1.0.1" + checksum: 10c0/93937279934bd66cc3270016dd8d0afec14fb7c94a05c72dc57321f8bd1fa97e5bea6d1f7c89e728d077ca31ea125b78320a616a6c6cd0e6b9cb94cb864381c1 + languageName: node + linkType: hard + "tough-cookie@npm:^4.1.2": version: 4.1.3 resolution: "tough-cookie@npm:4.1.3" @@ -6641,6 +8076,13 @@ __metadata: languageName: node linkType: hard +"tr46@npm:~0.0.3": + version: 0.0.3 + resolution: "tr46@npm:0.0.3" + checksum: 10c0/047cb209a6b60c742f05c9d3ace8fa510bff609995c129a37ace03476a9b12db4dbf975e74600830ef0796e18882b2381fb5fb1f6b4f96b832c374de3ab91a11 + languageName: node + linkType: hard + "true-myth@npm:^4.1.0": version: 4.1.1 resolution: "true-myth@npm:4.1.1" @@ -6705,7 +8147,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0": +"tslib@npm:^2.0.1, tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0": version: 2.6.2 resolution: "tslib@npm:2.6.2" checksum: 10c0/e03a8a4271152c8b26604ed45535954c0a45296e32445b4b87f8a5abdb2421f40b59b4ca437c4346af0f28179780d604094eb64546bee2019d903d01c6c19bdb @@ -6723,6 +8165,13 @@ __metadata: languageName: node linkType: hard +"tweezer.js@npm:^1.4.0": + version: 1.5.0 + resolution: "tweezer.js@npm:1.5.0" + checksum: 10c0/3ae9627fd89ce178fb51da4a405677b9c1fb8f58a8bcbdecd345cdbae8304c9b71f675e286af648d38cc9089577dd6ff7ee5d93f634a7d988566687e1a011e27 + languageName: node + linkType: hard + "type-check@npm:^0.4.0, type-check@npm:~0.4.0": version: 0.4.0 resolution: "type-check@npm:0.4.0" @@ -6746,6 +8195,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^0.8.1": + version: 0.8.1 + resolution: "type-fest@npm:0.8.1" + checksum: 10c0/dffbb99329da2aa840f506d376c863bd55f5636f4741ad6e65e82f5ce47e6914108f44f340a0b74009b0cb5d09d6752ae83203e53e98b1192cf80ecee5651636 + languageName: node + linkType: hard + "typed-array-buffer@npm:^1.0.2": version: 1.0.2 resolution: "typed-array-buffer@npm:1.0.2" @@ -6798,6 +8254,15 @@ __metadata: languageName: node linkType: hard +"typedarray-to-buffer@npm:^3.1.5": + version: 3.1.5 + resolution: "typedarray-to-buffer@npm:3.1.5" + dependencies: + is-typedarray: "npm:^1.0.0" + checksum: 10c0/4ac5b7a93d604edabf3ac58d3a2f7e07487e9f6e98195a080e81dbffdc4127817f470f219d794a843b87052cedef102b53ac9b539855380b8c2172054b7d5027 + languageName: node + linkType: hard + "typescript@npm:^4.5.4, typescript@npm:^4.9.5": version: 4.9.5 resolution: "typescript@npm:4.9.5" @@ -6862,6 +8327,22 @@ __metadata: languageName: node linkType: hard +"unique-string@npm:^2.0.0": + version: 2.0.0 + resolution: "unique-string@npm:2.0.0" + dependencies: + crypto-random-string: "npm:^2.0.0" + checksum: 10c0/11820db0a4ba069d174bedfa96c588fc2c96b083066fafa186851e563951d0de78181ac79c744c1ed28b51f9d82ac5b8196ff3e4560d0178046ef455d8c2244b + languageName: node + linkType: hard + +"universalify@npm:^0.1.0": + version: 0.1.2 + resolution: "universalify@npm:0.1.2" + checksum: 10c0/e70e0339f6b36f34c9816f6bf9662372bd241714dc77508d231d08386d94f2c4aa1ba1318614f92015f40d45aae1b9075cd30bd490efbe39387b60a76ca3f045 + languageName: node + linkType: hard + "universalify@npm:^0.2.0": version: 0.2.0 resolution: "universalify@npm:0.2.0" @@ -6876,6 +8357,13 @@ __metadata: languageName: node linkType: hard +"unpipe@npm:~1.0.0": + version: 1.0.0 + resolution: "unpipe@npm:1.0.0" + checksum: 10c0/193400255bd48968e5c5383730344fbb4fa114cdedfab26e329e50dd2d81b134244bb8a72c6ac1b10ab0281a58b363d06405632c9d49ca9dfd5e90cbd7d0f32c + languageName: node + linkType: hard + "update-browserslist-db@npm:^1.0.13": version: 1.0.13 resolution: "update-browserslist-db@npm:1.0.13" @@ -6890,6 +8378,27 @@ __metadata: languageName: node linkType: hard +"update-notifier@npm:^4.1.0": + version: 4.1.3 + resolution: "update-notifier@npm:4.1.3" + dependencies: + boxen: "npm:^4.2.0" + chalk: "npm:^3.0.0" + configstore: "npm:^5.0.1" + has-yarn: "npm:^2.1.0" + import-lazy: "npm:^2.1.0" + is-ci: "npm:^2.0.0" + is-installed-globally: "npm:^0.3.1" + is-npm: "npm:^4.0.0" + is-yarn-global: "npm:^0.3.0" + latest-version: "npm:^5.0.0" + pupa: "npm:^2.0.1" + semver-diff: "npm:^3.1.1" + xdg-basedir: "npm:^4.0.0" + checksum: 10c0/75deb7313ad1aec72862e7bdbad8b8fbc4d6ffe3be90c2186bd647e9141d90a9620a7451c8ead9eb3c102ef05b21188140af55d3c31ffa6db0755fb948e59bc5 + languageName: node + linkType: hard + "uri-js@npm:^4.2.2": version: 4.4.1 resolution: "uri-js@npm:4.4.1" @@ -6899,6 +8408,15 @@ __metadata: languageName: node linkType: hard +"url-parse-lax@npm:^3.0.0": + version: 3.0.0 + resolution: "url-parse-lax@npm:3.0.0" + dependencies: + prepend-http: "npm:^2.0.0" + checksum: 10c0/16f918634d41a4fab9e03c5f9702968c9930f7c29aa1a8c19a6dc01f97d02d9b700ab9f47f8da0b9ace6e0c0e99c27848994de1465b494bced6940c653481e55 + languageName: node + linkType: hard + "url-parse@npm:^1.5.3": version: 1.5.10 resolution: "url-parse@npm:1.5.10" @@ -6916,6 +8434,13 @@ __metadata: languageName: node linkType: hard +"utils-merge@npm:1.0.1": + version: 1.0.1 + resolution: "utils-merge@npm:1.0.1" + checksum: 10c0/02ba649de1b7ca8854bfe20a82f1dfbdda3fb57a22ab4a8972a63a34553cf7aa51bc9081cf7e001b035b88186d23689d69e71b510e610a09a4c66f68aa95b672 + languageName: node + linkType: hard + "uuid@npm:^8.3.2": version: 8.3.2 resolution: "uuid@npm:8.3.2" @@ -7097,6 +8622,13 @@ __metadata: languageName: node linkType: hard +"webidl-conversions@npm:^3.0.0": + version: 3.0.1 + resolution: "webidl-conversions@npm:3.0.1" + checksum: 10c0/5612d5f3e54760a797052eb4927f0ddc01383550f542ccd33d5238cfd65aeed392a45ad38364970d0a0f4fea32e1f4d231b3d8dac4a3bdd385e5cf802ae097db + languageName: node + linkType: hard + "webidl-conversions@npm:^7.0.0": version: 7.0.0 resolution: "webidl-conversions@npm:7.0.0" @@ -7130,6 +8662,16 @@ __metadata: languageName: node linkType: hard +"whatwg-url@npm:^5.0.0": + version: 5.0.0 + resolution: "whatwg-url@npm:5.0.0" + dependencies: + tr46: "npm:~0.0.3" + webidl-conversions: "npm:^3.0.0" + checksum: 10c0/1588bed84d10b72d5eec1d0faa0722ba1962f1821e7539c535558fb5398d223b0c50d8acab950b8c488b4ba69043fd833cc2697056b167d8ad46fac3995a55d5 + languageName: node + linkType: hard + "wheel-gestures@npm:^2.2.5": version: 2.2.45 resolution: "wheel-gestures@npm:2.2.45" @@ -7150,6 +8692,13 @@ __metadata: languageName: node linkType: hard +"which-module@npm:^2.0.0": + version: 2.0.1 + resolution: "which-module@npm:2.0.1" + checksum: 10c0/087038e7992649eaffa6c7a4f3158d5b53b14cf5b6c1f0e043dccfacb1ba179d12f17545d5b85ebd94a42ce280a6fe65d0cbcab70f4fc6daad1dfae85e0e6a3e + languageName: node + linkType: hard + "which-typed-array@npm:^1.1.14": version: 1.1.14 resolution: "which-typed-array@npm:1.1.14" @@ -7197,6 +8746,15 @@ __metadata: languageName: node linkType: hard +"widest-line@npm:^3.1.0": + version: 3.1.0 + resolution: "widest-line@npm:3.1.0" + dependencies: + string-width: "npm:^4.0.0" + checksum: 10c0/b1e623adcfb9df35350dd7fc61295d6d4a1eaa65a406ba39c4b8360045b614af95ad10e05abf704936ed022569be438c4bfa02d6d031863c4166a238c301119f + languageName: node + linkType: hard + "wrap-ansi-cjs@npm:wrap-ansi@^7.0.0, wrap-ansi@npm:^7.0.0": version: 7.0.0 resolution: "wrap-ansi@npm:7.0.0" @@ -7208,6 +8766,17 @@ __metadata: languageName: node linkType: hard +"wrap-ansi@npm:^6.2.0": + version: 6.2.0 + resolution: "wrap-ansi@npm:6.2.0" + dependencies: + ansi-styles: "npm:^4.0.0" + string-width: "npm:^4.1.0" + strip-ansi: "npm:^6.0.0" + checksum: 10c0/baad244e6e33335ea24e86e51868fe6823626e3a3c88d9a6674642afff1d34d9a154c917e74af8d845fd25d170c4ea9cf69a47133c3f3656e1252b3d462d9f6c + languageName: node + linkType: hard + "wrap-ansi@npm:^8.1.0": version: 8.1.0 resolution: "wrap-ansi@npm:8.1.0" @@ -7226,6 +8795,33 @@ __metadata: languageName: node linkType: hard +"write-file-atomic@npm:^3.0.0": + version: 3.0.3 + resolution: "write-file-atomic@npm:3.0.3" + dependencies: + imurmurhash: "npm:^0.1.4" + is-typedarray: "npm:^1.0.0" + signal-exit: "npm:^3.0.2" + typedarray-to-buffer: "npm:^3.1.5" + checksum: 10c0/7fb67affd811c7a1221bed0c905c26e28f0041e138fb19ccf02db57a0ef93ea69220959af3906b920f9b0411d1914474cdd90b93a96e5cd9e8368d9777caac0e + languageName: node + linkType: hard + +"ws@npm:^7.4.3": + version: 7.5.9 + resolution: "ws@npm:7.5.9" + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + checksum: 10c0/aec4ef4eb65821a7dde7b44790f8699cfafb7978c9b080f6d7a98a7f8fc0ce674c027073a78574c94786ba7112cc90fa2cc94fc224ceba4d4b1030cff9662494 + languageName: node + linkType: hard + "ws@npm:^8.13.0": version: 8.16.0 resolution: "ws@npm:8.16.0" @@ -7241,6 +8837,13 @@ __metadata: languageName: node linkType: hard +"xdg-basedir@npm:^4.0.0": + version: 4.0.0 + resolution: "xdg-basedir@npm:4.0.0" + checksum: 10c0/1b5d70d58355af90363a4e0a51c992e77fc5a1d8de5822699c7d6e96a6afea9a1e048cb93312be6870f338ca45ebe97f000425028fa149c1e87d1b5b8b212a06 + languageName: node + linkType: hard + "xml-name-validator@npm:^4.0.0": version: 4.0.0 resolution: "xml-name-validator@npm:4.0.0" @@ -7267,6 +8870,13 @@ __metadata: languageName: node linkType: hard +"y18n@npm:^4.0.0": + version: 4.0.3 + resolution: "y18n@npm:4.0.3" + checksum: 10c0/308a2efd7cc296ab2c0f3b9284fd4827be01cfeb647b3ba18230e3a416eb1bc887ac050de9f8c4fd9e7856b2e8246e05d190b53c96c5ad8d8cb56dffb6f81024 + languageName: node + linkType: hard + "y18n@npm:^5.0.5": version: 5.0.8 resolution: "y18n@npm:5.0.8" @@ -7295,6 +8905,27 @@ __metadata: languageName: node linkType: hard +"yargonaut@npm:^1.1.2": + version: 1.1.4 + resolution: "yargonaut@npm:1.1.4" + dependencies: + chalk: "npm:^1.1.1" + figlet: "npm:^1.1.1" + parent-require: "npm:^1.0.0" + checksum: 10c0/3d9ece55799075ae7e39b3b0c3aa043aa648cf3326bff9c3fca8d49ad4ffe314a444a8afbd74983132d6b8bc95c3967a6456da078c45599ce4a6f4219d64727f + languageName: node + linkType: hard + +"yargs-parser@npm:^18.1.2": + version: 18.1.3 + resolution: "yargs-parser@npm:18.1.3" + dependencies: + camelcase: "npm:^5.0.0" + decamelize: "npm:^1.2.0" + checksum: 10c0/25df918833592a83f52e7e4f91ba7d7bfaa2b891ebf7fe901923c2ee797534f23a176913ff6ff7ebbc1cc1725a044cc6a6539fed8bfd4e13b5b16376875f9499 + languageName: node + linkType: hard + "yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" @@ -7302,6 +8933,25 @@ __metadata: languageName: node linkType: hard +"yargs@npm:^15.3.0": + version: 15.4.1 + resolution: "yargs@npm:15.4.1" + dependencies: + cliui: "npm:^6.0.0" + decamelize: "npm:^1.2.0" + find-up: "npm:^4.1.0" + get-caller-file: "npm:^2.0.1" + require-directory: "npm:^2.1.1" + require-main-filename: "npm:^2.0.0" + set-blocking: "npm:^2.0.0" + string-width: "npm:^4.2.0" + which-module: "npm:^2.0.0" + y18n: "npm:^4.0.0" + yargs-parser: "npm:^18.1.2" + checksum: 10c0/f1ca680c974333a5822732825cca7e95306c5a1e7750eb7b973ce6dc4f97a6b0a8837203c8b194f461969bfe1fb1176d1d423036635285f6010b392fa498ab2d + languageName: node + linkType: hard + "yargs@npm:^17.5.1": version: 17.7.2 resolution: "yargs@npm:17.7.2" From 20ad5e5e27153bd11317b0e4a463bcf902b97a1d Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 1 Apr 2024 21:50:03 -0700 Subject: [PATCH 110/189] Add link to deployed documentation. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7ec613f0..c4fab493 100644 --- a/README.md +++ b/README.md @@ -29,4 +29,6 @@ A comprehensive camera card for Home Assistant. * Direct media downloads. * Lovelace visual editing. * Full [Picture Elements](https://www.home-assistant.io/lovelace/picture-elements/) support. -* Theme friendly. \ No newline at end of file +* Theme friendly. + +See [full documentation](https://dermotduffy.github.io/frigate-hass-card). \ No newline at end of file From 71eac1b4d9da250cea65db02f3a3c27947ad50c2 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 1 Apr 2024 22:12:32 -0700 Subject: [PATCH 111/189] Add the word 'DEV' to the coverpage for now. --- docs/_coverpage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_coverpage.md b/docs/_coverpage.md index e203eaa3..777ac33d 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -1,6 +1,6 @@ ![logo](images/frigate-logo.svg) -# Frigate Card 6.0.0 +# Frigate Card 6.0.0 *DEV* > A comprehensive camera card for Home Assistant. From 0b09bd6c3fe5bbf37821aab439772a6d7c0afa40 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 1 Apr 2024 23:07:50 -0700 Subject: [PATCH 112/189] Add documentation favicon. --- docs/images/favicon.ico | Bin 0 -> 143732 bytes docs/index.html | 3 +++ 2 files changed, 3 insertions(+) create mode 100644 docs/images/favicon.ico diff --git a/docs/images/favicon.ico b/docs/images/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..dce649962bc0a90f8328eced29fee2221915242e GIT binary patch literal 143732 zcmeI52V4`$7srFBUzdsp=A3S#fQor=Bpev0KU*n8*fh`slMo)r~)?}!b%o()9> z72*H;EjzhD0wf`Uc$asd@4cDXnKy6V&d$#6MpY;*6jlm~g(9b-Q6`0AIMVL!5&44F z77AaKb?Ow6-{_%GytTJbRH-5#uclCV?6pvoC?Oxur%)XJ3QIZVysbjfEqfw`Ei~=- zN~}<%ES5+ytx2QWsgh?+u23ja)vZ&b8IKZc99MiD-RYe|ktsvn8dY1k`oHrWxxD46 zU1!{!N~FknVrP;jZSrK!FzC$2jniIP<=I$p+LNqhN~T@&WW1x-Mw<+4N)~V0rNq&^ zS<8*DI&1Lg;%QP&uUfN?qH0x(&bD*=cgno@U2vG~>CP`6y6nGF;lUs8pO5+3^Je7- zx7z=4`Q5tBS?g#gXRT&>E86Zn`f{@W?q0j^Wme4C<$QG3*MhZ@O~00?*znMnQ)l^2 zZRj_#q2J_|t!Ee8=sUdmmSVf?KiyXNWp%oi!Sia4(NA4^&1v>_T9>^woBG#2-*jBo z7HhJ$+*m6~t4<{s2Bh#aW8(HRe~bP9w69e_F!&$kp5RCxlPgzwbwOrwZTF`OGe#dcxqu-`6bJU+c~)uQux* z1SQ_-RC{ompQWmLY%S8bYyEd0&-Hc9YyZ4elIII9__@s8mL&Xq*0JZ#jNJRR{PSG* z7dStuzqLiv%5}qPcnli$zq|E{KhE%Wt5c7WmiGpg*ifXf*BH;y$$$IW@6(>o#T~k4 zd$;StNWbZsK31=J%k5I9rk5)@@YGMKdw904 zpTjGl%DZ`&lKCx|)1&0dql?cBAAh)ig-RC=-X1*WQ`ek6_5bSN@-o%N$8A>ouG!Y7 z-H8Qz&y@ELv^{FO%qINK;iAREzqh^8!aHzYw>c}5^*dLx-L`EXYTZ0{%s;gG%B9XP z&Ru-m^}yNA1;T2&+$-eT#N)>+pL@;kjdTdUZ5O=QXF-?X_Y1mBD*e+kq|wHV3-bqA z?3~-UZ{Lckp4PnEIMst%#R^>a3~v_Nx$)8M+g_Hw*lknJ(FHEgTD#8et@nm0j+4E5 zy{VAup6l#_KX1+3=RJQ>?>E&f?9P_)AJynW`rc0${`}T`ZL#S;W{tF}-=#uOfpf{< z=Q%qdq}8)+N6+5&ulO;g)y`TjcMAR0-Xqki(cyF*7R>hiG`sa!%k%4A+xsk;?Z4v6 zguQ<}$uRu)FF|!{7Tb|_o!#S|KleE{aw*c`@g@JP1APyrAAhd(*~Xsrc20A?eS3Os zziA(Ozd3BNtU^1FkmN6$ZGF1Vf7C~7hpV?oS>~U1J@vD~HbeT&4bJr`srR!W|51;Q z=YL=1Y}y? z;z32PCG$Txt=f@yuCqdVygT<>_b3Ue9h)9! z@jrN}*3TbW8s*Bf`5c+_S)Y>^h6S=Z^Jwd!nsf{+mtC zPH{@rGs|e}-RT4K_4h3I#KAx7!jzqs`%T)^CC87Equvy^&G%R9-kq1OSlZev%_rZP zUg0}7UG5UFBe;aeP~RKJTBSJ^R^!4_KRer9fldYGXdVlQn_8Mg! zv)mX{J=AOKp}-Wow%5<@U=^OX-qljW?JiW>G;`g_%)$M4201jnyrRqh94cl%@!Qu- zZ3kYS=0EDP&;3_plO{j$yM>~tuba!-6$58Ay?#aU{?z1+74J?gaOv2jv=d64Z}aBy z>p9Ez)$EnnX3uhmfsb>psx@MEm!WGHkMW-M=bll8H{WfHYt?FNod$pUrN3*nVNV|W z>?4E2UuJaf+4gYG3jW_pyEnB+y0!3(1>@>xPkG=@*4i#_4{+mtm=OM+>VQmt9%PheVV_1#qUqsbx(F6)1ryHAGb}N=HAr8 z6UQXIm!jCdm!;n=@}FO!bD7LvQDv&+ zu?>C|?@he;XWjWNhs-Y>R(kx1=Sed88>wWtJ9_{P+%xCM15##%oyqGEA@3ZgU3>cTJ zi}f?l);V?#f3oPwwqwbHF=I%k4CvR8IN!qUZr#csB9?te=*N!$0dn@HQ)Am-I zNp{yiINP5YIWPEBIhSh>#$y-{ids_@n zogvr#GuI|vzSV4fWuL;$AGIswF}>K(0m05W_Kbg*H1Ur_*(Xi#Y~5<;{o?s+9!%xc zy^Tw%{8?Y;{phj$-p|Ho9>2==Y*(kGB^+Pfui7o~#QUy2EbK1t-d--S#fwBm=eBD$ zWO|yacF9-PS@@*-)UiLujkKB2@O1x(FKUamAi0Z)a33kiJ5xo^Ch0Y#IEr z*0Cav7kXc8P^_lc2)h+EosP|#ccaXj^?rzXF_3jEAN{{N%F#X3Nhthff^~&aB zL6=PTJ-@BJd~;CgMkmURNMpNy$&fo;cBM$Vy5N(=r>54Zp5;Z>Me{#4ozqdVyVm(< z$p%%M;5BaD`x^yzrRq64hoy_}*0+bcd>MVNc;M(GgGz! z#!~kd)#;JZF1T{)yInJE@B1Uk)qv!MwqH3sXWk39Bj<-Xzt}jlX4$C&{z$c}lw!-~ zJZsXAs8jReg|Rh%E7E<*%~w61ChOc&;rZvm(jK*o>|4HK(K=VlG6#=8X=RbZveVGL zE&pzo>%EOvsse2rBpGmZVXjn1I+tu!wxfIM;VEX;sgSbgrhT4COQl%2toVvoU4vHp zXRZ=nXSYS-=jStbSYFo7WpB+oRd+S?FP_cv)#{zrp_45RwA%H>V{sDK7A})LTKguy zm$^!cy}JtLaLN=^=hoNegROe>o-sGk42ONQEYepGUO)Zz$9t2?ZLvMG#WP2iDlYHF zcD8POJL9Tk4&N(`+j-*BZ??^Dt{9#2eYZ;eb7h^@V%)N(Yl_v(ll_uKq7AvG%?&Hr zF7;T&$HIz3tu&$ya7D9QWl z3p;0Oms!zp>ehg3L$V&*QLI|JF!$iSHG8=)aB!biv`DAc^}2?n3Q23z>%vvVjOU{U ze7|acXVcjV)8{V!`!3c@}RemT39^EXwu{-jb&Opwai!R$cOC+@~zHXPxR-Y*8vj`Rq@e zd>)R>@cnh6qKUfoOW7&UZ5NNPn}l0!%P)$KcT&Vz+lhtF*J z<9NHbf2U9^n|@?Slavns`_|-A)3@om?&`F^l;ZVQr(#PV+b#UwZ?0#d`|Z1VcO8Fy z$e>LPJ6E#Yx!J!+jzN>|v_IZ7#A(v#8y6j?E=ldV^M0F4jxLpwv`Tt=h(pIb7pvZ{ z_G#$H%AeA1Z<;yTmKq&~cXZESJ*>=I9uM! zarvg7=bpVCKd0=sdeH)l)LV{~-rt~Jhm+$yzRhgE`{w(sZ4Np3d}=+p+WWOx9G|7> zT*z)?@LzAndvy=XQsR%0hG%Dd=>N^{^3V%~1MbZ|cKm$ij=T2GopibRsrHlXQiZ*% z=9s77x5MMl9q_$peY5lAUH%hN4(Z#v-N3t>OI~&xc-LyjntR2=Ut6ZU==kjI%u{9S zx>VbhVM4>ti@xW7JJGG*r)4fDgHCN2@U^UE>*5dg&bLjJx_iy(Rl_Hquqos+)U$x4 z>jm$|CGSf%eCw2RSqw0d@I@w8lY(0{l=n+ik;5o ztS5voET7@+>4vjYRZI_pf($dv@me)|Rb% z*Kn{}F|NSwI`j5rJkqe1SD}nuERMe0>TqN5!MnYFG+BAyEBi#3t5)y29L%%W>3K+c zho_Bp-A~n~d!08^x0Ld#v$W5{>CWZr?=5+%!%vIHbN;&YamNyeKCZL;?lo<5$9qza zNe7pH%u(BE)4m`}>z;}S-;R2}$o<5!(C(=@PQC6}-ELm!{E#Caho(JVlCNR4=IMGB zxLWk&o3RZpmCSIUNYLwCDF$t8Ir-+ix$SN~8lJw~=bleXIVU@|{Y=W4ZGJEeb}t9#rlEPm;C`u?7*!MHIh73BHBY4_}@Re6L z1c$GkyK9ltfr{ggPP}iC@@3ku>0eaZRdj#RQ+ZDOc$9oinz9+*H9b&qsKuVr^S2b} zI5=~Pf+q+2I}BBfE&TQG>vjCURh!6NscWafI)2xNF&*jhtE?x_#J}T-xeQV=m z>F!mWuy0k{#W`9{$aQ4=rA4mg>rMFN(|VWh;`UwKP7KO2=WIJ4$83d<51Tcr@^9|z z9*%jqrqfbCum9zC+O{lrl0Jb=#%4M2_4VEZS#p+H^)%7Nr1z6d-gYY8mUX=|r6^hX z`j)}90(>tfxj1Fq{=xg7j(9)e@ox8R-~ReK!!uv-wEtC@d@IfVZ}W!T$aQb%*p*AY z=4D(O)*v8l|4ThijXBqMMa?l~KDFvwp;7i@^DO?}*2TX65w{!ToOTB;z14HA-<%?O z+`{V)$#*ZsyM=?c|FO-+w{Y`{Q`%H&6!PMKg@z`rGyf@<(k8w&58@HH zM$@lPJud_f9GXCFLlbD&mr-#yM97S}8` zWBm8U0Yy%<0>=b=h&%|7yv11>HI}ee!7Jg7vkIzVm4Qo1=4{)**`q zrYnEuf>oJHVFl~myR&8Vk0Pr}jdI>zC+KY-yG`5f^=sH^wfDmjI~z54*uv-7$c1$; z7j~_`w1C_8ZFk*$*V5|n;cw9+~dW$BtunoE+LYk=5XBFIR25eB#@i2Hn3bNU?Tt<>3Jp>`J*+C_S#LQ|;6Z z(mC(&>@xV>=IC*7$m`!ii}g+?x0{ST{1smFI=e zoGkP%Y~QnEd;fSib?Cl*Pcp1{QDXMaW(TiS>SVjnCFALWz89<J;zdIHC@bdGx#!Xynb?cn>kI*H4{_--*Q=A2+!+%t-!(y$MPM{IcDLG!|q4QmkKPgeSR0WUfI`=wZ1&FM1`Y4sTU4v z=kqM6+_Y(4bEaK-{iu<5;N<1jpFX9SV;!)5U$Y@$ijalgN3(q_YIED}&EgYZ51%~$ z$J(XN>EAdOYqh~Go2%2w7rCwsEPwV%r4sE!Lo@mI`u6*o-fwp}9j#z7rTgJW+(ixi_GI=?*aT@x#Z6oWkYdThQ3a#9;bXNb7t3M1J zH^h7Ot-~dke5jo?g==a1%^h>!{*?IRv=ldYXWH?+Tj~pc&fQ+V`|^yPa*cYLH)Tzm zi)DMJ=pO7_z}6{o?hP4d1Ujxbp1b*`(sd457QOT&FgX8*4?mM0Jw9W|hkg!Ijw&9JnpF20YMNm+kCuJM|y~B6d;fecqp1s*?M1_JQdnvNNzyEDP>q$vM ztRDL0Zod7&qe0JBSp+C*?_YeYbEUFtQVuPd$-YyM_eZ~^I#=7$)h^q$Ojc`b{BvcU zv#jFQZ0`{cZ9ff3YkhTPmZfWoeXZ&6`Ba#n{gJIR$F-gl9*}O#+eibX4io=4nscOR1BY#qsjDU=|6<@wAov&$lfYNJXTs?YC5S;zv}rmH<{I^#j506 zc4mCOvC3a}w-y^+Ok0z#IW{1k4dIN5C8ba|Fy0Fh{@~0doY*5%{$u5FQ?` z0Es{fU=K=y@}M%P4H|=%;CIjrGyru#bx;Q60k$A9psim!ApZgH<@1ytn&)x|ms4Y&im!7|_mT7x1W9k2rCIbmXRN+kLbZ{GZ0vBKhqpwYj7&51GcKt%kYxd&?kHh~v_vKOQQYF@Am@H(6f zeuDUvFm(1e*af3PhRKy3GYbT$}c;2}uk4|`Qx&KlN7RzK9d#=q1DeT`Da6K^J7u3#{ zLYyl;tMk6S1@PG{HsRVn5m*8>t1JUtLpYC2LHLZxdl>gF9IKko|HT5v0q`C_2XfQ>-kb$S)r^4UNwTr300 zz!G3e!m+LcMZte=4#;Cp0^JD2b&nPZ8!cp;k>-FXgDwsp08qzetBRT&s z&0wsY@7xEC0DM+5g!sS+pS9GY#xlVBtviVC=RtHCtGq#tW`KUG`TuVz5aWa9d0Ghg z3}-0$4nqTh#%FDmGq$uTTpe%K)DmH^f$xh^A`Zi#V zCb|pxNXDL0|_BKucLv+dn?N6V|H)?#JBKypL-Dc5a|?( zGUx^%5KySQ1C3*eWFUbv@KG8QbaRlTTjw_X9JAS>a7#%F7kGnT2qMi5`(hmQCzTJ1c_ zWxOx-10f))aIMM-67n=h+c*6J+^cK>rXug)NIei;yjfleJORcQzVqUKj^|h{jw}Ow zKgMqYnuPnP1wi9`Rx=on1@MW!^I3)COQ?H3y4EOMOSz`1MTBJ_F_;F7{fu%NedGYq z`N8;2iN%jkIL><({Z_M+PzAC-yw?T*Qxnd|K|o{73ud<5FcD^#ou z)NHESH+EX?pL@Q;z|@6%JSU(QGf@WJ7<>SR63)B1K;yNFa{9u($swStY(N7(zZm;8 zYqZaPWx7F!fL}p2!%2-XLpjGI-n$uUEVp2&Fl|Q_mH|Es3;_DvC^w!qk@JCc3&C&Oz$ z82n0d49;c)k;cRf%K-NXlL4RC<08k=nAb;4{mhC>2WZPRpg#K`@g;J9>7jkVuO{5% z4+n{WTF6)i@_>s#U*TT3IZ!(54$@e26mWHh_B(LkY){1gMS0&;{%RaNqI}{K~@XrUr=VJT<`acRCD` z@91X$jpqX8>?f_1Q3(6e*r55&ssvzcer5O_g?llL(O@~S1a2U< z=fNYW!?>u~Vj1AMnFov|elVP7Js(^bA zW62j7ZVuFZh~$ttqf-P#JfS-P##obhp)fg6v&}NVcXZo@Uenf#7oDhPk1{SW+# zW)%7r)1FLqXzq7~gds5nXuRf7&UV?r84w>5fKCbm{RSFME83H(0KF0LI@oDK&>#Ax z@x4nl!_ui3wiyGyFXFovA$&)i7pU1{8Q}FY68r%1Az#tS??5_VYEJ1{AltKm9uG`a zuEMbbK+jRe-i)>ZpBe4~KJRr08e=V&mxMOf^BzoVlrbpP=u_+?)LcWh$9EyT#!OLo zE~0(*);ucROVJ18%4>QMU@T&KcVva*i$Ht}e;dYYRrdi#(}K1D_Z7#0DGK*J8lSzR z8Is<`=!dc3ena}U%e<<{$62Q~cnjiNHlagatEz6rDNS2|@x260P2R&H{{E0Y#%Y{} zXe|4Y2Acb$gpjl7lzUD?3`ep-TOc2Z?|T`#j8&GRhC%1MzJY@u(j0{D3b+?b2zic9 zivxX!q1KMJKxOa}n3C|>y9_X;Yde~)}Fh=xcEQsw}0jd~H`1@sNpzly3wWA%GHqiXeXez?zJ(Ky~0bdv=u0;<) zLP{Vymwwj}=|t+8fh}?VJ0Z>IEK`sWIKk&VgFffz86puMYxuL=1cLJkKGXyH4kuDO z+L7r7{T-Ns`~@fY`>aU5CPaol$S~%77D;H~@5-70gM@>2WV%3`!ue;68wtM*GRQa> zk^RU3y&sr@80-AE#o)N^CbW3M0gc~U<8T`FY6?HZwb2J@Q-}@E4fp8$-J)J&($t8y z0N=61$2UxL6RmJ>RSHOP*W_z_mdSqPfxZSzMR@!XwV0Y*fkXDdV3DCMkQy8W@hyL&!&*S?+81TenL)ff6UcpLg62C2 zQoTB8 zKBADnRZyEdYR1e3T1P;{6S_Mv=AUPH3HwzwfP;|9n|AojmcI`9KQ!%0j@j0Dtt#a6By;$ zM+6Y|#W~uE*b+$IG4v{csL&y?g)+ zDJNho3lOJVsaXc}`PTXd?W)V|mG+nrWzaPMub*F8cui=0R*p1i17y$-W5@gR3ScPV zca)YuIxnhjiZW=v*LVbUm0f6%7O0w)(kug3U_Rj9<5v{=JsBAEov&K3c;z^^FWvs40Vu`^Zy`vNv#FNmu= zgMkV_?fi%`=oTO@bL}G9=cK);!ZI0t)8QWESCfr!I9|SeirAq)5wo^P^ZL?P_$_HF z(710!Is4)74vvDj2>WpZd}l0%q0}q`SpoMTzmj}{vyFgsK9mEBhlJcGpE*wgedQ_| z7657SqLhEyW*rt!L z6V+e2+|c*sRj{jZt(5!YK4UHT6@=eNeg|svIchA8m6!WY4}B2mDs02HYVNTN@SZRm z7*amKn8x)IAJ2jFmKG!73wJ%N>`WG?dvjAhOt-MFYCO~cOiZbXb-~}+W zaLweNLJUKxSq74T8NigE2N}P5KrMdC!NgNS_JM1vF6*Wz>TCQv8)SQ_p|=2I2=6=n zfyUU$<@uqn08A-=Wj3!kk91HOxnPC{{DJg@|6Zn6yI0H=X5h1bw@ z5YuyK1{~+T!jy!2zRtj8&b>H^vQIY9t3hfPdmVwnX}Ml%VZHJ}v7+6_$adU;&6v;d&nL>xhcw^Ili|bzU2fu%myO)#SF^; z_bTpydzXX|&QU(EXxuZYIc)+3@Rf1nGvQ3YJ+ud~25R2145SD9K|;uPbUGYx?-8AU z+_Rhq@h$X?`&7nK%{Nmnpud27XvVfM^HGImGTaw%e~?h(kB%KcR2PMR)Lno+@43-T zFX1!FYLE`7`SmLl&~LzdfrX|q$j5U*Uj_*+T%))LQ41~00MCOrh%aGZjE$N<|AqpN z3vg~s010((Mb}Evk-_B%EEWW6zC?2D7tM%qL6--QfT;+- zsl@h-GRKI{a?L*sih_UTx#yIX$HqO)8emGoJxDj8G4^tKF=%7Fqu@KQtst-5&o6p) z$LzKk8#LdoeE_B=XW{lyKfH1et)wxu@pLFIphR2i+Vz1Ewb2 zi?{(xpcZA80ej#J3?YBR$QZzHo@)L58w)s2!1!_vxC(gRGbMQhXSg>}3qQ+b+CYo< zTS)3G95bJLngJ`I*4Mwefa3*xF62Jf3w!~lBrD*IHBdVZECak=w*!5IzcE|_r1$yI zYJL1y3OIJaSoQ&TfT;-gCXIk}y{n!NQ3hQN@H?Wm!fXBtZ~@%^s+#@JrWpsowZH+a z0=zyIy#oF*{DvVoW641 z;_sd~S5$@j8J>5Jf#0{JaYeOZ&TEcPAAcoR)1I;~REwBhY0{k`_U&8kkjzG7Vv#iO)wOA0)9t73+@8GYvo>&@9n+< zo>#*BJHWZ)2e{`u1-5{Rpf#uncn>n#ILw9(69Jwh!1b8-3a;7w?M5C@8Spu*F=z$a z0j?d)R|lm*Zjc#p-^q70(sux8!#HQQVvc}00_F&qBVdkzIRfSgm?L10fH?x@2$&;a zj(|A=<_MT0V2*$}0_F(BQv~o{^B0gXg~D0Y%|L~MZ+De~yuwYH!zXy;ZT`uh3_<>% z24NP=|I;8;5z4&1Xb`ACe<}ui6l0m^dtgc26>iKc4Z=C*g+Ul|c4yu>qB=UWSIxsY z8y}V90muVoeIJFwDnJ2oi)inTJO?E5NLfnxQ0X{*wUh=JDmCC(qybulIJ1H@Ru)=@ z*eml=qd+Mync@Jg0;G@yASn&dDuBOA4)8a5+H690UF*?<3{IWpU?_ROXNmhb#pkqJj_4G4cTl2 z=A~hyx#*91>AcDH879@dJ@V3dlaEKuJA29JNj~n(_^8--6L~qFW1*$vay~S2-Xc_T z7@a}_I9XKkXlEIsyi_GSm|T*#;{00$sN@l5%nY6^h`r<|CbOGr9y5a{8-n8)CuRmG z1H@U%Bg4rPkw;Ic9C5+R^Bcw^E_msRR@Y40-&WRs!!AD$QytpG) zu!!@>iO)LH>A{4N>i&}tunNE-^dU`81VHK=K1jo7-Umr(fEW%2Ecq@CP|Am5c+wc9 z;o(F}W0fkop?Y|@R8=w}Wg}(+JCUOv(KYh&S&>}h0C5&65w0T7X(aL-puLohI4)oP zERpQVtAkX7{$YU1lkCI%Skaw4b#TE)n3JcTvoJ3kw0CzC$HU#x-u}2UE6qKdEC1x_ zvCp>zTmfx<$O6aRWhM+%~ z0}g;Q;3D8}dHn!?|9cBu11vub_-9Fm1O67Y7~pR{6N6a$HCKp;0AmH3fVlkGEdE)Z z7vLON2%3TH;6HzTAO?&t;cw6L0=_m;PCupr|GW|ByrG1Do`%&jS&G<1FN0T^07!QfFa0OSIE&-Jg3KF21*HN7vm0JuH~Ifg_= zpo{_2fPc1n88DXc&jIn87zzG$=K*69ap#-O?tu45)wm-o3IANxV4&$5a6tJZU`*j> zubZF;;GgYK`k|ZIwQP!?k=C;C)UP;h*KJ z3M4xmuSi380I^*|sA4er3`>0O_$B^)Ap8`uDuDEEz%^AL*^Wk$#*92|^BzLG@hMl) z8K19Bdg{|ZnX=GlKwRW28n*|M%_!GEb(HfOi4WmEA=4DM*Q%le{nKIB($LcT3+5A2RQzE)jIlR)1iRe3Du>Cm%rIzu?=NT?tE@&1zHg1%H}_!^Kpq}b zJ+7=6PYJpIEYSObv1ADhb04c571MzI`T}Ffa~S1)Oc`I1h8_ucZLS5jK@l0 zas(A3T{}uA4Um9sG53cf&HYzG$!2uS^-nn}ra=a96zC%XXjBSFW29j@&1b(cK%4Pu zyhkaWjAKIfhx>vXAR*-oI&TT0#)|o-fNOy+!u{qrz*tLBqLwKM{Rn6)yiPKMI7T~i zbJ~+h=(!I!Bsqcq^Z85ZDAOQ0SOs*Ei>Pb|qT1qG#QUl)!u78skm98@7{`QcFB5b^ zt^4RYl7u41xu6`UNJH~I)H9%s1fx=Cpvg`>lyiTtt8foxu;*gfl6-@10qC!(h(8=D z0+h3hX^;p^0$f*OlYOYbZwgUuq(Pa!zk3Nn+XkvOmB#f*&<@};_DW!CvJehw+Oy@1fkwj|7ahGA>L5-n*XwL&!`R ziPVR(v;RN>V`n^*f@MHe&LR_OZ9txN`Tk}#FqE8tp-A_3UBiy{!molz^WArRu0I*& z{&jU*sxR6?mjDj|Ky-o5qIy1b|jR z87EzQ7j@sTe3vPzh%u%|*&$#^;j>tz=X7PKS|rd`_%_avPHAb&7xfJC z950U}2Q*_}m3blZF^;n@V7v@1gJ4jvIV88^+=;q=8rsLG_P(H?4baPP5nG{UI~+#_ zplQFE2j$!^8bfBls9xic+tJ^x#&9eKn;UT~B@iJril%+QZwXU@v1B(4>-Aj*?dTu( z&?iBB$xC!p3FtLvbU9IS9~GeaENLt`1H*c~3qm`_fcvytAiiV{I^vwvC6qeXrG1bB ztOLfBi!jc6yS_f=LfiYsbWp|i9i$5Zoqg4%0qx81ePR$Wrd)+_zPr)IMX4^^fV?08 z7+d&0c`%S-qqDO*G?4q?z1RmBTW+EQt|2;j7*UmN0QUxufU$+oih9ixT?U3er1J~S zb8U?MCd@_>uHA8oza84&jbzdA8GbM1S`c4zpU?8f9+QaDbtLq9j*;V$1=?79W8vcl zB-Gwv>N2mjsVk2sG4w3aaXjct=!0vWHZDf0!!{rtI1P*?e3v2ZHzRd!;0*c@>kglP zUm0sK8tle(|H=1@CSMN$!F5dAPkHIdifs3CT+NYdw|~^ z+(5FRTdx<>78*T2mj?6j9t2RpcknIB@XE) zXj=*>BgeGNAJBXcp(<~YsR^Vy%0~a8ggo{R&~bfU{|OuJAQ5c}VH)tgn;+05yHTj= zn<3lrevudCGa>TBmz*F@YfqH;aC}^k<05<(n#;Dw36d*u<32`I;^Z-O=e_vBo+^%d?ny8=xytcG%~Gcn0!9MtFB#bnc%$9Uh0 zbe+dB{)`*nk#R2SBYV+^_i?2gOoLQlJBUrVcDaE_V?v%bih{eqROAC3k?vW_!NxHG zdmJZ!kHhyFx{BI86b5LIbOK+1Hu4yiN(1F+n3m!D1Z4iu*-4g1UG=T@&Fb2 z{3e}0x*(^yj*J0ZS9Fm;RF3Z1jlb6l(#4n&>T*8uIVO(LR&P$5G9#e1i5u&T6zx=E zPdmSX0HBW?L8J6Q=_J#D?-|#Fgc7a`Tpy%3DV;N5Lbja^`W%Q&Sci3$9xx58z;d9k z@EVWq-Cac-<32PYIbG` zlv_Aj2q?#^bjU~v(HAt|3q;+&&qEp40cGz@gFN6GFr;jPF-_N5I+PzaWJl51;(n|x zh_~2_pvrynnwtYc0fpB?VIZoB`N;j|BoGD+DLnVwcPhs(($I~-M_?@Bn5Te9&o;_| z$3p^rbKKkuZUNkX4FQ^BVa$CApS!ZKUm>y&$)Mx%&I-+A6kdD0&P2EIuGzN??|E(@ z(*8?6#%siw`*O}hK9guV?|ja90t_uaFvxFQ%0A;g_$nRBen@LR(-h$wbPMnq7*p=S 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 j8{V< + + + Date: Tue, 2 Apr 2024 13:03:00 -0700 Subject: [PATCH 113/189] Only show download button in media viewer. --- src/components-lib/menu-button-controller.ts | 10 ++++++-- .../menu-button-controller.test.ts | 23 +++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/components-lib/menu-button-controller.ts b/src/components-lib/menu-button-controller.ts index 6d0a7f73..388763a9 100644 --- a/src/components-lib/menu-button-controller.ts +++ b/src/components-lib/menu-button-controller.ts @@ -131,7 +131,9 @@ export class MenuButtonController { .getAllDependentCameras(selectedCameraID, 'substream'); if (selectedCameraID && substreamCameraIDs && view.is('live')) { - const substreams = [...substreamCameraIDs].filter((cameraID) => cameraID !== selectedCameraID); + const substreams = [...substreamCameraIDs].filter( + (cameraID) => cameraID !== selectedCameraID, + ); const streams = [selectedCameraID, ...substreams]; if (streams.length === 2) { @@ -258,7 +260,11 @@ export class MenuButtonController { }); } - if (mediaCapabilities?.canDownload && !this._isBeingCasted()) { + if ( + view.isViewerView() && + mediaCapabilities?.canDownload && + !this._isBeingCasted() + ) { buttons.push({ icon: 'mdi:download', ...config.menu.buttons.download, diff --git a/tests/components-lib/menu-button-controller.test.ts b/tests/components-lib/menu-button-controller.test.ts index 305233f5..c6887c37 100644 --- a/tests/components-lib/menu-button-controller.test.ts +++ b/tests/components-lib/menu-button-controller.test.ts @@ -726,6 +726,7 @@ describe('MenuButtonController', () => { createMediaCapabilities({ canDownload: true }), ); const view = createView({ + view: 'media', queryResults: new MediaQueriesResults({ results: [new ViewMedia('clip', 'camera-1')], selectedIndex: 0, @@ -772,6 +773,28 @@ describe('MenuButtonController', () => { expect.arrayContaining([expect.objectContaining({ title: 'Download' })]), ); }); + + it('not in a non-media view', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getMediaCapabilities).mockReturnValue( + createMediaCapabilities({ canDownload: true }), + ); + const view = createView({ + view: 'live', + queryResults: new MediaQueriesResults({ + results: [new ViewMedia('clip', 'camera-1')], + selectedIndex: 0, + }), + }); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); + + expect(buttons).not.toEqual( + expect.arrayContaining([expect.objectContaining({ title: 'Download' })]), + ); + }); }); it('should have camera UI button', () => { From 7d2dd7483821a44e296bddd4c2d8815403c6b090 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Thu, 4 Apr 2024 15:02:33 -0700 Subject: [PATCH 114/189] Refactor menu buttons controller into different functions. --- src/components-lib/menu-button-controller.ts | 538 +++++++++++------- .../menu-button-controller.test.ts | 119 +++- 2 files changed, 445 insertions(+), 212 deletions(-) diff --git a/src/components-lib/menu-button-controller.ts b/src/components-lib/menu-button-controller.ts index 388763a9..eeaae499 100644 --- a/src/components-lib/menu-button-controller.ts +++ b/src/components-lib/menu-button-controller.ts @@ -5,9 +5,9 @@ import { MediaPlayerManager } from '../card-controller/media-player-manager'; import { MicrophoneManager } from '../card-controller/microphone-manager'; import { ViewManager } from '../card-controller/view-manager'; import { - FRIGATE_CARD_VIEWS_USER_SPECIFIED, FrigateCardConfig, FrigateCardCustomAction, + FRIGATE_CARD_VIEWS_USER_SPECIFIED, MenuItem, } from '../config/types'; import { FRIGATE_BUTTON_MENU_ICON } from '../const'; @@ -20,6 +20,7 @@ import { createFrigateCardShowPTZAction, createFrigateCardSimpleAction, } from '../utils/action'; +import { isTruthy } from '../utils/basic'; import { getEntityIcon, getEntityTitle } from '../utils/ha'; import { hasUsablePTZ } from '../utils/ptz'; import { hasSubstream } from '../utils/substream'; @@ -63,23 +64,47 @@ export class MenuButtonController { view: View, options?: MenuButtonControllerOptions, ): MenuItem[] { - const selectedCameraID = view.camera; - const substreamAwareCameraID = - view.context?.live?.overrides?.get(selectedCameraID) ?? selectedCameraID; - const selectedCameraConfig = cameraManager - .getStore() - .getCameraConfig(selectedCameraID); + return [ + this._getFrigateButton(config), + this._getCamerasButton(config, cameraManager, view), + this._getSubstreamsButton(config, cameraManager, view), + this._getLiveButton(config, view, options?.viewManager), + this._getClipsButton(config, view, options?.viewManager), + this._getSnapshotsButton(config, view, options?.viewManager), + this._getRecordingsButton(config, view, options?.viewManager), + this._getImageButton(config, view, options?.viewManager), + this._getTimelineButton(config, view, options?.viewManager), + this._getDownloadButton(config, cameraManager, view), + this._getCameraUIButton(config, options?.showCameraUIButton), + this._getMicrophoneButton( + config, + options?.microphoneManager, + options?.currentMediaLoadedInfo, + ), + this._getExpandButton(config, options?.inExpandedMode), + this._getFullscreenButton(config, options?.inFullscreenMode), + this._getCastButton( + hass, + config, + cameraManager, + view, + options?.mediaPlayerController, + ), + this._getPlayPauseButton(config, options?.currentMediaLoadedInfo), + this._getMuteUnmuteButton(config, options?.currentMediaLoadedInfo), + this._getScreenshotButton(config, options?.currentMediaLoadedInfo), + this._getDisplayModeButton(config, cameraManager, view), + this._getPTZButton(config, cameraManager, view), - const substreamAwareCameraCapabilities = - cameraManager.getCameraCapabilities(substreamAwareCameraID); + ...this._dynamicMenuButtons.map((button) => ({ + style: this._getStyleFromActions(config, view, button, options), + ...button, + })), + ].filter(isTruthy); + } - const selectedMedia = view.queryResults?.getSelectedResult(); - const mediaCapabilities = selectedMedia - ? cameraManager?.getMediaCapabilities(selectedMedia) - : null; - - const buttons: MenuItem[] = []; - buttons.push({ + protected _getFrigateButton(config: FrigateCardConfig): MenuItem { + return { // Use a magic icon value that the menu will use to render the custom // Frigate icon. icon: FRIGATE_BUTTON_MENU_ICON, @@ -93,8 +118,14 @@ export class MenuButtonController { hold_action: createFrigateCardSimpleAction( 'diagnostics', ) as FrigateCardCustomAction, - }); + }; + } + protected _getCamerasButton( + config: FrigateCardConfig, + cameraManager: CameraManager, + view: View, + ): MenuItem | null { // Show all cameras in the menu rather than just cameras that support the // current view for a less surprising UX. const menuCameraIDs = cameraManager.getStore().getCameraIDsWithCapability('menu'); @@ -111,47 +142,53 @@ export class MenuButtonController { entity: config.camera_entity, state_color: true, title: metadata?.title, - selected: selectedCameraID === cameraID, + selected: view.camera === cameraID, ...(action && { tap_action: action }), }; }, ); - buttons.push({ + return { icon: 'mdi:video-switch', ...config.menu.buttons.cameras, type: 'custom:frigate-card-menu-submenu', title: localize('config.menu.buttons.cameras'), items: menuItems, - }); + }; } + return null; + } + protected _getSubstreamsButton( + config: FrigateCardConfig, + cameraManager: CameraManager, + view: View, + ): MenuItem | null { const substreamCameraIDs = cameraManager .getStore() - .getAllDependentCameras(selectedCameraID, 'substream'); + .getAllDependentCameras(view.camera, 'substream'); - if (selectedCameraID && substreamCameraIDs && view.is('live')) { + if (substreamCameraIDs.size && view.is('live')) { const substreams = [...substreamCameraIDs].filter( - (cameraID) => cameraID !== selectedCameraID, + (cameraID) => cameraID !== view.camera, ); - const streams = [selectedCameraID, ...substreams]; + const streams = [view.camera, ...substreams]; + const substreamAwareCameraID = this._getSubstreamAwareCameraID(view); if (streams.length === 2) { // If there are only two dependencies (the main camera, and 1 other) // then use a button not a menu to toggle. - buttons.push({ + return { icon: 'mdi:video-input-component', style: - substreamAwareCameraID !== selectedCameraID - ? this._getEmphasizedStyle() - : {}, + substreamAwareCameraID !== view.camera ? this._getEmphasizedStyle() : {}, title: localize('config.menu.buttons.substreams'), ...config.menu.buttons.substreams, type: 'custom:frigate-card-menu-icon', tap_action: createFrigateCardSimpleAction( hasSubstream(view) ? 'live_substream_off' : 'live_substream_on', ) as FrigateCardCustomAction, - }); + }; } else if (streams.length > 2) { const menuItems = Array.from(streams, (streamID) => { const action = createFrigateCardCameraAction( @@ -166,134 +203,192 @@ export class MenuButtonController { entity: cameraConfig?.camera_entity, state_color: true, title: metadata?.title, - selected: - (view.context?.live?.overrides?.get(selectedCameraID) ?? - selectedCameraID) === streamID, + selected: substreamAwareCameraID === streamID, ...(action && { tap_action: action }), }; }); - buttons.push({ + return { icon: 'mdi:video-input-component', title: localize('config.menu.buttons.substreams'), style: - substreamAwareCameraID !== selectedCameraID - ? this._getEmphasizedStyle() - : {}, + substreamAwareCameraID !== view.camera ? this._getEmphasizedStyle() : {}, ...config.menu.buttons.substreams, type: 'custom:frigate-card-menu-submenu', items: menuItems, - }); + }; } } + return null; + } - buttons.push({ - icon: 'mdi:cctv', - ...config.menu.buttons.live, - type: 'custom:frigate-card-menu-icon', - title: localize('config.view.views.live'), - style: view.is('live') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction('live') as FrigateCardCustomAction, - }); + protected _getLiveButton( + config: FrigateCardConfig, + view: View, + viewManager?: ViewManager | null, + ): MenuItem | null { + return viewManager?.isViewSupportedByCamera(view.camera, 'live') + ? { + icon: 'mdi:cctv', + ...config.menu.buttons.live, + type: 'custom:frigate-card-menu-icon', + title: localize('config.view.views.live'), + style: view.is('live') ? this._getEmphasizedStyle() : {}, + tap_action: createFrigateCardSimpleAction('live') as FrigateCardCustomAction, + } + : null; + } - if (options?.viewManager?.isViewSupportedByCamera(selectedCameraID, 'clips')) { - buttons.push({ - icon: 'mdi:filmstrip', - ...config.menu.buttons.clips, - type: 'custom:frigate-card-menu-icon', - title: localize('config.view.views.clips'), - style: view?.is('clips') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction('clips') as FrigateCardCustomAction, - hold_action: createFrigateCardSimpleAction('clip') as FrigateCardCustomAction, - }); - } + protected _getClipsButton( + config: FrigateCardConfig, + view: View, + viewManager?: ViewManager | null, + ): MenuItem | null { + return viewManager?.isViewSupportedByCamera(view.camera, 'clips') + ? { + icon: 'mdi:filmstrip', + ...config.menu.buttons.clips, + type: 'custom:frigate-card-menu-icon', + title: localize('config.view.views.clips'), + style: view?.is('clips') ? this._getEmphasizedStyle() : {}, + tap_action: createFrigateCardSimpleAction('clips') as FrigateCardCustomAction, + hold_action: createFrigateCardSimpleAction('clip') as FrigateCardCustomAction, + } + : null; + } - if (options?.viewManager?.isViewSupportedByCamera(selectedCameraID, 'snapshots')) { - buttons.push({ - icon: 'mdi:camera', - ...config.menu.buttons.snapshots, - type: 'custom:frigate-card-menu-icon', - title: localize('config.view.views.snapshots'), - style: view?.is('snapshots') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction( - 'snapshots', - ) as FrigateCardCustomAction, - hold_action: createFrigateCardSimpleAction( - 'snapshot', - ) as FrigateCardCustomAction, - }); - } + protected _getSnapshotsButton( + config: FrigateCardConfig, + view: View, + viewManager?: ViewManager | null, + ): MenuItem | null { + return viewManager?.isViewSupportedByCamera(view.camera, 'snapshots') + ? { + icon: 'mdi:camera', + ...config.menu.buttons.snapshots, + type: 'custom:frigate-card-menu-icon', + title: localize('config.view.views.snapshots'), + style: view?.is('snapshots') ? this._getEmphasizedStyle() : {}, + tap_action: createFrigateCardSimpleAction( + 'snapshots', + ) as FrigateCardCustomAction, + hold_action: createFrigateCardSimpleAction( + 'snapshot', + ) as FrigateCardCustomAction, + } + : null; + } - if (options?.viewManager?.isViewSupportedByCamera(selectedCameraID, 'recordings')) { - buttons.push({ - icon: 'mdi:album', - ...config.menu.buttons.recordings, - type: 'custom:frigate-card-menu-icon', - title: localize('config.view.views.recordings'), - style: view.is('recordings') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction( - 'recordings', - ) as FrigateCardCustomAction, - hold_action: createFrigateCardSimpleAction( - 'recording', - ) as FrigateCardCustomAction, - }); - } + protected _getRecordingsButton( + config: FrigateCardConfig, + view: View, + viewManager?: ViewManager | null, + ): MenuItem | null { + return viewManager?.isViewSupportedByCamera(view.camera, 'recordings') + ? { + icon: 'mdi:album', + ...config.menu.buttons.recordings, + type: 'custom:frigate-card-menu-icon', + title: localize('config.view.views.recordings'), + style: view.is('recordings') ? this._getEmphasizedStyle() : {}, + tap_action: createFrigateCardSimpleAction( + 'recordings', + ) as FrigateCardCustomAction, + hold_action: createFrigateCardSimpleAction( + 'recording', + ) as FrigateCardCustomAction, + } + : null; + } - buttons.push({ - icon: 'mdi:image', - ...config.menu.buttons.image, - type: 'custom:frigate-card-menu-icon', - title: localize('config.view.views.image'), - style: view?.is('image') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction('image') as FrigateCardCustomAction, - }); + protected _getImageButton( + config: FrigateCardConfig, + view: View, + viewManager?: ViewManager | null, + ): MenuItem | null { + return viewManager?.isViewSupportedByCamera(view.camera, 'image') + ? { + icon: 'mdi:image', + ...config.menu.buttons.image, + type: 'custom:frigate-card-menu-icon', + title: localize('config.view.views.image'), + style: view?.is('image') ? this._getEmphasizedStyle() : {}, + tap_action: createFrigateCardSimpleAction('image') as FrigateCardCustomAction, + } + : null; + } - if (options?.viewManager?.isViewSupportedByCamera(selectedCameraID, 'timeline')) { - buttons.push({ - icon: 'mdi:chart-gantt', - ...config.menu.buttons.timeline, - type: 'custom:frigate-card-menu-icon', - title: localize('config.view.views.timeline'), - style: view.is('timeline') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction('timeline') as FrigateCardCustomAction, - }); - } + protected _getTimelineButton( + config: FrigateCardConfig, + view: View, + viewManager?: ViewManager | null, + ): MenuItem | null { + return viewManager?.isViewSupportedByCamera(view.camera, 'timeline') + ? { + icon: 'mdi:chart-gantt', + ...config.menu.buttons.timeline, + type: 'custom:frigate-card-menu-icon', + title: localize('config.view.views.timeline'), + style: view.is('timeline') ? this._getEmphasizedStyle() : {}, + tap_action: createFrigateCardSimpleAction( + 'timeline', + ) as FrigateCardCustomAction, + } + : null; + } + protected _getDownloadButton( + config: FrigateCardConfig, + cameraManager: CameraManager, + view: View, + ): MenuItem | null { + const selectedMedia = view.queryResults?.getSelectedResult(); + const mediaCapabilities = selectedMedia + ? cameraManager?.getMediaCapabilities(selectedMedia) + : null; if ( view.isViewerView() && mediaCapabilities?.canDownload && !this._isBeingCasted() ) { - buttons.push({ + return { icon: 'mdi:download', ...config.menu.buttons.download, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.download'), tap_action: createFrigateCardSimpleAction('download') as FrigateCardCustomAction, - }); + }; } + return null; + } - if (options?.showCameraUIButton) { - buttons.push({ - icon: 'mdi:web', - ...config.menu.buttons.camera_ui, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.camera_ui'), - tap_action: createFrigateCardSimpleAction( - 'camera_ui', - ) as FrigateCardCustomAction, - }); - } + protected _getCameraUIButton( + config: FrigateCardConfig, + showCameraUIButton?: boolean, + ): MenuItem | null { + return showCameraUIButton + ? { + icon: 'mdi:web', + ...config.menu.buttons.camera_ui, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.camera_ui'), + tap_action: createFrigateCardSimpleAction( + 'camera_ui', + ) as FrigateCardCustomAction, + } + : null; + } - if ( - options?.microphoneManager && - options?.currentMediaLoadedInfo?.capabilities?.supports2WayAudio - ) { - const forbidden = options.microphoneManager.isForbidden(); - const muted = options.microphoneManager.isMuted(); + protected _getMicrophoneButton( + config: FrigateCardConfig, + microphoneManager?: MicrophoneManager | null, + currentMediaLoadedInfo?: MediaLoadedInfo | null, + ): MenuItem | null { + if (microphoneManager && currentMediaLoadedInfo?.capabilities?.supports2WayAudio) { + const forbidden = microphoneManager.isForbidden(); + const muted = microphoneManager.isMuted(); const buttonType = config.menu.buttons.microphone.type; - buttons.push({ + return { icon: forbidden ? 'mdi:microphone-message-off' : muted @@ -315,41 +410,59 @@ export class MenuButtonController { ...(!forbidden && buttonType === 'toggle' && { tap_action: createFrigateCardSimpleAction( - options.microphoneManager.isMuted() - ? 'microphone_unmute' - : 'microphone_mute', + muted ? 'microphone_unmute' : 'microphone_mute', ) as FrigateCardCustomAction, }), - }); + }; } + return null; + } - if (!this._isBeingCasted()) { - buttons.push({ - icon: options?.inFullscreenMode ? 'mdi:fullscreen-exit' : 'mdi:fullscreen', - ...config.menu.buttons.fullscreen, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.fullscreen'), - tap_action: createFrigateCardSimpleAction( - 'fullscreen', - ) as FrigateCardCustomAction, - style: options?.inFullscreenMode ? this._getEmphasizedStyle() : {}, - }); - } - - buttons.push({ - icon: options?.inExpandedMode ? 'mdi:arrow-collapse-all' : 'mdi:arrow-expand-all', + protected _getExpandButton( + config: FrigateCardConfig, + inExpandedMode?: boolean, + ): MenuItem { + return { + icon: inExpandedMode ? 'mdi:arrow-collapse-all' : 'mdi:arrow-expand-all', ...config.menu.buttons.expand, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.expand'), tap_action: createFrigateCardSimpleAction('expand') as FrigateCardCustomAction, - style: options?.inExpandedMode ? this._getEmphasizedStyle() : {}, - }); + style: inExpandedMode ? this._getEmphasizedStyle() : {}, + }; + } + protected _getFullscreenButton( + config: FrigateCardConfig, + inFullscreenMode?: boolean, + ): MenuItem | null { + return !this._isBeingCasted() + ? { + icon: inFullscreenMode ? 'mdi:fullscreen-exit' : 'mdi:fullscreen', + ...config.menu.buttons.fullscreen, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.fullscreen'), + tap_action: createFrigateCardSimpleAction( + 'fullscreen', + ) as FrigateCardCustomAction, + style: inFullscreenMode ? this._getEmphasizedStyle() : {}, + } + : null; + } + + protected _getCastButton( + hass: HomeAssistant, + config: FrigateCardConfig, + cameraManager: CameraManager, + view: View, + mediaPlayerController?: MediaPlayerManager | null, + ): MenuItem | null { + const selectedCameraConfig = cameraManager.getStore().getCameraConfig(view.camera); if ( - options?.mediaPlayerController?.hasMediaPlayers() && - (view?.isViewerView() || (view.is('live') && selectedCameraConfig?.camera_entity)) + mediaPlayerController?.hasMediaPlayers() && + (view.isViewerView() || (view.is('live') && selectedCameraConfig?.camera_entity)) ) { - const mediaPlayerItems = options.mediaPlayerController + const mediaPlayerItems = mediaPlayerController .getMediaPlayers() .map((playerEntityID) => { const title = getEntityTitle(hass, playerEntityID) || playerEntityID; @@ -371,45 +484,69 @@ export class MenuButtonController { }; }); - buttons.push({ + return { icon: 'mdi:cast', ...config.menu.buttons.media_player, type: 'custom:frigate-card-menu-submenu', title: localize('config.menu.buttons.media_player'), items: mediaPlayerItems, - }); + }; } + return null; + } - if (options?.currentMediaLoadedInfo && options.currentMediaLoadedInfo.player) { - if (options.currentMediaLoadedInfo.capabilities?.supportsPause) { - const paused = options.currentMediaLoadedInfo.player.isPaused(); - buttons.push({ - icon: paused ? 'mdi:play' : 'mdi:pause', - ...config.menu.buttons.play, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.play'), - tap_action: createFrigateCardSimpleAction( - paused ? 'play' : 'pause', - ) as FrigateCardCustomAction, - }); - } - - if (options.currentMediaLoadedInfo.capabilities?.hasAudio) { - const muted = options.currentMediaLoadedInfo.player.isMuted(); - buttons.push({ - icon: muted ? 'mdi:volume-off' : 'mdi:volume-high', - ...config.menu.buttons.mute, - type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.mute'), - tap_action: createFrigateCardSimpleAction( - muted ? 'unmute' : 'mute', - ) as FrigateCardCustomAction, - }); - } + protected _getPlayPauseButton( + config: FrigateCardConfig, + currentMediaLoadedInfo?: MediaLoadedInfo | null, + ): MenuItem | null { + if ( + currentMediaLoadedInfo && + currentMediaLoadedInfo.player && + currentMediaLoadedInfo.capabilities?.supportsPause + ) { + const paused = currentMediaLoadedInfo.player.isPaused(); + return { + icon: paused ? 'mdi:play' : 'mdi:pause', + ...config.menu.buttons.play, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.play'), + tap_action: createFrigateCardSimpleAction( + paused ? 'play' : 'pause', + ) as FrigateCardCustomAction, + }; } + return null; + } - if (options?.currentMediaLoadedInfo && options.currentMediaLoadedInfo.player) { - buttons.push({ + protected _getMuteUnmuteButton( + config: FrigateCardConfig, + currentMediaLoadedInfo?: MediaLoadedInfo | null, + ): MenuItem | null { + if ( + currentMediaLoadedInfo && + currentMediaLoadedInfo.player && + currentMediaLoadedInfo?.capabilities?.hasAudio + ) { + const muted = currentMediaLoadedInfo.player.isMuted(); + return { + icon: muted ? 'mdi:volume-off' : 'mdi:volume-high', + ...config.menu.buttons.mute, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.mute'), + tap_action: createFrigateCardSimpleAction( + muted ? 'unmute' : 'mute', + ) as FrigateCardCustomAction, + }; + } + return null; + } + + protected _getScreenshotButton( + config: FrigateCardConfig, + currentMediaLoadedInfo?: MediaLoadedInfo | null, + ): MenuItem | null { + if (currentMediaLoadedInfo && currentMediaLoadedInfo.player) { + return { icon: 'mdi:monitor-screenshot', ...config.menu.buttons.screenshot, type: 'custom:frigate-card-menu-icon', @@ -417,13 +554,20 @@ export class MenuButtonController { tap_action: createFrigateCardSimpleAction( 'screenshot', ) as FrigateCardCustomAction, - }); + }; } + return null; + } + protected _getDisplayModeButton( + config: FrigateCardConfig, + cameraManager: CameraManager, + view: View, + ): MenuItem | null { const viewCameraIDs = getCameraIDsForViewName(cameraManager, view.view); if (view.supportsMultipleDisplayModes() && viewCameraIDs.size > 1) { const isGrid = view.isGrid(); - buttons.push({ + return { icon: isGrid ? 'mdi:grid-off' : 'mdi:grid', ...config.menu.buttons.display_mode, style: isGrid ? this._getEmphasizedStyle() : {}, @@ -432,30 +576,42 @@ export class MenuButtonController { ? localize('display_modes.single') : localize('display_modes.grid'), tap_action: createFrigateCardDisplayModeAction(isGrid ? 'single' : 'grid'), - }); + }; } + return null; + } - if (hasUsablePTZ(substreamAwareCameraCapabilities, config.live.controls.ptz)) { + protected _getSubstreamAwareCameraID(view: View): string { + return view.context?.live?.overrides?.get(view.camera) ?? view.camera; + } + + protected _getPTZButton( + config: FrigateCardConfig, + cameraManager: CameraManager, + view: View, + ): MenuItem | null { + const substreamAwareCameraCapabilities = cameraManager.getCameraCapabilities( + this._getSubstreamAwareCameraID(view), + ); + + if ( + view.is('live') && + hasUsablePTZ(substreamAwareCameraCapabilities, config.live.controls.ptz) + ) { const isOn = view.context?.live?.ptzVisible === false ? false : config.live.controls.ptz.mode === 'on'; - buttons.push({ + return { icon: 'mdi:pan', ...config.menu.buttons.ptz, style: isOn ? this._getEmphasizedStyle() : {}, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.ptz'), tap_action: createFrigateCardShowPTZAction(!isOn), - }); + }; } - - const styledDynamicButtons = this._dynamicMenuButtons.map((button) => ({ - style: this._getStyleFromActions(config, view, button, options), - ...button, - })); - - return buttons.concat(styledDynamicButtons); + return null; } /** diff --git a/tests/components-lib/menu-button-controller.test.ts b/tests/components-lib/menu-button-controller.test.ts index c6887c37..daba7957 100644 --- a/tests/components-lib/menu-button-controller.test.ts +++ b/tests/components-lib/menu-button-controller.test.ts @@ -177,6 +177,25 @@ describe('MenuButtonController', () => { }); describe('should have substream button', () => { + it('with no dependency', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera-1', + capabilities: createCapabilities({ substream: true }), + }, + ]), + ); + const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + + expect(buttons).not.toContainEqual( + expect.objectContaining({ + title: 'Substream(s)', + }), + ); + }); + it('with single dependency', () => { const cameraManager = createCameraManager(); vi.mocked(cameraManager.getStore).mockReturnValue( @@ -248,7 +267,7 @@ describe('MenuButtonController', () => { }); }); - it('with substream selected and multiple dependencies', () => { + it('with substream unselected and multiple dependencies', () => { const cameraManager = createCameraManager(); vi.mocked(cameraManager.getStore).mockReturnValue( createStore([ @@ -440,7 +459,12 @@ describe('MenuButtonController', () => { describe('should have live menu button', () => { it('when in live view', () => { - const buttons = calculateButtons(controller); + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(true); + const buttons = calculateButtons(controller, { + view: createView({ view: 'live' }), + viewManager: viewManager, + }); expect(buttons).toContainEqual({ icon: 'mdi:cctv', @@ -454,8 +478,12 @@ describe('MenuButtonController', () => { }); it('when not in live view', () => { - const view = createView({ view: 'clips' }); - const buttons = calculateButtons(controller, { view: view }); + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(true); + const buttons = calculateButtons(controller, { + view: createView({ view: 'clips' }), + viewManager: viewManager, + }); expect(buttons).toContainEqual({ icon: 'mdi:cctv', @@ -467,6 +495,20 @@ describe('MenuButtonController', () => { tap_action: { action: 'fire-dom-event', frigate_card_action: 'live' }, }); }); + + it('when not supported', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(false); + const buttons = calculateButtons(controller, { + viewManager: viewManager, + }); + + expect(buttons).not.toContainEqual( + expect.objectContaining({ + title: 'Live view', + }), + ); + }); }); describe('should have clips menu button', () => { @@ -634,8 +676,12 @@ describe('MenuButtonController', () => { describe('should have image menu button', () => { it('when in image view', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(true); + const buttons = calculateButtons(controller, { view: createView({ view: 'image' }), + viewManager: viewManager, }); expect(buttons).toContainEqual({ @@ -650,7 +696,13 @@ describe('MenuButtonController', () => { }); it('when not in image view', () => { - const buttons = calculateButtons(controller); + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(true); + + const buttons = calculateButtons(controller, { + view: createView({ view: 'live' }), + viewManager: viewManager, + }); expect(buttons).toContainEqual({ icon: 'mdi:image', @@ -662,6 +714,20 @@ describe('MenuButtonController', () => { tap_action: { action: 'fire-dom-event', frigate_card_action: 'image' }, }); }); + + it('when not supported', () => { + const viewManager = mock(); + vi.mocked(viewManager.isViewSupportedByCamera).mockReturnValue(false); + const buttons = calculateButtons(controller, { + viewManager: viewManager, + }); + + expect(buttons).not.toContainEqual( + expect.objectContaining({ + title: 'Static image', + }), + ); + }); }); describe('should have timeline button', () => { @@ -1288,23 +1354,34 @@ describe('MenuButtonController', () => { createCapabilities(), ); - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); - - expect(buttons).not.toContainEqual({ - enabled: false, - icon: 'mdi:pan', - priority: 50, - style: { - color: 'var(--primary-color, white)', - }, - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'show_ptz', - show_ptz: false, - }, - title: 'Show PTZ controls', - type: 'custom:frigate-card-menu-icon', + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: createView({ view: 'live' }), }); + + expect(buttons).not.toContainEqual( + expect.objectContaining({ + title: 'Show PTZ controls', + }), + ); + }); + + it('when not in live view', () => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( + createCapabilities({ ptz: { panTilt: ['relative'] } }), + ); + + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: createView({ view: 'clips' }), + }); + + expect(buttons).not.toContainEqual( + expect.objectContaining({ + title: 'Show PTZ controls', + }), + ); }); it('when the selected camera is PTZ enabled', () => { From f67620397f163f3e3caa9d203be557e9e186e81c Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 7 Apr 2024 20:21:09 -0700 Subject: [PATCH 115/189] Set timeline to now not to most recent event. --- src/components-lib/live/live-controller.ts | 224 +++++++++++ src/components-lib/media-grid-controller.ts | 4 +- src/components/live/live.ts | 151 ++----- src/components/message.ts | 30 ++ src/components/surround.ts | 90 +---- src/components/timeline-core.ts | 9 +- src/components/views.ts | 10 +- src/types.ts | 1 - .../auto-media-loaded-info.ts | 6 +- src/utils/media-info.ts | 12 +- src/utils/media-to-view.ts | 10 +- src/view/view.ts | 30 ++ .../card-element-manager.test.ts | 29 +- tests/card-controller/view-manager.test.ts | 2 +- .../live/live-controller.test.ts | 377 ++++++++++++++++++ .../media-filter-controller.test.ts | 66 ++- tests/components-lib/menu-controller.test.ts | 52 +-- tests/test-utils.ts | 42 +- .../auto-media-actions.test.ts | 2 +- .../embla/plugins/auto-size/auto-size.test.ts | 2 +- tests/utils/embla/test-utils.ts | 14 - vite.config.ts | 1 + 22 files changed, 828 insertions(+), 336 deletions(-) create mode 100644 src/components-lib/live/live-controller.ts create mode 100644 tests/components-lib/live/live-controller.test.ts diff --git a/src/components-lib/live/live-controller.ts b/src/components-lib/live/live-controller.ts new file mode 100644 index 00000000..3080ea78 --- /dev/null +++ b/src/components-lib/live/live-controller.ts @@ -0,0 +1,224 @@ +import sub from 'date-fns/sub'; +import { LitElement, ReactiveController } from 'lit'; +import { ViewContext } from 'view'; +import { CameraManager } from '../../camera-manager/manager.js'; +import { FrigateCardMessageEventTarget } from '../../components/message.js'; +import { CardWideConfig, LiveConfig } from '../../config/types.js'; +import { MediaLoadedInfo, Message } from '../../types.js'; +import { + FrigateCardMediaLoadedEventTarget, + dispatchExistingMediaLoadedInfoAsEvent, +} from '../../utils/media-info.js'; +import { + changeViewToRecentEventsForCameraAndDependents, + changeViewToRecentRecordingForCameraAndDependents, +} from '../../utils/media-to-view.js'; +import { FrigateCardViewChangeEventTarget, View } from '../../view/view.js'; + +interface LiveViewContext { + // A cameraID override (used for dependencies/substreams to force a different + // camera to be live rather than the camera selected in the view). + overrides?: Map; + + ptzVisible?: boolean; + fetchThumbnails?: boolean; +} + +declare module 'view' { + interface ViewContext { + live?: LiveViewContext; + } +} + +interface LastMediaLoadedInfo { + mediaLoadedInfo: MediaLoadedInfo; + source: EventTarget; +} + +type LiveControllerHost = LitElement & + FrigateCardMediaLoadedEventTarget & + FrigateCardMessageEventTarget & + FrigateCardViewChangeEventTarget; + +export class LiveController implements ReactiveController { + protected _host: LiveControllerHost; + + // Whether or not the live view is currently in the background (i.e. preloaded + // but not visible). + protected _inBackground = false; + + // Intersection handler is used to detect when the live view flips between + // foreground and background (in preload mode). + protected _intersectionObserver: IntersectionObserver; + + // Whether or not to allow updates. + protected _messageReceived = false; + + // MediaLoadedInfo object and target from the underlying live media. In the + // case of pre-loading these may be propagated later (from the original + // source). + protected _lastMediaLoadedInfo: LastMediaLoadedInfo | null = null; + + protected _renderEpoch = 0; + + constructor(host: LiveControllerHost) { + this._host = host; + this._intersectionObserver = new IntersectionObserver( + this._intersectionHandler.bind(this), + ); + } + + public shouldUpdate(): boolean { + // Don't process updates if it's in the background and a message was + // received (otherwise an error message thrown by the background live + // component may continually be re-spammed hitting performance). + return !this._inBackground || !this._messageReceived; + } + + public hostConnected(): void { + this._intersectionObserver.observe(this._host); + + this._host.addEventListener('frigate-card:media:loaded', this._handleMediaLoaded); + this._host.addEventListener('frigate-card:message', this._handleMessage); + this._host.addEventListener('frigate-card:view:change', this._handleViewChange); + } + + public hostDisconnected(): void { + this._intersectionObserver.disconnect(); + + this._host.removeEventListener('frigate-card:media:loaded', this._handleMediaLoaded); + this._host.removeEventListener('frigate-card:message', this._handleMessage); + this._host.removeEventListener('frigate-card:view:change', this._handleViewChange); + } + + public clearMessageReceived(): void { + this._messageReceived = false; + } + + public isInBackground(): boolean { + return this._inBackground; + } + + public getRenderEpoch(): number { + return this._renderEpoch; + } + + protected _handleMessage = (ev: CustomEvent): void => { + this._messageReceived = true; + + if (this._inBackground) { + ev.stopPropagation(); + + // Force the whole DOM to re-render next time. + this._renderEpoch++; + } + }; + + protected _handleMediaLoaded = (ev: CustomEvent): void => { + this._lastMediaLoadedInfo = { + source: ev.composedPath()[0], + mediaLoadedInfo: ev.detail, + }; + + if (this._inBackground) { + ev.stopPropagation(); + } + }; + + protected _handleViewChange = (ev: CustomEvent): void => { + if (this._inBackground) { + ev.stopPropagation(); + } + }; + + protected _intersectionHandler(entries: IntersectionObserverEntry[]): void { + const wasInBackground = this._inBackground; + this._inBackground = !entries.some((entry) => entry.isIntersecting); + + if (!this._inBackground && !this._messageReceived && this._lastMediaLoadedInfo) { + // If this isn't being rendered in the background, the last render did not + // generate a message and there's a saved MediaInfo, dispatch it upwards. + dispatchExistingMediaLoadedInfoAsEvent( + // Specifically dispatch the event "where it came from", as otherwise + // the intermediate layers (e.g. media-carousel which controls the title + // popups) will not re-receive the events. + this._lastMediaLoadedInfo.source, + this._lastMediaLoadedInfo.mediaLoadedInfo, + ); + } + + if (wasInBackground !== this._inBackground) { + this._host.requestUpdate(); + } + } + + /** + * Fetch thumbnail media when a target is not already specified in the view + * (e.g. first time live is visited). + */ + public async fetchMediaInBackgroundIfNecessary( + view: View, + cameraManager: CameraManager, + cardWideConfig: CardWideConfig, + overriddenLiveConfig: LiveConfig, + ): Promise { + if ( + this._inBackground || + // Only fetch media if there isn't any already. + view.query || + overriddenLiveConfig.controls.thumbnails.mode === 'none' || + view.context?.live?.fetchThumbnails === false + ) { + return; + } + + const mediaType = overriddenLiveConfig.controls.thumbnails.media_type; + const now = new Date(); + const viewContext: ViewContext = { + // Force the window to start at the most recent time, not + // necessarily when the most recent event/recording was: + // https://github.com/dermotduffy/frigate-hass-card/issues/1301 + timeline: { + window: { + start: sub(now, { + seconds: overriddenLiveConfig.controls.timeline.window_seconds, + }), + end: now, + }, + }, + }; + + /* istanbul ignore else: the else path cannot be reached -- @preserve */ + if (mediaType === 'events') { + await changeViewToRecentEventsForCameraAndDependents( + this._host, + cameraManager, + cardWideConfig, + view, + { + allCameras: view.isGrid(), + targetView: view.view, + eventsMediaType: overriddenLiveConfig.controls.thumbnails.events_media_type, + select: 'latest', + // Force the window to start at the most recent time, not + // necessarily when the most recent event was: + // https://github.com/dermotduffy/frigate-hass-card/issues/1301 + viewContext: viewContext, + }, + ); + } else if (mediaType === 'recordings') { + await changeViewToRecentRecordingForCameraAndDependents( + this._host, + cameraManager, + cardWideConfig, + view, + { + allCameras: view.isGrid(), + targetView: view.view, + select: 'latest', + viewContext: viewContext, + }, + ); + } + } +} diff --git a/src/components-lib/media-grid-controller.ts b/src/components-lib/media-grid-controller.ts index 89a02b61..353ef331 100644 --- a/src/components-lib/media-grid-controller.ts +++ b/src/components-lib/media-grid-controller.ts @@ -9,7 +9,7 @@ import { setOrRemoveAttribute, } from '../utils/basic'; import { - FrigateMediaLoadedEventTarget, + FrigateCardMediaLoadedEventTarget, dispatchExistingMediaLoadedInfoAsEvent, dispatchMediaUnloadedEvent, } from '../utils/media-info'; @@ -23,7 +23,7 @@ const MEDIA_GRID_DEFAULT_IDEAL_CELL_WIDTH = 600; const MEDIA_GRID_DEFAULT_SELECTED_WIDTH_FACTOR = 2.0; type GridID = string; -type MediaGridChild = HTMLElement & FrigateMediaLoadedEventTarget; +type MediaGridChild = HTMLElement & FrigateCardMediaLoadedEventTarget; type MediaGridContents = Map; export interface MediaGridSelected { diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 4eacabfc..fd478d29 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -19,6 +19,7 @@ import { getOverriddenConfig, } from '../../card-controller/conditions-manager.js'; import { ReadonlyMicrophoneManager } from '../../card-controller/microphone-manager.js'; +import { LiveController } from '../../components-lib/live/live-controller.js'; import { MediaGridSelected } from '../../components-lib/media-grid-controller.js'; import { CameraConfig, @@ -34,12 +35,7 @@ import basicBlockStyle from '../../scss/basic-block.scss'; import liveCarouselStyle from '../../scss/live-carousel.scss'; import liveGridStyle from '../../scss/live-grid.scss'; import liveProviderStyle from '../../scss/live-provider.scss'; -import { - ExtendedHomeAssistant, - FrigateCardMediaPlayer, - MediaLoadedInfo, - Message, -} from '../../types.js'; +import { ExtendedHomeAssistant, FrigateCardMediaPlayer } from '../../types.js'; import { stopEventFromActivatingCardWideActions } from '../../utils/action.js'; import { aspectRatioToString, contentsChanged } from '../../utils/basic.js'; import { CarouselSelected } from '../../utils/embla/carousel-controller.js'; @@ -48,10 +44,7 @@ import { AutoMediaActions } from '../../utils/embla/plugins/auto-media-actions/a import AutoMediaLoadedInfo from '../../utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.js'; import AutoSize from '../../utils/embla/plugins/auto-size/auto-size.js'; import { getStateObjOrDispatchError } from '../../utils/get-state-obj.js'; -import { - dispatchExistingMediaLoadedInfoAsEvent, - dispatchMediaUnloadedEvent, -} from '../../utils/media-info.js'; +import { dispatchMediaUnloadedEvent } from '../../utils/media-info.js'; import { updateElementStyleFromMediaLayoutConfig } from '../../utils/media-layout.js'; import { playMediaMutingIfNecessary } from '../../utils/media.js'; import { dispatchViewContextChangeEvent, View } from '../../view/view.js'; @@ -67,24 +60,6 @@ import { getDefaultTitleConfigForView, } from '../title-control.js'; -interface LiveViewContext { - // A cameraID override (used for dependencies/substreams to force a different - // camera to be live rather than the camera selected in the view). - overrides?: Map; - ptzVisible?: boolean; -} - -declare module 'view' { - interface ViewContext { - live?: LiveViewContext; - } -} - -interface LastMediaLoadedInfo { - mediaLoadedInfo: MediaLoadedInfo; - source: EventTarget; -} - const FRIGATE_CARD_LIVE_PROVIDER = 'frigate-card-live-provider'; @customElement('frigate-card-live') @@ -101,7 +76,7 @@ export class FrigateCardLive extends LitElement { @property({ attribute: false }) public nonOverriddenLiveConfig?: LiveConfig; - @property({ attribute: false }) + @property({ attribute: false }>) public overriddenLiveConfig?: LiveConfig; @property({ attribute: false, hasChanged: contentsChanged }) @@ -119,76 +94,32 @@ export class FrigateCardLive extends LitElement { @property({ attribute: false }) public triggeredCameraIDs?: Set; - // Whether or not the live view is currently in the background (i.e. preloaded - // but not visible) - @state() - protected _inBackground?: boolean = false; - - // Intersection handler is used to detect when the live view flips between - // foreground and background (in preload mode). - protected _intersectionObserver: IntersectionObserver; - - // MediaLoadedInfo object and target from the underlying live object. In the - // case of pre-loading these may be propagated later (from the original - // source). - protected _lastMediaLoadedInfo: LastMediaLoadedInfo | null = null; - - protected _messageReceivedPostRender = false; - protected _renderKey = 0; - - constructor() { - super(); - this._intersectionObserver = new IntersectionObserver( - this._intersectionHandler.bind(this), - ); - } - - /** - * Called when the live view intersects with the viewport. - * @param entries The IntersectionObserverEntry entries (should be only 1). - */ - protected _intersectionHandler(entries: IntersectionObserverEntry[]): void { - this._inBackground = !entries.some((entry) => entry.isIntersecting); - - if ( - !this._inBackground && - !this._messageReceivedPostRender && - this._lastMediaLoadedInfo - ) { - // If this isn't being rendered in the background, the last render did not - // generate a message and there's a saved MediaInfo, dispatch it upwards. - dispatchExistingMediaLoadedInfoAsEvent( - // Specifically dispatch the event "where it came from", as otherwise - // the intermediate layers (e.g. media-carousel which controls the title - // popups) will not re-receive the events. - this._lastMediaLoadedInfo.source, - this._lastMediaLoadedInfo.mediaLoadedInfo, - ); - } - - // Trigger a re-render which may be necessary if the prior render resulted - // in a message. - if (this._messageReceivedPostRender && !this._inBackground) { - this.requestUpdate(); - } - } + protected _controller = new LiveController(this); // eslint-disable-next-line @typescript-eslint/no-unused-vars protected shouldUpdate(_changedProps: PropertyValues): boolean { - // Don't process updates if it's in the background and a message was - // received (otherwise an error message thrown by the background live - // component may continually be re-spammed hitting performance). - return !this._inBackground || !this._messageReceivedPostRender; + return this._controller.shouldUpdate(); } - connectedCallback(): void { - this._intersectionObserver.observe(this); - super.connectedCallback(); - } + protected willUpdate(changedProperties: PropertyValues): void { + if ( + ['view', 'cameraManager', 'cardWideConfig', 'overriddenLiveConfig'].some((prop) => + changedProperties.has(prop), + ) && + this.view && + this.cameraManager && + this.cardWideConfig && + this.overriddenLiveConfig + ) { + this._controller.fetchMediaInBackgroundIfNecessary( + this.view, + this.cameraManager, + this.cardWideConfig, + this.overriddenLiveConfig, + ); + } - disconnectedCallback(): void { - super.disconnectedCallback(); - this._intersectionObserver.disconnect(); + this._controller.clearMessageReceived(); } protected render(): TemplateResult | void { @@ -210,49 +141,25 @@ export class FrigateCardLive extends LitElement { // - The entire returned template is keyed to allow for the whole template // to be re-rendered in certain circumstances (specifically: if a message // is received when the card is in the background). - const result = html`${keyed( - this._renderKey, + return html`${keyed( + this._controller.getRenderEpoch(), html` ) => { - this._renderKey++; - this._messageReceivedPostRender = true; - if (this._inBackground) { - ev.stopPropagation(); - } - }} - @frigate-card:media:loaded=${(ev: CustomEvent) => { - this._lastMediaLoadedInfo = { - source: ev.composedPath()[0], - mediaLoadedInfo: ev.detail, - }; - if (this._inBackground) { - ev.stopPropagation(); - } - }} - @frigate-card:view:change=${(ev: CustomEvent) => { - if (this._inBackground) { - ev.stopPropagation(); - } - }} > `, )}`; - - this._messageReceivedPostRender = false; - return result; } static get styles(): CSSResultGroup { @@ -525,7 +432,7 @@ export class FrigateCardLiveCarousel extends LitElement { }) // Don't yet fetch thumbnails (they will be fetched when the carousel // settles). - .mergeInContext({ thumbnails: { fetch: false } }) + .mergeInContext({ live: { fetchThumbnails: false } }) .dispatchChangeEvent(this); } } @@ -673,7 +580,7 @@ export class FrigateCardLiveCarousel extends LitElement { @frigate-card:carousel:select=${this._setViewHandler.bind(this)} @frigate-card:carousel:settle=${() => { // Fetch the thumbnails after the carousel has settled. - dispatchViewContextChangeEvent(this, { thumbnails: { fetch: true } }); + dispatchViewContextChangeEvent(this, { live: { fetchThumbnails: true } }); }} @frigate-card:media:loaded=${() => { if (this._refTitleControl.value) { diff --git a/src/components/message.ts b/src/components/message.ts index fd0106b8..0f704279 100644 --- a/src/components/message.ts +++ b/src/components/message.ts @@ -200,6 +200,36 @@ export function dispatchFrigateCardErrorEvent( } } +// Facilitates correct typing of event handlers. +export interface FrigateCardMessageEventTarget extends EventTarget { + addEventListener( + event: 'frigate-card:message', + listener: ( + this: FrigateCardMessageEventTarget, + ev: CustomEvent, + ) => void, + options?: AddEventListenerOptions | boolean, + ): void; + addEventListener( + type: string, + callback: EventListenerOrEventListenerObject, + options?: AddEventListenerOptions | boolean, + ): void; + removeEventListener( + event: 'frigate-card:message', + listener: ( + this: FrigateCardMessageEventTarget, + ev: CustomEvent, + ) => void, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + callback: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + declare global { interface HTMLElementTagNameMap { 'frigate-card-progress-indicator': FrigateCardProgressIndicator; diff --git a/src/components/surround.ts b/src/components/surround.ts index cab592b3..4ff26aa8 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -14,31 +14,12 @@ import { ThumbnailsControlConfig, } from '../config/types.js'; import basicBlockStyle from '../scss/basic-block.scss'; -import { - ClipsOrSnapshotsOrAll, - EventsOrRecordings, - ExtendedHomeAssistant, -} from '../types.js'; +import { ExtendedHomeAssistant } from '../types.js'; import { contentsChanged, dispatchFrigateCardEvent } from '../utils/basic.js'; -import { - changeViewToRecentEventsForCameraAndDependents, - changeViewToRecentRecordingForCameraAndDependents, -} from '../utils/media-to-view'; import { View } from '../view/view.js'; import './surround-basic.js'; import { ThumbnailCarouselTap } from './thumbnail-carousel.js'; -interface ThumbnailViewContext { - // Whether or not to fetch thumbnails. - fetch?: boolean; -} - -declare module 'view' { - interface ViewContext { - thumbnails?: ThumbnailViewContext; - } -} - @customElement('frigate-card-surround') export class FrigateCardSurround extends LitElement { @property({ attribute: false }) @@ -53,13 +34,6 @@ export class FrigateCardSurround extends LitElement { @property({ attribute: false, hasChanged: contentsChanged }) public timelineConfig?: MiniTimelineControlConfig; - // If fetchMedia is not specified, no fetching is done. - @property({ attribute: false, hasChanged: contentsChanged }) - public fetchMediaType?: EventsOrRecordings; - - @property({ attribute: false, hasChanged: contentsChanged }) - public fetchEventsMediaType?: ClipsOrSnapshotsOrAll; - @property({ attribute: false }) public cameraManager?: CameraManager; @@ -68,56 +42,6 @@ export class FrigateCardSurround extends LitElement { protected _cameraIDsForTimeline?: Set; - /** - * Fetch thumbnail media when a target is not specified in the view (e.g. for - * the live view). - * @param param Task parameters. - * @returns - */ - protected async _fetchMedia(): Promise { - if ( - !this.cameraManager || - !this.cardWideConfig || - !this.fetchMediaType || - !this.fetchEventsMediaType || - !this.hass || - !this.view || - this.view.query || - !this.thumbnailConfig || - this.thumbnailConfig.mode === 'none' || - !(this.view.context?.thumbnails?.fetch ?? true) - ) { - return; - } - - if (this.fetchMediaType === 'events') { - await changeViewToRecentEventsForCameraAndDependents( - this, - this.cameraManager, - this.cardWideConfig, - this.view, - { - allCameras: this.view.isGrid(), - targetView: this.view.view, - eventsMediaType: this.fetchEventsMediaType, - select: 'latest', - }, - ); - } else if (this.fetchMediaType === 'recordings') { - await changeViewToRecentRecordingForCameraAndDependents( - this, - this.cameraManager, - this.cardWideConfig, - this.view, - { - allCameras: this.view.isGrid(), - targetView: this.view.view, - select: 'latest', - }, - ); - } - } - /** * Determine if a drawer is being used. * @returns `true` if a drawer is used, `false` otherwise. @@ -128,9 +52,6 @@ export class FrigateCardSurround extends LitElement { ); } - /** - * Called before each update. - */ protected willUpdate(changedProperties: PropertyValues): void { if (this.timelineConfig?.mode && this.timelineConfig.mode !== 'none') { import('./timeline-core.js'); @@ -147,15 +68,6 @@ export class FrigateCardSurround extends LitElement { ) { this._cameraIDsForTimeline = this._getCameraIDsForTimeline() ?? undefined; } - - // Once the component will certainly update, dispatch a media request. Only - // do so if properties relevant to the request have changed (as per their - // hasChanged). - if ( - ['view', 'fetch', 'browseMediaParams'].some((prop) => changedProperties.has(prop)) - ) { - this._fetchMedia(); - } } protected _getCameraIDsForTimeline(): Set | null { diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index c46bc8f3..dbd3eca2 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -651,7 +651,14 @@ export class FrigateCardTimelineCore extends LitElement { }): Promise { this._removeTargetBar(); - if (!this._timeline || !this.view) { + if ( + !this._timeline || + !this.view || + // When in mini mode, something else is in charge of the primary media + // population (e.g. the live view), in this case only act when the user + // themselves are interacting with the timeline. + (this.mini && !properties.byUser) + ) { return; } diff --git a/src/components/views.ts b/src/components/views.ts index 352547b9..d1c3a2ef 100644 --- a/src/components/views.ts +++ b/src/components/views.ts @@ -163,12 +163,6 @@ export class FrigateCardViews extends LitElement { class="${classMap(overallClasses)}" .hass=${this.hass} .view=${this.view} - .fetchMediaType=${this.view?.is('live') - ? this.overriddenConfig.live.controls.thumbnails.media_type - : undefined} - .fetchEventsMediaType=${this.view?.is('live') - ? this.overriddenConfig.live.controls.thumbnails.events_media_type - : undefined} .thumbnailConfig=${!this.hide ? thumbnailConfig : undefined} .timelineConfig=${!this.hide ? miniTimelineConfig : undefined} .cameraManager=${this.cameraManager} @@ -254,6 +248,10 @@ export class FrigateCardViews extends LitElement { : `` } `; + + // .fetchMediaType=${this.view?.is('live') ? this.overriddenConfig.live.controls.thumbnails.media_type : undefined} + // .fetchEventsMediaType=${this.view?.is('live') ? this.overriddenConfig.live.controls.thumbnails.events_media_type : undefined} + } static get styles(): CSSResultGroup { diff --git a/src/types.ts b/src/types.ts index 40afdd63..06258cf6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -8,7 +8,6 @@ import { z } from 'zod'; export type ClipsOrSnapshots = 'clips' | 'snapshots'; export type ClipsOrSnapshotsOrAll = 'clips' | 'snapshots' | 'all'; -export type EventsOrRecordings = 'events' | 'recordings'; export class FrigateCardError extends Error { context?: unknown; diff --git a/src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.ts b/src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.ts index 402b9d9e..bc104ed7 100644 --- a/src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.ts +++ b/src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.ts @@ -1,11 +1,11 @@ import { EmblaCarouselType } from 'embla-carousel'; +import { LooseOptionsType } from 'embla-carousel/components/Options'; import { CreatePluginType, LoosePluginType } from 'embla-carousel/components/Plugins'; import { MediaLoadedInfo } from '../../../../types'; import { + FrigateCardMediaLoadedEventTarget, dispatchExistingMediaLoadedInfoAsEvent, - FrigateMediaLoadedEventTarget, } from '../../../media-info'; -import { LooseOptionsType } from 'embla-carousel/components/Options'; declare module 'embla-carousel/components/Plugins' { interface EmblaPluginsType { @@ -17,7 +17,7 @@ type AutoMediaLoadedInfoType = CreatePluginType, ) => void, options?: AddEventListenerOptions | boolean, ): void; addEventListener( event: 'frigate-card:media:unloaded', - listener: (this: FrigateMediaLoadedEventTarget, ev: CustomEvent) => void, + listener: (this: FrigateCardMediaLoadedEventTarget, ev: CustomEvent) => void, options?: AddEventListenerOptions | boolean, ): void; addEventListener( @@ -135,14 +135,14 @@ export interface FrigateMediaLoadedEventTarget extends EventTarget { removeEventListener( event: 'frigate-card:media:loaded', listener: ( - this: FrigateMediaLoadedEventTarget, + this: FrigateCardMediaLoadedEventTarget, ev: CustomEvent, ) => void, options?: boolean | EventListenerOptions, ): void; removeEventListener( event: 'frigate-card:media:unloaded', - listener: (this: FrigateMediaLoadedEventTarget, ev: CustomEvent) => void, + listener: (this: FrigateCardMediaLoadedEventTarget, ev: CustomEvent) => void, options?: boolean | EventListenerOptions, ): void; removeEventListener( diff --git a/src/utils/media-to-view.ts b/src/utils/media-to-view.ts index 4fbe8fc8..6ca25497 100644 --- a/src/utils/media-to-view.ts +++ b/src/utils/media-to-view.ts @@ -28,6 +28,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( targetView?: FrigateCardView; select?: ResultSelectType; useCache?: boolean; + viewContext?: ViewContext; }, ): Promise => { const capabilitySearch: CapabilitySearchOptions = @@ -61,6 +62,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( targetView: options?.targetView, select: options?.select, useCache: options?.useCache, + viewContext: options?.viewContext }, ) )?.dispatchChangeEvent(element); @@ -103,6 +105,7 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( targetView?: FrigateCardView; select?: ResultSelectType; useCache?: boolean; + viewContext?: ViewContext; }, ): Promise => { const cameraIDs = options?.allCameras @@ -131,6 +134,7 @@ export const changeViewToRecentRecordingForCameraAndDependents = async ( targetView: options?.targetView, select: options?.select, useCache: options?.useCache, + viewContext: options?.viewContext, }, ) )?.dispatchChangeEvent(element); @@ -159,6 +163,7 @@ export const executeMediaQueryForView = async ( targetTime?: Date; select?: ResultSelectType; useCache?: boolean; + viewContext?: ViewContext; }, ): Promise => { const queries = query.getQueries(); @@ -195,7 +200,8 @@ export const executeMediaQueryForView = async ( view: options?.targetView, camera: cameraID, }) - .mergeInContext(viewerContext); + .mergeInContext(options?.viewContext) + .mergeInContext(viewerContext) }; export const executeMediaQueryForViewWithErrorDispatching = async ( @@ -209,6 +215,7 @@ export const executeMediaQueryForViewWithErrorDispatching = async ( targetTime?: Date; select?: ResultSelectType; useCache?: boolean; + viewContext?: ViewContext; }, ): Promise => { try { @@ -218,6 +225,7 @@ export const executeMediaQueryForViewWithErrorDispatching = async ( targetTime: options?.targetTime, select: options?.select, useCache: options?.useCache, + viewContext: options?.viewContext, }); } catch (e: unknown) { errorToConsole(e as Error); diff --git a/src/view/view.ts b/src/view/view.ts index 6d395a9b..03dbfeec 100644 --- a/src/view/view.ts +++ b/src/view/view.ts @@ -269,6 +269,36 @@ export class View { } } +// Facilitates correct typing of event handlers. +export interface FrigateCardViewChangeEventTarget extends EventTarget { + addEventListener( + event: 'frigate-card:view:change', + listener: ( + this: FrigateCardViewChangeEventTarget, + ev: CustomEvent, + ) => void, + options?: AddEventListenerOptions | boolean, + ): void; + addEventListener( + type: string, + callback: EventListenerOrEventListenerObject, + options?: AddEventListenerOptions | boolean, + ): void; + removeEventListener( + event: 'frigate-card:view:change', + listener: ( + this: FrigateCardViewChangeEventTarget, + ev: CustomEvent, + ) => void, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + callback: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} + /** * Dispatch an event to change the view context. * @param target The EventTarget to send the event from. diff --git a/tests/card-controller/card-element-manager.test.ts b/tests/card-controller/card-element-manager.test.ts index a695b637..c378ab10 100644 --- a/tests/card-controller/card-element-manager.test.ts +++ b/tests/card-controller/card-element-manager.test.ts @@ -1,16 +1,7 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; -import { - CardElementManager, - CardHTMLElement, -} from '../../src/card-controller/card-element-manager'; -import { createCardAPI } from '../test-utils'; import { mock } from 'vitest-mock-extended'; - -const createElement = (): CardHTMLElement => { - const element = document.createElement('div') as unknown as CardHTMLElement; - element.requestUpdate = vi.fn(); - return element as CardHTMLElement; -}; +import { CardElementManager } from '../../src/card-controller/card-element-manager'; +import { createCardAPI, createLitElement } from '../test-utils'; // @vitest-environment jsdom describe('CardElementManager', () => { @@ -20,7 +11,7 @@ describe('CardElementManager', () => { }); it('should get element', () => { - const element = createElement(); + const element = createLitElement(); const manager = new CardElementManager( createCardAPI(), element, @@ -35,7 +26,7 @@ describe('CardElementManager', () => { const callback = vi.fn(); const manager = new CardElementManager( createCardAPI(), - createElement(), + createLitElement(), callback, () => undefined, ); @@ -49,7 +40,7 @@ describe('CardElementManager', () => { const callback = vi.fn(); const manager = new CardElementManager( createCardAPI(), - createElement(), + createLitElement(), () => undefined, callback, ); @@ -60,7 +51,7 @@ describe('CardElementManager', () => { }); it('should update', () => { - const element = createElement(); + const element = createLitElement(); const manager = new CardElementManager( createCardAPI(), element, @@ -73,7 +64,7 @@ describe('CardElementManager', () => { }); it('should get hasUpdated', () => { - const element = createElement(); + const element = createLitElement(); element.hasUpdated = true; const manager = new CardElementManager( createCardAPI(), @@ -86,7 +77,7 @@ describe('CardElementManager', () => { }); it('should get height', () => { - const element = createElement(); + const element = createLitElement(); element.getBoundingClientRect = vi.fn().mockReturnValue({ width: 200, height: 800, @@ -106,7 +97,7 @@ describe('CardElementManager', () => { const windowAddEventListener = vi.spyOn(global.window, 'addEventListener'); const addEventListener = vi.fn(); - const element = createElement(); + const element = createLitElement(); element.addEventListener = addEventListener; const api = createCardAPI(); @@ -147,7 +138,7 @@ describe('CardElementManager', () => { it('should disconnect', () => { const windowRemoveEventListener = vi.spyOn(global.window, 'removeEventListener'); - const element = createElement(); + const element = createLitElement(); element.setAttribute('panel', ''); const removeEventListener = vi.fn(); diff --git a/tests/card-controller/view-manager.test.ts b/tests/card-controller/view-manager.test.ts index 9fd7b5d4..f1395938 100644 --- a/tests/card-controller/view-manager.test.ts +++ b/tests/card-controller/view-manager.test.ts @@ -78,7 +78,7 @@ describe('ViewManager.setView', () => { it('should set view with new context', () => { const api = createCardAPI(); const manager = new ViewManager(api); - const context = { thumbnails: { fetch: false } }; + const context = { live: { fetchThumbnails: false } }; // Setting context with no existing view does nothing. manager.setViewWithNewContext(context); diff --git a/tests/components-lib/live/live-controller.test.ts b/tests/components-lib/live/live-controller.test.ts new file mode 100644 index 00000000..b3dea6c9 --- /dev/null +++ b/tests/components-lib/live/live-controller.test.ts @@ -0,0 +1,377 @@ +import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { LiveController } from '../../../src/components-lib/live/live-controller'; +import { dispatchMessageEvent } from '../../../src/components/message'; +import { + changeViewToRecentEventsForCameraAndDependents, + changeViewToRecentRecordingForCameraAndDependents, +} from '../../../src/utils/media-to-view'; +import { EventMediaQueries } from '../../../src/view/media-queries'; +import { + IntersectionObserverMock, + callIntersectionHandler, + createCameraManager, + createConfig, + createLitElement, + createMediaLoadedInfo, + createMediaLoadedInfoEvent, + createParent, + createView, + createViewChangeEvent, +} from '../../test-utils'; + +vi.mock('../../../src/utils/media-to-view'); + +// @vitest-environment jsdom +describe('LiveController', () => { + beforeEach(() => { + vi.clearAllMocks(); + vi.stubGlobal('IntersectionObserver', IntersectionObserverMock); + }); + + it('should be constructable', () => { + const controller = new LiveController(createLitElement()); + expect(controller).toBeTruthy(); + }); + + it('should connect and disconnect', () => { + const host = createLitElement(); + const parent = createParent({ children: [host] }); + const eventListener = vi.fn(); + parent.addEventListener('frigate-card:message', eventListener); + + const controller = new LiveController(host); + + controller.hostConnected(); + + callIntersectionHandler(false); + dispatchMessageEvent(host, 'message', 'info'); + + expect(eventListener).toBeCalledTimes(0); + + controller.hostDisconnected(); + dispatchMessageEvent(host, 'message', 'info'); + + expect(eventListener).toBeCalledTimes(1); + }); + + describe('should handle background / foreground', () => { + it('should start in the foreground', () => { + const controller = new LiveController(createLitElement()); + expect(controller.isInBackground()).toBeFalsy(); + }); + + it('should handle changing to background', () => { + const element = createLitElement(); + const controller = new LiveController(element); + expect(controller.isInBackground()).toBeFalsy(); + expect(element.requestUpdate).toBeCalledTimes(0); + + callIntersectionHandler(true); + expect(controller.isInBackground()).toBeFalsy(); + expect(element.requestUpdate).toBeCalledTimes(0); + + callIntersectionHandler(false); + expect(controller.isInBackground()).toBeTruthy(); + expect(element.requestUpdate).toBeCalledTimes(1); + }); + + it('should dispatch media loaded on background change', () => { + const host = createLitElement(); + const parent = createParent({ children: [host] }); + const eventListener = vi.fn(); + parent.addEventListener('frigate-card:media:loaded', eventListener); + + const controller = new LiveController(host); + const mediaLoadedInfo = createMediaLoadedInfo(); + + controller.hostConnected(); + + callIntersectionHandler(false); + expect(controller.isInBackground()).toBeTruthy(); + + host.dispatchEvent(createMediaLoadedInfoEvent(mediaLoadedInfo)); + expect(eventListener).toBeCalledTimes(0); + + callIntersectionHandler(true); + expect(eventListener).toBeCalledTimes(1); + expect(eventListener).toHaveBeenLastCalledWith( + expect.objectContaining({ + detail: mediaLoadedInfo, + }), + ); + + host.dispatchEvent(createMediaLoadedInfoEvent(mediaLoadedInfo)); + expect(eventListener).toBeCalledTimes(2); + + callIntersectionHandler(false); + dispatchMessageEvent(host, 'message', 'info'); + callIntersectionHandler(true); + expect(eventListener).toBeCalledTimes(2); + + controller.clearMessageReceived(); + callIntersectionHandler(true); + expect(eventListener).toBeCalledTimes(3); + }); + }); + + describe('should correctly allow updates', () => { + it('when not in background', () => { + const controller = new LiveController(createLitElement()); + expect(controller.shouldUpdate()).toBeTruthy(); + }); + + it('when in background without message', () => { + const host = createLitElement(); + const controller = new LiveController(host); + controller.hostConnected(); + + callIntersectionHandler(false); + + expect(controller.shouldUpdate()).toBeTruthy(); + }); + + it('when in background with message', () => { + const host = createLitElement(); + const controller = new LiveController(host); + controller.hostConnected(); + + callIntersectionHandler(false); + dispatchMessageEvent(host, 'message', 'info'); + + expect(controller.shouldUpdate()).toBeFalsy(); + }); + }); + + it('should handle message', () => { + const host = createLitElement(); + const parent = createParent({ children: [host] }); + const eventListener = vi.fn(); + parent.addEventListener('frigate-card:message', eventListener); + + const controller = new LiveController(host); + controller.hostConnected(); + + callIntersectionHandler(false); + expect(controller.isInBackground()).toBeTruthy(); + + const firstRenderEpoch = controller.getRenderEpoch(); + + dispatchMessageEvent(host, 'message', 'info'); + expect(eventListener).toBeCalledTimes(0); + + const secondRenderEpoch = controller.getRenderEpoch(); + expect(secondRenderEpoch).not.toBe(firstRenderEpoch); + + callIntersectionHandler(true); + + dispatchMessageEvent(host, 'message', 'info'); + expect(eventListener).toBeCalledTimes(1); + expect(controller.getRenderEpoch()).toBe(secondRenderEpoch); + }); + + it('should handle view change', () => { + const host = createLitElement(); + const parent = createParent({ children: [host] }); + const eventListener = vi.fn(); + parent.addEventListener('frigate-card:view:change', eventListener); + + const controller = new LiveController(host); + controller.hostConnected(); + const view = createView(); + + callIntersectionHandler(false); + expect(controller.isInBackground()).toBeTruthy(); + host.dispatchEvent(createViewChangeEvent(view)); + + expect(eventListener).toBeCalledTimes(0); + + callIntersectionHandler(true); + expect(controller.isInBackground()).toBeFalsy(); + + host.dispatchEvent(createViewChangeEvent(view)); + + expect(eventListener).toBeCalledTimes(1); + }); + + describe('should fetch media', () => { + it('when in background', async () => { + const controller = new LiveController(createLitElement()); + + callIntersectionHandler(false); + + await controller.fetchMediaInBackgroundIfNecessary( + createView(), + createCameraManager(), + {}, + createConfig().live, + ); + + expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled(); + expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled(); + }); + + it('when has existing query', async () => { + const controller = new LiveController(createLitElement()); + + await controller.fetchMediaInBackgroundIfNecessary( + createView({ query: new EventMediaQueries() }), + createCameraManager(), + {}, + createConfig().live, + ); + + expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled(); + expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled(); + }); + + it('when has no thumbnails', async () => { + const controller = new LiveController(createLitElement()); + + await controller.fetchMediaInBackgroundIfNecessary( + createView(), + createCameraManager(), + {}, + createConfig({ + live: { + controls: { + thumbnails: { + mode: 'none', + }, + }, + }, + }).live, + ); + + expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled(); + expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled(); + }); + + it('when fetch disabled in context', async () => { + const controller = new LiveController(createLitElement()); + + await controller.fetchMediaInBackgroundIfNecessary( + createView({ + context: { + live: { + fetchThumbnails: false, + }, + }, + }), + createCameraManager(), + {}, + createConfig().live, + ); + + expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled(); + expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled(); + }); + + describe('with fetch', () => { + const now = new Date('2024-04-07T19:43'); + beforeAll(() => { + vi.useFakeTimers(); + vi.setSystemTime(now); + }); + + afterAll(() => { + vi.useRealTimers(); + }); + + it('events', async () => { + const host = createLitElement(); + const controller = new LiveController(host); + const view = createView(); + const cameraManager = createCameraManager(); + const cardWideConfig = {}; + + await controller.fetchMediaInBackgroundIfNecessary( + view, + cameraManager, + cardWideConfig, + createConfig({ + live: { + controls: { + thumbnails: { + media_type: 'events', + events_media_type: 'all', + }, + timeline: { + window_seconds: 3600, + }, + }, + }, + }).live, + ); + + expect(changeViewToRecentEventsForCameraAndDependents).toBeCalledWith( + host, + cameraManager, + cardWideConfig, + view, + expect.objectContaining({ + allCameras: false, + targetView: 'live', + eventsMediaType: 'all', + select: 'latest', + viewContext: expect.objectContaining({ + timeline: { + window: { + start: new Date('2024-04-07T18:43'), + end: now, + }, + }, + }), + }), + ); + expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled(); + }); + + it('recordings', async () => { + const host = createLitElement(); + const controller = new LiveController(host); + const view = createView(); + const cameraManager = createCameraManager(); + const cardWideConfig = {}; + + await controller.fetchMediaInBackgroundIfNecessary( + view, + cameraManager, + cardWideConfig, + createConfig({ + live: { + controls: { + thumbnails: { + media_type: 'recordings', + }, + timeline: { + window_seconds: 3600, + }, + }, + }, + }).live, + ); + + expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled(); + expect(changeViewToRecentRecordingForCameraAndDependents).toBeCalledWith( + host, + cameraManager, + cardWideConfig, + view, + expect.objectContaining({ + allCameras: false, + targetView: 'live', + select: 'latest', + viewContext: expect.objectContaining({ + timeline: { + window: { + start: new Date('2024-04-07T18:43'), + end: now, + }, + }, + }), + }), + ); + }); + }); + }); +}); diff --git a/tests/components-lib/media-filter-controller.test.ts b/tests/components-lib/media-filter-controller.test.ts index e88052e3..623b4fbc 100644 --- a/tests/components-lib/media-filter-controller.test.ts +++ b/tests/components-lib/media-filter-controller.test.ts @@ -1,7 +1,6 @@ import endOfDay from 'date-fns/endOfDay'; import startOfDay from 'date-fns/startOfDay'; import sub from 'date-fns/sub'; -import { LitElement } from 'lit'; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import { Capabilities } from '../../src/camera-manager/capabilities'; import { CameraManagerStore } from '../../src/camera-manager/store'; @@ -23,6 +22,7 @@ import { createCameraConfig, createCameraManager, createCapabilities, + createLitElement, createPerformanceConfig, createStore, createView, @@ -30,12 +30,6 @@ import { vi.mock('../../src/utils/media-to-view'); -const createHost = (): LitElement => { - const host = document.createElement('div') as unknown as LitElement; - host.requestUpdate = vi.fn(); - return host; -}; - const createCameraStore = (options?: { capabilities: Capabilities; }): CameraManagerStore => { @@ -64,7 +58,7 @@ describe('MediaFilterController', () => { describe('should have correct default options', () => { it('media type', () => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); expect(controller.getMediaTypeOptions()).toEqual([ { value: MediaFilterMediaType.Clips, @@ -82,7 +76,7 @@ describe('MediaFilterController', () => { }); it('favorite', () => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); expect(controller.getFavoriteOptions()).toEqual([ { value: MediaFilterCoreFavoriteSelection.Favorite, @@ -96,7 +90,7 @@ describe('MediaFilterController', () => { }); it('when', () => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); expect(controller.getWhenOptions()).toEqual([ { value: MediaFilterCoreWhen.Today, @@ -122,22 +116,22 @@ describe('MediaFilterController', () => { }); it('cameras', () => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); expect(controller.getCameraOptions()).toEqual([]); }); it('what', () => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); expect(controller.getWhatOptions()).toEqual([]); }); it('where', () => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); expect(controller.getWhereOptions()).toEqual([]); }); it('tags', () => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); expect(controller.getTagsOptions()).toEqual([]); }); }); @@ -152,7 +146,7 @@ describe('MediaFilterController', () => { }); vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); controller.computeCameraOptions(cameraManager); expect(controller.getCameraOptions()).toEqual([ { @@ -178,7 +172,7 @@ describe('MediaFilterController', () => { }), ); - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); controller.computeCameraOptions(cameraManager); expect(controller.getCameraOptions()).toEqual([]); }); @@ -188,7 +182,7 @@ describe('MediaFilterController', () => { vi.mocked(cameraManager.getCameraMetadata).mockReturnValue(null); vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); controller.computeCameraOptions(cameraManager); expect(controller.getCameraOptions()).toEqual([ { @@ -206,7 +200,7 @@ describe('MediaFilterController', () => { const cameraManager = createCameraManager(); vi.mocked(cameraManager.getMediaMetadata).mockRejectedValue(new Error('error')); - const host = createHost(); + const host = createLitElement(); const controller = new MediaFilterController(host); await controller.computeMetadataOptions(cameraManager); expect(host.requestUpdate).not.toBeCalled(); @@ -218,7 +212,7 @@ describe('MediaFilterController', () => { what: new Set(['person', 'car']), }); - const host = createHost(); + const host = createLitElement(); const controller = new MediaFilterController(host); await controller.computeMetadataOptions(cameraManager); expect(controller.getWhatOptions()).toEqual([ @@ -240,7 +234,7 @@ describe('MediaFilterController', () => { where: new Set(['front_door', 'back_yard']), }); - const host = createHost(); + const host = createLitElement(); const controller = new MediaFilterController(host); await controller.computeMetadataOptions(cameraManager); expect(controller.getWhereOptions()).toEqual([ @@ -262,7 +256,7 @@ describe('MediaFilterController', () => { tags: new Set(['tag-1', 'tag-2']), }); - const host = createHost(); + const host = createLitElement(); const controller = new MediaFilterController(host); await controller.computeMetadataOptions(cameraManager); expect(controller.getTagsOptions()).toEqual([ @@ -284,7 +278,7 @@ describe('MediaFilterController', () => { days: new Set(['2024-02-04', '2024-02-05']), }); - const host = createHost(); + const host = createLitElement(); const controller = new MediaFilterController(host); await controller.computeMetadataOptions(cameraManager); @@ -306,7 +300,7 @@ describe('MediaFilterController', () => { const view = createView({ query: new EventMediaQueries() }); const cameraManager = createCameraManager(); - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ events: true, recordings: false, @@ -317,7 +311,7 @@ describe('MediaFilterController', () => { const view = createView({ query: new RecordingMediaQueries() }); const cameraManager = createCameraManager(); - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ events: false, recordings: true, @@ -331,7 +325,7 @@ describe('MediaFilterController', () => { createCapabilities({ 'favorite-events': true }), ); - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ favorites: true, }); @@ -344,7 +338,7 @@ describe('MediaFilterController', () => { createCapabilities({ 'favorite-recordings': true }), ); - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ favorites: true, }); @@ -354,7 +348,7 @@ describe('MediaFilterController', () => { const view = createView(); const cameraManager = createCameraManager(); - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ favorites: false, }); @@ -363,7 +357,7 @@ describe('MediaFilterController', () => { describe('should handle value change', () => { it('must have visible cameras', async () => { - const host = createHost(); + const host = createLitElement(); const controller = new MediaFilterController(host); await controller.valueChangeHandler( createCameraManager(), @@ -380,7 +374,7 @@ describe('MediaFilterController', () => { '%s', async (viewName: 'clips' | 'snapshots') => { const eventListener = vi.fn(); - const host = createHost(); + const host = createLitElement(); host.addEventListener('frigate-card:view:change', eventListener); const controller = new MediaFilterController(host); @@ -458,7 +452,7 @@ describe('MediaFilterController', () => { it('with recordings media type', async () => { const eventListener = vi.fn(); - const host = createHost(); + const host = createLitElement(); host.addEventListener('frigate-card:view:change', eventListener); const controller = new MediaFilterController(host); @@ -522,7 +516,7 @@ describe('MediaFilterController', () => { }); it('without favorites', async () => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); const cameraManager = createCameraManager(); vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); @@ -583,7 +577,7 @@ describe('MediaFilterController', () => { new Date('2024-02-29T23:59:59.999'), ], ])('%s', async (value: MediaFilterCoreWhen | string, from: Date, to: Date) => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); const cameraManager = createCameraManager(); vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); @@ -614,7 +608,7 @@ describe('MediaFilterController', () => { }); it('custom without values', async () => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); const cameraManager = createCameraManager(); vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); @@ -646,7 +640,7 @@ describe('MediaFilterController', () => { describe('should calculate correct defaults', () => { it('with no queries', () => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); controller.computeInitialDefaultsFromView(createCameraManager(), createView()); @@ -654,7 +648,7 @@ describe('MediaFilterController', () => { }); it('with no cameras', () => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); controller.computeInitialDefaultsFromView( createCameraManager(), @@ -956,7 +950,7 @@ describe('MediaFilterController', () => { mediaQueries: MediaQueries, defaults: MediaFilterCoreDefaults | null, ) => { - const controller = new MediaFilterController(createHost()); + const controller = new MediaFilterController(createLitElement()); const cameraManager = createCameraManager(); vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); diff --git a/tests/components-lib/menu-controller.test.ts b/tests/components-lib/menu-controller.test.ts index 163e621b..596d9312 100644 --- a/tests/components-lib/menu-controller.test.ts +++ b/tests/components-lib/menu-controller.test.ts @@ -1,25 +1,15 @@ -import { - HASSDomEvent, - handleActionConfig, -} from '@dermotduffy/custom-card-helpers'; -import { LitElement } from 'lit'; +import { HASSDomEvent, handleActionConfig } from '@dermotduffy/custom-card-helpers'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { FRIGATE_ICON_SVG_PATH } from '../../src/camera-manager/frigate/icon'; import { MenuController } from '../../src/components-lib/menu-controller'; import { ActionsConfig, MenuConfig, menuConfigSchema } from '../../src/config/types'; import { StateParameters } from '../../src/types'; import { refreshDynamicStateParameters } from '../../src/utils/ha'; -import { createHASS } from '../test-utils'; +import { createHASS, createLitElement } from '../test-utils'; vi.mock('@dermotduffy/custom-card-helpers'); vi.mock('../../src/utils/ha'); -const createHost = (): LitElement => { - const host = document.createElement('div') as unknown as LitElement; - host.requestUpdate = vi.fn(); - return host; -}; - const createMenuConfig = (config: unknown): MenuConfig => { return menuConfigSchema.parse(config); }; @@ -59,7 +49,7 @@ describe('MenuController', () => { }); it('should set and get menu config', () => { - const host = createHost(); + const host = createLitElement(); const controller = new MenuController(host); const config = createMenuConfig({ @@ -79,7 +69,7 @@ describe('MenuController', () => { describe('should set and sort buttons', () => { it('by priority', () => { - const controller = new MenuController(createHost()); + const controller = new MenuController(createLitElement()); controller.setButtons([ { type: 'custom:frigate-card-menu-icon', @@ -146,7 +136,7 @@ describe('MenuController', () => { }); it('with frigate button first', () => { - const controller = new MenuController(createHost()); + const controller = new MenuController(createLitElement()); controller.setMenuConfig( createMenuConfig({ style: 'hidden', @@ -197,7 +187,7 @@ describe('MenuController', () => { describe('should get buttons', () => { it('with matching alignment', () => { - const controller = new MenuController(createHost()); + const controller = new MenuController(createLitElement()); controller.setButtons([ { type: 'custom:frigate-card-menu-icon', @@ -229,7 +219,7 @@ describe('MenuController', () => { }); it('with disabled buttons', () => { - const controller = new MenuController(createHost()); + const controller = new MenuController(createLitElement()); controller.setButtons([ { type: 'custom:frigate-card-menu-icon', @@ -261,7 +251,7 @@ describe('MenuController', () => { }); it('with hidden non-expanded menu', () => { - const controller = new MenuController(createHost()); + const controller = new MenuController(createLitElement()); controller.setMenuConfig( createMenuConfig({ style: 'hidden', @@ -303,7 +293,7 @@ describe('MenuController', () => { describe('should get fresh button state', () => { it('on state icon', () => { - const controller = new MenuController(createHost()); + const controller = new MenuController(createLitElement()); const stateButton = { type: 'custom:frigate-card-menu-state-icon' as const, icon: 'mdi:sheep', @@ -322,7 +312,7 @@ describe('MenuController', () => { }); it('on non state icon', () => { - const controller = new MenuController(createHost()); + const controller = new MenuController(createLitElement()); const button = { type: 'custom:frigate-card-menu-icon' as const, icon: 'mdi:sheep', @@ -335,7 +325,7 @@ describe('MenuController', () => { describe('should get svg path', () => { it('frigate icon', () => { - const controller = new MenuController(createHost()); + const controller = new MenuController(createLitElement()); const button = { type: 'custom:frigate-card-menu-icon' as const, icon: 'frigate', @@ -344,7 +334,7 @@ describe('MenuController', () => { }); it('non-frigate icon', () => { - const controller = new MenuController(createHost()); + const controller = new MenuController(createLitElement()); const button = { type: 'custom:frigate-card-menu-icon' as const, icon: 'mdi:cow', @@ -355,13 +345,13 @@ describe('MenuController', () => { describe('should handle actions', () => { it('should bail without config', () => { - const controller = new MenuController(createHost()); + const controller = new MenuController(createLitElement()); controller.actionHandler(createHASS(), createEvent('tap')); expect(vi.mocked(handleActionConfig)).not.toBeCalled(); }); it('should execute simple action in non-hidden menu', () => { - const host = createHost(); + const host = createLitElement(); const hass = createHASS(); const controller = new MenuController(host); @@ -377,7 +367,7 @@ describe('MenuController', () => { }); it('should execute simple action in with config in event', () => { - const host = createHost(); + const host = createLitElement(); const hass = createHASS(); const controller = new MenuController(host); @@ -391,7 +381,7 @@ describe('MenuController', () => { }); it('should execute simple array of actions in non-hidden menu', () => { - const host = createHost(); + const host = createLitElement(); const hass = createHASS(); const controller = new MenuController(host); @@ -401,7 +391,7 @@ describe('MenuController', () => { describe('should close menu', () => { it('tap', () => { - const host = createHost(); + const host = createLitElement(); const hass = createHASS(); const controller = new MenuController(host); controller.setMenuConfig( @@ -418,7 +408,7 @@ describe('MenuController', () => { }); it('end_tap', () => { - const host = createHost(); + const host = createLitElement(); const hass = createHASS(); const controller = new MenuController(host); controller.setMenuConfig( @@ -439,7 +429,7 @@ describe('MenuController', () => { describe('should not close menu', () => { it('start_tap with later action', () => { - const host = createHost(); + const host = createLitElement(); const hass = createHASS(); const controller = new MenuController(host); controller.setMenuConfig( @@ -459,7 +449,7 @@ describe('MenuController', () => { }); it('with a menu toggle action', () => { - const host = createHost(); + const host = createLitElement(); const hass = createHASS(); const controller = new MenuController(host); controller.setMenuConfig( @@ -479,7 +469,7 @@ describe('MenuController', () => { }); it('when no action is actually taken', () => { - const host = createHost(); + const host = createLitElement(); const hass = createHASS(); const controller = new MenuController(host); controller.setMenuConfig( diff --git a/tests/test-utils.ts b/tests/test-utils.ts index 0ae2a6f6..2009ceaf 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -1,5 +1,6 @@ import { CurrentUser, HomeAssistant } from '@dermotduffy/custom-card-helpers'; import { HassEntities, HassEntity } from 'home-assistant-js-websocket'; +import { LitElement } from 'lit'; import { expect, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { Camera } from '../src/camera-manager/camera'; @@ -13,7 +14,6 @@ import { CameraEventCallback, CameraManagerMediaCapabilities, } from '../src/camera-manager/types'; -import { CapabilitiesRaw } from '../src/types'; import { ActionsManager } from '../src/card-controller/actions-manager'; import { AutoUpdateManager } from '../src/card-controller/auto-update-manager'; import { AutomationsManager } from '../src/card-controller/automations-manager'; @@ -47,7 +47,7 @@ import { frigateCardConfigSchema, performanceConfigSchema, } from '../src/config/types'; -import { ExtendedHomeAssistant, MediaLoadedInfo } from '../src/types'; +import { CapabilitiesRaw, ExtendedHomeAssistant, MediaLoadedInfo } from '../src/types'; import { EntityRegistryManager } from '../src/utils/ha/entity-registry'; import { Entity } from '../src/utils/ha/entity-registry/types'; import { ViewMedia, ViewMediaType } from '../src/view/media'; @@ -248,6 +248,24 @@ export const createMediaLoadedInfo = ( }; }; +export const createMediaLoadedInfoEvent = ( + mediaLoadedInfo?: MediaLoadedInfo, +): CustomEvent => { + return new CustomEvent('frigate-card:media:loaded', { + detail: mediaLoadedInfo ?? createMediaLoadedInfo(), + composed: true, + bubbles: true, + }); +}; + +export const createViewChangeEvent = (view?: View): CustomEvent => { + return new CustomEvent('frigate-card:view:change', { + detail: view ?? createView(), + composed: true, + bubbles: true, + }); +}; + export const createPerformanceConfig = (config: unknown): PerformanceConfig => { return performanceConfigSchema.parse(config); }; @@ -342,6 +360,20 @@ export const requestAnimationFrameMock = (callback: FrameRequestCallback) => { return 1; }; +export const callIntersectionHandler = (intersecting = true, n = 0): void => { + const mockResult = vi.mocked(IntersectionObserver).mock.results[n]; + if (mockResult.type !== 'return') { + return; + } + const observer = mockResult.value; + vi.mocked(IntersectionObserver).mock.calls[n][0]( + // Note this is a very incomplete / invalid IntersectionObserverEntry that + // just provides the bare basics current implementation uses. + intersecting ? [{ isIntersecting: true } as IntersectionObserverEntry] : [], + observer, + ); +}; + export const createSlotHost = (options?: { slot?: HTMLSlotElement; children?: HTMLElement[]; @@ -370,6 +402,12 @@ export const createParent = (options?: { children?: HTMLElement[] }): HTMLElemen return parent; }; +export const createLitElement = (): LitElement => { + const element = document.createElement('div') as unknown as LitElement; + element.requestUpdate = vi.fn(); + return element; +}; + export const createCardAPI = (): CardController => { const api = mock(); diff --git a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts index 8ebb42f7..4cbfea08 100644 --- a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts +++ b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts @@ -20,12 +20,12 @@ import { import { dispatchExistingMediaLoadedInfoAsEvent } from '../../../../../src/utils/media-info'; import { IntersectionObserverMock, + callIntersectionHandler, createMediaLoadedInfo, createParent, } from '../../../../test-utils'; import { callEmblaHandler, - callIntersectionHandler, callVisibilityHandler, createEmblaApiInstance, createTestEmblaOptionHandler, diff --git a/tests/utils/embla/plugins/auto-size/auto-size.test.ts b/tests/utils/embla/plugins/auto-size/auto-size.test.ts index b04784c3..021a01ed 100644 --- a/tests/utils/embla/plugins/auto-size/auto-size.test.ts +++ b/tests/utils/embla/plugins/auto-size/auto-size.test.ts @@ -3,12 +3,12 @@ import AutoSize from '../../../../../src/utils/embla/plugins/auto-size/auto-size import { IntersectionObserverMock, ResizeObserverMock, + callIntersectionHandler, createParent, requestAnimationFrameMock, } from '../../../../test-utils'; import { callEmblaHandler, - callIntersectionHandler, callResizeHandler, createEmblaApiInstance, createTestEmblaOptionHandler, diff --git a/tests/utils/embla/test-utils.ts b/tests/utils/embla/test-utils.ts index e3ab0389..66aee8a8 100644 --- a/tests/utils/embla/test-utils.ts +++ b/tests/utils/embla/test-utils.ts @@ -43,20 +43,6 @@ export const callVisibilityHandler = (): void => { } }; -export const callIntersectionHandler = (intersecting = true, n = 0): void => { - const mockResult = vi.mocked(IntersectionObserver).mock.results[n]; - if (mockResult.type !== 'return') { - return; - } - const observer = mockResult.value; - vi.mocked(IntersectionObserver).mock.calls[n][0]( - // Note this is a very incomplete / invalid IntersectionObserverEntry that - // just provides the bare basics current implementation uses. - intersecting ? [{ isIntersecting: true } as IntersectionObserverEntry] : [], - observer, - ); -}; - export const callMutationHandler = (n = 0): void => { const mockResult = vi.mocked(MutationObserver).mock.results[n]; if (mockResult.type !== 'return') { diff --git a/vite.config.ts b/vite.config.ts index 0aaea85e..4479c43b 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -13,6 +13,7 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'camera-manager/utils/*.ts', 'card-controller/*.ts', 'components-lib/cached-value-controller.ts', + 'components-lib/live/live-controller.ts', 'components-lib/media-filter-controller.ts', 'components-lib/menu-button-controller.ts', 'components-lib/menu-controller.ts', From d191e9e608415a865fb994aac5326bbb780f600f Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 7 Apr 2024 20:24:12 -0700 Subject: [PATCH 116/189] Fix typo. --- src/components/live/live.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/live/live.ts b/src/components/live/live.ts index fd478d29..fe075223 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -76,7 +76,7 @@ export class FrigateCardLive extends LitElement { @property({ attribute: false }) public nonOverriddenLiveConfig?: LiveConfig; - @property({ attribute: false }>) + @property({ attribute: false }) public overriddenLiveConfig?: LiveConfig; @property({ attribute: false, hasChanged: contentsChanged }) From 9c9548afc8800964f5ab4d971078456a333a71be Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 7 Apr 2024 21:18:55 -0700 Subject: [PATCH 117/189] Fix card-wide actions. --- src/card-controller/actions-manager.ts | 24 ++++++++++++++--- src/card-controller/card-element-manager.ts | 12 +++++++-- tests/card-controller/actions-manager.test.ts | 26 ++++++++++++++++--- 3 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/card-controller/actions-manager.ts b/src/card-controller/actions-manager.ts index 89060699..8546dc9b 100644 --- a/src/card-controller/actions-manager.ts +++ b/src/card-controller/actions-manager.ts @@ -1,3 +1,4 @@ +import { z } from 'zod'; import { Actions, ActionsConfig, @@ -13,6 +14,15 @@ import { import { getStreamCameraID } from '../utils/substream.js'; import { CardActionsManagerAPI } from './types.js'; +const interactionSchema = z.object({ + action: z.enum(['tap', 'double_tap', 'hold', 'start_tap', 'end_tap']), +}); +export type Interaction = z.infer; + +const interactionEventSchema = z.object({ + detail: interactionSchema, +}); + export class ActionsManager { protected _api: CardActionsManagerAPI; @@ -49,7 +59,14 @@ export class ActionsManager { /** * Handle an human interaction called on an element (e.g. 'tap'). */ - public handleInteraction(interaction: string): void { + public handleInteractionEvent = (ev: Event): void => { + const result = interactionEventSchema.safeParse(ev); + if (!result.success) { + // The event may not be a CustomEvent object, see: + // https://github.com/custom-cards/custom-card-helpers/blob/master/src/fire-event.ts#L70 + return; + } + const interaction = result.data.detail.action; const hass = this._api.getHASSManager().getHASS(); const config = this.getMergedActions(); const actionConfig = getActionConfigGivenAction(interaction, config); @@ -70,12 +87,11 @@ export class ActionsManager { actionConfig, ); } - } + }; public handleActionEvent = (ev: Event): void => { if (!('detail' in ev)) { - // The event may not actually be a CustomEvent object, but may still have a - // detail field. See: + // The event may not be a CustomEvent object, see: // https://github.com/custom-cards/custom-card-helpers/blob/master/src/fire-event.ts#L70 return; } diff --git a/src/card-controller/card-element-manager.ts b/src/card-controller/card-element-manager.ts index 38599fd2..1b442f1e 100644 --- a/src/card-controller/card-element-manager.ts +++ b/src/card-controller/card-element-manager.ts @@ -77,7 +77,11 @@ export class CardElementManager { this._api.getActionsManager().handleActionEvent, ); this._element.addEventListener( - '@action', + 'action', + this._api.getActionsManager().handleInteractionEvent, + ); + this._element.addEventListener( + 'action', this._api.getInteractionManager().reportInteraction, ); @@ -123,7 +127,11 @@ export class CardElementManager { this._api.getActionsManager().handleActionEvent, ); this._element.removeEventListener( - '@action', + 'action', + this._api.getActionsManager().handleInteractionEvent, + ); + this._element.removeEventListener( + 'action', this._api.getInteractionManager().reportInteraction, ); diff --git a/tests/card-controller/actions-manager.test.ts b/tests/card-controller/actions-manager.test.ts index 02742759..8b11b640 100644 --- a/tests/card-controller/actions-manager.test.ts +++ b/tests/card-controller/actions-manager.test.ts @@ -14,7 +14,7 @@ import { frigateCardHandleActionConfig, getActionConfigGivenAction, } from '../../src/utils/action.js'; -import { ActionsManager } from '../../src/card-controller/actions-manager'; +import { ActionsManager, Interaction } from '../../src/card-controller/actions-manager'; import { createCardAPI, createConfig, @@ -165,7 +165,9 @@ describe('ActionsManager.handleInteraction', () => { }; vi.mocked(getActionConfigGivenAction).mockReturnValue(actionForThisInteraction); - manager.handleInteraction('tap'); + manager.handleInteractionEvent( + new CustomEvent('event', { detail: { action: 'tap' } }), + ); expect(frigateCardHandleActionConfig).toBeCalledWith( element, @@ -176,13 +178,29 @@ describe('ActionsManager.handleInteraction', () => { ); }); - it('should not handle interaction', () => { + it('should not handle interaction without hass', () => { const api = createCardAPI(); const manager = new ActionsManager(api); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(null); // No values of hass. - manager.handleInteraction('tap'); + manager.handleInteractionEvent( + new CustomEvent('event', { detail: { action: 'tap' } }), + ); + expect(frigateCardHandleActionConfig).not.toBeCalledWith(); + }); + + it('should not handle malformed interaction', () => { + const api = createCardAPI(); + const manager = new ActionsManager(api); + + manager.handleInteractionEvent( + new CustomEvent('event', { + + // Malformed interaction type. + detail: { action: 'double_finger_snap' } as unknown as Interaction, + }), + ); expect(frigateCardHandleActionConfig).not.toBeCalledWith(); }); }); From 25d080f0d43a3b802d982a2abc87f079c312a8de Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 7 Apr 2024 21:21:27 -0700 Subject: [PATCH 118/189] Remove unnecessary comment. --- src/card-controller/actions-manager.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/card-controller/actions-manager.ts b/src/card-controller/actions-manager.ts index 8546dc9b..69c54ab4 100644 --- a/src/card-controller/actions-manager.ts +++ b/src/card-controller/actions-manager.ts @@ -62,8 +62,6 @@ export class ActionsManager { public handleInteractionEvent = (ev: Event): void => { const result = interactionEventSchema.safeParse(ev); if (!result.success) { - // The event may not be a CustomEvent object, see: - // https://github.com/custom-cards/custom-card-helpers/blob/master/src/fire-event.ts#L70 return; } const interaction = result.data.detail.action; From 18bbe3a6415ddadfb5f7215f55afc50496129ce3 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 7 Apr 2024 21:24:35 -0700 Subject: [PATCH 119/189] Fix element tests. --- tests/card-controller/card-element-manager.test.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/card-controller/card-element-manager.test.ts b/tests/card-controller/card-element-manager.test.ts index c378ab10..82f9392b 100644 --- a/tests/card-controller/card-element-manager.test.ts +++ b/tests/card-controller/card-element-manager.test.ts @@ -122,7 +122,11 @@ describe('CardElementManager', () => { api.getActionsManager().handleActionEvent, ); expect(addEventListener).toBeCalledWith( - '@action', + 'action', + api.getActionsManager().handleInteractionEvent, + ); + expect(addEventListener).toBeCalledWith( + 'action', api.getInteractionManager().reportInteraction, ); expect(windowAddEventListener).toBeCalledWith('location-changed', expect.anything()); @@ -169,7 +173,11 @@ describe('CardElementManager', () => { api.getActionsManager().handleActionEvent, ); expect(removeEventListener).toBeCalledWith( - '@action', + 'action', + api.getActionsManager().handleInteractionEvent, + ); + expect(removeEventListener).toBeCalledWith( + 'action', api.getInteractionManager().reportInteraction, ); expect(windowRemoveEventListener).toBeCalledWith( From 6a55e2d54cd31eb4b5dead38c715835e6941fd01 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 7 Apr 2024 21:38:00 -0700 Subject: [PATCH 120/189] Improve favicon constrast. --- docs/images/README.md | 7 +++++++ docs/images/camera-iris.png | Bin 0 -> 10269 bytes docs/images/favicon.ico | Bin 143732 -> 143967 bytes 3 files changed, 7 insertions(+) create mode 100644 docs/images/README.md create mode 100644 docs/images/camera-iris.png diff --git a/docs/images/README.md b/docs/images/README.md new file mode 100644 index 00000000..b14e2066 --- /dev/null +++ b/docs/images/README.md @@ -0,0 +1,7 @@ +favicon.ico +-- + - https://pictogrammers.com/library/mdi/icon/camera-iris/ + - $ convert camera-iris.png -define icon:auto-resize="256,128,96,64,48,32,16" favicon.ico + + + diff --git a/docs/images/camera-iris.png b/docs/images/camera-iris.png new file mode 100644 index 0000000000000000000000000000000000000000..a2e19a57ba1f85263a402f0111c2992b63f88198 GIT binary patch literal 10269 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%0D}LZe4lE5}8`| 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 literal 143732 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%0A;g_$nRBen@LR(-h$wbPMnq7*p=S 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 j8{V< Date: Sat, 13 Apr 2024 18:23:11 -0700 Subject: [PATCH 121/189] Add support for more advanced forms of overriding --- docs/configuration/overrides.md | 173 +++++++- docs/examples.md | 32 +- package.json | 4 +- src/camera-manager/manager.ts | 2 +- src/card-controller/conditions-manager.ts | 91 ++-- src/card-controller/config-manager.ts | 12 +- src/components/live/live.ts | 31 +- src/components/views.ts | 14 +- src/config/management.ts | 2 +- src/config/types.ts | 89 ++-- src/utils/basic.ts | 22 +- src/utils/zod.ts | 5 +- tests/camera-manager/manager.test.ts | 4 +- .../conditions-manager.test.ts | 399 +++++++++++++++--- tests/config/management.test.ts | 57 ++- tests/config/profiles/index.test.ts | 2 +- tests/config/types.test.ts | 4 +- tests/test-utils.ts | 2 +- tests/utils/basic.test.ts | 54 ++- tests/utils/zod.test.ts | 17 + yarn.lock | 124 +++--- 21 files changed, 855 insertions(+), 285 deletions(-) diff --git a/docs/configuration/overrides.md b/docs/configuration/overrides.md index 59873789..d0c70375 100644 --- a/docs/configuration/overrides.md +++ b/docs/configuration/overrides.md @@ -1,39 +1,166 @@ # `overrides` -Various parts of card configuration may [conditionally](conditions.md) be -overridden (e.g. to hide the menu in fullscreen mode). +The card configuration may [conditionally](conditions.md) be overridden (e.g. to +hide the menu in fullscreen mode). ```yaml overrides: - conditions: [condition] - overrides: - [override] + [...] ``` -Not all configuration parameters are overriddable, some because it doesn't make -sense for that parameter to vary, and many because of the extra complexity of -supporting overriding given the lack of compelling usecases ([please request new -overridable parameters -here!](https://github.com/dermotduffy/frigate-hass-card/issues/new/choose)). +!> Whilst all configuration parameters are theoretically overridable, in some instances a configuration variable may only be consulted on startup or changing its value may negatively impact behavior -- override results may vary! -Each entry under the top-level `overrides` configuration block should be a list -item, that has both of the following parameters set: +The top-level `overrides` configuration block expects a list, with each list +item containing `conditions` and at least one of `merge`, `delete` or `set` specified. | Option | Default | Description | | - | - | - | | `conditions` | | A list of [conditions](conditions.md) that must evaluate to `true` in order for the overrides to be applied. | -| `overrides` | | Configuration overrides to be applied. Any configuration parameter matching [Overrideable parameters](overrides.md?id=overrideable-parameters) can be overridden. | +| `delete` | | An array of configuration paths to delete. See below. | +| `merge` | | A dictionary of configuration paths to merge. See below. | +| `set` | | A dictionary of configuration paths to set. See below. | -## Overrideable parameters +## Configuration Paths -| Configuration Key | Overrideable | -| - | - | -| [`cameras.*`](cameras/README.md) | :white_check_mark: | -| [`cameras_global.*`](cameras/README.md) | :white_check_mark: | -| [`dimensions.*`](dimensions.md) | :white_check_mark: | -| [`image.*`](image.md) | :white_check_mark: | -| [`live.controls.*`](live.md?id=controls), [`live.display.*`](live.md?id=display), [`live.microphone.*`](live.md?id=microphone), [`live.show_image_during_load`](live.md), [`live.zoomable`](live.md) | :white_check_mark: | -| [`menu.*`](menu.md) | :white_check_mark: | -| [`view.*`](view.md) | :white_check_mark: | -| *(Everything else)* | :heavy_multiplication_x: | +The `delete`, `merge` and `set` parameters take configuration paths. Paths are dot-separated references to particular configuration parameters. To refer to list elements use `[n]` notation. + +For example the path `cameras[1].dimensions.aspect_ratio` refers to the `aspect_ratio` parameter below: + +```yaml +cameras: + - camera_entity: camera.other + - camera_entity: camera.relevant + dimensions: + aspect_ratio: '16:9' +``` + +## `delete` + +An array of configuration paths to delete. + +```yaml +overrides: + - conditions: + [condition] + delete: + - [path_1] + - [path_2] +``` + +### Examples + +Delete the 2nd camera: + +```yaml +overrides: + - conditions: + [condition] + delete: + 'cameras[2]' +``` + +Delete the menu style parameter, thus falling back to the default: + +```yaml +overrides: + - conditions: + [condition] + delete: + 'menu.style' +``` + +## `merge` + +Specifies an object to recursively merge into existing configuration. + +| Option | Default | Description | +| - | - | - | +| [configuration path] | | Arbitrary configuration object to merge. Must be an object (i.e. not a literal value). | + +### Examples + +Hide the menu when a given condition is met: + +```yaml +overrides: + - conditions: + [condition] + merge: + menu: { + style: 'hidden' + } +``` + +Enable thumbnails below the `live` feed: + +```yaml +overrides: + - conditions: + [condition] + merge: + 'live.controls.thumbnails': { + mode: 'below' + } +``` + +Also enables thumbnails below the `live` feed, but without using the dot-separated notation: + +```yaml +overrides: + - conditions: + [condition] + merge: + live: { + controls: { + thumbnails: { + mode: 'below' + } + } + } +``` + +## `set` + +Specifies a value to set in the configuration. This differs from `merge` in that the existing value is entirely replaced. + +| Option | Default | Description | +| - | - | - | +| [configuration path] | | Arbitrary configuration value / object / list to set. | + +### Examples + +Set the entire menu configuration to defaults with the exception of the `style` which is set to `overlay`. + +```yaml +overrides: + - conditions: + [condition] + set: + menu: { + style: 'overlay' + } +``` + +Set the menu style but without touching the other `menu` parameters: + +```yaml +overrides: + - conditions: + [condition] + set: + 'menu.style': 'overlay' +``` + +That is equivalent to merging the following: + +```yaml +overrides: + - conditions: + [condition] + merge: + menu: { + style: 'overlay' + } +``` \ No newline at end of file diff --git a/docs/examples.md b/docs/examples.md index d2859a8d..c9a47395 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -424,7 +424,7 @@ overrides: - condition: state entity: light.office_main_lights state: 'on' - overrides: + merge: menu: position: bottom ``` @@ -451,7 +451,7 @@ overrides: - condition: state entity: binary_sensor.alarm_armed state: 'off' - overrides: + merge: view: default: image ``` @@ -471,7 +471,7 @@ overrides: fullscreen: true - condition: display_mode display_mode: grid - overrides: + merge: live: display: grid_columns: 5 @@ -497,7 +497,7 @@ overrides: - conditions: - condition: expand expand: true - overrides: + merge: menu: style: overlay ``` @@ -520,11 +520,29 @@ overrides: - conditions: - condition: fullscreen fullscreen: true - overrides: + merge: menu: style: none ``` +### Remove a camera when an entity state changes + +This example removes a camera from the card when an entity is disabled (e.g. a switch controlling power to the camera). + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + - camera_entity: camera.kitchen +overrides: + - conditions: + - condition: state + entity: switch.kitchen_camera_power + state: off + delete: + - 'cameras[1]' +``` + ## PTZ control The card supports using PTZ controls to conveniently control pan, tilt and zoom for cameras. This example shows the PTZ controls on the `live` view. Note that if your camera engine supports it (e.g. `frigate`) this will just work out of the box with no configuration at all. @@ -568,7 +586,7 @@ overrides: - conditions: - condition: screen media_query: '(orientation: landscape)' - overrides: + merge: menu: position: left ``` @@ -584,7 +602,7 @@ overrides: - conditions: - condition: screen media_query: '(max-width: 300px)' - overrides: + merge: menu: style: none live: diff --git a/package.json b/package.json index d91d94d5..f72013e0 100644 --- a/package.json +++ b/package.json @@ -61,7 +61,7 @@ "@types/masonry-layout": "^4.2.5", "@typescript-eslint/eslint-plugin": "^5.36.2", "@typescript-eslint/parser": "^5.36.2", - "@vitest/coverage-istanbul": "^1.3.1", + "@vitest/coverage-istanbul": "^1.5.0", "docsify-cli": "^4.4.4", "eslint": "^8.23.0", "eslint-config-airbnb-base": "^15.0.0", @@ -81,7 +81,7 @@ "sass": "^1.54.9", "ts-prune": "^0.10.3", "typescript": "^4.9.5", - "vitest": "^1.3.1", + "vitest": "^1.5.0", "vitest-mock-extended": "^1.3.1" }, "scripts": { diff --git a/src/camera-manager/manager.ts b/src/camera-manager/manager.ts index 7f3968a6..df7775fa 100644 --- a/src/camera-manager/manager.ts +++ b/src/camera-manager/manager.ts @@ -145,7 +145,7 @@ export class CameraManager { // order, to ensure that the defaults in the cameras global config do not // override the values specified in the per-camera config. const cameras = config.cameras.map((camera) => - recursivelyMergeObjectsNotArrays(cloneDeep(config?.cameras_global), camera), + recursivelyMergeObjectsNotArrays({}, cloneDeep(config?.cameras_global), camera), ); try { diff --git a/src/card-controller/conditions-manager.ts b/src/card-controller/conditions-manager.ts index 122a44b7..7cc0d7ec 100644 --- a/src/card-controller/conditions-manager.ts +++ b/src/card-controller/conditions-manager.ts @@ -1,14 +1,21 @@ import { CurrentUser } from '@dermotduffy/custom-card-helpers'; import { HassEntities } from 'home-assistant-js-websocket'; import merge from 'lodash-es/merge'; -import { copyConfig } from '../config/management'; +import { ZodSchema } from 'zod'; +import { + copyConfig, + deleteConfigValue, + getConfigValue, + setConfigValue, +} from '../config/management'; import { FrigateCardCondition, - frigateConditionalSchema, - OverrideConfigurationKey, RawFrigateCardConfig, ViewDisplayMode, + frigateConditionalSchema, + Overrides, } from '../config/types'; +import { desparsifyArrays } from '../utils/basic'; import { CardConditionAPI } from './types'; interface MicrophoneConditionState { @@ -73,44 +80,66 @@ export function evaluateConditionViaEvent( return evaluateEvent.evaluation ?? false; } -type RawOverrides = { - conditions: FrigateCardCondition[]; - overrides: RawFrigateCardConfig; -}[]; - export function getOverriddenConfig( manager: Readonly, config: Readonly, - configOverrides?: Readonly, - stateOverrides?: Partial, + options?: { + configOverrides?: Readonly; + stateOverrides?: Partial; + schema?: ZodSchema; + logOnParseError?: boolean; + }, ): RawFrigateCardConfig { - const output = copyConfig(config); + let output = copyConfig(config); let overridden = false; - if (configOverrides) { - for (const override of configOverrides) { - if (manager.evaluateConditions(override.conditions, stateOverrides)) { - merge(output, override.overrides); + if (options?.configOverrides) { + for (const override of options.configOverrides) { + if (manager.evaluateConditions(override.conditions, options?.stateOverrides)) { + override.delete?.forEach((deletionKey) => { + deleteConfigValue(output, deletionKey); + }); + + Object.keys(override.set ?? {}).forEach((setKey) => { + setConfigValue(output, setKey, override.set?.[setKey]); + }); + + Object.keys(override.merge ?? {}).forEach((mergeKey) => { + setConfigValue( + output, + mergeKey, + merge({}, getConfigValue(output, mergeKey), override.merge?.[mergeKey]), + ); + }); + overridden = true; } } } - // Attempt to return the same configuration object if it has not been - // overridden (to reduce re-renders for a configuration that has not changed). - return overridden ? output : config; -} -export function getOverridesByKey( - key: OverrideConfigurationKey, - overrides?: Readonly, -): RawOverrides { - return ( - overrides - ?.filter((o) => key in o.overrides) - .map((o) => ({ - conditions: o.conditions, - overrides: o.overrides[key] as RawFrigateCardConfig, - })) ?? [] - ); + if (!overridden) { + // Attempt to return the same configuration object if it has not been + // overridden (to reduce re-renders for a configuration that has not changed). + return config; + } + + if (options?.configOverrides?.some((override) => override.delete?.length)) { + // If anything was deleted during this override, empty undefined slots may + // be left in arrays where values were unset. Desparsify them. + output = desparsifyArrays(output); + } + + if (options?.schema) { + const parseResult = options.schema.safeParse(output); + if (options.logOnParseError && !parseResult.success) { + console.warn( + `Cannot parse overridden configuration`, + output, + parseResult.error.message, + ); + } + return parseResult.success ? parseResult.data : config; + } + return output; } // A tiny wrapper interface to allow the same manager to be passed around diff --git a/src/card-controller/config-manager.ts b/src/card-controller/config-manager.ts index a062944d..947b530b 100644 --- a/src/card-controller/config-manager.ts +++ b/src/card-controller/config-manager.ts @@ -4,7 +4,7 @@ import { CardWideConfig, FrigateCardConfig, frigateCardConfigSchema, - RawFrigateCardConfig + RawFrigateCardConfig, } from '../config/types'; import { localize } from '../localize/localize'; import { setProfiles } from '../config/profiles'; @@ -104,11 +104,11 @@ export class ConfigManager { if (!this._config) { return; } - const overriddenConfig = getOverriddenConfig( - conditionsManager, - this._config, - this._config.overrides, - ) as FrigateCardConfig; + const overriddenConfig = getOverriddenConfig(conditionsManager, this._config, { + configOverrides: this._config.overrides, + schema: frigateCardConfigSchema, + logOnParseError: !!this.getCardWideConfig()?.debug?.logging, + }) as FrigateCardConfig; // Save on Lit re-rendering costs by only updating the configuration if it // actually changes. diff --git a/src/components/live/live.ts b/src/components/live/live.ts index fe075223..59a0bc70 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -26,8 +26,9 @@ import { CardWideConfig, frigateCardConfigDefaults, LiveConfig, - LiveOverrides, + liveConfigAbsoluteRootSchema, LiveProvider, + Overrides, TransitionEffect, } from '../../config/types.js'; import { localize } from '../../localize/localize.js'; @@ -80,7 +81,7 @@ export class FrigateCardLive extends LitElement { public overriddenLiveConfig?: LiveConfig; @property({ attribute: false, hasChanged: contentsChanged }) - public liveOverrides?: LiveOverrides; + public overrides?: Overrides; @property({ attribute: false }) public cameraManager?: CameraManager; @@ -151,7 +152,7 @@ export class FrigateCardLive extends LitElement { .overriddenLiveConfig=${this.overriddenLiveConfig} .inBackground=${this._controller.isInBackground()} .conditionsManagerEpoch=${this.conditionsManagerEpoch} - .liveOverrides=${this.liveOverrides} + .overrides=${this.overrides} .cardWideConfig=${this.cardWideConfig} .cameraManager=${this.cameraManager} .microphoneManager=${this.microphoneManager} @@ -182,7 +183,7 @@ export class FrigateCardLiveGrid extends LitElement { public overriddenLiveConfig?: LiveConfig; @property({ attribute: false, hasChanged: contentsChanged }) - public liveOverrides?: LiveOverrides; + public overrides?: Overrides; @property({ attribute: false }) public conditionsManagerEpoch?: ConditionsManagerEpoch; @@ -211,7 +212,7 @@ export class FrigateCardLiveGrid extends LitElement { .nonOverriddenLiveConfig=${this.nonOverriddenLiveConfig} .overriddenLiveConfig=${this.overriddenLiveConfig} .conditionsManagerEpoch=${this.conditionsManagerEpoch} - .liveOverrides=${this.liveOverrides} + .overrides=${this.overrides} .cardWideConfig=${this.cardWideConfig} .cameraManager=${this.cameraManager} .microphoneManager=${this.microphoneManager} @@ -290,7 +291,7 @@ export class FrigateCardLiveCarousel extends LitElement { public overriddenLiveConfig?: LiveConfig; @property({ attribute: false, hasChanged: contentsChanged }) - public liveOverrides?: LiveOverrides; + public overrides?: Overrides; @property({ attribute: false }) public conditionsManagerEpoch?: ConditionsManagerEpoch; @@ -471,19 +472,23 @@ export class FrigateCardLiveCarousel extends LitElement { // (in the carousel for example) is not necessarily the live camera *this* // is rendering right now, so we provide a // stateOverride to evaluate the condition in that context. - const config = getOverriddenConfig( + const liveConfig = getOverriddenConfig( this.conditionsManagerEpoch.manager, - this.nonOverriddenLiveConfig, - this.liveOverrides, - { camera: cameraID }, - ) as LiveConfig; + { live: this.nonOverriddenLiveConfig }, + { + configOverrides: this.overrides, + stateOverrides: { camera: cameraID }, + schema: liveConfigAbsoluteRootSchema, + logOnParseError: !!this.cardWideConfig?.debug?.logging, + }, + ).live as LiveConfig; const cameraMetadata = this.cameraManager.getCameraMetadata(cameraID); return html`

    this.cameraManager?.getCameraEndpoints(cameraID) ?? undefined, )} .label=${cameraMetadata?.title ?? ''} - .liveConfig=${config} + .liveConfig=${liveConfig} .hass=${this.hass} .cardWideConfig=${this.cardWideConfig} > diff --git a/src/components/views.ts b/src/components/views.ts index d1c3a2ef..f5d08c0e 100644 --- a/src/components/views.ts +++ b/src/components/views.ts @@ -9,10 +9,7 @@ import { import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { CameraManager } from '../camera-manager/manager.js'; -import { - ConditionsManagerEpoch, - getOverridesByKey, -} from '../card-controller/conditions-manager.js'; +import { ConditionsManagerEpoch } from '../card-controller/conditions-manager.js'; import { ReadonlyMicrophoneManager } from '../card-controller/microphone-manager.js'; import { CardWideConfig, @@ -233,10 +230,7 @@ export class FrigateCardViews extends LitElement { .nonOverriddenLiveConfig=${this.nonOverriddenConfig.live} .overriddenLiveConfig=${this.overriddenConfig.live} .conditionsManagerEpoch=${this.conditionsManagerEpoch} - .liveOverrides=${getOverridesByKey( - 'live', - this.overriddenConfig.overrides, - )} + .overrides=${this.overriddenConfig.overrides} .cameraManager=${this.cameraManager} .cardWideConfig=${this.cardWideConfig} .microphoneManager=${this.microphoneManager} @@ -248,10 +242,6 @@ export class FrigateCardViews extends LitElement { : `` } `; - - // .fetchMediaType=${this.view?.is('live') ? this.overriddenConfig.live.controls.thumbnails.media_type : undefined} - // .fetchEventsMediaType=${this.view?.is('live') ? this.overriddenConfig.live.controls.thumbnails.events_media_type : undefined} - } static get styles(): CSSResultGroup { diff --git a/src/config/management.ts b/src/config/management.ts index 146531f2..454826ee 100644 --- a/src/config/management.ts +++ b/src/config/management.ts @@ -42,7 +42,6 @@ import { arrayify } from '../utils/basic'; * @param keys The key to the property to set. * @param value The value to set. */ - export const setConfigValue = ( obj: RawFrigateCardConfig, keys: string | (string | number)[], @@ -689,4 +688,5 @@ const UPGRADES = [ // Delete the value if it's set to the default. transform: (val) => (val === 'low' ? ['low-performance'] : null), }), + upgradeArrayOfObjects(CONF_OVERRIDES, upgradeMoveTo('overrides', 'merge')), ]; diff --git a/src/config/types.ts b/src/config/types.ts index d3ca5191..7692d2ec 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -1008,8 +1008,24 @@ const livethumbnailsControlSchema = thumbnailsControlSchema.extend({ ), }); -const liveOverridableConfigSchema = z +const liveConfigSchema = z .object({ + auto_pause: z + .enum(MEDIA_ACTION_NEGATIVE_CONDITIONS) + .array() + .default(liveConfigDefault.auto_pause), + auto_play: z + .enum(MEDIA_ACTION_POSITIVE_CONDITIONS) + .array() + .default(liveConfigDefault.auto_play), + auto_mute: z + .enum(MEDIA_MUTE_CONDITIONS) + .array() + .default(liveConfigDefault.auto_mute), + auto_unmute: z + .enum(MEDIA_UNMUTE_CONDITIONS) + .array() + .default(liveConfigDefault.auto_unmute), controls: z .object({ builtin: z.boolean().default(liveConfigDefault.controls.builtin), @@ -1032,55 +1048,36 @@ const liveOverridableConfigSchema = z title: titleControlConfigSchema.optional(), }) .default(liveConfigDefault.controls), - show_image_during_load: z - .boolean() - .default(liveConfigDefault.show_image_during_load), - microphone: microphoneConfigSchema.default(liveConfigDefault.microphone), - zoomable: z.boolean().default(liveConfigDefault.zoomable), display: viewDisplaySchema, - }) - .merge(actionsSchema); - -const liveConfigSchema = liveOverridableConfigSchema - .extend({ - auto_play: z - .enum(MEDIA_ACTION_POSITIVE_CONDITIONS) - .array() - .default(liveConfigDefault.auto_play), - auto_pause: z - .enum(MEDIA_ACTION_NEGATIVE_CONDITIONS) - .array() - .default(liveConfigDefault.auto_pause), - auto_mute: z - .enum(MEDIA_MUTE_CONDITIONS) - .array() - .default(liveConfigDefault.auto_mute), - auto_unmute: z - .enum(MEDIA_UNMUTE_CONDITIONS) - .array() - .default(liveConfigDefault.auto_unmute), - preload: z.boolean().default(liveConfigDefault.preload), + draggable: z.boolean().default(liveConfigDefault.draggable), lazy_load: z.boolean().default(liveConfigDefault.lazy_load), lazy_unload: z .enum(MEDIA_ACTION_NEGATIVE_CONDITIONS) .array() .default(liveConfigDefault.lazy_unload), - draggable: z.boolean().default(liveConfigDefault.draggable), + microphone: microphoneConfigSchema.default(liveConfigDefault.microphone), + preload: z.boolean().default(liveConfigDefault.preload), + show_image_during_load: z + .boolean() + .default(liveConfigDefault.show_image_during_load), transition_effect: transitionEffectConfigSchema.default( liveConfigDefault.transition_effect, ), + zoomable: z.boolean().default(liveConfigDefault.zoomable), }) + .merge(actionsSchema) .default(liveConfigDefault); export type LiveConfig = z.infer; -const liveOverridesSchema = z - .object({ - conditions: frigateCardConditionSchema.array(), - overrides: liveOverridableConfigSchema, - }) - .array() - .optional(); -export type LiveOverrides = z.infer; +// This schema is used when the live config needs to be overridden (see +// `live.ts`). Overrides will always be "relative" to the config root, so this +// schema maintains that 'depth' from the root but without the other +// requirements that frigateCardConfigSchema has. Without this, overrides +// calculated in `live.ts` would fail since cameras/type are not provided (as +// these are mandatory parameters in the full config). +export const liveConfigAbsoluteRootSchema = z.object({ + live: liveConfigSchema, +}); // ************************************************************************* // Cast Configuration @@ -1580,26 +1577,16 @@ export const dimensionsConfigSchema = z // Override Configuration // ************************************************************************* -// Strip all defaults from the override schemas, to ensure values are only what -// the user has specified. -const overrideConfigurationSchema = z.object({ - cameras: deepRemoveDefaults(camerasConfigSchema).optional(), - cameras_global: deepRemoveDefaults(cameraConfigSchema).optional(), - live: deepRemoveDefaults(liveOverridableConfigSchema).optional(), - menu: deepRemoveDefaults(menuConfigSchema).optional(), - image: deepRemoveDefaults(imageConfigSchema).optional(), - view: deepRemoveDefaults(viewConfigSchema).optional(), - dimensions: deepRemoveDefaults(dimensionsConfigSchema).optional(), -}); -export type OverrideConfigurationKey = keyof z.infer; - const overridesSchema = z .object({ conditions: frigateCardConditionSchema.array(), - overrides: overrideConfigurationSchema, + merge: z.object({}).passthrough().optional(), + set: z.object({}).passthrough().optional(), + delete: z.string().array().optional(), }) .array() .optional(); +export type Overrides = z.infer; // ************************************************************************* // Automation Configuration diff --git a/src/utils/basic.ts b/src/utils/basic.ts index 9c074f54..a31f1223 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -243,8 +243,8 @@ export const getChildrenFromElement = (parent: HTMLElement): HTMLElement[] => { return children.filter(isHTMLElement); }; -export const recursivelyMergeObjectsNotArrays = (src1: T, src2: T): T => { - return mergeWith({}, src1, src2, (_a, b) => (Array.isArray(b) ? b : undefined)); +export const recursivelyMergeObjectsNotArrays = (target: T, src1: T, src2: T): T => { + return mergeWith(target, src1, src2, (_a, b) => (Array.isArray(b) ? b : undefined)); }; export const aspectRatioToString = (options?: { @@ -268,3 +268,21 @@ export const aspectRatioToStyle = (options?: { 'aspect-ratio': aspectRatioToString(options), }; }; + +/** + * Remove empty slots from nested arrays. + */ +export const desparsifyArrays = (data: T): T => { + if (Array.isArray(data)) { + return ( + data.filter((item) => item !== undefined).map((item) => desparsifyArrays(item)) + ); + } else if (typeof data === 'object' && data !== null) { + const result: Record = {}; + for (const key in data) { + result[key] = desparsifyArrays(data[key]); + } + return result; + } + return data; +}; diff --git a/src/utils/zod.ts b/src/utils/zod.ts index 03de3a50..2afdc90c 100644 --- a/src/utils/zod.ts +++ b/src/utils/zod.ts @@ -28,7 +28,10 @@ export function deepRemoveDefaults(schema: T): any { } if (schema instanceof z.ZodArray) { - return z.ZodArray.create(deepRemoveDefaults(schema.element)); + return z.ZodArray.create(deepRemoveDefaults(schema.element)) + .min(schema._def.minLength?.value, schema._def.minLength?.message) + .max(schema._def.maxLength?.value, schema._def.maxLength?.message) + .length(schema._def.exactLength?.value, schema._def.exactLength?.message); } if (schema instanceof z.ZodOptional) { diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts index 282cf68e..6a0a2258 100644 --- a/tests/camera-manager/manager.test.ts +++ b/tests/camera-manager/manager.test.ts @@ -457,11 +457,11 @@ describe('CameraManager', async () => { }, ); - it('without cameras', async () => { + it('without camera', async () => { const api = createCardAPI(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); - const manager = createCameraManager(api, mock(), []); + const manager = createCameraManager(api, mock()); expect(manager.generateDefaultEventQueries('not_a_camera')).toBeNull(); }); diff --git a/tests/card-controller/conditions-manager.test.ts b/tests/card-controller/conditions-manager.test.ts index eea42258..b072c0c0 100644 --- a/tests/card-controller/conditions-manager.test.ts +++ b/tests/card-controller/conditions-manager.test.ts @@ -1,10 +1,10 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { z } from 'zod'; import { ConditionsEvaluateRequestEvent, ConditionsManager, evaluateConditionViaEvent, getOverriddenConfig, - getOverridesByKey, } from '../../src/card-controller/conditions-manager'; import { FrigateCardCondition } from '../../src/config/types'; import { @@ -77,77 +77,350 @@ describe('getOverriddenConfig', () => { style: 'none', }, }; - const overrides = [ - { - overrides: { - menu: { - style: 'above', - }, - }, - conditions: [ - { - condition: 'fullscreen' as const, - fullscreen: true, - }, - ], - }, - ]; - it('should not override config', () => { - const manager = new ConditionsManager(createCardAPI()); - expect(getOverriddenConfig(manager, config, overrides)).toBe(config); - }); - - it('should override config', () => { - const manager = new ConditionsManager(createCardAPI()); - manager.setState({ fullscreen: true }); - - expect(getOverriddenConfig(manager, config, overrides)).toEqual({ - menu: { - style: 'above', - }, - }); - }); - - it('should do nothing without overrides', () => { + it('should not override without overrides', () => { const manager = new ConditionsManager(createCardAPI()); manager.setState({ fullscreen: true }); expect(getOverriddenConfig(manager, config)).toBe(config); }); -}); -describe('getOverridesByKey', () => { - const conditions = [ - { - condition: 'fullscreen' as const, - fullscreen: true, - }, - ]; - const override = { - menu: { - style: 'above', - }, - }; - const overrides = [ - { - overrides: override, - conditions: conditions, - }, - ]; - - it('should get overrides', () => { - expect(getOverridesByKey('menu', overrides)).toEqual([ - { conditions: conditions, overrides: { style: 'above' } }, - ]); + it('should not override when condition does not match', () => { + const manager = new ConditionsManager(createCardAPI()); + expect( + getOverriddenConfig(manager, config, { + configOverrides: [ + { + merge: { + menu: { + style: 'hidden', + }, + }, + delete: ['menu.style'], + set: { + 'menu.style': 'overlay', + }, + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], + }, + ], + }), + ).toBe(config); }); - it('should get no overrides', () => { - expect(getOverridesByKey('live', overrides)).toEqual([]); + describe('should merge', () => { + it('with path', () => { + const manager = new ConditionsManager(createCardAPI()); + manager.setState({ fullscreen: true }); + + expect( + getOverriddenConfig(manager, config, { + configOverrides: [ + { + merge: { + 'live.controls.thumbnails': { + mode: 'none', + }, + }, + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], + }, + ], + }), + ).toEqual({ + menu: { + style: 'none', + }, + live: { + controls: { + thumbnails: { + mode: 'none', + }, + }, + }, + }); + }); + + it('without path', () => { + const manager = new ConditionsManager(createCardAPI()); + manager.setState({ fullscreen: true }); + + expect( + getOverriddenConfig(manager, config, { + configOverrides: [ + { + merge: { + menu: { + style: 'hidden', + }, + }, + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], + }, + ], + }), + ).toEqual({ + menu: { + style: 'hidden', + }, + }); + }); + + it('with invalid merge', () => { + const manager = new ConditionsManager(createCardAPI()); + manager.setState({ fullscreen: true }); + + expect( + getOverriddenConfig(manager, config, { + configOverrides: [ + { + merge: 6 as unknown as Record, + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], + }, + ], + }), + ).toEqual({ + menu: { + style: 'none', + }, + }); + }); }); - it('should get no overrides when undefined', () => { - expect(getOverridesByKey('live')).toEqual([]); + describe('should set', () => { + it('leaf node', () => { + const manager = new ConditionsManager(createCardAPI()); + manager.setState({ fullscreen: true }); + + expect( + getOverriddenConfig(manager, config, { + configOverrides: [ + { + set: { + 'menu.style': 'hidden', + }, + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], + }, + ], + }), + ).toEqual({ + menu: { + style: 'hidden', + }, + }); + }); + + it('root node', () => { + const manager = new ConditionsManager(createCardAPI()); + manager.setState({ fullscreen: true }); + + expect( + getOverriddenConfig(manager, config, { + configOverrides: [ + { + set: { + menu: { + style: 'hidden', + }, + }, + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], + }, + ], + }), + ).toEqual({ + menu: { + style: 'hidden', + }, + }); + }); + }); + + describe('should delete', () => { + it('leaf node', () => { + const manager = new ConditionsManager(createCardAPI()); + manager.setState({ fullscreen: true }); + + expect( + getOverriddenConfig(manager, config, { + configOverrides: [ + { + delete: ['menu.style' as const], + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], + }, + ], + }), + ).toEqual({ + menu: {}, + }); + }); + + it('root node', () => { + const manager = new ConditionsManager(createCardAPI()); + manager.setState({ fullscreen: true }); + + expect( + getOverriddenConfig(manager, config, { + configOverrides: [ + { + delete: ['menu' as const], + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], + }, + ], + }), + ).toEqual({}); + }); + + // it('with empty value and object', () => { + // const manager = new ConditionsManager(createCardAPI()); + // manager.setState({ fullscreen: true }); + + // expect( + // getOverriddenConfig(manager, config, { + // configOverrides: [ + // { + // delete: [''], + // conditions: [ + // { + // condition: 'fullscreen' as const, + // fullscreen: true, + // }, + // ], + // }, + // ], + // emptyKeyReplaces: true, + // }), + // ).toEqual({}); + // }); + }); + + describe('should validate schema', () => { + const testSchema = z.object({ + menu: z.object({ + style: z.enum(['none', 'hidden']), + }), + }); + + it('passing', () => { + const manager = new ConditionsManager(createCardAPI()); + manager.setState({ fullscreen: true }); + + expect( + getOverriddenConfig(manager, config, { + configOverrides: [ + { + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], + set: { + 'menu.style': 'hidden', + }, + }, + ], + schema: testSchema, + }), + ).toEqual({ + menu: { + style: 'hidden', + }, + }); + }); + + it('failing', () => { + const manager = new ConditionsManager(createCardAPI()); + manager.setState({ fullscreen: true }); + + expect( + getOverriddenConfig(manager, config, { + configOverrides: [ + { + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], + set: { + 'menu.style': 'NOT_A_STYLE', + }, + }, + ], + schema: testSchema, + }), + ).toEqual(config); + }); + + it('failing and logging', () => { + const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined); + + const manager = new ConditionsManager(createCardAPI()); + manager.setState({ fullscreen: true }); + + expect( + getOverriddenConfig(manager, config, { + configOverrides: [ + { + conditions: [ + { + condition: 'fullscreen' as const, + fullscreen: true, + }, + ], + set: { + 'menu.style': 'NOT_A_STYLE', + }, + }, + ], + schema: testSchema, + logOnParseError: true, + }), + ).toEqual(config); + + expect(consoleSpy).toBeCalledWith( + 'Cannot parse overridden configuration', + expect.anything(), + expect.anything(), + ); + }); }); }); @@ -194,7 +467,7 @@ describe('ConditionsManager', () => { return createConfig({ overrides: [ { - overrides: {}, + merge: {}, conditions: conditions, }, ], @@ -455,7 +728,7 @@ describe('ConditionsManager', () => { describe('with screen condition', () => { const mediaQueryConfig = { type: 'custom:frigate-card', - cameras: [], + cameras: [{}], elements: [ { type: 'custom:frigate-card-conditional', diff --git a/tests/config/management.test.ts b/tests/config/management.test.ts index e12e60e4..9bfb248e 100644 --- a/tests/config/management.test.ts +++ b/tests/config/management.test.ts @@ -420,7 +420,7 @@ describe('should handle version specific upgrades', () => { media_loaded: true, }, ], - overrides: { + merge: { view: { default: 'clips', }, @@ -489,7 +489,7 @@ describe('should handle version specific upgrades', () => { overrides: [ { conditions: {}, - overrides: { + merge: { menu: { buttons: { camera_ui: { @@ -1872,7 +1872,7 @@ describe('should handle version specific upgrades', () => { views: ['clips', 'snapshots'], }, ], - overrides: { + merge: { view: { default: 'clips', }, @@ -1987,7 +1987,7 @@ describe('should handle version specific upgrades', () => { cameras: ['camera_1', 'camera_2'], }, ], - overrides: { + merge: { view: { default: 'clips', }, @@ -2107,7 +2107,7 @@ describe('should handle version specific upgrades', () => { [condition]: true, }, ], - overrides: { + merge: { view: { default: 'clips', }, @@ -2255,7 +2255,7 @@ describe('should handle version specific upgrades', () => { state_not: 'off', }, ], - overrides: { + merge: { view: { default: 'clips', }, @@ -2387,7 +2387,7 @@ describe('should handle version specific upgrades', () => { media_query: 'query', }, ], - overrides: { + merge: { view: { default: 'clips', }, @@ -2497,5 +2497,48 @@ describe('should handle version specific upgrades', () => { }); }); }); + + it('from overrides to merge', () => { + const config = { + type: 'custom:frigate-card', + cameras: [], + overrides: [ + { + conditions: [ + { + condition: 'view', + view: ['clips'], + }, + ], + overrides: { + menu: { + style: 'hidden', + }, + }, + }, + ], + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [], + overrides: [ + { + conditions: [ + { + condition: 'view', + view: ['clips'], + }, + ], + merge: { + menu: { + style: 'hidden', + }, + }, + }, + ], + }); + }); }); }); diff --git a/tests/config/profiles/index.test.ts b/tests/config/profiles/index.test.ts index 20fd2ad5..c34d1c08 100644 --- a/tests/config/profiles/index.test.ts +++ b/tests/config/profiles/index.test.ts @@ -25,7 +25,7 @@ describe('setProfiles', () => { it('should handle profiles', () => { const input = { type: 'frigate-hass-card', - cameras: [], + cameras: [{}], live: { controls: { timeline: { diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 76ec3350..e94ced6c 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -12,7 +12,7 @@ import { createConfig } from '../test-utils'; describe('config defaults', () => { it('should be as expected', () => { expect(createConfig()).toEqual({ - cameras: [], + cameras: [{}], cameras_global: { dependencies: { all_cameras: false, @@ -453,7 +453,7 @@ describe('should handle custom frigate elements', () => { it('should not require title controls to specify all options', () => { expect( createConfig({ - cameras: [], + cameras: [{}], live: { controls: { title: { diff --git a/tests/test-utils.ts b/tests/test-utils.ts index 2009ceaf..3b1cf6e2 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -67,7 +67,7 @@ export const createCondition = ( export const createConfig = (config?: RawFrigateCardConfig): FrigateCardConfig => { return frigateCardConfigSchema.parse({ type: 'frigate-hass-card', - cameras: [], + cameras: [{}], ...config, }); }; diff --git a/tests/utils/basic.test.ts b/tests/utils/basic.test.ts index 4bbadfe6..38c0add6 100644 --- a/tests/utils/basic.test.ts +++ b/tests/utils/basic.test.ts @@ -7,6 +7,7 @@ import { aspectRatioToStyle, contentsChanged, dayToDate, + desparsifyArrays, dispatchFrigateCardEvent, errorToConsole, formatDate, @@ -158,6 +159,7 @@ describe('runWhenIdleIfSupported', () => { }); it('should run directly when not supported', () => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any (window as any).requestIdleCallback = undefined; const func = vi.fn(); runWhenIdleIfSupported(func); @@ -166,7 +168,7 @@ describe('runWhenIdleIfSupported', () => { it('should run idle when supported', () => { const requestIdle = vi.fn(); - (window as any).requestIdleCallback = requestIdle; + window.requestIdleCallback = requestIdle; const func = vi.fn(); runWhenIdleIfSupported(func); expect(requestIdle).toBeCalledWith(func, {}); @@ -174,7 +176,7 @@ describe('runWhenIdleIfSupported', () => { it('should run idle with timeout when supported', () => { const requestIdle = vi.fn(); - (window as any).requestIdleCallback = requestIdle; + window.requestIdleCallback = requestIdle; const func = vi.fn(); runWhenIdleIfSupported(func, 10); expect(requestIdle).toBeCalledWith(func, { timeout: 10 }); @@ -298,6 +300,7 @@ describe('recursivelyMergeObjectsNotArrays', () => { it('should recursively merge objects but replace arrays', () => { expect( recursivelyMergeObjectsNotArrays( + {}, { a: { b: { @@ -356,3 +359,50 @@ describe('aspectRatioToStyle', () => { expect(aspectRatioToStyle({ ratio: [4] })).toEqual({ 'aspect-ratio': 'auto' }); }); }); + +describe('desparsifyArrays', () => { + it('number', () => { + expect(desparsifyArrays(1)).toBe(1); + }); + it('string', () => { + expect(desparsifyArrays('foo')).toBe('foo'); + }); + describe('array', () => { + it('simple', () => { + expect(desparsifyArrays([1, 2, undefined, 3])).toEqual([1, 2, 3]); + }); + it('nested', () => { + expect( + desparsifyArrays([ + 1, + 2, + undefined, + { + subArray: [undefined, 3], + }, + 4, + ]), + ).toEqual([1, 2, { subArray: [3] }, 4]); + }); + }); + describe('object', () => { + it('simple', () => { + expect( + desparsifyArrays({ foo: [1, 2, undefined, 3], bar: [undefined, 4] }), + ).toEqual({ + foo: [1, 2, 3], + bar: [4], + }); + }); + it('nested', () => { + expect( + desparsifyArrays({ foo: { bar: [1, undefined, 2], empty: [undefined] } }), + ).toEqual({ + foo: { + bar: [1, 2], + empty: [], + }, + }); + }); + }); +}); diff --git a/tests/utils/zod.test.ts b/tests/utils/zod.test.ts index b2d1b837..ef69193f 100644 --- a/tests/utils/zod.test.ts +++ b/tests/utils/zod.test.ts @@ -49,6 +49,23 @@ describe('deepRemoveDefaults', () => { const result = deepRemoveDefaults(schema).parse({ string: 'moo' }); expect(result.string).toBe('moo'); }); + describe('should still enforce array length', () => { + it('min', () => { + const schema = z.number().array().min(1); + const result = deepRemoveDefaults(schema).safeParse([]); + expect(result.success).toBeFalsy(); + }); + it('max', () => { + const schema = z.number().array().max(1); + const result = deepRemoveDefaults(schema).safeParse([1, 2]); + expect(result.success).toBeFalsy(); + }); + it('exact', () => { + const schema = z.number().array().length(1); + const result = deepRemoveDefaults(schema).safeParse([]); + expect(result.success).toBeFalsy(); + }); + }); }); describe('getParseErrorKeys', () => { diff --git a/yarn.lock b/yarn.lock index f11c2b5c..4cbbfb1b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -800,6 +800,16 @@ __metadata: languageName: node linkType: hard +"@jridgewell/trace-mapping@npm:^0.3.23": + version: 0.3.25 + resolution: "@jridgewell/trace-mapping@npm:0.3.25" + dependencies: + "@jridgewell/resolve-uri": "npm:^3.1.0" + "@jridgewell/sourcemap-codec": "npm:^1.4.14" + checksum: 10c0/3d1ce6ebc69df9682a5a8896b414c6537e428a1d68b02fcc8363b04284a8ca0df04d0ee3013132252ab14f2527bc13bea6526a912ecb5658f0e39fd2860b4df4 + languageName: node + linkType: hard + "@lit-labs/scoped-registry-mixin@npm:^1.0.3": version: 1.0.3 resolution: "@lit-labs/scoped-registry-mixin@npm:1.0.3" @@ -1467,76 +1477,76 @@ __metadata: languageName: node linkType: hard -"@vitest/coverage-istanbul@npm:^1.3.1": - version: 1.3.1 - resolution: "@vitest/coverage-istanbul@npm:1.3.1" +"@vitest/coverage-istanbul@npm:^1.5.0": + version: 1.5.0 + resolution: "@vitest/coverage-istanbul@npm:1.5.0" dependencies: debug: "npm:^4.3.4" istanbul-lib-coverage: "npm:^3.2.2" istanbul-lib-instrument: "npm:^6.0.1" istanbul-lib-report: "npm:^3.0.1" - istanbul-lib-source-maps: "npm:^4.0.1" + istanbul-lib-source-maps: "npm:^5.0.4" istanbul-reports: "npm:^3.1.6" magicast: "npm:^0.3.3" picocolors: "npm:^1.0.0" test-exclude: "npm:^6.0.0" peerDependencies: - vitest: 1.3.1 - checksum: 10c0/40efacde51e5998bde8032dd45d64fe214674f1efb97c094c4ae9ef1893afc4e0ef97f3fa4cc4923561b67b1196c27a877a0fa5bc71a049b8e48e3ef1f5c48db + vitest: 1.5.0 + checksum: 10c0/12abbaf8925c797e1fafef05c8b7d554c9fc61d13eb70c3f8532ade72db305a3cb1fec9bb7642763de27471e3f3da3d684d6533aa954756c5edf2707d2fc25cd languageName: node linkType: hard -"@vitest/expect@npm:1.3.1": - version: 1.3.1 - resolution: "@vitest/expect@npm:1.3.1" +"@vitest/expect@npm:1.5.0": + version: 1.5.0 + resolution: "@vitest/expect@npm:1.5.0" dependencies: - "@vitest/spy": "npm:1.3.1" - "@vitest/utils": "npm:1.3.1" + "@vitest/spy": "npm:1.5.0" + "@vitest/utils": "npm:1.5.0" chai: "npm:^4.3.10" - checksum: 10c0/ea66a1e912d896a481a27631b68089b885af7e8ed62ba8aaa119c37a9beafe6c094fd672775a20e6e23460af66e294f9ca259e6e0562708d1b7724eaaf53c7bb + checksum: 10c0/12138caf0831a9bcdf475750fdff27588f03f11ee5101124f9d39951bbcdec39aa6a19a1a30f3ab0ca17374ddfc7399b861e2fcb1548bba302943e8e88512a9c languageName: node linkType: hard -"@vitest/runner@npm:1.3.1": - version: 1.3.1 - resolution: "@vitest/runner@npm:1.3.1" +"@vitest/runner@npm:1.5.0": + version: 1.5.0 + resolution: "@vitest/runner@npm:1.5.0" dependencies: - "@vitest/utils": "npm:1.3.1" + "@vitest/utils": "npm:1.5.0" p-limit: "npm:^5.0.0" pathe: "npm:^1.1.1" - checksum: 10c0/d732de2368d2bc32cbc27f0bbc5477f6e36088ddfb873c036935a45b1b252ebc529b932cf5cd944eed9b692243acebef828f6d3218583cb8a6817a8270712050 + checksum: 10c0/a7b693e4121b6159a77f6cbffc03c228cd18c3734e27a968fe26579777f6d7a4d55a02fba396d564df996a91881ee76de80ee5a526d27a4b508f44a9af62d95a languageName: node linkType: hard -"@vitest/snapshot@npm:1.3.1": - version: 1.3.1 - resolution: "@vitest/snapshot@npm:1.3.1" +"@vitest/snapshot@npm:1.5.0": + version: 1.5.0 + resolution: "@vitest/snapshot@npm:1.5.0" dependencies: magic-string: "npm:^0.30.5" pathe: "npm:^1.1.1" pretty-format: "npm:^29.7.0" - checksum: 10c0/cad0844270852c6d53c1ca6b7ca279034880d2140837ff245d5bd2376f4356cc924929c58dc69bcf9fad83ba934d4a06000c908971cc24b5d7a9ec2656b72d29 + checksum: 10c0/d897070b3a7c008eb58d44ca0dc324c69dfc1f787335e59fb930ae2e8d02a148e6b3c13497a588083a0654bdc430281fdd84276ead4888230314a2984dd9f93d languageName: node linkType: hard -"@vitest/spy@npm:1.3.1": - version: 1.3.1 - resolution: "@vitest/spy@npm:1.3.1" +"@vitest/spy@npm:1.5.0": + version: 1.5.0 + resolution: "@vitest/spy@npm:1.5.0" dependencies: tinyspy: "npm:^2.2.0" - checksum: 10c0/efc42f679d2a51fc6583ca3136ccd47581cb27c923ed3cb0500f5dee9aac99b681bfdd400c16ef108f2e0761daa642bc190816a6411931a2aba99ebf8b213dd4 + checksum: 10c0/0206f1e8431f543474dc6d252b553227d0f286b27226b987b63babb18865e8320e6c3d822c67782aae68555728a57ecdeb7c4e16283dbad49791608a691f26d1 languageName: node linkType: hard -"@vitest/utils@npm:1.3.1": - version: 1.3.1 - resolution: "@vitest/utils@npm:1.3.1" +"@vitest/utils@npm:1.5.0": + version: 1.5.0 + resolution: "@vitest/utils@npm:1.5.0" dependencies: diff-sequences: "npm:^29.6.3" estree-walker: "npm:^3.0.3" loupe: "npm:^2.3.7" pretty-format: "npm:^29.7.0" - checksum: 10c0/d604c8ad3b1aee30d4dcd889098f591407bfe18547ff96485b1d1ed54eff58219c756a9544a7fbd4e37886863abacd7a89a76334cb3ea7f84c3d496bb757db23 + checksum: 10c0/b9d779ea5c1a5759df4f59e3ba3f3a94816d6c600afe7a2d14b963ea114ce1acedbfe678cbfacb0a20d33cabcce890a08b2ce3fd52e3465f2e0969cc39f7686b languageName: node linkType: hard @@ -3855,7 +3865,7 @@ __metadata: "@types/masonry-layout": "npm:^4.2.5" "@typescript-eslint/eslint-plugin": "npm:^5.36.2" "@typescript-eslint/parser": "npm:^5.36.2" - "@vitest/coverage-istanbul": "npm:^1.3.1" + "@vitest/coverage-istanbul": "npm:^1.5.0" component-emitter: "npm:^1.3.0" crypto: "npm:^1.0.1" date-fns: "npm:^2.29.2" @@ -3895,7 +3905,7 @@ __metadata: vis-data: "npm:^7.1.9" vis-timeline: "npm:^7.7.3" vis-util: "npm:^5.0.2" - vitest: "npm:^1.3.1" + vitest: "npm:^1.5.0" vitest-mock-extended: "npm:^1.3.1" web-dialog: "npm:^0.0.11" xss: "npm:^1.0.14" @@ -4938,14 +4948,14 @@ __metadata: languageName: node linkType: hard -"istanbul-lib-source-maps@npm:^4.0.1": - version: 4.0.1 - resolution: "istanbul-lib-source-maps@npm:4.0.1" +"istanbul-lib-source-maps@npm:^5.0.4": + version: 5.0.4 + resolution: "istanbul-lib-source-maps@npm:5.0.4" dependencies: + "@jridgewell/trace-mapping": "npm:^0.3.23" debug: "npm:^4.1.1" istanbul-lib-coverage: "npm:^3.0.0" - source-map: "npm:^0.6.1" - checksum: 10c0/19e4cc405016f2c906dff271a76715b3e881fa9faeb3f09a86cb99b8512b3a5ed19cadfe0b54c17ca0e54c1142c9c6de9330d65506e35873994e06634eebeb66 + checksum: 10c0/48b48294590675005ba439888a53157fc71a99d78321428f3ce5f64e28cdfb6bc6eb45871333f448437118ef56a0ef371f4958163e2c2d066d3a703415a71b2e languageName: node linkType: hard @@ -8011,10 +8021,10 @@ __metadata: languageName: node linkType: hard -"tinypool@npm:^0.8.2": - version: 0.8.2 - resolution: "tinypool@npm:0.8.2" - checksum: 10c0/8998626614172fc37c394e9a14e701dc437727fc6525488a4d4fd42044a4b2b59d6f076d750cbf5c699f79c58dd4e40599ab09e2f1ae0df4b23516b98c9c3055 +"tinypool@npm:^0.8.3": + version: 0.8.3 + resolution: "tinypool@npm:0.8.3" + checksum: 10c0/c219d0cfb69de8e3cf17403034a508d773f2fccaad79a13cdbad68600c4fb10186ad814d2320bcaa8f6e774fff5666d2a3d3b241dc8a7ad9d970ee63fe620a32 languageName: node linkType: hard @@ -8487,9 +8497,9 @@ __metadata: languageName: node linkType: hard -"vite-node@npm:1.3.1": - version: 1.3.1 - resolution: "vite-node@npm:1.3.1" +"vite-node@npm:1.5.0": + version: 1.5.0 + resolution: "vite-node@npm:1.5.0" dependencies: cac: "npm:^6.7.14" debug: "npm:^4.3.4" @@ -8498,7 +8508,7 @@ __metadata: vite: "npm:^5.0.0" bin: vite-node: vite-node.mjs - checksum: 10c0/b50665ef224f3527f856ab88a0cfabab36dd6e2dd1e3edca8f8f25d5d33754e1050495472c2c82147d0dcf7c5280971dae2f37a531c10f3941d8d3344e34ce0b + checksum: 10c0/85f9e8616f3612c71193a2bbdfb00f610685108a65eaa7ac535655ca1bd65dda5436ee577465436f715966f34e4b25b54140bbd584fe2c95ea0726acf4ecd351 languageName: node linkType: hard @@ -8554,15 +8564,15 @@ __metadata: languageName: node linkType: hard -"vitest@npm:^1.3.1": - version: 1.3.1 - resolution: "vitest@npm:1.3.1" +"vitest@npm:^1.5.0": + version: 1.5.0 + resolution: "vitest@npm:1.5.0" dependencies: - "@vitest/expect": "npm:1.3.1" - "@vitest/runner": "npm:1.3.1" - "@vitest/snapshot": "npm:1.3.1" - "@vitest/spy": "npm:1.3.1" - "@vitest/utils": "npm:1.3.1" + "@vitest/expect": "npm:1.5.0" + "@vitest/runner": "npm:1.5.0" + "@vitest/snapshot": "npm:1.5.0" + "@vitest/spy": "npm:1.5.0" + "@vitest/utils": "npm:1.5.0" acorn-walk: "npm:^8.3.2" chai: "npm:^4.3.10" debug: "npm:^4.3.4" @@ -8574,15 +8584,15 @@ __metadata: std-env: "npm:^3.5.0" strip-literal: "npm:^2.0.0" tinybench: "npm:^2.5.1" - tinypool: "npm:^0.8.2" + tinypool: "npm:^0.8.3" vite: "npm:^5.0.0" - vite-node: "npm:1.3.1" + vite-node: "npm:1.5.0" why-is-node-running: "npm:^2.2.2" peerDependencies: "@edge-runtime/vm": "*" "@types/node": ^18.0.0 || >=20.0.0 - "@vitest/browser": 1.3.1 - "@vitest/ui": 1.3.1 + "@vitest/browser": 1.5.0 + "@vitest/ui": 1.5.0 happy-dom: "*" jsdom: "*" peerDependenciesMeta: @@ -8600,7 +8610,7 @@ __metadata: optional: true bin: vitest: vitest.mjs - checksum: 10c0/66d312a3dc12e67bba22d31332d939e89cd17d38531893c7b13b8826704564031c1dde795df2799b855660572c19a595301e920710c7775d072ee6332502efc5 + checksum: 10c0/87f6666cccd52678a0e1dbf32e7492e4003580a168114221e4c2d404d53097d886a8be4c5c379e347d0e749affa0ea5416e4e3a0356aeca228a77ee54891ca3c languageName: node linkType: hard From 842240021d7b6746bdc7a6e0318832c42348dfd7 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 14 Apr 2024 18:37:18 -0700 Subject: [PATCH 122/189] Fix media autoplay. --- .../auto-media-actions/auto-media-actions.ts | 18 +++++++++--------- .../auto-media-actions.test.ts | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts b/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts index e31b10db..9086cf62 100644 --- a/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts +++ b/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts @@ -50,7 +50,7 @@ export function AutoMediaActions( let options: OptionsType; let emblaApi: EmblaCarouselType; let slides: HTMLElement[]; - let hadInitialIntersectionCall: boolean | null = false; + let containerIntersecting: boolean | null = null; const microphoneMuteTimer = new Timer(); const intersectionObserver: IntersectionObserver = new IntersectionObserver( @@ -184,15 +184,15 @@ export function AutoMediaActions( } function intersectionHandler(entries: IntersectionObserverEntry[]): void { - if (!hadInitialIntersectionCall) { - hadInitialIntersectionCall = true; - return; - } + const wasIntersecting = containerIntersecting; + containerIntersecting = entries.some((entry) => entry.isIntersecting); - // If the live view is preloaded (i.e. in the background) we may need to - // take media actions, e.g. muting a live stream that is now running in the - // background. - actOnVisibilityChange(entries.some((entry) => entry.isIntersecting)); + if (wasIntersecting !== null && wasIntersecting !== containerIntersecting) { + // If the live view is preloaded (i.e. in the background) we may need to + // take media actions, e.g. muting a live stream that is now running in + // the background, so we act even if the new state is hidden. + actOnVisibilityChange(containerIntersecting); + } } function getPlayer(slide: HTMLElement | undefined): FrigateCardMediaPlayer | null { diff --git a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts index 4cbfea08..91cf31c8 100644 --- a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts +++ b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts @@ -315,7 +315,7 @@ describe('AutoMediaActions', () => { // Intersection observer always calls handler on creation (and we ignore // these first calls). - callIntersectionHandler(true); + callIntersectionHandler(false); callIntersectionHandler(true); expect(getPlayer(children[5], 'video')?.play).toBeCalled(); From b4ed40e6c75dfb08089a1f3df97a4a269f16f38f Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 14 Apr 2024 19:47:44 -0700 Subject: [PATCH 123/189] Fix controls and seeking bugs. --- src/components/surround.ts | 1 + src/utils/media.ts | 11 +++++++++++ tests/utils/media.test.ts | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+) diff --git a/src/components/surround.ts b/src/components/surround.ts index 4ff26aa8..45ee50f1 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -138,6 +138,7 @@ export class FrigateCardSurround extends LitElement { ...(media.getCameraID() && { camera: media.getCameraID() }), }) .removeContext('timeline') + .removeContext('mediaViewer') // Send the view change from the source of the tap event, so // the view change will be caught by the handler above (to // close the drawer). diff --git a/src/utils/media.ts b/src/utils/media.ts index 6bf63a93..f63f07a9 100644 --- a/src/utils/media.ts +++ b/src/utils/media.ts @@ -44,6 +44,17 @@ export const hideMediaControlsTemporarily = ( setControlsOnVideo(video, false); video._controlsHideTimer ??= new Timer(); video._controlsOriginalValue = oldValue; + + // LitElement may change the src attribute of the video element during + // rendering, so we need to ensure that the controls are reset on the 'old' + // video. See: + // https://github.com/dermotduffy/frigate-hass-card/issues/1310 + const resetIfReloaded = () => { + setControlsOnVideo(video, oldValue); + video.removeEventListener('loadstart', resetIfReloaded); + }; + video.addEventListener('loadstart', resetIfReloaded); + video._controlsHideTimer.start(seconds, () => { setControlsOnVideo(video, oldValue); }); diff --git a/tests/utils/media.test.ts b/tests/utils/media.test.ts index 01859e85..adbdd322 100644 --- a/tests/utils/media.test.ts +++ b/tests/utils/media.test.ts @@ -51,6 +51,24 @@ describe('hideMediaControlsTemporarily', () => { expect(video.controls).toBeTruthy(); expect(video._controlsHideTimer).toBeFalsy(); }); + + it('should add event listener that resets controls', () => { + const video: FrigateCardHTMLVideoElement = document.createElement('video'); + video.controls = true; + + hideMediaControlsTemporarily(video); + expect(video.controls).toBeFalsy(); + + // After a new media starts to load, the controls should reset. + video.dispatchEvent(new Event('loadstart')); + expect(video.controls).toBeTruthy(); + + // ... but only once, future loadstart events without subsequent calls to + // hideMediaControlsTemporarily() should do nothing. + video.controls = false; + video.dispatchEvent(new Event('loadstart')); + expect(video._controlsHideTimer).toBeFalsy(); + }); }); class NotAllowedError extends Error { From c7c85d188db04026bae6f49b81850a5f80661329 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 15 Apr 2024 16:10:09 -0700 Subject: [PATCH 124/189] Add support for precise layout cropping options. --- docs/configuration/cameras/README.md | 31 +++++- docs/configuration/dimensions.md | 12 ++- docs/images/media_layout/fit.png | Bin 0 -> 38041 bytes .../position-shorter-than-height.png | Bin 0 -> 49273 bytes .../position-thinner-than-width.png | Bin 0 -> 49881 bytes docs/images/media_layout/view-box.png | Bin 0 -> 34967 bytes package.json | 2 + scripts/update-images.sh | 16 +++ src/camera-manager/manager.ts | 14 ++- src/config/types.ts | 8 ++ src/const.ts | 8 ++ src/editor.ts | 93 +++++++++++++++--- src/localize/languages/ca.json | 8 ++ src/localize/languages/en.json | 10 +- src/localize/languages/fr.json | 8 ++ src/localize/languages/it.json | 8 ++ src/localize/languages/pt-BR.json | 8 ++ src/localize/languages/pt-PT.json | 8 ++ src/scss/media-layout.scss | 9 ++ src/utils/media-layout.ts | 10 ++ yarn.lock | 25 +++++ 21 files changed, 251 insertions(+), 27 deletions(-) create mode 100644 docs/images/media_layout/fit.png create mode 100644 docs/images/media_layout/position-shorter-than-height.png create mode 100644 docs/images/media_layout/position-thinner-than-width.png create mode 100644 docs/images/media_layout/view-box.png create mode 100755 scripts/update-images.sh diff --git a/docs/configuration/cameras/README.md b/docs/configuration/cameras/README.md index 1036071b..6aeef734 100644 --- a/docs/configuration/cameras/README.md +++ b/docs/configuration/cameras/README.md @@ -114,7 +114,8 @@ cameras: ## `dimensions` -The `dimensions` block configures the dimensions and layout of media of a given camera. +The `dimensions` block configures the dimensions and layout of media of a given camera (see [Card Dimensions](../dimensions.md) to set the dimensions of the whole card and not just a single camera). + ```yaml cameras: @@ -130,8 +131,7 @@ cameras: ### Layout Configuration -The `layout` block configures the fit and position of the media _within_ the camera dimensions (in order to control the dimensions for the whole card see [the card dimensions configuration](../dimensions.md) ). As the default behavior is to always expand to fit the media precisely, these options only make sense if the camera `dimensions.aspect_ratio` is set to a static value that forces a particular aspect ratio that does not match the camera media. - +The `layout` block configures the fit and position of the media _within_ the camera dimensions (in order to control the dimensions for the whole card see [the card dimensions configuration](../dimensions.md) ). ```yaml cameras: @@ -143,11 +143,32 @@ cameras: | Option | Default | Description | | - | - | - | -| `fit` | `contain` | If `contain`, the media is contained within the card and letterboxed if necessary. If `cover`, the media is expanded proportionally (i.e. maintaining the media aspect ratio) until the card is fully covered. If `fill`, the media is stretched to fill the card (i.e. ignoring the media aspect ratio). See [CSS object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) for technical details and a visualization. | -| `position` | | A dictionary that contains an `x` and `y` percentage (`0` - `100`) to control the position of the media when the fit is `cover`. This can be effectively used to "pan" the media around. At any given time, only one of `x` and `y` will have an effect, depending on whether media width is larger than the card width (in which case `x` controls the position) or the media height is larger than the card height (in which case `y` controls the position). A value of `0` means maximally to the left or top of the media, a value of `100` means maximally to the right or bottom of the media. See [CSS object-position](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) for technical details and a visualization. | +| `fit` | `contain` | If `contain`, the media is contained within the card and letterboxed if necessary. If `cover`, the media is expanded proportionally (i.e. maintaining the media aspect ratio) until the camera/card dimensions are fully covered. If `fill`, the media is stretched to fill the camera/card dimensions (i.e. ignoring the media aspect ratio). See [CSS object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) for technical details and a visualization. | +| `position` | | A dictionary that may contain an `x` and `y` percentage (`0` - `100`) to control the position of the media when the fit is `cover` (for other values of `fit` this option has no effect). This can be effectively used to "pan"/cut the media shown. At any given time, only one of `x` and `y` will have an effect, depending on whether media width is larger than the camera/card dimensions (in which case `x` controls the position) or the media height is larger than the camera/card dimensions (in which case `y` controls the position). A value of `0` means maximally to the left or top of the media, a value of `100` means maximally to the right or bottom of the media. See [CSS object-position](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) for technicals. See visualizations below. | +| `view_box` | | A dictionary that may contain a `top`, `bottom`, `left` and `right` percentage (`0` - `100`) to precisely crop what part of the media to show by specifying a % inset value from each side. Browsers apply this cropping after `position` and `fit` have been applied. See visualizations below. | + +!> The `view_box` parameter only has effect on browsers that support [`object-view-box`](https://caniuse.com/mdn-css_properties_object-view-box). As of writing this is exclusively Chromium based browsers (e.g. Google Chrome or Microsoft Edge). See [media layout examples](../../examples.md?id=media-layout). +#### Layout **Visualizations** + +##### `fit` + +![](../../images/media_layout/fit.png "Media Layout Fit :size=400") + +##### `position`: When media is shorter than dimensions height + +![](../../images/media_layout/position-shorter-than-height.png "Media Layout Position: Wider than taller :size=400") + +##### `position`: When media is thinner than dimensions width + +![](../../images/media_layout/position-thinner-than-width.png "Media Layout Position: Taller than wider :size=400") + +#### `view_box`: Precise media cropping + +![](../../images/media_layout/view-box.png "Media Layout Position: Taller than wider :size=400") + ## `triggers` The `triggers` block configures what triggers a camera. Triggering can be used diff --git a/docs/configuration/dimensions.md b/docs/configuration/dimensions.md index 2e60fdd8..45338087 100644 --- a/docs/configuration/dimensions.md +++ b/docs/configuration/dimensions.md @@ -1,10 +1,12 @@ # `dimensions` -These options control the dimensions and aspect-ratio of the card. These options -configuration applies once to the entire card (including the menu, thumbnails, -etc), not just to displayed media. This only applies to the card in normal -render mode -- when in fullscreen, or when in expanded (popup/dialog mode) the -aspect ratio is chosen dynamically to maximize the amount of content shown. +These options control the dimensions and aspect-ratio of the card (See [Camera +Dimensions](./cameras/README.md?id=dimensions) to set the dimensions of a camera +and not the whole card). These options configuration applies once to the entire +card (including the menu, thumbnails, etc), not just to displayed media. This +only applies to the card in normal render mode -- when in fullscreen, or when in +expanded (popup/dialog mode) the aspect ratio is chosen dynamically to maximize +the amount of content shown. ```yaml dimensions: diff --git a/docs/images/media_layout/fit.png b/docs/images/media_layout/fit.png new file mode 100644 index 0000000000000000000000000000000000000000..b47fe96a89bdd29decf998e661ca88fd608aad5b GIT binary patch literal 38041 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 NedUKr#R|_t{tu0n!qxx) literal 0 HcmV?d00001 diff --git a/docs/images/media_layout/position-shorter-than-height.png b/docs/images/media_layout/position-shorter-than-height.png new file mode 100644 index 0000000000000000000000000000000000000000..e4804d12aa88d5c5a021f0455d55aa939d0394f6 GIT binary patch literal 49273 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 W>Qnkjcm@UdQNM9V6|MZ#=f3~~ZtcJT literal 0 HcmV?d00001 diff --git a/docs/images/media_layout/position-thinner-than-width.png b/docs/images/media_layout/position-thinner-than-width.png new file mode 100644 index 0000000000000000000000000000000000000000..2f171db295ca570a93d7aba487a77301687faa20 GIT binary patch literal 49881 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 literal 0 HcmV?d00001 diff --git a/docs/images/media_layout/view-box.png b/docs/images/media_layout/view-box.png new file mode 100644 index 0000000000000000000000000000000000000000..9a91d96a26e9192998b31667cf9c6001096108b4 GIT binary patch literal 34967 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 { + await this.reset(); await this._initializeCameras(cameras); + }; + + try { + // This concurrency limit prevents multiple rapidly arriving configs from + // generating reset-n-initialize race conditions (e.g. changing values + // rapidly in the config editor). + await this._initializationLimit.add(resetAndInitialize); } catch (e: unknown) { this._api.getMessageManager().setErrorIfHigherPriority(e); return false; diff --git a/src/config/types.ts b/src/config/types.ts index 7692d2ec..9c08c061 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -618,6 +618,14 @@ const mediaLayoutConfigSchema = z.object({ y: z.number().min(0).max(100).optional(), }) .optional(), + view_box: z + .object({ + bottom: z.number().min(0).max(100).optional().default(0), + left: z.number().min(0).max(100).optional().default(0), + right: z.number().min(0).max(100).optional().default(0), + top: z.number().min(0).max(100).optional().default(0), + }) + .optional(), }); export type MediaLayoutConfig = z.infer; diff --git a/src/const.ts b/src/const.ts index 6a497438..d39d45aa 100644 --- a/src/const.ts +++ b/src/const.ts @@ -61,6 +61,14 @@ export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_X = `${CONF_CAMERAS}.#.dimensions.layout.position.x` as const; export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_Y = `${CONF_CAMERAS}.#.dimensions.layout.position.y` as const; +export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_TOP = + `${CONF_CAMERAS}.#.dimensions.layout.view_box.top` as const; +export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_BOTTOM = + `${CONF_CAMERAS}.#.dimensions.layout.view_box.bottom` as const; +export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_LEFT = + `${CONF_CAMERAS}.#.dimensions.layout.view_box.left` as const; +export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_RIGHT = + `${CONF_CAMERAS}.#.dimensions.layout.view_box.right` as const; export const CONF_CAMERAS_ARRAY_TRIGGERS_MOTION = `${CONF_CAMERAS}.#.triggers.motion` as const; export const CONF_CAMERAS_ARRAY_TRIGGERS_OCCUPANCY = diff --git a/src/editor.ts b/src/editor.ts index 9502d69f..0b9adc74 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -46,6 +46,10 @@ import { CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_FIT, CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_X, CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_Y, + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_BOTTOM, + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_LEFT, + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_RIGHT, + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_TOP, CONF_CAMERAS_ARRAY_FRIGATE_CAMERA_NAME, CONF_CAMERAS_ARRAY_FRIGATE_CLIENT_ID, CONF_CAMERAS_ARRAY_FRIGATE_LABELS, @@ -1226,6 +1230,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor configPathFit: string, configPathPositionX: string, configPathPositionY: string, + configPathPositionTop: string, + configPathPositionBottom: string, + configPathPositionLeft: string, + configPathPositionRight: string, ): TemplateResult | void { return this._putInSubmenu( domain, @@ -1236,16 +1244,50 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderOptionSelector(configPathFit, this._layoutFits, { label: localize('config.cameras.dimensions.layout.fit'), })} - ${this._renderNumberInput(configPathPositionX, { - min: 0, - max: 100, - label: localize('config.cameras.dimensions.layout.position.x'), - })} - ${this._renderNumberInput(configPathPositionY, { - min: 0, - max: 100, - label: localize('config.cameras.dimensions.layout.position.y'), - })} + ${this._putInSubmenu( + `${domain}.position`, + true, + 'config.cameras.dimensions.layout.position.editor_label', + { name: 'mdi:aspect-ratio' }, + html` ${this._renderNumberInput(configPathPositionX, { + min: 0, + max: 100, + label: localize('config.cameras.dimensions.layout.position.x'), + })} + ${this._renderNumberInput(configPathPositionY, { + min: 0, + max: 100, + label: localize('config.cameras.dimensions.layout.position.y'), + })}`, + )} + ${this._putInSubmenu( + `${domain}.view_box`, + true, + 'config.cameras.dimensions.layout.view_box.editor_label', + { name: 'mdi:crop' }, + html` + ${this._renderNumberInput(configPathPositionTop, { + min: 0, + max: 100, + label: localize('config.cameras.dimensions.layout.view_box.top'), + })} + ${this._renderNumberInput(configPathPositionBottom, { + min: 0, + max: 100, + label: localize('config.cameras.dimensions.layout.view_box.bottom'), + })} + ${this._renderNumberInput(configPathPositionLeft, { + min: 0, + max: 100, + label: localize('config.cameras.dimensions.layout.view_box.left'), + })} + ${this._renderNumberInput(configPathPositionRight, { + min: 0, + max: 100, + label: localize('config.cameras.dimensions.layout.view_box.right'), + })} + `, + )} `, ); } @@ -1971,9 +2013,34 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderMediaLayout( MENU_CAMERAS_DIMENSIONS_LAYOUT, 'config.cameras.dimensions.layout.editor_label', - CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_FIT, - CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_X, - CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_Y, + getArrayConfigPath( + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_FIT, + cameraIndex, + ), + getArrayConfigPath( + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_X, + cameraIndex, + ), + getArrayConfigPath( + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_Y, + cameraIndex, + ), + getArrayConfigPath( + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_TOP, + cameraIndex, + ), + getArrayConfigPath( + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_BOTTOM, + cameraIndex, + ), + getArrayConfigPath( + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_LEFT, + cameraIndex, + ), + getArrayConfigPath( + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_RIGHT, + cameraIndex, + ), )} `, )} diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json index a822bf33..7890348b 100644 --- a/src/localize/languages/ca.json +++ b/src/localize/languages/ca.json @@ -56,8 +56,16 @@ "fill": "El suport s'estira per omplir la targeta" }, "position": { + "editor_label": "", "x": "Percentatge d'emplaçament horitzontal", "y": "Percentatge d'emplaçament vertical" + }, + "view_box": { + "bottom": "", + "editor_label": "", + "left": "", + "right": "", + "top": "" } } }, diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index f0c5df92..61b48940 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -56,8 +56,16 @@ "fill": "Media is stretched to fill the card" }, "position": { + "editor_label": "Layout Cover Position", "x": "Horizontal placement percentage", "y": "Vertical placement percentage" + }, + "view_box": { + "bottom": "Bottom inset percentage", + "editor_label": "Layout View Box", + "left": "Left inset percentage", + "right": "Right inset percentage", + "top": "Top inset percentage" } } }, @@ -616,4 +624,4 @@ "timeline": { "select_date": "Choose date" } -} +} \ No newline at end of file diff --git a/src/localize/languages/fr.json b/src/localize/languages/fr.json index fdc1107b..806ed481 100644 --- a/src/localize/languages/fr.json +++ b/src/localize/languages/fr.json @@ -56,8 +56,16 @@ "fill": "Il supporto viene allungato per riempire la scheda" }, "position": { + "editor_label": "", "x": "Percentuale di posizionamento orizzontale", "y": "Percentuale di posizionamento verticale" + }, + "view_box": { + "bottom": "", + "editor_label": "", + "left": "", + "right": "", + "top": "" } } }, diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index e515dc57..b55a68e3 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -56,8 +56,16 @@ "fill": "Il supporto viene allungato per riempire la scheda" }, "position": { + "editor_label": "", "x": "Percentuale di posizionamento orizzontale", "y": "Percentuale di posizionamento verticale" + }, + "view_box": { + "bottom": "", + "editor_label": "", + "left": "", + "right": "", + "top": "" } } }, diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index ad8fe495..fb1fb510 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -56,8 +56,16 @@ "fill": "A mídia é esticada para preencher o cartão" }, "position": { + "editor_label": "", "x": "Porcentagem do posicionamento horizontal", "y": "Porcentagem do posicionamento vertical" + }, + "view_box": { + "bottom": "", + "editor_label": "", + "left": "", + "right": "", + "top": "" } } }, diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index fb8f531c..2bee1366 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -56,8 +56,16 @@ "fill": "Preencher" }, "position": { + "editor_label": "", "x": "Percentagem da localização horizontal", "y": "Percentagem da localização vertical" + }, + "view_box": { + "bottom": "", + "editor_label": "", + "left": "", + "right": "", + "top": "" } } }, diff --git a/src/scss/media-layout.scss b/src/scss/media-layout.scss index cde335ec..ec93509a 100644 --- a/src/scss/media-layout.scss +++ b/src/scss/media-layout.scss @@ -2,4 +2,13 @@ object-fit: var(--frigate-card-media-layout-fit, contain); object-position: var(--frigate-card-media-layout-position-x, 50%) var(--frigate-card-media-layout-position-y, 50%); + + // This is supported on limited browsers: + // See: https://caniuse.com/?search=object-view-box + object-view-box: inset( + var(--frigate-card-media-layout-view-box-top, 0%) + var(--frigate-card-media-layout-view-box-right, 0%) + var(--frigate-card-media-layout-view-box-bottom, 0%) + var(--frigate-card-media-layout-view-box-left, 0%) + ); } diff --git a/src/utils/media-layout.ts b/src/utils/media-layout.ts index 017c1efe..356a8dd0 100644 --- a/src/utils/media-layout.ts +++ b/src/utils/media-layout.ts @@ -24,4 +24,14 @@ export const updateElementStyleFromMediaLayoutConfig = ( element.style.removeProperty(`--frigate-card-media-layout-position-${dimension}`); } } + for (const dimension of ['top', 'bottom', 'left', 'right']) { + if (mediaLayoutConfig?.view_box?.[dimension] !== undefined) { + element.style.setProperty( + `--frigate-card-media-layout-view-box-${dimension}`, + `${mediaLayoutConfig.view_box[dimension]}%`, + ); + } else { + element.style.removeProperty(`--frigate-card-media-layout-view-box-${dimension}`); + } + } }; diff --git a/yarn.lock b/yarn.lock index 4cbbfb1b..d7d556b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3622,6 +3622,13 @@ __metadata: languageName: node linkType: hard +"eventemitter3@npm:^5.0.1": + version: 5.0.1 + resolution: "eventemitter3@npm:5.0.1" + checksum: 10c0/4ba5c00c506e6c786b4d6262cfbce90ddc14c10d4667e5c83ae993c9de88aa856033994dd2b35b83e8dc1170e224e66a319fa80adc4c32adcd2379bbc75da814 + languageName: node + linkType: hard + "execa@npm:^8.0.1": version: 8.0.1 resolution: "execa@npm:8.0.1" @@ -3886,6 +3893,7 @@ __metadata: markdown-link-check: "npm:^3.12.1" masonry-layout: "npm:^4.2.2" moment: "npm:^2.29.4" + p-queue: "npm:^8.0.1" prettier: "npm:^2.6.0" propagating-hammerjs: "npm:^2.0.1" quick-lru: "npm:^6.1.0" @@ -6234,6 +6242,16 @@ __metadata: languageName: node linkType: hard +"p-queue@npm:^8.0.1": + version: 8.0.1 + resolution: "p-queue@npm:8.0.1" + dependencies: + eventemitter3: "npm:^5.0.1" + p-timeout: "npm:^6.1.2" + checksum: 10c0/fe185bc8bbd32d17a5f6dba090077b1bb326b008b4ec9b0646c57a32a6984035aa8ece909a6d0de7f6c4640296dc288197f430e7394cdc76a26d862339494616 + languageName: node + linkType: hard + "p-timeout@npm:^3.1.0, p-timeout@npm:^3.2.0": version: 3.2.0 resolution: "p-timeout@npm:3.2.0" @@ -6243,6 +6261,13 @@ __metadata: languageName: node linkType: hard +"p-timeout@npm:^6.1.2": + version: 6.1.2 + resolution: "p-timeout@npm:6.1.2" + checksum: 10c0/d46b90a9a5fb7c650a5c56dd5cf7102ea9ab6ce998defa2b3d4672789aaec4e2f45b3b0b5a4a3e17a0fb94301ad5dd26da7d8728402e48db2022ad1847594d19 + languageName: node + linkType: hard + "p-try@npm:^2.0.0": version: 2.2.0 resolution: "p-try@npm:2.2.0" From 5f4943e19008e0962257b88ddb768a2dd0b2fbe5 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 15 Apr 2024 16:26:47 -0700 Subject: [PATCH 125/189] Add tests. --- src/utils/media-layout.ts | 2 +- tests/utils/media-layout.test.ts | 116 +++++++++++++++++++++++++++++++ vite.config.ts | 1 + 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 tests/utils/media-layout.test.ts diff --git a/src/utils/media-layout.ts b/src/utils/media-layout.ts index 356a8dd0..6128e10c 100644 --- a/src/utils/media-layout.ts +++ b/src/utils/media-layout.ts @@ -8,7 +8,7 @@ import { MediaLayoutConfig } from '../config/types'; export const updateElementStyleFromMediaLayoutConfig = ( element: HTMLElement, mediaLayoutConfig?: MediaLayoutConfig, -) => { +): void => { if (mediaLayoutConfig?.fit !== undefined) { element.style.setProperty('--frigate-card-media-layout-fit', mediaLayoutConfig.fit); } else { diff --git a/tests/utils/media-layout.test.ts b/tests/utils/media-layout.test.ts new file mode 100644 index 00000000..85054fc9 --- /dev/null +++ b/tests/utils/media-layout.test.ts @@ -0,0 +1,116 @@ +import { describe, expect, it } from 'vitest'; +import { updateElementStyleFromMediaLayoutConfig } from '../../src/utils/media-layout.js'; + +// @vitest-environment jsdom +describe('updateElementStyleFromMediaLayoutConfig', () => { + describe('fit', () => { + it('set', () => { + const video = document.createElement('video'); + + updateElementStyleFromMediaLayoutConfig(video, { + fit: 'cover', + }); + + expect(video.style.getPropertyValue('--frigate-card-media-layout-fit')).toBe( + 'cover', + ); + }); + + it('unset', () => { + const video = document.createElement('video'); + video.style.setProperty('--frigate-card-media-layout-fit', 'cover'); + + updateElementStyleFromMediaLayoutConfig(video); + + expect( + video.style.getPropertyValue('--frigate-card-media-layout-fit'), + ).toBeFalsy(); + }); + }); + + describe('position', () => { + it('set', () => { + const video = document.createElement('video'); + + updateElementStyleFromMediaLayoutConfig(video, { + position: { + x: 10, + y: 20, + }, + }); + + expect( + video.style.getPropertyValue('--frigate-card-media-layout-position-x'), + ).toBe('10%'); + expect( + video.style.getPropertyValue('--frigate-card-media-layout-position-y'), + ).toBe('20%'); + }); + + it('unset', () => { + const video = document.createElement('video'); + video.style.setProperty('--frigate-card-media-layout-position-x', '10%'); + video.style.setProperty('--frigate-card-media-layout-position-y', '20%'); + + updateElementStyleFromMediaLayoutConfig(video); + + expect( + video.style.getPropertyValue('--frigate-card-media-layout-position-x'), + ).toBeFalsy(); + expect( + video.style.getPropertyValue('--frigate-card-media-layout-position-y'), + ).toBeFalsy(); + }); + }); + + describe('view_box', () => { + it('set', () => { + const video = document.createElement('video'); + + updateElementStyleFromMediaLayoutConfig(video, { + view_box: { + top: 1, + bottom: 2, + left: 3, + right: 4, + }, + }); + + expect( + video.style.getPropertyValue('--frigate-card-media-layout-view-box-top'), + ).toBe('1%'); + expect( + video.style.getPropertyValue('--frigate-card-media-layout-view-box-bottom'), + ).toBe('2%'); + expect( + video.style.getPropertyValue('--frigate-card-media-layout-view-box-left'), + ).toBe('3%'); + expect( + video.style.getPropertyValue('--frigate-card-media-layout-view-box-right'), + ).toBe('4%'); + }); + + it('unset', () => { + const video = document.createElement('video'); + video.style.setProperty('--frigate-card-media-layout-view-box-top', '1%'); + video.style.setProperty('--frigate-card-media-layout-view-box-bottom', '2%'); + video.style.setProperty('--frigate-card-media-layout-view-box-left', '3%'); + video.style.setProperty('--frigate-card-media-layout-view-box-right', '4%'); + + updateElementStyleFromMediaLayoutConfig(video); + + expect( + video.style.getPropertyValue('--frigate-card-media-layout-view-box-top'), + ).toBeFalsy(); + expect( + video.style.getPropertyValue('--frigate-card-media-layout-view-box-bottom'), + ).toBeFalsy(); + expect( + video.style.getPropertyValue('--frigate-card-media-layout-view-box-left'), + ).toBeFalsy(); + expect( + video.style.getPropertyValue('--frigate-card-media-layout-view-box-right'), + ).toBeFalsy(); + }); + }); +}); diff --git a/vite.config.ts b/vite.config.ts index 4479c43b..6794fe02 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -34,6 +34,7 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'utils/ha/entity-registry/types.ts', 'utils/ha/types.ts', 'utils/media-info.ts', + 'utils/media-layout.ts', 'utils/media-to-view.ts', 'utils/media.ts', 'utils/ptz.ts', From c630b9f2211efed7ff261ce3baebf8aab08c20ce Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 15 Apr 2024 16:46:03 -0700 Subject: [PATCH 126/189] Fix menu hide bug causing menu background to stay even when hidden. --- src/components-lib/menu-controller.ts | 4 ++-- tests/components-lib/menu-controller.test.ts | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/components-lib/menu-controller.ts b/src/components-lib/menu-controller.ts index 0410a340..9f773a56 100644 --- a/src/components-lib/menu-controller.ts +++ b/src/components-lib/menu-controller.ts @@ -14,7 +14,7 @@ import { frigateCardHandleActionConfig, getActionConfigGivenAction, } from '../utils/action'; -import { arrayify, isTruthy } from '../utils/basic.js'; +import { arrayify, isTruthy, setOrRemoveAttribute } from '../utils/basic.js'; import { refreshDynamicStateParameters } from '../utils/ha/index.js'; export class MenuController { @@ -86,7 +86,7 @@ export class MenuController { public setExpanded(expanded: boolean): void { this._expanded = expanded; - this._host.setAttribute('expanded', ''); + setOrRemoveAttribute(this._host, expanded, 'expanded'); this._host.requestUpdate(); } diff --git a/tests/components-lib/menu-controller.test.ts b/tests/components-lib/menu-controller.test.ts index 596d9312..1467ea47 100644 --- a/tests/components-lib/menu-controller.test.ts +++ b/tests/components-lib/menu-controller.test.ts @@ -67,6 +67,22 @@ describe('MenuController', () => { expect(host.getAttribute('data-alignment')).toBe('top'); }); + it('should expand', () => { + const host = createLitElement(); + const controller = new MenuController(host); + + expect(controller.isExpanded()).toBeFalsy(); + expect(host.getAttribute('expanded')).toBeNull(); + + controller.setExpanded(true); + expect(controller.isExpanded()).toBeTruthy(); + expect(host.getAttribute('expanded')).toBe(''); + + controller.setExpanded(false); + expect(controller.isExpanded()).toBeFalsy(); + expect(host.getAttribute('expanded')).toBeNull(); + }); + describe('should set and sort buttons', () => { it('by priority', () => { const controller = new MenuController(createLitElement()); From f96a1229be1accd7b2e23beb4dcdb27dbecf62a4 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 24 Apr 2024 22:00:23 -0700 Subject: [PATCH 127/189] Create CNAME --- docs/CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/CNAME diff --git a/docs/CNAME b/docs/CNAME new file mode 100644 index 00000000..79327ec1 --- /dev/null +++ b/docs/CNAME @@ -0,0 +1 @@ +card.camera \ No newline at end of file From 7917e5c53728cd9510276d7626da63a9e80461ce Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 27 Apr 2024 14:55:38 -0700 Subject: [PATCH 128/189] Add support for pre-defined zoom/pan settings. --- docs/README.md | 2 + docs/_coverpage.md | 4 +- docs/configuration/actions.md | 24 +- docs/configuration/cameras/README.md | 18 +- docs/configuration/conditions.md | 5 + docs/configuration/menu.md | 9 +- docs/examples.md | 60 ++ docs/images/browsers/chrome_16x16.png | Bin 0 -> 819 bytes docs/images/browsers/chromium_16x16.png | Bin 0 -> 680 bytes docs/images/browsers/edge_16x16.png | Bin 0 -> 811 bytes docs/images/media_layout/fit.png | Bin 38041 -> 67839 bytes docs/images/media_layout/pan-zoom.png | Bin 0 -> 40162 bytes .../position-shorter-than-height.png | Bin 49273 -> 76391 bytes .../position-thinner-than-width.png | Bin 49881 -> 79860 bytes docs/images/media_layout/view-box.png | Bin 34967 -> 63271 bytes scripts/update-images.sh | 6 +- src/camera-manager/manager.ts | 10 +- src/card-controller/actions-manager.ts | 17 +- src/card-controller/card-element-manager.ts | 12 +- src/card-controller/initialization-manager.ts | 30 +- src/card-controller/view-manager.ts | 2 +- src/card.ts | 4 +- src/components-lib/menu-button-controller.ts | 29 +- src/components-lib/zoom-controller.ts | 160 ----- src/components-lib/zoom/types.ts | 11 + src/components-lib/zoom/zoom-controller.ts | 419 +++++++++++ src/components-lib/zoom/zoom-view-context.ts | 57 ++ src/components/image.ts | 22 +- src/components/live/live-image.ts | 14 +- src/components/live/live.ts | 33 +- src/components/viewer.ts | 22 +- src/components/zoomer.ts | 38 +- src/config/types.ts | 90 ++- src/const.ts | 6 + src/editor.ts | 64 +- src/localize/languages/ca.json | 8 +- src/localize/languages/en.json | 8 +- src/localize/languages/fr.json | 8 +- src/localize/languages/it.json | 8 +- src/localize/languages/pt-BR.json | 8 +- src/localize/languages/pt-PT.json | 8 +- src/scss/live-image.scss | 13 - src/scss/live-provider.scss | 8 + src/utils/action.ts | 21 + src/utils/basic.ts | 32 +- src/view/view.ts | 4 +- tests/camera-manager/manager.test.ts | 13 +- tests/card-controller/actions-manager.test.ts | 60 +- .../card-element-manager.test.ts | 3 +- .../initialization-manager.test.ts | 18 +- tests/card-controller/view-manager.test.ts | 4 +- .../menu-button-controller.test.ts | 71 +- tests/components-lib/zoom-controller.test.ts | 321 --------- .../zoom/zoom-controller.test.ts | 658 ++++++++++++++++++ .../zoom/zoom-view-context.test.ts | 85 +++ tests/config/types.test.ts | 4 + tests/utils/action.test.ts | 33 + tests/utils/basic.test.ts | 53 ++ vite.config.ts | 2 +- 59 files changed, 1981 insertions(+), 638 deletions(-) create mode 100644 docs/images/browsers/chrome_16x16.png create mode 100644 docs/images/browsers/chromium_16x16.png create mode 100644 docs/images/browsers/edge_16x16.png create mode 100644 docs/images/media_layout/pan-zoom.png delete mode 100644 src/components-lib/zoom-controller.ts create mode 100644 src/components-lib/zoom/types.ts create mode 100644 src/components-lib/zoom/zoom-controller.ts create mode 100644 src/components-lib/zoom/zoom-view-context.ts delete mode 100644 src/scss/live-image.scss delete mode 100644 tests/components-lib/zoom-controller.test.ts create mode 100644 tests/components-lib/zoom/zoom-controller.test.ts create mode 100644 tests/components-lib/zoom/zoom-view-context.test.ts diff --git a/docs/README.md b/docs/README.md index 7db2c4de..a6dc8d47 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,3 +1,5 @@ +!> This documentation is for the unreleased `dev` branch! See the [Github README](https://github.com/dermotduffy/frigate-hass-card?tab=readme-ov-file#frigate-lovelace-card) for documentation of the released version. + # Getting Started ## Installation diff --git a/docs/_coverpage.md b/docs/_coverpage.md index 777ac33d..ec27a485 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -1,8 +1,8 @@ ![logo](images/frigate-logo.svg) -# Frigate Card 6.0.0 *DEV* +# Frigate Card 6.0.0 _*DEV*_ > A comprehensive camera card for Home Assistant. [GitHub](https://github.com/dermotduffy/frigate-hass-card/) -[Documentation](README.md) \ No newline at end of file +[Documentation](README.md) diff --git a/docs/configuration/actions.md b/docs/configuration/actions.md index 2d0af42d..5b9af685 100644 --- a/docs/configuration/actions.md +++ b/docs/configuration/actions.md @@ -118,15 +118,24 @@ frigate_card_action: camera_ui Open the UI for the selected camera engine (e.g. the Frigate UI). -### `default` +### `change_zoom` -Change to the default view. +Zoom in and/or pan for a given camera. ```yaml action: custom:frigate-card-action -frigate_card_action: default +frigate_card_action: change_zoom +[...] ``` +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `change_zoom`. | +| `target_id` | The [camera ID](cameras/README.md?id=cameras) to adjust the pan/zoom of, or a media ID (e.g. `frigate` event ID) to zoom in on specific media items. | +| `zoom` | How much to zoom-in. See the [camera zoom parameter](cameras/README.md?id=layout-configuration). | +| `pan` | How much to pan-x/y. See the [camera pan parameter](cameras/README.md?id=layout-configuration). | + ### `clip`, `clips`, `image`, `live`, `recording`, `recordings`, `snapshot`, `snapshots` Change to the specified view. @@ -136,6 +145,15 @@ action: custom:frigate-card-action frigate_card_action: [view] ``` +### `default` + +Change to the default view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: default +``` + ### `download` Download the displayed media. diff --git a/docs/configuration/cameras/README.md b/docs/configuration/cameras/README.md index 6aeef734..31124162 100644 --- a/docs/configuration/cameras/README.md +++ b/docs/configuration/cameras/README.md @@ -144,10 +144,12 @@ cameras: | Option | Default | Description | | - | - | - | | `fit` | `contain` | If `contain`, the media is contained within the card and letterboxed if necessary. If `cover`, the media is expanded proportionally (i.e. maintaining the media aspect ratio) until the camera/card dimensions are fully covered. If `fill`, the media is stretched to fill the camera/card dimensions (i.e. ignoring the media aspect ratio). See [CSS object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) for technical details and a visualization. | +| `pan` | | A dictionary that may contain an `x` and `y` percentage (`0` - `100`) to control the position of the media when "digitally zoomed in" (see `zoom` parameter). This can be effectively used to "pan"/cut the media shown. A value of `0` means maximally to the left or top of the media, a value of `100` means maximally to the right or bottom of the media. See visualizations below. | | `position` | | A dictionary that may contain an `x` and `y` percentage (`0` - `100`) to control the position of the media when the fit is `cover` (for other values of `fit` this option has no effect). This can be effectively used to "pan"/cut the media shown. At any given time, only one of `x` and `y` will have an effect, depending on whether media width is larger than the camera/card dimensions (in which case `x` controls the position) or the media height is larger than the camera/card dimensions (in which case `y` controls the position). A value of `0` means maximally to the left or top of the media, a value of `100` means maximally to the right or bottom of the media. See [CSS object-position](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) for technicals. See visualizations below. | -| `view_box` | | A dictionary that may contain a `top`, `bottom`, `left` and `right` percentage (`0` - `100`) to precisely crop what part of the media to show by specifying a % inset value from each side. Browsers apply this cropping after `position` and `fit` have been applied. See visualizations below. | +| `view_box` | | A dictionary that may contain a `top`, `bottom`, `left` and `right` percentage (`0` - `100`) to precisely crop what part of the media to show by specifying a % inset value from each side. Browsers apply this cropping after `position` and `fit` have been applied. Unlike `zoom`, the user cannot dynamically zoom back out -- however the builtin media controls will work as normal. See visualizations below. Limited [browser support](https://caniuse.com/mdn-css_properties_object-view-box): ![](../../images/browsers/chrome_16x16.png "Google Chrome :no-zoom") ![](../../images/browsers/chromium_16x16.png "Chromium :no-zoom") ![](../../images/browsers/edge_16x16.png "Microsoft Edge :no-zoom") | +| `zoom` | `1.0` | A value between `1.0` and `10.0` inclusive that defines how much additional "digital zoom" to apply to this camera by default. Unlike with `view_box` the user can easily "zoom back out". Often used in conjuction with `pan`. When zoomed in the [builtin browser media controls](../live.md?id=controls) will automatically be disabled (as otherwise they would be enlarged also). | -!> The `view_box` parameter only has effect on browsers that support [`object-view-box`](https://caniuse.com/mdn-css_properties_object-view-box). As of writing this is exclusively Chromium based browsers (e.g. Google Chrome or Microsoft Edge). +?> Layout operations are effectively applied in this order: `fit`, `position`, `view_box`, `zoom` then `pan`. See [media layout examples](../../examples.md?id=media-layout). @@ -169,6 +171,11 @@ See [media layout examples](../../examples.md?id=media-layout). ![](../../images/media_layout/view-box.png "Media Layout Position: Taller than wider :size=400") +#### `pan` and `zoom`: Predefined panning and zooming + +![](../../images/media_layout/pan-zoom.png "Panning and zooming :size=400") + + ## `triggers` The `triggers` block configures what triggers a camera. Triggering can be used @@ -300,6 +307,13 @@ cameras: movies: directory_pattern: '%Y-%m-%d' file_pattern: '%H-%M-%S' + - camera_entity: camera.zoomed + dimensions: + layout: + zoom: 2.0 + pan: + x: 50 + y: 50 cameras_global: live_provider: ha ``` diff --git a/docs/configuration/conditions.md b/docs/configuration/conditions.md index 23620cf2..40e59550 100644 --- a/docs/configuration/conditions.md +++ b/docs/configuration/conditions.md @@ -164,6 +164,11 @@ conditions: | `condition` | Must be `view`. | | `views` | A list of [views](view.md?id=supported-views) in which this condition is satified (e.g. `clips`). | +?> Internally, views associated with the media viewer (e.g. `clip`, `snapshot`, +`recording`) are translated to a special view called `media` after the relevant +media is fetched. When including views as part of a [condition](conditions.md), +you may need to refer to this special `media` view. + # Fully expanded reference [](common/expanded-warning.md ':include') diff --git a/docs/configuration/menu.md b/docs/configuration/menu.md index 1348e516..093f8e11 100644 --- a/docs/configuration/menu.md +++ b/docs/configuration/menu.md @@ -33,6 +33,7 @@ menu: | `camera_ui` | The `camera_ui` menu button: brings the user to a context-appropriate page on the UI of their camera engine (e.g. the Frigate camera homepage). Will only appear if the camera engine supports a camera UI (e.g. if `frigate.url` option is set for `frigate` engine users).| | `cameras` | The camera selection submenu. Will only appear if multiple cameras are configured. | | `clips` | The `clips` view menu button: brings the user to the `clips` view on tap and the most-recent `clip` view on hold. | +| `default_zoom` | The `default_zoom` button allows easily returning the camera to default pan/zoom. | | `display_mode` | The `display_mode` button allows changing between single and grid views. | | `download` | The `download` menu button: allow direct download of the media being displayed.| | `expand` | The `expand` menu button: expand the card into a popup/dialog. | @@ -53,7 +54,7 @@ menu: | Option | Default | Description | | - | - | - | | `alignment` | `matching` | Whether this button should have an alignment that is `matching` the menu alignment or `opposing` the menu. Can be used to create two separate groups of buttons on the menu. `priority` orders buttons within a given `alignment`. | -| `enabled` | `true` for `frigate`, `cameras`, `substreams`, `live`, `clips`, `snapshots`, `timeline`, `download`, `camera_ui`, `fullscreen`, `media_player`, `display_mode`. `false` for `image`, `expand`, `microphone`, `mute`, `play`, `recordings`, `screenshot`, `ptz` | Whether or not to show the button. | +| `enabled` | `true` for `frigate`, `cameras`, `substreams`, `live`, `clips`, `snapshots`, `timeline`, `download`, `camera_ui`, `fullscreen`, `media_player`, `display_mode` and `default_zoom`. `false` for `image`, `expand`, `microphone`, `mute`, `play`, `recordings`, `screenshot`, `ptz` | Whether or not to show the button. | | `icon` | | An icon to overriding the default for that button, e.g. `mdi:camera-front`. | | `priority` | `50` | The button priority. Higher priority buttons are ordered closer to the start of the menu alignment (i.e. a button with priority `70` will order further to the left than a button with priority `60`, when the menu alignment is `left`). Minimum `0`, maximum `100`.| @@ -90,9 +91,15 @@ menu: enabled: true alignment: matching icon: mdi:video-switch + default_zoom: + priority: 50 + enabled: true + alignment: matching + icon: mdi:magnify-close substreams: priority: 50 enabled: true + alignment: matching icon: mdi:video-input-component live: priority: 50 diff --git a/docs/examples.md b/docs/examples.md index c9a47395..0165992c 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -997,3 +997,63 @@ cameras: webrtc_card: ui: true ``` + +## Zoom + +### Pre-defining camera zoom and pan + +This example changes the default [zoom/pan settings for a camera](./configuration/cameras/README.md?id=layout-configuration) to always zoom in on a given area: + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + dimensions: + layout: + zoom: 3 + pan: + x: 20 + y: 80 +``` + +### Disable zooming in media views + +This example prevents zooming on the media viewer but keeps it on in other views (e.g. `live` view): + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + dimensions: + layout: + zoom: 3 + pan: + x: 20 + y: 80 +media_viewer: + zoomable: false +``` + +### Different zoom settings in media viewer vs `live` + +This example uses different settings for the media viewer and `live` view, by overriding the camera configuration: + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office + dimensions: + layout: + zoom: 2 +overrides: + - conditions: + - condition: view + views: + - media + set: + 'cameras[0].dimensions.layout': + zoom: 3 + pan: + x: 100 + y: 100 +``` diff --git a/docs/images/browsers/chrome_16x16.png b/docs/images/browsers/chrome_16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..e4e2773fc99e01094d7634e8f9bebd218b57a3d6 GIT binary patch literal 819 zcmV-31I+x1P)Ah3I(AVE^R=)$fd zv93Y_0|f~aW;Ys@5LV#U7E_6hjZx$5xE;^){C?jqx(a%|1TZmJ2M9m}2wA8}8ZuL# zWXLpW(iLD~>CQ6UtGWUZ7aL77{uO{IDVKBvcuTOJ|C*KQbk{wdA3ENa6uN6&QGYzL zB>=Gq+L*zpWObRaEOR6`2{V&Ok_nT>tUC?^Gif0Y0&vJDc5eAarn*^Z1C`WlYDI2X z5JiG4U+rdA$jC()o4)$W0MHh|iFb!S8u?-VaE97=$}@xe_V1^$V;9Qc-tt>oH%}8C zWT8#+Jao5@1BbQy)JSc*mXCdKW~%3@8x3FXkk%hN$%$+a=YCuQhmpaR9C`dKcH=c- zGMA#f&73cVdRX`Jw&7Ob;Pl!KfBNbz-GAV9j&C~1(JyYJqRpLVi*K&|P0{%z&ptRy zG4s9T-Hy|x%&%C>=&QCOzizDhrN`Ei9vb57pO)#VWmGDGN+r;aDh{h>nrQ@iYufLkc$j&c*2N0hozp9B}tz zDW%yIOErpUhc-4tZ)dc-DVsCdakQcz>zD=tSQNm-V4b~hZwf%X@Y!vidvimrObi*` xcX{U`y({Bnqsch&iI_syouUR&9pJs)3v`zJi zwh06sv%cZD)tx=BFmAz*r6e*rAkL1!csu5v_=ywGDsa|Ng)=Xzu;^?#=ASOd;&T;( zwqAd&dKn8$-&XCFw9i#Ipx_hyVr*(qyaVTrl~{X=$B3n+j1|{wQCtmNv&*<@lhx~X z1sBXx(UB)EFD_nWr`JZj{jsbH}fa_GXB6n^AEULzcBAYHQxSGaO8=A zGX_yTYZO65aq)Zj^tj!1NINJf0}8(2@S`$}Tvo>9u-rmMKvp3J%rC~fKQc}mn5eh| znJhpcY2ROE!lo*mGgf2xl2Uf(hJpTV1R@9|?&a0VTkCN0xqxL?tF_0bNFjrZ{)L5? zs`37hf}>9boHI3k1uvqIK-_L#)z*ejGK&mZRLod>xf*YND@;0L^vFeo7yFGQEhUh! zhZkaY@zA!<7$iJ=E8)>QiJnTr&btE6o0urL1MD~IfzHGmJrcKvUS~@kX6@uLbt{jo z!#w>qQEecie6lTjNqjPW~j^2jQ zTLm5h%uTNcAOQq`#asIx$jYbyyY97d#U#zDfr(%MSa+=0|E5tKzCWlM_fC&@J&@(X z_Xi%xxytjda4U!|m}JyyQ)*MGFeXWJvF+wRi zer8-6XD7g^36*oMj^3qI#wwJt{uo&Fm(8ZuzPoqx;jjNSM|J6}oD>U9Q!CwYw=ebK zv6N3`39)BI=tvp+t_UNGzMcoW?N)EzUEcotc-BtMnVXyuil$PY5|hx1^K;9czgQaW z9JP#|sE#z{M3u}2l`yRA#jtx{&rwX_e6(C8v9VHgqfNT~)msC&15jSR@TR5SPs#VC zP9sK=R5dwBy^zCc69no6AwaK-wErN?JaYm7FgE#5(==13L8{!q#D+!6b;mpXGMLdu z4K;+|V1HYKiD&Z3OTcdcqU%?jjKGGmsw+$_1;-n}cF=4;I43)Zol!M&!+{eQK=XT| z)wjTpeD}Z1vn6{wmgtA<`7$v5YNZmHO98vMrK@zDzz@CaMf z_L8OaVLkio&TxJ~)O&AO0S0DUU>~?NJm<|Gi8zmQSpWdI+VVgKkW@|C6SGU9v-Mou p+aMf2ZcG2@4sZnET<|~!_#ZwEoO)Fu@mc@?002ovPDHLkV1gG{iRl0U literal 0 HcmV?d00001 diff --git a/docs/images/media_layout/fit.png b/docs/images/media_layout/fit.png index b47fe96a89bdd29decf998e661ca88fd608aad5b..a8ade712d8bc3f407390e55b51b37c573eceadbc 100644 GIT binary patch literal 67839 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 NedUKr#R|_t{tu0n!qxx) diff --git a/docs/images/media_layout/pan-zoom.png b/docs/images/media_layout/pan-zoom.png new file mode 100644 index 0000000000000000000000000000000000000000..4e25a97949f98c9adc11c581d179172e0ff8e675 GIT binary patch literal 40162 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π4V1LHqb#6L*JZbJ~6~`Ho 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áPC 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 repu(U8jx0xXAxP9H2pE~dkc8GoW}=M> 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 W>Qnkjcm@UdQNM9V6|MZ#=f3~~ZtcJT diff --git a/docs/images/media_layout/position-thinner-than-width.png b/docs/images/media_layout/position-thinner-than-width.png index 2f171db295ca570a93d7aba487a77301687faa20..0fe36f320a48a16d6040d0c96069d835fa1d03a8 100644 GIT binary patch literal 79860 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 diff --git a/docs/images/media_layout/view-box.png b/docs/images/media_layout/view-box.png index 9a91d96a26e9192998b31667cf9c6001096108b4..4744ff4bd1e3753567f014715ec43369d08b5e35 100644 GIT binary patch literal 63271 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 { - await this._store.reset(); - } - public async initializeCamerasFromConfig(): Promise { const config = this._api.getConfigManager().getConfig(); const hass = this._api.getHASSManager().getHASS(); @@ -149,7 +145,7 @@ export class CameraManager { ); const resetAndInitialize = async () => { - await this.reset(); + await this._reset(); await this._initializeCameras(cameras); }; @@ -165,6 +161,10 @@ export class CameraManager { return true; } + protected async _reset(): Promise { + await this._store.reset(); + } + protected async _getEnginesForCameras( camerasConfig: CamerasConfig, ): Promise> { diff --git a/src/card-controller/actions-manager.ts b/src/card-controller/actions-manager.ts index 69c54ab4..08eff63c 100644 --- a/src/card-controller/actions-manager.ts +++ b/src/card-controller/actions-manager.ts @@ -12,6 +12,7 @@ import { getActionConfigGivenAction, } from '../utils/action.js'; import { getStreamCameraID } from '../utils/substream.js'; +import { generateViewContextForZoomChange } from '../components-lib/zoom/zoom-view-context.js'; import { CardActionsManagerAPI } from './types.js'; const interactionSchema = z.object({ @@ -263,9 +264,19 @@ export class ActionsManager { } break; case 'show_ptz': - this._api - .getViewManager() - .setViewWithNewContext({ live: { ptzVisible: frigateCardAction.show_ptz } }); + this._api.getViewManager().setViewWithMergedContext({ + live: { ptzVisible: frigateCardAction.show_ptz }, + }); + break; + case 'change_zoom': + this._api.getViewManager().setViewWithMergedContext( + generateViewContextForZoomChange(frigateCardAction.target_id, { + zoom: { + pan: frigateCardAction.pan, + zoom: frigateCardAction.zoom, + }, + }), + ); break; default: console.warn(`Frigate card received unknown card action: ${action}`); diff --git a/src/card-controller/card-element-manager.ts b/src/card-controller/card-element-manager.ts index 1b442f1e..c586173e 100644 --- a/src/card-controller/card-element-manager.ts +++ b/src/card-controller/card-element-manager.ts @@ -99,6 +99,9 @@ export class CardElementManager { // Manually call the location change handler as the card will be // disconnected/reconnected when dashboard 'tab' changes happen within HA. this._api.getQueryStringManager().executeAll(); + + // Make sure reconnections call the initialization code. + this._element.requestUpdate(); } public elementDisconnected(): void { @@ -108,15 +111,10 @@ export class CardElementManager { this._api.getMediaLoadedInfoManager().clear(); this._api.getFullscreenManager().disconnect(); - // Reset and uninitialize cameras to cause them to reinitialize on + // Uninitialize cameras to cause them to reinitialize on // reconnection, to ensure the state subscription/unsubscription works // correctly for triggers. - this._api - .getCameraManager() - .reset() - .then(() => - this._api.getInitializationManager().uninitialize(InitializationAspect.CAMERAS), - ); + this._api.getInitializationManager().uninitialize(InitializationAspect.CAMERAS), this._element.removeEventListener( 'mousemove', diff --git a/src/card-controller/initialization-manager.ts b/src/card-controller/initialization-manager.ts index 3c640198..cbc23190 100644 --- a/src/card-controller/initialization-manager.ts +++ b/src/card-controller/initialization-manager.ts @@ -86,19 +86,25 @@ export class InitializationManager { } if (!this._api.getMessageManager().hasMessage()) { - // Set a view on initial load. However, if the query string contains a - // view related action, we don't set any view here and allow that content - // to be triggered by the firstUpdated() call that runs query string - // actions. To do otherwise may cause a race condition between the default - // view and the querystring view, see: - // https://github.com/dermotduffy/frigate-hass-card/issues/1200 - const hasViewRelatedActions = this._api - .getQueryStringManager() - .hasViewRelatedActions(); - if (hasViewRelatedActions) { - this._api.getQueryStringManager().executeViewRelated(); + if (!this._api.getViewManager().hasView()) { + // Set a view on initial load. However, if the query string contains a + // view related action, we don't set any view here and allow that content + // to be triggered by the firstUpdated() call that runs query string + // actions. To do otherwise may cause a race condition between the default + // view and the querystring view, see: + // https://github.com/dermotduffy/frigate-hass-card/issues/1200 + const hasViewRelatedActions = this._api + .getQueryStringManager() + .hasViewRelatedActions(); + if (hasViewRelatedActions) { + this._api.getQueryStringManager().executeViewRelated(); + } else { + this._api.getViewManager().setViewDefault({ failSafe: true }); + } } else { - this._api.getViewManager().setViewDefault({ failSafe: true }); + // If we already have a view something (e.g. cameras) may have been + // reinitialized, be sure to ask for an update. + this._api.getCardElementManager().update(); } } diff --git a/src/card-controller/view-manager.ts b/src/card-controller/view-manager.ts index 2570fed9..5a369700 100644 --- a/src/card-controller/view-manager.ts +++ b/src/card-controller/view-manager.ts @@ -161,7 +161,7 @@ export class ViewManager { } } - public setViewWithNewContext(context: ViewContext): void { + public setViewWithMergedContext(context: ViewContext | null): void { if (this._view) { return this._setView(this._view?.clone().mergeInContext(context)); } diff --git a/src/card.ts b/src/card.ts index 517f5def..c6b49571 100644 --- a/src/card.ts +++ b/src/card.ts @@ -269,8 +269,8 @@ class FrigateCard extends LitElement { this._controller.getMessageManager().setMessageIfHigherPriority(ev.detail)} @frigate-card:view:change=${(ev: CustomEvent) => this._controller.getViewManager().setView(ev.detail)} - @frigate-card:view:change-context=${(ev: CustomEvent) => - this._controller.getViewManager().setViewWithNewContext(ev.detail)} + @frigate-card:view:change-context=${(ev: CustomEvent) => + this._controller.getViewManager().setViewWithMergedContext(ev.detail)} @frigate-card:media:loaded=${(ev: CustomEvent) => this._controller.getMediaLoadedInfoManager().set(ev.detail)} @frigate-card:media:unloaded=${() => diff --git a/src/components-lib/menu-button-controller.ts b/src/components-lib/menu-button-controller.ts index eeaae499..5fa25a9a 100644 --- a/src/components-lib/menu-button-controller.ts +++ b/src/components-lib/menu-button-controller.ts @@ -5,9 +5,9 @@ import { MediaPlayerManager } from '../card-controller/media-player-manager'; import { MicrophoneManager } from '../card-controller/microphone-manager'; import { ViewManager } from '../card-controller/view-manager'; import { + FRIGATE_CARD_VIEWS_USER_SPECIFIED, FrigateCardConfig, FrigateCardCustomAction, - FRIGATE_CARD_VIEWS_USER_SPECIFIED, MenuItem, } from '../config/types'; import { FRIGATE_BUTTON_MENU_ICON } from '../const'; @@ -15,6 +15,7 @@ import { localize } from '../localize/localize.js'; import { MediaLoadedInfo } from '../types'; import { createFrigateCardCameraAction, + createFrigateCardChangeZoomAction, createFrigateCardDisplayModeAction, createFrigateCardMediaPlayerAction, createFrigateCardShowPTZAction, @@ -95,6 +96,7 @@ export class MenuButtonController { this._getScreenshotButton(config, options?.currentMediaLoadedInfo), this._getDisplayModeButton(config, cameraManager, view), this._getPTZButton(config, cameraManager, view), + this._getDefaultZoomButton(config, view), ...this._dynamicMenuButtons.map((button) => ({ style: this._getStyleFromActions(config, view, button, options), @@ -582,7 +584,9 @@ export class MenuButtonController { } protected _getSubstreamAwareCameraID(view: View): string { - return view.context?.live?.overrides?.get(view.camera) ?? view.camera; + return view.is('live') + ? view.context?.live?.overrides?.get(view.camera) ?? view.camera + : view.camera; } protected _getPTZButton( @@ -614,6 +618,27 @@ export class MenuButtonController { return null; } + protected _getDefaultZoomButton( + config: FrigateCardConfig, + view: View, + ): MenuItem | null { + const targetID = view.isViewerView() + ? view.queryResults?.getSelectedResult()?.getID() ?? null + : this._getSubstreamAwareCameraID(view); + + if (!targetID || (view.context?.zoom?.[targetID]?.isDefault ?? true)) { + return null; + } + + return { + icon: 'mdi:magnify-close', + ...config.menu.buttons.default_zoom, + type: 'custom:frigate-card-menu-icon', + title: localize('config.menu.buttons.default_zoom'), + tap_action: createFrigateCardChangeZoomAction(targetID) as FrigateCardCustomAction, + }; + } + /** * Get the style of emphasized menu items. * @returns A StyleInfo. diff --git a/src/components-lib/zoom-controller.ts b/src/components-lib/zoom-controller.ts deleted file mode 100644 index 07557136..00000000 --- a/src/components-lib/zoom-controller.ts +++ /dev/null @@ -1,160 +0,0 @@ -import Panzoom, { PanzoomEventDetail, PanzoomObject } from '@dermotduffy/panzoom'; -import round from 'lodash-es/round'; -import { dispatchFrigateCardEvent, isHoverableDevice } from '../utils/basic'; - -export class ZoomController { - constructor(element: HTMLElement) { - this._element = element; - } - - protected _element: HTMLElement; - protected _panzoom?: PanzoomObject; - protected _zoomed = false; - protected _allowClick = true; - - protected _events = isHoverableDevice() - ? { - down: ['pointerdown'], - move: ['pointermove'], - up: ['pointerup', 'pointerleave', 'pointercancel'], - } - : { - down: ['touchstart'], - move: ['touchmove'], - up: ['touchend', 'touchcancel'], - }; - - protected _downHandler = (ev: Event) => { - if (this._shouldZoomOrPan(ev)) { - this._panzoom?.handleDown(ev as PointerEvent); - ev.stopPropagation(); - - // If we do not prevent default here, the media carousels scroll. - ev.preventDefault(); - this._allowClick = false; - } else { - this._allowClick = true; - } - }; - - protected _clickHandler = (ev: Event) => { - // When mouse clicking is used to pan, need to avoid that causing a click - // handler elsewhere in the card being called. Example: Viewing a snapshot, - // and panning within it should not cause a related clip to play (the click - // handler in the viewer). - if (!this._allowClick) { - ev.stopPropagation(); - } - this._allowClick = true; - }; - - protected _moveHandler = (ev: Event) => { - if (this._shouldZoomOrPan(ev)) { - this._panzoom?.handleMove(ev as PointerEvent); - ev.stopPropagation(); - } - }; - - protected _upHandler = (ev: Event) => { - if (this._shouldZoomOrPan(ev)) { - this._panzoom?.handleUp(ev as PointerEvent); - ev.stopPropagation(); - } - }; - - protected _wheelHandler = (ev: Event) => { - if (ev instanceof WheelEvent && this._shouldZoomOrPan(ev)) { - this._panzoom?.zoomWithWheel(ev); - ev.stopPropagation(); - } - }; - - protected _isScaleNormal(scale?: number): boolean { - // Floating point arithmetic warning: comparing floating point numbers, - // round them first. - return scale !== undefined && round(scale, 4) <= 1; - } - - protected _shouldZoomOrPan(ev: Event): boolean { - return ( - !this._isScaleNormal(this._panzoom?.getScale()) || - // TouchEvent does not exist on Firefox on non-touch events. - // See: https://github.com/dermotduffy/frigate-hass-card/issues/1174 - (window.TouchEvent && ev instanceof TouchEvent && ev.touches.length > 1) || - (ev instanceof WheelEvent && ev.ctrlKey) - ); - } - - protected _setTouchAction(touchEnabled: boolean): void { - this._element.style.touchAction = touchEnabled ? '' : 'none'; - } - - public activate(): void { - this._panzoom = Panzoom(this._element, { - contain: 'outside', - maxScale: 10, - minScale: 1, - noBind: true, - // Do not force the cursor style (by default it will always show the - // 'move' type cursor whether or not it is zoomed in). - cursor: undefined, - - // Disable automatic touchAction setting from Panzoom() as otherwise it - // effectively disables dashboard scrolling. - // See: https://github.com/dermotduffy/frigate-hass-card/issues/1181 - touchAction: '', - }); - - const registerListeners = ( - events: string[], - func: (ev: Event) => void, - options?: AddEventListenerOptions, - ) => { - events.forEach((eventName) => { - this._element.addEventListener(eventName, func, options); - }); - }; - - registerListeners(this._events['down'], this._downHandler, { capture: true }); - registerListeners(this._events['move'], this._moveHandler, { capture: true }); - registerListeners(this._events['up'], this._upHandler, { capture: true }); - registerListeners(['wheel'], this._wheelHandler); - registerListeners(['click'], this._clickHandler, { capture: true }); - - this._element.addEventListener('panzoomzoom', (ev: Event) => { - // Take care here to only dispatch the zoomed/unzoomed events when the - // absolute state changes (rather than on every single zoom adjustment). - if (this._isScaleNormal((>ev).detail.scale)) { - if (this._zoomed) { - this._setTouchAction(true); - dispatchFrigateCardEvent(this._element, 'zoom:unzoomed'); - } - this._zoomed = false; - } else { - if (!this._zoomed) { - this._setTouchAction(false); - dispatchFrigateCardEvent(this._element, 'zoom:zoomed'); - } - this._zoomed = true; - } - }); - } - - public deactivate(): void { - const unregisterListener = ( - events: string[], - func: (ev: Event) => void, - options?: EventListenerOptions, - ) => { - events.forEach((eventName) => { - this._element.removeEventListener(eventName, func, options); - }); - }; - - unregisterListener(this._events['down'], this._downHandler, { capture: true }); - unregisterListener(this._events['move'], this._moveHandler, { capture: true }); - unregisterListener(this._events['up'], this._upHandler, { capture: true }); - unregisterListener(['wheel'], this._wheelHandler); - unregisterListener(['click'], this._clickHandler, { capture: true }); - } -} diff --git a/src/components-lib/zoom/types.ts b/src/components-lib/zoom/types.ts new file mode 100644 index 00000000..04f92855 --- /dev/null +++ b/src/components-lib/zoom/types.ts @@ -0,0 +1,11 @@ +export interface ZoomConfig { + pan?: { + x?: number; + y?: number; + }; + zoom?: number; +} + +export interface ZoomDefault { + isDefault: boolean; +} diff --git a/src/components-lib/zoom/zoom-controller.ts b/src/components-lib/zoom/zoom-controller.ts new file mode 100644 index 00000000..8a6aeec6 --- /dev/null +++ b/src/components-lib/zoom/zoom-controller.ts @@ -0,0 +1,419 @@ +import Panzoom, { PanzoomEventDetail, PanzoomObject } from '@dermotduffy/panzoom'; +import debounce from 'lodash-es/debounce'; +import round from 'lodash-es/round'; +import { + arefloatsApproximatelyEqual, + dispatchFrigateCardEvent, + isHoverableDevice, +} from '../../utils/basic'; +import { ZoomConfig } from './types'; + +const ZOOM_DEFAULT_PAN_X = 50; +const ZOOM_DEFAULT_PAN_Y = 50; +const ZOOM_DEFAULT_SCALE = 1; +const ZOOM_PRECISION = 4; + +export class ZoomController { + protected _element: HTMLElement; + protected _panzoom?: PanzoomObject; + + // Is the controller zoomed in at all? + protected _zoomed = false; + + // Is the controller set to the default zoom/pan settings? + protected _default = true; + + // Should clicks be allowed to propagate, or consumed as a pan/zoom action? + protected _allowClick = true; + + protected _defaultConfig: ZoomConfig | null; + protected _config: ZoomConfig | null; + + // When the user pans/zooms changes may be created at a very high rate. + protected _debouncedChangeHandler = debounce(this._changeHandler.bind(this), 200); + + // Multiple calls to setConfig() or setDefaultConfig() or resizes should only + // update once. + protected _debouncedUpdater = debounce(this._updateBasedOnConfig.bind(this), 200); + + protected _resizeObserver = new ResizeObserver(this._debouncedUpdater); + + protected _events = isHoverableDevice() + ? { + down: ['pointerdown'], + move: ['pointermove'], + up: ['pointerup', 'pointerleave', 'pointercancel'], + } + : { + down: ['touchstart'], + move: ['touchmove'], + up: ['touchend', 'touchcancel'], + }; + + protected _downHandler = (ev: Event) => { + if (this._shouldZoomOrPan(ev)) { + this._panzoom?.handleDown(ev as PointerEvent); + ev.stopPropagation(); + + // If we do not prevent default here, the media carousels scroll. + ev.preventDefault(); + this._allowClick = false; + } else { + this._allowClick = true; + } + }; + + protected _clickHandler = (ev: Event) => { + // When mouse clicking is used to pan, need to avoid that causing a click + // handler elsewhere in the card being called. Example: Viewing a snapshot, + // and panning within it should not cause a related clip to play (the click + // handler in the viewer). + if (!this._allowClick) { + ev.stopPropagation(); + } + this._allowClick = true; + }; + + protected _moveHandler = (ev: Event) => { + if (this._shouldZoomOrPan(ev)) { + this._panzoom?.handleMove(ev as PointerEvent); + ev.stopPropagation(); + } + }; + + protected _upHandler = (ev: Event) => { + if (this._shouldZoomOrPan(ev)) { + this._panzoom?.handleUp(ev as PointerEvent); + ev.stopPropagation(); + } + }; + + protected _wheelHandler = (ev: Event) => { + if (ev instanceof WheelEvent && this._shouldZoomOrPan(ev)) { + this._panzoom?.zoomWithWheel(ev); + ev.stopPropagation(); + } + }; + + constructor( + element: HTMLElement, + options?: { config?: ZoomConfig | null; defaultConfig?: ZoomConfig | null }, + ) { + this._element = element; + this._config = options?.config ?? null; + this._defaultConfig = options?.defaultConfig ?? null; + } + + public activate(): void { + const config = this._getConfigToUse(); + const converted = this._convertPercentToXYPan( + config?.pan?.x ?? ZOOM_DEFAULT_PAN_X, + config?.pan?.y ?? ZOOM_DEFAULT_PAN_Y, + config?.zoom ?? ZOOM_DEFAULT_SCALE, + ); + + this._panzoom = Panzoom(this._element, { + contain: 'outside', + maxScale: 10, + minScale: 1, + noBind: true, + // Do not force the cursor style (by default it will always show the + // 'move' type cursor whether or not it is zoomed in). + cursor: undefined, + + // Disable automatic touchAction setting from Panzoom() as otherwise it + // effectively disables dashboard scrolling. See: + // https://github.com/dermotduffy/frigate-hass-card/issues/1181 + touchAction: '', + + // Set the initial pan/zoom values to avoid an initial unzoomed view. + ...(config && converted && { startX: converted.x }), + ...(config && converted && { startY: converted.y }), + ...(config && + converted && { + startScale: + config.zoom ?? + // This is not reachable as without a zoom value, a default of 1 is + // assumed in _convertPercentToXYPan, which will return null @ + // default zoom, and so this cannot be reached in practice. + /* istanbul ignore next @preserve */ + ZOOM_DEFAULT_SCALE, + }), + }); + + const registerListeners = ( + events: string[], + func: (ev: Event) => void, + options?: AddEventListenerOptions, + ) => { + events.forEach((eventName) => { + this._element.addEventListener(eventName, func, options); + }); + }; + + registerListeners(this._events['down'], this._downHandler, { capture: true }); + registerListeners(this._events['move'], this._moveHandler, { capture: true }); + registerListeners(this._events['up'], this._upHandler, { capture: true }); + registerListeners(['wheel'], this._wheelHandler); + registerListeners(['click'], this._clickHandler, { capture: true }); + + this._resizeObserver.observe(this._element); + this._element.addEventListener('panzoomchange', this._debouncedChangeHandler); + } + + public deactivate(): void { + const unregisterListener = ( + events: string[], + func: (ev: Event) => void, + options?: EventListenerOptions, + ) => { + events.forEach((eventName) => { + this._element.removeEventListener(eventName, func, options); + }); + }; + + unregisterListener(this._events['down'], this._downHandler, { capture: true }); + unregisterListener(this._events['move'], this._moveHandler, { capture: true }); + unregisterListener(this._events['up'], this._upHandler, { capture: true }); + unregisterListener(['wheel'], this._wheelHandler); + unregisterListener(['click'], this._clickHandler, { capture: true }); + + this._resizeObserver.disconnect(); + this._element.removeEventListener('panzoomchange', this._debouncedChangeHandler); + } + + public setDefaultConfig(config: ZoomConfig | null): void { + this._defaultConfig = config; + this._debouncedUpdater(); + } + + public setConfig(config: ZoomConfig): void { + this._config = config; + this._debouncedUpdater(); + } + + protected _changeHandler(ev: Event): void { + const pz = (>ev).detail; + + const isUnzoomed = this._isUnzoomed(pz.scale); + const isAtDefault = this._isAtDefaultZoomAndPan(pz.x, pz.y, pz.scale); + + // Take care here to only dispatch the zoomed/unzoomed events when the + // absolute state changes (rather than on every single zoom adjustment). + if (isUnzoomed && this._zoomed) { + this._zoomed = false; + this._setTouchAction(true); + dispatchFrigateCardEvent(this._element, 'zoom:unzoomed'); + } else if (!isUnzoomed && !this._zoomed) { + this._zoomed = true; + this._setTouchAction(false); + dispatchFrigateCardEvent(this._element, 'zoom:zoomed'); + } + + if (isAtDefault && !this._default) { + this._default = true; + dispatchFrigateCardEvent(this._element, 'zoom:default', { isDefault: true }); + } else if (!isAtDefault && this._default) { + this._default = false; + dispatchFrigateCardEvent(this._element, 'zoom:default', { isDefault: false }); + } + } + + protected _isZoomEqual(a: ZoomConfig, b: ZoomConfig): boolean { + // The ?? clauses below cannot be reached since this function is only ever + // used fully specified by this object. It's kept as-is for completeness. + return ( + arefloatsApproximatelyEqual( + /* istanbul ignore next @preserve */ + a.zoom ?? ZOOM_DEFAULT_SCALE, + /* istanbul ignore next @preserve */ + b.zoom ?? ZOOM_DEFAULT_SCALE, + ZOOM_PRECISION, + ) && + arefloatsApproximatelyEqual( + /* istanbul ignore next @preserve */ + a.pan?.x ?? ZOOM_DEFAULT_PAN_X, + /* istanbul ignore next @preserve */ + b.pan?.x ?? ZOOM_DEFAULT_PAN_X, + ZOOM_PRECISION, + ) && + arefloatsApproximatelyEqual( + /* istanbul ignore next @preserve */ + a.pan?.y ?? ZOOM_DEFAULT_PAN_Y, + /* istanbul ignore next @preserve */ + b.pan?.y ?? ZOOM_DEFAULT_PAN_Y, + ZOOM_PRECISION, + ) + ); + } + + protected _isZoomEmpty(config?: ZoomConfig | null): boolean { + return ( + config?.pan?.x === undefined && + config?.pan?.y === undefined && + config?.zoom === undefined + ); + } + + protected _getConfigToUse(): ZoomConfig | null { + return this._isZoomEmpty(this._config) ? this._defaultConfig : this._config; + } + + protected _updateBasedOnConfig(): void { + if (!this._panzoom) { + return; + } + + const config = this._getConfigToUse(); + const desiredScale = config?.zoom ?? ZOOM_DEFAULT_SCALE; + + // Transform won't exist (will be null) if the element has no dimensions, or + // if the desired scale has no zoom (i.e. is 1). + const converted = this._convertPercentToXYPan( + config?.pan?.x ?? ZOOM_DEFAULT_PAN_X, + config?.pan?.y ?? ZOOM_DEFAULT_PAN_Y, + desiredScale, + ); + + const x = converted?.x ?? 0; + const y = converted?.y ?? 0; + + // Verify there is a material change in the pan/zoom settings before acting. + if ( + this._isZoomEqual( + { zoom: desiredScale, pan: { x: x, y: y } }, + { + zoom: this._panzoom.getScale(), + pan: this._panzoom.getPan(), + }, + ) + ) { + return; + } + + this._panzoom.zoom(desiredScale, { + animate: false, + }); + + // Panzoom must allow the browser to paint the zoomed image in order to + // "contain" the pan within the parent, this creates somewhat of an async + // situation where we need to ensure the zoom completes first. Using + // `requestAnimationFrame` appears to reliably allow the zoom to finish + // rendering first, before the pain is applied. + // See: https://github.com/timmywil/panzoom?tab=readme-ov-file#a-note-on-the-async-nature-of-panzoom + window.requestAnimationFrame(() => { + this._panzoom?.pan(x, y, { + animate: false, + }); + }); + } + + /** + * Convert from Frigate card pan % values to Panzoom X/Y transformation + * coordinates. + * @param x The x translation value. + * @param y The y translation value. + * @param scale The desired (not current) scale. + * @returns An object with x/y pan % values or null on error. + */ + protected _convertPercentToXYPan( + x: number, + y: number, + scale: number, + ): { x: number; y: number } | null { + const minMax = this._getTransformMinMax(scale, this._panzoom?.getScale()); + if (minMax === null) { + return null; + } + + return { + x: minMax.minX + (minMax.maxX - minMax.minX) * (x / 100), + y: minMax.minY + (minMax.maxY - minMax.minY) * (y / 100), + }; + } + + protected _getTransformMinMax( + desiredScale: number, + currentScale?: number, + ): { + minX: number; + maxX: number; + minY: number; + maxY: number; + } | null { + const rendered = this._getRenderedSize(currentScale); + + if (!rendered.width || !rendered.height) { + return null; + } + + const minX = (rendered.width * (desiredScale - 1)) / desiredScale / 2; + const minY = (rendered.height * (desiredScale - 1)) / desiredScale / 2; + + if (arefloatsApproximatelyEqual(minX, 0) || arefloatsApproximatelyEqual(minY, 0)) { + return null; + } + + return { + minX: minX, + maxX: -minX, + minY: minY, + maxY: -minY, + }; + } + + protected _getRenderedSize(scale?: number): { width: number; height: number } { + const rect = this._element.getBoundingClientRect(); + return { + width: rect.width / (scale ?? ZOOM_DEFAULT_SCALE), + height: rect.height / (scale ?? ZOOM_DEFAULT_SCALE), + }; + } + + protected _isUnzoomed(scale?: number): boolean { + return scale !== undefined && round(scale, ZOOM_PRECISION) <= 1; + } + + protected _isAtDefaultZoomAndPan(x: number, y: number, scale: number): boolean { + if (!this._defaultConfig) { + return this._isUnzoomed(scale); + } + + const convertedDefault = this._convertPercentToXYPan( + this._defaultConfig.pan?.x ?? ZOOM_DEFAULT_PAN_X, + this._defaultConfig.pan?.y ?? ZOOM_DEFAULT_PAN_Y, + this._defaultConfig.zoom ?? ZOOM_DEFAULT_SCALE, + ); + if (!convertedDefault) { + return true; + } + + return ( + arefloatsApproximatelyEqual(x, convertedDefault.x) && + arefloatsApproximatelyEqual(y, convertedDefault.y) && + arefloatsApproximatelyEqual( + scale, + this._defaultConfig.zoom ?? + // The ZOOM_DEFAULT_SCALE clause below cannot be reached since when + // this._defaultConfig.zoom is undefined, convertedDefault will end up + // null above and this function will have already returned. + /* istanbul ignore next @preserve */ + ZOOM_DEFAULT_SCALE, + ) + ); + } + + protected _shouldZoomOrPan(ev: Event): boolean { + return ( + !this._isUnzoomed(this._panzoom?.getScale()) || + // TouchEvent does not exist on Firefox on non-touch events. See: + // https://github.com/dermotduffy/frigate-hass-card/issues/1174 + (window.TouchEvent && ev instanceof TouchEvent && ev.touches.length > 1) || + (ev instanceof WheelEvent && ev.ctrlKey) + ); + } + + protected _setTouchAction(touchEnabled: boolean): void { + this._element.style.touchAction = touchEnabled ? '' : 'none'; + } +} diff --git a/src/components-lib/zoom/zoom-view-context.ts b/src/components-lib/zoom/zoom-view-context.ts new file mode 100644 index 00000000..bd8b169a --- /dev/null +++ b/src/components-lib/zoom/zoom-view-context.ts @@ -0,0 +1,57 @@ +import { ViewContext } from 'view'; +import { ZoomConfig, ZoomDefault } from './types.js'; +import { dispatchViewContextChangeEvent } from '../../view/view.js'; + +interface ZoomViewContext { + // Populate this to request zoom to a particular scale/x/y. An empty object + // will reset to default, null will make no change. + zoom?: ZoomConfig | null; + + // This will be populated with whether or not the current zoom is at the + // default level. + isDefault?: boolean; +} + +interface ZoomsViewContext { + [targetID: string]: ZoomViewContext; +} + +declare module 'view' { + interface ViewContext { + zoom?: ZoomsViewContext; + } +} + +export const generateViewContextForZoomChange = ( + targetID: string, + options?: { + zoom?: ZoomConfig | null; + isDefault?: boolean; + }, +): ViewContext | null => { + return { + zoom: { + [targetID]: { + zoom: options?.zoom ?? null, + ...(options?.isDefault !== undefined && { isDefault: options.isDefault }), + }, + }, + }; +}; + +/** + * Convenience wrapper to convert a zoom default into a dispatched view context + * change. + */ +export const handleZoomDefaultEvent = ( + element: EventTarget, + ev: CustomEvent, + targetID?: string, +): void => { + targetID && dispatchViewContextChangeEvent( + element, + generateViewContextForZoomChange(targetID, { + isDefault: ev.detail.isDefault, + }), + ); +}; diff --git a/src/components/image.ts b/src/components/image.ts index 0ba8bbcf..5a1850d3 100644 --- a/src/components/image.ts +++ b/src/components/image.ts @@ -9,10 +9,13 @@ import { unsafeCSS, } from 'lit'; import { customElement, property } from 'lit/decorators.js'; +import { guard } from 'lit/directives/guard.js'; import { live } from 'lit/directives/live.js'; import { createRef, ref, Ref } from 'lit/directives/ref.js'; import isEqual from 'lodash-es/isEqual'; import { CachedValueController } from '../components-lib/cached-value-controller.js'; +import { ZoomDefault } from '../components-lib/zoom/types.js'; +import { handleZoomDefaultEvent } from '../components-lib/zoom/zoom-view-context.js'; import { CameraConfig, ImageViewConfig } from '../config/types.js'; import defaultImage from '../images/frigate-bird-in-sky.jpg'; import { localize } from '../localize/localize.js'; @@ -277,8 +280,25 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay } protected _useZoomIfRequired(template: TemplateResult): TemplateResult { + const targetID = this.cameraConfig?.id; + const zoomConfig = targetID ? this.view?.context?.zoom?.[targetID]?.zoom : undefined; + return this.imageConfig?.zoomable - ? html` ${template} ` + ? html` + this.cameraConfig?.dimensions?.layout + ? { + pan: this.cameraConfig.dimensions.layout.pan, + zoom: this.cameraConfig.dimensions.layout.zoom, + } + : undefined, + )} + .config=${zoomConfig} + @frigate-card:zoom:default=${(ev: CustomEvent) => + handleZoomDefaultEvent(this, ev, targetID)} + > + ${template} + ` : template; } diff --git a/src/components/live/live-image.ts b/src/components/live/live-image.ts index 91a5351d..a4d20cbd 100644 --- a/src/components/live/live-image.ts +++ b/src/components/live/live-image.ts @@ -3,8 +3,7 @@ import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit import { customElement, property } from 'lit/decorators.js'; import { createRef, ref, Ref } from 'lit/directives/ref.js'; import { CameraConfig } from '../../config/types'; -import { localize } from '../../localize/localize'; -import liveImageStyle from '../../scss/live-image.scss'; +import basicBlockStyle from '../../scss/basic-block.scss'; import { FrigateCardMediaPlayer } from '../../types.js'; import { getStateObjOrDispatchError } from '../../utils/get-state-obj'; import '../image.js'; @@ -17,9 +16,6 @@ export class FrigateCardLiveImage extends LitElement implements FrigateCardMedia @property({ attribute: false }) public cameraConfig?: CameraConfig; - @property({ attribute: true }) - public watermark?: string; - protected _refImage: Ref = createRef(); public async play(): Promise { @@ -80,17 +76,11 @@ export class FrigateCardLiveImage extends LitElement implements FrigateCardMedia .cameraConfig=${this.cameraConfig} > - ${this.watermark - ? html`` - : ''} `; } static get styles(): CSSResultGroup { - return unsafeCSS(liveImageStyle); + return unsafeCSS(basicBlockStyle); } } diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 59a0bc70..8251fc07 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -21,6 +21,8 @@ import { import { ReadonlyMicrophoneManager } from '../../card-controller/microphone-manager.js'; import { LiveController } from '../../components-lib/live/live-controller.js'; import { MediaGridSelected } from '../../components-lib/media-grid-controller.js'; +import { ZoomConfig, ZoomDefault } from '../../components-lib/zoom/types.js'; +import { handleZoomDefaultEvent } from '../../components-lib/zoom/zoom-view-context.js'; import { CameraConfig, CardWideConfig, @@ -501,6 +503,9 @@ export class FrigateCardLiveCarousel extends LitElement { .liveConfig=${liveConfig} .hass=${this.hass} .cardWideConfig=${this.cardWideConfig} + .zoomConfig=${this.view?.context?.zoom?.[cameraID]?.zoom} + @frigate-card:zoom:default=${(ev: CustomEvent) => + handleZoomDefaultEvent(this, ev, cameraID)} >
    @@ -688,6 +693,9 @@ export class FrigateCardLiveProvider @property({ attribute: false }) public microphoneStream?: MediaStream; + @property({ attribute: false }) + public zoomConfig?: ZoomConfig | null; + @state() protected _isVideoMediaLoaded = false; @@ -793,9 +801,6 @@ export class FrigateCardLiveProvider this._isVideoMediaLoaded = false; } - /** - * Record that video media is being shown. - */ protected _videoMediaShowHandler(): void { this._isVideoMediaLoaded = true; } @@ -852,6 +857,15 @@ export class FrigateCardLiveProvider protected _useZoomIfRequired(template: TemplateResult): TemplateResult { return this.liveConfig?.zoomable ? html` + this.cameraConfig?.dimensions?.layout + ? { + pan: this.cameraConfig.dimensions.layout.pan, + zoom: this.cameraConfig.dimensions.layout.zoom, + } + : undefined, + )} + .config=${this.zoomConfig} @frigate-card:zoom:zoomed=${() => this.setControls(false)} @frigate-card:zoom:unzoomed=${() => this.setControls()} > @@ -899,15 +913,12 @@ export class FrigateCardLiveProvider } } - return this._useZoomIfRequired(html` + return html`${this._useZoomIfRequired(html` ${showImageDuringLoading || provider === 'image' ? html` { if (provider === 'image') { // Only count the media has loaded if the required provider is @@ -968,7 +979,13 @@ export class FrigateCardLiveProvider > ` : html``} - `); + `)} + ${showImageDuringLoading && !this._isVideoMediaLoaded + ? html`` + : ''} `; } static get styles(): CSSResultGroup { diff --git a/src/components/viewer.ts b/src/components/viewer.ts index e37a7df0..1d3b4694 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -12,6 +12,8 @@ import { ifDefined } from 'lit/directives/if-defined.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js'; import { CameraManager } from '../camera-manager/manager.js'; import { MediaGridSelected } from '../components-lib/media-grid-controller.js'; +import { ZoomDefault } from '../components-lib/zoom/types.js'; +import { handleZoomDefaultEvent } from '../components-lib/zoom/zoom-view-context.js'; import { dispatchMessageEvent, renderMessage, @@ -484,7 +486,7 @@ export class FrigateCardViewerCarousel extends LitElement { stopEventFromActivatingCardWideActions(ev); }} > - ${guard(this._media, () => this._getSlides())} + ${guard([this._media, this.view], () => this._getSlides())} + cameraConfig?.dimensions?.layout + ? { + pan: cameraConfig.dimensions.layout.pan, + zoom: cameraConfig.dimensions.layout.zoom, + } + : undefined, + )} + .config=${mediaID ? this.view?.context?.zoom?.[mediaID]?.zoom : undefined} @frigate-card:zoom:zoomed=${() => this.setControls(false)} @frigate-card:zoom:unzoomed=${() => this.setControls()} + @frigate-card:zoom:default=${(ev: CustomEvent) => + handleZoomDefaultEvent(this, ev, mediaID)} > ${template} ` diff --git a/src/components/zoomer.ts b/src/components/zoomer.ts index 111c7bb5..7c690060 100644 --- a/src/components/zoomer.ts +++ b/src/components/zoomer.ts @@ -6,13 +6,20 @@ import { PropertyValues, TemplateResult, } from 'lit'; -import { customElement, state } from 'lit/decorators.js'; -import { ZoomController } from '../components-lib/zoom-controller.js'; +import { customElement, property, state } from 'lit/decorators.js'; +import { ZoomConfig } from '../components-lib/zoom/types.js'; +import { ZoomController } from '../components-lib/zoom/zoom-controller.js'; import { setOrRemoveAttribute } from '../utils/basic.js'; @customElement('frigate-card-zoomer') export class FrigateCardZoomer extends LitElement { - protected _zoom = new ZoomController(this); + protected _zoom: ZoomController | null = null; + + @property({ attribute: false }) + public defaultConfig?: ZoomConfig; + + @property({ attribute: false }) + public config?: ZoomConfig | null; @state() protected _zoomed = false; @@ -24,11 +31,13 @@ export class FrigateCardZoomer extends LitElement { super.connectedCallback(); this.addEventListener('frigate-card:zoom:zoomed', this._zoomHandler); this.addEventListener('frigate-card:zoom:unzoomed', this._unzoomHandler); - this._zoom.activate(); + + // Call for an update to activate. + this.requestUpdate(); } disconnectedCallback(): void { - this._zoom.deactivate(); + this._zoom?.deactivate(); this.removeEventListener('frigate-card:zoom:zoomed', this._zoomHandler); this.removeEventListener('frigate-card:zoom:unzoomed', this._unzoomHandler); } @@ -37,7 +46,26 @@ export class FrigateCardZoomer extends LitElement { if (changedProps.has('_zoomed')) { setOrRemoveAttribute(this, this._zoomed, 'zoomed'); } + + if (this._zoom) { + if (changedProps.has('defaultConfig')) { + this._zoom.setDefaultConfig(this.defaultConfig ?? null); + } + // If config is null, make no change to the zoom. + if (changedProps.has('config') && this.config) { + this._zoom.setConfig(this.config); + } + } else { + // Ensure that the configuration will be set before activation (vs + // activating in `connectedCallback`). + this._zoom = new ZoomController(this, { + config: this.config, + defaultConfig: this.defaultConfig, + }); + this._zoom.activate(); + } } + protected render(): TemplateResult | void { return html` `; } diff --git a/src/config/types.ts b/src/config/types.ts index 9c08c061..6f2d6dd3 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -90,6 +90,16 @@ const CAMERA_TRIGGER_EVENT_TYPES = [ ] as const; export type CameraTriggerEventType = (typeof CAMERA_TRIGGER_EVENT_TYPES)[number]; +// ************************************************************************* +// Pan / Zoom +// ************************************************************************* + +const panSchema = z.object({ + x: z.number().min(0).max(100).optional(), + y: z.number().min(0).max(100).optional(), +}); +const zoomSchema = z.number().min(1).max(10); + // ************************************************************************* // View Display Mode // ************************************************************************* @@ -289,15 +299,23 @@ const frigateCardShowPTZActionSchema = frigateCardCustomActionsBaseSchema.extend show_ptz: z.boolean(), }); +const frigateCardChangeZoomActionSchema = frigateCardCustomActionsBaseSchema.extend({ + frigate_card_action: z.literal('change_zoom'), + target_id: z.string(), + zoom: zoomSchema.optional(), + pan: panSchema.optional(), +}); + export const frigateCardCustomActionSchema = z.union([ - frigateCardViewActionSchema, - frigateCardGeneralActionSchema, frigateCardCameraSelectActionSchema, + frigateCardChangeZoomActionSchema, + frigateCardGeneralActionSchema, frigateCardLiveDependencySelectActionSchema, frigateCardMediaPlayerActionSchema, - frigateCardViewDisplayModeActionSchema, frigateCardPTZActionSchema, frigateCardShowPTZActionSchema, + frigateCardViewActionSchema, + frigateCardViewDisplayModeActionSchema, ]); export type FrigateCardCustomAction = z.infer; @@ -626,6 +644,8 @@ const mediaLayoutConfigSchema = z.object({ top: z.number().min(0).max(100).optional().default(0), }) .optional(), + pan: panSchema.optional(), + zoom: zoomSchema.optional(), }); export type MediaLayoutConfig = z.infer; @@ -1345,22 +1365,20 @@ const hiddenButtonDefault = { }; const menuConfigDefault = { - style: 'hidden' as const, - position: 'top' as const, alignment: 'left' as const, + button_size: 40, buttons: { - frigate: visibleButtonDefault, - cameras: visibleButtonDefault, - substreams: visibleButtonDefault, - live: visibleButtonDefault, - clips: visibleButtonDefault, - snapshots: visibleButtonDefault, - image: hiddenButtonDefault, - timeline: visibleButtonDefault, - download: visibleButtonDefault, camera_ui: visibleButtonDefault, - fullscreen: visibleButtonDefault, + cameras: visibleButtonDefault, + clips: visibleButtonDefault, + default_zoom: visibleButtonDefault, + display_mode: visibleButtonDefault, + download: visibleButtonDefault, expand: hiddenButtonDefault, + frigate: visibleButtonDefault, + fullscreen: visibleButtonDefault, + image: hiddenButtonDefault, + live: visibleButtonDefault, media_player: visibleButtonDefault, microphone: { ...hiddenButtonDefault, @@ -1368,12 +1386,15 @@ const menuConfigDefault = { }, mute: hiddenButtonDefault, play: hiddenButtonDefault, + ptz: hiddenButtonDefault, recordings: hiddenButtonDefault, screenshot: hiddenButtonDefault, - display_mode: visibleButtonDefault, - ptz: hiddenButtonDefault, + snapshots: visibleButtonDefault, + substreams: visibleButtonDefault, + timeline: visibleButtonDefault, }, - button_size: 40, + position: 'top' as const, + style: 'hidden' as const, }; const visibleButtonSchema = menuBaseSchema.extend({ @@ -1393,18 +1414,21 @@ export const menuConfigSchema = z alignment: z.enum(FRIGATE_MENU_ALIGNMENTS).default(menuConfigDefault.alignment), buttons: z .object({ - frigate: visibleButtonSchema.default(menuConfigDefault.buttons.frigate), - cameras: visibleButtonSchema.default(menuConfigDefault.buttons.cameras), - substreams: visibleButtonSchema.default(menuConfigDefault.buttons.substreams), - live: visibleButtonSchema.default(menuConfigDefault.buttons.live), - clips: visibleButtonSchema.default(menuConfigDefault.buttons.clips), - snapshots: visibleButtonSchema.default(menuConfigDefault.buttons.snapshots), - image: hiddenButtonSchema.default(menuConfigDefault.buttons.image), - timeline: visibleButtonSchema.default(menuConfigDefault.buttons.timeline), - download: visibleButtonSchema.default(menuConfigDefault.buttons.download), camera_ui: visibleButtonSchema.default(menuConfigDefault.buttons.camera_ui), - fullscreen: visibleButtonSchema.default(menuConfigDefault.buttons.fullscreen), + cameras: visibleButtonSchema.default(menuConfigDefault.buttons.cameras), + clips: visibleButtonSchema.default(menuConfigDefault.buttons.clips), + default_zoom: visibleButtonSchema.default( + menuConfigDefault.buttons.default_zoom, + ), + display_mode: visibleButtonSchema.default( + menuConfigDefault.buttons.display_mode, + ), + download: visibleButtonSchema.default(menuConfigDefault.buttons.download), expand: hiddenButtonSchema.default(menuConfigDefault.buttons.expand), + frigate: visibleButtonSchema.default(menuConfigDefault.buttons.frigate), + fullscreen: visibleButtonSchema.default(menuConfigDefault.buttons.fullscreen), + image: hiddenButtonSchema.default(menuConfigDefault.buttons.image), + live: visibleButtonSchema.default(menuConfigDefault.buttons.live), media_player: visibleButtonSchema.default( menuConfigDefault.buttons.media_player, ), @@ -1415,14 +1439,14 @@ export const menuConfigSchema = z .default(menuConfigDefault.buttons.microphone.type), }) .default(menuConfigDefault.buttons.microphone), - recordings: hiddenButtonSchema.default(menuConfigDefault.buttons.recordings), mute: hiddenButtonSchema.default(menuConfigDefault.buttons.mute), play: hiddenButtonSchema.default(menuConfigDefault.buttons.play), - screenshot: hiddenButtonSchema.default(menuConfigDefault.buttons.screenshot), - display_mode: visibleButtonSchema.default( - menuConfigDefault.buttons.display_mode, - ), ptz: hiddenButtonSchema.default(menuConfigDefault.buttons.ptz), + recordings: hiddenButtonSchema.default(menuConfigDefault.buttons.recordings), + screenshot: hiddenButtonSchema.default(menuConfigDefault.buttons.screenshot), + snapshots: visibleButtonSchema.default(menuConfigDefault.buttons.snapshots), + substreams: visibleButtonSchema.default(menuConfigDefault.buttons.substreams), + timeline: visibleButtonSchema.default(menuConfigDefault.buttons.timeline), }) .default(menuConfigDefault.buttons), button_size: z.number().min(BUTTON_SIZE_MIN).default(menuConfigDefault.button_size), diff --git a/src/const.ts b/src/const.ts index d39d45aa..b3d9c9ec 100644 --- a/src/const.ts +++ b/src/const.ts @@ -57,6 +57,10 @@ export const CONF_CAMERAS_ARRAY_DEPENDENCIES_ALL_CAMERAS = `${CONF_CAMERAS}.#.dependencies.all_cameras` as const; export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_FIT = `${CONF_CAMERAS}.#.dimensions.layout.fit` as const; + export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_PAN_X = + `${CONF_CAMERAS}.#.dimensions.layout.pan.x` as const; +export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_PAN_Y = + `${CONF_CAMERAS}.#.dimensions.layout.pan.y` as const; export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_X = `${CONF_CAMERAS}.#.dimensions.layout.position.x` as const; export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_Y = @@ -69,6 +73,8 @@ export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_LEFT = `${CONF_CAMERAS}.#.dimensions.layout.view_box.left` as const; export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_RIGHT = `${CONF_CAMERAS}.#.dimensions.layout.view_box.right` as const; +export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_ZOOM_FACTOR = + `${CONF_CAMERAS}.#.dimensions.layout.zoom` as const; export const CONF_CAMERAS_ARRAY_TRIGGERS_MOTION = `${CONF_CAMERAS}.#.triggers.motion` as const; export const CONF_CAMERAS_ARRAY_TRIGGERS_OCCUPANCY = diff --git a/src/editor.ts b/src/editor.ts index 0b9adc74..f79390e8 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -44,12 +44,15 @@ import { CONF_CAMERAS_ARRAY_DEPENDENCIES_CAMERAS, CONF_CAMERAS_ARRAY_DIMENSIONS_ASPECT_RATIO, CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_FIT, + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_PAN_X, + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_PAN_Y, CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_X, CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_POSITION_Y, CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_BOTTOM, CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_LEFT, CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_RIGHT, CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_VIEW_BOX_TOP, + CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_ZOOM_FACTOR, CONF_CAMERAS_ARRAY_FRIGATE_CAMERA_NAME, CONF_CAMERAS_ARRAY_FRIGATE_CLIENT_ID, CONF_CAMERAS_ARRAY_FRIGATE_LABELS, @@ -817,9 +820,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor } } - /** - * Called before each update. - */ protected willUpdate(): void { if (!this._initialized) { sideLoadHomeAssistantElements().then((success) => { @@ -981,6 +981,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor max?: number; label?: string; default?: number; + step?: number; }, ): TemplateResult | void { if (!this._config) { @@ -992,7 +993,14 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor return html` ` : ''} diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json index 7890348b..f6bd7c74 100644 --- a/src/localize/languages/ca.json +++ b/src/localize/languages/ca.json @@ -55,6 +55,10 @@ "cover": "El suport s'expandeix proporcionalment per cobrir la targeta", "fill": "El suport s'estira per omplir la targeta" }, + "pan": { + "x": "", + "y": "" + }, "position": { "editor_label": "", "x": "Percentatge d'emplaçament horitzontal", @@ -66,7 +70,8 @@ "left": "", "right": "", "top": "" - } + }, + "zoom": "" } }, "engines": { @@ -357,6 +362,7 @@ "camera_ui": "Interfície d'usuari de la càmera", "cameras": "Càmeres", "clips": "Clips", + "default_zoom": "", "display_mode": "Mode de visualització", "download": "Descarregar", "enabled": "Botó habilitat", diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 61b48940..d145acab 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -55,6 +55,10 @@ "cover": "Media expands proportionally to cover the card", "fill": "Media is stretched to fill the card" }, + "pan": { + "x": "Pan horizontal percentage", + "y": "Pan vertical percentage" + }, "position": { "editor_label": "Layout Cover Position", "x": "Horizontal placement percentage", @@ -66,7 +70,8 @@ "left": "Left inset percentage", "right": "Right inset percentage", "top": "Top inset percentage" - } + }, + "zoom": "Zoom factor" } }, "engines": { @@ -357,6 +362,7 @@ "camera_ui": "Camera user interface", "cameras": "Cameras", "clips": "Clips", + "default_zoom": "Zoom to default", "display_mode": "Display mode", "download": "Download", "enabled": "Button enabled", diff --git a/src/localize/languages/fr.json b/src/localize/languages/fr.json index 806ed481..0c639c16 100644 --- a/src/localize/languages/fr.json +++ b/src/localize/languages/fr.json @@ -55,6 +55,10 @@ "cover": "Il supporto si espande proporzionalmente per coprire la scheda", "fill": "Il supporto viene allungato per riempire la scheda" }, + "pan": { + "x": "", + "y": "" + }, "position": { "editor_label": "", "x": "Percentuale di posizionamento orizzontale", @@ -66,7 +70,8 @@ "left": "", "right": "", "top": "" - } + }, + "zoom": "" } }, "engines": { @@ -357,6 +362,7 @@ "camera_ui": "Interface utilisateur de la caméra", "cameras": "Appareils photo", "clips": "Extraits", + "default_zoom": "", "display_mode": "", "download": "Télécharger", "enabled": "Bouton activé", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index b55a68e3..cf078f21 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -55,6 +55,10 @@ "cover": "Il supporto si espande proporzionalmente per coprire la scheda", "fill": "Il supporto viene allungato per riempire la scheda" }, + "pan": { + "x": "", + "y": "" + }, "position": { "editor_label": "", "x": "Percentuale di posizionamento orizzontale", @@ -66,7 +70,8 @@ "left": "", "right": "", "top": "" - } + }, + "zoom": "" } }, "engines": { @@ -357,6 +362,7 @@ "camera_ui": "Interfaccia utente della fotocamera", "cameras": "Telecamere", "clips": "Clip", + "default_zoom": "", "display_mode": "", "download": "Download", "enabled": "Pulsante abilitato", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index fb1fb510..ad57b80a 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -55,6 +55,10 @@ "cover": "A mídia se expande proporcionalmente para cobrir o cartão", "fill": "A mídia é esticada para preencher o cartão" }, + "pan": { + "x": "", + "y": "" + }, "position": { "editor_label": "", "x": "Porcentagem do posicionamento horizontal", @@ -66,7 +70,8 @@ "left": "", "right": "", "top": "" - } + }, + "zoom": "" } }, "engines": { @@ -357,6 +362,7 @@ "camera_ui": "Interface de usuário da câmera", "cameras": "Selecionar câmera", "clips": "Clipes", + "default_zoom": "", "display_mode": "", "download": "Baixe a mídia do evento", "enabled": "Botão ativado", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 2bee1366..46cd0f18 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -55,6 +55,10 @@ "cover": "Tapar", "fill": "Preencher" }, + "pan": { + "x": "", + "y": "" + }, "position": { "editor_label": "", "x": "Percentagem da localização horizontal", @@ -66,7 +70,8 @@ "left": "", "right": "", "top": "" - } + }, + "zoom": "" } }, "engines": { @@ -357,6 +362,7 @@ "camera_ui": "Camera", "cameras": "Selecionar câmera", "clips": "Clipes", + "default_zoom": "", "display_mode": "", "download": "Descarregar mídia do evento", "enabled": "Botão ativado", diff --git a/src/scss/live-image.scss b/src/scss/live-image.scss deleted file mode 100644 index e3950e11..00000000 --- a/src/scss/live-image.scss +++ /dev/null @@ -1,13 +0,0 @@ -:host { - width: 100%; - height: 100%; - display: block; - position: relative; -} - -ha-icon { - position: absolute; - top: 10px; - right: 10px; - color: var(--primary-color); -} diff --git a/src/scss/live-provider.scss b/src/scss/live-provider.scss index 15c43662..468bf011 100644 --- a/src/scss/live-provider.scss +++ b/src/scss/live-provider.scss @@ -2,8 +2,16 @@ display: block; height: 100%; width: 100%; + position: relative; } .hidden { display: none; } + +ha-icon { + position: absolute; + top: 10px; + right: 10px; + color: var(--primary-color); +} diff --git a/src/utils/action.ts b/src/utils/action.ts index 01b39f78..cb4e2b18 100644 --- a/src/utils/action.ts +++ b/src/utils/action.ts @@ -102,6 +102,27 @@ export function createFrigateCardShowPTZAction( }; } +export function createFrigateCardChangeZoomAction( + targetID: string, + options?: { + cardID?: string; + pan?: { + x?: number; + y?: number; + }; + zoom?: number; + }, +): FrigateCardCustomAction { + return { + action: 'fire-dom-event', + frigate_card_action: 'change_zoom', + target_id: targetID, + ...(options?.cardID && { card_id: options.cardID }), + ...(options?.pan && { pan: options.pan }), + ...(options?.zoom && { zoom: options.zoom }), + }; +} + /** * Get an action configuration given a config and an interaction (e.g. 'tap'). * @param interaction The interaction: `tap`, `hold` or `double_tap` diff --git a/src/utils/basic.ts b/src/utils/basic.ts index a31f1223..99f16855 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -3,7 +3,8 @@ import differenceInMinutes from 'date-fns/differenceInMinutes'; import differenceInSeconds from 'date-fns/differenceInSeconds'; import format from 'date-fns/format'; import { StyleInfo } from 'lit/directives/style-map'; -import isEqual from 'lodash-es/isEqual'; +import { round } from 'lodash-es'; +import isEqualWith from 'lodash-es/isEqualWith'; import mergeWith from 'lodash-es/mergeWith'; import { FrigateCardError } from '../types'; @@ -87,8 +88,12 @@ export const setify = (value: T | T[] | Set): Set => { * @param o The old value. * @returns `true` is the contents have changed. */ -export function contentsChanged(n: unknown, o: unknown): boolean { - return !isEqual(n, o); +export function contentsChanged( + n: unknown, + o: unknown, + customizer?: (a: unknown, b: unknown) => boolean | undefined, +): boolean { + return !isEqualWith(n, o, customizer); } /** @@ -286,3 +291,24 @@ export const desparsifyArrays = (data: T): T => { } return data; }; + +export const arefloatsApproximatelyEqual = ( + a: number, + b: number, + precision?: number, +): boolean => { + return round(a, precision) === round(b, precision); +}; + +/** + * Create a lodash isEqualsWith customizer that can compare floats. + */ +export const generateFloatApproximatelyEqualsCustomizer = ( + precision: number, +): ((a: unknown, b: unknown) => boolean | undefined) => { + return (a: unknown, b: unknown) => { + return typeof a === 'number' && typeof b === 'number' + ? arefloatsApproximatelyEqual(a, b, precision) + : undefined; + }; +}; diff --git a/src/view/view.ts b/src/view/view.ts index 03dbfeec..9e9e54e6 100644 --- a/src/view/view.ts +++ b/src/view/view.ts @@ -177,7 +177,7 @@ export class View { * @param context The context to merge in. * @returns This view. */ - public mergeInContext(context?: ViewContext): View { + public mergeInContext(context?: ViewContext | null): View { this.context = merge({}, this.context, context); return this; } @@ -306,7 +306,7 @@ export interface FrigateCardViewChangeEventTarget extends EventTarget { */ export const dispatchViewContextChangeEvent = ( target: EventTarget, - context: ViewContext, + context: ViewContext | null, ): void => { dispatchFrigateCardEvent(target, 'view:change-context', context); }; diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts index 6a0a2258..6c69a6fb 100644 --- a/tests/camera-manager/manager.test.ts +++ b/tests/camera-manager/manager.test.ts @@ -259,16 +259,9 @@ describe('CameraManager', async () => { return new CameraManager(api, { factory: mockFactory }); }; - it('should reset', async () => { - const store = new CameraManagerStore(); - store.addCamera( - new Camera(createCameraConfig({ id: 'id' }), mock()), - ); - const manager = new CameraManager(createCardAPI(), { store: store }); - - expect(manager.getStore().getCameraCount()).toBe(1); - await manager.reset(); - expect(manager.getStore().getCameraCount()).toBe(0); + it('should construct', async () => { + const manager = new CameraManager(createCardAPI()); + expect(manager.getStore()).toBeTruthy(); }); describe('should initialize cameras from config', () => { diff --git a/tests/card-controller/actions-manager.test.ts b/tests/card-controller/actions-manager.test.ts index 8b11b640..0da864a7 100644 --- a/tests/card-controller/actions-manager.test.ts +++ b/tests/card-controller/actions-manager.test.ts @@ -196,7 +196,6 @@ describe('ActionsManager.handleInteraction', () => { manager.handleInteractionEvent( new CustomEvent('event', { - // Malformed interaction type. detail: { action: 'double_finger_snap' } as unknown as Interaction, }), @@ -800,11 +799,68 @@ describe('ActionsManager.executeAction', () => { })!, ); - expect(api.getViewManager().setViewWithNewContext).toBeCalledWith( + expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith( expect.objectContaining({ live: { ptzVisible: true } }), ); }); + describe('should handle change_zoom action', () => { + it('default', async () => { + const api = createCardAPI(); + const manager = new ActionsManager(api); + + await manager.executeFrigateAction( + createAction({ + frigate_card_action: 'change_zoom', + target_id: 'camera.office', + })!, + ); + + expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith( + expect.objectContaining({ + zoom: { + 'camera.office': { + zoom: {}, + }, + }, + }), + ); + }); + + it('non-default', async () => { + const api = createCardAPI(); + const manager = new ActionsManager(api); + + await manager.executeFrigateAction( + createAction({ + frigate_card_action: 'change_zoom', + target_id: 'camera.office', + zoom: 2, + pan: { + x: 3, + y: 4, + }, + })!, + ); + + expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith( + expect.objectContaining({ + zoom: { + 'camera.office': { + zoom: { + zoom: 2, + pan: { + x: 3, + y: 4, + }, + }, + }, + }, + }), + ); + }); + }); + it('should handle unknown action', async () => { const manager = new ActionsManager(createCardAPI()); diff --git a/tests/card-controller/card-element-manager.test.ts b/tests/card-controller/card-element-manager.test.ts index 82f9392b..664c1faa 100644 --- a/tests/card-controller/card-element-manager.test.ts +++ b/tests/card-controller/card-element-manager.test.ts @@ -149,7 +149,6 @@ describe('CardElementManager', () => { element.removeEventListener = removeEventListener; const api = createCardAPI(); - vi.mocked(api.getCameraManager().reset).mockResolvedValue(); const manager = new CardElementManager( api, @@ -186,6 +185,6 @@ describe('CardElementManager', () => { ); expect(windowRemoveEventListener).toBeCalledWith('popstate', expect.anything()); - expect(api.getCameraManager().reset).toBeCalled(); + expect(api.getInitializationManager().uninitialize).toBeCalledWith('cameras'); }); }); diff --git a/tests/card-controller/initialization-manager.test.ts b/tests/card-controller/initialization-manager.test.ts index 7abc77b0..6ba18553 100644 --- a/tests/card-controller/initialization-manager.test.ts +++ b/tests/card-controller/initialization-manager.test.ts @@ -1,10 +1,10 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; -import { loadLanguages } from '../../src/localize/localize'; import { InitializationAspect, InitializationManager, } from '../../src/card-controller/initialization-manager'; +import { loadLanguages } from '../../src/localize/localize'; import { sideLoadHomeAssistantElements } from '../../src/utils/ha'; import { Initializer } from '../../src/utils/initializer/initializer'; import { createCardAPI, createConfig, createHASS } from '../test-utils'; @@ -184,6 +184,22 @@ describe('InitializationManager', () => { expect(await manager.initializeMandatory()).toBeFalsy(); }); + + it('with existing view', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + vi.mocked(api.getViewManager().hasView).mockReturnValue(true); + + const initializer = mock(); + const manager = new InitializationManager(api, initializer); + initializer.initializeMultipleIfNecessary + .mockResolvedValueOnce(true) + .mockResolvedValueOnce(true); + + expect(await manager.initializeMandatory()).toBeTruthy(); + expect(api.getCardElementManager().update).toBeCalled(); + }); }); describe('should initialize background', () => { diff --git a/tests/card-controller/view-manager.test.ts b/tests/card-controller/view-manager.test.ts index f1395938..c0bed650 100644 --- a/tests/card-controller/view-manager.test.ts +++ b/tests/card-controller/view-manager.test.ts @@ -81,7 +81,7 @@ describe('ViewManager.setView', () => { const context = { live: { fetchThumbnails: false } }; // Setting context with no existing view does nothing. - manager.setViewWithNewContext(context); + manager.setViewWithMergedContext(context); expect(manager.getView()).toBeNull(); const view = createView({ @@ -89,7 +89,7 @@ describe('ViewManager.setView', () => { camera: 'camera', }); manager.setView(view); - manager.setViewWithNewContext(context); + manager.setViewWithMergedContext(context); expect(manager.getView()?.camera).toBe('camera'); expect(manager.getView()?.view).toBe('live'); diff --git a/tests/components-lib/menu-button-controller.test.ts b/tests/components-lib/menu-button-controller.test.ts index daba7957..f7bdc4e7 100644 --- a/tests/components-lib/menu-button-controller.test.ts +++ b/tests/components-lib/menu-button-controller.test.ts @@ -11,7 +11,12 @@ import { MenuButtonController, MenuButtonControllerOptions, } from '../../src/components-lib/menu-button-controller'; -import { FrigateCardConfig, MenuItem, ViewDisplayMode } from '../../src/config/types'; +import { + FrigateCardConfig, + FrigateCardView, + MenuItem, + ViewDisplayMode, +} from '../../src/config/types'; import { FrigateCardMediaPlayer } from '../../src/types'; import { createFrigateCardSimpleAction } from '../../src/utils/action'; import { ViewMedia } from '../../src/view/media'; @@ -29,6 +34,7 @@ import { createStateEntity, createStore, createView, + TestViewMedia, } from '../test-utils'; vi.mock('../../src/utils/media-player-controller.js'); @@ -1487,6 +1493,69 @@ describe('MenuButtonController', () => { }); }); + describe('should have change zoom button', () => { + it.each([ + ['live' as const, true, false], + ['live' as const, undefined, false], + ['live' as const, false, true], + ['media' as const, true, false], + ['media' as const, undefined, false], + ['media' as const, false, true], + ])( + '%s view with isDefault %s', + ( + viewName: FrigateCardView, + isDefault: boolean | undefined, + expectedResult: boolean, + ) => { + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue( + createStore([{ cameraID: 'camera-1' }]), + ); + + const targetID = viewName === 'live' ? 'camera-1' : 'media-1'; + const view = createView({ + view: viewName, + camera: 'camera-1', + queryResults: new MediaQueriesResults({ + results: [new TestViewMedia({ id: 'media-1' })], + selectedIndex: 0, + }), + context: { + zoom: { + [targetID]: { + isDefault: isDefault, + }, + }, + }, + }); + const buttons = calculateButtons(controller, { + cameraManager: cameraManager, + view: view, + }); + + if (expectedResult) { + expect(buttons).toContainEqual({ + enabled: true, + icon: 'mdi:magnify-close', + priority: 50, + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'change_zoom', + target_id: targetID, + }, + title: 'Zoom to default', + type: 'custom:frigate-card-menu-icon', + }); + } else { + expect(buttons).not.toContainEqual( + expect.objectContaining({ title: 'Set zoom to default' }), + ); + } + }, + ); + }); + describe('should handle dynamic buttons', () => { it('successfully', () => { const button: MenuItem = { diff --git a/tests/components-lib/zoom-controller.test.ts b/tests/components-lib/zoom-controller.test.ts deleted file mode 100644 index e040e4d1..00000000 --- a/tests/components-lib/zoom-controller.test.ts +++ /dev/null @@ -1,321 +0,0 @@ -import Panzoom, { PanzoomEventDetail, PanzoomObject } from '@dermotduffy/panzoom'; -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { mock } from 'vitest-mock-extended'; -import { ZoomController } from '../../src/components-lib/zoom-controller'; - -vi.mock('@dermotduffy/panzoom'); - -// https://github.com/jsdom/jsdom/issues/2527 -(window as any).PointerEvent = MouseEvent; - -// @vitest-environment jsdom -describe('ZoomController', () => { - const mediaMediSpy = vi.spyOn(window, 'matchMedia'); - - const createMockPanZoom = (): PanzoomObject => { - const panzoom = mock(); - panzoom.getScale.mockReturnValue(1.0); - return panzoom; - }; - - const createAndRegisterZoom = (element: HTMLElement): ZoomController => { - const zoom = new ZoomController(element); - zoom.activate(); - return zoom; - }; - - const createTouch = (target: HTMLElement): Touch => { - return { - clientX: 0, - clientY: 0, - force: 0, - identifier: 0, - pageX: 0, - pageY: 0, - radiusX: 0, - radiusY: 0, - rotationAngle: 0, - screenX: 0, - screenY: 0, - target: target, - }; - }; - - beforeEach(() => { - mediaMediSpy.mockReturnValue({ matches: true }); - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - it('should be creatable', () => { - const element = document.createElement('div'); - const zoom = new ZoomController(element); - expect(zoom).toBeTruthy(); - }); - - it('should respond with pointer', () => { - const element = document.createElement('div'); - - const panzoom = createMockPanZoom(); - vi.mocked(Panzoom).mockReturnValueOnce(panzoom); - - createAndRegisterZoom(element); - - // Won't zoom without control key. - const ev_1 = new WheelEvent('wheel', { bubbles: false, deltaY: -120 }); - element.dispatchEvent(ev_1); - expect(panzoom.zoomWithWheel).not.toBeCalled(); - - const ev_2 = new WheelEvent('wheel', { - bubbles: false, - deltaY: -120, - ctrlKey: true, - }); - element.dispatchEvent(ev_2); - expect(panzoom.zoomWithWheel).toBeCalledWith(ev_2); - - panzoom.getScale = vi.fn().mockReturnValue(1.2); - - const ev_3 = new PointerEvent('pointerdown'); - element.dispatchEvent(ev_3); - expect(panzoom.handleDown).toBeCalledWith(ev_3); - - const ev_4 = new PointerEvent('pointermove'); - element.dispatchEvent(ev_4); - expect(panzoom.handleMove).toBeCalledWith(ev_4); - - const ev_5 = new PointerEvent('pointerup'); - element.dispatchEvent(ev_5); - expect(panzoom.handleUp).toBeCalledWith(ev_5); - }); - - it('should not respond to pointer when not zoomed', () => { - const element = document.createElement('div'); - - const panzoom = createMockPanZoom(); - vi.mocked(Panzoom).mockReturnValueOnce(panzoom); - - createAndRegisterZoom(element); - - const ev_1 = new PointerEvent('pointerdown'); - element.dispatchEvent(ev_1); - expect(panzoom.handleDown).not.toBeCalledWith(ev_1); - - const ev_2 = new PointerEvent('pointermove'); - element.dispatchEvent(ev_2); - expect(panzoom.handleDown).not.toBeCalledWith(ev_2); - - const ev_3 = new PointerEvent('pointerup'); - element.dispatchEvent(ev_3); - expect(panzoom.handleDown).not.toBeCalledWith(ev_3); - }); - - it('should respond with touch', () => { - mediaMediSpy.mockReturnValue({ matches: false }); - - const element = document.createElement('div'); - - const panzoom = createMockPanZoom(); - vi.mocked(Panzoom).mockReturnValueOnce(panzoom); - - createAndRegisterZoom(element); - - const ev_1 = new TouchEvent('touchstart', { - bubbles: false, - touches: [createTouch(element), createTouch(element)], - }); - element.dispatchEvent(ev_1); - expect(panzoom.handleDown).toBeCalledWith(ev_1); - - panzoom.getScale = vi.fn().mockReturnValue(1.2); - - const ev_3 = new TouchEvent('touchstart'); - element.dispatchEvent(ev_3); - expect(panzoom.handleDown).toBeCalledWith(ev_3); - - const ev_4 = new TouchEvent('touchmove'); - element.dispatchEvent(ev_4); - expect(panzoom.handleMove).toBeCalledWith(ev_4); - - const ev_5 = new TouchEvent('touchend'); - element.dispatchEvent(ev_5); - expect(panzoom.handleUp).toBeCalledWith(ev_5); - }); - - it('should ignore click after pointerdown', () => { - const outer = document.createElement('div'); - const inner = document.createElement('div'); - outer.appendChild(inner); - const clickHandler = vi.fn(); - outer.addEventListener('click', clickHandler); - - const panzoom = createMockPanZoom(); - vi.mocked(Panzoom).mockReturnValueOnce(panzoom); - - createAndRegisterZoom(inner); - - // Simulate being zoomed in. - panzoom.getScale = vi.fn().mockReturnValue(1.2); - - // A click on its own will be fine. - const click_1 = new MouseEvent('click', { bubbles: true }); - inner.dispatchEvent(click_1); - expect(clickHandler).toBeCalledTimes(1); - - // A click after a pointerdown will be ignored. - const pointerdown_1 = new PointerEvent('pointerdown'); - inner.dispatchEvent(pointerdown_1); - - const click_2 = new MouseEvent('click', { bubbles: true }); - inner.dispatchEvent(click_2); - - // Click will have been ignored. - expect(clickHandler).toBeCalledTimes(1); - - // Simulate being zoomed out. - panzoom.getScale = vi.fn().mockReturnValue(1.0); - const pointerdown_2 = new PointerEvent('pointerdown'); - inner.dispatchEvent(pointerdown_2); - - const click_3 = new MouseEvent('click', { bubbles: true }); - inner.dispatchEvent(click_3); - - // Click will have been processed. - expect(clickHandler).toBeCalledTimes(2); - }); - - it('deactivate should remove event handlers', () => { - const element = document.createElement('div'); - - const panzoom = createMockPanZoom(); - vi.mocked(Panzoom).mockReturnValueOnce(panzoom); - - createAndRegisterZoom(element).deactivate(); - - const ev_1 = new WheelEvent('wheel', { - bubbles: false, - deltaY: -120, - ctrlKey: true, - }); - element.dispatchEvent(ev_1); - expect(panzoom.zoomWithWheel).not.toBeCalled(); - }); - - it('should fire frigate cards on zoom/unzoom', () => { - const element = document.createElement('div'); - - const zoomedFunc = vi.fn(); - const unzoomedFunc = vi.fn(); - - element.addEventListener('frigate-card:zoom:zoomed', zoomedFunc); - element.addEventListener('frigate-card:zoom:unzoomed', unzoomedFunc); - - vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); - - createAndRegisterZoom(element); - - const ev_1 = new CustomEvent('panzoomzoom', { - detail: { - x: 0, - y: 0, - scale: 1.2, - isSVG: false, - originalEvent: new PointerEvent('pointermove'), - }, - }); - element.dispatchEvent(ev_1); - expect(zoomedFunc).toBeCalled(); - expect(unzoomedFunc).not.toBeCalled(); - - const ev_2 = new CustomEvent('panzoomzoom', { - detail: { - x: 0, - y: 0, - scale: 1, - isSVG: false, - originalEvent: new PointerEvent('pointermove'), - }, - }); - element.dispatchEvent(ev_2); - expect(unzoomedFunc).toBeCalled(); - }); - - it('should set touch action on zoom/unzoom', () => { - const element = document.createElement('div'); - vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); - - createAndRegisterZoom(element); - - const ev_1 = new CustomEvent('panzoomzoom', { - detail: { - x: 0, - y: 0, - scale: 1.2, - isSVG: false, - originalEvent: new PointerEvent('pointermove'), - }, - }); - element.dispatchEvent(ev_1); - expect(element.style.touchAction).toBe('none'); - - const ev_2 = new CustomEvent('panzoomzoom', { - detail: { - x: 0, - y: 0, - scale: 1, - isSVG: false, - originalEvent: new PointerEvent('pointermove'), - }, - }); - element.dispatchEvent(ev_2); - expect(element.style.touchAction).toBeFalsy(); - }); - - it('should not fire frigate cards when state has not changed or spurious events received', () => { - const element = document.createElement('div'); - - const zoomedFunc = vi.fn(); - const unzoomedFunc = vi.fn(); - - element.addEventListener('frigate-card:zoom:zoomed', zoomedFunc); - element.addEventListener('frigate-card:zoom:unzoomed', unzoomedFunc); - - vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); - - createAndRegisterZoom(element); - - const ev_1 = new CustomEvent('panzoomzoom', { - detail: { - x: 0, - y: 0, - scale: 1, - isSVG: false, - originalEvent: new PointerEvent('pointermove'), - }, - }); - element.dispatchEvent(ev_1); - - // Unzoomed event with scale === 1, this._zoomed will already be false. - expect(unzoomedFunc).not.toBeCalled(); - expect(zoomedFunc).not.toBeCalled(); - - const ev_2 = new CustomEvent('panzoomzoom', { - detail: { - x: 0, - y: 0, - scale: 1.2, - isSVG: false, - originalEvent: new PointerEvent('pointermove'), - }, - }); - element.dispatchEvent(ev_2); - expect(zoomedFunc).toBeCalledTimes(1); - expect(unzoomedFunc).not.toBeCalled(); - - // Another call when already zoomed will be ignored. - element.dispatchEvent(ev_2); - expect(zoomedFunc).toBeCalledTimes(1); - }); -}); diff --git a/tests/components-lib/zoom/zoom-controller.test.ts b/tests/components-lib/zoom/zoom-controller.test.ts new file mode 100644 index 00000000..46fa22e2 --- /dev/null +++ b/tests/components-lib/zoom/zoom-controller.test.ts @@ -0,0 +1,658 @@ +import Panzoom, { PanzoomEventDetail, PanzoomObject } from '@dermotduffy/panzoom'; +import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { mock, mockClear } from 'vitest-mock-extended'; +import { ZoomController } from '../../../src/components-lib/zoom/zoom-controller'; +import { ResizeObserverMock, requestAnimationFrameMock } from '../../test-utils'; + +vi.mock('@dermotduffy/panzoom'); +vi.mock('lodash-es/debounce', () => ({ + default: vi.fn((fn) => fn), +})); + +// https://github.com/jsdom/jsdom/issues/2527 +// eslint-disable-next-line @typescript-eslint/no-explicit-any +(window as any).PointerEvent = MouseEvent; + +const triggerResizeObserver = (): void => { + const resizeObserverTrigger = vi.mocked(global.ResizeObserver).mock.calls[0][0]; + resizeObserverTrigger([], mock()); +}; + +const setElementToDefaultCardSize = (element: HTMLElement, multiple?: number): void => { + element.getBoundingClientRect = vi.fn().mockReturnValue({ + width: 492 * (multiple ?? 1), + height: 276.75 * (multiple ?? 1), + }); +}; + +// @vitest-environment jsdom +describe('ZoomController', () => { + const mediaSpy = vi.spyOn(window, 'matchMedia'); + + const createMockPanZoom = (): PanzoomObject => { + const panzoom = mock(); + panzoom.getScale.mockReturnValue(1.0); + panzoom.getPan.mockReturnValue({ x: 0, y: 0 }); + return panzoom; + }; + + const createAndRegisterZoom = (element: HTMLElement): ZoomController => { + const zoom = new ZoomController(element); + zoom.activate(); + return zoom; + }; + + const createTouch = (target: HTMLElement): Touch => { + return { + clientX: 0, + clientY: 0, + force: 0, + identifier: 0, + pageX: 0, + pageY: 0, + radiusX: 0, + radiusY: 0, + rotationAngle: 0, + screenX: 0, + screenY: 0, + target: target, + }; + }; + + beforeAll(() => { + vi.stubGlobal('ResizeObserver', ResizeObserverMock); + window.requestAnimationFrame = requestAnimationFrameMock; + }); + + beforeEach(() => { + vi.mocked(Panzoom).mockReset(); + vi.mocked(global.ResizeObserver).mockClear(); + mediaSpy.mockReturnValue({ matches: true }); + }); + + it('should be creatable', () => { + const element = document.createElement('div'); + const zoom = new ZoomController(element); + expect(zoom).toBeTruthy(); + }); + + describe('should pan and zoom', () => { + it('should respond with pointer', () => { + const element = document.createElement('div'); + + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + createAndRegisterZoom(element); + + // Won't zoom without control key. + const ev_1 = new WheelEvent('wheel', { bubbles: false, deltaY: -120 }); + element.dispatchEvent(ev_1); + expect(panzoom.zoomWithWheel).not.toBeCalled(); + + const ev_2 = new WheelEvent('wheel', { + bubbles: false, + deltaY: -120, + ctrlKey: true, + }); + element.dispatchEvent(ev_2); + expect(panzoom.zoomWithWheel).toBeCalledWith(ev_2); + + panzoom.getScale = vi.fn().mockReturnValue(1.2); + + const ev_3 = new PointerEvent('pointerdown'); + element.dispatchEvent(ev_3); + expect(panzoom.handleDown).toBeCalledWith(ev_3); + + const ev_4 = new PointerEvent('pointermove'); + element.dispatchEvent(ev_4); + expect(panzoom.handleMove).toBeCalledWith(ev_4); + + const ev_5 = new PointerEvent('pointerup'); + element.dispatchEvent(ev_5); + expect(panzoom.handleUp).toBeCalledWith(ev_5); + }); + + it('should not respond to pointer when not zoomed', () => { + const element = document.createElement('div'); + + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + createAndRegisterZoom(element); + + const ev_1 = new PointerEvent('pointerdown'); + element.dispatchEvent(ev_1); + expect(panzoom.handleDown).not.toBeCalledWith(ev_1); + + const ev_2 = new PointerEvent('pointermove'); + element.dispatchEvent(ev_2); + expect(panzoom.handleDown).not.toBeCalledWith(ev_2); + + const ev_3 = new PointerEvent('pointerup'); + element.dispatchEvent(ev_3); + expect(panzoom.handleDown).not.toBeCalledWith(ev_3); + }); + + it('should respond with touch', () => { + mediaSpy.mockReturnValue({ matches: false }); + + const element = document.createElement('div'); + + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + createAndRegisterZoom(element); + + const ev_1 = new TouchEvent('touchstart', { + bubbles: false, + touches: [createTouch(element), createTouch(element)], + }); + element.dispatchEvent(ev_1); + expect(panzoom.handleDown).toBeCalledWith(ev_1); + + panzoom.getScale = vi.fn().mockReturnValue(1.2); + + const ev_3 = new TouchEvent('touchstart'); + element.dispatchEvent(ev_3); + expect(panzoom.handleDown).toBeCalledWith(ev_3); + + const ev_4 = new TouchEvent('touchmove'); + element.dispatchEvent(ev_4); + expect(panzoom.handleMove).toBeCalledWith(ev_4); + + const ev_5 = new TouchEvent('touchend'); + element.dispatchEvent(ev_5); + expect(panzoom.handleUp).toBeCalledWith(ev_5); + }); + }); + + it('should ignore click after pointerdown', () => { + const outer = document.createElement('div'); + const inner = document.createElement('div'); + outer.appendChild(inner); + const clickHandler = vi.fn(); + outer.addEventListener('click', clickHandler); + + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + createAndRegisterZoom(inner); + + // Simulate being zoomed in. + panzoom.getScale = vi.fn().mockReturnValue(1.2); + + // A click on its own will be fine. + const click_1 = new MouseEvent('click', { bubbles: true }); + inner.dispatchEvent(click_1); + expect(clickHandler).toBeCalledTimes(1); + + // A click after a pointerdown will be ignored. + const pointerdown_1 = new PointerEvent('pointerdown'); + inner.dispatchEvent(pointerdown_1); + + const click_2 = new MouseEvent('click', { bubbles: true }); + inner.dispatchEvent(click_2); + + // Click will have been ignored. + //expect(clickHandler).toBeCalledTimes(1); + + // Simulate being zoomed out. + panzoom.getScale = vi.fn().mockReturnValue(1.0); + const pointerdown_2 = new PointerEvent('pointerdown'); + inner.dispatchEvent(pointerdown_2); + + const click_3 = new MouseEvent('click', { bubbles: true }); + inner.dispatchEvent(click_3); + + // Click will have been processed. + expect(clickHandler).toBeCalledTimes(2); + }); + + it('deactivate should remove event handlers', () => { + const element = document.createElement('div'); + + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + createAndRegisterZoom(element).deactivate(); + + const ev_1 = new WheelEvent('wheel', { + bubbles: false, + deltaY: -120, + ctrlKey: true, + }); + element.dispatchEvent(ev_1); + expect(panzoom.zoomWithWheel).not.toBeCalled(); + }); + + describe('should fire events', () => { + it('on zoom/unzoom', () => { + const element = document.createElement('div'); + const zoomedFunc = vi.fn(); + const unzoomedFunc = vi.fn(); + element.addEventListener('frigate-card:zoom:zoomed', zoomedFunc); + element.addEventListener('frigate-card:zoom:unzoomed', unzoomedFunc); + + vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); + createAndRegisterZoom(element); + + const ev_1 = new CustomEvent('panzoomchange', { + detail: { + x: 0, + y: 0, + scale: 1.2, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_1); + expect(zoomedFunc).toBeCalled(); + expect(unzoomedFunc).not.toBeCalled(); + + const ev_2 = new CustomEvent('panzoomchange', { + detail: { + x: 0, + y: 0, + scale: 1, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_2); + expect(unzoomedFunc).toBeCalled(); + }); + + it('when state has not changed or spurious events received', () => { + const element = document.createElement('div'); + const zoomedFunc = vi.fn(); + const unzoomedFunc = vi.fn(); + element.addEventListener('frigate-card:zoom:zoomed', zoomedFunc); + element.addEventListener('frigate-card:zoom:unzoomed', unzoomedFunc); + + vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); + createAndRegisterZoom(element); + + const ev_1 = new CustomEvent('panzoomchange', { + detail: { + x: 0, + y: 0, + scale: 1, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_1); + + // Unzoomed event with scale === 1, this._zoomed will already be false. + expect(unzoomedFunc).not.toBeCalled(); + expect(zoomedFunc).not.toBeCalled(); + + const ev_2 = new CustomEvent('panzoomchange', { + detail: { + x: 0, + y: 0, + scale: 1.2, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_2); + expect(zoomedFunc).toBeCalledTimes(1); + expect(unzoomedFunc).not.toBeCalled(); + + // Another call when already zoomed will be ignored. + element.dispatchEvent(ev_2); + expect(zoomedFunc).toBeCalledTimes(1); + }); + + describe('on default/non-default', () => { + it('without explicit default', () => { + const element = document.createElement('div'); + setElementToDefaultCardSize(element); + + const defaultFunc = vi.fn(); + element.addEventListener('frigate-card:zoom:default', defaultFunc); + + vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); + createAndRegisterZoom(element); + + const ev_1 = new CustomEvent('panzoomchange', { + detail: { + x: 0, + y: 0, + scale: 1.2, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_1); + expect(defaultFunc).toBeCalledWith( + expect.objectContaining({ detail: { isDefault: false } }), + ); + + const ev_2 = new CustomEvent('panzoomchange', { + detail: { + x: 50, + y: 50, + scale: 1, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_2); + expect(defaultFunc).toBeCalledWith( + expect.objectContaining({ detail: { isDefault: true } }), + ); + }); + + it('with complete explicit default', () => { + const element = document.createElement('div'); + setElementToDefaultCardSize(element); + + const defaultFunc = vi.fn(); + element.addEventListener('frigate-card:zoom:default', defaultFunc); + + vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); + const controller = createAndRegisterZoom(element); + controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } }); + + const ev_1 = new CustomEvent('panzoomchange', { + detail: { + x: 50, + y: 50, + scale: 1, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_1); + expect(defaultFunc).toHaveBeenLastCalledWith( + expect.objectContaining({ detail: { isDefault: false } }), + ); + + const ev_2 = new CustomEvent('panzoomchange', { + detail: { + x: 115.62, + y: 63.6525, + scale: 2, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_2); + expect(defaultFunc).toHaveBeenLastCalledWith( + expect.objectContaining({ detail: { isDefault: true } }), + ); + }); + + it('with partial explicit default', () => { + const element = document.createElement('div'); + setElementToDefaultCardSize(element); + + const defaultFunc = vi.fn(); + element.addEventListener('frigate-card:zoom:default', defaultFunc); + + vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); + const controller = createAndRegisterZoom(element); + + const ev_1 = new CustomEvent('panzoomchange', { + detail: { + x: 51, + y: 51, + scale: 2, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_1); + expect(defaultFunc).toHaveBeenLastCalledWith( + expect.objectContaining({ detail: { isDefault: false } }), + ); + + controller.setDefaultConfig({}); + + const ev_2 = new CustomEvent('panzoomchange', { + detail: { + x: 50, + y: 50, + scale: 1, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_2); + expect(defaultFunc).toHaveBeenLastCalledWith( + expect.objectContaining({ detail: { isDefault: true } }), + ); + }); + }); + }); + + describe('should automatically set correct zoom', () => { + it('with start', () => { + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + const element = document.createElement('div'); + setElementToDefaultCardSize(element); + + const controller = new ZoomController(element); + controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } }); + + // Controller was not activated, config setting will not update pan/zoom. + expect(panzoom.zoom).not.toBeCalled(); + expect(panzoom.pan).not.toBeCalled(); + + controller.activate(); + expect(Panzoom).toBeCalledWith( + expect.anything(), + expect.objectContaining({ + contain: "outside", + cursor: undefined, + maxScale: 10, + minScale: 1, + noBind: true, + touchAction: "", + startScale: 2, + startX: 115.62, + startY: 63.6525, + }) + ); + }); + + it('with set of default config', () => { + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + const element = document.createElement('div'); + setElementToDefaultCardSize(element); + + const controller = createAndRegisterZoom(element); + controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } }); + + triggerResizeObserver(); + + expect(panzoom.zoom).toBeCalledWith(2, { animate: false }); + expect(panzoom.pan).toBeCalledWith(115.62, 63.6525, { animate: false }); + }); + + it('with set of config when a default is already set', () => { + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + const element = document.createElement('div'); + setElementToDefaultCardSize(element); + + const controller = createAndRegisterZoom(element); + + // This call will do nothing since this is what zoom/pan already are. + controller.setDefaultConfig({ zoom: 1, pan: { x: 0, y: 0 } }); + + expect(panzoom.zoom).not.toBeCalled(); + expect(panzoom.pan).not.toBeCalled(); + + controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } }); + + expect(panzoom.zoom).toHaveBeenNthCalledWith(1, 2, { animate: false }); + expect(panzoom.pan).toHaveBeenNthCalledWith(1, 115.62, 63.6525, { + animate: false, + }); + + controller.setConfig({ zoom: 3, pan: { x: 5, y: 6 } }); + + expect(panzoom.zoom).toHaveBeenNthCalledWith(2, 3, { animate: false }); + expect(panzoom.pan).toHaveBeenNthCalledWith(2, 147.6, 81.18, { + animate: false, + }); + }); + + it('with repeated calls with same values', () => { + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + const element = document.createElement('div'); + setElementToDefaultCardSize(element); + + const controller = createAndRegisterZoom(element); + + controller.setConfig({ zoom: 1 }); + expect(panzoom.zoom).not.toHaveBeenCalled(); + + controller.setConfig({ pan: { x: 50, y: 50 } }); + expect(panzoom.zoom).not.toHaveBeenCalled(); + + controller.setConfig({ zoom: 1, pan: { x: 50, y: 50 } }); + expect(panzoom.zoom).not.toHaveBeenCalled(); + + controller.setConfig({}); + expect(panzoom.zoom).not.toHaveBeenCalled(); + + controller.setConfig({ zoom: 2 }); + + expect(panzoom.zoom).toBeCalledTimes(1); + expect(panzoom.pan).toBeCalledTimes(1); + expect(panzoom.zoom).toHaveBeenNthCalledWith(1, 2, { animate: false }); + expect(panzoom.pan).toHaveBeenNthCalledWith(1, 0, 0, { + animate: false, + }); + + vi.mocked(panzoom.getScale).mockReturnValue(2); + vi.mocked(panzoom.getPan).mockReturnValue({ x: 0, y: 0 }); + controller.setConfig({ zoom: 2 }); + + expect(panzoom.zoom).toBeCalledTimes(1); + expect(panzoom.pan).toBeCalledTimes(1); + }); + + it('when config is set to empty', () => { + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + const element = document.createElement('div'); + setElementToDefaultCardSize(element); + + const controller = createAndRegisterZoom(element); + controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } }); + mockClear(panzoom); + + controller.setConfig({}); + + // Should fall back to default. + expect(panzoom.zoom).toBeCalledWith(2, { animate: false }); + expect(panzoom.pan).toBeCalledWith(115.62, 63.6525, { + animate: false, + }); + }); + + it('when resized', () => { + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + const element = document.createElement('div'); + setElementToDefaultCardSize(element); + + const controller = createAndRegisterZoom(element); + controller.setConfig({ zoom: 2, pan: { x: 3, y: 4 } }); + + expect(panzoom.zoom).toHaveBeenNthCalledWith(1, 2, { animate: false }); + expect(panzoom.pan).toHaveBeenNthCalledWith(1, 115.62, 63.6525, { + animate: false, + }); + + vi.mocked(panzoom.getScale).mockReturnValue(2); + vi.mocked(panzoom.getPan).mockReturnValue({ x: 3, y: 4 }); + + setElementToDefaultCardSize(element); + triggerResizeObserver(); + + expect(panzoom.zoom).toHaveBeenNthCalledWith(2, 2, { animate: false }); + expect(panzoom.pan).toHaveBeenNthCalledWith(2, 57.81, 31.82625, { + animate: false, + }); + }); + + it('when not yet activated', () => { + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + const element = document.createElement('div'); + setElementToDefaultCardSize(element); + + new ZoomController(element); + + triggerResizeObserver(); + + expect(panzoom.zoom).not.toBeCalled(); + expect(panzoom.pan).not.toBeCalled(); + }); + + it('when element has no size', () => { + const panzoom = createMockPanZoom(); + vi.mocked(Panzoom).mockReturnValueOnce(panzoom); + + const element = document.createElement('div'); + element.getBoundingClientRect = vi.fn().mockReturnValue({ + width: 0, + height: 0, + }); + createAndRegisterZoom(element); + + triggerResizeObserver(); + + expect(panzoom.zoom).not.toBeCalled(); + expect(panzoom.pan).not.toBeCalled(); + }); + }); + + it('should set touch action on zoom/unzoom', () => { + const element = document.createElement('div'); + vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); + + createAndRegisterZoom(element); + + const ev_1 = new CustomEvent('panzoomchange', { + detail: { + x: 0, + y: 0, + scale: 1.2, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_1); + expect(element.style.touchAction).toBe('none'); + + const ev_2 = new CustomEvent('panzoomchange', { + detail: { + x: 0, + y: 0, + scale: 1, + isSVG: false, + originalEvent: new PointerEvent('pointermove'), + }, + }); + element.dispatchEvent(ev_2); + expect(element.style.touchAction).toBeFalsy(); + }); +}); diff --git a/tests/components-lib/zoom/zoom-view-context.test.ts b/tests/components-lib/zoom/zoom-view-context.test.ts new file mode 100644 index 00000000..818cc569 --- /dev/null +++ b/tests/components-lib/zoom/zoom-view-context.test.ts @@ -0,0 +1,85 @@ +import { describe, expect, it, vi } from 'vitest'; +import { + generateViewContextForZoomChange, + handleZoomDefaultEvent, +} from '../../../src/components-lib/zoom/zoom-view-context'; + +describe('generateViewContextForZoomChangeRequest', () => { + it('with config', () => { + expect( + generateViewContextForZoomChange('target', { + zoom: { + pan: { x: 1, y: 2 }, + zoom: 3, + }, + }), + ).toEqual({ + zoom: { + target: { + zoom: { + pan: { x: 1, y: 2 }, + zoom: 3, + }, + }, + }, + }); + }); + + it('without config', () => { + expect(generateViewContextForZoomChange('target')).toEqual({ + zoom: { + target: { + zoom: null, + }, + }, + }); + }); +}); + +describe('generateViewContextForZoomDefault', () => { + it('default', () => { + expect(generateViewContextForZoomChange('target', { isDefault: true })).toEqual({ + zoom: { + target: { + isDefault: true, + zoom: null, + }, + }, + }); + }); + + it('not default', () => { + expect(generateViewContextForZoomChange('target', { isDefault: false })).toEqual({ + zoom: { + target: { + isDefault: false, + zoom: null, + }, + }, + }); + }); +}); + +// @vitest-environment jsdom +it('handleZoomDefaultEvent', () => { + const element = document.createElement('div'); + const callback = vi.fn(); + element.addEventListener('frigate-card:view:change-context', callback); + handleZoomDefaultEvent( + element, + new CustomEvent('frigate-card:zoom:default', { detail: { isDefault: true } }), + 'target', + ); + expect(callback).toBeCalledWith( + expect.objectContaining({ + detail: { + zoom: { + target: { + zoom: null, + isDefault: true, + }, + }, + }, + }), + ); +}); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index e94ced6c..05342c9d 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -175,6 +175,10 @@ describe('config defaults', () => { enabled: true, priority: 50, }, + default_zoom: { + enabled: true, + priority: 50, + }, display_mode: { enabled: true, priority: 50, diff --git a/tests/utils/action.test.ts b/tests/utils/action.test.ts index d75389b6..1591b68b 100644 --- a/tests/utils/action.test.ts +++ b/tests/utils/action.test.ts @@ -5,6 +5,7 @@ import { actionSchema } from '../../src/config/types'; import { convertActionToFrigateCardCustomAction, createFrigateCardCameraAction, + createFrigateCardChangeZoomAction, createFrigateCardDisplayModeAction, createFrigateCardMediaPlayerAction, createFrigateCardShowPTZAction, @@ -114,6 +115,38 @@ describe('createFrigateCardShowPTZAction', () => { }); }); +describe('createFrigateCardChangeZoomAction', () => { + it('should create change zoom default action', () => { + expect( + createFrigateCardChangeZoomAction('target_id', { + cardID: 'card_id', + }), + ).toEqual({ + action: 'fire-dom-event', + frigate_card_action: 'change_zoom', + card_id: 'card_id', + target_id: 'target_id', + }); + }); + + it('should create change zoom specific action', () => { + expect( + createFrigateCardChangeZoomAction('target_id', { + cardID: 'card_id', + pan: { x: 1, y: 2 }, + zoom: 3, + }), + ).toEqual({ + action: 'fire-dom-event', + frigate_card_action: 'change_zoom', + card_id: 'card_id', + target_id: 'target_id', + pan: { x: 1, y: 2 }, + zoom: 3, + }); + }); +}); + describe('getActionConfigGivenAction', () => { const action = actionSchema.parse({ action: 'fire-dom-event', diff --git a/tests/utils/basic.test.ts b/tests/utils/basic.test.ts index 38c0add6..50fc0e60 100644 --- a/tests/utils/basic.test.ts +++ b/tests/utils/basic.test.ts @@ -2,6 +2,7 @@ import { afterAll, describe, expect, it, vi } from 'vitest'; import { FrigateCardError } from '../../src/types'; import { allPromises, + arefloatsApproximatelyEqual, arrayify, arrayMove, aspectRatioToStyle, @@ -12,6 +13,7 @@ import { errorToConsole, formatDate, formatDateAndTime, + generateFloatApproximatelyEqualsCustomizer, getChildrenFromElement, getDurationString, isHoverableDevice, @@ -406,3 +408,54 @@ describe('desparsifyArrays', () => { }); }); }); + +describe('arefloatsApproximatelyEqual', () => { + describe('without precision', () => { + it('equals', () => { + expect(arefloatsApproximatelyEqual(1.1, 1.2)).toBeTruthy(); + }); + it('not equals', () => { + expect(arefloatsApproximatelyEqual(0.5, 1.5)).toBeFalsy(); + }); + }); + describe('with precision', () => { + it('equals', () => { + expect(arefloatsApproximatelyEqual(1.00001, 1.00002, 4)).toBeTruthy(); + }); + it('not equals', () => { + expect(arefloatsApproximatelyEqual(0.5, 1.5, 4)).toBeFalsy(); + }); + }); +}); + +describe('generateFloatApproximatelyEqualsCustomizer', () => { + describe('with incorrect types', () => { + it('undefined a', () => { + expect( + generateFloatApproximatelyEqualsCustomizer(4)(undefined, 1.2), + ).toBeUndefined(); + }); + it('undefined b', () => { + expect( + generateFloatApproximatelyEqualsCustomizer(4)(1.2, undefined), + ).toBeUndefined(); + }); + it('strings', () => { + expect( + generateFloatApproximatelyEqualsCustomizer(4)('foo', 'bar'), + ).toBeUndefined(); + }); + }); + describe('with correct types', () => { + it('equals', () => { + expect( + generateFloatApproximatelyEqualsCustomizer(4)(1.00001, 1.00002), + ).toBeTruthy(); + }); + it('not equals', () => { + expect( + generateFloatApproximatelyEqualsCustomizer(5)(1.00001, 1.00002), + ).toBeFalsy(); + }); + }); +}); diff --git a/vite.config.ts b/vite.config.ts index 6794fe02..25a3f0be 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -18,7 +18,7 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'components-lib/menu-button-controller.ts', 'components-lib/menu-controller.ts', 'components-lib/ptz-controller.ts', - 'components-lib/zoom-controller.ts', + 'components-lib/zoom/*.ts', 'config/**/*.ts', 'const.ts', 'types.ts', From b70e3157d6f2cc9f7e3a7beca214e238e492779b Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 27 Apr 2024 19:56:50 -0700 Subject: [PATCH 129/189] Add example to documentation. --- docs/configuration/actions.md | 20 ++++++++++++-- docs/examples.md | 32 ++++++++++++++++++++++ docs/images/zoom-automation.gif | Bin 0 -> 2363800 bytes src/card-controller/conditions-manager.ts | 1 + 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 docs/images/zoom-automation.gif diff --git a/docs/configuration/actions.md b/docs/configuration/actions.md index 5b9af685..b371f765 100644 --- a/docs/configuration/actions.md +++ b/docs/configuration/actions.md @@ -132,9 +132,13 @@ frigate_card_action: change_zoom | - | - | | `action` | Must be `custom:frigate-card-action`. | | `frigate_card_action` | Must be `change_zoom`. | -| `target_id` | The [camera ID](cameras/README.md?id=cameras) to adjust the pan/zoom of, or a media ID (e.g. `frigate` event ID) to zoom in on specific media items. | -| `zoom` | How much to zoom-in. See the [camera zoom parameter](cameras/README.md?id=layout-configuration). | -| `pan` | How much to pan-x/y. See the [camera pan parameter](cameras/README.md?id=layout-configuration). | +| `target_id` | The [camera ID](cameras/README.md?id=cameras) or a media ID (e.g. `frigate` event ID) to change zoom/pam settings for. | +| `zoom` | Optional parameter that controls how much to zoom-in. See the [camera zoom parameter](cameras/README.md?id=layout-configuration). | +| `pan` | Optional parameter that controls how much to pan-x/y. See the [camera pan parameter](cameras/README.md?id=layout-configuration). | + +?> If neither `zoom` nor `pan` are specified the camera will return to its default zoom and pan settings. + +See [example of automatically zoom/panning based on state](../examples.md?id=automatically-zoom-based-on-state). ### `clip`, `clips`, `image`, `live`, `recording`, `recordings`, `snapshot`, `snapshots` @@ -536,4 +540,14 @@ elements: frigate_card_action: ptz ptz_action: preset ptz_preset: doorway + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-r-circle + title: Change Zoom + tap_action: + action: custom:frigate-card-action + frigate_card_action: change_zoom + pan: + x: 50 + y: 50 + zoom: 1 ``` diff --git a/docs/examples.md b/docs/examples.md index 0165992c..5c2aa999 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -1057,3 +1057,35 @@ overrides: x: 100 y: 100 ``` + +### Automatically zoom based on state + +This example automatically zooms in and out based on the state of an entity: + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.living_room + live_provider: go2rtc +debug: + logging: true +automations: + - conditions: + - condition: state + entity: binary_sensor.door_contact + state: 'on' + actions: + - action: custom:frigate-card-action + frigate_card_action: change_zoom + target_id: camera.living_room + zoom: 4 + pan: + x: 38 + y: 20 + actions_not: + - action: custom:frigate-card-action + frigate_card_action: change_zoom + target_id: camera.living_room +``` + +![](images/zoom-automation.gif 'Zoom automation example :size=400') diff --git a/docs/images/zoom-automation.gif b/docs/images/zoom-automation.gif new file mode 100644 index 0000000000000000000000000000000000000000..609ad1b1dab87dcebeb982161c90d475f37bf18d GIT binary patch literal 2363800 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
      tP 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 z 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

      Gqq~2mZ%vwTRT*m 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�`i9AJCNzs7nU!KKENIC-R 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

      8Z7@&dyAY7mYi3dSgxJqgC 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Ν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⪚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

      gZEGqYPV$~JQ>O~5YmJnY04>&tP@BnzFf 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�rLIw_=1ZbfdtUqTz(-ckps>7=??Zl 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�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

      Z$bnPyw4+z+(D4pi1%cP8;xf4}$(G%B4&F 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�?XAeku$J zGHS{MFaIfd*|K}!c1NM!`aOiJC+7BqkPpU;`(Hx*d^V#2*qHMhb}&~gTN(#{L?tM7 zwEb0Y6Jj;sWeIh?4>!FULrXH&wcE@%=Zwb&fcp(e+D)^x0F`!F`gF(7C&+hXWgU!` z^_>_n+YDO5#)1PlK{B=;TLgdomW11i>i*e{)K^U+NjPb70eMxfe@-9LopMxj2^!L@ zFCEQtEDzOFaU-&^W!W|=@7hFu)O*xP*>Xyi{4#^i_HZ zh_X0v7+{PI9#oE~BpTXlb${Y1VqNl+^TIovG+RE8fnbrD8$&qvV?F)|N(jbY@V{v~ zrMA{R_pVH;*zDCTF~~romY8sh=8v|kOO;9FrwH_!1#^) zEa)eo^jz{xGy0Y|dI?EY5*A6<{2Amv%CXf3lXxM*6XAL4RZ8kB>Jv{983!|vunB?Z z-j}_Wgz|6Rh*=N3QO>n#ZlOokXG2;^EWgauwH~weGi6czH#hs&3B#wahht5Lys|+I z>L^lciW(o1c+$z!1%?z^`ozr7^0tx{UHUhTX4cHy5~Z>pXDSQpK;6D#(^?7M5w`a8 z9s69Ub6H52fFiL3XjS37p73n}a?I@N0VmJ7CYPAJ2Y*6CFVPk2N}c)&(j&aH?VeBg z?Q@t%T3^eWnj+WPCYCp*3>w`dT#!=iham!6i#YKOwk4qojy&G>pWx^E9*;S4+5nvn-o#MHSZ7Yo7+wE{kUrqYU`jk?e6dm1aE{EJzQr zmesosxv_#)XRsLCgmHU*+)R%$|VWO5Ix3<-)vQ*7S zU(-9@FI&Sb;T?`%F+s%ivCwghEMaU6S59}^rNL6|z>7F{=Dc@RE(;uN4&_Z+;?T`v z99m6u7++Zqeyb-Izh&;=p{x-UTb!Qixp-EdaC2n6u={d#7iNYU`@s&!UWa!u%jkS^rha~o5!ukVamzndO z6}P#cdEcR+At@e3?^_|pYC`mc1mR%Vso96F5M7^ZL?#Wpdr{H-=Qbysx&k+TO!?ps zGyEuZe+lR47HSfyf|jX2Kgd`lrBL>`h~f|)bR4s|c-%D^f82zg&%7o!T`!*2GtUHTK`Wp$4v?()r*8pDH~iB=N4M;H0B z_c+W3nx*YtnrgAf#~?SKMkP@C8$K99u*a*ehpU-Mc9k)&aTxEkUre0dn$})|^*7^B zaH#UuL(|^WwmDez0Ttpta(Kf?8N0PoB=CtXm#5g~UqVlMlz`gv>BLx8zpszwyGjl@ zkYhiD0t5nkv)}wcft#|~DTk*Q2>WvZ_{*-guUOWEbQul%72M*PSJ)i20zG=y@)YohOK@O zK^a^Ld!MuCsAY^*h`S2ryKys-cy#A}VJ&ON5ksWi3E7x0Jz|4GI7#^qY-{amEl_i> z-)wbzCI~9c@ET|v1`+WjdIr2G zHCW}8;LBh{P1=>o^tU;!rrDaepkp?Q=i@y-dDNm)(5_}NtET%(<%3*!97OD1R3fxW zdp#;$8T$SfkLN}Ka>0eT0JtK7(hhJL8$j5rZblm>eLXPx2ru7Kl35gBxUbZto{5v$ zE0-yN028Img`@XJ0JUo7OLrLM=U6aYV6tYlLOV3sXVC7>45I=?(Hp~ni%C%*>=}ge zQ=lCiCMvefFlq1`nonP2`R{tx5%=dG3IZ11rTi)KQrnZjp+6v`S+;}6#1=~7^-(Xk zwB7TFT+-Tqi7m_XBcI@4#Br;~QLG($JM2X0o%~=@?HJF^t0)gbStH^lRDwr^SwcI? zTb;tNzgvFV;ln0ez8eO9lae@(oIZ5HsY2c03PE%a@lt3rY~%Ec2x+YR3$cz7A&0hV z^Qv?9=0~+VQ5!>kyFyZw{=`pp-7=HeM`m?S26L<6Fr2$dt>M~S>d(eOMO-{X=8!Wq zP>B>pAM!4r0}0gtAljB<;9;!0i9lHzdm+o_RsV&VS&1GkLAl`!C<7pkG(Yc$Vwf7!fA!Lf!BlW_$eBXQ>qBK*A~<42HY2)XQVJxDC(G@tyyw=G z_QxMJCwCx=t`pywzNv3u=|9I9zz5F+3+x>0Wf%JP9ig`nvcD<=!cts8qq;Wd?dSFV zSuv~ve$uY!t47_fhVl?A2uKl&M)C*ES(E8qhSEBG_W^Mj0 zPZY$0eRk`mME0$YjF|31L?6bJRHT^}qBuWqeM?WJHojyotmHc1AeZC1bE;UK6(-7> z(HLD)OP~Z{Q!*4*UWzLW^4x1vGiQ%#)YskLF{cjZ$sC>>Jbw=6cxAdP?Q3+1-TGbG zy1^!+6Gq{Qm=?@^$$~fC{@389bQX%(Ze0i0Xja&?UN_u`RpWiW%rGbBW~!$=G^?$E zJfEuYZ$@F|p;|kDRoKBIunMA8B z$U}>gJhxgrnkkpD)c9tEruBH#PznR9KA#&t}<}TofIxl;4NG*qf|E6i7gXRb@WU%Ur1%bua z*KRGrjWs|Tw&vlEUCGBJu^44Yt64amh`P4_SYeO?3B0u!?s$eRqXIrk9P^P8oQdL-rth!RP_wc|*3)x};6Pdv}+hO$e zg}2J*WzwH8V9cs$@%KB*9hciZg4~JckFqZijqt6`HWg?!!IsnIHFgp?4$8c)=zo za%aevPK_zS>(&pi)1CR_P^B%vjd9>C+8AEdstg-gNQv2_X+P@-G0J@@HW<}vS_Ow= z3>3N4229(i)cYh^4~B}JF;jV68>t9Jn^)XdPj9E|yH%h!f2??Osd4StUVn{^{OR=j z0{@>MPNDAfNge2BRv8WOA0MON$h^&t^cUEh5kln`M`L}F?0mV9nhEO~zfo#mPLFG# zrs@9q{3MUB_yGAK@f+y6EtdU>o!O!(Q!izmCNMZaNz(VRu*#Rq-<1x2<8Vj)29BRM zs_}oI1H!{#%Ynd;fx!^Dack8h>+&%APUWSfNn_>3Bd(!=-HL(Midx$RZW9Jf(Ujf7 zW07?hm*rR336;<`9fy($>=yZE>@}(PV`;pBcT>S)$Ne7|RIpi>h1*_S3BzG64J|q2 zgF#WKA|4Gqx5w?N>d3DOrdfV8tnTG3<D+yOL zs!d8%qLd+KeAgP6BN@jO`O^D4Pwrh6x^Q0E)UEK&Av$Gx>By#NxvbH5hwc}-mP#n0 zgo-XOT{7!#*Zehx@FAl;n8K!Fz;dpF+hs=bVA7{~=b;$bE>CH2449a#yO__mvUCM+ zevg~eaMMzmpG$v#(q7ior%5};YzD8)Ww3xYP&Zw|+T)i!$U5$tT=Jp?ai1x!BJ-CS zvzBk@+Gi!Vjgv#=moH20K1TmGlXAs+{p703e<8G5DpQ9SwUrkLj}1CZa21;u(b$UU ze&<#yXQ0Y)e%QUNsx-oH7=7pc{ZrGQm&BOlUCqvJ9@@xPROg^SZkKgCs(xH03sIhT zOY-uZMmAZW&ZVZ!+##4PB?0|tzF_{fm`fqX>PI_j8#PoLLD5{5mb`X zEdFD8&8(OxoMhOiWIOdEifk^odKI0KVwY}tY5lb)G z26BRBlgD`jLgez;t2$Yd+qpRjZIa%ngS$D_OJdbq7m}=p!s&9imkdVvI$f6~dd#bs zx>KvZFRr`GebE+c8ho1AvmC{EX{YY(){#jKTV59Y>|+)oZx>q8+GJ_>m1EI!Cq1;m zo}T^4dCx0CTc8$o9ATq4(dODV?_5=26f?K}VnG!;?@7~-k9$G+`NWx5PH6Bp{l24a zE=kU|`EAsw(R8N~aMFK>OLe{}pQ4`iptoMKLTN*0UT3gKC^J4`L`O5qe4l0(^Sbx8 z(mly1LkXNg_RIRGPg}Q+eDfG56VTP1yuUfMtXBbJe}~z5pOARu&k7Ec`RdM z;RC5gEYGkARb6DOxcjs0i*II(di`TJfdvii3no~e)-qVgICeMG+h;_Dx<)sjGK<)P zm=czx%VoajX$hCh(5vVSvQ`-jY;VY&Tl#~iBhl+C>g@MMWR+s--xrJdUcD1%O#bp# zaZvpG>OTpoypnckZi1r>O$lFK!-3jZ!Ls|@m|*vm{>EKJmjw%(yqB$XF9^pwrd>Vx zB}9bF7yL=*xw_+}*cG?8PZ3)yv4l~BMIjdgn%qKuH{#FQ{^I=S6@fFN!bWepZpC@& z7paksgTL}lMF`H30n+^IV)AIw>Vqv*0PBy9gxfR@rMDyJE*p&&F$1cG{Rhz9$?s7IoM{JfH&~DICfBgMnbC)@ZZTPSE#hskEZ;7+d>_tVk_HPs z6ZZHv{Etgl^2i>2bQ4hMNJhVWApSUcz-{RJn)3cHp&vr!b72e{<60k&T}X`I=K*&} z)ES$RPo0V{8;oP(-vi;P>E|?Jp*^71(dQ-c4ELX_dP6aMiUN$y;>W|T6PZw7NZqF8 zM8B|9F=Klx3>Y;LfZSY#wCa$wN>l-k3l8ZFW`G)OOC>2*Z?@L@9?OxH0)`T^rHVO8 zztFhY1`s$R?NI$g4`W3F1iEq>2d}^9s&9}~Zdq^LJlOZ=xmVg1v&L61DfVBW^Rv7B zUzjgHlqHW!y|sASr+hFNn#bs)>7D=S{dA>Kp=PS;%Fga`iGwSH2AwG<;P1LPMD~M)7}x zT!nMBiwz&|S!tX>E{I(>BzYTLhmyY6O1PUh(pPPrsCJxzToF33tXIg-=alUaBj^bt z7}DcFI)u`mcmPp3;ORc*dh3_hlq-K&N{qurC4gEuLW;j$N~bZPHFH)+uZ=wFv$)kb z)pNtpIu{gXIh-G$qa6YDAx_)?t0Z*wqk1-mtkj4pUdo;>QRTlr#G@M9<huKK3dvVI=?$Eh`=mGPPn{Iank~m>nZN;K9*CF)UNcRX3a+x45Ph_C{ z&>)?UYe=nm6UHA}D`cH3%?S7l$yXK3nN<=;PuZOSJlC9=)&)-pr@7!d!8L6|PwmaMAU1iCK6424RsNx4Nc@1Xr zShe!b-?maxEGtTRN*1M-tS))xcE05j(bDqFDj+0EK;lvz$cwwR!p>)s_zkWftJfcp z=4;MHZ=BvJCB#^gy(9miIE3RBGxvP;3pjslCREq=oU3AS(4EVs@8V*079^Y)))&eF4{fH+O`rUnm@+VmiIIwKoZ1FZ_9K2cF>3FKa zG4Y{+lyyLeWGKJT6l6XBx0Lm6()j3*^|@azhvI729>xc$2gj?Uf-J7i<_q4!iqfSH8` zJszD`M8vFpO`$#w;xB(@|ky-=G1hU=*4>DyUS7%uM6;w zT*j=x$dMh_JyJ~7Y#V;YxzYW1fQ5w7UCMhv0 zu_aHf`wh=%Bg|h*dIN5%DVt7t@O{hsT)JTpy&HwOWlcI%wNvcnb<2jMV$YvBAulEE z=(MA##myXblxohRZFY$X+o2bkQ1{2bK|rm&%L_*08TTjxJVS z=Z>pCNK--H{hq9LFkw$f|zkP54~`k=)3vzMIRnSGtoJTTiO# zJq4WVm1u1{MECQvbxxdOHwREb&9GkKOEHh?ljsa20f9E>B;-S;)itS`-R3TdYuQZg z3S!zOep~D8J&R`TR^)&}LXuqpMnFarn z0SX$u_5PGGy?EEib7>W6#7?9AT2cg7y{!|E3D?g0WxHgt)5wkpbiWm;i5pC@d*k}r zi1yM`;*W2Z<(>c}k+JNX{ceZS(oA98SL2Hf$XO*~X#F++I8(o^gUGm*2St`?C4q)9 zyHRzo_U!b2PNr|ir&sLmN8ihk3xEqOYbrw>#B-IbgmvQ2tKyWlo14BVGiA@bXCO#a`y$16qHBx=)tH zXk2M)npf`V)U^1^-&noC@JD;B+1HV^a$2MI;oI}=p>`|3*W|xM-c>n>vYT|q9I}5U zm#JYNn&O~i3sSTB&Qy6GzU5nHs@Z?1kzdM=pTvqn*;}7b!rNwR(}ke5Yge@b6Y77} z=0v*5wruSESJGDSAGFV=IF!3jb*)6y>=dT{-=$|&>#tuH`?XX+qqKC$h>l#S9HJ>i z7eV_FC3;9GZ&mo$&~VU9f5o=bePIxiE(A&Uh;sNT(m$*jO|L3!g(AO~)xd*=%tOON zFRqLtMZJRY2?3tU^8E_(GI)8310PYlQ1B+$BM2k|z~!&hP9(%`>#<` z)!ugw=;2zPb;GxW7F@(S=uecx`a2;aTvxBiIWEf?0te;{yLt}Xs+_q&zDh)OfSw-` znl{q-AnJ zRu|NuD5J|%rl63n*Up0DA(Ww8m%byNL^2QFI>=f^uH@v1xuZA($`pcZJn#Le z4R>b@KFA4IG(aLYKrFK$4HzH^fd4|l6T&epT3I5>cfzRYFnh2t()R%#`i){4rfqvH zlmQSjM1n$GTm6hKGYBq)?CK&{!Y*g!1cFiY7=th%Du)iFmHgiPRj^}9=M5cN5Gv?C zqRc7es;?d{4`KlV@bnNj=mYyAEj*HQBbVDddN(v3KAUHnk(FKtrl8GC3@*LMHoCJd z-w;I>I(4IhwMwo;`Ca~S-DEUm%66>UjT*ZU z;1n0m;^tLv8^G)aN6gZLH{p@pK=eiMNtkbYr95`d!>O7%{8oLkAn?` z*`qOZ@>xIae%Jc+EZ86hz~Brf$RV^DPk)JktafF*&<_CVz@T`UmN-iP8V7HB7SIop z3X8a7m!BhyEEvznwn5`usnjk8>M{L$17x{)!Ow)$&*J8`?~pMyf~`y9$)bgRrxz># z`+)p2sA!<-HTKwIJD$jQj12wZp&IxAf&pXk$a{FCE1?KD00I5?>)>|+GSc}a5*~LH zGs%%q41nZYR7xo_c>}32Mjy58?Y?t{`AUqhM{b4PU}_7~sgK%zSo>e1vi62r$v1xi z`hcv6c(%hzAA& zEV!U)DHrwK5Sa%6@E!m#2Vn?wmtX+8zg}!Nde?!&V7yGEhB5ZEwfJ0pN}vRLZxTaq zJ@P?f`B;2;@9PZB1c%zUx1Q!!9M?4>91YufFaD}({H-0tq2I(B2Ely0c!eh!E7uM` zgboD4*7llg(MTE^xd}&6!^>XPRYNchpY$6Tt+ItO8s1)`y0$v|0t{ksfNWZ5fF$s$7eYy4-~f3^vp+rMpR_!)?=rR=2%|qs)@J5ulC=)q1X(v&YbW zmdpANk31_K-&QRShbG({(ksAoN8z(nwjiOrNZAJf)GZ|~s_+!#6{v>Lh&dWJC%I7t7A0FRWR?gKlkXMZY zm-YS+2=dwry>1k2eXohmtq5XK4M9EB$xqPENC*1MhV5Wy!%8HBGt7_tH3`*S(9n?F zIn>KA;@C2>g1lUZtiMpPH#jhxOj&tY5VV8*#d-Cb!Qrn_vY&GnM&|}iIXI&uHh8-Z{6`o7 zyY=}-m5(R-J*^*b0!C^$bN-ETd-JA2+PauC zz#EJ`{L!$pc0r~LMsW1Aie+RkwXD5125gb8KMn$GJ%8ntAh0p@!U@%4RED0V4YVVz z6=5cQsQA{NTqYpJyu~+tJVFBLdN7^>?K+Y|nb$b{V!Z10X=1@K(<5GyRT#4Ij;?~* z^iP|v^yB1-B5vb<&V1tkxo!yv@f#l z-`3pH0Xx-OtY%L((D~SqgzJo%_Km(^cg8B3)xzEsdb!*4T+S0mvick85Was z5?_x92~4h`9@8@eoC!11jjmAXJcfdcrP6iink!j)usTVkg9cK_cj|T{vgx^mTLtbzeCa!@rPk9X>+r1C+ zw6ZyeD%|Dh;-Bnyi zUM+#Os_16lJW6LQt4DE(mGOeq8K*&g8p!kyJHGV^ynk1iH17zeSJP>&WM!w+-n7hg zb-rPOdPwNVJXr+?O^a*1qHB8{(c^pt`6xi9>#hW)S6}7lYU;-J-Hf&(w0)%8y9rhc z!{cnZT@_@G(RSgfpq=-K-0#6Qk~H%B?`4Y!0!Xkv__kH4*}~D~_b%$fIoD6K{B*t-zxMr=Dv1|u~vKR)~3Hd@(RZL*C%fs{l{@jTsOD5)so(>$mKro z`R9xpV**xvrVLAw(y}Pgu;wQu<&MJV!MophTdU*DHi*1?jXk;MPw(5`0dEh80_n6d zX!*e-e6T88HVY7Xz;I1-jn0iK$Nb{8^h?(RzcA$&%YSRMpgHH6K5O{jfcpNp2DA7O z78Gp}=LH>BCu6E| zymV&{4rp}w8Gw}nL;W`IGS}BR&%`UDo|&#UglE1GFuz;BIfR1g7i}yaP~ZU0pkAe} zH8zQb?{c+N5L*=q&@cp#l_Du4Y-*Ca;ElR7+^W8$$!|piwkQL&DlCn1U|FIs{02>o z#T(~oyAGfQ{#2Rg%X)(%ui5Es=c#z?U{}GV&4bbw`vEuw8zFYUE)S2ww&J7Cgcga& z+HFkKa56@+G0&XJL74~*@VC=R)V6}YZUyQBcg&t?Su_Xm+^;l_)8cG54pVSDoyybH z0rO-yVlaR{>RhVzxK$t}v!wZ}+6BcZb)X%LuRLHb_~@h%>P(0B7`)&)D0(zRALR(V z>pr#^d&@M~EnE@k)Q-cr0>_2_MK-FqZI1xEUoKIBT2gzR&!Q}bHP8@Nwq_X7q(pJL z)vENSpfFGZsZL&BK65>GAeKOlSHv9C7_oY^2>B=4M}yN)TlzE5I;X`d>Ry4Mu&y#5zOjB46o^As;YoGDVmKY#8e53(?>)~CYGoI<*i-p*PB{d zg8V%`!~V#8w~k;5L9?A9Vl6Cc3JPe$j_h#hkux`TmL7#?Q>qL<1NBJ#LZtIZ)gA%s zG*K3}uub1a%x_ePj4n2mIen-IF?uGT&^-zK(J}9jFOU|$$Ae1Bui&hILYjsNW%&$g z*erkZQh(x^_#WXX|3L|0GD+N_fa`WCBy*@l)(uxuLNc|<&n~Xon{>84DR(!CyK@Wz zOhDAQym<54?yE(8g5oRhLcYGN&LLdh6w$cxgZ)Du0l?r`LlHqj8_1+5AF7b;zkPsu ziSe|(`fa%1XFi5fH9YA8qU_P)??H9@SxL*J%T*ihh3G9L4sv`FXrbU4 zGDT)ttUNBvhAPl_0jtM%?oyMx(3@rB+GWnL?H{&t*9(|C;#YS<1eTuf@zJ_(V!T}1 z*r$^MJ5g%}`g#jxX*C^e@lBt^{I1ePEiG!FwxxE(h392x!!(pMdKC3<-SACA)>g&} z9(*Q4zzgh};HYFs*~PZfIBgkFl(pE9kgygA9>~My6NfVmSY9mxFN)?f`Fop5@#&kk zHlsqkaiXq#fzZRO9j5mdnJP)I^affOeQ>OK%cRi3A9{-FDPcpB>-SXLaUF87IMd)v zr+4v4aqkxaR`q5-yWT&E$1}^}cleos_sTgKvQe^|1Cvpvi01_e9}rg5o)c$4ks=8F zYFL1V;cGJTG96$S$D#cf9`QedI9;Qp`>FylEW5^c!QzRybDXl;0HY-|-};%lJhARr z2D9{Q`trn&>;#*XSU$Pz@c0mksZ(_r5Ln1L*3pUT-+iBc0_tax66ZXBEKNXVQ1uv; zvpvPFgubpqne75Etg_F(-%`?8EuLG`LI2R1O**3=Ftu2p3Ng4nk-5&jQBm z;!vPuqca;MkMZN+JOEsyVQ5JHow|kCkh#p4{!rmJJxJeLZ<)FiqL-lIazJ`5N}DEG z{_sAr&$}+&+8ZZ%uT`gCr6=Qa*sz*V@wVxV)pM-BmO-l})#W$5U7I1)@E7mB0@=5;_Y`L`01S zv-x9aBe3uVTubS^HcR}i_+c6CFnS%H4xSN+#G5GG*Yps1+jh7cMMWtl z_54%ss{m6XT+f_bXUFL+z6q)srC(ueCT8$~JcPkz@v)161Bj$nJxXW1(s^afLeT}6 zYEgGK)8Xl;i){}$-KT?peC}0#LjA>c>%z1Ik+<4gTbri_WmU-uWYI;TV8{07^4eco z{$0>Ak~DgW#jRYAcz*vH%!m5Fh&u0os^9;QzYYiImD~UC6%GEluuevbiB7#CW(W&%9HxUXXNDzJ-^eKLygyw9*z)|FkJd*x=AKYwcRO5 z8^^=NGGauRpY8V9S(OQxjS<`|)IR^%RlWDhFN@R_jMSa~gt$ITwFZ5*)d9x#NW%?_ z6Myq!%Z!_c6@8MW{9j}n5@z**%ltY zyRRNOBIM9(R?0@OX^JiZ2%V!gLuC<8?MU(SgWYSji&mFemW4gMNy1IAXsa{b+1>%B zbB`n=T=|&OPqpNI6U;i{#X2)*V}oGzRd=oVC)dX((`j*gMwj|kt$~Yr-0FePX{yO< zUta0`jf}CE2bbt6L;qRFP0xqkl+Yjgyxn(t>nD?F_;<))WFLiam~`UIQd5`TdB4N# zapX1|kMj8WJmcq?@SwQ*V91D1|WWk})l??BRuP6MPpkP>iL@M(ct__O4(29lcuiNCkHtj}|>Z+jN93w{372l>25 znF=Ew*T8Aa-4_qFNP*oR0B{n*e(D=rF1kqmQw0in|IoJP;j26t)S>jR{s03@-8*+3 zm%{`Z0v*P%ufj9O50|9ngYB|{SS6???GRgfP)R}39mUL?A!M~NEoDV$;voy)4G_t# zU!;eNgzC>jH4pJateV=(m=nb)+L`1|h9?6KbWh6hE$=2WWhD^NpPFg~M!auO3glD) zGX3@TDv36A8a+W0o6i?PmB~+=`dqq7r~G|^Q&m<-b>LaW0@m13ZnugjVS_3QF*W|8 z5d#Js`$|((W%lC8ifaAikLW#iYmYgqZ!tuCW16Hp8d7@Po-II)C?Y1VX!A)thrstkE@`OUn zZ{|K-;s}0c^^ofcvj7||ms$*g!g{I|CZuSJQ%Z~FOtUS6EMO&jLrFtAOlKA4Al)6o z`0*OG3E#JqL#+sZ{=L}n(Y|Gp>iCqW1!}f(FP#{*q>*KB_1JJIwq}wLhJWxwX! zYt?;~Sxnd6qv(~cT%bPsq)~&*ME4KQik4&d#_Bm=>L{qu>M}inzwunA+g-Pw0g!*S zQfZ+xUH%4qN`d%f1qL7PlajL${1|EtknPd-tecP2MPZzZ6w54KM$+DkFE_WAKO_Y3ro{Vs2l^~$fTNAzdG&s-gC@*K3ASL*Uo2e1{1Wf3Rw_( zCV=pE1|lJT|Bpb+`D_ z5*$0k`-P$M3U3(o62z9IJ{_@0OwA6ar^)CNm2xMrDd}fE_j;Q~YD=T?0L7e9zzG9g>xU8DWLAUA1H$S}z3EaTHHYNeo2 zLA5HOCUQFHEKc0=)@S#qY}+J;Qdw)a==T0oNC+W+o6$J2W}W9Y`4yFcHfa`4s(M^L zpJ~tNrUVt!x;xwpktlWkiGdW9aXPQcl@3he1HU_LXTP8 z5DX;PQn<_AH!U{r;Fyltv(tI4SVEVGb5PQIIl5>dh5%UV8ea z=O;ac_D;Kp{qi;*BnScNM?Fk;0|lG57;8ekECq*H&5DM-{~|$!-U;-|DALZ` zydKDN21DZo$4r!jc@EwZnXFq&()y%Eb0PCC<-?SE<&S25B{*#gun>j~Yen4NdX0aV zQrlhhQZdv`GRR1ldYg|{Ok>b|a`fo8eNJP}MUvalqq{@&n1q}1_p;bhuV{!}GZ=vC zfjD&STRg_@@#Eq4?)^&QZw>%1etgo{y=V3iG?|aZmF$DtIQ79nG(BKT@!GWEv_`-q z1JDH;Ljp^{Yqb(vw`s)V!?adl$=Gd-1|(?!sjV{pLF8O~Nzs z>L+UmmNWMm45J=SuXY6zJq-!YPlQm@42xYd8_uVvdwt&_hLzWK7%bLZ6AFDxectA9 z;qHqIaz^{9wVrVaI)UAIH+O!i|yZ=k-`4fkSt~m0^VS{LNr>Y{CPH1Z7Z`{Arz*a%3jT9Qm z&FNOscG?W&)+Hf8wVZ2F`tX_$-*7?6fhftu?_Xg1D-krHdX9eqVqHzNCY#v)dxDRU z6hS5U-YvZP1|qpweGhL>^|Hl@B-~k9c5Ky7LZAv<@JTpd^7}2S3q;)oVjk;K&LAH1 zm9JW1CS!s9mX=SWYPpS1z5E{e70pWg%9;QK3(H$k&rm`u65!7svc!bGMSwlf=DcUqNGwckP<5J~O43=Wih zzaHHfntFqD%0%cSom@U%kz(8?lUhIY z>ssGwZFXY*Bq+6@}!r8?0@`3W#iGmA< z>2JMr%7v>tL(raB2>+@%08Dc{zL=!z`LqAyRsX5h^&!HDw;*^T54dFi7Gk_d?_GHn zng!WD1gZ0HKkV-j{lb^s_ccef?B-YIcvHI%qHfo$ZR)%~eWGe`3!R%>c)b@9Ho4RK zzz2l*LC%a0Nm#2&CcNPTreU$<|JeLbh1bU)q;fY)5ByMua-kAdg}*vmlY8+Tqy0kJ{_9sU?w|DaQF5}^Z%N+ezOUS&VKPL$}JQ1w<7RU@Zn%BHCSt zfG851!%Z$ARvri&K@$jJYz4y<{91@C(yX;=sw5N~umU6@ZKdgFP@5NMK?V z&EC9w^%cdlMPsK znQq8lSI$Q*FY!zu|4>e z@4QSbyf}>ETaNTC=BW#?4)nR({B*GpQwVL-El1-#BZ5Z>86i1s-V>dWXX@_`e~o(V z?aa-mwcIIW$H#MC_}VBNjTAY-w&|1XhQ6DDn&{zjln(OA<26%k0|uBB@qBzYmy?QT z;&d)-zICC?9b^)_&6-a}0J3ldma@v z$SEO_!E|i6WT5Ja6Wrh(7H0o!IB1E>RE@#qTCDaw-1&S0*~P^Ge3==zXk(6WMaBat zNaULyI=0*I+@_&??}}?s60s=JummN2J}=F_*jxmL+1V^NUXxbKj=@K`n7XOTNSRf0 z9^rxoA}n%31YD{Rt`~P02g+#1^95Og?9MX2PFJF9T*rvf4g?SvR_Zdc=UC2cM{P6+ zy}JHZ7Ol%l!$e$$NS64S@xFt>tsRdfx&Iu?*ehOMwzL<`#>dSFF_mum7y001y!r8f zP@c_jq_(p?Cp}?}hJ*S=I9h`vyqrz@5z~*Hr3~!Z=r}!O(f>HH-sra%{7x$xGy{uf zm~U0BDqYi6c`SQVpz*0arinSP3E{B2H;r}c5foPf*sTBi~e2O%qU&Smq4@zi)L)cN1usz_3GDnH+va_ zI0#}{kWV9A9gC9!Ew*LH?q>CWpDvT&>GJ7p-UxReJ92Jl$VJpopEdyb~WWqal_X$8mu(96qv?qkzS z_hIL(tC2EOId^m~8@_ViyjcCkrO5emTLGm?3Lk6nC90+j!Wp8|&Q1O*t=+C?!)oF% z!2d|Gy1?MLH7#;-`aL68#=}@MfA5^Nm5fAsUJ`*pWR9}e%Of7{EvZ83@umhc()xB-KAc-t4m1MX< zLbIMFnq4MI23!l96boiD&YEg>d$mB-Q9(&t5jPGD@aibr zDvQToh*Rfjg$aBUzvlrLc=sf66S~Q2lE^BS{KG2gPi}Ut8(59LRz*NOEtsy|1OrOW z75Oopdrt8+st(ay0-y9T>)bJY$;)tyeKVE!RE|Hb9w8FoXfg1Ei|91L9~N zOD4Ev?!~sntAwczgjo2lX$+xN4M4DC91C)j!FqsZ7i{}QXfi<4Ye}N8c>10ncPB*HI6*eOxt}bh==LCEfI&GRO0-s-!HBay zB7?WY8m(xMbFTWjo}&o)*&@qD;mgP3{k{S0OjOE4c3QNb6xpVhBD6r2lfB~7L4wlx zQ^i#!90oJO44^s;>&Xx4k>)!P-&dwaKPJJcaA4Or_dBV$Qj&csJv@9pfd)b{q1SSR z9V7+PF(Xr{NnMU0txP=le00FQorC6H)~$!E7~w4Y=_VU%<@7M2nh@TvQXLSd8x4q? z%-$-4C7qH#RU2K%QL{OS_hPBqLc3Zr{em)xJ;S%EmDFw(kCj(+~+z&fy<`b=qA z75&p@+C<5b5nvStE|qQW#;C)|!|XF=7UBJp6`qZdDs$?WA1M4Pib(QD*g!0b*sQ+g zK87$M@l=7AZQqDHGn_UB*HukO6ZQVM(Ry!Lb|3C!=>}S^@{6C6yIFkLG z5Jcrt%P0{QJrdrHQ)lqK|9XcRX#Eu%YTc3d?oZn7lS#JHy1nvrMmGf9>V_F`;zzeF zm!EqE)QCdyoWA(bHRwFUjK%^$B)Db+JQK?%<|AuRywaB-OawfSXTjfWAq_zL^7>w{W*o)&+=)I(~~)@^_NAA>If0!LZgW_peA zxbBX`##mWDO1urJws>FYz92=2=VBIid_%cTuuT(WT1S@gvdaYdV52?zbSDRkLB zp-}VUjwWc3pEWUFcy$mAfGbLh3$*q}sGRPe-i{7#);dAfv>BH~p0}tY^6=lRIVJN# zcdQcs#Cfozf&i~U5bRQq>DMH1eJsmjuCM{p$}u-BU5|+3gd>bH17Y}J#fxpfymz7o zN57uJUJaXBFWC(wxoFyOnQ~%hg63!^c2|6?Vb~dzvp2+pH0E4>qBVNrv(mW_y+f`v zbz@m|2lK$O%v>ZPJzi)R!zEHl#A;<6j_=>_Du08OKQO?;Nos^)_x&L*`-_3AZb1pQ z4>yHFt;GP^8r*{tnfI)J%~z0VzumBJC0E%6M9p-`;4~NXK%o?;AR2&; zu<|~N&nN0Fc1oo@fh0WXWFB)C{>?d|=T1_mI2H!E;bcMU@dWyvfrdU@jOwY`%ia8_ z`xUyw2;V8emYMfzah|wo0pBI}&$!XzHrHt=OPDaHYr_la)b(!}uUx}%GJjL==?*(v zd!xY#a6@X_o{J(mSqgFQKX;N5Xn_BT=_}{+$tOPFKFvjyxI6SOn_4s83M`ahmH4-1 z8RQNg#53@Fl?<*WYk81{)JiJmEGiT|T$Z3t)>4)6ml8{=<@8OR46UG9+4sH0eGM@l zD0}Nc)@U|x?ex^+3?cN6_~pJar-n)BeV8i*j(8{ZjDI6?XW=(1&7Npc0`|7TZD@Xm zbWFcZ*vew!!oEqsn}M@+F~d$L&~2Y8xt=xDloy|UN>}{-w?P6m?x&=`pBOG%+u6R5 zd{TheO%(i0Y^{#61i=Iz7y57LEXPw>F<-x{eiuMfh2i zz}YjzT#Dh=Ae1%I3~}~bbgNF*cV20P%QjaUQ5b;h*^0y!Dr;pmyA+;6*T%wM5`^J`HJ%%cD4o8dsuHI9k1-vK=U8#_$%Z?8iADgQml)I3OOCN@t)0VSxECa6L z??a`{DP9+L?q5RZ%Sv;def$Tw^<>a5(O_`NSa*vqP<+;hEsK|aPBr-=FQ*amSQbB67= zl;=oNPe}^i8H+1M9j&T(e7+yhw9H8g%;8qg!oKN4*C_?2&vM*@Voknn4@OiEe#OeH zV5wRw;mj!;Hk%`cCB8STKSn$9s>!>W)xnKeI@wRL;Yc&LK+jB`X@!2WfD%&=Wwh{y zc}MI!(|KkH&2c9Hr z*JAN|-z-u{XC4HIS`RK6GV|k`T>7h{q?5-)3hQs#3+l;x8V8ffmS~(SGA#RPbDiIU;AN;IF2@!3=YDzz z37+?vFQdS86^!NepsD71UYU~q8%X?mI&RMCip#C8Oh^7sqir$fv73kw|B!1-iUR=<2R1e#tp&FH}&^^%8}!$9@$Dhu)IBx=o`~qY)M2d4Y1)%ajqE zvl|ZeHG?tY9u&;^H5(+>cy;=e&6oY-qH4J5NMMQ#|_DhXut@sV!b@3^H2h^twriq!;b z?^<=7FyjqpOLE|+zfcmh*ju6g>8Jd@r%>p6GFW@*h1mNAc9zIGk+J9RIKHr|p>Z{m zRpX#bEnEgOi=ks&eJ`A2@@t;RQ{dCL807&!_cS<`cMM>fAE1MeD$D@vODclg;J8rc zi){xe0?N4hQMB5Gu*|91C4OGL%QTVp07oghSetpaGHbIwxFsGs@5cr+S31s1H8Fc# z;&;`<9nygxt%;DHTs`si@1^FwN$)AP9i@*nJ{_Tpa9}!zGE^q`I5Y%%aIDpe^z>-_ zRW`rS+l`DW+MMei#4`!hZboh|MthusB>{!J21q(csea);G zeFQqYey!cgNe>;^(($!?MY8T$yDEX4dGs?%syHF_MN*H5b zD0o-c>Rm!~2La$c7Z0~d;XNxo(?%GHz_g0eOK&qRC%iPXGb4}2xix<6GKY?5ockf} zhr{@TF_Dw1VJGHnLZfNlu7>J$?lylmmoFVrWO$v4+%91ucj~)F(Itinq4!)~&8c07 zonr5?a8T%Xh4^mZor}B>g8S-EObz1@0JKYDgnXM(x_qoaNYWymUC=GW5_^@pIs(tI zX=Y*KzHjqDbo4gHAJ+Hy<1O;`Fa55FWV*(i@@!aE7&t!wtv!!Rr+h3KgiToi5ms}usq?g5#rLV) z;A*vm&4e{q!jY!uaLQPZ*?9)f`&8k7@<6R-bnTzVpPrcR5o-N*P;-W1JDon^jd7B3 zkR24-SY8?DN}pf2l^{_`5vOc zf7TSfw3H;}|Iw)T#k!)ezUFxUYA`T|EuEB~simK5Prktz`PU)b2;}eJ1mi&mRt9I? zT413yagwUsh&)7S0Sd}uOKj#OZKeV(ng2E2s*r^ zS)9NKL!<-%ygoGQi$TNmVs;y>-wippdikgyLwqYqaR&?gkX1H8K;3B88Y0a~kQaH5 z`lEhUPFGe*HO@GQw4l~l5dnOjGY*DS0U(@?JnLD_DqT1Fns`o`0A6T;WWH;st3#Fn zXqw;3go$17%13Fh_I27IXYj8dw{X5-JaAL&+p+>|c!h^?_~n*U{`#;5FFkbq?wE>$ zZ#&Rqc?^3!WG;WP*ZQO`{YAA)WB_9mSeDQM%eEY6MaVfwTa)%$Z**<2ivUqk{cLKX z7}wF)ylihBS}}02*oslCutCgcj{0j%d%8ZtX%Uh}jCK*T!>Cm4fLDgUw}grh?Mzr} zej|(JT?Y2H)HSQBdWv6YzsoX6gVqL7Qyo z!VNOxlaYf!25Rf%%ft=f5^MDUJ6Fcjug?-?*^l+PR8Dg;7KgGls;&2}jLFVVA8KVC z(c?3#djNTDAc!87R+Hb+VyU2KDKDoWbR>^%YEoCGlJYhnDQz#U15+MQXV2thTpgQ8 zeZAmsL!HE+11Z66%$TyMRBk^ z^8*~4#`? zCc70+j(lcT>KvxliX^D=q_59ZnGZ>ja!9=uyFFoC%&CuZ^*6|x0PFY=tlC#yy~=Tj zU#&{z#z8{{ptoK<@T@mu-HO2HoKv$bA0Kq83lUq_dLSZf%-w@1o}T3)Ywn157O5wI z2zEwP7x&MlT|e9dYZyQPhaoPXVish7Hc1!FYv3{h5VQaz(Xvf#|27ax;H7V4kA{;v z<0==~`ccht3WlvqOEd4yr@4OvJ$%*b2V0YtZZ!mMf^6YVWN1CCSxauE`UY9PY0=Lq zg>|AyOj9ZZ+iJOMupVff6bBoIM%?tVZ?sI4feE|W^@d!KfMAXQKN z{jFE!HnFv{lj5w-1{7g_y`7l8qVcNQro|5XB$YN2`0%#8i{A)JORch0)K@xhNLBZ z7iE4|Aywiw^P;|nkLT#%?#UfzMf!%wT%>!JXzP}=eq<_HUpbe>7hcLyK ze3~es9dSYYzSC>ERSCN1n0=nX>w|+_Sv5@5Vc-C;EDYyBD}t4AV#IHp_-sj5J=+L1 zOWmU<`~h-OY9nfc#!jiPY<3s`RqHk9_7dtByg7XF))g!Nr+D7>wx=nQ4d`bZB4utR z!YK*%HUV50z9XtpWIP}q8P36G+}6y~tBMpuj4>h9&GlCTk{RRzFrku_qGtq3B2D1s z^!c&(;q1BhEErY=KdBY9S$Y5WAp3Jb9?aOK%EGFn6sQk>cr$`4L3EI-Ilp5#h0F!q zk57XIzbQLw+bZ~Tv6qG8%iUfc$oub-rCvgSmu_oPQL8M>7<;||I(#M*ntYrUCk&I+ zKq{$|GZp1?b&nk46UGD{*ZqR+otS!^y^Eg|F5t+9oNV4GSAIy3B(U&6#$l;QNssQq z?RT#$t!1}PxlY~rJ|mBmuc} zu;5@4M?>g3&s?f>=X@ITCA%oST+2saSu$nNwjb4lT83)myu^7Mcw^QYh z{DecRuH~|G+jZ!{vWX&%vn9|p>{5I&lfmpTHywfzn%i*x>X1y9vnCQru2EO{?D`zW z=r4ars3ts-C?H-He_gw6aU7DpE6c6?rY|BKW~m4)rwHn9h9z67IY7ES5` z2a0fOcNv0Ld0+FQ$(sQ>#V^u=^bUs4cB#|T=erVj9&=VSu9+h@p@O(yo^s@fe3PpL zwLR@D9(w1hB#J6YLw(NGaHg^4)dX-HhwEWjXN}ZclDYIE^THP4<*M&KJk6LZeXH5s zt~0o4S4UZ<%sHYCScR?xCru>yFo+B7u4fH73a?fKG5JW^K5U)fS%2~K!6ZE(^*hg_ zx*@k(7!6`|>J|qVv6{W0J$T$FMLS|sGx+Khh5>s%&sso6o99{FrB2ss!P+jMyUyEB zs4^&r=cS$Zn8+}oA`Uy|<$3zj&anv=iQSCR#j{4{nDp#uX6{#taw@d{aZEQd@=F%4 zVb5rY-g=Ksmzbfhn8;gy7QXN;vi_SZ$5n}}lt9a}$z`EgVW{`tXurHouc6QJmiedm zR^45lHX*Uk8M~L4_{Hs_EpI#_miHLl7#mKt+9Q_lnDIr;h`hk0Sf5-BNM5CXKDW_; z#Dv+&Y}SanFI_+xLQ3zBcwY?Nz#o*Pb`FpHZXe6jR-2%;o)DPh=_iARV)gYIQQ0Bm zr_wl~%PgXww55Dk_p3>Nq^{<+2nXFfu)FC8mgmMzh;aEJ&0@C{Zn>)GuQ9(IIK7I? zCcKi`1zzfOrbnsEIfk5ce$jINSsyB}nlA8=^oW?Dlmy-(-j2{d6 z-F|14vP@y+L$A9F7#O2xt~Q1|oBQtA)^He~wc0Co^&*sw{yGA63oi^y|u64 z;DWr&#v3(gVMg5x6!6g1&SuL$yvZ}O;P*G~OAr`W1xmC082MvCTJ`%2;=C8BAVWF^aw@w~+7E~n zQgkZYGLy-l@kEp^CoNqiCoqt)Ew^-}?S#!8;UL4#QIT&?5Dx!+%1U!#$1P+KEqQH2 z<*ojsC|_4>kTG`g4MtDeW0f-VxDwD+2sjBtE3XB@ z;Oa+!z`34e5#wuNM&gp;l90-=>~?@QgZl!^L)9hdPg5lpLN*lTNhp|2SYn*|(DRkO zB30%kuO0f$SJGcpPfzxi`!ZyhKo9?^YTz)MrC*#d*2br4lJo0QGO?fAA!8M~M0uY? zls=tnUf2kc(xFbTyHYnZA{&d9JzD%CC9kZUhOs4MHp#vqA_9CnNGSxOyfJGOH9N<( zp3;{jPRNtZLZ%i^4v7+jvLcWF$XIxcO0+(x$l8z(X^ag_d8HUq@XYT@6XwwrSRcw9 zyIFTe6qkAh20u8o?&L@!)AiCmUzR7x|6gn4P$fL#vD+j2qimHU0@HsDerMsVxpm_} zy8WgQt^!G9agO4IueKou8c^dZuad4TD~GDPSC}c>UTt$hj^|ACKIW(2RgJZ@8>2|* zjm@^?4;ZG3f1TrwuxwHG%sO@csvWF++fw4r>FThtDD_vVA2wMz4Nt!Vbjk_in2pp! zi`V<=?5`-}MhR0)9%^AUmDtL!!u8A>ywZhKGvk0YB<7Js4xT+{;EVcD_0%DKEC+V} z(a$A3%*$zo3V(PbN0!nFLyCW2lFGwnNR$%fehzinCRGUTAp`Set0{^oY4r$`P)NR= zUUp$TJ%!y8Y3-o#x)!_Y>tND=CD-6gaYwX$k{P#>9JITZ|N_49OEK@d+v>r!UlsEDGC%OdVX$s=pcf)PY5{pxds z&)Sg%=MP=vx(|?NlGxK?0`X5Ze)843yn^#%2U3YCy0@(rAEk8dNQ$aO7h{xKXEj2z zP5eICT)Spw-A*6Qt{w!~DV5r3t+1M1tyT%w3h-wTpAgq!bT$tPlCQ14f(@5^1Y;Ge z#uXJdRZ9ekL@PFGgw-jLdNioWWuWRbY zS8b!(FU=zkkf+jW+S|KQyDqN501)0CAocwcJXnGM%CunT`Oxz=Ih{$OT8e-CL=rwa zjB+`OMC-!&0sfQRqc0x+tutJjd_R4Nw8evMSHX&p6Vbrj7$NjaB<%K%@-m*|2O;BL zlC0@tof$-X0C7+8(~Dxs2F1pT_Z;6jr9f``3{~MpsJ2y|0A3CN|sa@_#4^HJuWOVp+#@-hhZ3HO;%zS5))~svcnf zZk^CWhZS|5%P&VWKoJ}r^}y9M$k&a%){uSG#;m{9jCkGT)8dP3eCq%urzkE*fbp)# z3#nT@%KsTZiqL@TuTdR@x`N71?%q{=zQhYG>>+t6yn|-|Vwgh{KiC#OxHnV5O)a>h zUb!DpDMmaEufyu-+`F2X`o~xG&ALo&w#w3cz^9*fET%SYls|5q7+73HkrtWbimvp# zJCo`LSBJ(AtON%1x(?DoiaipWDk|Rs!QI!B^#|AufOMDNV7J~%J6jb!UyjJ_!cPt& zFF|qoC&g3{@G_x3dt6ALSns5TbaWB%`r0rK0=zO+)lR-(FRHYa zif*9mKW0DpwD%zOx9(CEF z5P`Fmb7sK-Ag2JxkbaK^Kqo@Dxi+QJi1`3n)1c!O_%?}4dXv{Z;`nsh6%&Qb zpHGS20>r%usSCd8B?4ydIoY3Ld@<6}>BV`OMvWU8{kM1rGdOp~20J~eGm3JjR=JV}KqUl#|jR8+0Hr{Z!@>-8AfuY-9MMr81ksC1d)CtKaFP;Q4{bVLw= z5qdwLVE!iskwCHZf5UBj&)@!m(GtPM9VaAT)oj!w^}r+S7tgVGmmsN#1?3#$-kakO!3z)j^e$6&iT^9?n^y9r&jL%c)nD7XwDUu z0fy-3e@k)?-?9Mm_hT{N&x>7dUXmA3fWIhyfQtMu%_A;3f~Dh;nN;ci6WOa2-sGDu z|31iXKSF?GR0i|&c2~-nq);%-M%7CHgOwKaI1ZC<+ceBwG;zlNoRY!5aWLQulykzd zjeVN-b>X>jGbl+^A=#7f`n>1P^($@{pVz&orl-r*6=VF0{#Lg?-S6@EXVCrh$Ks9u z?q!!I2-oJCD*8q7BtKg(?-8u z(VZv$LbA9?s^^C3n$#H6gujDzJ8%zm>z?LL<5vR1wh z$TIXdZOX7dg987l;|zfCtS|t<38{h~bzE-J0ZHH?NGFU(Z0{S>6oaKFZn8N;oOTTu zNo|_bh`0kZ4`#`cxKN=EEr10`PmpO=V|)3!@WOtQzm|q5=9>gub}1#Gu)6XGtWypk zBX59vnK6paRjyr4x_*uJf@|tsT|J!02<%vL80@t8+1?>z(je=lylC_PavK=1pKUUQ zW5ub1ED2k|JHA+_o;N)#+6s}G3y`11=JL}BjzG2*Wx$eKe(7e@5E+xO^RJT1r81|Z)Oax!-Q;V&t58GVazVQ%Rs zHBy!3NN{bDA?wSZ4HWHz;r$I}&wAsLtEDr1ZRhx2KtlumiF5$e|t6 zj2XCdVkZ${U`AGSRr^wXyV{qsc~_F03KMI^8de_;JGj^St4X9?XNx%YMd)S z@%^?V{A*L*x#hl+w5u^M_vr!y&kIbt%r#!QRymBmcTj2kVb-j9?n!@WpGN#~<3+!% z`QTg1vrjY+ztbDM&4T#fT$*o{jEGqE;$o*zWv%=*_Clgvd!(V z@i}0b;&dpZm0&0TPzX_S-|>^xD}m!YYTs!_Fsgo{cdnled3@uR;%Wek$6UzAXTEID z#pq<;hHGgXKX@2V@Vt2%vS)ksd07bVWaMXRKI!T+wV12%AFpTib?M5g>Cz!zgy+(_ z#PP(~PI3w}h0(G)CW3Jx;xis5Q6CJQVLrvcD(6KW5Ll+#(HZA&+%JON_Vpv7AblGN zE#|T#(*ClKLihI#W@>MuE*ma)+I+wU%(=z`nD})p@9UqY<#gwRM&j3aFVD){in(v* zHHtiAiUM61ac;sN>Xk{`x3?a<{nR!uh`4$uQF6aKrgsKkpru^dB?!`SFvAGWSHqOT zuPdxaB4VUyYvBTiu{GM3Ok*xD?IX|eNI!hbJU6Jak{d#ChN^6t6d?Q<*JPwY&;%kE zZJQBQtDb@5Ha^wiK9kkc=;emjY&^I9RZn>EKcc)7Trr25UNZ=EVsy-vUEFrSjUPP!`D?|IV6oS=?HaD8`v^HS2n;!1Cvo3SxFnIcrC8R*pS!R1pGItY zjAX=RI(1Nl^?g{wo?14&ueUn1W`sGyP53}H4g!iSGWTrXB;Y$DGag%AL|zk-hLYMs zWY$cMef=2GE?6)iA?t7W@miM-+*l{|M?3M=Be8dqSBfwJ_9)lj_SB_equ>G_`|I)J zm(w^8T*C)1tTW!S(}>x*#3$%zysMr5OVa+&9I}Y>_D|^`yW*?QAlj-O0$Y*kgT)fH z5e^p}?xdc&(4C_SCVounY7eLIsna0&ni2+PliNXFdYZXRh2gWuDr zdXsVYP>#8sFnQr__~f|8iK z#%mmun;Wz*@A)&pl`upSf=Ux}rweG$4zL$&Z8rfMD*ShxJdyixjrM?#z*UZk&%q}~m zy7rcp%t9$bp`}uOe*eSg^El_cU$6J`=@#&jJEa_EDHwwK@gI%Gr7@Z7>_3Yh|4I+$ z48Qt>>0@#^NaN|Io_`ycYE)?&zv`1mb^9;5~;yq`MXT05H4IO^=s&X zWkG5``GGW7p?SgGVRMOpEJAek-!(l|;)}q_6=oo)&Ff{L<`E`Jpl#!&|&j!0Y z#{1wXL-bPyb~TnHZK0}LLZk8c3mV(QAz)h`AgZLM9OCpQT!4o!q$7bODX1=+OIiqD1hp2{da$^r+Y=xcwu{lxR~vsZw3&DU0&*?*_gWD#i)9%tG3 z4(msDbe^i67JLN5&(OzBY|yX%kB9366o0eL>#>TQs+Fi@np?_It6E!O8Y*GH?hae2 z`TbSJh&4I+?Z}9BZX3kB4M!-4lqvh`Cmg6XK~TcAFM|>;pq!-G2lo=%Ag{XVI&=?o zo3dDi?prCnoKK_91trQQCUoeE9f|lsJ2ZL{>-G?$i5*S!7P8jGFMztPo@jlq5Y-*g zr!--hx!Bm*ry=FE9_3^Y;yszwuoo;&hNPpAfp}(ni*5Q+1T- zCKU{Q-xgAaJV%zT=G-@_if8A!b23~O>%b9+=-Jm)OdBr{xSlFK!0GxsFtfPro8Ha5 zV%y=Un<~mm(I0)=TDebu@}%nARNHT_Q+7xGq`byfWF+O$xmk#L^Kz{BIz}+@bwo$m zUhfuj0CoLtt>_hfghEkg80y*jmvQR}C!>*wZW+5|3+2E4>j z6xon?>HOv`Y0W03mL+K$U1lVvAGw>B))P1mh@zfMOHEOK|6P_enfwgyqQ4 zr#7ooU)qKojT5sx%l4^Wr7s?E`o5^t`=WKf+zQ)a&0I-^3}Y@b(S|%v1$vXzMd+IL zX3`nL?v)HYi5y|XVTpJh%?zg$m8OO_aZqNN3vidI6^Y6CQk&u}(*R|NzDW~`;*Mpk}H+g~w z6_?KOQ>3Ja0t$M6shU;;MmN#QaGTm&ycKftj#%%Rjfsw`O`_OqKHc%6FEO{|UTeN% z0Akf&!YUk-!S#B%EHlDheC;CBKq`%(+{+*7^Ame}^i``TpR)F}R@utB+8v6;J&6!HW2gLF7oCMYb1 zOH6t-N<#TgnrIZmjMUByt?f*+6R&}CM%E_ZWA-{7`d8AUyeEBYA@Ik~94u0luoQ8Y zexCKqc>xN&*pX*Ogwc8j9c%A3S-PHCf2)R|Ln?=?38i-vZ~fRTlAOP=Mrh?Yvu?iz z5+--MYVJ7%ee+&EK76xZYgci@cKqbM%=n9-Dbv=9G?(~=d`9lzKHuXiF16IvdmF;#L#7zcP0yCyZQ0RFzn&aG3$*j@l{Qa^2+ZxFV#`*5vxw>ako>(Wk>8yK;9(Zc6e$(~Nvkf!?_%;d8vMm@u7^XkT% z-gEd?h7CM)<`O#QBWEByr+h6d0RC+M>D7yex+?Yu!@3l1J=wf!u7-U@INWrz1V6g{ zFaRzO04e~W^qFcCV_YG4u^v1kf zH|G`SElb`6A-BtaxVUC>Sa)0?#_1QKetkOZCjM5yXH}+u2Z{5!q_ayA=YjC5%sk8# z?^@uiSQH)a{ekS@{#%qz(k9JSR@y-6KB->nohI3iq|Z|AS`yH3h`2yK1NHphr9esN zv*V>LVPl`~U*7t`>DQK~F6+FFm#=qM=$0_WwHyi0f*A9T(%7cL?@1gxjqI?r<%ubt z3pfAwF1s>XNLqF|F2^jZMlrgokjkFR9WX4FCzmLauQ_y(({4!x&77DrK3<{^4dksd z{R&9aaXGB(0#`W2_TOC({U~p3GU(vX~%jW`9>u-N-n*4Ny zDRo_3V*@3m=K1x^qhS3%U1KDc+OB0;O1_EmXoLE9pfIfR0Vd zb9r`4lZ+5Hh8(?gz`IiHh1a`-=j+U1qDEkpm?=slb{hglK>>pVQMM5-i-iyQl0a7` zh$2_<@`3WWG^hwpuPLclA+dM@A+iI;5%P;6)eV`VSCLW)p%99BGmvqrWWLm7)2fzn z0nA_&G|w#GVW8IC=Em%`tP}Z9geSz2!=Ixn?ohr$8ZJ`9owOe&7}9T_(uu1 z0Lr6;6Xcu>$EmxKG;o4DpcyhIB1T4dc?{d9LKhKjtJ3e(TUlloWAY21@xZ(Yx@I|l& z^)R?x1N-n+T~mYB@DW*bR(6}rtPDAp6w>h|Ya!SwWm;JOs-UGuAS_L^gZ=>wBZHVh zGrP%9wdSsAfMs4UiP#Z|_ET6`k^>BhvR$jy9S0LwIbTURN!+i)CvRftjVlOa@^Y8o zU-kRy93z%JT4;8wuwBR;IS`2X3}w1ko%_#H$uu8q_RUnAwsUVwJN87Z_D>}xE?HkS z1G-RE9+!fq8x1u@V@v!A;sO%Y!RVgF)!+(yP+jy;FTs#-X@JRME0MyKGbiIlE7aA} z?;F4%H;QRY>+$Q6lts@OcAp0*+yKSzDy%f*G8%+*8WGY=QO8D4B0;V{oq#b*?H<$Y z$(w<_T%kJf{~TfySfBs$#%5*ez)YUrKeH`h&Yyw5?~|JW%8y6s@7Q8>_rgqS^{Y@R zFDj5HwiRdj19*HE+TU)VSvJ7R3$SNzv`Sp}-?b|CGa(E)a+w#&j3NyTM_9Dv4@mBa z{lXSrjrI`1=d34&+WtJ|TlNXLmNy(`6$g=y3BGImf>x2K7^Rbq?~uH&x5Wu;c9HE* z0#ElvsM#+FoT{57;G6)@?z&zte2q(rX`5@4^WUPgNL_8R`SlGFEvZh9DnnF4iw)Mgl+xzVn+04IzR{Gy zR2VseY7j7!8CEe&iTc=%{PyT3qA)$XV5nN;N)~~k)tW9B(>(P}+kWLX`TE0-XDbEQ z4PbQIn5jBN`F}LXeL)rtc-+I&VT4N#oLa&j4Fez&7?2Qk?nRc!} z*zH#sq-1!_nnOo2A4ncc-L2nxd6%<~MQp?;RmM6!f1ygGfl})ZQX`0bePz(I}OLqPrb>qsRaX+&#!uKhy(=yfP z=AsN+7cgeK*H`*2&5mOyN-8I2+S;t_$4#3I{|qok3nyMFpOkWt7kZH3TiZYBcNB2j zVsz0`W(3CI!db<|_I_7}IeFVGokv?t1X9!=5xdljMcl9-NnO1~M7)pe+O({^e9Zm! zSBghTYra(R_-crGQ zC*ZEg?c8zPP~}-`6JCd-Vj4$^sJDdTgiFu~EnboxMR^P%Gz)!43`ts4-X{C*Ya1VC zZC@xXIjhKVZpmW&Crh?1RI4yd@;6gh=E|0l?vEJM4sAGE0g0_meI;a0&kD`@;3xAFI<6@OQj(Qn`>7t`Etl?GJu!)T%RfW|m0LGkS3TEV_N7 zuBQ-5hkE~Vgjd#XGP23C#vY23Y?Nha#NnD${F3}>CyV=2YPtkZ&l&wc4GOnuM-3`4 zm;~iE)^ytXO&XAq5v&(DHnVp+!t)uO%bBS@&7)5;jDA+LdcMFM%e%R+1tF1_LVI}| zM_1A@xy=D)yh7+>GA*zTx)E{I_c4VR*O zCn1rPNgG{9(Oij@#Kz;XkZKDR>8dL=PcL2TeoP|r_E#1px>gUGH_?S+Xa~XR$H~l} zIH|&<(dwBsDAfxwL9SR0dGj*;?TT*S`q*~)(qptU9-rIRVR!tba9;SEL1%)kpm3bR z+G*0f{(ef+f(*ND=D4tJ6v}X;5wF+`S+A2!> z`Hub6;Gu9_Lw2J=(r#?}SUM@7fe>Rh~9nNl>Da@-4Z|DiP;S)-Ea;u!q8M&$)6nfP%W0 z%9*@p7}L3OYMu(sNf=TvwTTnYxFW56efWGSTeYN(O*lp#%ll%hLJXmrpJIR$9~y9R z6ZyM_=f2)4I??T9s3X8~ZCa@_L7LCtr= z8qy#C4AG)hQw3G|mL+NlT$(%;`NuHJ)s`;kl&xC_cbk0t?Ru7|0VcE{Q-zrMr1n?M zPC=O3K+Z!ixAFY6Yn%o+hp#e)eR=@24b{jf*^|Ws7YOn1A-VEUpOJ2S)2T{p3*1eN z$WFRu`7EKF^5=x2K!oaI`y(fwov#l*rnKo&U`?^y2JL+%{}~#j`C-Z2FnWK3*)2}K zvHr*9ll+U!OESWfahXHmdS3`88?G6)N( z_MD|W?U3N}Z4tQmo%STG^y?Yj%xzUnN{+QR+$9VA$!t*_h+X+L!B)2v$=?0p@{qFr z-LzL^?sLy<89tnB2jh9GpIVWYX2NWCm>s!PzG~C(7wNy!=x#7Y>Y zQNHq3`;ncu^3A@Qa8u2G1S{Lim3bCkc(!_85ZDK$K`2uQaHMzL(Fij+66Q`(ze9=K zO$;VNBU}^SctR3p+q8{T?&2-aWcw42^!2GHHMhWGW0!_c7P*=WMh47`{K?}J-fWWOoggX%%KPf|hp7F#`rUsTC7>qC=@Hsl#ZcNbpcfG`5X51^_WAD8~p`qy`Fatau5R6-kc2(aZXm*8Ct{N|AbGgRksu z1cO+8_KR8kBDPJ#wYb)4S}CS28%r0L{6;;3MhZ*Xf95PX`G)C=Pt_b=ncRAX#8o^mfy4W+W_GOe9KAh%GF!+q zui9f9%Pp5R zU8l&supT$p`Q~pWI~Pfx;QYpQHi1+B%7ISfE4Qj9=iAhPX18;zBuV>l8h;Ab^@6Uy zi_>#**Y005YIZ1Tao{|oE3LyMwN;aj)+CML|7QD1>oC4>E5;&1t!vF$vozz=t38A% zL;9sce~*F+J>+sMDk@gh8ft-}5e5K@i>4<4*o;vjOzjx*?cV<4gKTuJ3nM2yk>k)} zfj{}9n@jydo`n2*FFI%6{;X0xGN+==HbH1(7fExF5rpvy|DAO1R}2*hgvz(r+&-i* z^0{k8Sax2qwEOqQu+zagL*<8bou0eItk@VCN8p>DD{#JQ##>4*fc;@JX=};spgiwX z7f#rBN%2jc`b*@1f-ipmR7%nJ`jrSopN%6i&&>g^^4D^m}-eE}?!GpeFa2g&3lCQp*FGz5r>zpS)l@#ex} zWoqj^lt6h#0+wZ~yu|)>#o3dAKWlNhbp~;Jg&)>-2J1|=52&xVXf#Uman{qvrdmbM z+l9RR;F?v!I_{&ivY2W? z8g9B@$a;-kOz&lYMO+5%qcNF@vtgBur!<^9WQ%B3<%8f7c#=WVkQNG>SEJ6Iy)772 zl}pGE^eA$Ne@=wcr{-cR}Y~uF< zzKwgA?!q6ThU+;Gvj#G|k78ww>0$Tjxq&681StRR5gQZ?6vTy(kir$I^=XL$ryxU0 zqONHO+e<23aL5}PfEI|&-r2llRcZ0G)4p+IgYo{SMHRG;a`~|ytJICjuiU;Y{%UREwSgfrTh2e zE8`JIT5eo8b~11eoa$%L+Eld}#t&h$h=spywe3QMw=VD9`WT#0KF)*8vfB$5D33)% zfrK~T*#blslT(s!oTVv^*C_~>Np)_RNhKadViApKsN#B*7*SMK4% z*oEm+dP(Kb7MWE{N*a4&njSm%*lQn1!e@R0R`knfP8}YeH#wxEjN2!_9^8}FSU>Ul z7~1LtmA8f1(9AJW$G16=Z3AzeH?z82ehW5AnCpGEmNwT5dJ^Ey|3M;glAQiF`3B#V zd#POjdMWVRPG&0cCy19oHolj@;X*bJienLoNTfi%(h`kt-gc|;;d3dgq5DPkD*rXS z>K_&HpzAzye|0Ij#>pg3Yx%GHlSlu;G| z-I$|tjRG1Xn|#zc$#JT{OItubd=qLWV~f+TH@7nM`lzdI2*hQ*Kf|)i0BqKljxvI1 zJvNL8#Q1qvT5CgXs z!lUL3CkPHx_CpfJKD}-adg;vHh*toOk)jviLOMYwHjeG>AGtwyWmwIDm{?0LFJ7f= zOOqS@+ScYy3KazBERB3ycgfZv2chN~Yi(NqCCCz#M^1nnPO)V>Mq7nLfK)weTeqg+ zs4C{BU(^&2?BUn|y(&nZPPjDLTi2()ghrji5;!9J0ym(<5WZYdK2OJxdk(te6ukNgJjEdoRxW9 z3J&m4S1`AAi^$uuYx%*u--t=H6x1_?qVF?hU6IN56h>RyYLA>Odl1roC2%qUq!t!Q zP4*S8&H~qyF`+6DFi7xPsAQn$!#o>+p)jJ^0Ri505Any~Cy$=~j-+VN4b;OoHr>lm z4uP)xftg`<2iJnMJq?lLk?0#A$NSm1`lNNUF|sK`6{%7ohG-djF>c@Te=eMVLDGvg zqW3|Gak!vW*3Uq0!ygMaBW?2;l_X*7WZt&U{3f>BdFf%2|oGz=>QxJT+*0`7D%bp7Q;8BnFJJ|rkP7R3sc72 z95j}<^({>=ua<~orV2CEiG#e6j7ci5>Sy|z7A__R>VZLmOz(|1Y4m(QqI3UbL`j(Q zCq@sMh@4@t;sfcKj@yWbSRUB5A9a_j1I_DiyX_Cm_5#$t=UAOzab_ji<+blyyq>OY zOt)3y9{UPwIxF+fI@cJ&`HV0x4dz%PGUWk+9A-XOq~%eaksFtYzuQ69D}V^*&YVjt z&=Uf3&0Z*z(~-f|+7hxBFH+Xc{AtFKdbi4J?mQF^nsJ*60Ypo8JH)eS5}5D{5Dn<_ zaphD)sPLtFK9i^<6Lb&s!Ti@2(@@Lsc2moh(9oQPXhVWfSOq;OTsD^rdS9=e%v5UL z;G!>#6X9}Z_55DJSRtG&=;y5cAyobuYPu+=;zN2@&on3F^%#qHptR>4LaZ$)h?`QC z_u}hLDPIb#z||*`arL z#ny=JY|*l`sPmhniym27V;1;kpt$W9=Wc$Aq40fytNf`8gC={_DuJjN5Ly5CGqW`6taLEt4{>S^ty`j48p z-sMn&IBR?k)GZW>anRwLl!fU3SO_Y9daL|&G?()!$*Zu&E;BYww5^G-FY&!sAqsZC z_iOy5V3Vq`Q^8Hs`ub`6HMY`~VXX;^N`0-SH9iPiy?9ZjOG8wrm~p!wnal8$T>L4s zg-ETc;UUpxg$UiWlfV2>o1b5UDPrjh;?sLPxNXw9AIC)mW_@mE=M2_I#iu^K}}L);1GT{OX(`EA^8Y2K9|RxZCvkdjS}D=zDoY-kT+h$u=T} zU60{)xtI~x>a66uic3OM)WyG$;#Ya;?DCi8SnPT=MGy^6pDv^YN7R>GI^J+}`evt{ z4@+Hw(@C~8jtIWQKpb*{4}# zlNi-i`U{EzTS2;Pcr0{TBf?4N^_hAnpw4JX?`!#g3^9Egf%H|==0BOL#UIqLz5@-+mw z;{;a%sR=}cQqQ@^we9R_Ukh7YE!Tz`8t%TaG1i0-zj*FFhqbx$*`#|L!M~QwuF)C%aCY7~T z)A%aHk|c|nX;zrxn@PG z&@QOVa`E5GsH<}!tUK9zdLm`k*=Wif4}egk37A?&Czr*3_^(`J-%x*IcZYc76?e8X zIh6Z3tv{YTv=K3k*x9J*7tl{DfCqE49#B$pG5-$9p3dI$mKPguiTc0QQwXtZSvs9D z>#U@q3=K_!VQf4O)b2RI3=!rI7E=4Pu-iWH=vzi8NXzsCvViylW#?P@UEmox4 zAr6r}iRO4k7BP=lWdqfikD5ggde?&t;rPf2I8QqxPQ}%lBOhGB_5GfA@h+ zPflO&HEGD_kp|q5NJUIks!Me1*1<1B-+iOd?JjIV8}w&C25n%SBurN{?=Hn^8v*)p_*W7QebcKU$%YgZ{l2&826Dq8>_~XSreaJErp_i zA6Lr!qX30tXZK}7XmA~DH|M(IrN$YC@ZYhK&Zx`j&nl(Zc7p{>@(3Btp zWoF5;)y#gC8q{M(8N54mY5cDk8Z@AvJTQe-BdIaz$De`RG%+I`BcSl}AT6-WQwF5B6)Y*5c^X;3!~iOw?k7j%R<^5npN$*V%K$CrnMb z8~3{m953qdXSu8Jew8*;xFg2$%167Ysj$KGzr@wa&rla$Be>x?NC+Fh;f^n{_F=TV zzG6$^={}@b_Y14T=yr)_Z8S%(q|{_b^5LJhE%ly&DrbJV=}Y7ESb4gBc@r?g0t^BV zogtz!Y0G6ij17mYy=al{!_Wj$ePCKygvLhbrJw%nr-EXfr2fE2WI(x zA8S&MsR!=J9t&3QJ{4OhrAGFQK$oWz!9mRBsB%GnU1D?|T}zl?26fo{r>@O6oxAz#m|gf*zPUg`OOJOHBMuQ?M=~k#n&8^Yf6gr3R;`5bJ}- z1T2~D{*XW0=X%f9MiRu`eQ)+6yIBvq|L}N++lt7~ukS44T2jrFnd7Gz3@&1n!_#v= zU*{nc(S2sxhLjrCOCq{$U+%Qb{Ce5i8J1LbE`HRu9~@PFWbd%_!`a+D_?mdo6&<5^N6eAl5*q55>3XI{Wag(E}cs@%R))&1a?}BjYFJ+d`Xhn zoK)ibxpLb!a9xY1oI%E3GTVMZWeCA_PnpoQ z`?66bVyH55NZM8)-6tefijhHUk+TVhI*7V~wVKS*XpI2J&-Ek-;|ELytdN7IKq z%KQKv2neUTqjlskOyfI+r%vO4mj+;{9)tzh?4@dBeVcVC|Ol$8D6oM=2Tj)=lu%rABm5(Sg2w(qMAJ#< z@7{d&w`ozeLjhiX$Jm!|v>k^k&SjXsS+{jzJnl6S@=5YnL^v#C?>1W8!D>p7%DU<- zhznp523e6sARE=4A|o3=C`5Z5ThW%hFz`X-t%U>iHWfAB)6a@Ye-vqo%Ncm4PzU2R z{0!*2euRV(K`oXYdov||-g9{2cSqD;&Q@%8Da(Ra@oEH%=M%j}e>Ty&>l)ClvXnpB zKcg0wbh0~Yns2%Yvg|?V>s%P+Z3s3#AlN1-Jhd7u3r+Mb1~LxBIJL-ZpJSfF0vQZ*F{X zc(YJ05E++KL{)UB!D}k#xAXu%ehNA^kA%nV)x?8*vWM2~TH`}iw)AZie?=u^{)}e% z@e;c(Rn{?)2w^%PHj4Kce93n!@Vm1n+NQ6T{o$t3$IdSK$);zAU1VUQh9&MntKRRF zc!TeBj~aU(iO&wlv|i~Z@H+LmOVbe}%xU6IiaNz!kWbG9E1%xR-bn4!qzk|Kp?*Ng z_f0dQTto3hHIkm%CG@9w9H`b{c~XsVi`$VP8fZhQmHjWoeU$pXwboK~b&$+2Le$<` zZR-#%h&xziGMTE~v{BhcOD@vj^)kpWRV(|Pdc8$4yMLMxTwJp71L}S9(&>hV(&;o6 z@FX#HM|2W)K;&^ehlf0D!cFX~T9WQ8wlNIlgNL;zUKe8nX;&@za~0rzG{X17HJAJ_60z&HBDcwTV#O&LN2Y z=_RDq{wA%OV5`W;3+}@6)9re2v!EC*dBiuk5e1O_#p%bvM7rb)=HVcN6I;DCumlUy z?hYq6K1%#-ZU$wi(pGHe)@l&u^h2f|AUS#ONXP=xAv*{yI+oFjkKqRCiHHOH*d#>J z`-%>Psl)ulvSV>`mt>N`bXQE!8V6BU*gjk7U8d%Y5wL7HcCMTZ-4d!)1;IV#*dEM+ zfkX9^ic6XbZwfqe-0gDB@^L$2GRa3QVrhUbjEz`p{~^xuzJOXDJ&lDEKBdH?v}M4- zXWCRU>DG4zEjS-O#MXn)+}_sJF6Q?zpL|XoyKlhMAe+B%C<8Hoc|Y=sz7`m*5Pt2C zVI`Z^KDv`XT-Bm7+D@~%i^aE*!!W6vm!o4*4KS{he;p9ka{>DPYLbLWmdezV;vP>L z>m=fbzo2~e(+`*E`Y5aa#J-n45S`Rmpj9qtjO-VC{SIp9Rg+Xsdnr<>KwMMpROvV$0WV%)i zq5QdOti}tlQF@tBwC(pSTMgKB^_Oq3cf({ij|P7> z>!1uVFKMQ_k_X|?3Jn^4^+zvfHz7ObYdK}P++saCijiTjH$Fx1{P~+2;JLrX|2+wQ zUQb7)5ue%8DW|$T6bq-nUQ&h?$r{ssKLbnr^>{cUa095%$%}KE>!$?bD4Ya%J)I5l7@oHHrfPcn#+8*u^65ZQ+U4uv5J71d;?Wu~M1F>Lj^^zhFvW3m=-PS^? z=%q`Mlv?Alk_!5N%h3#f%vNeKU>bB`gVYexX`?IIU}5C4j`I+^A1~3 zAjzd5K<;6528Bu#>+V!e*A=DWPE%VmcG9YXB>Sv~&+-O8F(Q zSAnkA-dF)iM;zr>v4uoQts11sf2CQ{cvqO&hUmW76OgdJCo?Wtp$QY5Nr)10I`_}s zFk~s&Y)Nd2+DH12C`c`Ko0U-`E}j1tm44rmjH08vkNyrPC+H2RL=BJWV(>B?bnGv9 zg_`tNzxL~n*M`?sF=La?D<5RvZGbg}5pZ@ZvW2lr=y*Lf84Gt{e5AbV zw6);4kVs%EJJ#jUwUEh7TD~G=-1p8=Hxq*AUN?dV~avP!vd%+*a_%+n>yM<-7{Q7uyoJ2HkR`?p70O0d{)*Y{Kv{t z?~I#U}0 z1TUDB;m7V(fuxVZkK-))$DVYa#!k~5|^$OYF>m7@0X$d{p{POuZNYHOj~w`r4!8<{S8QLKrp1J zX9F2>a8qPA1S-P&y(}f)SkUsc+5~R#U?)!A3*&U;<7ACX8Z)e^&Z{A`Arqi_B)n_S z5t1n#t#heYlP~ecjr;5p>VF%OajX6G@*cF(@Il#midJoqr{i!8H;_^9E$!(}OY5ma zi(MWIgLdmgNRG?@Y%30QjOXcza5Y5j68T@Mn0!Erx(apI3T#+=yDK!OB$8r z>sKLZVFW=8{-U(B`N{Unk0s?F{V$FD&1)KSwPLmdv!HcY;lBqDO3lAmJku9c>e!iy z^sXTOJeMBiR#BQ$IYXDGbfYi-pdXqBTXME;E=SgZW!h>&(hNw*q^(uA0U9bBbvgFe z?iv%!N$}2kBPTQa2Z1{6Maxliirrn)Gq*o~wG-|6uSt<`?U!H6RLf?t15~SBT%$Ar zO%&KX`8-o$qZ>kKx3SC#Kfb zf?3U`*f}04FK%jHL%X8 zy&_HHsfVMP)wGKr46nX>>P+>~nkq2h(Ovs{Ww)k2YH2#2?x7fH_V57pi3#n9>rcoh z!E-5hm2wo5h#L}cWfh5K=0zirZfhC$XmtnJV3TNeYEMIaI5q*Zo7UC~Fd9FMAa6&Q z>RCEs6Z@FO`8{tEw%<~=JD^fucp0N6+{pyYe3|bM{|(6>+mGW=P-oW#X{OXfI7^@w zAP|pitCbcU1fASd&d`-t)4aj!-uq^UIXyt%l=+BKNMlC>~dR5`dZg z{Koo|hE5|)DBz~!M83DaZ;bEYb9h(qCr+L~+XA1Xncyb{u8dYq*W(&7;8~sX4r<_o zI+f#=biqY-P!4v~{BZ`qakt5dKSb#pwGwW&*O^&ZrK%AVH}P$pAg?J`(7Xb#3-O*s ze}VvKbLe#nV>cDsJriEoEM|#{rRd%--b!eCu;*QO$^nCn?db2ep#ESp4uOEgsMdjl znf!@+3|P;by_q)b&0k197ZYnqjHDzHwjDW%cBWX}ozy94ke051N`Q)@kivpgjK+_o zcH^+uUN$6p^yXs3E;KTa_V0YaHuriW1X@QYKBlP=X_)X6Km3@*jveoQVRW zqT0QhjAKp4+zqH6NiJzIw)^)gxldl8LOnk<%>dOTb$zTk;ZR;y_}rgn^T&;|Gsz@( zYR>OcUt}S|@uPEzV_jv~XnW-8r=TaYM%=oU4)#s-<$g@>G=cco>v6KLs++zNsCvuk z^~;C&bWJ||*fm_%6^xWbM8u^t^T>1HFwRXXm1hnf-JWEm`X4+xc(7>NP@Js~d~9tT007;HWV4`RT=Nwi!t&0Cw> zlEK8IPhaNb2jNPL!tl`IM+la3IvM~jmBpyMU5({4ZS44T$5=>_c`mR>R`KU>(C-gH zacSR%3}WDMO4*vq%kP(Cz7kJl1Zn&~HApFI_iN>`Xm@H~IsZ+6wO80&-~H<94az}0 z_DJZB;U0U~9Ign@@jX2sm^tI!K69_J)}Qwo+LjoJn{#f|T>hGzC@fnlDpKgX?Yv3N zPyvIVEJ{p*@%1x~GAyn@{SOO4e7PaCgPD;Po;B~ZSbKSC&S^XM`}-njW1;&%@T}FePa&rGItlhNxvyo8s{A z9}EC11H=CqIuC!gpD>Ppvxry`v1xqgGL?W}BFysJ&^-+O?~?>{S#+ zttzUDYO6Ya-G2UryVu?8?wOaG?B6zXg1lS|VI)c{I^syz zeU!qR2rF)ERj?yIreI3=;P8W{wkAniWn+^cq;94fg$r2c=#@6w$Cr=+iTSwUI=vMk(&ytyjq{Ukd=+h4?2k)c4g z4oI#86l{%CZ1vuM@THNEPM+`EMi_<_&4Pf zFYpYvA7?N#P?#}rFJ3=?aJ|M-q?^PcFG1($_*LtaXYSW^=Dc&0i*8-+&Zpy$%eJ^P%;i_`5)7u}2Q@-ZJdA;F_XRlZ6K#PCP_tMsP{cw`< zwD-8a*uzVtp#`{Tli@Dj;rOdqIX{qd-OgvUrRWDMe)<2t5Oybs`ID`7*lg3684OqO z_dURV5xQ?eZLfZbxVL7n!os;~A@EL+okI5=OkWX|_$9DLkrim&o|O*pJ_bY&l9F*p zi~+VO*88IU`5&IVz|XMTk!>~e9Z~{)qKq<&&rgwN6(T;_L2lN#5W{@qTdBNg=D^Np zhS2gFeK|}m{e_`hi9-R|S7S>cVf@8d?p(L6ais@=zH!G;bqAH{0BlF0#N$Zj5f~ua zNqSwQgNTg0WiRju;>CUtSsRgcF(BVi;CfRLR`Q$m+1)j58cDHJ)emLJ!hf}l zQ>&UVH?H*Q<-kD8OZA)w8M+6}LC|kvJ~z2&Loo<>Ii^8XmT9&;*;I{CNrYcy=|$t8 z+m@Z1GXeUE*^nUZRmO4+HbJGlttS>e0nW0u!}ajC*OCm|gvG151-Ul6BRB@V^);d# zI}ov&cb6c5=n!F?H~2%}w109(NPxQYGL*(j#kB6mPU=_U&(?o57A>5`-;A)Uqte=> z8mR$Gh1mbX<|AcjEEh|n44pfSxxG2_`1RlMpBdh*ztZ!o!%3ivHQA&_JX%q_nMm(T zXz(M!xMY|+f| zulAR%;q7l(PN}nv`Pm_f$-~ra8B~fX_;oPte6X|qUVF^@;45V>W0oE3l4xEWM|EeF z5v_t^f6ZWdy_ULI@}*_^jlUDyoE5Cup%%ojEB0VI=PBxH#)dcZ>pBbnZAh%ma-9H^ zyff0?0lBTNanPa>|CYYKJa1q}uAvWmMpY=wlC?QKjXWBO1fUEn0OD*$+}*#2Q$sVZ z^W!h8lm(l*lmoe2geUL1E8l;I6%3+(9e>8np#n@@RIl__r*k^T#pX$$(L~3~t6bI7 zY4QAs-S;p0a{p$h-2r&&yWVbuLT!!IuVIdo5)MZJn#I~niF8qo{yc;OUB&gUBYLI@M#3MXuP3Y%To!>NxV;ftuit^r74KUk#1*~!f-1%uq{lrBclLvF z2h1$%Zu5L#`7aga+2@+x>nud7jpvoSz&9{$Tmuz}Kg6;ctZOo%$bMXonP=W%9i(bX z_qq%%+{9U6xA12NkM?k|x&q7w>D3jWSm!7*H2tcBmR-mdAt#i4Wsb{_s-jo4w6LVp zx2cvla-yH}M@)Y5^=lk=FceUuEtB2}KR#(% za}Qo{r4sTtaBobWZ7QL{00PEJs(_MyFvh~N) za}O=b-7=Gi~eLFDlQgJZ8# z1h&=Q8T^Pb2pUDH8XjL71Z8@Ygm%w)2rF7L{G$I<9vv|+H>j3K_Q#Zp8}05zcNf1G zSgRtyOQb#(x*+BM{C@V0o@U6QrjkK;@zt!#uXfVx!Y6NBlAqzyW z?LPIMgf8ePckN9TNVq)7j0tOX1fLrR6_NS8^T36|IWLjhI1Rv&`S`Tq*0Hpw_e&a* z0ft-FW0(Z$FxdV?zD#q$7LG#{XRr&Z7sIa!e34?2Gw|%v+s@0!Xr-c^Q1w6fL=BHf z>Ho0Ve2QkDgBoYpNRGG!_DE*xv-+wYKs1iK5MtYj!!Sxl^e#KPWx)VOhT)V_=isdE zqB9o;Je=ejK4xc^W=A(V%w%=KVu&HZ@(3QOAo~)}^nx8Y;FFo_l%>2y@yhB6U9l7| ziKYSk!YY(={2`sbh8)1?_f%XL$kK(=&ohhkILDuxPAP@eXCOGp4x6WIO`~ZfLQDvjU@v3${{4-ivqmjg4wA+AtaUEaPYd z4m=#d*S@hO6_oZ4<50~oAT@tVp928>L5(>|rL8<19_^8qy!EMZ^NlZGCllX5-(zIUX#q8*tjeRW@-RXp#9d4jaD*mOA^! zB2E!pLU%WDOIOJ(Wou;Gyz=i`E_ud~SLs!i|K{Y!gw*Bg7=WowbOBC_i|Czy`$maF z9j)>Kwc#@8gsqVs-0|5-G#=6Az~q0BlV(e%Kv-{7HWEF+e|w1nwOD}+!6Eir;dAQG zClqw2#U*msp6%z-vb8;E@V?P4Cg#GnVm$Ssa4V4>hu^cG9YgO6Pbh^WBilZ*TU)AF zl`da{;*i_b>AvMxH(Ksh9;T?|7^;44N*)B`^E1R?%uD&TfNZ?Y;@^eDEF6<$s655d zYQ`>!^UAN!-h5sRVUv0OgyK~GO}4~(V3Uuw6@cmpw2`FtiDv>&!5x!xUC(a_O2N*w za;|98&<*B_Tpi9<*R;H8`j@uwuA;YfPPgOO`ENRz z65xgT0?_foo2LtoY{5;_j@nD&g><7b!U1cS|8xkrv4H`(0j>|{^!Y?O>FZ2G$z3IO z+^MUcsrQ_?UsNR53)@z!%y_{=svMMB3+dIYbC|-p6WcRdjSwc$FH2Xjd40>bu&?lR zG1kMvaj&NMb^47(pov*z&m>OBMp5kz`F_K%b#!EI!Wko)wr1YSRHE<{kt7{;j<695 zFT2I?jysGat&YLIQP+*vx}b*nC?i=eu~L+fJ4`UJ=IT7K7|LPe=8z8bn{&?M+af6j za4{SAuB`+|dl|e-k)Sy1OrEck$0@dZlyz1(t4JQ-ae`F5iKESW%>n9Tr1NwEe8!)N-&D5v=pd(DmARMcy)vYS1;5AE@oYeL(Dzf!l=Q^-j z|5dfryi;FC!jc}!Mc}8)&E&rmxQT18!53Gy`}Clo#4s31Cr7}bGrvwZazE?oPYX;Z zfb!E5%;8tsbGlPe-4o;|wTWdk_V5FT+&B}h*wwoi;6riO=_wdZC3s^ldznYoA(LJ0 z)A%2F50_CLWqgcNFNfB+yc+0-8U)?qY^Ut=6r7|64r4rvkekfF`IERYRq4Vsz4|** zHJbFdq{40_ogSM-c4V_nd_fLQShbM3v zjjc5zYnntG?!NBHR9U=wm7YOEujzgj?c-}=$@CR`@B!#)dpd43h`ZYVJEn`}7>>Uh z^qvr?)uo(|?bZw;3QGX8w?=by%dSFk3Go_88`Ewjty>KAwn7u;YJ{qSXO1bHd4>nm z3bwqpS1wu!As<9g_yMI?H1z5cXLvX?Ii9atlv{lD>y~KEU#}f~t{SVhsJwnfSL++| z$nrl2*NyGUjzdx*(y|5B0dE4DiqP^b(u1cIZvoaHK}IhY7ttDDhRu9ok z6Om|miU6dT1sXH(v-RCwOP}K78idTnE(AHzQk_f>tpy7wcQz;qMf6enD$JAa<0=mboMtZ{5TcY% zb9)lfuAWCUqj8ch-os}`w~koglAlD74pcn1`cHg9GdF`@T`K$EsS#`Wor@p?(=bOh z%Q2|@3csN&dFex>?y9(jNZRz&oxEGF82!RWa7zs*UkdJLvxF>XL$0@Scdtm&{>Ha= zj*sXWb=ftpyi_$UFxJrxh7!lcZTn&vSc;ebFqovut`=F5IKFd(56PNk{FZvGKh+=g z^)EMF4icZT%gf&&OQnx_^CK4ih-hwT`AlU07U7dwY3e+PmAcTlkhiwZPJC}OUHNRj z6+a4=+%U$#d~(})2#FzC@cmV$l2mkl%1T`r413SoeFtmP{=%V`~Z)@~hc$AL-1Al%$V zpo!gYW<)S3KE3`=$ZkX4EwZI-=k-O*o7pT67fiCfE3X|IFZI0&bku+m9f*UJSn;L$FE2HR5Uz)i*#9Wb8WMK=(W*xzj2_ut8mf9 z{2S(YZI2{l`o+NIReNnEp*CbKw?T^H)umsZ{WlmWhc!X&){(7tGk?8k-hvJP$IQ}* zrwz%`kTbCFS$$zs=-HB2sCmpX2=g9qe-h6+Gr=fyHm^ z8RlFCm<6QU~bJcwC#wq#Z8Ul{fK6s%#HB$1l_ z1twZFpR}_lSv1JiY(?KegXVCu> zOU^Ww@RV(d5klsQu+=oqNWECnd&u#{uA`~E=2Vim+?0{8` zgS%uYe0x8Z>9f_MV;qD(f2}dgMG4>>2n+hv2^cKE#+S#|eCoy2iDCNenl=%5mFt%0 z=b|3fFgv`wojuzvRhsAHv`?ZdpEh#d5kaO{l9HT!{Zua^4v?X~*s$?SzlGu$tjIZs zJf0miqGJ&k4zji;o%j#ZKFTYT{j$e7ST4U4-pJLiP(}_Hl;s>0e4(6)v_!f{>_>rz z3<4v{|FWQ)0CX$M`9-h%F1VsOkBza*96SVJ9Ll(A#UF5p45f>?W|Z>FnUu*RoFq zWSUbN^o2|t)KHsAD5833c&+~xaabjlcoiD}S%6kp**#%HH(1fP%OM{%sWOo`SZ#`& zE5M%?8r%D=Z-iTZg`AQ~pLKfJ#fDJ!JsvgNeEN~N z2{Qdp04L4g;59&2Uv8umgU&Wc{4PF&yG#~eX3spZ>mb)N(Uzx994O3o zIX3QOGLh^0J%dpu#wRhIoaLQko_BZxwQQ$7E(>6;`urHlFdEukf`)pkPm6oSx5({(xQZf$WD;#c+D135XEK@5?Gv z)~>rqYuQL^Dm2;GWUsOG5u)IyN||)0u)HYLqSHAyTBTMnU11d^kZTh^EYhP^-Y=LO z%B|b8Elc-Bg*VoJFV^cTku}BOUFmhW3!Z7at=guCQB3WH zkau0+0IYSe>6u~mV)D&j-Y9Fe>@QF0VrV)9B)W)}+<#)g5~Pa^!=l(>vI6qXkpg3X ztbsamU)lOYX)}1I`NK-^g%YGOwKHY>@t-Cw&vW~YY5#2v)Z0K}kDaYf$CK>e^?GBT z{?4$eobV75<7C*=L7}@~7PE-^zCVi3f(%ULdS{RWz8rUdgD!MDi)dnh$T0J$wULxj zQ(7x_d2<|Q%$9=yN;x=X?+(F*ItCIg>qrwZrW$dkRvVkh+DC-*`^Rh0YZ|<* z>$8q&c7l9l02`Jp#;Vg4+2}OTurk~8jLlgtU~F`W+whs zGc?V^@Sj;LS0&A??+%@)JQi~}gGLvG&G`S6v%wDzw?4x>KBsX$tKS&7!XnS0rdA!E z>?n#<9H#a0s7*h)2dU+fPh4u2kkh~*VmJ7cO-1}T!gzoo*cII zHi+khKjTuEd0;vyW4!o)VP>SYUG#C_^(EKdI5xXJ$kOL9O3%aM48pAf3Bib2^~VaD zv%U$Mb+~S;;ryz0j{Dc*mS(&ASo-a5W*06+}{-(BHH+lf!PUueh4pTiFs+PVg=4|zHj%|G4PtEhJmx3Q~mT~Ofo-Y}! zdqmP!(?Fau6RTnZ?w9Ff^Z1N*sSJXq3uAGaC45{|G&w@q`kJGV<1SBAT^668NBpGH za;-;huGZEwniDas!k%|br8Ivcxng+1-;I<#kj6tF! zJYXGBtVAw#$xs#Y1b8B|C^~uIV%y7kt;L5G(eDO|=9R+2l-RDi_H29z@}LjTHq&`! zw3Uw*z43?Z`0s4UZ|?rwsbP{!5WJ2WG5dAJnYdoHFLX)lx#3dFWy9^` z17R7zjmzq`>L;G97tRXjoV!DK7|P*5hkYBP9IcLLTcj6;AsfmBsZyLU%DHxWK;5w6l&$Ss(=n(>RL?+?VVRtXh|67RiPohx+%*dM)hHi?&x?C;Nx zkYgxH*{#qH^rw~guM0fm{l1K})|>v!L!D_7g+5PtFR+2{nu>Qq=ho@G7*+d%>5AW9 zB4Ch68FVSYI8B8zA)&0b5QYn4{le<|vGx-;1}58&h1wctf-C0r4;CVO!y@lZEVGe! zIJOF7S|JLVU)48m=%Dl;3G;IA{=15=toxiL6yYay82tMBf%PYMy}xGcck4$6U$!J| zcseEPKR4XCet32S(n6VbK%ikKHYfTBk%dbBWY!drT?&*FM|*$kBFAmEJFf3I!{3c% zH^ycUN-@twq@Tw1w6pZ!_&9vzjC~YOrkwWO82Gnt2$iVIXdH!Z<<22-r*MNOvE{EG zF_N#Cf81M_S4!BA_{jUoR@z4Kn-i8m;U04SRkbWDn!s2sqmje*Tm?xC*au|4_efv- zM-gSTvb(_Ks&(x%>k#I8_cx4j;G5~>(1mNWmrmm?7O`2!9AG!QxN+}lH$M3fY?e1> zGk>_O-c-o?LVEi{19Dh2D%hTrS$K9e$b|hF&+GE7pID#QDu=<;kCPvCxa_O601%Ek zC~8^*cyyg%J(0q2S};-ox;scgi5SGgfeGDoov7`>YDn!MpQIyjpjgj(?uLHtK`)%c z4mc|)tf2hpuAKia@)BbDS!lEJ75%)?ltgGc3sy7p1gR8Y!+f#A{TtvRPGS-4zX8Ju z96R1~SMdD{Y>%WN&x@&kx4?r%s`0?+0}0FdLA`hsX!YUCTtRCB<3)oC$Iry^EFK9P z_Hf_Uv=XScPLRlL6S5mk6#k2>DJR(uDA6|iwZj2ieqss&;;1OHE3m4}U`s7XvLYR^ z_j`LFcT72z^#WK1nJ60K=9&y)Ui!k*FdCNCrt#?_xz_+?P0x3>ya+gGZ3@arI^%%g zpUjG?{9C+dUEj>svV2JUn``!h^m~a;0wGWeSPw9vBBMNr^xDTLxXdFU+7kH?%CdJ) zk49ofj`OvfR)8UbtMt6_oo|G_E6$X4@cHncVYYDyJ58>5mbsGKj(BijV{fpd4qs=4PB?R z-;RFl zjRUC#B`L}P)syZ#dpqqtTQ&*7F#!QXbeC0^y>3g9w~}sK0og~aB({GMU+2Ls0-<7^ zb%^=avvK0I75UUgLJEyAm4%{p=E>=L(565e@^Rvc4#Szal3jVolbB_cknYS1Sz2v| ziSIQ=z4l@fAAvx2H0hi41z9F4i;;AXsQzurrY^0w9x~Nn44kt!!>V1{kCSHkiXUXk zHWTPR_zpGH7oBH*Spm^0?*`N3?+zFVpd(KB8&v*K>P&_U;)KDE3`bo-&$TWFEbZv?@PXh|VhPSpI_!oxJ+^jVZQ%L52^5!9zbOU0v zMdx!iZTVaLRfLiAVowx=x7FzuhPku~-*{#y6r4h@zGbrEIX%X^PuUZ|ij{}EW1!Is z!ofp+Ml60H#xHP&&~p?i+q7Sc98)%(uG-X&ALdT2Y7pkEyS5gGWMko)_oDy9N#^#$ zmVY9fM7DEQvNTF>5p0A~{3J^LfPuv@J9!dh>=v{jO6kKpLd@YRobZ@AQzE+F*0%3wJNzg3QzV+qy#ib z#qfENERU1q;3CQp&d*atkqOJ(0Ngg)8w0B|`DCAdE*UW(83IhBkhtV`8vm7;k7JSI z=AfmwG^OkS6(^m+pvMblsXjAgLi;A{Y^T~@H%jf3zR*r&^>O`b6#9$7Px{elDbaD{ zH3$=J@Wsv_z)8wd$D<97c7lQxlo~siC^GfyIMk_08sOog^wwVg5v_2Rq+y&BwphPP zaOs2&k7%_V7V7X6AUc9XdqE%dsrENUPY`tFxQZ7mWazl zz;RTz9pHP@~$ z(UmC?)LW{V8Fn4Wsb&C$)~W!{{GM{p`sXMk9TCZCTzKoHvWdkKb!N5Uh&;1m51~@x zLJ9A})_;ApmD!eO3$7o?4vbJ8GynPBklv0B-kzyhvL%1Ptcj(;_r2#D?cr7lsP_)g zALeb)P*OzxopRrAv{xR{}Gxc=eQTgf~ zNng3R>FSs$%p>keMzikih5?Dp=qEDJ?Anq_R~p_g6CAP@EsmH*B_)8csAr4h-ex6IK%_+8UpV#N zd|~_d2QB1G@ZNv_BB>SU>k#TWPoJA@`x_QcS^tc5M%F&9a^(k3PvD%3jn~V1bIHuE z+`Cyzb!W`JvyyL>Qe3vI-Hlg$Lb6pKAHrB&=!cl@BWrj+wb7eu%#%Y#l>2VGLPsyS zbI{L-xE4Vn+zRRGxZPqFtcS<=S?r4>+QhrO_Xh7^bDrN`D{btJr9!}mq_$UOd#$AF z)~Q?`4pf20FYX_4hSeY(D0B!1XP1GreZpaE2U1ek)-z-LT7bc+i2*Qc$;o$wRA8F* zuaB~itj##ltsZrIKYJ{?eU|oKEedLh2`&gKzHDbTC1VWX%cY8Sw8JmN?d7&TyWng> zT}e{Lp6p;NLnVI!+W$(gG|SN7*ymJ_(oCztGK3tXfim>XX`j}AU*rJuQ2Q~im^O)< zXA;rO-77AT<|$XMDBJl!HZ*U_^ykPV91L-_=DuVe^mTSwSjY z-SzSW!UA$6cxlsV*}`i@cTejR-G)o-5Wiy7WL?zy_usE4dCQCAT~0^}X`_6fDGFTK zD2jsu=QtajPgXV{^En6-RXd`aNM^j9^hfGH4c^;Rc_{p6HpSf^W#OIrzH*d4)mEnJNPJk$&m(_4KMBf>iAe8`J$>Q zrXx3WsZqF%;a$1$Xea7g=&u}a1a{HO#k}r)aQiLQyFpIV6!i{IR)%?g)2v@(=OZPCfGHrL3WFys6+cGmXZw{*tMV7kwG>dx%;=zP?Xwg1$Iq_ zwI7L`1&qtztfc{HInH3Zq;z=K9JQtMQBw($V{s8_o7==mNdz#mNoRxtbsGg}Fz}cPY*lci|in2;Q-$@%r-G-|SvzYq| zazkp6CMAL_Z!EmNG*MnQ&)hp}bsHSBkd;IcYe~OglbIO5asLKHn5e@fzFsAYNdMHy z`aw{K!rAA@|m1bQqEamDM7a(Vu%_)w1aMj zf3h0#z@X6PL1xTIA?xFIN42pg-Hz?{vuDPY63B2@5Hk`S`A0YEk1p^-R|k_!Z~Y9H z12wW7NXr-wkA{atQ{tgOn4g}RP6mM&PR7=25`=7Z@CGN6Y9_K8Jg67qkc`YB+BaZf zeo7O$h}_TqECS_OgDUT83i(-<3YZ-m3IAaMAI^hh)y&?%siLlm=v61g4KL(CV!V&x%|Ex6XiWTLY4PU;3ABv&a+6!WW;Dgmu~O#>Yp3r` z_P#^kYS^Au-xD0$5p03W11F$MIFp_T$j>u%iyqtO1h^#72n9-#O}G^zEolKbZQV8v zSv8eRNF@)NkTGdDEhVo)0EI6m0C1NDZR#qgLeA-S|14T3)>I!OmeV~U>?43yKHyjJ40YXz%W-0&B@GIM?XWj!hj`cx8mZ<{gibu+gAeM<=b!TPj zR?ZCJHjJaZV*H>avFQ47SN63t+>?!HieGw>NN1UuTTM4ac&?|af}8SvRZ62%<3QD{ z%GwG$sz^Q|FY*>+a7mbG)qon<1`9=CTXkRk_7`fR2fXBkBjEd}Ku(cMV74~Ddm3xA zSi*|I#yxnqhd9ifR@pnp16gZe`;4ZTF|3JleiPJNIn;1SPf(vPeJidJs$F6MsHS?( zTL6tTF_kvgwKD%{(x~e*Tsfh62n9lbrL}a1kpr95T@x}Tg%AO=8LZS5ntY}+G^ax_ zV3V@rp^PUJ##e2pp-e|&`iDl8)F13D^>AXMMsKc07MxDTYB}?yEgR^(y-F!*T`uc@ zZa@L}4<7e1tN1fCg(DQGO}@n^NcJwLVoc@~yv=)Kjny>C?r$<&lFT8=8FwG6%{{ay z{^lghA|xkog?+FF-~%0YCcV(sUdb0$elU-N6nB8+Npct?y?hY4kru6*pv0iYMhOO% z5|;YTamqo+w8Y1C_F^n-xrMMX2C^O^%!C1Ig1@IBM)sRoZFJ3;;ofST$yO3@8@_LA zsy`Q@L6WeO1L`ys<~#9{W}QDcJ;fuw;2s67r;|%am;`$CV7}Tf(iuOw z4z1-2Bh@ofgGa}odzm*&-TI9ogO2AU+;}IP$V~H~O9zWz_pG}ka6=hTEljd;=(8v` zxW}2th9@PpUn$e`0QO(j#sfBrXLLV#aKoEwbLEExu)U$F&k7V;4WAd6-%ddI;EhQv zKy*8Kbino(pGWSzJBU5fWG1z4Y5c2RT}Rd}DB^XaEMB4}I9EIQg#Erk=PUVFOW5>6 zB^^Pm>Sh>oSo*72a_Z>sV%y1v3R1KCESMqmsU^>fi5%VQ4-YiTTI#e~_Gfyv66fAT zw%pYMHAT8B*~$Z(mp(mWZkn`?M1dbtlEU;&%&#R;StSQ!DL+h;141_j5;l}*NJ>#} zRDw5D=HUIa4t3ElRQ^8KxY5Su#4RE@aWmf6$a(A20Q&H+@%K>^)%W?Qb6HXT(>goE<;+#-#pLvizD} z4t#r&Cfm(c+6cXoJf&{Sea)lw1q=+satjE+wSxot|}dlP9EcVV3Z_Y*_cw&2zFOC{(h#;6~T?H zC^rz&+VV?Sd6)S>v}*mzR_(znbJe<$%Sjc%-vB<3(jUa<9c(YtI7NGuUWabe{Fn7c zjs3k+DonX*BdRLJi!|)jzu^>`8Z!rvU+J3^W%1v>V)E;Sjse2d(Gu3sN>iUZsC_>t zV=vVp>!KyMEQzqzzem??J5e1qEEhr#duGks|+`}(F|TBvGjpVa#_`1>gB_x(O8o_<&Uo$*q7*x@#S z2)o+eB_>-gN#`G$)%(+A=#6rq3c-&6zu7B z3$3wR(GPRu7pPrNj5jFi#%`TPua@+DY|UpaeCYfdcR06&mklybyP?^?If8IWKYoAR zN`TXHa`g^cPsO;4^^W^z88^loH`;y^$j=a<$2dLhZQc9&_Y8vWoFuU|7KQ$ES0S9X zZG9sX!|FKs9|pm!MH#$5eGHF^dh$N`*DO51BK7aLQ>Z>7s6P-1UaCLBt*L!^($Go{ z-3+t91CB}ah_;A(tD{jv8`}!dkPDr^voQ15ZCb^2c;G>Y_t%|y-pl&rYMYsy6O2DL z*%j(LSN`}y0=|?$;M@Hs7b%k4!nbJ`sR^2}p^BWH+x3IBl!c74INiWwgR6T6g(izd zm%9E!$bVL+TjSxNF12%vB{%SLS#Y#h&tVAl%e~letlt7~{FO%dE^>wpbq-no83thw zw?B-%XLtwo*>K(H(-im6Gj7w@F7*o@zk4r398i?Bvl~m^os6+hzhw3cz5c-{Hh6vX zVCcX~v4Y5Pe9ehPkYjlnR4eOt-p1~ch67Y1I3*k3P_y|=IANtQ9JeBH9*Q@G0d#;f z5a2ZJJ!On1mqLm3-Gd+!60A%8f!u|dm5CB^PH;pRPz5$DfX;(N;bakm3QDsT=`a> z=mt<(D8f;k!M%i!am2hH+w(s|PndggUf zaD-7yYhwwuZ4@9mx|e4r>J7uCYOzHWrn>V*7T97`-xk>Gmmb*C3WFnc?Cty;m*MUS zFdWQd3XZn)1tASFA)udL_+Su~9Vj%dDaCy_E`&?o6q}lstR&c46K{LQ6w4Q=`IY8f zzOiN|KP?KuiH|~krUh?Pg>(2}kDV5I+F)!vK!01Vi_t?ei|sXIcrtGoUP=VUf!Dh~ z8aeO8fo9!`nQ${Y+qM$ViPp%xzIEP{k$i{g&f~UK7RxF`c4Sy7pXVD%@eD z@#VOW2?JtGRb|r`bTwMn@8E_;F^2lGXm2_|B!#ZxCEwf^f``ElE(Mg)udf@{`K3t1PJ|nd+DeHOcL$r5HQAP z4!Y#&*&rf(@a@cJ*$u}5T8}K9ea6Jbu$wg zuX7+jwzjZW z1ZS`GTuUI7MtjLjDv(YOlZi!Yjd~)()?Qwk1JN6{nqU$o7-(UODrDO!)6KLNi}O8tXQRR+*lb#uljISiX}x^`z{t`*8^qZQ zH>DIy4&|OV9&j!mj2h2Rw0v9E)3v96<~EvI&~QL-p2=eu{I8gxZ_ol!H7>`=+ZOB( z&PqiEQeO#+BKr?bE`ZZ@F9Y-GPa`@)F_H}aocTgzq#&EnBaPh>DuVwKyTQbVc};TDV!G&``!YE!+{wS1KyX zukQEv;CgYgb{EE|8k?<7MH|pOgM3PdxPJA(_APw~zQ$wyR__pwNAHCs3%ZIh*>KzE z8pu`0cuKxwyT!VGWM9)GRKk6~pF`LjQzy1sPH@PRrtU<5J^8Le7kO4c_?8av*Rb3Y z6va#Bs?V*>g`<_ageo$lUoGrTPQDQPxlOA*8^|25V~0GdM9_W`n`F|4r5wuXg=Y=vWAwz6meT7HOS;h0;((y|k>SsPb zDY!dvz+l-~Crm~jhto&|943qLtYW)8ndzs|4G5Az@UiMxr+8QamG=lEqW*Hte5z*9 z-H5CN2XgL3$)}8krhf4`t#T$iC?0f)+iB0mj7$5w6zP zmdIHxN+!WBT3+tBp(82e^i^+`TW*y-ePJfmOkbqKk0KE(*}z~af}KaOy8d2&xGL0F zwdA0&UY%|ItL=UYKZBsFc&fjF5pvJvojOPI6LD6H>GAvv{p_lPbGj5) zDp4&7rqJO7 z`^Lh6vfGZ!LgFk}Oh$=!u6)oNozCdMg`V;C{rT0qOT4xCVK_qea}v*W&t%bzO_w5W zr^aqdQ}{cd7u0RV<7lpj7G7|->fyuUr;3gbW*^IHX-PKER)}wz$iswy=}%X)v%^Rn zT^*<8wW99G__RS!+BdzXLs>RP$yPOEId_NC-003-`BC!fa+A73_Kb>1kXt8mm^mM+1n@|#_y*x1r{ zx$#2Lx!y5wF*HRrqS{w6TY^xF+rwWNT`DIrJ*ejoLMI<}Fe!XUS4hBbu|ZKzY#&Wu zDDh83C7a@dCZ5i|jOP-#D+l7|uHkpLipDbI9~J6oVn|X&aWl&tQ_Fb83U#|}CReI3 zcttA)ni#F8y?__?#-Amj*;5`H-Sy-Y@4_69ZCU&n&D2|wsNzl+gQf3KnqQ4!&GJri zVeK&hSElWzewWP^x6vfr4+zjYqCtWHdL!-;5Y|U7A{3n-E}HM4;+2FAQy)FN zCCy$0MA_HNvT-Ej&>FvrH_c*F+tS~ZGyMZgc^JdtKDzNyZ-@m}gRwS5uX0^fVKpL3wBY&Cz7XyH{!J2u;) zsKT}DL*=nsV=Qc=9|>es2M1az!~Ngoi~CNhf4w}Je2HC|H>Gzuo7ftWjd7BD35uAS z!WT_H2BY;r{z2TpB#B%BrE%o;01av;)QN88{PcD-i7sob-lPAn7jQHQJg%8}?3*D! z)(wXRXpMEw3!85>(Aol)C(afq{%o;Ir2F`#ZJ72~$h81n2>?*OK@J5-m)e#>9z3&j z<9GKimv4kbxu>p)8LZc*Mr4&+RcCLu4aI0LyXno8l8vfG$B!tAYHDq51hm~eb3w{@eZo*NL z^h8CL-3%mh4H)d`u7_37ze40VAG-A?=8Y|>v>PzFIp7tCuFg~jACJcv7si4OHHb7Q z5RQ?6XN2Mz(a`=3)2AP5*_Xxcay8()aF@6naCytBTzfYT0s3uIL1pai3d9|n0BQyT zecpd)H0q-r@Sm$_t?xlAx~L932z{hiA6!Biz%Yanu%75(c&Pt4j(=})ch=ckXKx`2p~D$xl)cB< zv$8|TaX6g4iR?|3tz;aTWkgm&5+xZWt)HJizJGlG{XD*(@Av(EeO|BUYdFi#kkfoS zYs>G|sJS!7^(`w_ir3d8!)dE-yoe>2E*C0@Ci{(*+*P`*(O!ISy!_wM&91D*1*(Yy zXuK2Gjx!YtP5T!bqIB(SJzMTe@Tj<{4+{KG=5{a2i`N8w@bD2<^h;W-neUYV%sW~WVx()$j zIrC~oRAbI;HOL1|c|^6f5hWmIib z8bzFkU~@~O^{b$ZC}(Ci+}HNbLbWGKR$0!^O#K;%P*OL_bZNb*@Lv4 zMUa6hSoF{gEen2G2Wj-cxeYj!SyIaqxF7mybQ45=te_&y?YpHMiLH~T!;_tN6v8qv zJX$O)LtKNdlO!(Fr-P$1f& zZ_#RN+t+FNhf%g(X>wUr*z_ z;GN&*lx&vK>T)3>8w4;=Hyai{@@^XS85^HtgI<;lV7g-VW|ZFp`}kp+?+vaitaqo> zwnoC*B{^0bAI5%Fcp4*Y`&6Te)z!n%u1yZfA*MCKYSwpje?TsD3asokiddOYam7}L zQ@Amt-$<+mD+PEY);7;uEsGJY@2RA5}1pN81vv;OHlNTQ2x9qoxywpvRa5 zusf{GaVicO5bqjRCTb}G7}rYZ4iKZl5t@6Df_oHLHornsVx{)QQPC z?MI(FH=g=D4fXB2>T>;5oZbC;Mw}7}qP!7$?O~jfe-%|s_+I2>SJ*e2@VD3Qf4CR@{^d00_>b*IG6h2WOVBA8ReYFv|(*2Zwz~ z7~s<(UjSD+O1d2O88lOY|cK@ZK! z^m<*XCz@y7+g^qs2t$iVDy*1=+FR6tV=A(~lZn;FAQVlEM_n;)zQJLVZS!@iCUd{A z{!h=Vb1AJ$cZ6?@&cl*^Lq6ss zrSb;$Z}8oPgoHlR8+xJTOW(j2@#jpJpFjImaKl0B+7LwWd%FLPM~}XlH@yEsXM~jv z*d!#aQhk&~3DuECmaO}<1v2iyR!kRNGiOCNi8Sv3Q+tMHYAnOC2?wuBw>EYm8aS(U z2!WLcmRVr z;&WViNgFxt%NLPJ`#jItG!9!T^Zc@ZZ*vPD1RUmH^o+WDI1>;;8#$Kx${BZDpDQtk z+a0q^%Tj@~YEo})kIkfk;|s+qV9W6jb=X5F{GL1nw>M>~ATMJ}bDJ*jtW)P|5vvC4 zq>Xx)O>vZK?%46TMC0K(7745a19ZRwfJ!X`{~MC5*%^r!s{|7Yy$sR+tm`XFL5<9$ zI|+5$A@_NyFwl;L#f)T0c@I$=%QR|CQ`A9l8s^=akFf&e*JoeJ7X!ajq@GZ?8Z{p& z8DufuB54?xUsOoVFzTS1TnC}z5gEpu4s|BF40j6-?S5yu?cBEc_mgGRno$Jh0!MK2 z+k}=&#;da)z7M^vtA0}?yrb$7X*Oen!$^30p zS_*H2u-Cv@9vdS-TnORY6+nzLPSP)|!}Z#ctI!Mid+>%!1)i5OSb z5RJNNOa;9y-6<8?5>dVUZdsmh_2(%?-|*^r!_Uhf8ji=uAUJTh5D|Jgc!!!*Vw8E5 zUCp>0$$q~a<05v>^M=;0$m9d3gL;&vGSFtK&E}qVWXW~qyA`xd!n-IVnYLY^8bEa<8m?eBK2i z&Xg)R@a`Afur2-KXOJSnkEh(1g~iyb8a!=9wg}~y-}42gu>a5_<*5L+H!&Qu81CM zzd7vWIdM16>d!5G=#xY-0(BagvlO#)?=db|JTaD>+c?46Ex_fErVbVoN)3~G8U6&F zk&O?!dR(~e#|-D)B1`naiL}wT(3=K&Dv4S`z7En?OYeUg^~0f<1NHgc1&cp#Se>Kp zFVtB=lQPcX-Y-1BXeSL8J;B7?F~Y6}`c7C~f5s9jL&3;|O-(O-E0#YES)B~{4@o#Y znMm6%qi%`BaacTgWf5zlRI5y0z_1jA%8y^}46nrqY;??{g+eSU=90rk4Szp0K=(}8 zG(p3SRrzwzG2A2&Ct_M|m!F=A7tT4hLDiDw%;3aI&w_--e*|H&lC(%|QiZZ(Y5^{n z250QoU3vT~a?p0cgUT=FOp)GGJ}Sav#aJuUT<%SYui06ms*DIV@j5qm1bx%@9sc|t zTC0CKjQrHGdAGhBH^ej7XuiY1uc5FEZa|E82Quc3K2@_T3}Z7bvAT6WYuU`;XMdG? zYdRH(X?|_;#?x{x?jW2Y_wq+c9P{v6?!LT&{rrT+5=EKZGiuADcL|`SiD8R`(H}_~ z^E8`x`Xiv_zmaaQPD5YDVLNW;qHNJnrbG;$6>zm~_U@5DDVpohzzV!U2n z$J_;K_k}?ln3Np^f|&$@%8prf9(VsGIxk3(s`dryLt0MGDZ5yNVP0R(W7RI{iV5*C z+kqb28aY?X<@#V(GAfFV_>8J&Jgp?YFG73A^AW5}zoifzeluae4XjLUx$0PobHPACY2me+{JOIxbTcF;^ z5X>az@c3OA*dS}>a;8eMn!??TFhVhhp+{m^z?Q)napYlCgO@#4~=B^p=+=UGKr z@&o7vCmnmHOr<7q$K3z}w*s-a<2pU}HbH5PYHd|N6srRE@rzK9GtHbQk-nL z7jnjPs7kGXT}OH0qC`9k$c>L z4GeQRV4V$s#H>*th1ZuG9|+Y%=&I|fFf+!hV#VoVN4eltRWDa3j8Jd2j@H@i8V*U9 zpP`?h9yn{HF~92A=;1cYa_p|@`25CPZ+QZs-Y!M04<2ELR5QXZD%I=gQ$5PXc3+WI zZzrGxP*%JZ-j|BJ7X)B5wm|P|y4ZLyLs%0w5!|C21---rLbABq&Q^KOl8sB0S^5PW zJI0uZz1qhNNWP`@3i{&il%{vjW3t{sXF*b5vwYxHQcf+?MS^!g4@Syq|nmj_A-OheWL3 zc`dAjJkr`(L#^a*zv8cQ@g{OPw23fXlMo$r5EZ(2=^pC+mS$t6O8Tt1Hcaa06J+ex z4H|;(H7jglVi=({%$Ul=ej!S!Jp6*oL`{HMU$wkd22+SJVu9UlSoB#su>%GmcX9>Q z{AH>6sS1Sj$3VQJCiXM4R)`~CiOmO7xolJ%0yZbgRAZsOV6QkGO}LzDiXyr$MpRhP z=9adiI-BH~*%d$*`6)gD5JF_nT)jPiI}(FkObm)Z#V*x4L1(>{2(V97!5^uB$g?1@ zoE=FEqPh{Tf-%W7bAOv7d+A&brP8hNq$c8&UH#qy5fT92VGcl+`|B?;N9HlH2Zd^x zs#pvvFCWWU!vS`{G4!Xv0E>(lqqq4}U8wVwxSxpZvXp0DhEO>KwGf<$N{mFKPFYp& zpkf!VQGwfF4IjykAIZYy;qI*AWmi$QWsqFaXjnqX%0@)&__*!} z!UiJ*Sv@1FlOmn{rYyh`hY{5u>?QM<%f(zw;P=^I23UZk6LOR3#8B)rR3`2cDI)?F znrvz1NEIDb#qCI_9MVS*)mxV^s^H}3MIITWUhHz4s-t$5b*kwggWD|Z2E0Y}P}Z2> zJ+|mLz2K!PNaeXlcwC)N&jLv~5UL71c0?YojCo$q@f{AudrOq4p*Yz4xP7sh+;{u2J_hTi_rE~cBxxxheC!I|?P_3 z^B-e`-o|gZcs=}>2OR1GXfaL%&>xndt%Hh1BSzqWr>xV1@T?`yg6Ul<*9==Cjw)Um z_20QR$}R@xHUOpHbl(fb=dx!*GD)~vh+Bx=Rk$pYg1u2Mrcvl|`ZleQKV7;l2h5)i zU~(Z=WdT&hZJeyqnXJ+SAemMj@SrD?iHmEFzy6tWyEh8$stMLmaYv{PY^%RF4Ww@K z(uyO1L9~p!TOw+nQiq*E^G1xXPXIHv|gey{OcO`(Sc{$r^74P~5H2Rch7RY__W3+K}e zw?+B;pw5EmH`Vw3-83JO-YnkC$JktTK3?Si+G@rE!s* zX^!Y9k1S7@>16RCwnIR!w4ld>7keXs?b=`+T;W>tK)u&eh1Xfd)N%*)eJX0ZRshxD ziASlbpkkM^?8-WyOn9?#!wg%Y5JG9t{W}on>?a?q`0u02JQbP~E?gui)eJoC(?`l; zA?(L|2X!^l@q$-ZA)<%OZ&r$^JlU!4L1>Y+r)U04MJONBbbp^*!(Cs>soX+{bgW0+ zz#ihrUHG8aI>YvHu220x38YVVePsq5wn-f;i-?x(gvzz@Bc6dTZueSgH_0aGMk+>F z;3QN}zl)m&W{rl*;hw+ot%7O9-Mdb58xh+&-wj8G;$Hfo_Tb9>)h3G(J@PJ+hl_aK z%3y+T|H~o1{HmtENhouh=GUMX&B|rxzn&~fq~BdEaw0UB7+6cr_Oyu$m`O42>T3?L zD#53$5A+|W^Jmi8*FOhng61DXHsRf0;L#g>l@chL$v(vhsu$N=-`G$=H(Om>Vc}$_ zUmaPnOj|ZdRLXecvO$-7d{tNqD(QSG8_L-4nVX$lpyY_G*$+@d)O6?FM`d28+y(WN z{^gN~;VHLoUROYQCD+tk=tL9E*RO|CJKv`QO)9ss@XDfGAiC6RE#!D)#exkp2_p#s zP&`xA8c2#gO2G$p+x}VfK%bx#>a`SVthlpqhin%!bhi)6)&~u~j*9cELQhsvF~)`Z zDwJ7@<^F1%sEmU#=1?@dF>7MQWGkaz;}>o!Y3tdR&K@Nal(1sT$3PNjFl< zGA8ZPj-NCNjWpU9{}x?f(`_N-g$ig`yZvf{_bim74eg|akxwSctjH#AWY)}#)(2NQ zxmM4wsOZ+#S#l>zc)G@7F}lgZaKrXlM3rvx^QeDsjW-~BR(6j(3h4rt)S493)O-WW zC(>Ldvc8P}I!}DPqR<vP}CaqT)*L(ckj z#WQAARJ82i^!|I~AnZ9^>QgT2R|TC99ws(htnoC?&2p38e7R$)k0RD7jYvHCmhejD z*^@hr&R-+J2oL|Fi_%(-3HHJMWr_CRQ_GLMYKt3}TT~gBRPM=H7MYE+BA@G-%&m0$ z3F}=Aa+yY*V@i}{siIL+=SHY_)CRLX)e8gE^LLAowuUatri`~bTvigttOA67_yCw4XmQb~o={{KV zNpjV7mDTfVcBbU!AE^T_ppI{!5oRfoTK%Y>bO7!S>fiHiN!OPq>Zm&XlChM|CZB04 zP^lzhjGKGMaKlMo;?<1rb4}w-u*R3`I6Scgqx)ule{dcX@UE&b?S@=;q4lS1BRSvC z6bv1s(=|_or@E5dJ>d)xFIuH*9}y>8K`U+^#h#G+AIcOxYotCXIsg8@f7=Bui|!c> zcT$}MRTDik8hj^bZP&^6(QRPHE^fOn>E`Egq|!$oue$GqTm2qGvW%-4_Lm@XRQ}Cp zJM_HvVZWA|jncks!VXWgH9o z*SWg(_P^3^3gUJLr-@h8=4~Q&#QMJc*!kjdx>JGM(&m{6ZuwLol&&TVhW+OIl9D8R zYvjg#7m;tDX!+AYsvn{%M`{EJ%y6YAB`5SpFj$*Bt8N7dbKz= zMK+UpyAeKwFa5Um_p_T!v~ersDeUl3UikX;NBg0VzAgSX*&gOy;N!e;^i}m!`;Gk( znLlrhP$el7h}kXW@}KmxKYgrF=Jy8(??0rtpOnT2COkkr1%OcdSzr8t{+*YlGAQ?% zRo(N~FS*njBWQm-ZLkQUBiYSNciBGg=wA!-#Z#TGb-0J8@ucZ`Hc5WjXW z=3ilWO=dh(Y-9mkFMwqy{xpTssKRzwD{)+pUlaOy1PmmXrro}%3e$jdjHXz{SY%sdbo73SihGY?>Iz))Eg1368XOlgzapy%53ts##{ zbQkqZnb!%(RF-X7=rFu>hE>z8Z(VilFY}-h-<)ZS^GNn7!ku61@;jIivD1;ZfSl$(nVjf zC1z^RjEPAAO-y4A@@VAcXOG9gzGV3dC`R?kOe|amn1gJzh*kK1llcq%Yyg*k;U;j= z7BSP<|NJ=ngdeyh0B;`?7-km8$C!~cUNLQLQcVMAm@1S%>Rb#;P-xm1VgL1Ab}Y%o zZCWtL&`?~M-g;`x^n$71R$CezTc@jUX0aeH6wia8-S6bu8*iD&FnxAB#3Uw@xxTX1 zoH*eIzR|Z`@y#F;dS7qZojuMALnwR4yh5dT5~PvIH_Qew(JPvxh0P;0&{Q0Cc<9_r zi2@~6vsb#3t)yaCkU89!F6O54E?`dbs4^+rjGkZ=;0w3^fhX3QC1ncn$9ABaS|jSl zMIQ59e%8{ti)`+0pCZX*jhfd_UH&qx3BUFu4*trcu==!Ikcwh90HaeWpDF5c@Y0C& z(o4=wwC{le)J$S{5Z4^kXOH{5hzUHuCc^HpcCSh==Fi*g9lqmhEPxOQ z&s00FvxG|Ex25#fwf?DSkQdm|M<Oyc$OR8ECasI7(ob#5=A3<2Z1CTL{{8psug4sG*a=X+u-ypAf$7tgWp zPQ~7W#TGeb-Z7YVWL1)l#Z1KNk z*5i{mg#og7VFjD%B=b3$weKFC= zrEq!;6YT8*az_r{*S$d(Tw^FO5FjOJN7A$p8!63w^D-*cfSF~Dg(K^4eBjxA_|8Mc zE2EJf0`-H-rX0c5||&dB#I6U&T0*XUS-pfS4oH|$B>~ww{v2G(}454mg5p~LAsSG zs^TR!7V9b;A0_#eVPd_C-NT3;qf%z+;x)=aIgF80{{Y%k$!2l<0f{$GIEW&Fj zP7Rn6jl&4t;@cZz0izkSwmpL-5P%N;)BV7{G&*flxkLLs+PziQ#}V-pnaxa>Pe23X z1-Xo3i}g3vF|;nnInsbob3Vvzq7;b1kg#S#-q3*yG?fk@H2}F3IPRmLaWiY`=<2oS z?3!1*1vXL-HH3eSX{o^8=!I-39(}j{&Q&PLj1*$bTJpTnT$H0PzeSgmGofXx$VA#S za&bpDHV{_^e3JTSlU7M{EC#667T)-GSH8g2kWM}} zNw+mvI4MdGCPm>VTYH?F$@F-mJx?_5!!D;kO7=@m_NiFafci|B@o8g*^+;hA;mOZL zEksQg8b>X~SLfG57BN}`(q)$?L&cYvCbW*p8pw~Exxdh+*hG)*=D-r)vF)GzF9x!r zjSoQ&;2$7Bcn(#T30VfVb%iU^11jQxpd%_XDWlnd8$gWy>49O*U>1wf|#(a4Do!ouigxW_P;1Y!FL`f@$X}%Qfg1K?g{r+J=B-Yq^6VA=B!aF z!6>z}tRgIgo}Js6)ZPRXgR{0B4h;4ER>Yaq3>h*Vndwc7Y_C=hoDRCaf(x%MUNwm5 zkN~WQF+qBZEq_B*tB7Oo^$aNjogD@SsCm0W6j2VRVC|`rE%|Ll3P9~3`l>Wu^ZeuF z!qY#~C(sfi{nryIu}qIoOc>U8r|(pZT|MkY^{ZqQfAnq$jj9^wvC7u)Cny zGhNl(7JF;PdZm!pkCYFN$$G1G!X*~T`_=7?<_VYNdYB%QO1jYNeT`d5UtHLSo0(Rv z@!+mckV!=if+2yQHiS9qMMlk^XQ`)!Roqo9T)TK`@ZhMH7zns|Bc5#zA>kJo^k#8; z)Nx|WQXCx+XFEAtYkWTO(~Eow`fWu)dM zfl_kJ(p?FhOi*IHRClka^_a?X_sCaDqVd7ysOQ12F9{fizDK)f3aaD^*i zoG%;#$UkIsf50GVmwCmC$nEl7n7wBoR9L2Ks-&o~?G~V2_~a@V=iz}Ora&a3lSON! z+Ee|#AmUWZv6k!{{d>&dzcT9lXB`=TSJU?mKN)r9EsrHw4jAo^k>qo>w>)frMn|S{J9?O)b61t|KW}zz9>J1H9{z;yakT z$_yw3q4nRN!mc3Z-r(Mlo>&93XmtK30{s}8&wc;;ULpJVm(vnPDGtr z*RhNlbtMg7VrWS@OiGHvCn!w`y4&*I<)(D`sB(I=EL|`p{8;4{8mb8tuL(k*7DC%; z`l(ZR_XGO2CgDgLNUvEzW|{i4`u?2xEIC<$4=(Al`~p3)s@(#Jm*tmUc&S=VD0_Op zsGbr2HpfXCcvjUKo2VCmJ_!f$B>CtgCAbyKw@O5qYgJu9R+Bn2al)A>1wC_~f0)AX;-N1pUF3mk34vbw*k^(^2*&Oqsv=#WjChe=GM&;5 zpA}iYkGcm+5_vjOemu~?NLOz|XP;C1@Q_$~nDl{z$f=R6OsrzX>YPVM5X%RL)u3YP z?X4dxHF_&Gu0GXiA|?0YaJ)WQd<`65v@U(O!B)d#hqc(AWzg*DxAQ@2GLHfqV`K|HfeZue0jNUfDDv`n>I6XX^`rO zTX1Mq1~G*))+i56JsETVJe*dJ&aQ*cY-#C&^>bxMZB_&&I|A+kp9C}NZTiGv7MD4ns&&+2z zm?{hDeXzm4vbw9CI_X?;PPjz4poL zQ`Mv?BO(buU`X(aeK0YU=^rmWO{y+O`yCq=4qymNMYKc~UG3><9)uWvM&t+kS|psw zP=i%fN6LZKbXzYj4SErk$Bvq4oPGkz|9 z=u^t{+dwPaiqX>MTY@3wg^H50Y#<8!- zCB3CkAF8IkbFD7dVw*yj)6L;vwj{gi$olP|%ItSOQX?nAr<*9I{+ z)ZUqmpS+4+m>(uv=Z>{r48u{bmVlQCS@B8yR83|`vQc>EMH}ATX~RkUaJBbzf5x0L zZE^6l8UQEm;U>E+ioGI;=dbL_ydp{7?X4O2`)P~&vOg?K&Mpt7raX$r0f1(gX7z{z z@{AFFkwzu{An@u^86LIuHjOdF}`Qb*EOIJ1pq?Te;soZ z`QRNZV?4YJrfcn(9DZHbBVbm|k{o?-Ggoh_7wNVcwV7#s%askzqD1g1LP1JUR_35N zv4+_%nxD?Bm&dGKcnXy5(?qI0SR1x8`L1{`tnU9BmdMbNsTt)N8k7@}WBkKioM6V5 z?OD6K_aFi8@=@&Yho{9i2jVHzo(*w?y04kgy+!h zJq<0A?udKUXyr{8H_LasFUb3a5tH00eU8>8R1giJ)t4~yRDsQU!~(JZJ*D(2ZNiBA zdE$?o>ah3P&PW&&0ezn|R8tZtUBawaR7aolhi7Is2DOK777U^HSoTWh;UJAEwr{?B zC9*&si!(|fwRcvv|EKkX&-2B!tW1V)AREF={}H+HE6eJhi`=vD1X7Tc&y=FmCYzIe zjq52J+&g9_lO#gZ4XvdC!HdLSm%+2Ld=|P(fG4l_=(G5CG;cxIvSd?t%spS zZ%rPbA|1cB*^%n5-^dyLSnS<5Dcw*0wshxfBL3rWirLkxY|l@9PfQJ`N5sZy{j@ht zXA}=J(YvZ;FzBr-Ox=%m5`4(jfi$t7#{%Dz`X$u;g~ZnH+;Uj0lnJmH@5I#e-dbw)5>SW7b<_h$m1vZyf`&qes(1SdY;`ml|u!X zSZySFf#I4Vm{EGMUZYmD3RRyKbUqU-)IjlPBZeO`cv4@f%}%ZNiukr~g81 z2MpnAe*ev{XB-!@!Y{vGLiuWHRo2RDwUmloN>a9e8&YyASjQ~-IXIDl@kRn^GpOcx zy<0sv0RCioALXgs6_7Hhe#Fu8&{C!=!o7GKZ^;CADdLGN?GkiC9EaGK_~rH95a)JC zR+Sauy&VV)Bz#dmc9g%Y!}l9gelWRG(YQ5>O^NGNoLni{&a_sLuKSH9oSilp&N$X& zcZNMvyPJ1#I-eJC#JSg2#_-@Y2Y?r?xNFN9Zhtnr3Uu9`>!Qzm%50@R)i5z%vj=iX%n@!Y=Pd z@<&$^RDdQxHdbfkVqQ3`3yY;@07Rv(N_ig(P2@;$R&eNvp#WSY6;)CD%*$+1b>J)p zyn(nSC7H-1?ekr1F1tW~VmzCAz$^hqT@fDVf#(2hhV30Vs0_!&ooZqVpUg;UiQ8AT z@`}L*^1A%Hu!L1vB=a-jLIv6<83<;6k$bchP|P8vJQj2g=ih%?uIU1S(VH)3uxV*Y z(A}$Y4uGYmKyF0ywE0(!(Tl2(uqEGr=*vUg^|M%lc5Xey1gYo2|6DuV7%-!YB;sBP z)CZIF;38A4 zdAN89BSl)dnG+;?VJ9QNZP7jh7cHQ|Aeu_3FjRYpPotWIF$J6v7ubE1p+|Z z!|kGCp@85aT>)wMKnZOR)lh{FZ0Mz7v<%BG=8{LDbkE0{U>;yx*i+Y>#z1G_WsE+;+In7b-cqeD@U zdK)HTF_TzhQJ~BpuO~R*ZL7ooL-zb@dq~SwE?~*U_W&303<^Br{H$PHhH;*feWlI* z+=WkC1`E>&#pj@$UUOb`$bo^uQ^U9G=#hE9xI92Ivv*#*{dAbaB%sd3QqFrrTnYmzL5$Ud|RT#Ju zQty>(Ysz9O^y1k7O<^MYYSXKUnKe4+Wn+pZeQ?xc+O~lJ+?-e<9UxoxeK^UNp5=rf z(q{Mz)6jhP%CykJzHO}Hhn{oK_{hWa+gg$Gk3RRb#OUH+n{2TUS#3aorGN5%0dsxq zl$ay1J7gJQ#rscco95RF7tk-8*TVVO+|Q)+m`byi1uP{zSDd?MJSUrjp}o)4w|Ux6 z6bDd^)(}Qr&76^b?MFpsFj3LVui(u1aezcOt4#%e+Nyj#?EEM$h z&_NNEPxNxM^H)*g*dNpySTA7;8G=&8s5@FI5iC!zl9~Z z!6S@GnmIybOCW4h)1!_L@OrKPc9q+8;|l6f_yRbDpi(dlNQ#d!7S?vt(?Mcm!Gq)^ z)_^t5hLN5{Jk7bST;Fo6YJO=6ISsW29=IHSoXzmV$57-*F^*G^BJBxl;gTj{}oND5S)&wq5A8CoW(m}64~;3@ zq74U$a%vXF55zDb{PY-oop1ff1YqTZaBUYV?fHT9avG4v2d*uG_8y*=CKF*aP?zN# z+}^Bv?!A-D$KSUsXB0~(=Z%Z$LPa@za+KFjVKUBA6%haU=rzU8gMnXOn=2(B>+5#&X&ox>2re+zlL#%>HNs6>dvy|xj{C*mF7aj*osOZ zMi4)UGNmPU-TC)b-}a4+UapXiNHt4v-PT(Tnf$OS6`|vagsc8}wV9BBg*C4GOuS`5 z_t#T7qUOS~s;RW(_at#rMKMWu+M^rgipxbc)r`&b#B$_<({zJ&3+Z2ah4SE1S?NY& zD!6OF5SQ=ID`t9KzDlzDBss07^6kxPq1LLf>3fGiAdhz|~{ZTE2-0$ppYz()|TO_$2E~BqyP25 zb`HmX@80ZkpjHf}Lko$!{?1!3(<0a7i$HuI%^--vks$mV-C&6%P-z}MEM>G_5aOzb z6Ph|)CvgTEPyF7cdb{u!)In9Zo(JpZ?o?VrzDg46Z)AHZZZFI0RF-Ax3; z6tXtuG7>uNiV>_ymkZErPNcY=SX01!@G;AJzF~NK##bzRe4J58lbf*Gp8L=BR(10A zBoQe?iG}Ppul6xj&WRDl+mODM1wxEktf=~d#t${4SfJ&`6d@!kc}0^4D7)g(h@E?t z(JqKypZz{Qt3A%yqJJu;*y10FwwSr9k56{qE3J+9dradnwkVIXND1rod~E})hNdR^^3s&cpyCPHt13nvL|*qy%vn|-;^Zwjr2 zjxuB@E2Y)?R$}fQ3;9GdewN96cNL+hgjMNXWu~yJs`sqRR}Z$o@8Jw-*N0UT)X6qS zfqB<&<&c?@?tAFL;7;gdfK&$UAobsSxZ=#-mvZ7NkfhWjswoB4s;9x5i`9rBy3^d{`WaKE;9cj14IDyRB89X7h*$HG~Z(dOPM-h7v$z>_^ zmOeGUcH1c<#?FWnw^oi6h?+k!XV)1V#dfc(!zP`1%Jc`$0qOna@OsM60yga`a=$yY z1nr;!%h3+Ytx(OeMS$;=z1qX)kT4*8E81VqtdBN-eo5o2p|-{M%Wq5HsJSWDQ!CTvyjC?0majzblS3oVDhm~#37wurD zCTxqu$9SIUKF$=>ZpUfS+D#o=}1bmFeskl7h8D>j>UeQT+irKYR|*TnmxE@O3eH=M(=2Rp7UU1?JUwOuO2 z=%wQLGlgfs(3_(%^ptD#=ft3!<@lPa7Q6*ZfYXcTLe`lB2)wsSDHK7rz!gD*R7AC` z*NusK#z5*^6AhE~@Z50gq-S z%TmlbtQgxLWfc)UzZcasRLwV2(%J-TWuS=2fv!Ag9T=z+VWrDR%~H#`x#c#z$IP}7 z^BX4ID3VN)KPR^H3I`21M4e{U;G_BD+(Tkp6C%PT$I%QJ2?tB*2_adJ10FfAYOv3|z zCi*upRS}z;K3?5;0zH&~eAOubT%@W@#gH9JH3!FQS2X{C6X`?NvivM(FgX zsH>wc+n%^*oD3Qexs3%)7Mf@>)3pXl{#MO{zYq1FN$Gdr4jkRbhHXxgmqb>uXjwc8vM)!bo+ z>yLWR=aD{N^XwUXYoJ`DaWj6Rbi?>Ho%bs{$w8XlCUxZUk=tD^jcfGS?{dTk-w#rk zbzj|?G^G885nIm8VZ4PU{6@&U!h^5;s!VC0>@yTmbj~ z`!+pM#Cu6T7wSwt=-xm`W8#+6q@^Qiaj*Q~1JywhK2I_Q5oK zYQByQ@w^%(pxsESEs{VE;SwDD-X$lymHtF#!gP#~Q$pcha>0!|v6tm2I-B8g1~s{0 z=bK(x4+}#IcU&k&zw(Gp&3E&vsUQ4hD*Aj6 zWFYv|h~>3Fx{JgP>;pph&L=6A8GE(qWF0!ia&t2sjylFBLkDYo3G_q?=ha}G**?)= z!Z4yTw?>x9N74Ca-O;~ziBpM9ah1l?V;^Vc`G3zQa>?npexNqTfIi816%xgfkF#@q zoWU`d^xknA9615BOAclC4J;IyUVfu<}Q z35t@1wu*-srC7m?Auh5ezkOhm>OvAn+U9=_%?Y(t_OOGdAgh=Ft!_tZjq|sXC+Gnb zdBy%MQrhO^%O|sT2 zmj-9`&1C4^!l_>WQ*LH4)JSE6sSAemeuOzf3E78YYYKQ7_AO(M^8|5d2ySZrrSV2C zj^AD+=v{>3|6HAASX5oqu+J3C40UGc5QiALyTqYk2-m@U>qR5heP&@f0}xJ*OW`FNNeva`0_I(D_Qq`M2m7e4VT; z+<5pa&vvlfQHR04_{-g|nrg~qR!wKEelyQ7GyUa&AEM6r7p#qpiN1_+*0&?Fm48Bw z%r4Kjay^JbBxXp?T+Y>>0sv5+G7cTAmK;4a6PI?J7XR>)-(UJ|_3B$@-;Kn+GySqQoypYq z)l_Hh6}R6{A0%hcB&Of{`|cH3wHc=czUW{Knt9P4Kk?JxiOowx-`b{iO1Dvu$j3jY zf1j!zQ8&mpR8xdgYVUnVUL=GRTs^wa`5#eVIipkmCO5*_EpObZ@wF$>(wuE`-NlN0 zX+e{}uw9k6pXjppoMxbNIbPA012GZbbLV^tQlc0?`HSEQbw~hioW&C33bZ&< z`aA04?vLyoqHs<3F@y_ek?A~`C^EXj;N?in(T1Q3v*TGPDW<(`4A6{>3{K1j5G zCX&{!wg4)WM4ex{&KZ@Rf<(te2x$Xb2OUdX)0|99vhB;KdPv`$d6rV#IYLvLMzv;g zJC%#~@OB2(@D2i~FhWWlQi(9|904I4(~0QX+-DN3nVVhr=%*P-tLEM7m#cq$fo4<0 z`0{QyQ1O1n;c-QIc;TL!{h9@9*vgexjl<~KMc+r+iX8)7ll_SeJdH}M*`nchsyK{W z^Z?t*0~|-|{{s1`(DHcx>k$T1lGLa~wgG^@Lv)6c(LV=SkDQUEkXSKL4*vg~t)!{KUtPyHSub(Pl z;SEQYB7SdkE;Zt3DCX?Q#lLBnWN%jqT`Lr7DB(a3*&FEd9$p4+jdMaa&OzVe zo-7hb`DJYIkaGB3gx&@Mj^34g7tYKt${+$a%tib>+%1_@>&MGk=J;jHW1-o?!1M~) zd$z%J?Xa`wQrh+{Ejb%?fh^t0&jaY_f>r$EEeyb6y#fIi-9*v?$xfQsl_G!17+l)W z2n5JrK>JBuo+-qx4+A*-{!mrv`8KqsI`V9Bl2@zp=^phiD!ck4G{Xy;Dl4e1hXfvSBrqo^7Vjj!5Xojp}| zf<#y7wfL1p-nZ}vGj*9EqfC1rqEgh-LCPKVIyC_J7Asuz(j!i%yR}%D!860)CWuuB zXvbuT?4X7BZQM!hmc3+c-e0kXf>%hQR@d+8S>ExRNkzWY^-1YqgA~n6S`gU4QPE+r ztg$?v;-clG?7lZGJ^e2%g@yy^R)mS) zqp>t^nAWTF_6RBB?7oOdsX0QKl+Ig2b{wuzx0gnn)25~&vIB4R!gdQGbS~SDQ%Dtri zZJlE4mX*slQ^41AY*g6IU(r=2AfT)JTyJs~pHV-fU?EeZ%dPGG8Aig!WPmd|-B--# z*k3OC2|Zr42se}-J0se2=u&Lma8Xjpc9pF|oI$OTb~?UB9QKAO5>y5a#NuT@it6cD zB3}$6N>4N9ws`G+L#UO3l)w3;IlXp@lvDZ|K(HuAB7oH*M$Iq|afI@iaLtglp~5zE zv1_wD(rrymwWTyX(*4#I3r3?nKFod%&gE9v6vyRGUEC_REN<=vweM^_=c=K_pkbPf z+gR@*_?_~+u+33Rw~zwRFb;Dd6)e`?)^M@f>GccGn9C#!?;rQ8Zu)H|(=9iv6xLa4OZqk@D1l8)n<-&NeC@i{HL8>eSZ?{JCP@PSfO z?dzSas&flH7y>w#2O>>{9)BUmy=H83?~3-^DDw3(w+9wkC#eslIT`Q0GkP3`TQP2P z!Nx1XK8a&!gFBO~=I2p-{3*w+Z#jWhf%X67WkuP=9+-FAj(2M-=%2C}3f#>5z;vhk zU;ynsGXGNIULhiCrpPIVw(u1c5YoWhkBz?(g1Zx_3`{d}gA=4CQMjJo5uCBA!xA~j&CSJ|kfq}m9gwRU&i3OH(dw&aX({x(mFFPm^z zcK03RfolCX6=X#urO+N_E6U)75dSC7y-|5j{uF#T_z8xLw+u9 z6YJ_xG>yY2+Z1>Ki;x=MuxFeP_b)!1y@rGC?w8$ic;Pn`hr1aN7~}O%TQGJ~k)bIt z_+w!G<j%6t;BPcZb_J2pLiO+|S#@?vsTWs#y*;AfFaS7fk!n zAmy3t3+XD1(pYnZ=T5T&L<_{ z&58s^!i}%c(`_6BQWT=)-Ga_XaBAh<{3iQSU7w#Osyn_x27s=hKt#5Bri&&p_z; zjN+;_c?_r-3-L&=q;GMrOWtMR>8`;)p&HmBt2(AW<=Ta@?IJmM@tq!SNaM+bs|LQV z4yWV6>d>p2YY@TN@16R?@tb)ySMWl7#!L)CTz9>!>3Fz>#hil>4`=|gtH{c}Plfi| zc4*9?Vb90CqeaQLz9CIO4Heb!WBN7isLl#{GQBs7=a`{nMqeOMaw04j&pVuL4gFSK zAISpp{DE$Qyvr2^G`F@lC*5)Wyb@A*TjP}dhk=(Zz5i_7x#`~3n5Rj1WnXxlSH4IB zpC%H(8!+bH`Nq7iI#1-rF<4mS>IcUFCL7w;&_w`;aTrz%AyA*1N}oMJzZ08O+1S}L zAC3<3{I%C1={QD|8CM$?XR`2Rx~RqO3o%;Ofyo6#M&_0~5tDO-xJGO_SdXF+I!s(Ff*?aZWeMuZAxAjh6;sY5T>?msP|2;E>8 zUx4NXsebYx<}imykiI~z$8C<1@YQ_m>HeQ(-Q_59=Aa%PPO+oa7B&LAuv+M_1MfN< zQiZzEa!hy7oqFG=Dulq3I?k57f@mNyL%YNt3e}iHQSGiL0=Mx}WJK#h7B|vB?%M=! z#{Inj;QA;EH6Gmv<5E4qnar2j7eF86i0`#}R!a)5F#u=kop%N5|1eE`RN51~lr`fh zE++DQ)KqLGLRZ0igbGiyTG_$yEO+%|U_=2%AV^GN$5q!Gj;ba~&gAF|`De3D!|d;g zTMY-|eDUgoq!4(UN9pj3gzFKg2OeK)ytD^qFhI)5#+l!?FYq zYo@jx77vjOAz=n6eJ0UY^J<2iteMO`hI?e@ynGN+gXBm;M3F3jm9@jW4+M}3A5w4x zlDcoIrN16(-2~#0srbu%&^v$_|El5LnzZh?-=ELwc}GfL2f>hFJRu1F4^6Az8ShLb zx1-&4=)OW>c=X?Bm6+`6;tbW&_oF(AU7&g zuudrkkRlc3)GK-M^TffI`cm}HWX6JAQ&ojB^f|S13KpKQjYrGKE23(Hp^5eXk?+`I z&+AN>)6jW$r)6VBKw?Pgq($JT$70DVBU!B-ZXXS%R~nVinwmwM+i4Pv_*EGQirBTt2=j<^TKe5Ett*VYN;omy5#B5{KBPKHB7z`hR^wuBNXBmAaIa(GUwP4J zK<2gM2Lf?@&=KZlk?ZHQzUx%A^?PuCYxo!+xP#+*31`rJ&Eg@SB{M#J_4z<}wL8c| zQX8;rnZW*93nWDR?ssJD!jjW{SBO$>``P zv$Y}VHFp6kI8cJVd-mV_e(*PqqhjT$5SPD^IP;SQb8!_}!BOp`QCs)$l9F(^$;!ul z(dpZ3YIkj#qJF5LV)Q+=<6V7ci~_uP8D-qIj&&^f(VI0H9aF7GiotnGL|zz4&wo6U$kT*G zQQ|&((T>Rp5XE_HAIuQMc=#pJML5<%`ZvpdDblRrUUxpz*M(Qni!es|f5@`E_G{(c z`CHKPKP0EU4=)o4)#q4)12r)Jp9L7rXhn7a_n_dlel&_M5yQJNNF^4gKtK7~alOZ4 z$Toy3O`!T`Y`qPhmPgQEMqs)~ne%fasW~ia*Mwiv`pWF}eQg{BZ?k=0B(N_pv`o0o z?1#Xc^fO&rk$z^yJpt>`|^$AsUgk+&=KTe6ATp_1VH6Hl9BFt^d&u5w644miJR;x zOnrn?S8jZnQkl)!pMNvsBBlh5hWo0}FV}o)Rt1*_lc*qFwU$Id4Qy1LdWg~EG&fHr z6&`4>z-7}=?QGxNwS08uz4v+!DmU?nt^3aoqs)D8pir2Owz`u zyF%ECT>XU15gS>@=$?mfQ>czd85RF$xh7g$%Tm#0z(pvF7?l9Gdd(if)M{XAO9h|f zN@u*ICw|vPur^**jFChSGusihnUj)Nzn~sL$UFmBf1X;Z#+G;#e+FQ0kN8;OPJv{Jk4XJE~FlP@^6HWKP)4IMB!3NOZopJ3;=1XYQa^+iRUG)7RvY z@$vXKb#iV{7a9DTCLZ8+^T!CNSmX7V~di)*`-p0$NT`|>5E z+;;`CGk)dLl55)VsJ(~Swla37N*Fvr7{vw8cp}4qrR_0 z%aL@ARp3QU)8AW>ZNV!a$HC4ss0tlBe-reL{fn0C zIZJfLdqV8i-P5-fvbLseZfY;SM3+M$~GTP>fl`eHxLsV_YMMlTUS@Vzu*^mx?#cXYqMtT%&moB zIow)gxqMA1v%ujacwPKz?eE1ZmZv5|&usia2Ajv9pBjE}~jubCTAMPzl`0Kr+ z3S=Zd{~BI+_H*QeOTU{%X+nEC4fN#^`QewwB?$R^CqE8=a|lW04Qj(URpOD-b))G_ zqV@x6n42TEqvn_5H}^ewCk`m#whQL;y4GPnpJp)!`k~6jNm{MS$9kEtW zbNM0_>afrN6fi6U2(1yRc^6cv*4UcYSLrXYOG>xp>lx72cyYNi`SXMVKzvzN|L7$>2yo z*a8Y@0?3wcc_Ker-7X~DM)tJMr5E9}Ei+XpT0IN~Mq+9)@Q*2JU$NY3F6!Dpfgdu} zXCNt3KEgB+fjtNF!CBx0d|^A48wE(?TRrpd(xw<_#gZ(sI^uMe?}@$1i4NKpvv5*~ zkn`v(8Z$T^VTO_4UI;guwe^UgH-1oWz2=43&{;FvFw@#nE}A09%;ux8ja`c14ImG< zsT~Kwl{pD=y}9Lf4CyO#x{x>MRoW6u7-5g!(LnMb^2b*+&>2(}{LCNIeX1ESBW5C_ z+Q<6bbdgBX1t9}UN|1Q+&<=;xV>p3XW@y9I1eldeW>TSR&<-FDz7Zi$z6y7Xv>|f?n4JPwR$_eQB-ub_aN1?IbBm00{dA@g=r3T(1!EqqAw=y?1wR7+L*3NEWi!ojro{O=Xaz{w zj~PCcmqXmHd?%M@qK1EK+H?is=HD`VDS~g5LA7YT{m~15t8oAxi?Oveu;d3?MoAll z;ks0_uHa-6^x8M+p7!gobm0}J!>KHr=U((oc0HM!%Xf5^3LqphJaJ3lAwWCqI;Z=H zCUSwzOX+S3VEOGTr%PN*lM0U- z*b2jMOPR?LEf2!qJZ^2%`7{?&OmAs0T5NOKgw|{lv~z3l6R)3@*@&eZ-P7WZ=)CuQ zmj1_{R?$)MosAp+qRT3cDe#MIkX`J3mDgQUj-TBva75Wh$eu4(m@o#lRAF~h#ipZs ze%n8hB6k|=G|);ziDsbnrA?`1-q<8&oq^u2wpl_v%PN{yaw|`n;DOsonq0#jLxl5R z@cbxuxe=AZdP+;NKT=NYB?=P6zHUmqo;K_muX#ve8g)d5rorCghosih$&6h|HApWG z-Rw!TF<9BzRf#b~b>J@TOD%f9lL^5nlNv1}tXh|HsWH&{7lZhf>`|w4g zd%M>{n9oomTV1r%4wM-8HcvZ0O*tlT2JBM=quSS5ILNJ=V%tG4j`*}&Q>(tZ z2J(`^CqD^bp9JgjhlY3RvzV;+3CHH}ewZ(D1;a~CGw692!X`_o3a0<$qav=wZuM~; z-cQ+at4VC8h%-!gw6fRnr`YajJ>2I3?t7Z`Val}Pj=(ChE0mY;K^FIo0o5lvInn$V zFY=wu4?nqZDCf20t?iDZ&Z@k}lMeIl0BWkAS$#=A?xHDO@oS9JZKysPGNew?*PhJ> zBJ~(c=PKS1l5i2Ntf9{dljnp~xPLU8cD;7jR>4Z-z5-qO!lHMWRC@c@oSAsDP-nTK zyv9}`2D_XH=doU=2gf`rWp1|r#bJbuDEUk%DxJPvu*9uET;smJON_U`qaB~{TMchi zPHa^EU~~yfOPb?tDuSJ!)xv!~@`oDN0UWQ8Mkq7>!tgsz_0fW2TE@Vj zfo3DqhB+l&PZ~4RVObB$%G$hL!Ptn8%hqgFoUfZzgoBW|9K0qW3Z8eJSHEaek}+p) z7pCN_>e9UBRmX&bg~RJkH?}(?phGK+ynv?HXAaHVFAsTYuJCDlzc^>KpksJ#=?rWx zLT4C^Ewx=U(~P7l%+|oBdTwzm(|tCZbu}+t;bRl+VVnG5=!?5v{cLXHScCNVK?s0* z^M}ja+1R~BO6~crOWVI+F!m`DybEZ1+L8GrlZ{(22^kEEFXUNkqWrS%h5fO z_-of>(wzov>9H_drRbx1XK7}D`BVJiaahA&G1i;9f@!o7HRkf&`Gu8POSESq40KLH z96V@i-H;#`w@1x7nzj>`in6(pZIhuzVfD9dQ>~WTYPG#%UVV!X^ho$10kHApGu> zL}aUJnmj5^-FL2RbR!#cu%JcMG2aaA+(Q| z&cloD&9u53Nut6h1Szyz+$a7VqU+XCS-+mDdLSz5!%y=Z-o6AITI#c9Oq1sFwm=Q87xLZ1$7 zsEna+ia!5NZPZ(yqGK#CzrX$f)ej|*9-gW%0r0d3oZd*NvGo`msc>zIl0nt1mzhZs4Yz8-x*}}k$-O=welF*wTSgF zhVFE6Jnh+xxDgbx`7ta(TFysw8ytBHuJ(l8(Taza_yMz?v8HF(A6PF8vl$&km|g)x z%oFCNa22x}M;`IM^|?fM0R8k6I=^}y02AolqErcyl10q28{|biOI^gt(xc-Kc1qMnM&vMfS_Fdv|98b1&U+?gLu^*AV;-+nUE=fD8l4t|Ll=hiv$V|hxh*h` zZ{6)mBOmoh1D!}S9M&yWP_fwLPBiA+ky>#Aa@gH~dIo{R@K01ZkT>8^FSU_}+$jKT z?|?r@Ihciv$|w!r2#0wgd3o1}XA5d!2(r~T-~58pYVJcB{-v?hnLekWts=*_ zHe9k`0?Eg;p4$}5deFqiwUphcLHX%(b_0_SQQHEUO$+GfD0R}NgFnIFQlJ!jVHb?^ z0E%_g$2P9UV}}cYn#}7hTjq$Re+AYv-gy&zT#q%bk+kZhdYmkHJ)KD&S9WFfCf2MhMHw6`7gaog zx=82cqcBGOPU6jZGWu)YIW-&{`Ra6-DCH9+iTdI;g9>n!*gYE5k;FhB%0PEeyB#Zd zZ{>V>A^Bm1#+N1V_ps!H7Rk0Q-iJG2!cwWEDeP7MO~!oDpRvrAJR$MF@{HMwi`XwS z#D*YPt5n=E*Upd5)rxK|0T{GW))C8zapCnBczqBCJrU58&A9^re@M5XQS`eZ^xGjE zyEXKd$&Hv$`c)|~C<7BBq8hOawjlsnMUZJ8Y}28~b~Q3!=#%0aqv9F?*CyMFW{>G+ zEQTTHT{G`=K|ZnN9E(|+(Nf;pa&x++YPW?E1OA`(As502fdG*6-Yrxc@_(O00cPML z1PS^7Z4kbl)c?;0QK{cmH%Tl1x>6{pSN&^8zq?_oP{^XyQQ4H5BnW6eY4D}o zetz?RZ4gK=*DHxqxkx7B>|}lgB7o!06pX;opjuC?A{MU~-U8yeLfK^nCdqn_xtU)* zXdi5{`d=GFR1HfV5J6I#FBF<73rXgF9YCR8E|b52ZvWkTXLTe^R&#DRDfP{S=4Fn7 zoBO^lfPSsO$C-Xv?P+_&AGX;2FNDWeD(D?EVx_$6DlR>%zQfXZj@YpZLHwETm>AZ| zF0sm%Yj>U@B3?PaI29;r11f&-UmvCRy7zX-nd-&;=IEy9BMfKSn+5}8`SuYzIJ#sZ zr=ME*BXzbOc?P~q$0Cw_pVY#|Yk%3~(|^9i1J}5GNzdMtYHBpkKU;as#=Hw9bdwEI z!io}s)?(9>X*EJ!4eLJWlsoAuDSZksZm}-HFk2(n0*itDS^{TW-Fg-b1<|>}hi-s5 zy?GvCufg{m!4wGpkXoKeJvGVa&P8j41)xHEb$usDE#kYN#nSSem0g z4B{Q!wXsvh>yR1`;oH6j+^G=gtYDBcw3y$B`5N1&l%OPZR z!ISb=IGWI%^d_KL(=?j}i!aq{Ci9y|dY0HZMqJ07Q9Eh`f5d&JlV~Q1#svQeA>S<# zY0|t=VQz`Ht37V1O=&KIqGB)nL6OAd6ExokUE=oJFubhNS6ri8@W$0V7ppB611#<~ zc8oxAEghF=uaR#;`=!1U%ByjvjbrM^qp8*LN=?~O!AOJD2%_QcgGcQBufwS;kPEE~ zwSVyS+3KI)*`W?Z^X`}&WVYM}PBS{te|8;Yp8S)sv=AzuWH-P=99q_kxiWSIXR6#@ zGxlhf>}Xy2;C}lpSw=eMUAdbwdi^@FST(=l;LkfPi>LGsk<<96qAkl9 zh83cveVmr}D&-v{xLGs@vvG_7a*oNyF&$-53%83Fx~`{xq0-c3dhr{fOYwDw7Cn!8 zo>s=EU5Q8cv^u)cefJm$sPd9QkIitZc8`B^e+;&7rJXSKz6}1GP7g&CZL|4FL|@ZC z8SG|FY%t*AUN0k9*KoOM1lyL+7i%srs4u^k2vq7`&e`J!FXXpks|;xw*HQ-hAfy<{ ztjsjfosc!SX{58tc}H_gVpv&9ujE)F?l;6i8>vpNnC;cPHgt(UoJ@9vrK<} za938-){OTaifby0d7mx{h`cjRbVgJMNBn~ z5izWN;MkIjA1GMzFA_807YHW9fkStFHQc}EOgVm6w%m0Bn{v1C=)BFqJX0;tw`Y+x z3;a4oO1H}(S9qXD+RW75ojrLxXbGlCEZjg%VEOPSIxz=Qo7yl?l*LFz1uig`~!uZ;ghJA7nE`y{bchC6c z>M}Kd=GozU`5W`OZlYBna#M0Ng2)g@nD`zfS1r=F0ek5+kwe!IE%=;|&=oPAI5#7^ z=m-TyA3kRjki4mWK0)ipR@$!p-O$ys#^sOu!-m$ay1-Mn2->$v%*YM6u^ohg@>$d< z@~e3YK8-q3P*|`PNU&pO7@XDxRp|C~uNP4GI~Gguu8g%%gJuoymS;)uRzU%d^g52; zBfG149`v!S^&LO7-kpWz;zZeo2rB0jr=+jFh@ovO@rJZJABAedTl2#dX#kt)2pZUd zm~XzGJ{fL+v=b9&W#uieNqZ5ov+&+7X8%DBdAkGoIWZVB3;_3gakyWii(r`WSp*@0 z6@YS4VNfQ&bGo6S!af*2Yr6tw8btM`ufdo4vL*LfvLLFs6P zk2GGi+y0EDLgt&kNj(*9B8z2BT*`q)pfstv-Z8}*)&w6iE!V5xIw61`>E;Tw1Mbn@ zmJYjMU=h*gKvblZwZ>|INKM+rzVpL2g}|Rr!M~X7ni&s#iXd%PEZ2v!uOIqTt98ga{P)(Vrb_ zSWvp57b}6zYdYTAQ1uYT8j(sSyq9nHlWBa{9^1hLEg2F*=m=88cBo_tqxnytR&VXF*;aJBnutG4mVpn2j4BGxG*Q7qV^5hQmjuBEs1HXkivx)GSQ>dzFs{Yg6F#K5 zrzv=es8^iPnFyo;l5k-weE2UE&3Aq}3WFqQ6L6EoR1{H(^&Gl|;{5WXQ98v^4<3V%%X}zQ@TjYSfp( zh?pD2kfY6b-HnLa7>66LA?zV8cKWKpIMY+SR54!Jn-Q5Hhr$an+X?y$#(+Y$pr*G^ zlr^}tVGKLCyg9+l7b=ni0n}{WL|xM|^hrl0VCm3RY7JBijzpW7-BSwktppfM#QYtO zXr6>L>qp?%qql8yhBghhLBHuXw^DOf(hn`Q#jLrxt3MlUXjWlzBp6jBvt=0*41l@b>7+1!6=V5}1OQP8vg zb>>EN+?0nsg8@hC;#JI{mS~>CtWbCdqgfXKywOMXq-GoSfzvpUUl{D}1*OYD2c>wC za!CGh{DoNv%dZgU!VJcP#4^@MQM~ET=Ii&BQdNf#=WO;<+cFOVC@AFrDYXc?l$mGe zGcu_|u~d^4GUN@z$^2q8-pY#Gw2_<5e&%aQf07iW0~X=HH#_H=hxV)0d0FQi6_fwrpXNWp}1=_smDkW?$B9P2hN zkIAp4Rf5LNCT?mVuh}U;Ep#XVkUm>i-&ytPTtlG*0#l(IEMc(K%zC_G=MUGe9?prr zINI9$my>DYt1$k32wH;%DqVs|M75;fpq|S{Z%d!9-Gqi_Y}m?Rg=!0WE9+wljH5%n z>kHv#9#pH25BjQ742tAb{MQ@(H+`y+2IY&%YIYG$lx}W%_FKWsW;#L~Q~Je-+BEe} z=!KewfSL;ASw#i0EZofi^QhlIow~B7S*GwODP|PHUZc&9R(RQxSkU7z>&b`bkeWKN zl4i6Z_cMBhfFJD2w5C9WaQU27(-PUqStbf5m*yy4OtYGHIxdpE3ft9y@lg4-_E#YC z(eIH!Zb&!)(zKLQ@{3AJ*$Nqc=D3YJ2=kS4+RJdo`J$y;Q9Nwk@BEZxl&{*Ny3498 zR=uQEz%I1Yy;kr6(T5R|26V!Ln9Zhr+ff>~PCm0SZSjt`CLlEs_x!;7so;4=oj)2c zkGgD)&R~gl3HcnouF~P6BCPS&p)e}+T)ZLLYR&;orK~tw9kfzul$lEv{ik$yXZx=5 zS#ou2BiJyJ*YdMSv!;^@(+qK-q%_;Vt_`c7V`@FARsx|`uHd7eR1bVWCszcGoA2dR zgYBJo$44cYZ4&+DrNY!4AC}g-jMB%YJ$yLfTQ!Ajibw&XEM>nip`ZOs7>wq`P?z6D zt{T5SDMHS-C9qslA;7+v-FKa1&eh;m!NCPmz%?l_hj{*!9ytB3u#oce6Yk>XFc8v; z5C0t>^82Z0GbxLgfoX0QFKyBuvXocDm0+}O5z zjF7O6-@)-E`TST+Mu8^{&mCZ};euUAKBZ*gOAOOar8iCEnnIpUs5ITS_u=0#QnCp7!Ki7fBSysw3^i>= zRG2G+BRw}3U6Hf)ATMDIc5vT8EQF;JJDA*Zf!Io$c*ogZ<_~%J;*MWbV0SSAnK;;e zfCju)x{uHU$*0%vsrWy&ZBj~}tg}h*hz7&llIZO!rrG55`~w)GrT`q>hfa`&7GTJv zx<3I7^f-SMli^>kWP#LqwX6JHb-2&ya&>t+Z_q^|zFRcz$aGzeS|Y;-j;k7g z+czhq@u>KCMz4JY>9n<9^{yOEwVVhTBjkC#tUmg&6SaAQdN)i}ieO+qIMK(gG}xri zH8pO31Dd%A%kQU2jL!bL2n-?tDH_3X<`V&1OBDlt`4=SCj%YdI;K~R~5#fT_7vV-C zA^OG#l`O7%^&B)SLD_(()BsJ010Mk2#4^2cr=un;$*w7TH{B=BIyb2#t^;s!*Ri_LX!sP<8*_zgCdu z&M3{lJYXF_WPlzX2G z+`0SUV{cyth){1Jbc}kOVQ-C^fb%3eqbhJd1Z5-w?fU$B4)XdjYeoNUht_-<5!|&8 zF{`bCSkDrW?Odq9WzqWhv)`&0|BY|bD!~r3C%Wn2pGTNu;f>bf71**hz%`}tXyNbA z6{?{c1Nv3O6;N`2nSTmq>U5lwlV2ZyoXP_a-A_^IuDh27rc)RLpL+%VL*Va%9TJFD zpHyuA-L%tt0k^;uhop*6c!eEnL~S6{3^9K#@O9Anb@+pDTe{II`5gI~drZmp9gDT( zugWJK;jo33;BStm-(>zgV(dyytNh|f@jP-qk}vyR@#!kn%p`J--a~i{I2(*BMPr>o z7w(Fjn5%08IecgDF^o69rYQXN{BQsaCKe_B6@|Qibmbdzb@zVjVeW76=m~a|{tvZT zAjWL}^@k=w0F(o=a9!?WY0T$Z2veoClwn4I7iy|uwyKlKCLg>J6FNGW!)Xu$48c8c z07V4D+t7(83F_sz#$)HVj4RPY@k5izJ|+_AUi~2M|Y0$?WP zv;j4awB}x|!?qj1hS@J9sY(KHcU#_t@nxq2)|F+8Fw%!iX1sGH+t0S=n2XY6u-$Cm zJUPkQdRQMxPvVnjR*&sI`R;Y|vSdQ}@a=oLb=s0dp2v8>wFXvWUhC^-lQ|cxLih4A ztm@CczVBaJt0vNl0e-B0cMzoXU$=Y1q|p*;b>B79z!UdzJ0%}YP!sytvjyvQn~A^x%IffU7?${PVaN?D|{gZi{ zzJyhHpRc}ejrJMRr zKKw(mG52y-S*rU}4i<`1?un3~*V76{K6QSBhOw#tDvfxAMAl2+KV5*Wk8>?O>k)j}6Q{G2)*f4ZdCx&4Aw=IWNLApuFzMv#mn}79{xKPKxSJW3f3FVu2nKlhB z0U@-zdJ-Gq3_zVZANp1HY37>H*`M_*PoGu?AJ$oDVe4G3Qzr-2+tboZ@OMZO*#IJw zJDk){r>fuI&l2`((Jj$x@~aXI2CP3*m&&Ikvu-ti^E(N~;4j0HQ4V5JVCDYs(_e{A z7rkGEZcP}B?1cTw!{$Am`S)tU=|?zu+JO45{{t86BdbZ*73W@I=4^A!t2}fbKt%Uj zX@T8fiuRt($Zl0visC?T)e2v50B5%+h11VqEjY0MO$~rMQxcMLb6C7L#V|-x0y_2d za^jYC$eO|tq5KwKMkWUeG;z^9LY5tV%(^QRa`XM;F7|WCGV|2@HdGVesyR~GdqV2w zzAHimtkzJPSADAO8N{^w?0muE&O?Md)}6nerIA`F%l0aTe`e}gPc&wKNKZ}|lYQMg zhAH;9Px#hSZBSO@-6qG|!nUiWPa`_D$Zm8>%5#7~vpZXMJD?p?Yg_qiUUiK~9hv&a=D z+Wu~mbAUJ7b#j^sZC9n~nT+`l;_83j_k+Z_RZ;XzbHeyVt!>X&dbQOt|Q8(UEpzk6WHz6A=U|VA&5Vj)fB?<`t6x6CU!& z@VQ$hpD`i8TQ%;A9#^SwjYxxqBC1)pV^r?f^YLcY{~_zVf|`E*aQ#gPkWdqPCxL+U z4g!KEp@k~F2~q^4ca*9G0)`%{G%3;%l_F9^480>&DT082R7F6=_T%uMIWyH8*)bq0ZQeB{FQO$v~`!j5%yq`jAI((>^e{qVgISkw!Y#HalE`YC4 zw1>`QQ=?GY!zDFvb26ACJys{uZ`mOAXjAXe;^9@FM8VM4KH^Wj1a(7qovK$v$$hW! zzAujr>y=pnb}-;k5P>kDP}o~*Jz}YGREn>6gsk@1%s^!52IfnO%>inCN^GXv|uCB}q zaR@aPT5_?Z0?TC`I!-G zf&jk={-4)J?|apCgpCwoQbU%z(Q#ajf+`nHlmc(Wykn~8^s7&3>qeuor<)0}G*TD> z(}%!Iw~ZyyeI&m^dGM37(S?M-$^tfkzAoh`JUVtzKT|$VVu4Q~jSB{5D&KPkEV+c~ zUV7`PJBy~uL1Z|0u|;SF&P*nsS9u2t>!xt9oX@cSEo*42>IO~D-g^Akr{Ma4Zx5om>Q8{Fdbt&Y@+wWY1*USSY=v9S239T#<@2DOC!^^u?64G6pKcUP~x zYpL0|SP!McoUeR;%J|z{h=Xeykb{KsN--Ldb$aZ=JOr4!5x%lUcB7H3DkDp%=A<1z zcAsH8Sru@WSmhnz-XA))7^*sm5YyY48_02=>|2#;3^!p~ql%vjY}$C=RF4E@#3Y*k zqe%++D=KG_{IXI@!p@RTo;aEkkKl67^?BQ+-}@0~tt@{7rLp5tB`odQsd`DK^zZOO z-3cho=l8+2)Oa7qw+J&5Shx{T*6fR=0f;>x#K(8XexBPs>#X?cd~0wSZ!zx|3c zuAA9`K9}upu(P(^!rKqC7#Aa7VI|?idR5`yKUn>4Szf7x=o#g&=L(p-FF9URV|;U^ zTsuA*Uog^GRXNPU#CWp~e7+A0iHR%LYpUuVlUHX+7GTv7QWLZf;mp3pQVkPzq)!sS zp^As8uB<^v4fCdio;Zx;%kDjH{r!kmoo#Nvp8ghSHSm>Zkbu$*9p@8q(e{#}dhiFy zwzMe*&bX>$g7SJu+kJ0N4X~0Bsy43ka`bF@Q8?tNuF;Jok=ht<3%n$&UP)iL%6tHK z9eH$2&!A70)I&+ifWhWw;bVXJu9B#(hI4R4OP`O#ivRFR{(FVZ78K7L+LgOc;tMLa zKduA!D~7m$yIJf1t!3cU$VH^I+1;v*tq!PK$C zZt9TTaRe{UC&A@28()#+UnC`9vBs>VZ#asl8OfZb;Fyc84bCQY1X4h?2Qq0vo-B^W{!XQWFO-E27F7?)C+Gu&6Dpv{7_zXQvvD-1v1r7LPY;W2EB_%NS z84fFMp_(d&4C`txqHr-o8B(aU(rpJ)RI!TO&ux{OQ=kQ^a0s@Y#4)SW4J*gVU$X6a zy)p}pDg>8^#eaMv?8Ybf%T|}$T<~0Ev6XsJts2aq!2tV%<&)5Ul&O(#910}hpN685 z=?l43!9zzOWiwQS@JhXej->RCmoanjS!hQJoVYZa*ZqxCYKlOs#Hz|t*9%dRB8p=&V{>5jZK3QS^pLC>DN{)gfD&31Ss4uV zoqqN21PVkFbFp0gq&Q-fr6p8|l+Y;0!oedvp0x?}Jy%oV+4jgGA$+5x z8>sEC0+6pji6tfXJUchE7$B{UrC~H#Ed=Jg$1X_xtx*D3;l!OTfo{8|Clv5V4nm2d zsXV61_X0ydmno2nO0UhZZAmIF;MDF)rG*K7Kt3AUfG#NIUj_j8aGXJ9L)IJ#)~=V( zh%>erk|egLnYFKLU!zhNC>mBdS9*1WJ}K6hV|TX*E1#t0R`L6T#HlH%gDO^e4f>$} zm3Y1)zChSvPrBV;I_0S8oC~o^(H+NB-{w(G4-~5pk{i<+d70B3qx~{%ihZ5?4VbY8 z4r5?BgMLyn*-O^pBZ2*k2DE`zEQ(DKfQv%GPuwbG@CFH+Q*vihe4%)rWzt~gsD~0} zs)6r6Qrvm9bJ_vJ7&ziBmZgxmG{hHSJZ?YiT#>t$A72a|PdS?KO-3^XmAzF=?U0`# zBcU|dp6yf}g(Lk0Jj4q$TGld2k;mn&PmWcNk7+1tjBD}jLhJhFE81I58fS|0(`Mx* zP%MQD3qyf~iM6%4v|2f?{QggsGGcqsc<7}!`D1BNgq$`<+!+vMS@Mm}G?cr={IPUD z0~=+Rw+9C1uN7yoB2_Zzo-a?Oh{aD1zxtqn*$~EbXSZ^@nrZ20o$n3LGc?u#rS&Kp zp4U+Ox!kaN#T|1ND#l?-3o~Q=nh6Iprt?_dU0cBes6mgSrQ>u3 z7t6TWb%ME-aOU8>h*|G``69~u6iUB@!@Jz^#W%4^R%jC3lBD*F3u9#hkaRda>B{~3 z(vGOEA>#|2ii3hfNgyAtV{y3?;kZM9jlO=ZoZ^PJm;9Jcw z0Hv$Ye*6jQ^5-ok?8crwsQsU@6(p&11)5`7LbQ1IcKwR}Yp8)S@T!(NoxEs8`iLfQCJp_sY(dg?!Pp_@>b?-O+- zQinFEhpX@XJc-T}iU~6m$+YCqSn{NfRRAudxNiD`vVZq4{L@m?WPCfqZe!1qCaubu zaw>mYse4Wi9yc?Gq0fC^>+J28lI{#rJ-L}`n=-QnwGh*%m6M;hfU?a=eGx|bsxyD* zCuN?c(4ECHs}6B@lZf%9jD?mLgve`nqAXqu=3YR!vihap=oGNfS%0Fs)Q6}tPzt;3 zF;{Tc%lUf`o=RUTu6F~1Wx4y^;m_kjmp+p7Fl5aBQPn3X|G&5AJ>xGKryIz~nLr%q zyRq%J6|+=lP#r0LNpXBdv*jayg2D~RfqqJLt5qrmTLhowgC%Q109E>=r^=kah6~0t zS!Ni(!bVa93d?EvaSdLLXa)ULxs-eC*@Os|T(=QHKmAvZbKNhJ7_cA_#_`Q*GX5{$ zlhcv+S(Dm3E~EV1dhi4VR@c;8n^frAGXuU!3gT-A^PfU|nNXI|VzHz&oR6n-e+4x_ z597wvj)b#krVxYC_Oqi?I;4W0e7`14<^5=|`kJL5|(pg*QsIhZ6eZ-GEJ zR1Zn5Cq~3M7fk=ls{S{(T*RYoqRbN^k^sCHHwAMjIG=;Hmldr@$aZs3kDF)eTGz~K z9c7zLxt@T$l_0j02AARGfQ~J9kMB=xVHR8tNep(`VS}W*iB8M>$h5#$OUo{X)PNpW z0S@kAPS#YF-SvmLZ#zhrss{c@Logg}*u?D1weNW=$K^cZ#-$EwZf3CB zGe7X{AXUq!B=V(fCSQqrC^oz!g1pEVbU)`}_vwYj%*@l!s|4jF-m@ZE(8Puhl8T8e zC5gONrx%lhRvMQ}M2SzDGe|4K+JGH$ZO8Up&z2agyT?5;C4=<;;tS?=80}+9(nY-G zJ*h*&7{h0|Bbv&8^q_>6)u7Lk(YwQsER6p;6D7D*E#%y0=AkeUtK=}%)L;@gc%|sb zuJDUtyt8F{chaLd5<}rY%=U@`?>1pO@ABElLkDj;f`r?u>13J1XBmr9bsIjzwAgwN zbkC;bYuAaFNq%|dh@Ngs^2GAh&#dbll0w$wXYbRGRNJ0BSP^Dj8CZ~Sn<{JFp6aq_|4;nAs|8~Z67ys1PnunYwtr_Y`C-WVOUNZA zfANrXc1SWe?=$b^?fMnBRR2^#l6daI5r{KMkvU41G0o@AD7yJfNbPQf;WSVI|(QGDIb6JAU-Q2XmH$Faax%jUIGM4z?(^S9dSq4|O zcJ;g#UF>Zg+_<9QAv(9XA|L^;&xW}pXa z+;5@;YcdSD?aIA5tJ;etUOxN}fQwvXTLNP3h7oS>N&nbx6>Iy57a5AxWoxJT7zL1& z7lW;pT=4IqazpzQXOL?@9MAQ*Jj|U%ZVW7F-CTXWL{gxfAe7faUb6{0&E5>4qrVT@ z-dEl(T5}$P@!{#FciwwEu9hobfs>sO*O{*Sy6ZR&WE6}&=m?lInIu;1r<@Iu4S#pW z*(Pvp$L4)Ao+mBeP<&Q_882(`O$w{$n>y#1)RXsyaKqIftUZK{8aCo{qQ z4#jkCteySgU&@;WJzs(N9fp&Bx4@-N(mf7ue;bEe*39Qx+uBW+(rx+brP2(rX2oY2 z=kU0LcR4DptGQclC}%=t_-6DQDLZ}9zfIF~#-F}fsj8F&=%zUyKNUiTtxy^K3(omG zXHAMYABsI#xmhx&xV&`mRoyAG`T|l)cyQTH( z$FxXGZgSN5px7L#^*K+g6{)GRmw3x@O!1>K;ReD^N6N<1;a4)Z|G;aj<5&8>_5a0P z&$k4`ARiMVQ8Z8`M*yxJPXiQ6KwxopJ8+CvoD)ZI!DC_y8{i-y^8pu_k|W0aFfg>8 z2xA4r5-QR83d6X3DbRtK*NG@#VE{D{-br?rvyoGfu56u3HY-L!WgPKT0A20%ATXC% zFa%al|CHrLVXMSEvvJW?4Ju?h67c#3KULf{6p9OCRh#jC_^F5h{m#N*p&-;R>nzGr z+#EQn3y^Zp@gu`#XnY1x>5J$fC%FTLCRw2!&09E>ER?Rtu4UUXy$5J-W|iWS2lAkz zB4;G$5<^QnqH~Yy-W>bo3Rmi*)_t32%r>dcU)W=h>W5kcZtsyV10R__0c)QgIdfkF zHhw43Bcu0DnO;FPY^Syh6Bv79#Xn6279{g3ipq3QqpifNv}g1y9j%u<0ko=x7m!m; zrN^jZ%fiaavkjN0L(FOWVbpSla8JbBr_2|ok9aKsBWi$I#r=D65IRujk=Cd*`a_WI z2;MXd5_3e*azng`*NYAu(u;^j_vRtJV6G(*duH>iyk9_ToVdHjZd@)F4(-!A|Gd7R z3z~?9>DqhA<>r*-AXxh23YiCVO(mMwA&(y{z?FKmDAKf!kt5u9h0AVyQx(=T3qn^K z-wN#K$Tq&p{ZKfGZAR22pzE^$&po>icpgFgNU~^ag<3{9v!*()46{GBl>RPkA*Hb? zeFGr9U&-=o*4G1&zT!D=#i+5?LOwt z7(J4jo7K9eX35*k?81Oy6e&NGqLWm;QJXTGg=wZmkNX{$@hM*xUKM-uSH;99_p*3| zcT$_;Tc()$c4KExXsk0+u8Vhfvil3xTUVrCcNkN1_*VDP&>x`8?>fqB-&`hvWwe7W9c4%t)(8i-6g+@`Xfq&JVN2eSEr4> z;LLDcP6I^9~{sZ zVY6{u$Zb#9ta4?7Ik9iBB7SSQ(QSXi-DhaY9s!&mKt_h20PseY38I9x;oBVmo^Y;) z=1yIM9`2xp;2?>S|{3cUbipA@`8eSlbBY;U} zXQ?y*&Ti%jfD`42Z$*EghIM5u^GDF*VbBN9GnfNq?h%8bwlo zKmmk^sU(x<=t*pRob=4Jo&b==B|Dt?S*_B>^FqG#P6&F9NPi9_$YszOjv%hPzzpf+ zd9)@kCtRziRWOL=Nf>fy^{OjfmXPH)JpRLNxk)4g5M&O+9oBSC z%Qc~0`(W&jRyDDA|>-CFO+C43oqcb!=`rv9l zoV0&aLkE*X@JQugyu2ow?)r(Bhlh^bTai$l?_-!@x>yzGTqWzjoNT{_Kvs?1N^MoB zJBO9F!7B*!BR<3}wTQ&&2bKY-7UJ!kP4kC`Rojer&MDhCrrx0kVw*w7>m(h9TbVIc zG^9oa*ljwcH^R7C(X&@$7cwc+r>3}i6}3#A`&4%6m_{^@&Q``?y}dYUP9S-;oPTR@9-W ztB(rjK5UY2=w#W@1P{CTrOcsT13q&M2tb!URut~0Qm})zs*a=LFB>kB*g%+6Zw&}0 zC^jTr`P3X3OC2}Y{OEAp&VDIhwJq<5Xt_|~xuexsX3A!mQ=-PE8~GO^4r1v2O#n+gJ5rrSF zLVOyc<$+VSBFnj6v4UEm3qxq})d-&_*I@-O${HN#Uyb>*{j<))4ri)j_AV;4pYmJ`b5n704VFRXwxU7n) zu%s)P2bQ1XCF>iktHVZL&9}JCI+Ehm&W-lIiq(DiV)W$I!I5U3`M@*p?zdXe!?I7c z%R3(#<{L?D-gc49ojMl5F9BrVkKi)b7mCe~0EhiP*NLTtNtK+s4}Jl%5@Th*O!#i< z8zQcMKo$PZ@#-rpznd{ys#=wNeOdC;+`(d*@Mw^i`R9H24dffEWzch;%7EBQ>Wg3+ zj8tMYt37<{9mj+ML7D0uo3bla1r$-6gs3QB|DI?KK}|b?kprU99`A+ zj@gR=8(YXdrcJY=03A6q>W{~dnOft_L?;Kb#kuGLktR~#<14|cUjUUDp9iJyhK(YZ4+& z#Auu(i1B}J(=;{&PqG4RAYcjr*u^rB67crl5^l;dW&M});7a!=b7AF&PF~iBuF3t( zh+wQU9zGpHl-r39(uF@|&te-#VHZxGMKrK4e_p`8@}Bw_cI~thty9lcQLpuT|0%Vk zpnqCGcO)Mz?dzn+5HJ9Vy9>e1PcR5}W!5hyc=}I-JBA*^w`gYjdB0(O{FZbmL z>Nni{IKgKj@9_NaVbSU6#goOFV_eA^F>s~-E4QwJ#z2<50OJc|YlQZT1I80jS#UXp zw$Ys0mU^Ch4TnUYs_9cbJGUgelv*$3GUg`#$}fpbC|&$UJ{uXuZQALh*-hp?z_#-a zS4OoM9P}L+066sv1o4(yKT{Kn8+I&t0iUJ{ff^YKd?}~hL}6nwxm6ZAR%}ccT^=L~ zi(Ip_b!0tG?fhu-LhFUCQ0a@dM)(yuY7HUMM1As_$?Ok)2Y$}b%WVbcq z7{}w3&^NS$AkuJtkTK6Yxm7W%A*k3;pIw50jJCj1xh)~vhI?qKF%`T=&=NyR<&vph zCh?zg{J^5B9q=41ERUZ$a7rM4RXy^EP9HlokYt4YcXp%J7;k(=5$`UJgcVb!dwJEh zMKyTz)=DF#&k1b@7p%L|ueQ|8s(L906OivH+s$&?Q~;XFfDN=SD$BCbp}lX z;3WVzC$b+KEyFm>^e2o|Sq?P&X*D6sU}HcHpX z5F$5ZjCQjE9#@AIacw!@5z9~*B!Fqa<`*hoD?zmXBlKVq^$*i}=Z#xaTm-(H*jh-u z(J&s2u~{OHw+dprV&QnKmNW#B0~zEJ1m@y4xQpCcCxSmz%88!5N zgLHHR_0{47X`(7#>z_Vs5N&FKe&lSTvwZN_euNfatC*j7lQIhX3Ezql?RAcHSZKv}JEIK8im zKn%FTabw-zKfyn48s2#c=^iEQXG1ryQf*XxqI4epEW; z^{16k(%b3DZaS6>+d+c_1<@@~Rw4L~Ez<3#x7_Fc7;LES)}P81n!?Xo6v&-HeQcAq z3k>v*v_XzG^&E7J$3P!StZ0$M0chz|E|D)#oBAlp!m==a5g*E@cLceW+WlGP_omF3 z$65=!X)M~$X_8BDI+i)Q|3K%lRH_TP(zGWF#z&#^ zQPu-#>6k}fTp!&TfI+2TfA_Gi2G&Li%*8s$c5Fr`C_@NkF5rx`><#AW{mIwQx|ki= z#XY-5{!>|u7kl^Y+tQsR}nlKfXAWn zy)E840$sT%{C+t5j&a%B$Gx_q<|1>xG*I)M-kT&V9Qt%JCZ4Xj9AcvX-4tjT z^v*H9q4G>qG~fE)FrC;TRjaYJoSzL$3OKEw`(01@?|e_In1baPf`DA#_10*SQv(;u zOGSkr@^3Wrl)X2}UEUx%g*tjWKwUrNjI8vtc-{(Q8ve!j^(fKBGgZjgVK**K@?hei z*DWni9dd}I&kTd!IM#=r>IOf>KpX2q8-O=IBy*@UZqDoo^7wxC_upIEn_u0Es-Cf3 zL1P0S2wc1z-g{aatUY)P$~31gsa^i=BKTpoe=~41=VhrRu77O0?cP(3i9Ipeb zyO@bbKD9BX_mYIu%qnD>#Gp^0uv8Yu)yfr1_$P(QpYQ$=5;xPOyPb%grOJAP6f#!koDFv=(8^g}`5UE0p} z-kbj(J38O^PoPX8>!|`2M)CUm_w|0@qm@>Bfk{%*EeA)&=`GmuUX zM)4BKi)3|sqW$^?f8h#5#4}dIm5w%n!VxxiJav4Qcf|Wq?3uL=-K*!nzjz;=N-+Ga z-mRv&A*BQm{W5yLpoCB;OB_=Bg(4MTWheMK*IE$UAHzW7Vo8kI%<+9X`qh7bl!*mBOf2IiwJ>%{{@LnIk@eH3GQ^!@wBFe| zZi)CfoYE)bYBp$u{JZ=9ooq|}Q_mK-!@$s4pp&t_w#$MZ_mQ4vP@)0ZX;eMieB!`G z^R4uT_Gxjbem`dV*GnxfdKw64pwB=u|b_fR`n zTvCA-x#+Em{VT3G`^;Ka`>cZQiy*UsmKx1xCb=v(}bUj_lKKUT?pzN}S= zW8g}0ItkPG2%(2wj;pZFpT(fZpraFntF_CXq(gQpZR(2EzE;(v`4xwWZbGLHf&KoL^U-El%?N4ev$S z1y<2yrcj3g9$~WDGLjvbKW@)?HU%Wm{;tW|qyDJ3GWSG7&dqg}2kC!=@e4jBIK_54 zDFy!ov2emIz>kU495L63`iQp0eOlBhHKFnB9$5 z2^SFlo%LzU`bZRcC-!BBycIccKKE(h)zHXP>%-0mHDm0xArO}Muxq)5#e#&|TwHQVJ=I`|@C+JF7%4Hda?2EMY$uS1__XtGcyl;ej4(b!uW4ZG) zk5l2`-kH{cte!*fwzA031J1k#(66;wC$W0v(RaF06~6y63panedu~S;t@nm{emzQs z%cX9353uPh(Y>xsL#kj-s#`y7#Xmoq8ms%m^8Hp2gh>#o#}LQM5R3{TqKGdWRkw%U zkR8{^#or&;nGV`To!??>UrmjFp%C<>_(ss32b)i8T8zhaH4MJurm&GF_Ra$8CP!5i z;mSFle^DI1vR4kbUFqelDKj4@WUlJ(FJliFY_-UKMF}k?16&IoErCp6=G_=l`O* z#bxfZj{*=BE)uc_3WTG2u>gd{AbdCLQ9KK4_wKRiI#!9cj|gg{8OM^j^#v?(!Su26 zv~AjIVmbynB8pXjEf}+HEP9#w%lPo-8Vd?T$Wtmb9m4YHBQ{j&fCm=*7HRfzrr*VJ zx@bEhln{3g>19T1xM@Pc6xa)-ZZR;$acI#Ntk*~ldQ1g$p~n&#$1Y7`OfFnBHHMonQPX|j(&I3d4MD%UPvA>B{nN(yG2fk zGx3`htR_anN12EZS!R;Wcq4k5#k}8Ao4x#EM?}s|ibS{)r*}NB9L&E`K`l4CGt-QE z!ZB;TB9gfdsf|Gow&gNg zIblOCjZp&gMXG?BQE}8nk@*-``zroJy-Yc4-I%BJ-cj;CvCB;Y1PcCDJxKla2m2?TOmhaL$(Ef{X9yfb%C6+)&KYJ(UG*G) zoCaX}D$@7pldv*5N3s=j<}C17N#$D`qmPYrOi41JsTrwi3R?d%v_fcBTrf^chAV3) zd^E0sVPfwYlSVszEF#I69<{Gv{!+UYocqNNqsXIe#=9am-u2+X_8{#i3r?$BUlT|5 zCaW3>o6Ry&sIQiOr|eD1(q;^M2|*pOJm4>mG%(`-%|82b1#aN&q+p{=e-7pXJmb*x zK0d4oTU-#?E>7bdnE`d1&?i^+rS3_*>cpI#mL&kDp_&uuV-;cjOsY=~Kx$3_8jUdD zK%=um>#D`TY~M$b+lS&%b9Sl1x%l`_uLm+#6MNYBkxII{%E)+dxk+->xBR z)KzEWQ(Q%e{)G=Ol|1e;Cvnm>+}*LF*PZ;B3a!SrP2Wmm2gLk~sAHApl_dJ&ZJpD7 zwF&$#3y7U@`lr_(747#QIBOUEOx0yzBl561dIoe;D-I+3@vfogdO+_MsktvhLE)RM zLFDlWF)wgNq$I9PZq<|!i6u!o<@@ze6I@&8qlatEUDyMj^O6-{qKJ zf4MTS!IbjYs-dj_>gOp8TUpI&+x~VKz@R_u%9DUdc1Ale(3@wHvs)g{IR~E>>eq6x zDJ`HOAy=GB8Cc`WqSujDrSXMxp)Jo>$V@o&H>^1qg8FF(6AEZB^^*WDzP+8be1DVe zwpsW;IZhLp_@-g?eH<8lxcxc^0o!2V%5s=uq`k<%p*O@HDih3si*r!OmdT2Cp9?x};H+_wHpurW#A`anySM9`juD}JS^|&VJW~@lX=j>M&4rhxN zLA{(cx!YBH<#j01o(--4VZq~aD*u+vqTMHI<$Q7uLg)r}#CWufxhgT7h!>f@1-q;z zEAF5#dM(8qck`$lsiYVp1ptf*l(_dw1DVjAi>l27^$(3;pkY=N*WaUX=^pSXz}!O8 zaMQq2)RZ71pBIW2!>%t%%Wy*|JoEUm)FTpFW(@BER~Q%PQrmx zT8FWg_7+S8PlD+*j@fmbgx%Ra78lZ{I>#c+6M`d{GZe4P2n1NqU;FPH602HmR+2>K zZ(O6kPPL!U5+~dI-;}cjXhH9F|2sK$U)ppGNht>!3(l*2HUiqR6%`fZi_nW>oO7j7 zpb?YGrQKMq#GkZGoHoo~&RAKH>z>4Y#O)C>M=eHFyiBYMta50<>{Ta|`=g z4gauljdoL&fkLa69>6>^0-pkM=<^hkFl55YYZK=ZhbI2DpG5d>DV^I z?XN6fEne93^1N?HS4|kF)8^&8AAQ)`I3VkLU&?L7v6iEiqN{5zZ!@e~U_5SCBbM=a zEhtW2^3^RI-)RAP+ufA^vng%-WKg>JCow*~Z>I^m|8^UQJg80lcMBEcNupclY=w+6 z&`a>P$nKn_#fH`0)!aXK_{g)+!||grla<+3kauy!`bTrYitp`fyi3!0KVH;1`uRBV zE-$|O@v>vZFW^4!hjosh?IVuRS+VUVN>^d!8a34b#J=UIi3uOz zX@Lnw=F`&40w_EXyPX*e;r6Wl8ZQ{SRWup;%zgcocDL)Z4{J*Po2$Z+mtv-r-$Ve; zfDOJ)dg=DHZ?|W3_exgrnTTJkF z>`95m`R02Y&68HAq9MbpsAk%0Lk}~EQVk_gPKhh;-a7?-%eem?Pl?$NX+8P<;2gOW zaAM626n_=pM4kqIIX6h(Ukw02vCto1#YwST4PUk>GXFTp8~0>6TnQ}qGFVn8rQ9g& zztg`c!FRftc}XDPQNx;;5rKyQ}?)4P2ar$vdF9TK6#?BO+)eLdT z|5N|^Cz>EcOZx83OGx1V5t|x;3w{M4@c$8;h8xTOFR|%cS-okwTa3L`Q^imQQY)EH zZ94lBP!AcUYu#fVc_?>lwD=doswWk&4yqh!sd-x}EDU1^GkaHWipiF69L;eS2QFoT zofn(y=AYQc<6c8C)+P@P2ta#gYr`Vx5_P2cfY~JrVO^SJO~bY?lx#0e7bSaTFXnb2 z63WJ)-MG@{@!r*~E+;U9Hw4C^!ouC;UaC?G#w27)1C56CybzYlU$$m7{Ym$tuR&T;DKrgUt-s%O>IFmp5Z6{dy?dxlx2vjHw2dZzP>z^NJj%5usX% zRMR_xc5Ed!afw&MNHZ8|<711vE19ATcbf-vZLybDY1b1}==wjTex4rwlt^7CnoGJ$ z;9PJH(kEeNG8}JzN@bs}Apii|>YA zGUl69%fZkviB~(jB7b^1XZEPrGG!!DYbWOa_dYJ<^8{(ChQ{3%2a|4(t;Z?lHEx%C zi=QX+`{XAp(`=Uu>7ia9 zm!GF*-2d7GKK}rJMSc;*Z`vl%)7J%*`SC1Khv{u#8r==@Jmb3~11FW!lN*|Bqt0W< z#(W%`GUgKZL;JgQ$8Ur#oi6Re%c2x+$KkAnmoHB~FWJA0D;cj_Tu5CSdHEvn8%2xx zd$s2F&hX-&%DH6~rDKesY^X$YU%f%Y$9LuC$&Y;)tdcHVP|j_(gdU`aM!f znS@3;QK?(SafO}`Q3EoHzoL*%ze$LGHqw4WqB1+~o2c5l3i;2k%v&37 ztYT^lic60WX(y+|-r_1c{q|tdbe|1+P_lWt@mSf*ej(r9#aXF)Mh_ey)my2%!xJd? zl96JuH5&7`MKXcu&CxCqasO{+&xU5J8wlwU;JHu#*ogC24adFtzm_Cbgbh4$=lM2e>y2pS>cu zXoPqEQ45t@M|;b0M+vw@W;WeZOwzV`(wMC=TYt63bI;xb-gh2uQJf_tj(US$$f21< zmTC?+FGW-pm^8PRn3mm?Fzc>fn19yZRn3OwwPr8=(&_TuLyr2-4RZr=t%z}9^Is3_ zFYLVRCvNMPa47U=1N!IMh3~@N@ZgDAwJq=eqM21h9j67*8G`+5&ByPnAAYIUQpl~t z*#8+fFnuX*lIn~Dyz2gd@4TU$qOm`1-~6Y6Zr{;Q2`H1esLz>7EXt?&8h?J-mh06P zzbMH(S+EjEv?w0`<(n?pX@B?Woq`emWV8T-OMj+G%$&Bki`uAJP_Sj*qso?7<#h#zc|&k(<$+EcC>LEkirU@j;dE{HNXvG0iuBUJUAhGqoU61$z|< z=isWO;s!9ZwOqp$O~BH~peIhO)`NQ`r5A`e{L+f`x;YV z>p>TCJhvY$iaPGoD0r`HLkfM%2(a)$SWTSp?2l!_Y-T^~Q|T}R3vJkF z4KgZwMaH+UX4h!QC+%k}jX+Ss>?awrMn7L`(z_KciQ9t;tNgcZH_w70k58mdijQ(t z|5lB~nF+ujmA;eyiS0Lz_n|9CJ`DUV>_C7i0RSryuEk1oOo~qh=DC?(AK#jo`_GKu zj(;HvJ1iE^eZ>iBpoxW*9Ns0?f+YTw{5aR3zJEx>3n56f!1UHDn@X+!kYBG23(J9i z5^Y_ewBIl)oN4bqN_5`mD~sWtx=Z5`#%-;csvNtg5a95FR)aQBl{5SjC>VA5&J!Ds zv(rc_d9c`B%cGim-)!LdrqO^iEmb)K6^fSf6DrXTw+%J1tBg@lh2Nfwc5u_3)04Z> z>`9!*#?9S_Oyg(XgKne!G;c@#M+0nW-ARhQciTlp`)8y^pr_tlJEQGLnF|VrDIDzy z&u>h~$1qTrhyFOR8{9O7^noNA@1~u~*EGk}JdXKf8P;SCXHX5G#?ol2Kx^UmMBfEu zQgC!Hh_`Gw-=E%V{dv#W8eXAAMSI=`zh;UMo}&73=dSJm9Gow62^m9p5i|e!nj8&L zTQ&J~`+m2)AG0lNu!;!8-ZQr4RC4wPOryYvxQABotKy zX|)UUmt7lHh_}1^!0r+}+!pQ+4>v8R6~#gu+~GvitHwLTMltCmd?G!TO1+T^Oo*dy zN`N5fsS)&)&nYnZkZ{Wf|5#&gvBijxL2lZ*OP`be#bcK^@uk!OjApRe>VT>?_j)n- z1peSeS&#Sir{x| z!l_RBiivNS=~n|ikHzx#PU8n&q&nMy9g{L@SYj>(J|GYu z{In=&dJza}Tl(@TnE$V2S{EQpgdMf~TjJ&%YqJ*CgsuAP?SilF4?dbe9W2+~ldD zSioKxX?n9q96pPWEVIjI;0~`J#xcWy1Y1tp+bMgWsgm37U33syYT+H?MF+!~`Es;x z7E*xNbdFzz;hdP@e8o$Ppp(HQ%3MKse(p`~ESP+r-OB)>cLBLme{1?2$idWs$m5+G}uyLiuyuJ(e*!$QkD35 zVb!beaSTnRRJN(39BC>`xlj<8*1KAyiso=Wj6fSm1Of?xEUKL4pYIZEzLD%m*VEf; zPO}Jcdqv^@V+<8RP>eHj@Vr2HqJ0%Wp|(Vaq=s4lu!z@&7HBWTJnX1~g2<=>O8`S7 z#7SWIrCSl{$Gn@&CQ)nB3I7-g?`eFp9}aI?%TcS(2k$ogcNadL6r;R^sJ#;nAyCiN zCRcRk<-(zr`h`TG@@Z|oo!OJkq!en&5_$q7(H{P~9`0D{PXz+kzIz4_G8q|;g~V4E z+Ep{kH-*{6P?VmJ>BA9A?h8xgKar1WGYO{pC3hdHtbtWs=Ww^qGe+ko>fUCZ9x z8Yt=sWV(3)&JchEcZ)GmfvBkEqp4l!s8K0U)Kk^HXFp~O#*+g6+Q277pFUqC`y^#w z^LCBB0$(a9yyXLTqzB}#sH+3i5CWs?8Qc|LWMx`KPw_UBgi8i`j@6muxxUCJz4+Ss z7(DGOXYd>fYGBt9I(3S1(4} z&*qwqrVu%L@D$9&4z5W$`=5+?q%OXg_?gNysl5yS~oo8bj z4JnSx^$`YxYDVepoL$<{@Hc%_ZBKy7Z4RBoN zgbgUSQ?*B}_<{#e8$_(sw`-xwqzz~Q0nRO8P#a`D3JpY5dHD0hc>j!2zRuuo7G+ZP z7p_G2df`&5dCe#+vze~pA`F!Wq;NH!d-t_#OmgtGKyM(}V&JSb_nU@&J|~VJ`P$kp zg`>+yh2`q+UYbiF4b-^NS|6Ec>YVW756bvS(# z-0%Oebyi_feeoLJ6EHL6rW=M%k#2Bi=#Xv@=>{oj{WAHWa=jPn)+kLTqYdvdy-}_Dvofc;<@N|?5diux>F6q;TT>}koK8@|oQx^bj zB|zgcBTJ{%ckHp&9HR$<6HrJmlAF@_*AQUb`_(HJc{apU;SCR8YYktEA6u@vy#Y^F+?U~S)r;^kj z^<0)T)L}2ej^9wBykaRP@ZD@@iA0L+DHw$G3Uvv^Qzj($w%YUt_!LD1R5{%&P5em= ziS`ef(d3;YsA5N;Sl?%B&&VjkNg*Uz8*jPh`y?~t+pAMDevdER1ijg46DO{=_xO^j z6=^w7I-mFaAF9bsUXwwZtA4(aWkK@yl#{S&V;pGuMd3I#+PbvYeV^VKZw0;l1I=NN zhQ3`yG_TUnAYD44d@)eiMpwv9?+@-D>g*p0zvv>nEdOxjP2=_`bQKJZ1V|81NggP? zQTs>J&qe~v{K$=k&E5i)n_${hBuNxNt3AwL6m;i!^flr+rQ|i%wERHPHe%l^@&WJq zgb%3lX&T5-G#ce74jOI2hQz@P(NEv?rmi=`kE5at`r(uRKt>U;RSb>`*p>MWJvy2L zWj_JFM-0J9uA(svig3(19zvyL8@oJx$rRE`%$m`(>ou) z*8f#RMBsZgmP6kg>GK(xH#jxNUAAkoi zXJ^BSSRo?{sk4E&39WqA0FgJp3wQU0&7pm!>R9OQR ztQ2I9BV@EzlC1WSm@yP5dnPY4h@*U(9zLg~s zWPmGP&HCXbk-;e={!F+TH=z}s{0xMq%_Q(?qFj)y;=B0We5J3g#Qm~RRnwrLslvzML+YAU5TU6yX zPRkU)7ZKV9k-r86_ov*H-aL;{K);h5!Sj79k2VvJ#9)gdvnMwonill5L1OS&e&mm| z4xgHgj82u{WW!f=>zf8EnqIt-_?Ey&eMSyw({hu z?*#XFn+#Q{`j`2X_?ZSKJXt}>`)QXs9X6<~wp2`i(c8Tqw*+7)<;MfwpDWqP%nwU% zHY`gQ9IATuzQPpsR20_&Tdy6{|X$>-4cbm^&q1fj@% z%ucnMkmxnhS)KRlNlNEtIS{0LrAhPZdKnF*e^B{o#oyqT9B)(?&xMl`W8(A|_3NK! zhLL1>pHewO1_5ZmoX%XtFAv!}8Y=xfcKBUt zc^=#G3`>O;F?oE?%{&MCsdQy@`emFGRb)s6w6f9$#0x6St9ZgC2e%P^KLe` zczFTGaFDUA-wbhvtT`frxl5lU4)vMVEiGBfw#*zx{=DOo7f^6#jblgP6GRj4@)CBr z83uv`aGqf7V{TXZqIw>G`miz`i%N{puw|ZH2Lru|46n@Uz|-?VL=M?t^r_ecRwp(- zJX46w)tUwHESw5!n@D7%p^o^H&Bc9zz8#vphSmE@#9C;uYob_j8Qvf>^D`n+*G1N9 zf*}_D$@Ed`5}w|QaVG|lqxf}mu-yZ+aNkX3IJeZ+(yG-s#fG$;L-MD0jY^j21@t{{ zOWbWK;DEOWNh#UAFbk^l~u`j!{YINO}j?ciwOnLf2T19$yHS)brLVf$n1 zv?QR=dBb%aBYDgt2*9Q=N=2a_Fsr_%CAX%!ibaQ&QHf7=KTAqNIRy#PJ1X?=E9*@D zTX0%gpp{W0#u9Bc%-WmN1U`Rt33A|@&fjgnJ@Ct_0C$SZTyUJtW&eaZpT35=d7>Pm zMdVbbpc@27?^QrD^R6#`_%W*Bet%@jI5=LuEF{5Yx;4b!wizh zGGqzwoNJPVIeo$W+J`4-6i8p1h}Ey9vTF0vevKKxdEZ!louE?tOZJfsJE#L(^QQmlx<^O9~lwUGg2;+2UpTyE@N3J<8NI zFs%IB_5yF$?g*ARkEyRE{QA*Ad#vT$ng`cpph%|l_h^zCdEJv1;yxGjobi`!ojFW#Nk(6Vj zN2kWq{+!V^s>!U~9Pvqn9^Vsm>*Gpeo6r+e&m*bKeS!Xup>Zt?L}cpJr< zOV$m3Af`&Hy|s56@IP3*@=;DPEn57DY(1;A_%WA;SGCix-Ey=1Z6m&SRnpOU>` zg8V58$7if*fpW{)Vq_w%8BM$t+}FRufEz-&Qp|*@IaOc|SFoyjnw4vFmOf!U(34y+ zQ}%FBFCE}3eL|$ZV2n>OX{MS4Wu${k}iNcGp)g) zujJYBvYsT0rWBitgFmGQ2%ZmZoGAXL&`g$fFiLW=`P5bhsS%jjr_3m1TPPp-TtRWG zCRlO2YkkQV>cOU%KR@#br=3(su@#o(sa@Rhk2LR*7+Axt(lG=<36hmNBR zl@#~hpx!Mck&#uinUMNku*Z1tYdw%vj89-56@TT`3;RgD~`LMU_##3eQV zOnF&H)Trd`MPv0;kS;1(uP2ge|`MwSGNluR%bqYpE~wl1JJ1?IJUbxizUV-m=0$y zTs%_`)KltJ8;E1B{Y2)sHg3LCNCt4Bf|Xqc`YC!d$j@Lms*$(tcdTu@#eR|hxw+OuM=YZXv6#85RE%zIsW~lX{CB^Er#kVP z4aAcC)mxc15fLL`JZXWa0ps}cBcP zT=+9lbwDQr8b2M!u7JXGDU_Fv{oM+6q$D>e^{8f}$}3&)<3YI4WKoGN%u6A{t#fjd zQ@x|{?gsLC>j?b=3bnr}sICoE;AzJPW#S7NWPmR&@DJ8JE~$Qi>J1SjsnWVk6Y5Cb z!jRt+or*J3$$EKDL&bJtwvb*;;?RtCfNo%IEI9^(PC~KqHSYeBtMleIoDhG58LLpF z-Cza{Cz4ApWVqN`!<3LWE@EGqED(^r8e)os4Cv3Cq(W0VgR4`Y=Tt3mlo2IHFpmAl zBLrMPPU4ahe#IP=k#hqXSNT6}$BC(Y4LyU= zv~W6xo+`1C6qf>$tx2RYoZZD`oO7L+QK+Y8mTJb9QC~)G?W=sX5MJuXNmU!mdmA|p zllyEAT2CmAkIxqN%ed+lF|FbkH;9j#;kKAbc^UEEt;P?vLtK9hFA)$!%ea1B%BOYt zOZa|kjPF>B83pzNDzd9dxLT+oaVGqVpTua|yHFSN!Us7to^hz^+Ag)|jlj^$=LJAb)FeYJ?UZSP_}mi&p(d5V$W3gL7l zFDVRU(bqssYl=X2gM*m*M%1DpF-RUp7Yy2PdzDN-#Lmm%p8q1h$ z*bZx~MRHj4Tiey7GFd|{$C2*((gY#%^bO=5H_a0p)}s*-qP{^%z#_S#d^Z0?_TR}y z%?+xw+%(UJxu;d5)va4FG6=U{t>P_%(_8Xo? zN^gJw>&dzSOH+f(YfAv$>}$Tc~= zcujH_skICJxUz@R7~yYq)9WLz3CtGWo5t;HW5u;x^onkMk{?(U9maepz*3S;VNI=Z zt)6ecZ&ayx7BQ6w%kCQ92^{Ucpec zql0ysC)9?p3jHxzlQ*AEcUHIHXo((7_sEGgT&45fU+B;DbmcJIZFUGH)u8UouW+!U zQ}Rwqu|=IHnDdhCgd6lfddkvI zTk{Imk>qH}6jaSGQ@L!|?^R;Z3h~mLl`Qg;_}zP(YLybJ#@?qX{o#M5)8-zBDZP{b zreG*1IU-G$KRdfkm})xAEvS)y!^uZBIa{)NT?zRnc0__~LE^YVASD51mwreBd-e7Y zXHu}XUMk_{u|nLIrr5fC`9kQeSk{Ewit+kh1d;J2-sX|kZZ(botl3$b7AbX=R3yOu$v zZuDRX%*C0~CTWO$zB);K{B>ZIo*5_&|NL$Nr6Uy#U}6dTe(y#p&PiLoYvpvVv`ZdT zu-`i2&u+@BrA&Kl^-`KE+p>U9Zou2nnz74J@{r>1IJMjuK6XR*uW_s)(kh=AFWQLI zLjbN(UkS)BNO3{MyPs?kNU?_iMr~ywc6`b$Byaco|66D zPlbA@5iqfv;-PV;->_MfSD`Te-ythyDP}ujra$~-6pe&lW^iiR_`cL0KAc{fU3B-Q zD0Dp@kDvOMakg7h;@sGA$?VnaU=nKsLLj|U`TaX=HtK+}rR&S_kKQy%ztg2p#Pl4h zROPwkDZ|6aJ#p{8lWSejelv^i%DuM+v3u2UPnfdUJ)EX$hD80)1T%#qz_(l4M_`!6w8e+O591qC>vxz08GzQGS^gT zM)WgEj?PMbXp5SFLB^)stwz09Y+=U2*D|A@=KKs6d55Gm@Y_n6$oDOwUwUsR^232w z?9JsDW+#Y6BOdc3F+>fH$OHD-=j%*JhV#=EIuspq8e0ubFg9>wB=D@9?WL*nycn$4iOsbLwl}y)rl0jBDfrc&0 ze2pH@ZG5@aKY-gJV-*sBNp#1KB~RySGs_-(bnt*|MP=y5)s6Mn47WWzoiFWpGZFpVxJ10qX{d0Up&fms;R zPe4r!+`@6k#T05`STu9)mIRXaCj!M1P~<8;fCp)K7sDMcmu6M&m4l*3aN{c1fzFy#|tjCGFK! zu0pMZh%Xjaw*c43vM2luiKY%FO<5m276Yx#iE<+~w{ZM}T~CVS2Xwi;aCnQ{ zH1jt1_g3*_!-?qU_;WOlW)>lAPj$2QT_xRzZ>|A)JRXiuZh+A9;(V(8pI!)5#Zyqm}vOM84;c z3J%54h6pLF;DZ3U9?vK(s26OFEaq9HeN}Fn?O&Vsn5+u}<2h|qm$3#V$=S+1Mo7jr zDx5+Wd(gOSsM!eaBE~8Pes^b*ANIHG*oBcy6ZYtbL!#i+d8tYT@x8Nl`)c*WagkM^ zzUT^8T8~-kwnSAXvITYy32b;2=%P@Wb;$r3iLi=4FOv zOpOZeYOwBNx8X}S<8iOIp%~mRbVJIMp8ATD#$vC@w`#!q7x|Z~4F-v=E9&1}UXkiEIH?2s}JCd{{l1J|~gUwcPERcjh?m zS5W6WjXUTlR8qFu6=YZGbKquRg;!q-l&J_ z0N@v5*We_Sa!3WB7dD+appKPUt%4e5ca`0RF@XV9l zsbF1c)>ZC+Pl&t8LAjBGVSQ{nC;ogoc=HOaD6{0p{zG|5r+bcpN&3UzcO=9Qs>~j3 zIJd#gb@63b^ueisjxkJ$J_ix6V9v(1Zc~w+OKx-=Y4OkcM}=w@f{*hQ&ovwKYGo-k zT#aHFbfvK6uxeGD4<|1pap4St_dQ#9S?DpSR-So ziVe{mP1!fCm({FK9-z+*#zCKtq;38rPp|y-9#S_J!BpABh-p`M`)FyJEine4Lf=}! z5;@uvO$NS{pZ!irIB4dYzpFnKvSxX19TMMgt1i-{cVW%6X!uDY47KZ#rjyYrLg!*s zIj)fxlR0p6-n&!=rO|akW4NN(PDPpiM2bW>kUmeJaYu+!$Au%WA?x1R4l{Xkws?a- z16)*zP5GThyYq$6p1FXysE)q_&by3+pn`uQAl-(;uu%@Yq>&nq&46*8t zz9l6Ikyxa&yyZQF?+?2BKoxs;Q*bCJ`PzSnL5u%J3ny1P2NL_0cWAzn7ItWem>M+I zMP}bs(5G}w3F-0^^sAVNn||2Gt}b>Nq(3GSd3=^GD8dr#mRRzq%3PK|ZTT9_bQ?aJ zMlxP*p6q54Vvn11eq2{_L8DmKO7O;=XRAKU+W7|sG}|cgTu#L9c5YH~mOL~x;3hozln|9;`~6pekKLJH)5k3nPa2p$ zg~n05-+b@fiA4z1diB<(tgB{RL^H{|kCDZa6>Zt2Na{Q2S%IJs9m8!co}Zo#@s>jy zPrg}L=?mG!4PxA};G0FJ+dc~B2-g__w@IQZJ>HYeRK{U6fF8Tc)D^z$qMBC%a8WeRHFkj%&Dp^wXwzr} zisF&!7G*pVJ+zf)I?YJAk0JM;yX^Yf0~PmhV87rIefUgC7MQ@&CNM; zdyAhbx|#9zW+x<5@sjOwGZ8#Wj8%w>oFBovZkqR&nKrYw-(sVeKmo3^2E(Q8`R}Z! zxjZ{dLRAVwhu4$K%I99#g$OyF>uz7(n-7x7WelV-j@IC6FN@eOXAFFYiFsr?jG>{= zb9dwX>ttIQf3x1WnB&DZwSTEo@1n^*mn|xeIxx}LWczusRic+sVE8+8W=Gr>K#6wb za>)M1zA=D`yGY|U6)VMrKscgF-9pmfhK`jikLF6&O`51sT4U%rZppw3I#yCT+cqmhM6l$Lw5i&t}YqgQWPJHGaH=Q#Wt4f!r*AQ$Qe2 zfakGkZ~s>BB~Xik=UQ_)I67s;k`=B>kOj|5AAx>n3&OsoBol=9}?*@y4jWSn$@S2xt5SO9C#E z)EN2DV~d8?mWOw8_RsMa)#!XagUi2aQWSDi1)6Dhz{dOYmV=m1Qb`cG!}qQ& zQktzjUmE#ZXJ0&A!96|cCPRE{K3n@cc-9tMU-|Xg+h*o~3g^g+yFAh@aqj;{bo%;r z^h}cOUcy`FRxsU6w+mgloY&=?+3E|1dB(@`kQ(B#8p27SUn}KrjWH@MR_lAq2=|Td zXbYG7q^S_VopzH3`;HR;GO@Qa;2YcF0_5RO=-rG)R;xVqSfaeh5%YLv{Cv7Gbo&c?t3t=u+-Vi0{az$qgb ze86S90cV-9G7Xxbk{Qzu)$@b6CltGD@uSe)Xu%|pwpA@(D8RA$B$75xDmvk^>;X&q z^dN^OX}}l+B?O3h#2h?|h<6^=5xm<6Q0;rhnlB{qj6G1&6}gw5;Jz=clmjY2$=+US z2t-$V7+BnFtTv6YFn&AS%@1b@VG^A6OeOQg4|-mu+mdFOR(gRI1tD_#wRrb=UlPqC zcS^klOu}T1sJO7{{;;)9ymRZ#WW7%&W!$FL4z#pp!Bn2*R5;2dPh4?LLEmeFxb|>$ zg>2A5F`2N5@qsXdaH1YBaJphGQLbk* zhTqhaY1EGnS%)83FNv6L)IOrsP@p($Dpglt7S*8;t-0`SlB;{JCfcf1*J>!*W?9$f zAlmL;*X}Rc5n9)AU$ir!t}|Vuib`XV|v>$~7CHcQqpVtce?d$jP~ck%7v;>Y?KTfgPm zdg++snFHT3@8gwO(YgD_BcTK-zT?+<4f4Imt5Fres3o0RN~avTl`iT{g&VQ z&a*bm@c7M#swdK(6 za<#g`c*BIV`U$Q2XlcXe+B&8DdeJi95r=0A?9Wt&2|pt5d>QrqbpQBbr(VhTW5S&f!$(&}wq9!ha3Y3PX~_0GQFGw1Uf>Rof%Q)-y#HpV!Vu z)IDD%r*SHYLj#d86)u>tl^C#fbR%r&=gAi}^}}E3(zAL2BYj^bDPW?$=heNzlejy} za?cdCTiY8Ol*SsjdHfV!O6xy9ny-}+zagW0$48}CTw4F+g6uk3%5%7xUjy#kKwb3I z@Obk{!IJ~}!! zJXuzHCSTlQr7b<}aQv?J`8?;9@TtkZ?whT4u=UIH?LNPq$$F(%N7UCPjNi4jhJIEw z50Hv$YVAAPvFfc6vbuLleT zd5Oz8=09+5Q<9DLRQw;II`%lBu~aSIaR!5~7A&tez+MnZdv&u@a!vkT%|#%J@N`=w zVXAG*ZocUor!HzsYkAdbZ}#3%M)O8zy4`!ubc^YuX;_r^6>MC={A~!+*98BNYL~5$ z?9qE`osn~+?E1x*;u{xrU%yg5GS_tYCKh$BG*$!{{ny;j2xSwLyQ$i}{U`e_lY&rp+`5_@xVY<)6aE#?bn7nHKc=_Q{H&Ur-T>n+ z3aBoF@}`!Sec6e#Ry}jTdfBwO*eW>WyotUjh~Y|P*E8o%)S|k(YZVvq)Xx5Qk_VT4 zmT(R$_WIlK_ZTTs6k|r=UxxBP*JPVa4Y*BsMv;Ed2W~8m=E*FXw=U60O2o zb<~Av9`)9xW(F~;8X6-gpCD|UCQVz32GW$y_c3vRaSdl~=&!hRK*Gl^PMaCwXL;*CYF76uZ~EZ;00hbKLH8TROV>^;X+O!?DSCjGC)F}axishFAWU&1U~a41D+G&RZ7sU{QMQ%;p>%9? zMk92&$e2H_i2_wg0p0pC<;thb{k)Kq?b`N?TC0hxJ|3mai+E)sL_ox97)LquC; zEnj}K&P3?ml+_Ve$La8qbd@KvK_#jBr}x~xKX#XYmiTo*m9D-fXtgEcT@j+BoiAlD zbIP{v`%T|fdz$?f=%?QM>@C<7alWM2S)KJg*c3LtuMxR-wgQq$|O zXDX$aGLpLa%e|q|OJRmfVIFOMbhI={w}=7a;Iw17DiM4ZA5QhlCcZH2bM%@g2_;zjrNJT|{SMF}DlD}m zxC9Wy5iOlfs^Zr%zKryd3gADQVT3VemL^0)j#uP)j0X!kXc$l>(1U;gb^_Y$mEmnk znoR4P->zle9K?h2|Bz)iBBql;k)x$~_hPwc&Z-)ZKH)Aevl4?yT&ma42k`iVZ0b!h z*=W))s6T810Fgxpf3c-XZTgBPIZ@87TiZ#62e}tn#!edaTu!myU5D2OB&)?lIyYzR zrRT^m2p!`YLaO>T`>C-OM9MBquO2j%-ZlKvjwfM0cBv;Sal4 zRoL0&FnR@idy$k=S727P;U*MG>*`8uSr!!GUedaUV;JD6C9^`lTwgwo4>Ay8r+eL5 z@Ry4FR}YH5R?j$&6N`wXaF1*JHO8Zr6aL>eUNhp9h3C>CK}2NRfR{1|#&l%KBbbX; z9&^^+ww}IGwc*&=F7xol$YhD^3t_<2xQ2;gCGKms3EwmVAZggS2hWTbi&-9A*Ud`^ zZhgcCrFruZ<(f!35F4#obme>=r$eOXDE zlNB><&B|#)JY32by`q~71AOR$LT6L7Vwy=~kj0?o{T)|Wre@P>qRo9;4ccIPdrB1k znIwn{Jidu!EW^y@c|rf_6Xr<+=M_ZSO)v zRgDL@cnZVQzd@v#yO%#q)xn5JX3{3N(zUI%#|E5`+P?L}@mX(dtGTJKMsdWO@O2vs zkP1j`OCT2hFdv-Mrk*Ch{`sYg%$ilB8URE9f#$<|WPDVz@bxkJj$0rb z=zAO=3znkcLK;|Avt zguj8MB+w_b*85;~;V&r=kU=7n9*K)RH`l5qcK3aN)SGCypd0poVC<1Ym{UBp!)pQ> zq)k*%P``Y3*}Y5e)g>>0do)(_VTTpm`S2Ep1xeVCT+nIz_eZ^y2Q$8UFw=NGjwi8RcG3O_W3D#FXc#yw zi$#xFKq0JJ=-Ajj7P=9|RvKnRAS?#~JU{?~ThNWM*x)Lt>*tl0&n89n1{fGmgI?J&mD``Nf%yPp^Y*=2IA z@>6xOv$WJz6apnL6?B)w{N)3n*{eDtWnR}i`SW)Dx#pocGGJXfUwQC-&c`wctP(O% zh^Q`fotEst3?*iMy#b)GQy{CH`|l4T0mhBY!o>74B3uNK7muT&B}nlSq#iL~;CTW< zQrb>JI?$8GLe^7d1wZ={b}v8L!6M9P&X$WgRxk{sGAPV=CMM@eQ0>3BXBm;RPaxS& z7o~C1c4mzx326-U?sE#cW(o!}`be0P?Y|fO6$&=Zk+rY>_jn6=RU1x1gO1}qu2)%? zvM9Q%0KZOVU|AGn1gT3*Dr_L?b8cu~hx)5d5&>b?pCjO%4rAp}7Zo|z*%jY{fy8K{ zwzm5g$ z35|H|<=fHu$XCr*e+05+H{Lri7pXvI68Erd0R< z;yxJDF9dc!OdT5~p?sK1G9LpnlbAG-T$PG~R`Zd~E^2XEcjOJeyMfgFLH9eO@4XiL zkI&@Q>+Be9H)Uy+CHV*=o19NN5tgCQPYOw@CJ_&j1o82E1^bE_=Z<{k+&Afz%9umG z&&PGogI~_$pv|{3nv%atIh4=c2he12EEyRJ=-5a8eTbx(@PX^ZK)F*lbU_bve!^u9 z$jg#-#d4Q+(bfkFf^|Uaez-C42=_7Tnl3mThYw?lZWyt6+v)1g8;ji5Na!G}Sml(O z>(bbku8Fm_fUY#kGrv32xw;N{U-B-qy)+znH*O-N8!MIVNkyb?%Gso z&;&;ez{S?ogPB|hUi-#{XTzJbfB)20rSpOgv2R*3Ed0nJkxU|+&oOf%Z0y~m79ogd z5Ykrf$tKcW#|AUgmRCsSmF4s6dV=iCi@1d_^=0d4?rUxJi1;;MyD>fI5O`ZX#jy!3N!X*vopm~$~r&U*H%)>cmi zKnE4-s!)FjYiN74vcuFLDKW$C*m@V76IYP8W97JDQNPGBS}YuD!pC@ z2zb?!dxDe-pgzXfPq35`iFL3Bsiq^WZLA~zeTxsukXndb5#0sO1BHM z!|Gdfi>`S#tO>T5>(Vfr@EF=j&Sa1o^|4{i_Yk?j;OUMfy6Kcm)U*#*u}XU67w zs?NQA{t z(6S|I<`5LyX=z0TQ!}E7u=s?a;ucbM1PwLy<^1zf+b(i$q#LHyL#P#(oIuNDTYVLE z4rnrN>&Bt0IKsM_i57_MHq^k&LMLJZQbz=tORdCEMicyrm_xf|e#WjjYv`-&c6 zOu1+!vVk|s|0zD$2d5UD>>n5$mx3Rtf=PLO;z^1U{TbrGfW3QF@3k`~jW5f{vIR?i zk*MfB+an($3-tBrNbtya$r#GFyF^=jVe_oJB6~)+alQ^jmfKPW!e121=~6gC?7hmH zO?25uR3ROYRU-1;d+j$yU;_dV5asg3^8d&?OTuU>v1T7hX*yyRR>>>YmtRy_p?P`R0ZbLga1+r9OBt$ znkQTsCdm(Do!+p|95fdPx)pB|n0!ELb}J*gDdd2mTQLJi4722qd*$foK1sKFpwmZ! zW1NuI^rk_jL&R+WxNVFq5$TJGCXKTJ$36yljb#SXH+@tDgLFuF8Y-=uDuctDtOMHK z__lrT63bHoTgey6Agt<_@O#1QWiQEl1^Z`nt?H|y-4+W$-l>*ACEZRI-HUp<${fhw zX=cU{^T50piK6jFt47FUn%v39N_EeLj}RgTAf_k^!JV(epluoxLn)ah4J-JJs(S9- zW}-Yy3DG#1SEnM6%}@0M?H0K&SOgFq@Ai5`fL^%MZ0S6mt#1+-4RW(RKs#aULI+4B zP0uQ(Zt*<-OHZc3KTSVRsn|28W;cCf{khZTl{d!7XCt6Fdtz>U5y`B~s5u|w{nAt2|?M6L+FOXGNu!pHmPVZ>9SR4m> zM$EyPXng=+rw##`MYu16(AmY1Ya-9vk|XI|@M zc&y9rhEGMHWFLCdi-FsN2}P6X6pqKK<}aE=c=xOPJZ(>C8_qtq;>)GI^;8?+wVh{ z@{NDB)?9WkG#}T#i(V%`D+s&hM`|)VZek}NGn>B8@@bK5o}ymucUrMX2KOVQ;vw|CEf-V~G1 zs7h+zPeS|S=yx}0g04#ZS9v5{C#hS-fq2A$=+XY@JMp97lDE)VuSnyZ<-Y2MSu^ww zIUwT*UX_ZGCJ+ka18DOHl0d?I$-%+W726;=X&%B+28BK_{M)JLQ}AM@X01zWhXeAK zym^`Cc#hQMXyomYOTb%f;d}D=(3^*qI_XvL0r=*u@#a5p6S??VQbOkV2D#Y1nLyaB zOEoAL8kD^aj>Ui^O#r$HdNI2?Bucx>`>Mm>=}-}~;P3L*w^MB=krwYynIUIT?mcs^ zw>vX6w*&UVXKU2ST4f!E$eLRlC>I(I@|#&-lLTg)i+pK|)R-O1mOCc$&gD3h^)4lz zK+jH~G*AXS^n&vodqZ`uWGPBS=}04(<eH7!vIll=V zK;8j>J59)xex%vw&CO$kk1?rF#y9)RLHPU;w)@BhO`?1fGk-Fa{Il}#XRDrGn~BIv zR?kOVKW?aPb?cCB6qH}&=AF<)(cW?xyN(7QVkn^7WQ~qw@NF`Z0e}?$x#hBE^k6(a z(zYWrthek!=9~3Xx$*Eo!obd%j5kH`nDFyN<%~dsD~Bg-#T8oe`ma;~OaUnPI^C~Y zF}MGq`K%N4SpW|(om+XA5#?qRfeYqOwj*y%(G7QNY z9ZWyKdaC?rt=UVq6g`E%lHqYE<)pzKGX#xbzojT-n--oL0kjX@>{mdX48TmOf^@uD zPPpAi|I75r^uug$3=^%8kU}qPR|!~e{trjz{Z94!$MLu0;GAO}$KL0d2glyCb2#=o z_6Qv_q_Pq|D(5&jRvmj*_EtzGsqDQ&h(bt2lBDVD`d-)l7u-L+?$`Z%J|281^K7uO zij6h_a>|1uKssjmva792)Pi_6ryreUR=AsnFm!#Wy+mGt6bYCKcO-9mjE@LI^2=Zc zQ*`auESvS*D3XqG>TlJXVml;{5o28k_%|d9i2mT{I`J03*x>hyAdxB2(%&a%nUl?z z64FZIc{bK+$aq*mQ~47gh?>M~_@ET5KCG9kwl9#&=M`p#Dq0H)SW%hH=pd7~z|>{r zihBo#>D{P9x@ULE^r^{3)IUK;5gX(PIwNNtS4Z-~4sppg=?sZ-Ql3%;q2h;p`M51M=xKSjqBF+DB5mK*snccTNuf9S3lX^ zeb^1!u=PmdGJcGKa9FsgkffR-dnnj`wO$TWaC{nKbZDDp&atw-B7>MthSKtgx%F>D zUyoNUd!z=L-W@Syt68Ul0Sl3i9lCfCjVm^CNm+*^O14NhrC!e_V2JI0yny%O7vdFL zw+FLwudTif72To#Gv#onUSZQn@%-KAC3ngU`&skLEZFXDe2U;z-(ZDEr=2$1kD@DC zE}g?Vm{lO$R9WNYC(QO{^Hs#4fC^*k_^R^-9}x3$vnyZxa?fMt0!O+15$j$NOoc zqbjzm$n#_!t+j1ZN0USrmg!T&!!Es`BBXga&llwkz96-p;blokx_ak+TNw!{5ZI?e z5TBbRVSK0(Jm-osopK>rVFSX~&YL?Y#l`zbQv##eEY={PC(mfyIVG+G8q!n-N*r6{ zOsa$Lki95dWtG9i;ao`%CvVc{#Hh!Q?s$WZ;A_fKcG*hr%5#`b<4rs-+vh4n<`MR& z$@l>;IRU{%`|NU3GdfO*ESRyZLHjn&dbL#rY8m1v{_<0oGe^ROzqF%D;N2HVjj{`F zt^;s)0LlK(f#0cZ7WddMEfDNxxl5U+(+aawsPG*ECHOqgJ~CJ8OzYdHJZ-Z8`yl&! z%Q^YWJK^Qt9D%iC-|Crw2G?4Ll8!eo&_3n=`EP{$jUDGP10k|#I0-vfayOZ%l;Dk% zjNC0t5A_w#j?20c_k5Z&YF$V`X*!}dE^C#*fXygrOqDJ(lvVrD(8$t^IVbme+=518 z`(uAGrcRh|n9C~Q@dU=Pd&T_t0AYAC$a$jxW=WVhrg7|0GnVwfSnbIWQ%E|6E_OxqWL^g1(iwL7><_g{^07H%sm8 zzd-s_N66 zT18ErdTv})mIayTYbm|m2(%=!{SOCNTQSAh=^KE`f()9(AMgLk#FBAn> z8=PTpN{k^b!8_e&Tx8+oiy#H&lK4 z*7MJO1YbvH$XUv+3b;_PKO_o}1D=CAbM|gQ=~1TePX?NpmXWgkahk$bI=T@gd(y zt>?sQHj?Q#^!2F)AI-b*gAalP8KrlznA$wq5iD|KHyR zx`#Nb-yW&?8bE@lz2s>*h49mhwLehT-Puw5l(l?Iu{n?IpG5z)actDo+jkl%r3_B~ zve&Y_CBj_Ab4nXbEWCs%T9L>RrLS0%1MSjo^U8YW?7IO^^YEHmp-oitSSC&3F|jZ&f1C#&C;iC_uU#`ZL+iOEz| z6Y97LmE9-Hq6#}~E~t?8Aj;4?m%bDN6a>m1>iGafL;jvKHhpwlztYPTZv+tT0AxgVzJXw;v_zd4RCPh}ZxJE&1mm#Q?(0#p)c(lEsI?0i?8wYD zusr-KP%2i55ob+VXmx0T@O+})j?Uy=)92UL%_-$@3pz{1x37-0M`YF$iD)2DfgDfz zjbJa3J9o-~d9`cbIpE5!hIl$s+!>&gqPcOqH=DVXRv4TL)~?6oTGZiY8}WRJ!g1$* z$Fk&=6`6Eb47-Z_E6>^fNlrLnQ9y$~^D8NI<)@wCWgKa4kIERc1%-x-R}LN{!$n2g zxrNc?1=RlRA?U+c=ne=76r@^4pBb4`L}^*S=>cGb?eP2^5rQ5s9`cq$vr|^Hd&Ef2 zg8BYiX8uTR$_eKsfqND-aGnZ2ME2h0bwLkAJ8T-mrkNN_NMWwN3A`=y6d-`Y%@Z%yT9j$6f0q8tuvSPk<<_Yu#w^j=+H{v7D`H)^Uhv?Mv zNsmJ4=jhLTqAJ*qR%>td89wU$IO!@eYSlUfST)V8l>ny~r;cU{AJDyv6@|{GxMGIt zB*xtxVJ}Hq08;Ox5f#b@Q5Ay30P(U&J#=O_x9e^06O9r(+S{1UNXxWSlk5Rae(?-| z4jx#&EM)%9Tt-l+V=TdjOqB`OQ^{2}%>c%v($eGQq|dH-O6l>ZpA`$f)TRIAuiF>L zc8sk!&{9S-5{{bO%Z%TL>lT;VQc8{gQlJ^|WaI7$sa2tn&l+#avfCPwh0oAIv%T5a zyw9}mHlQPCZG~F=(2?H^SvDHU zuPv)8$!z=9B)rPH*3kSUt-pwBJAEXpY^56nNxFuodX@;03&{ChbQDN8_d>z+np~kF zW+;NSy{(g1u%k*jeckRA7D>UCPgtZEU`hy5ua6k@&NbO>(sB}Zkv{a%^7bW&*3 zl0)V7@Qg=qU*EJaUOWH%ofdhz)7Cx5qIIcQ?2shX)W?xFj;#mH`9WxIbQa^|`Vv&X zjVHA@%{##?I7{V~vD;Wa%DEPtVTjD+`M#_|4WuLdet2s1p9yO^dWCKA-Je{E|4E}G zSu+W_{POqzM5YMGgVrwb8CRtUjZgkbKl2Xt{}O@%fO-ZsQR*A^V@HFS{#nPPkS5WV z?l||X-2_0M`|`YWL`>(B3fvHV@0i}js-Q|8T*fYJD4jMRC~1{Ypo7i2r|r*zHN%Mj41Bmo{2__B^@?T?g3o279e3)48d zC1hUtMK;pFiwZJsRoTq#RyN_1)KOomqcKE0TQO9f;U7O_Mt4wphpf2`Dtr9qBQ8M} zl0cHHkr1jcThjSvRau!;L-L=zrRMrnyTC8k7S){MGe??`C{KPdNlJ&3Kfjj2CV1%O zJ8q9K)4NqgYg63W{q*(+u6Cwwq}GiKowwt+MTyChNHl(>tiZIe+OHa$n;bK(%G zS*nMzUz~W{B;m?b4{b~B_^aOm2{nTZ+09Z?{-|| zE_^O{^3?=QpKvGs`JB2K!f} zg%(h}005*}y|vV`&rsq?`y&Nl>6$_@%X?-V5)~q@w=>+>M5dnT{2JHo99XS_!JcBEru`cB;YWV5{Lfu$mh$DFuygR92~TK%hW{lEg~`yUav2I(nN z`u4roU0FITbDOpEXSM!H7tfNz)>H9-T`tX_ z{LzyBD$|_uZRl`$^i<*ZHdr-mql&;PMJ;0Ra1(=M)5Wt1Lv&qx6|ZpZ&OwwQ39>*! zG)5YemOpTr73|PFl>S&LBGdWV7=P7=G>&qzz3ayLdBNc&5@d=5AyTO03m9g2B^{!9 zW%+aNS#5tWP;>8qJ8xz7wuD!wcHf9V$Ap|tMl@M4PsS>~;jVwW?QNFR4CjVga(3Wy zwZCDU2Zz01^HKj8$v;)X`*+O&VU*7vUQ;GmfWjD z#H*e0@cwcRC9l&!F^l){%Uh(B?YN@)%sl0bj2q@BK=>|jPzVU}$Qdv~M z2Od)9NQr-1F;=Q7RpdCs5z(9W{6n$x%$zZ|PfYr)sN20UZ~gw2d_2hViyR%u>hw?9 z!NeE^RKgnLL6?qOj(5@u+j9%I0}9uDtQgmRwg+{i9HL(RTZ z?4L49sTkWydBFB0-Qenvw;KiEY03Yf`+DvwYtAx!(E}bR znk;XMvgqM4YwO@p6edh`FuU%0! zS;fnbdPplxk3RT+Jy`bMY+6CEb6%3OB*1|sXnTM7N*u8io?570bP%z4NRLyTJbyO( z(xa#+vHdQyP=`ZQ(STU4cHvOV#{6-$Cs;k}c6#={;;)za*o!Q8YG2TWRDR(vAempN ziqm@cq57VbbF$kbflZ4yfe+A#7WQ~a@d;}*9skF`+n0^LccL{9MveTQ&6EP9lz{8x zF4z|%pEp#fcF$CZPL7t+Rk4vk(Plw(?e~bnmn{Q+_g;MCy;UxmJwL=Zoo(WsbV54S z+9YEyeo75|Ji9=aq{*6qpyoclyxkIVeq^Ll3bH-w%1DO!m&e*y(k-z@l=!6VP;`(M zM0ZrO3CaH`_U)GI;;xC*K*b&N?6#=;ftom*@~ie$qLA2Rwhc+J0r5K?Lb(jna4 z{B%^LG$8BjeVkUsi@X24oICKBF%)c2K*1I~Y^X^|m!b;8qpyqz-5aNugL`=0`MS0L zN7n3xfb^!si+q{*-M@L4KrCd-tRRb`PmeEBs|nmWrnza)rxQI@eXK)m7W3Wd){7&JmhK_y7LzGVUzHC#(ZN zl+kb)KsDqMYeYAvbh+}dXZhlrd!Y!FDd5^-xN3g37ENEJBZAEVVMjJSjtFr8E{#oJ z9sWifE07?pHf}RwOR*qnh9Wg+>K$o2QP2S$gHK<%`%|_Y@dFN5Af|5}|C+&@Pc5(q zfY1-fcZ*(t+$>b#1$dk6%Re(96D==L>OZtQaIpLX>q5ymMzr~1}nk%sdPVb zPncUuWj!O`tJ~hzGVj<(;Z}AKFOeZ!w4oru?eYo)Si)$U&=a=lqOjm8+x^!VPNZK|!zvff-SV??u@|RWOwEq^EBbwlC1jDIp9uIPPJkSkZ7EmfTx=y>0%Tb~T48)`L%(7oXsDT@VR-+FR6m!)AZw+N zv+H&|gL5rU;&3G3VG573MH~r71D#8WZs3+&k*2n#U|!turxET8adgeb##YqD0B>+h z%8swD7T-pMM>o)Q??3lG{>XSSi_`TA&ZrK18JvLuNqD+&2} z&ZpdS$6|JQ1MLh`W-HO+hRt1uso2UcF+!-_Z=M5OjKuAey@yHi$Ji_KR`59bxof*O zqQC!Y@B*c1YXUtwce0B-?2d|CC%h76+rW22IGEMon=jUZgXW$S>914tRyXU9An!PQ*nDHWB*(yMl!&+wN6kq=}>(hS=kB*d-Km;c5-*HCH0M_aJdmt}^9OHlvuhl>BLUvasT ztmSGAEF3#pc6R z(aqv~cA%%y5o>cM>smB)2r1@Th={Moe8E8JflAF1t`#%WQ_e+)nt@X#mCEQ`xT-W| zP@?7@pmMVr6MKoG@v)tYnY?=#g5357!9bhF9*B+u%iP6ka4V8&B**U(PO?wQU5@fo z!7jT?d@@>9?^-@0BcS&@vD>0gpIIX#IA1@EPMP#Hx#KD{nq49QPW+_Y=lD{&AIs6I z-!w&JkmTn08GkZ<>^&jHL}yM2ZSCX6gd>aobm8FUTtZn2GR>+>(?}I8sTP;?Q*Vg( zuR2`n*`eb_Ji8$2X~PNiAOj37Q?P8ev`>+NS@NY1=t-68Z|xQ2@(-E#O0X^kRnhiO zg{bC(*J(y~1H&JdL7!s99wf}>Aa#H5Y6rzTq{Z1H)w;Ze;!Pk`jy*LXZ4+bUf3vBd zvva{gNZb<>lf-M@-hqv|f>*0@lX{e4f(;)K`zbwuu%8OU5o_yC-}G&TN9fr;b9>gz zGSX14)Q077xlWC?<-k_N?b*s;Lg>WGat;!Gf`zC>E<}NdIX(PESOhASL?d4VqJ=Sy zx^6%m2MKm0ZHO!=bo*x$a(NbcV@E}qGL`vqbk|nD|7h;{UX3q0?s9sqvA$l6TJD3| z{xw;9S2ETn;EfuqA;B>-B7@nkoOwJg{1Lgk$N3hHx$l!yOWg+ylk89o^%Q=f?lrRi zD7Zj=FulPKE(|vu%BrZYO0bGYs)e?Bvlb)rU1LX$$5d)Ao_-*4{~WXDoo}_~ zuWPq^Pe6vQ8%;fd00NRe@pO%;*ydGwDM)v@X@8$VZsa0qgAMQ)wfeGzNJ@-=>R)EL ztndt&PB@tH;Yzy)U&iQ@x|$#7avb=ztXwhu@8Kw#<9?2)F~a;ZrKk8_4pwVfOX>a8 z#<@-UiA#M{ZK%8;grr_Ea$g@3icmksm;J!TNB7X^7-Kc(sO*7_cQX`INpr8Z+7uz`BXF;Apdz=(_l)I zGtM9qaMZv+xkk@*M;tW$vB_YsssF0S_Z@Dra@&FF$T>Y-_7pD&DV!A_3Ss5jJ=+-7 zOjkX3KDZuK`0UR2WwP59EHW#<h5}pDXUcF{)j5lBBwt7P|<-^~{V#Wlf z7z|yV6rd);-;)(leT2JCvz=2UiB+s)aekBNzFT4L^!@VYdsby{q5E*QXK(d4mpfUB z#>*)YEK~YTuJ$r;+z@{g9nif{v`=LX#CX~bxh!p*G93OfF8JKfgS4G9#<2&Cxk^$8 z!V;%QA}=#m8?=GSYm<-poyDyMTtd^BC=@1){T>uwqs(C!?^fAwehUx=Y zQJ8%V51%%<+_iG0eRlM5DW^5e2I_p~$z-F^iOdY~#Edv$l0{Xz!~NFnT5{90?;9_W zz>;FQQx=Oz{DVJBacjoTP)6=><07uK!JkQfv{GZLcZK@WW4kwtRhHI`LgvlL3ojs6 zVD0%kWLV&dr`=4qU1W23qpUKzu%`dXurR>b8Le^rd>egc z-F!4S^fC+d+Nw#Um5&xxQLJw$())788#xPi{$r?i9-bLNNeuy)HTqnM6o^z`ikL20 zp#ykU%ceF^xNSj4H71Zx#W|JXZ6|O{V?W1}{4aXTz2nA4`X3bb67kBDL7pgn2o*14 zW^#p+5b5Fk=lzs6_PMzLKZ0VunXT<*Z;YHF-oRQ;IM;-ZbbeZS&j97|D=GKCgY`&0 z7d5yoX%pRt=!u*cZ0^t1S{7*IxB=4Zs$89(R`4>J7{G&TfoCsuq<#?`m4}AF~gd=1kX{49mlfORmLn1uw)VSBN zv;d*>h0j$njSPW}nZ1t0xVB8(x-mb{6=pAD6M290^4uINn8rHS8YFBO=V_$JZ3bgV13c;Cq!i7QNkI#EX2myWnt#(9l_v4rUfj4kD8q83e9J!68t`b z0|t)&BJNxs)Av3lwcg-XJ~PR~-IzV4uUSw+c$gm-kjZTK>Z*wMYVVnmtFWQcku4vI zDMGmP1w9z37)BO7>BdTs#p7_2@KS@Gsw^UCZ-ZomSf00nfB0K{aW0h+ddE{}gS0i6 zHJ=5TjdPEHEgr!ACPbEVh4wferHMk zl}mlOhQhh&*6!Fe2mn*QZ zkLhNm^-VqDe)WsD)GA$MY-!$iVUMBAL0)!ocby^K%vyNW)Zk|WLp~l`IJ2Tf4r7VW<`i~k<-m4u=jcIFaY!68#h|6t1Vx#;lNi~^Xe)Td>pz| zkW~4(bG>w2{9uzRvThc&IW(g{M(gcO(Oq(xV#`KOWUOyBKpgKBP2brs!V=+e#$)|r zeQ$Ue?tJfefjSst2A(PmFmpk?iAlxJnn+qj%Lx2M7Q7Ob|E_x85!7#23}t~ z_sWA;xftCgG$wD-y>4ddgP{gsbikiqcDv5f5W_nRY~W`$-GY2QZI>D7_f8cwx0)it z0%Alc2f>TsG3Rv#N-7>pM>_MSmTxlT<7N!TUr8Ch27R95_w15*SMt^G%Nh3$xM)0N z8pmIK0WDoI!SMr{*80`dyO{@9D^KU|;mA1ST*{=O#pxfM*nI^r{N#de6%p~%B&Z;X z(I|Up8n~*f*CvX5=b>CE)j=~Sp4SEdzI&^bXC>Pm*%|rM+;2+(QjI2^$7X~j- z_PH$9m@mx@E{#|2gtC6IgTqaX4F{Pkck60h zJjv$#J9CEB{$To~0gD~)l3JCOcWS^7)2}Sa+7d6eBnl|6;AW-6c}}IhFgrhc>=YRU z<_gWfowzD$+A7&5iN3-vRbxi(HGUl5|Ey7{tU)I)H1SUi{ERJ2?7pnalbv_Y6V-J| z+XcnWj$MUGOU!K&aRWh7U%S_%4x1D%qi8K?-W9AGvb!H)Exp_KOW+_bB~V7z#c@U9 zXPd}5cEipuqQ8}qg0#y1CT#6{9G4A#Q~;->wzvs5zn}9wHSpiv*B$t;I$?=5tCyt3 zKQ_Jmglmrk?blg}gJS}d(#PfXI4iM2(l=ITF0>tBmsM~j^Mk1&K1fD3PDY$=wVey) zuQOP~OdZ!}xE9hkxBOsoers&gyvd8$f@P*-*UC@CVi!Z{q5&UvJQ8>`4k(cVbfkGx-k?eijS2mnq}Jsb&Q}6+4^KXXzqC2JBx5K z^rofQa%65HW=m1s(kJAEri3G^eygLY`M3;c>Sf_SPWqcmW z02W6iyMVu~QxBcN56ge7=4#!4lIm`H!5zOVr@3-=>jiKbpB|1|%$9UeOC@%#fVfMc zmv*pP_#~esnLie&K{XuL#F~~CpA&xa@WEr!#_;7n@dR;~`GFuBkTkeF=B1r?E811{ zOY)r)>aAzmqIdaOXYbmDoQyEN$-@zO*oCk5Eu$q_Mf+|Fso&+*+_jg^)EcERQ`+>7 z$l@jE>459+?nd-esWTV;SpQmfQn4XSugA7xbFS}3{_?w~G$$nDQo?X$e_|gqcAk@> z_db~%jLCSVbogh{)!(XR?4j|mOr*=5t0ABEZlB7s&XL=Y1ow|z=88HlvTtDcX=mod zNe|8B+ZTg~-}VhPaB-^KKX)~YkAo_n*#8{p1_IM@#JJa4#GW@EvkZ?-SPI9qm|{f@ zSsZT3pRXRc`ltT0D2D_-%hn-#_OH zTFgNWz(n1PEF72pRX21Az9M2M^dgCq@{f4PllfFcM1F}KA0zzECQAt`+_wPf6QGbn zXA(Uce%?5;_-R9T^IWBo+j3DOPqh?eMD$cES+lS1pt$O4pU)%xwdu<`d9waBjwWdV zUFTw%eZE(O@re~yJF!tjKg-o@d%mwZ>J^>ib$eJK=hG9yvo8H_J$arufBbgB&h98n z(M{I-d>@ZaAE_pUT@F0l(cS=HfCTEL;5Y+_d`g!XHH1!#k@+$X?PfXa@DFFd>Q9J% zGoiy->EfpQ3v>XJd6uX-La<=OTizWcN(V79_V0xQ1hvYR9@JC`pywx~3<98)h6xX_ zI%Eo#OCr{%Qn{^66c-1U0SS0>5gWZs?`Pm4&EslQLwCvi}skI+o;& z=@%LXX~Z{N(&tid;Oc^{5bi!ec5{iR)Y2P`iSSF`#y%i}>85s)ZOidDYjqL3ftRC5 zbxPec6tLb85+kK5%go%STH+uN2N0RSTY82oGfh4?0CV5&+^Go<;YiADNIW&!oH#Sj@u zkOVy&3quY91SvjJ)^KeP%WF(pBHXoor2VtO!D>P!wc}CQn$6e)S*|58QJP(s6M{`H zr*C++DbUJhMJI|&t2|JOt&mSHQbM3Q_;hB<6i<9wAO1Q)V3d*-V2=nSBOJjG7CyJ~$*G1q_8`>$T}>vu$)fs^#^uo1rspNvXdHNTO;M2gcwY zJ+Wa+08ur~A!>K2R1e$}iu^WaG&z*CQ@)D=4g|Ix(iL>L#rp+%U69JkKHTwgzT7>| zV~lN9r>f^$e%ZU^%1WjTu{LC6FOX6#oJ;+)J&#>=AMZLCYnrZCoZqVC#Os{v5};0p zCih5Gm>wdpBXwiBs58Y0A!6c6TmnJmN$t&7k$+7L$CPiLPh_#2G%3D@P881S=t4%F z(HlydK^hu+JAG6)M8#5eqk*akX`N>{lxl)=Jg$(t?7|4><~!{uR1~Ua%?_d#FAojL z))UMX0W@sRF)QoX#VQkETn!^#xN$8RH~MR)Y!pzkE>#f@mywqPkMw#Zt3?jk=Ddr` zW+dJcfGw4$Ki=C-Qxy;dT1~}J;CHVk-jr=*iSq;NRS|)h=Pl$IWFei>(?}p>0CJj< zEQrvn=>FgtUfEr_3X(hh!=P0;gp3#>POAKZeB)JJLd_@r*?a8L*ja%;V!dc-o;;s% zp5!C(v+IlBb&L)xgRF?4#a(wbII*cIdL+f@Ne4)iRBIKpp6YcZRjCRzGKcOVsH^n{ zA`Lv$*y@Q0Ym5;z|vE#Q*bx@jFlub-B6)_BGK zOvC>Rm*okT5WgNW=ciQhjJNM0%CXqn0!ZNyaNZA_GJC_vkdJ0_W17S4C83ej{YnIxJ#@(EQMVz_]Ot}oFZ=HL-9!bG`#gQK9-?b(#N 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

      b6kO}6jbl5ifm)vUbI-h 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 z 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 i7sYaTo<51GJu` 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�Ol3QWH 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

      I{T!q9<2rL#AR z+AaWpTZ(2pUpxK0BtK$&U8Wt@aBKM#L50LVyX9~>jmfvYTua5iPr$lh`EQrvk*I9F z-_V^uU9jM)@12l;5M1Pk8)~i<-I*L<19#9+vOosN3L5ev^{HY!0iuK#F7D`arAU4W zuQf5WvWMaaDHoiyc`#X5FSCBIFFNLDG4<{d;Gsr6#EYktu`2MMGySs^Sa`HobkPD% zJ#!p!sc-}Gd_b_IC<%39dx%TO&N|Jkozw_NR~8|`14-+>=Fz?S+#4nnvcNP>wiCo% z=Zce;f66h0rvYG@cjg%{)rxWKzno?hDgV8ow&~(ztb%c89U|plFey9}yTEtgl<|zV zS?)uMxI-q^p-v){ew&qX!z?JxW=%)u%|rPS3726BfEELp9)>j>Tkkk_A@Z(}p2^9m zJK7^nd*pB89Wp?X7@s;&h7PXg{JzGOOGyCsNj&_2PQ}hdcRKM zDS7pxAfyQWh4%WC-vU0A-v*zdhJTMKdg2l*6`*?pt8;=F7T%MacJDl0BJbazHke#^ zA^ccfnsZQ(BS=anfFX>(ou7vF8Wtm8m1uk^-amd1gq`_(8soBtR?t+bgfHxkc9m&s z{cD6_U*OVcuz#U<6>q`Ph={%?*uC4oap9@sR@Uolg5G?uLXRgOJ=%4-$qUq%KiGcD zgt3VIx4Q#tC=dqMhcM2x;AB%?;J&`aW#Mwq3*UyV=Y{1&sIE`-1?f#3@sh*8(Hap| za;C_SNaKar@FU{js0cE;o)VPS(I=i^+8jj6vA{2%tx*fG5XlFhbRsIcicRhxAMw6vtP!9j9RA?s z{CYPVdiwWND&dJbaB~kiv`~RwGiGfr;l95!i0G~b^30r#HN)B*ffcy`e&XV=hiM|1 zn943E`S5_q|5#jcRacDB%m$>OZ20J9jzVZEf=4-OlYb1nU+`_SC2L>y38L7FvQ*)1 z4(W}$06#`r%#_LoKzwWvl2Y`09hj_EBpyW4cS!Rv&9`2_Z_=9~gmkmAvH&sGN?qxQ zzLaCoY*7>da#H`esvkabL7tpn6Xtvzle{??cI1gBvmelU-PFG_oKk&DTDkI@&kC~` z$g}Q;p@D!tL}i93?a}|<1EILbesdg+!$@2NEmm2iv<&%&xa#Qog{<;7)V0i?b| zcpA54Trr9}oMR8y%S9SYBaMnluh`|KdH~_5g!`jUVBjRwDuivUo)}SL4zS8RE!GaC zBDHpLjd`TFPLm3n`v5;tvqK89WP4%P2Q4JZmtBUi33&x>Hvb%nI9e2ir)W9!sc*rToPN=BQRx}o*I~P zjg%8=yF)7Pw!TKHvINtb)Q812WVb&H^zF}}Uz(%>@?zfa?ZXlO}g>9oNkmv8xW zxN?36%q+Vh7P=GdE(`STg0CO1ff*z`}f zw^oxbxjmC^l&3(u%4W^>M`sF}5(&%c*__VPR9`MNqjAokl!X{`)X&eufDg)U&}G@eWKH9P%}f&q&&8yUD?}?xYwrH)4n{R0p6xXi1xND z7xYK$*KSY_K&Fl1u?-n_)<(wMc_&qEEd_v^=rH6dn5$*|z|U}@bZmU1P{+eQuEJST zI>NOI)*<$o^bvAGa1fe5B5qwl1m}|_)kpGGFC#h&PD5|#7kE$L#lPnt&XR*+?@P0& z@U_Fh!w|Obc3<_(?n8h&W9N8QsPyVOqEpr|w9Y`u1ltso627;%!u#|b|| z4yt3UN3e-2YO1|-IB+rzscR{k2QAtBw#`PlArmv9^O&D@N#|;j_sz9y7Mug{wy`*6 z(`DS10}?b^K{_^t3(Y|*^dd{$@aRV-#*4H773pLLh zcwZ^*V_JW_WknKLX}Zg7xqo4?cS7}J57$F$8e8m1rM*cj$&TW8 <1`3cue}<2z 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 conditions.push(...override.conditions)); + config?.automations?.forEach((automation) => conditions.push(...automation.conditions)); // Element conditions can be arbitrarily nested underneath conditionals and // custom elements that this card may not known. Here we recursively parse From 7d831f90db0c803d63dc0cba33720baefce8cdcc Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 27 Apr 2024 20:15:48 -0700 Subject: [PATCH 130/189] Ensure automations check for HA conditions. --- .../conditions-manager.test.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/card-controller/conditions-manager.test.ts b/tests/card-controller/conditions-manager.test.ts index b072c0c0..5c02be57 100644 --- a/tests/card-controller/conditions-manager.test.ts +++ b/tests/card-controller/conditions-manager.test.ts @@ -525,6 +525,29 @@ describe('ConditionsManager', () => { expect(manager.hasHAStateConditions()).toBeTruthy(); }); + + it('with automations', () => { + const api = createCardAPI(); + const userConfig = createConfig({ + automations: [ + { + conditions: [ + { + condition: 'state' as const, + entity: 'binary_sensor.foo', + state: 'on', + }, + ], + }, + ], + }); + + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(userConfig); + const manager = new ConditionsManager(api); + manager.setConditionsFromConfig(); + + expect(manager.hasHAStateConditions()).toBeTruthy(); + }); }); describe('should evaluate conditions', () => { From 63797ea35be8cdbaa31551188ff9e00778198a47 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 27 Apr 2024 20:16:10 -0700 Subject: [PATCH 131/189] Check links as part of the github build. --- .github/workflows/build.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4ed0f679..09728c81 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -40,6 +40,9 @@ jobs: # build). ignore: 'hacs' + - name: Verify docs links + run: yarn run docs-check-links + - name: Upload javascript uses: actions/upload-artifact@v3 with: From d154904b34c6a2f8e64c4883f8e0dbc2ff6d2834 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 27 Apr 2024 20:28:43 -0700 Subject: [PATCH 132/189] Add waiting label. --- .github/labels.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/labels.yml b/.github/labels.yml index 566843a4..0e3f8c22 100644 --- a/.github/labels.yml +++ b/.github/labels.yml @@ -30,7 +30,7 @@ color: a2eeef - name: github_actions description: Pull requests that update Github_actions code - color: "000000" + color: '000000' - name: good first issue description: Good for newcomers color: 7057ff @@ -42,7 +42,7 @@ color: e4e669 - name: performance description: Performance - color: "016175" + color: '016175' - name: python description: Pull requests that update Python code color: 2b67c6 @@ -67,3 +67,6 @@ - name: votes needed description: Vote for this feature to encourage prioritization! color: e2ed82 +- name: waiting + description: Waiting for something + color: daa036 From 9acb99a0b9298325818d1f13b2af15417caa0f46 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 30 Apr 2024 22:59:48 -0700 Subject: [PATCH 133/189] Add Google Analytics to docs. --- docs/index.html | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/docs/index.html b/docs/index.html index 796db462..9cb3ae05 100644 --- a/docs/index.html +++ b/docs/index.html @@ -40,7 +40,7 @@ name: 'Frigate Card', logo: 'images/frigate-logo.svg', - + // Automatically go to the top of a page on route change. auto2top: true, @@ -56,11 +56,20 @@ // Use relative links (this way both vscode and docsify work on clicking // a link). relativePath: true, + + // Skip the link to the main content. + skipLink: false, + + // Google tag (Google Analytics 4). + gtag: 'G-ZFD19QWCJP', }; - - + + + + From fa84b3e8951582de0a833a419e98f30a6b05d3b8 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 1 May 2024 20:10:55 -0300 Subject: [PATCH 134/189] Update Node.js from 18 to 20 LTS --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 561a83f0..1a00d380 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,7 @@ "coverage": "vitest run --coverage" }, "volta": { - "node": "18.17.1", - "yarn": "4.1.0" + "node": "20.12.2", + "yarn": "4.1.1" } } From 1a36ce0894dbbcb0eb61c06a46d707a9951ca599 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 5 Jun 2024 22:37:54 -0300 Subject: [PATCH 135/189] Update date-fns and date-fns-tz to v3 --- package.json | 6 +- rollup.config.js | 10 +- src/camera-manager/browse-media/media.ts | 2 +- src/camera-manager/frigate/engine-frigate.ts | 6 +- src/camera-manager/frigate/media.ts | 2 +- src/camera-manager/frigate/util.ts | 4 +- src/camera-manager/manager.ts | 2 +- .../motioneye/engine-motioneye.ts | 5 +- .../utils/range-to-cache-friendly.ts | 6 +- src/components-lib/live/live-controller.ts | 2 +- src/components-lib/media-filter-controller.ts | 22 ++-- src/components-lib/timeline-source.ts | 3 +- src/components/thumbnail.ts | 2 +- src/components/timeline-core.ts | 4 +- src/utils/basic.ts | 10 +- .../ha/browse-media/browse-media-manager.ts | 2 +- src/utils/screenshot.ts | 2 +- tests/camera-manager/cache.test.ts | 3 +- tests/camera-manager/frigate/util.test.ts | 2 +- tests/camera-manager/manager.test.ts | 2 +- tests/camera-manager/range.test.ts | 3 +- .../auto-update-manager.test.ts | 6 +- .../interaction-manager.test.ts | 2 +- .../card-controller/triggers-manager.test.ts | 2 +- .../media-filter-controller.test.ts | 4 +- .../auto-media-actions.test.ts | 2 +- tests/utils/media-to-view.test.ts | 3 +- yarn.lock | 108 ++++++------------ 28 files changed, 89 insertions(+), 138 deletions(-) diff --git a/package.json b/package.json index 561a83f0..2ad1af31 100644 --- a/package.json +++ b/package.json @@ -25,8 +25,8 @@ "@types/bluebird": "^3.5.36", "component-emitter": "^1.3.0", "crypto": "^1.0.1", - "date-fns": "^2.29.2", - "date-fns-tz": "^1.3.7", + "date-fns": "^3.6.0", + "date-fns-tz": "^3.1.3", "embla-carousel": "8.0.0-rc14", "embla-carousel-wheel-gestures": "8.0.0-rc04", "home-assistant-js-websocket": "^8.0.0", @@ -58,6 +58,7 @@ "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^13.3.0", "@rollup/plugin-replace": "^4.0.0", + "@rollup/plugin-typescript": "^11.1.6", "@types/lodash-es": "^4.17.5", "@types/masonry-layout": "^4.2.5", "@typescript-eslint/eslint-plugin": "^5.36.2", @@ -77,7 +78,6 @@ "rollup-plugin-serve": "^2.0.1", "rollup-plugin-styles": "^4.0.0", "rollup-plugin-terser": "^7.0.2", - "rollup-plugin-typescript2": "^0.33.0", "rollup-plugin-visualizer": "^5.8.2", "sass": "^1.54.9", "ts-prune": "^0.10.3", diff --git a/rollup.config.js b/rollup.config.js index 9ebfe496..628db8f2 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,4 +1,4 @@ -import typescript from 'rollup-plugin-typescript2'; +import typescript from '@rollup/plugin-typescript'; import commonjs from '@rollup/plugin-commonjs'; import nodeResolve from '@rollup/plugin-node-resolve'; import { terser } from 'rollup-plugin-terser'; @@ -48,7 +48,9 @@ const plugins = [ include: 'node_modules/**', sourceMap: false, }), - typescript(), + typescript({ + sourceMap: dev, + }), json({ exclude: 'package.json' }), replace({ preventAssignment: true, @@ -89,9 +91,7 @@ const config = { return '[name]-[hash].js'; }, format: 'es', - ...(dev && { - sourcemap: true, - }), + sourcemap: dev, }, plugins: plugins, // These files use this at the toplevel, which causes rollup warning diff --git a/src/camera-manager/browse-media/media.ts b/src/camera-manager/browse-media/media.ts index 12f7803d..16965357 100644 --- a/src/camera-manager/browse-media/media.ts +++ b/src/camera-manager/browse-media/media.ts @@ -1,4 +1,4 @@ -import format from 'date-fns/format'; +import { format } from 'date-fns'; import isEqual from 'lodash-es/isEqual'; import { formatDateAndTime } from '../../utils/basic'; import { RichBrowseMedia } from '../../utils/ha/browse-media/types'; diff --git a/src/camera-manager/frigate/engine-frigate.ts b/src/camera-manager/frigate/engine-frigate.ts index 0a9da710..de6ef537 100644 --- a/src/camera-manager/frigate/engine-frigate.ts +++ b/src/camera-manager/frigate/engine-frigate.ts @@ -1,9 +1,5 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import add from 'date-fns/add'; -import endOfHour from 'date-fns/endOfHour'; -import format from 'date-fns/format'; -import fromUnixTime from 'date-fns/fromUnixTime'; -import startOfHour from 'date-fns/startOfHour'; +import { add, endOfHour, format, fromUnixTime, startOfHour } from 'date-fns'; import isEqual from 'lodash-es/isEqual'; import orderBy from 'lodash-es/orderBy'; import throttle from 'lodash-es/throttle'; diff --git a/src/camera-manager/frigate/media.ts b/src/camera-manager/frigate/media.ts index 2a4c54d9..8617b4a1 100644 --- a/src/camera-manager/frigate/media.ts +++ b/src/camera-manager/frigate/media.ts @@ -1,4 +1,4 @@ -import fromUnixTime from 'date-fns/fromUnixTime'; +import { fromUnixTime } from 'date-fns'; import isEqual from 'lodash-es/isEqual'; import { CameraConfig } from '../../config/types'; import { diff --git a/src/camera-manager/frigate/util.ts b/src/camera-manager/frigate/util.ts index 0f5952a3..8303aea8 100644 --- a/src/camera-manager/frigate/util.ts +++ b/src/camera-manager/frigate/util.ts @@ -1,4 +1,4 @@ -import utcToZonedTime from 'date-fns-tz/utcToZonedTime'; +import { toZonedTime } from 'date-fns-tz'; import { CameraConfig } from '../../config/types'; import { ClipsOrSnapshots } from '../../types'; import { formatDateAndTime, prettifyTitle } from '../../utils/basic'; @@ -18,7 +18,7 @@ export const getEventTitle = (event: FrigateEvent): string => { const score = event.top_score !== null ? ` ${Math.round(event.top_score * 100)}%` : ''; return `${formatDateAndTime( - utcToZonedTime(event.start_time * 1000, localTimezone), + toZonedTime(event.start_time * 1000, localTimezone), )} [${durationSeconds}s, ${prettifyTitle(event.label)}${score}]`; }; diff --git a/src/camera-manager/manager.ts b/src/camera-manager/manager.ts index 780d0b28..e73776de 100644 --- a/src/camera-manager/manager.ts +++ b/src/camera-manager/manager.ts @@ -1,4 +1,4 @@ -import add from 'date-fns/add'; +import { add } from 'date-fns'; import cloneDeep from 'lodash-es/cloneDeep'; import sum from 'lodash-es/sum'; import PQueue from 'p-queue'; diff --git a/src/camera-manager/motioneye/engine-motioneye.ts b/src/camera-manager/motioneye/engine-motioneye.ts index 41540ddc..e02553ab 100644 --- a/src/camera-manager/motioneye/engine-motioneye.ts +++ b/src/camera-manager/motioneye/engine-motioneye.ts @@ -1,8 +1,5 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import add from 'date-fns/add'; -import endOfDay from 'date-fns/endOfDay'; -import parse from 'date-fns/parse'; -import startOfDay from 'date-fns/startOfDay'; +import { add, endOfDay, parse, startOfDay } from 'date-fns'; import orderBy from 'lodash-es/orderBy'; import { CameraConfig } from '../../config/types'; import { allPromises, formatDate, isValidDate } from '../../utils/basic'; diff --git a/src/camera-manager/utils/range-to-cache-friendly.ts b/src/camera-manager/utils/range-to-cache-friendly.ts index 0b8464bd..cb29c1ae 100644 --- a/src/camera-manager/utils/range-to-cache-friendly.ts +++ b/src/camera-manager/utils/range-to-cache-friendly.ts @@ -1,8 +1,4 @@ -import endOfDay from 'date-fns/endOfDay'; -import endOfHour from 'date-fns/endOfHour'; -import endOfMinute from 'date-fns/endOfMinute'; -import startOfDay from 'date-fns/startOfDay'; -import startOfHour from 'date-fns/startOfHour'; +import { endOfDay, endOfHour, endOfMinute, startOfDay, startOfHour } from 'date-fns'; import { DateRange } from '../range'; import { capEndDate } from './cap-end-date'; diff --git a/src/components-lib/live/live-controller.ts b/src/components-lib/live/live-controller.ts index 3080ea78..b7cd577f 100644 --- a/src/components-lib/live/live-controller.ts +++ b/src/components-lib/live/live-controller.ts @@ -1,4 +1,4 @@ -import sub from 'date-fns/sub'; +import { sub } from 'date-fns'; import { LitElement, ReactiveController } from 'lit'; import { ViewContext } from 'view'; import { CameraManager } from '../../camera-manager/manager.js'; diff --git a/src/components-lib/media-filter-controller.ts b/src/components-lib/media-filter-controller.ts index bfb68e15..d4c6ce99 100644 --- a/src/components-lib/media-filter-controller.ts +++ b/src/components-lib/media-filter-controller.ts @@ -1,13 +1,15 @@ -import endOfDay from 'date-fns/endOfDay'; -import endOfMonth from 'date-fns/endOfMonth'; -import endOfYesterday from 'date-fns/endOfYesterday'; -import endOfToday from 'date-fns/esm/endOfToday'; -import startOfToday from 'date-fns/esm/startOfToday'; -import format from 'date-fns/format'; -import parse from 'date-fns/parse'; -import startOfDay from 'date-fns/startOfDay'; -import startOfYesterday from 'date-fns/startOfYesterday'; -import sub from 'date-fns/sub'; +import { + endOfDay, + endOfMonth, + endOfYesterday, + endOfToday, + startOfToday, + format, + parse, + startOfDay, + startOfYesterday, + sub, +} from 'date-fns'; import { LitElement } from 'lit'; import isEqual from 'lodash-es/isEqual'; import orderBy from 'lodash-es/orderBy'; diff --git a/src/components-lib/timeline-source.ts b/src/components-lib/timeline-source.ts index 6b4f9f62..054cc0ef 100644 --- a/src/components-lib/timeline-source.ts +++ b/src/components-lib/timeline-source.ts @@ -1,5 +1,4 @@ -import add from 'date-fns/add'; -import sub from 'date-fns/sub'; +import { add, sub } from 'date-fns'; import { DataSet } from 'vis-data'; import { IdType, TimelineItem, TimelineWindow } from 'vis-timeline/esnext'; import { CameraManager } from '../camera-manager/manager'; diff --git a/src/components/thumbnail.ts b/src/components/thumbnail.ts index 50cafd75..eca1731c 100644 --- a/src/components/thumbnail.ts +++ b/src/components/thumbnail.ts @@ -1,4 +1,4 @@ -import format from 'date-fns/format'; +import { format } from 'date-fns'; import { CSSResult, html, diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index dbd3eca2..3e221d15 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -1,6 +1,4 @@ -import add from 'date-fns/add'; -import differenceInSeconds from 'date-fns/differenceInSeconds'; -import sub from 'date-fns/sub'; +import { add, differenceInSeconds, sub } from 'date-fns'; import { CSSResultGroup, html, diff --git a/src/utils/basic.ts b/src/utils/basic.ts index 99f16855..4c3c3bda 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -1,7 +1,9 @@ -import differenceInHours from 'date-fns/differenceInHours'; -import differenceInMinutes from 'date-fns/differenceInMinutes'; -import differenceInSeconds from 'date-fns/differenceInSeconds'; -import format from 'date-fns/format'; +import { + differenceInHours, + differenceInMinutes, + differenceInSeconds, + format, +} from 'date-fns'; import { StyleInfo } from 'lit/directives/style-map'; import { round } from 'lodash-es'; import isEqualWith from 'lodash-es/isEqualWith'; diff --git a/src/utils/ha/browse-media/browse-media-manager.ts b/src/utils/ha/browse-media/browse-media-manager.ts index c5a66800..86a5dc1c 100644 --- a/src/utils/ha/browse-media/browse-media-manager.ts +++ b/src/utils/ha/browse-media/browse-media-manager.ts @@ -1,5 +1,5 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import add from 'date-fns/add'; +import { add } from 'date-fns'; import { homeAssistantWSRequest } from '..'; import { MemoryRequestCache } from '../../../camera-manager/cache'; import { allPromises } from '../../basic'; diff --git a/src/utils/screenshot.ts b/src/utils/screenshot.ts index 4cf6105b..7aff55ef 100644 --- a/src/utils/screenshot.ts +++ b/src/utils/screenshot.ts @@ -1,4 +1,4 @@ -import format from 'date-fns/format'; +import { format } from 'date-fns'; import { View } from '../view/view'; export const screenshotMedia = (video: HTMLVideoElement): string | null => { diff --git a/tests/camera-manager/cache.test.ts b/tests/camera-manager/cache.test.ts index 6746ec8a..0f2f6fef 100644 --- a/tests/camera-manager/cache.test.ts +++ b/tests/camera-manager/cache.test.ts @@ -1,5 +1,4 @@ -import add from 'date-fns/add'; -import sub from 'date-fns/sub'; +import { add, sub } from 'date-fns'; import sortBy from 'lodash-es/sortBy'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { diff --git a/tests/camera-manager/frigate/util.test.ts b/tests/camera-manager/frigate/util.test.ts index 38e32482..9b99fea4 100644 --- a/tests/camera-manager/frigate/util.test.ts +++ b/tests/camera-manager/frigate/util.test.ts @@ -1,4 +1,4 @@ -import add from 'date-fns/add'; +import { add } from 'date-fns'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts index 6c69a6fb..8529c37d 100644 --- a/tests/camera-manager/manager.test.ts +++ b/tests/camera-manager/manager.test.ts @@ -1,5 +1,5 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import add from 'date-fns/add'; +import { add } from 'date-fns'; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { Camera } from '../../src/camera-manager/camera'; diff --git a/tests/camera-manager/range.test.ts b/tests/camera-manager/range.test.ts index 5d2a40c4..9a720252 100644 --- a/tests/camera-manager/range.test.ts +++ b/tests/camera-manager/range.test.ts @@ -1,5 +1,4 @@ -import add from 'date-fns/add'; -import sub from 'date-fns/sub'; +import { add, sub } from 'date-fns'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { compressRanges, diff --git a/tests/card-controller/auto-update-manager.test.ts b/tests/card-controller/auto-update-manager.test.ts index 2f1c2e2c..34382e1b 100644 --- a/tests/card-controller/auto-update-manager.test.ts +++ b/tests/card-controller/auto-update-manager.test.ts @@ -1,4 +1,4 @@ -import add from 'date-fns/add'; +import { add } from 'date-fns'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { AutoUpdateManager } from '../../src/card-controller/auto-update-manager'; import { createCardAPI, createConfig } from '../test-utils'; @@ -31,7 +31,7 @@ describe('AutoUpdateManager', () => { manager.startDefaultViewTimer(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); - + vi.setSystemTime(add(start, { seconds: 10 })); vi.runOnlyPendingTimers(); @@ -64,7 +64,7 @@ describe('AutoUpdateManager', () => { manager.startDefaultViewTimer(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); - + vi.setSystemTime(add(start, { seconds: 10 })); vi.runOnlyPendingTimers(); diff --git a/tests/card-controller/interaction-manager.test.ts b/tests/card-controller/interaction-manager.test.ts index 8e363948..8c17ae03 100644 --- a/tests/card-controller/interaction-manager.test.ts +++ b/tests/card-controller/interaction-manager.test.ts @@ -1,4 +1,4 @@ -import add from 'date-fns/add'; +import { add } from 'date-fns'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { InteractionManager } from '../../src/card-controller/interaction-manager'; import { createCardAPI, createConfig } from '../test-utils'; diff --git a/tests/card-controller/triggers-manager.test.ts b/tests/card-controller/triggers-manager.test.ts index 45193dda..5ae6b064 100644 --- a/tests/card-controller/triggers-manager.test.ts +++ b/tests/card-controller/triggers-manager.test.ts @@ -1,4 +1,4 @@ -import add from 'date-fns/add'; +import { add } from 'date-fns'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { CardController } from '../../src/card-controller/controller'; import { TriggersManager } from '../../src/card-controller/triggers-manager'; diff --git a/tests/components-lib/media-filter-controller.test.ts b/tests/components-lib/media-filter-controller.test.ts index 623b4fbc..cf08281d 100644 --- a/tests/components-lib/media-filter-controller.test.ts +++ b/tests/components-lib/media-filter-controller.test.ts @@ -1,6 +1,4 @@ -import endOfDay from 'date-fns/endOfDay'; -import startOfDay from 'date-fns/startOfDay'; -import sub from 'date-fns/sub'; +import { endOfDay, startOfDay, sub } from 'date-fns'; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import { Capabilities } from '../../src/camera-manager/capabilities'; import { CameraManagerStore } from '../../src/camera-manager/store'; diff --git a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts index 91cf31c8..d508772e 100644 --- a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts +++ b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts @@ -1,4 +1,4 @@ -import add from 'date-fns/add'; +import { add } from 'date-fns'; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { diff --git a/tests/utils/media-to-view.test.ts b/tests/utils/media-to-view.test.ts index a8b06416..05493cb3 100644 --- a/tests/utils/media-to-view.test.ts +++ b/tests/utils/media-to-view.test.ts @@ -1,5 +1,4 @@ -import add from 'date-fns/add'; -import sub from 'date-fns/sub'; +import { add, sub } from 'date-fns'; import { beforeEach, describe, expect, it, Mock, MockedFunction, vi } from 'vitest'; import { QueryType } from '../../src/camera-manager/types'; import { diff --git a/yarn.lock b/yarn.lock index d7d556b0..dbb1f02f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -325,15 +325,6 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.21.0": - version: 7.24.0 - resolution: "@babel/runtime@npm:7.24.0" - dependencies: - regenerator-runtime: "npm:^0.14.0" - checksum: 10c0/3495eed727bf4a4f84c35bb51ab53317ae38f4bbc3b1d0a8303751f9dfa0ce6f5fb2afced72b76c3dd0d8bb2ccb84787559a4dee9886291a36b26f02f0f759b4 - languageName: node - linkType: hard - "@babel/template@npm:^7.22.15, @babel/template@npm:^7.24.0": version: 7.24.0 resolution: "@babel/template@npm:7.24.0" @@ -1005,6 +996,25 @@ __metadata: languageName: node linkType: hard +"@rollup/plugin-typescript@npm:^11.1.6": + version: 11.1.6 + resolution: "@rollup/plugin-typescript@npm:11.1.6" + dependencies: + "@rollup/pluginutils": "npm:^5.1.0" + resolve: "npm:^1.22.1" + peerDependencies: + rollup: ^2.14.0||^3.0.0||^4.0.0 + tslib: "*" + typescript: ">=3.7.0" + peerDependenciesMeta: + rollup: + optional: true + tslib: + optional: true + checksum: 10c0/5347cd73ac28d4cf2401a3e689864a1a0df8f3ae029abd9c38525cbc84bcfa16c3a32a0ac5698dac65ec531ba7cf8332e14f5fc7f8fa501193da23320a134c5c + languageName: node + linkType: hard + "@rollup/pluginutils@npm:^3.0.8, @rollup/pluginutils@npm:^3.1.0": version: 3.1.0 resolution: "@rollup/pluginutils@npm:3.1.0" @@ -1028,7 +1038,7 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^5.0.1": +"@rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.1.0": version: 5.1.0 resolution: "@rollup/pluginutils@npm:5.1.0" dependencies: @@ -2619,21 +2629,19 @@ __metadata: languageName: node linkType: hard -"date-fns-tz@npm:^1.3.7": - version: 1.3.8 - resolution: "date-fns-tz@npm:1.3.8" +"date-fns-tz@npm:^3.1.3": + version: 3.1.3 + resolution: "date-fns-tz@npm:3.1.3" peerDependencies: - date-fns: ">=2.0.0" - checksum: 10c0/4cb16aeae3ea4a72ac4ae9f7db2011e38797aff122a78be16217a0492dde3938e1e62d21dbf1469a36fb4426824196233cedc70807f0a3033bca132bf76d563e + date-fns: ^3.0.0 + checksum: 10c0/dcedf178a96632a798966cf5a881441aefc451cc308336a98919e49c2df8eff7a302d19b9d3903c50838dd0912533f862f0bfb9429e8c28c1c3ce5da19ccb64e languageName: node linkType: hard -"date-fns@npm:^2.29.2": - version: 2.30.0 - resolution: "date-fns@npm:2.30.0" - dependencies: - "@babel/runtime": "npm:^7.21.0" - checksum: 10c0/e4b521fbf22bc8c3db332bbfb7b094fd3e7627de0259a9d17c7551e2d2702608a7307a449206065916538e384f37b181565447ce2637ae09828427aed9cb5581 +"date-fns@npm:^3.6.0": + version: 3.6.0 + resolution: "date-fns@npm:3.6.0" + checksum: 10c0/0b5fb981590ef2f8e5a3ba6cd6d77faece0ea7f7158948f2eaae7bbb7c80a8f63ae30b01236c2923cf89bb3719c33aeb150c715ea4fe4e86e37dcf06bed42fb6 languageName: node linkType: hard @@ -3752,18 +3760,7 @@ __metadata: languageName: node linkType: hard -"find-cache-dir@npm:^3.3.2": - version: 3.3.2 - resolution: "find-cache-dir@npm:3.3.2" - dependencies: - commondir: "npm:^1.0.1" - make-dir: "npm:^3.0.2" - pkg-dir: "npm:^4.1.0" - checksum: 10c0/92747cda42bff47a0266b06014610981cfbb71f55d60f2c8216bc3108c83d9745507fb0b14ecf6ab71112bed29cd6fb1a137ee7436179ea36e11287e3159e587 - languageName: node - linkType: hard - -"find-up@npm:^4.0.0, find-up@npm:^4.1.0": +"find-up@npm:^4.1.0": version: 4.1.0 resolution: "find-up@npm:4.1.0" dependencies: @@ -3867,6 +3864,7 @@ __metadata: "@rollup/plugin-json": "npm:^4.1.0" "@rollup/plugin-node-resolve": "npm:^13.3.0" "@rollup/plugin-replace": "npm:^4.0.0" + "@rollup/plugin-typescript": "npm:^11.1.6" "@types/bluebird": "npm:^3.5.36" "@types/lodash-es": "npm:^4.17.5" "@types/masonry-layout": "npm:^4.2.5" @@ -3875,8 +3873,8 @@ __metadata: "@vitest/coverage-istanbul": "npm:^1.5.0" component-emitter: "npm:^1.3.0" crypto: "npm:^1.0.1" - date-fns: "npm:^2.29.2" - date-fns-tz: "npm:^1.3.7" + date-fns: "npm:^3.6.0" + date-fns-tz: "npm:^3.1.3" docsify-cli: "npm:^4.4.4" embla-carousel: "npm:8.0.0-rc14" embla-carousel-wheel-gestures: "npm:8.0.0-rc04" @@ -3902,7 +3900,6 @@ __metadata: rollup-plugin-serve: "npm:^2.0.1" rollup-plugin-styles: "npm:^4.0.0" rollup-plugin-terser: "npm:^7.0.2" - rollup-plugin-typescript2: "npm:^0.33.0" rollup-plugin-visualizer: "npm:^5.8.2" sass: "npm:^1.54.9" screenfull: "npm:^6.0.2" @@ -5469,7 +5466,7 @@ __metadata: languageName: node linkType: hard -"make-dir@npm:^3.0.0, make-dir@npm:^3.0.2": +"make-dir@npm:^3.0.0": version: 3.1.0 resolution: "make-dir@npm:3.1.0" dependencies: @@ -6454,15 +6451,6 @@ __metadata: languageName: node linkType: hard -"pkg-dir@npm:^4.1.0": - version: 4.2.0 - resolution: "pkg-dir@npm:4.2.0" - dependencies: - find-up: "npm:^4.0.0" - checksum: 10c0/c56bda7769e04907a88423feb320babaed0711af8c436ce3e56763ab1021ba107c7b0cafb11cde7529f669cfc22bffcaebffb573645cbd63842ea9fb17cd7728 - languageName: node - linkType: hard - "pkg-types@npm:^1.0.3": version: 1.0.3 resolution: "pkg-types@npm:1.0.3" @@ -7076,13 +7064,6 @@ __metadata: languageName: node linkType: hard -"regenerator-runtime@npm:^0.14.0": - version: 0.14.1 - resolution: "regenerator-runtime@npm:0.14.1" - checksum: 10c0/1b16eb2c4bceb1665c89de70dcb64126a22bc8eb958feef3cd68fe11ac6d2a4899b5cd1b80b0774c7c03591dc57d16631a7f69d2daa2ec98100e2f29f7ec4cc4 - languageName: node - linkType: hard - "regexp.prototype.flags@npm:^1.5.2": version: 1.5.2 resolution: "regexp.prototype.flags@npm:1.5.2" @@ -7148,7 +7129,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.21.0, resolve@npm:^1.22.4": +"resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.21.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -7161,7 +7142,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.21.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": +"resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.21.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -7269,21 +7250,6 @@ __metadata: languageName: node linkType: hard -"rollup-plugin-typescript2@npm:^0.33.0": - version: 0.33.0 - resolution: "rollup-plugin-typescript2@npm:0.33.0" - dependencies: - "@rollup/pluginutils": "npm:^4.1.2" - find-cache-dir: "npm:^3.3.2" - fs-extra: "npm:^10.0.0" - tslib: "npm:^2.4.0" - peerDependencies: - rollup: ">=1.26.3" - typescript: ">=2.4.0" - checksum: 10c0/20cf7b9557245f6c540e496052656bc0a6e24aebdc27ba83b471545fe3f5bd1c35b69459fdeadde2d59dfe45cb9f18c15d228e11e1a577491bb5d01e357b81fa - languageName: node - linkType: hard - "rollup-plugin-visualizer@npm:^5.8.2": version: 5.12.0 resolution: "rollup-plugin-visualizer@npm:5.12.0" @@ -8182,7 +8148,7 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.1, tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0": +"tslib@npm:^2.0.1, tslib@npm:^2.1.0, tslib@npm:^2.3.1": version: 2.6.2 resolution: "tslib@npm:2.6.2" checksum: 10c0/e03a8a4271152c8b26604ed45535954c0a45296e32445b4b87f8a5abdb2421f40b59b4ca437c4346af0f28179780d604094eb64546bee2019d903d01c6c19bdb From 289618d40a4530d2d3325ad1ca6338d1ccc7addc Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 5 Jun 2024 22:55:26 -0300 Subject: [PATCH 136/189] Update typescript to v5, as well as eslint and typescript-eslint --- package.json | 8 +- src/action-handler-directive.ts | 6 +- src/components/live/live-ha.ts | 2 +- yarn.lock | 265 ++++++++++++++++---------------- 4 files changed, 138 insertions(+), 143 deletions(-) diff --git a/package.json b/package.json index 2e13f7db..a188473e 100644 --- a/package.json +++ b/package.json @@ -61,11 +61,11 @@ "@rollup/plugin-typescript": "^11.1.6", "@types/lodash-es": "^4.17.5", "@types/masonry-layout": "^4.2.5", - "@typescript-eslint/eslint-plugin": "^5.36.2", - "@typescript-eslint/parser": "^5.36.2", + "@typescript-eslint/eslint-plugin": "^7.12.0", + "@typescript-eslint/parser": "^7.12.0", "@vitest/coverage-istanbul": "^1.5.0", "docsify-cli": "^4.4.4", - "eslint": "^8.23.0", + "eslint": "^8.57.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^8.5.0", "eslint-plugin-import": "^2.25.4", @@ -81,7 +81,7 @@ "rollup-plugin-visualizer": "^5.8.2", "sass": "^1.54.9", "ts-prune": "^0.10.3", - "typescript": "^4.9.5", + "typescript": "^5.4.5", "vitest": "^1.5.0", "vitest-mock-extended": "^1.3.1" }, diff --git a/src/action-handler-directive.ts b/src/action-handler-directive.ts index c61f028e..5a7a4448 100644 --- a/src/action-handler-directive.ts +++ b/src/action-handler-directive.ts @@ -13,7 +13,7 @@ import { import { stopEventFromActivatingCardWideActions } from './utils/action.js'; import { Timer } from './utils/timer.js'; -interface ActionHandler extends HTMLElement { +interface ActionHandlerInterface extends HTMLElement { holdTime: number; bind(element: Element, options): void; } @@ -25,7 +25,7 @@ interface FrigateCardActionHandlerOptions extends ActionHandlerOptions { allowPropagation?: boolean; } -class ActionHandler extends HTMLElement implements ActionHandler { +class ActionHandler extends HTMLElement implements ActionHandlerInterface { public holdTime = 0.4; protected holdTimer = new Timer(); @@ -56,7 +56,7 @@ class ActionHandler extends HTMLElement implements ActionHandler { public bind( element: ActionHandlerElement, - options: FrigateCardActionHandlerOptions, + options?: FrigateCardActionHandlerOptions, ): void { if (element.actionHandlerOptions) { // Reset the options on an existing actionHandler. diff --git a/src/components/live/live-ha.ts b/src/components/live/live-ha.ts index eb090928..46920002 100644 --- a/src/components/live/live-ha.ts +++ b/src/components/live/live-ha.ts @@ -6,7 +6,7 @@ import { CameraConfig } from '../../config/types'; import { localize } from '../../localize/localize'; import '../../patches/ha-camera-stream'; import '../../patches/ha-hls-player.js'; -import '../../patches/ha-web-rtc-player.ts'; +import '../../patches/ha-web-rtc-player.js'; import liveHAStyle from '../../scss/live-ha.scss'; import { FrigateCardMediaPlayer } from '../../types.js'; import { renderMessage } from '../message'; diff --git a/yarn.lock b/yarn.lock index dbb1f02f..2be981ac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -573,7 +573,7 @@ __metadata: languageName: node linkType: hard -"@eslint-community/eslint-utils@npm:^4.2.0": +"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0": version: 4.4.0 resolution: "@eslint-community/eslint-utils@npm:4.4.0" dependencies: @@ -584,7 +584,14 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.4.0, @eslint-community/regexpp@npm:^4.6.1": +"@eslint-community/regexpp@npm:^4.10.0": + version: 4.10.1 + resolution: "@eslint-community/regexpp@npm:4.10.1" + checksum: 10c0/f59376025d0c91dd9fdf18d33941df499292a3ecba3e9889c360f3f6590197d30755604588786cdca0f9030be315a26b206014af4b65c0ff85b4ec49043de780 + languageName: node + linkType: hard + +"@eslint-community/regexpp@npm:^4.6.1": version: 4.10.0 resolution: "@eslint-community/regexpp@npm:4.10.0" checksum: 10c0/c5f60ef1f1ea7649fa7af0e80a5a79f64b55a8a8fa5086de4727eb4c86c652aedee407a9c143b8995d2c0b2d75c1222bec9ba5d73dbfc1f314550554f0979ef4 @@ -1256,13 +1263,6 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:^7.0.9": - version: 7.0.15 - resolution: "@types/json-schema@npm:7.0.15" - checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db - languageName: node - linkType: hard - "@types/json5@npm:^0.0.29": version: 0.0.29 resolution: "@types/json5@npm:0.0.29" @@ -1338,13 +1338,6 @@ __metadata: languageName: node linkType: hard -"@types/semver@npm:^7.3.12": - version: 7.5.8 - resolution: "@types/semver@npm:7.5.8" - checksum: 10c0/8663ff927234d1c5fcc04b33062cb2b9fcfbe0f5f351ed26c4d1e1581657deebd506b41ff7fdf89e787e3d33ce05854bc01686379b89e9c49b564c4cfa988efa - languageName: node - linkType: hard - "@types/sizzle@npm:*": version: 2.3.8 resolution: "@types/sizzle@npm:2.3.8" @@ -1359,124 +1352,121 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^5.36.2": - version: 5.62.0 - resolution: "@typescript-eslint/eslint-plugin@npm:5.62.0" +"@typescript-eslint/eslint-plugin@npm:^7.12.0": + version: 7.12.0 + resolution: "@typescript-eslint/eslint-plugin@npm:7.12.0" dependencies: - "@eslint-community/regexpp": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:5.62.0" - "@typescript-eslint/type-utils": "npm:5.62.0" - "@typescript-eslint/utils": "npm:5.62.0" - debug: "npm:^4.3.4" + "@eslint-community/regexpp": "npm:^4.10.0" + "@typescript-eslint/scope-manager": "npm:7.12.0" + "@typescript-eslint/type-utils": "npm:7.12.0" + "@typescript-eslint/utils": "npm:7.12.0" + "@typescript-eslint/visitor-keys": "npm:7.12.0" graphemer: "npm:^1.4.0" - ignore: "npm:^5.2.0" - natural-compare-lite: "npm:^1.4.0" - semver: "npm:^7.3.7" - tsutils: "npm:^3.21.0" + ignore: "npm:^5.3.1" + natural-compare: "npm:^1.4.0" + ts-api-utils: "npm:^1.3.0" peerDependencies: - "@typescript-eslint/parser": ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + "@typescript-eslint/parser": ^7.0.0 + eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/3f40cb6bab5a2833c3544e4621b9fdacd8ea53420cadc1c63fac3b89cdf5c62be1e6b7bcf56976dede5db4c43830de298ced3db60b5494a3b961ca1b4bff9f2a + checksum: 10c0/abf899e07144e8edd8ae010d25e4679e2acded407a10efc6aaa7ee325af8daf0dd149946ad58e46982e29e0a23f56b1e0dd461ef09aab09b0d94fc24ffc827c2 languageName: node linkType: hard -"@typescript-eslint/parser@npm:^5.36.2": - version: 5.62.0 - resolution: "@typescript-eslint/parser@npm:5.62.0" +"@typescript-eslint/parser@npm:^7.12.0": + version: 7.12.0 + resolution: "@typescript-eslint/parser@npm:7.12.0" dependencies: - "@typescript-eslint/scope-manager": "npm:5.62.0" - "@typescript-eslint/types": "npm:5.62.0" - "@typescript-eslint/typescript-estree": "npm:5.62.0" + "@typescript-eslint/scope-manager": "npm:7.12.0" + "@typescript-eslint/types": "npm:7.12.0" + "@typescript-eslint/typescript-estree": "npm:7.12.0" + "@typescript-eslint/visitor-keys": "npm:7.12.0" debug: "npm:^4.3.4" peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/315194b3bf39beb9bd16c190956c46beec64b8371e18d6bb72002108b250983eb1e186a01d34b77eb4045f4941acbb243b16155fbb46881105f65e37dc9e24d4 + checksum: 10c0/223c32a6ba6cee770ee39108fb0a6d132283673d44c751bec85d8792df3382ddb839617787d183dc8fd7686d8a2018bf1ec0f3d63b7010c4370913f249c80fbc languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/scope-manager@npm:5.62.0" +"@typescript-eslint/scope-manager@npm:7.12.0": + version: 7.12.0 + resolution: "@typescript-eslint/scope-manager@npm:7.12.0" dependencies: - "@typescript-eslint/types": "npm:5.62.0" - "@typescript-eslint/visitor-keys": "npm:5.62.0" - checksum: 10c0/861253235576c1c5c1772d23cdce1418c2da2618a479a7de4f6114a12a7ca853011a1e530525d0931c355a8fd237b9cd828fac560f85f9623e24054fd024726f + "@typescript-eslint/types": "npm:7.12.0" + "@typescript-eslint/visitor-keys": "npm:7.12.0" + checksum: 10c0/7af53cd9045cc70459e4f451377affc0ef03e67bd743480ab2cbfebe1b7d8269fc639406966930c5abb26f1b633623c98442c2b60f6257e0ce1555439343d5e9 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/type-utils@npm:5.62.0" +"@typescript-eslint/type-utils@npm:7.12.0": + version: 7.12.0 + resolution: "@typescript-eslint/type-utils@npm:7.12.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:5.62.0" - "@typescript-eslint/utils": "npm:5.62.0" + "@typescript-eslint/typescript-estree": "npm:7.12.0" + "@typescript-eslint/utils": "npm:7.12.0" debug: "npm:^4.3.4" - tsutils: "npm:^3.21.0" + ts-api-utils: "npm:^1.3.0" peerDependencies: - eslint: "*" + eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/93112e34026069a48f0484b98caca1c89d9707842afe14e08e7390af51cdde87378df29d213d3bbd10a7cfe6f91b228031b56218515ce077bdb62ddea9d9f474 + checksum: 10c0/41f4aa20d24724b461eb0cdac69d91ef60c2b628fb4a5739e4dbb8378aa4a7ff20c302f60e5d74ce75d5b99fcd3e3d71b9b3c96a1714aac47ce2ce5d6d611fcd languageName: node linkType: hard -"@typescript-eslint/types@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/types@npm:5.62.0" - checksum: 10c0/7febd3a7f0701c0b927e094f02e82d8ee2cada2b186fcb938bc2b94ff6fbad88237afc304cbaf33e82797078bbbb1baf91475f6400912f8b64c89be79bfa4ddf +"@typescript-eslint/types@npm:7.12.0": + version: 7.12.0 + resolution: "@typescript-eslint/types@npm:7.12.0" + checksum: 10c0/76786d02a0838750d74ad6e49b026875c0753b81c5a46a56525a1e82d89c0939a13434b03494e3b31b7ffbba7824f426c5b502a12337806a1f6ca560b5dad46c languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/typescript-estree@npm:5.62.0" +"@typescript-eslint/typescript-estree@npm:7.12.0": + version: 7.12.0 + resolution: "@typescript-eslint/typescript-estree@npm:7.12.0" dependencies: - "@typescript-eslint/types": "npm:5.62.0" - "@typescript-eslint/visitor-keys": "npm:5.62.0" + "@typescript-eslint/types": "npm:7.12.0" + "@typescript-eslint/visitor-keys": "npm:7.12.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" - semver: "npm:^7.3.7" - tsutils: "npm:^3.21.0" + minimatch: "npm:^9.0.4" + semver: "npm:^7.6.0" + ts-api-utils: "npm:^1.3.0" peerDependenciesMeta: typescript: optional: true - checksum: 10c0/d7984a3e9d56897b2481940ec803cb8e7ead03df8d9cfd9797350be82ff765dfcf3cfec04e7355e1779e948da8f02bc5e11719d07a596eb1cb995c48a95e38cf + checksum: 10c0/855be5ba6c3d7540319ad250555055a798deb04855f26abe719a3b8d555a3227d52e09453930bd829e260a72f65a985998b235514ce2872b31615015da3163c0 languageName: node linkType: hard -"@typescript-eslint/utils@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/utils@npm:5.62.0" +"@typescript-eslint/utils@npm:7.12.0": + version: 7.12.0 + resolution: "@typescript-eslint/utils@npm:7.12.0" dependencies: - "@eslint-community/eslint-utils": "npm:^4.2.0" - "@types/json-schema": "npm:^7.0.9" - "@types/semver": "npm:^7.3.12" - "@typescript-eslint/scope-manager": "npm:5.62.0" - "@typescript-eslint/types": "npm:5.62.0" - "@typescript-eslint/typescript-estree": "npm:5.62.0" - eslint-scope: "npm:^5.1.1" - semver: "npm:^7.3.7" + "@eslint-community/eslint-utils": "npm:^4.4.0" + "@typescript-eslint/scope-manager": "npm:7.12.0" + "@typescript-eslint/types": "npm:7.12.0" + "@typescript-eslint/typescript-estree": "npm:7.12.0" peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 10c0/f09b7d9952e4a205eb1ced31d7684dd55cee40bf8c2d78e923aa8a255318d97279825733902742c09d8690f37a50243f4c4d383ab16bd7aefaf9c4b438f785e1 + eslint: ^8.56.0 + checksum: 10c0/04241c0313f2d061bc81ec2d5d589c9a723f8c1493e5b83d98f804ff9dac23c5e7157d9bb57bee8b458f40824f56ea65a02ebd344926a37cb58bf151cb4d3bf2 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:5.62.0": - version: 5.62.0 - resolution: "@typescript-eslint/visitor-keys@npm:5.62.0" +"@typescript-eslint/visitor-keys@npm:7.12.0": + version: 7.12.0 + resolution: "@typescript-eslint/visitor-keys@npm:7.12.0" dependencies: - "@typescript-eslint/types": "npm:5.62.0" - eslint-visitor-keys: "npm:^3.3.0" - checksum: 10c0/7c3b8e4148e9b94d9b7162a596a1260d7a3efc4e65199693b8025c71c4652b8042501c0bc9f57654c1e2943c26da98c0f77884a746c6ae81389fcb0b513d995d + "@typescript-eslint/types": "npm:7.12.0" + eslint-visitor-keys: "npm:^3.4.3" + checksum: 10c0/f3aa6704961e65fa8d66fcde57cd28e382412bb8bec2e99312bf8cda38772ae9a74d6d95b9765f76a249bc9ab65624db34b8c00078ebad129b2e1b624e935d90 languageName: node linkType: hard @@ -3451,16 +3441,6 @@ __metadata: languageName: node linkType: hard -"eslint-scope@npm:^5.1.1": - version: 5.1.1 - resolution: "eslint-scope@npm:5.1.1" - dependencies: - esrecurse: "npm:^4.3.0" - estraverse: "npm:^4.1.1" - checksum: 10c0/d30ef9dc1c1cbdece34db1539a4933fe3f9b14e1ffb27ecc85987902ee663ad7c9473bbd49a9a03195a373741e62e2f807c4938992e019b511993d163450e70a - languageName: node - linkType: hard - "eslint-scope@npm:^7.2.2": version: 7.2.2 resolution: "eslint-scope@npm:7.2.2" @@ -3478,7 +3458,7 @@ __metadata: languageName: node linkType: hard -"eslint@npm:^8.23.0": +"eslint@npm:^8.57.0": version: 8.57.0 resolution: "eslint@npm:8.57.0" dependencies: @@ -3565,13 +3545,6 @@ __metadata: languageName: node linkType: hard -"estraverse@npm:^4.1.1": - version: 4.3.0 - resolution: "estraverse@npm:4.3.0" - checksum: 10c0/9cb46463ef8a8a4905d3708a652d60122a0c20bb58dec7e0e12ab0e7235123d74214fc0141d743c381813e1b992767e2708194f6f6e0f9fd00c1b4e0887b8b6d - languageName: node - linkType: hard - "estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": version: 5.3.0 resolution: "estraverse@npm:5.3.0" @@ -3868,8 +3841,8 @@ __metadata: "@types/bluebird": "npm:^3.5.36" "@types/lodash-es": "npm:^4.17.5" "@types/masonry-layout": "npm:^4.2.5" - "@typescript-eslint/eslint-plugin": "npm:^5.36.2" - "@typescript-eslint/parser": "npm:^5.36.2" + "@typescript-eslint/eslint-plugin": "npm:^7.12.0" + "@typescript-eslint/parser": "npm:^7.12.0" "@vitest/coverage-istanbul": "npm:^1.5.0" component-emitter: "npm:^1.3.0" crypto: "npm:^1.0.1" @@ -3878,7 +3851,7 @@ __metadata: docsify-cli: "npm:^4.4.4" embla-carousel: "npm:8.0.0-rc14" embla-carousel-wheel-gestures: "npm:8.0.0-rc04" - eslint: "npm:^8.23.0" + eslint: "npm:^8.57.0" eslint-config-airbnb-base: "npm:^15.0.0" eslint-config-prettier: "npm:^8.5.0" eslint-plugin-import: "npm:^2.25.4" @@ -3905,7 +3878,7 @@ __metadata: screenfull: "npm:^6.0.2" side-drawer: "npm:^3.1.0" ts-prune: "npm:^0.10.3" - typescript: "npm:^4.9.5" + typescript: "npm:^5.4.5" uuid: "npm:^8.3.2" vis-data: "npm:^7.1.9" vis-timeline: "npm:^7.7.3" @@ -4469,7 +4442,7 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.2.0": +"ignore@npm:^5.2.0, ignore@npm:^5.3.1": version: 5.3.1 resolution: "ignore@npm:5.3.1" checksum: 10c0/703f7f45ffb2a27fb2c5a8db0c32e7dee66b33a225d28e8db4e1be6474795f606686a6e3bcc50e1aa12f2042db4c9d4a7d60af3250511de74620fbed052ea4cd @@ -5680,6 +5653,15 @@ __metadata: languageName: node linkType: hard +"minimatch@npm:^9.0.4": + version: 9.0.4 + resolution: "minimatch@npm:9.0.4" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 10c0/2c16f21f50e64922864e560ff97c587d15fd491f65d92a677a344e970fe62aafdbeafe648965fa96d33c061b4d0eabfe0213466203dd793367e7f28658cf6414 + languageName: node + linkType: hard + "minimist@npm:^1.2.0, minimist@npm:^1.2.6": version: 1.2.8 resolution: "minimist@npm:1.2.8" @@ -5829,13 +5811,6 @@ __metadata: languageName: node linkType: hard -"natural-compare-lite@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare-lite@npm:1.4.0" - checksum: 10c0/f6cef26f5044515754802c0fc475d81426f3b90fe88c20fabe08771ce1f736ce46e0397c10acb569a4dd0acb84c7f1ee70676122f95d5bfdd747af3a6c6bbaa8 - languageName: node - linkType: hard - "natural-compare@npm:^1.4.0": version: 1.4.0 resolution: "natural-compare@npm:1.4.0" @@ -7444,7 +7419,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.3, semver@npm:^7.5.4": +"semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4": version: 7.6.0 resolution: "semver@npm:7.6.0" dependencies: @@ -7455,6 +7430,15 @@ __metadata: languageName: node linkType: hard +"semver@npm:^7.6.0": + version: 7.6.2 + resolution: "semver@npm:7.6.2" + bin: + semver: bin/semver.js + checksum: 10c0/97d3441e97ace8be4b1976433d1c32658f6afaff09f143e52c593bae7eef33de19e3e369c88bd985ce1042c6f441c80c6803078d1de2a9988080b66684cbb30c + languageName: node + linkType: hard + "send@npm:0.18.0": version: 0.18.0 resolution: "send@npm:0.18.0" @@ -8091,6 +8075,15 @@ __metadata: languageName: node linkType: hard +"ts-api-utils@npm:^1.3.0": + version: 1.3.0 + resolution: "ts-api-utils@npm:1.3.0" + peerDependencies: + typescript: ">=4.2.0" + checksum: 10c0/f54a0ba9ed56ce66baea90a3fa087a484002e807f28a8ccb2d070c75e76bde64bd0f6dce98b3802834156306050871b67eec325cb4e918015a360a3f0868c77c + languageName: node + linkType: hard + "ts-essentials@npm:^9.3.2": version: 9.4.1 resolution: "ts-essentials@npm:9.4.1" @@ -8141,13 +8134,6 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^1.8.1": - version: 1.14.1 - resolution: "tslib@npm:1.14.1" - checksum: 10c0/69ae09c49eea644bc5ebe1bca4fa4cc2c82b7b3e02f43b84bd891504edf66dbc6b2ec0eef31a957042de2269139e4acff911e6d186a258fb14069cd7f6febce2 - languageName: node - linkType: hard - "tslib@npm:^2.0.1, tslib@npm:^2.1.0, tslib@npm:^2.3.1": version: 2.6.2 resolution: "tslib@npm:2.6.2" @@ -8155,17 +8141,6 @@ __metadata: languageName: node linkType: hard -"tsutils@npm:^3.21.0": - version: 3.21.0 - resolution: "tsutils@npm:3.21.0" - dependencies: - tslib: "npm:^1.8.1" - peerDependencies: - typescript: ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - checksum: 10c0/02f19e458ec78ead8fffbf711f834ad8ecd2cc6ade4ec0320790713dccc0a412b99e7fd907c4cda2a1dc602c75db6f12e0108e87a5afad4b2f9e90a24cabd5a2 - languageName: node - linkType: hard - "tweezer.js@npm:^1.4.0": version: 1.5.0 resolution: "tweezer.js@npm:1.5.0" @@ -8264,7 +8239,7 @@ __metadata: languageName: node linkType: hard -"typescript@npm:^4.5.4, typescript@npm:^4.9.5": +"typescript@npm:^4.5.4": version: 4.9.5 resolution: "typescript@npm:4.9.5" bin: @@ -8274,7 +8249,17 @@ __metadata: languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^4.5.4#optional!builtin, typescript@patch:typescript@npm%3A^4.9.5#optional!builtin": +"typescript@npm:^5.4.5": + version: 5.4.5 + resolution: "typescript@npm:5.4.5" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/2954022ada340fd3d6a9e2b8e534f65d57c92d5f3989a263754a78aba549f7e6529acc1921913560a4b816c46dce7df4a4d29f9f11a3dc0d4213bb76d043251e + languageName: node + linkType: hard + +"typescript@patch:typescript@npm%3A^4.5.4#optional!builtin": version: 4.9.5 resolution: "typescript@patch:typescript@npm%3A4.9.5#optional!builtin::version=4.9.5&hash=289587" bin: @@ -8284,6 +8269,16 @@ __metadata: languageName: node linkType: hard +"typescript@patch:typescript@npm%3A^5.4.5#optional!builtin": + version: 5.4.5 + resolution: "typescript@patch:typescript@npm%3A5.4.5#optional!builtin::version=5.4.5&hash=5adc0c" + bin: + tsc: bin/tsc + tsserver: bin/tsserver + checksum: 10c0/db2ad2a16ca829f50427eeb1da155e7a45e598eec7b086d8b4e8ba44e5a235f758e606d681c66992230d3fc3b8995865e5fd0b22a2c95486d0b3200f83072ec9 + languageName: node + linkType: hard + "ufo@npm:^1.3.2": version: 1.4.0 resolution: "ufo@npm:1.4.0" From 027e13d5607f23856ff6353007be7296dd29b7e8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 03:29:17 +0000 Subject: [PATCH 137/189] Bump crazy-max/ghaction-github-labeler from 4.1.0 to 5.0.0 Bumps [crazy-max/ghaction-github-labeler](https://github.com/crazy-max/ghaction-github-labeler) from 4.1.0 to 5.0.0. - [Release notes](https://github.com/crazy-max/ghaction-github-labeler/releases) - [Commits](https://github.com/crazy-max/ghaction-github-labeler/compare/v4.1.0...v5.0.0) --- updated-dependencies: - dependency-name: crazy-max/ghaction-github-labeler dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/labeler.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index d41c81aa..d6e56abb 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -16,6 +16,6 @@ jobs: uses: actions/checkout@v4 - name: Run Labeler - uses: crazy-max/ghaction-github-labeler@v4.1.0 + uses: crazy-max/ghaction-github-labeler@v5.0.0 with: skip-delete: true From 7ab545738dc037dc00e6ff577d3a0b25d97f6b6b Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 5 Jun 2024 21:39:52 -0700 Subject: [PATCH 138/189] Add initial keyboard shortcut support. --- docs/configuration/README.md | 2 +- docs/configuration/_sidebar.md | 32 +- docs/configuration/actions.md | 553 ----------- docs/configuration/actions/README.md | 73 ++ docs/configuration/actions/_sidebar.md | 27 + docs/configuration/actions/custom/README.md | 737 ++++++++++++++ docs/configuration/actions/custom/_sidebar.md | 27 + docs/configuration/actions/stock/README.md | 120 +++ docs/configuration/actions/stock/_sidebar.md | 27 + docs/configuration/automations.md | 6 +- docs/configuration/cameras/README.md | 117 ++- docs/configuration/cameras/_sidebar.md | 36 +- docs/configuration/conditions.md | 29 +- docs/configuration/elements.md | 8 +- docs/configuration/image.md | 6 +- docs/configuration/live.md | 85 +- docs/configuration/media-gallery.md | 2 +- docs/configuration/media-viewer.md | 35 +- docs/configuration/menu.md | 20 +- docs/configuration/view.md | 38 +- docs/examples.md | 49 +- docs/usage/_sidebar.md | 7 +- docs/usage/keyboard-shortcuts.md | 18 + docs/usage/url-actions.md | 6 +- package.json | 3 +- src/action-handler-directive.ts | 18 +- .../browse-media/engine-browse-media.ts | 2 + src/camera-manager/camera.ts | 2 +- src/camera-manager/capabilities.ts | 12 + src/camera-manager/engine.ts | 5 +- src/camera-manager/frigate/camera.ts | 34 +- src/camera-manager/frigate/engine-frigate.ts | 13 +- src/camera-manager/generic/engine-generic.ts | 9 +- src/camera-manager/manager.ts | 26 +- src/camera-manager/utils/ptz.ts | 82 ++ src/card-controller/actions-manager.ts | 285 ------ .../actions/actions-manager.ts | 121 +++ src/card-controller/actions/actions/base.ts | 29 + .../actions/actions/camera-select.ts | 26 + .../actions/actions/camera-ui.ts | 9 + .../actions/actions/default.ts | 9 + .../actions/actions/display-mode-select.ts | 9 + .../actions/actions/download.ts | 9 + src/card-controller/actions/actions/expand.ts | 9 + .../actions/actions/fullscreen.ts | 9 + .../actions/actions/generic.ts | 20 + src/card-controller/actions/actions/log.ts | 10 + .../actions/actions/media-player.ts | 21 + .../actions/actions/menu-toggle.ts | 9 + .../actions/actions/microphone-mute.ts | 9 + .../actions/actions/microphone-unmute.ts | 9 + src/card-controller/actions/actions/mute.ts | 9 + src/card-controller/actions/actions/pause.ts | 9 + src/card-controller/actions/actions/play.ts | 9 + .../actions/actions/ptz-controls.ts | 11 + .../actions/actions/ptz-digital.ts | 126 +++ .../actions/actions/ptz-multi.ts | 60 ++ src/card-controller/actions/actions/ptz.ts | 121 +++ .../actions/actions/screenshot.ts | 9 + src/card-controller/actions/actions/set.ts | 44 + src/card-controller/actions/actions/sleep.ts | 12 + .../actions/actions/substream-off.ts | 9 + .../actions/actions/substream-on.ts | 9 + .../actions/actions/substream-select.ts | 9 + src/card-controller/actions/actions/unmute.ts | 9 + src/card-controller/actions/actions/view.ts | 16 + src/card-controller/actions/factory.ts | 133 +++ src/card-controller/actions/types.ts | 23 + .../actions/utils/action-state.ts | 25 + .../actions/utils/execution-request.ts | 38 + .../actions/utils/time-delta.ts | 10 + src/card-controller/automations-manager.ts | 53 +- src/card-controller/card-element-manager.ts | 31 +- src/card-controller/conditions-manager.ts | 21 +- .../{ => config}/config-manager.ts | 21 +- .../config/load-automations.ts | 8 + .../config/load-keyboard-shortcuts.ts | 130 +++ src/card-controller/controller.ts | 12 +- src/card-controller/keyboard-state-manager.ts | 59 ++ src/card-controller/query-string-manager.ts | 24 +- src/card-controller/types.ts | 56 +- src/card.ts | 1 + src/components-lib/key-assigner-controller.ts | 83 ++ src/components-lib/live/live-controller.ts | 1 - src/components-lib/menu-button-controller.ts | 167 ++-- src/components-lib/menu-controller.ts | 12 +- src/components-lib/ptz-controller.ts | 170 ---- src/components-lib/ptz/ptz-controller.ts | 145 +++ src/components-lib/ptz/types.ts | 21 + src/components-lib/zoom/types.ts | 30 +- src/components-lib/zoom/zoom-controller.ts | 134 ++- src/components-lib/zoom/zoom-view-context.ts | 39 +- src/components/image.ts | 100 +- src/components/key-assigner.ts | 93 ++ src/components/live/live.ts | 50 +- src/components/menu.ts | 15 +- src/components/ptz.ts | 90 +- src/components/viewer.ts | 24 +- src/components/views.ts | 2 +- src/components/zoomer.ts | 18 +- src/config/keyboard-shortcuts.ts | 47 + src/config/management.ts | 118 ++- src/config/ptz.ts | 12 + src/config/types.ts | 391 +++++--- src/const.ts | 20 +- src/declarations.d.ts | 4 + src/editor.ts | 74 +- src/localize/languages/ca.json | 21 +- src/localize/languages/en.json | 26 +- src/localize/languages/fr.json | 21 +- src/localize/languages/it.json | 21 +- src/localize/languages/pt-BR.json | 21 +- src/localize/languages/pt-PT.json | 21 +- src/scss/card.scss | 3 + src/scss/key-assigner.scss | 79 ++ src/types.ts | 9 +- src/utils/action.ts | 179 ++-- src/utils/basic.ts | 13 +- src/utils/ha/index.ts | 21 +- src/utils/ptz.ts | 86 +- src/utils/substream.ts | 4 +- src/view/view.ts | 12 +- tests/camera-manager/capabilities.test.ts | 4 +- tests/camera-manager/frigate/camera.test.ts | 19 +- .../frigate/engine-frigate.test.ts | 2 +- tests/camera-manager/manager.test.ts | 47 +- tests/camera-manager/utils/ptz.test.ts | 191 ++++ tests/card-controller/actions-manager.test.ts | 914 ------------------ .../actions/actions-manager.test.ts | 289 ++++++ .../actions/actions/base.test.ts | 19 + .../actions/actions/camera-select.test.ts | 163 ++++ .../actions/actions/camera-ui.test.ts | 18 + .../actions/actions/default.test.ts | 15 + .../actions/display-mode-select.test.ts | 16 + .../actions/actions/download.test.ts | 18 + .../actions/actions/expand.test.ts | 18 + .../actions/actions/fullscreen.test.ts | 18 + .../actions/actions/generic.test.ts | 46 + .../actions/actions/log.test.ts | 24 + .../actions/actions/media-player.test.ts | 104 ++ .../actions/actions/menu-toggle.test.ts | 18 + .../actions/actions/microphone-mute.test.ts | 18 + .../actions/actions/microphone-unmute.test.ts | 18 + .../actions/actions/mute.test.ts | 26 + .../actions/actions/pause.test.ts | 26 + .../actions/actions/play.test.ts | 26 + .../actions/actions/ptz-controls.test.ts | 21 + .../actions/actions/ptz-digital.test.ts | 479 +++++++++ .../actions/actions/ptz-multi.test.ts | 150 +++ .../actions/actions/ptz.test.ts | 513 ++++++++++ .../actions/actions/screenshot.test.ts | 18 + .../actions/actions/set.test.ts | 41 + .../actions/actions/sleep.test.ts | 29 + .../actions/actions/substream-off.test.ts | 18 + .../actions/actions/substream-on.test.ts | 18 + .../actions/actions/substream-select.test.ts | 19 + .../actions/actions/unmute.test.ts | 26 + .../actions/actions/view.test.ts | 36 + tests/card-controller/actions/factory.test.ts | 138 +++ .../actions/utils/time-delta.test.ts | 20 + .../automations-manager.test.ts | 120 +-- .../card-element-manager.test.ts | 8 +- .../conditions-manager.test.ts | 55 ++ .../{ => config}/config-manager.test.ts | 14 +- .../config/load-automations.test.ts | 38 + .../config/load-keyboard-shortcuts.test.ts | 143 +++ tests/card-controller/controller.test.ts | 18 +- .../keyboard-state-manager.test.ts | 86 ++ .../query-string-manager.test.ts | 32 +- .../key-assigner-controller.test.ts | 131 +++ .../menu-button-controller.test.ts | 136 +-- tests/components-lib/menu-controller.test.ts | 60 +- tests/components-lib/ptz-controller.test.ts | 316 ------ .../components-lib/ptz/ptz-controller.test.ts | 378 ++++++++ .../zoom/zoom-controller.test.ts | 119 ++- .../zoom/zoom-view-context.test.ts | 90 +- tests/config/management.test.ts | 774 +++++++++++++-- tests/config/types.test.ts | 213 +++- tests/test-utils.ts | 30 +- tests/utils/action.test.ts | 241 +++-- tests/utils/basic.test.ts | 48 + tests/utils/ptz.test.ts | 178 +++- tests/utils/substream.test.ts | 13 + tsconfig.json | 10 +- vite.config.ts | 5 +- yarn.lock | 20 +- 186 files changed, 9564 insertions(+), 3658 deletions(-) delete mode 100644 docs/configuration/actions.md create mode 100644 docs/configuration/actions/README.md create mode 100644 docs/configuration/actions/_sidebar.md create mode 100644 docs/configuration/actions/custom/README.md create mode 100644 docs/configuration/actions/custom/_sidebar.md create mode 100644 docs/configuration/actions/stock/README.md create mode 100644 docs/configuration/actions/stock/_sidebar.md create mode 100644 docs/usage/keyboard-shortcuts.md create mode 100644 src/camera-manager/utils/ptz.ts delete mode 100644 src/card-controller/actions-manager.ts create mode 100644 src/card-controller/actions/actions-manager.ts create mode 100644 src/card-controller/actions/actions/base.ts create mode 100644 src/card-controller/actions/actions/camera-select.ts create mode 100644 src/card-controller/actions/actions/camera-ui.ts create mode 100644 src/card-controller/actions/actions/default.ts create mode 100644 src/card-controller/actions/actions/display-mode-select.ts create mode 100644 src/card-controller/actions/actions/download.ts create mode 100644 src/card-controller/actions/actions/expand.ts create mode 100644 src/card-controller/actions/actions/fullscreen.ts create mode 100644 src/card-controller/actions/actions/generic.ts create mode 100644 src/card-controller/actions/actions/log.ts create mode 100644 src/card-controller/actions/actions/media-player.ts create mode 100644 src/card-controller/actions/actions/menu-toggle.ts create mode 100644 src/card-controller/actions/actions/microphone-mute.ts create mode 100644 src/card-controller/actions/actions/microphone-unmute.ts create mode 100644 src/card-controller/actions/actions/mute.ts create mode 100644 src/card-controller/actions/actions/pause.ts create mode 100644 src/card-controller/actions/actions/play.ts create mode 100644 src/card-controller/actions/actions/ptz-controls.ts create mode 100644 src/card-controller/actions/actions/ptz-digital.ts create mode 100644 src/card-controller/actions/actions/ptz-multi.ts create mode 100644 src/card-controller/actions/actions/ptz.ts create mode 100644 src/card-controller/actions/actions/screenshot.ts create mode 100644 src/card-controller/actions/actions/set.ts create mode 100644 src/card-controller/actions/actions/sleep.ts create mode 100644 src/card-controller/actions/actions/substream-off.ts create mode 100644 src/card-controller/actions/actions/substream-on.ts create mode 100644 src/card-controller/actions/actions/substream-select.ts create mode 100644 src/card-controller/actions/actions/unmute.ts create mode 100644 src/card-controller/actions/actions/view.ts create mode 100644 src/card-controller/actions/factory.ts create mode 100644 src/card-controller/actions/types.ts create mode 100644 src/card-controller/actions/utils/action-state.ts create mode 100644 src/card-controller/actions/utils/execution-request.ts create mode 100644 src/card-controller/actions/utils/time-delta.ts rename src/card-controller/{ => config}/config-manager.ts (85%) create mode 100644 src/card-controller/config/load-automations.ts create mode 100644 src/card-controller/config/load-keyboard-shortcuts.ts create mode 100644 src/card-controller/keyboard-state-manager.ts create mode 100644 src/components-lib/key-assigner-controller.ts delete mode 100644 src/components-lib/ptz-controller.ts create mode 100644 src/components-lib/ptz/ptz-controller.ts create mode 100644 src/components-lib/ptz/types.ts create mode 100644 src/components/key-assigner.ts create mode 100644 src/config/keyboard-shortcuts.ts create mode 100644 src/config/ptz.ts create mode 100644 src/scss/key-assigner.scss create mode 100644 tests/camera-manager/utils/ptz.test.ts delete mode 100644 tests/card-controller/actions-manager.test.ts create mode 100644 tests/card-controller/actions/actions-manager.test.ts create mode 100644 tests/card-controller/actions/actions/base.test.ts create mode 100644 tests/card-controller/actions/actions/camera-select.test.ts create mode 100644 tests/card-controller/actions/actions/camera-ui.test.ts create mode 100644 tests/card-controller/actions/actions/default.test.ts create mode 100644 tests/card-controller/actions/actions/display-mode-select.test.ts create mode 100644 tests/card-controller/actions/actions/download.test.ts create mode 100644 tests/card-controller/actions/actions/expand.test.ts create mode 100644 tests/card-controller/actions/actions/fullscreen.test.ts create mode 100644 tests/card-controller/actions/actions/generic.test.ts create mode 100644 tests/card-controller/actions/actions/log.test.ts create mode 100644 tests/card-controller/actions/actions/media-player.test.ts create mode 100644 tests/card-controller/actions/actions/menu-toggle.test.ts create mode 100644 tests/card-controller/actions/actions/microphone-mute.test.ts create mode 100644 tests/card-controller/actions/actions/microphone-unmute.test.ts create mode 100644 tests/card-controller/actions/actions/mute.test.ts create mode 100644 tests/card-controller/actions/actions/pause.test.ts create mode 100644 tests/card-controller/actions/actions/play.test.ts create mode 100644 tests/card-controller/actions/actions/ptz-controls.test.ts create mode 100644 tests/card-controller/actions/actions/ptz-digital.test.ts create mode 100644 tests/card-controller/actions/actions/ptz-multi.test.ts create mode 100644 tests/card-controller/actions/actions/ptz.test.ts create mode 100644 tests/card-controller/actions/actions/screenshot.test.ts create mode 100644 tests/card-controller/actions/actions/set.test.ts create mode 100644 tests/card-controller/actions/actions/sleep.test.ts create mode 100644 tests/card-controller/actions/actions/substream-off.test.ts create mode 100644 tests/card-controller/actions/actions/substream-on.test.ts create mode 100644 tests/card-controller/actions/actions/substream-select.test.ts create mode 100644 tests/card-controller/actions/actions/unmute.test.ts create mode 100644 tests/card-controller/actions/actions/view.test.ts create mode 100644 tests/card-controller/actions/factory.test.ts create mode 100644 tests/card-controller/actions/utils/time-delta.test.ts rename tests/card-controller/{ => config}/config-manager.test.ts (94%) create mode 100644 tests/card-controller/config/load-automations.test.ts create mode 100644 tests/card-controller/config/load-keyboard-shortcuts.test.ts create mode 100644 tests/card-controller/keyboard-state-manager.test.ts create mode 100644 tests/components-lib/key-assigner-controller.test.ts delete mode 100644 tests/components-lib/ptz-controller.test.ts create mode 100644 tests/components-lib/ptz/ptz-controller.test.ts diff --git a/docs/configuration/README.md b/docs/configuration/README.md index 7104216b..5cc275de 100644 --- a/docs/configuration/README.md +++ b/docs/configuration/README.md @@ -39,5 +39,5 @@ Only the `cameras` option is required, all other parameters are optional. | Option | Description | | - | - | -| [`actions`](actions.md) | Configure actions. | +| [`actions`](actions/README.md) | Configure actions. | | [`conditions`](conditions.md) | Configure conditions. | diff --git a/docs/configuration/_sidebar.md b/docs/configuration/_sidebar.md index c07b3bbb..8bbd9965 100644 --- a/docs/configuration/_sidebar.md +++ b/docs/configuration/_sidebar.md @@ -1,21 +1,21 @@ * [Getting Started](../README.md) * [Configuration](README.md) - * [`actions`](actions.md) - * [`automations`](automations.md) - * [`cameras`](cameras/README.md) - * [`conditions`](conditions.md) - * [`dimensions`](dimensions.md) - * [`elements`](elements.md) - * [`image`](image.md) - * [`live`](live.md) - * [`media_gallery`](media-gallery.md) - * [`media_viewer`](media-viewer.md) - * [`menu`](menu.md) - * [`overrides`](overrides.md) - * [`performance`](performance.md) - * [`profiles`](profiles.md) - * [`timeline`](timeline.md) - * [`view`](view.md) + * [`actions`](actions/README.md) + * [`automations`](automations.md) + * [`cameras`](cameras/README.md) + * [`conditions`](conditions.md) + * [`dimensions`](dimensions.md) + * [`elements`](elements.md) + * [`image`](image.md) + * [`live`](live.md) + * [`media_gallery`](media-gallery.md) + * [`media_viewer`](media-viewer.md) + * [`menu`](menu.md) + * [`overrides`](overrides.md) + * [`performance`](performance.md) + * [`profiles`](profiles.md) + * [`timeline`](timeline.md) + * [`view`](view.md) * [Examples](../examples.md) * [Screenshots](../screenshots.md) * [Troubleshooting](../troubleshooting.md) diff --git a/docs/configuration/actions.md b/docs/configuration/actions.md deleted file mode 100644 index b371f765..00000000 --- a/docs/configuration/actions.md +++ /dev/null @@ -1,553 +0,0 @@ -# `actions` - -## Introduction to actions - -`actions` is not a top-level configuration block, but can be used as part of -multiple other blocks. - -Actions are pre-configured activities that can be triggered in response to a -variety of circumstances (e.g. tapping on a menu icon, double tapping on an -[element](./elements.md) or holding the mouse/tap down on a particular -[view](./view.md?id=supported-views)). - -### Differences in actions between Frigate Card and Home Assistant - -Both the Home Assistant frontend and the Frigate card cooperate to provide -action functionality. In general, the Frigate Card functionality is a superset -of that offered by stock Home Assistant. - -Stock action functionality is used for Stock [Home Assistant picture -elements](https://www.home-assistant.io/lovelace/picture-elements/). Extended -Frigate card behavior covers all other interactions on the Frigate card (e.g. -menu icon elements, submenus and actions on the card or views). - -#### Custom action types: `start_tap` and `end_tap` - -The card has partial support for two special action types `start_tap` and -`end_tap` which occur when a tap is started (e.g. mouse is pressed down / -touch begins), and ended (e.g. mouse released / touch ends) respectively. This -might be useful for PTZ cameras cameras to start/stop movement on touch. Network -latency may introduce unavoidable imprecision between `end_tap` and action -actually occurring. - -#### Multiple actions - -Extended Frigate card behavior supports a list of actions instead of a single -action, all of which will be handled. See [an example of multiple -actions](../examples.md?id=multiple-actions). - -## Card and view actions - -Actions may be attached to the card itself, to trigger action when the card -experiences a `tap`, `double_tap`, `hold`, `start_tap` or `end_tap` event. -Alternatively they can be configured on a per group-of-views basis, e.g. only -when `live` view is tapped. - -| Configuration path | Views to which it refers | -| - | - | -| `image.actions` | `image` | -| `live.actions` | `live` | -| `media_gallery.actions` | `clips`, `snapshots`, `recordings` | -| `media_viewer.actions` | `clip`, `snapshot`, `recording` | -| `view.actions` | All | - -If an action is configured for both the whole card (`view.actions`) and a more -specific view (e.g. `live.actions`) then the actions are merged, with the more -specific overriding the less specific. - -!> The card itself relies on user interactions to function (e.g. `tap` on -the menu should activate that button). Card or View actions are prevented from -being activated through standard interaction with menu buttons, next/previous -controls, thumbnails, etc, but in some cases this prevention is not possible -(e.g. embedded WebRTC card controls) -- in these cases duplicate actions may -occur with certain configurations (e.g. `tap`). - -!> Card-wide actions are not supported on timelines nor when a info/error message -is being displayed. - -## `call-service` - -Call a service. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). - -```yaml -action: call-service -[...] -``` - -## `custom:frigate-card-action` - -Execute a Frigate Card action. - -```yaml -action: custom:frigate-card-action -[...] -``` - -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | A supported Frigate Card action. See below. | - -### `camera_select` - -Select a given camera. - -```yaml -action: custom:frigate-card-action -frigate_card_action: camera_select -[...] -``` - -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `camera_select`. | -| `camera` | The [camera ID](cameras/README.md?id=cameras) of the camera to select. | -| `triggered` | If `true` instead of `camera` being specified then a triggered camera (if any) is selected instead. | - -This action will respect the value of the `view.camera_select` to choose the appropriate view on the new camera. See [`view` configuration](view.md). - -### `camera_ui` - -Download the displayed media. - -```yaml -action: custom:frigate-card-action -frigate_card_action: camera_ui -``` - -Open the UI for the selected camera engine (e.g. the Frigate UI). - -### `change_zoom` - -Zoom in and/or pan for a given camera. - -```yaml -action: custom:frigate-card-action -frigate_card_action: change_zoom -[...] -``` - -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `change_zoom`. | -| `target_id` | The [camera ID](cameras/README.md?id=cameras) or a media ID (e.g. `frigate` event ID) to change zoom/pam settings for. | -| `zoom` | Optional parameter that controls how much to zoom-in. See the [camera zoom parameter](cameras/README.md?id=layout-configuration). | -| `pan` | Optional parameter that controls how much to pan-x/y. See the [camera pan parameter](cameras/README.md?id=layout-configuration). | - -?> If neither `zoom` nor `pan` are specified the camera will return to its default zoom and pan settings. - -See [example of automatically zoom/panning based on state](../examples.md?id=automatically-zoom-based-on-state). - -### `clip`, `clips`, `image`, `live`, `recording`, `recordings`, `snapshot`, `snapshots` - -Change to the specified view. - -```yaml -action: custom:frigate-card-action -frigate_card_action: [view] -``` - -### `default` - -Change to the default view. - -```yaml -action: custom:frigate-card-action -frigate_card_action: default -``` - -### `download` - -Download the displayed media. - -```yaml -action: custom:frigate-card-action -frigate_card_action: download -``` - -### `expand` - -Expand the card into a dialog/popup. - -```yaml -action: custom:frigate-card-action -frigate_card_action: expand -``` - -### `fullscreen` - -Toggle fullscreen. - -```yaml -action: custom:frigate-card-action -frigate_card_action: fullscreen -``` - -### `live_substream_select` - -Select a substream. - -```yaml -action: custom:frigate-card-action -frigate_card_action: live_substream_select -[...] -``` - -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `live_substream_select`. | -| `camera` | The [camera ID](cameras/README.md?id=cameras) of the substream to select. | - -### `media_player` - -Perform a media player action. - -```yaml -action: custom:frigate-card-action -frigate_card_action: media_player -[...] -``` - -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `media_player`. | -| `media_player` | The entity ID of the media_player on which to perform the action. | -| `media_player_action` | Either `play` or `stop` to play or stop the media in question. | - -### `menu_toggle` - -Show/hide the menu (for the `hidden` mode style). - -```yaml -action: custom:frigate-card-action -frigate_card_action: menu_toggle -``` - -### `microphone_mute`, `microphone_unmute` - -Mute/Unmute the microphone during [2-way audio](../usage/2-way-audio.md). - -```yaml -action: custom:frigate-card-action -frigate_card_action: microphone_mute -``` - -```yaml -action: custom:frigate-card-action -frigate_card_action: microphone_unmute -``` - -### `mute`, `unmute` - -Mute/Unmute the selected media. - -```yaml -action: custom:frigate-card-action -frigate_card_action: mute -``` - -```yaml -action: custom:frigate-card-action -frigate_card_action: unmute -``` - -### `play`, `pause` - -Play/Pause the selected media. - -```yaml -action: custom:frigate-card-action -frigate_card_action: play -``` - -```yaml -action: custom:frigate-card-action -frigate_card_action: pause -``` - -### `ptz` - -Execute a native PTZ action (only for native out-of-the-box PTZ camera engines, e.g. Frigate). - - Takes a required `ptz_action` parameter that is one of . - -```yaml -action: custom:frigate-card-action -frigate_card_action: ptz -[...] -``` - -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `ptz`. | -| `ptz_action` | One of `left`, `right`, `up`, `down`, `zoom_in`, `zoom_out` or `preset`. | -| `ptz_phase` | Optional parameter that is one of `start` or `stop` to start or stop the movement separately. | -| `ptz_preset` | Optional preset to execute when the `ptz_action` is `preset`. | - -### `screenshot` - -Take a screenshot of the selected media (e.g. a still from a video). - -```yaml -action: custom:frigate-card-action -frigate_card_action: screenshot -``` - -### `show_ptz` - -Show or hide the PTZ controls. - -```yaml -action: custom:frigate-card-action -frigate_card_action: show_ptz -[...] -``` - -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `show_ptz`. | -| `show_ptz` | If `true` shows the PTZ controls, if `false` hides them. | - -## `more-info` - -Open the "more-info" dialog for an entity. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). - -```yaml -action: more-info -[...] -``` - -## `navigate` - -Navigate to a particular dashboard path. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). - -```yaml -action: navigate -[...] -``` - -## `toggle` - -Toggle an entity. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). - -```yaml -action: toggle -[...] -``` - -## `url` - -Navigate to an arbitrary URL. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). - -```yaml -action: url -[...] -``` - -## Fully expanded reference - -[](common/expanded-warning.md ':include') - -### Stock Home Assistant actions - -Reference: [Home Assistant Actions](https://www.home-assistant.io/dashboards/actions/). - -```yaml -elements: - - type: icon - icon: mdi:numeric-1-box - title: More info action - style: - left: 200px - top: 50px - entity: light.office_main_lights - tap_action: - action: more-info - - type: icon - icon: mdi:numeric-2-box - title: Toggle action - style: - left: 200px - top: 100px - entity: light.office_main_lights - tap_action: - action: toggle - - type: icon - icon: mdi:numeric-3-box - title: Call Service action - style: - left: 200px - top: 150px - tap_action: - action: call-service - service: homeassistant.toggle - service_data: - entity_id: light.office_main_lights - - type: icon - icon: mdi:numeric-4-box - title: Navigate action - style: - left: 200px - top: 200px - tap_action: - action: navigate - navigation_path: /lovelace/2 - - type: icon - icon: mdi:numeric-5-box - title: URL action - style: - left: 200px - top: 250px - tap_action: - action: url - url_path: https://www.home-assistant.io/ - - type: icon - icon: mdi:numeric-6-box - title: None action - style: - left: 200px - top: 300px - tap_action: - action: none - - type: icon - icon: mdi:numeric-7-box - title: Custom action - style: - left: 200px - top: 350px - tap_action: - action: fire-dom-event - key: value -``` - -### Frigate Card actions - -```yaml -elements: - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-a-circle - title: Show default view - tap_action: - action: custom:frigate-card-action - frigate_card_action: default - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-b-circle - title: Show most recent clip - tap_action: - action: custom:frigate-card-action - frigate_card_action: clip - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-c-circle - title: Show clips - tap_action: - action: custom:frigate-card-action - frigate_card_action: clips - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-d-circle - title: Show image view - tap_action: - action: custom:frigate-card-action - frigate_card_action: image - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-e-circle - title: Show live view - tap_action: - action: custom:frigate-card-action - frigate_card_action: live - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-f-circle - title: Show most recent snapshot - tap_action: - action: custom:frigate-card-action - frigate_card_action: snapshot - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-g-circle - title: Show snapshots - tap_action: - action: custom:frigate-card-action - frigate_card_action: snapshots - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-h-circle - title: Download media - tap_action: - action: custom:frigate-card-action - frigate_card_action: download - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-i-circle - title: Open Frigate UI - tap_action: - action: custom:frigate-card-action - frigate_card_action: camera_ui - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-j-circle - title: Change to fullscreen - tap_action: - action: custom:frigate-card-action - frigate_card_action: fullscreen - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-k-circle - title: Toggle hidden menu - tap_action: - action: custom:frigate-card-action - frigate_card_action: menu_toggle - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-l-circle - title: Select Front Door - tap_action: - action: custom:frigate-card-action - frigate_card_action: camera_select - camera: camera.front_door - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-m-circle - title: Media player play - tap_action: - action: custom:frigate-card-action - frigate_card_action: media_player - media_player: media_player.nesthub50be - media_player_action: play - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-n-circle - title: Media player stop - tap_action: - action: custom:frigate-card-action - frigate_card_action: media_player - media_player: media_player.nesthub - media_player_action: stop - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-o-circle - title: Screenshot - tap_action: - action: custom:frigate-card-action - frigate_card_action: screenshot - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-p-circle - title: Show PTZ - tap_action: - action: custom:frigate-card-action - frigate_card_action: show_ptz - show_ptz: true - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-q-circle - title: Native PTZ Preset - tap_action: - action: custom:frigate-card-action - frigate_card_action: ptz - ptz_action: preset - ptz_preset: doorway - - type: custom:frigate-card-menu-icon - icon: mdi:alpha-r-circle - title: Change Zoom - tap_action: - action: custom:frigate-card-action - frigate_card_action: change_zoom - pan: - x: 50 - y: 50 - zoom: 1 -``` diff --git a/docs/configuration/actions/README.md b/docs/configuration/actions/README.md new file mode 100644 index 00000000..1853b004 --- /dev/null +++ b/docs/configuration/actions/README.md @@ -0,0 +1,73 @@ +# `actions` + +## Introduction to actions + +`actions` is not a top-level configuration block, but can be used as part of +multiple other blocks. + +Actions are pre-configured activities that can be triggered in response to a +variety of circumstances (e.g. tapping on a menu icon, double tapping on an +[element](../elements.md) or holding the mouse/tap down on a particular +[view](../view.md?id=supported-views)). + +### Differences in actions between Frigate Card and Home Assistant + +Both the Home Assistant frontend and the Frigate card cooperate to provide +action functionality. In general, the Frigate Card functionality is a superset +of that offered by stock Home Assistant. + +Stock action functionality is used for Stock [Home Assistant picture +elements](https://www.home-assistant.io/lovelace/picture-elements/). Extended +Frigate card behavior covers all other interactions on the Frigate card (e.g. +menu icon elements, submenus and actions on the card or views). + +#### Custom action types: `start_tap` and `end_tap` + +The card has partial support for two special action types `start_tap` and +`end_tap` which occur when a tap is started (e.g. mouse is pressed down / +touch begins), and ended (e.g. mouse released / touch ends) respectively. This +might be useful for PTZ cameras cameras to start/stop movement on touch. Network +latency may introduce unavoidable imprecision between `end_tap` and action +actually occurring. + +#### Multiple actions + +Extended Frigate card behavior supports a list of actions instead of a single +action, all of which will be handled. See [an example of multiple +actions](../../examples.md?id=multiple-actions). + +## Card and view actions + +Actions may be attached to the card itself, to trigger action when the card +experiences a `tap`, `double_tap`, `hold`, `start_tap` or `end_tap` event. +Alternatively they can be configured on a per group-of-views basis, e.g. only +when `live` view is tapped. + +| Configuration path | Views to which it refers | +| ----------------------- | ---------------------------------- | +| `image.actions` | `image` | +| `live.actions` | `live` | +| `media_gallery.actions` | `clips`, `snapshots`, `recordings` | +| `media_viewer.actions` | `clip`, `snapshot`, `recording` | +| `view.actions` | All except `timeline` and `diagnostic` | + +If an action is configured for both the whole card (`view.actions`) and a more +specific view (e.g. `live.actions`) then the actions are merged, with the more +specific overriding the less specific. + +!> The card itself relies on user interactions to function (e.g. `tap` on +the menu should activate that button). Card or View actions are prevented from +being activated through standard interaction with menu buttons, next/previous +controls, thumbnails, etc, but in some cases this prevention is not possible +(e.g. embedded WebRTC card controls) -- in these cases duplicate actions may +occur with certain configurations (e.g. `tap`). + +!> Card-wide actions are not supported on the `timeline` view, `diagnostics` +view nor when a info/error message is being displayed. + +## Actions + +| Option | Description | +| ------------------------------------ | ----------------------------------- | +| [Custom Actions](./custom/README.md) | Custom actions to control the card. | +| [Stock Actions](./stock/README.md) | Standard Home Assistant actions. | diff --git a/docs/configuration/actions/_sidebar.md b/docs/configuration/actions/_sidebar.md new file mode 100644 index 00000000..04802078 --- /dev/null +++ b/docs/configuration/actions/_sidebar.md @@ -0,0 +1,27 @@ +* [Getting Started](../../README.md) +* [Configuration](../README.md) + * [`actions`](README.md) + * [Custom Actions](./custom/README.md) + * [Stock Actions](./stock/README.md) + * [`automations`](../automations.md) + * [`cameras`](../cameras/README.md) + * [`conditions`](../conditions.md) + * [`dimensions`](../dimensions.md) + * [`elements`](../elements.md) + * [`image`](../image.md) + * [`live`](../live.md) + * [`media_gallery`](../media-gallery.md) + * [`media_viewer`](../media-viewer.md) + * [`menu`](../menu.md) + * [`overrides`](../overrides.md) + * [`performance`](../performance.md) + * [`profiles`](../profiles.md) + * [`timeline`](../timeline.md) + * [`view`](../view.md) +* [Screenshots](../../screenshots.md) +* [Troubleshooting](../../troubleshooting.md) +* [Usage](../../usage/README.md) + +--- + +* [Developing](../../developing.md) \ No newline at end of file diff --git a/docs/configuration/actions/custom/README.md b/docs/configuration/actions/custom/README.md new file mode 100644 index 00000000..66f53159 --- /dev/null +++ b/docs/configuration/actions/custom/README.md @@ -0,0 +1,737 @@ +# `custom:frigate-card-action` + +Execute a Frigate Card action. + +```yaml +action: custom:frigate-card-action +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | A supported Frigate Card action. See below. | + +## `camera_select` + +Select a given camera. + +```yaml +action: custom:frigate-card-action +frigate_card_action: camera_select +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `camera_select`. | +| `camera` | The [camera ID](../../cameras/README.md?id=cameras) of the camera to select. | +| `triggered` | If `true` instead of `camera` being specified then a triggered camera (if any) is selected instead. | + +This action will respect the value of the `view.camera_select` to choose the appropriate view on the new camera. See [`view` configuration](../../view.md). + +## `camera_ui` + +Download the displayed media. + +```yaml +action: custom:frigate-card-action +frigate_card_action: camera_ui +``` + +Open the UI for the selected camera engine (e.g. the Frigate UI). + +## `change_zoom` + +Zoom in and/or pan for a given camera. + +```yaml +action: custom:frigate-card-action +frigate_card_action: change_zoom +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `change_zoom`. | +| `target_id` | The [camera ID](../../cameras/README.md?id=cameras) or a media ID (e.g. `frigate` event ID) to change zoom/pam settings for. | +| `zoom` | Optional parameter that controls how much to zoom-in. See the [camera zoom parameter](../../cameras/README.md?id=layout-configuration). | +| `pan` | Optional parameter that controls how much to pan-x/y. See the [camera pan parameter](../../cameras/README.md?id=layout-configuration). | + +?> If neither `zoom` nor `pan` are specified the camera will return to its default zoom and pan settings. + +See [example of automatically zoom/panning based on state](../../../examples.md?id=automatically-zoom-based-on-state). + +## `clip` + +Change to the `clip` view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: clip +``` + +## `clips` + +Change to the `clips` view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: clips +``` + +## `default` + +Change to the default view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: default +``` + +## `diagnostics` + +Show the card diagnostics. + +```yaml +action: custom:frigate-card-action +frigate_card_action: diagnostics +``` + +## `display_mode_select` + +Select a display mode (e.g. view a `single` camera or a `grid` of cameras). + +```yaml +action: custom:frigate-card-action +frigate_card_action: display_mode_select +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `display_mode_select`. | +| `display_mode` | `single` to show a single camera at a time in a carousel, or `grid` to show a grid of cameras. | + +## `download` + +Download the displayed media. + +```yaml +action: custom:frigate-card-action +frigate_card_action: download +``` + +## `expand` + +Expand the card into a dialog/popup. + +```yaml +action: custom:frigate-card-action +frigate_card_action: expand +``` + +## `fullscreen` + +Toggle fullscreen. + +```yaml +action: custom:frigate-card-action +frigate_card_action: fullscreen +``` + +## `image` + +Change to the `image` view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: image +``` + +## `live` + +Change to the `live` view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: live +``` + +## `live_substream_off` + +Turn off the substream (if on). + +```yaml +action: custom:frigate-card-action +frigate_card_action: live_substream_on +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `live_substream_on`. | + +## `live_substream_on` + +Turn on the first available substream. Use [Camera dependency configuration](../../cameras/README.md?id=dependencies) to configure substreams. + +```yaml +action: custom:frigate-card-action +frigate_card_action: live_substream_on +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `live_substream_on`. | + + + +## `live_substream_select` + +Select a substream. Use [Camera dependency configuration](../../cameras/README.md?id=dependencies) to configure substreams. + +```yaml +action: custom:frigate-card-action +frigate_card_action: live_substream_select +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `live_substream_select`. | +| `camera` | The [camera ID](../../cameras/README.md?id=cameras) of the substream to select. | + +## `log` + +Log a message to the Javascript console. + +```yaml +action: custom:frigate-card-action +frigate_card_action: log +[...] +``` + +| Parameter | Default | Description | +| - | - | - | +| `action` | | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | | Must be `log`. | +| `message` | | The message to log. | +| `level` | `info` | The console logging level to use. One of `['debug', 'info', 'warn', 'error']`. | + +## `media_player` + +Perform a media player action. + +```yaml +action: custom:frigate-card-action +frigate_card_action: media_player +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `media_player`. | +| `media_player` | The entity ID of the media_player on which to perform the action. | +| `media_player_action` | Either `play` or `stop` to play or stop the media in question. | + +## `menu_toggle` + +Show/hide the menu (for the `hidden` mode style). + +```yaml +action: custom:frigate-card-action +frigate_card_action: menu_toggle +``` + +## `microphone_mute` + +Mute the microphone during [2-way audio](../../../usage/2-way-audio.md). + +```yaml +action: custom:frigate-card-action +frigate_card_action: microphone_mute +``` + +## `microphone_unmute` + +Unmute the microphone during [2-way audio](../../../usage/2-way-audio.md). + +```yaml +action: custom:frigate-card-action +frigate_card_action: microphone_unmute +``` + +## `mute` + +Mute the selected media. + +```yaml +action: custom:frigate-card-action +frigate_card_action: mute +``` + +## `pause` + +Pause the selected media. + +```yaml +action: custom:frigate-card-action +frigate_card_action: pause +``` + +## `play` + +Play the selected media. + +```yaml +action: custom:frigate-card-action +frigate_card_action: play +``` + +## `ptz` + +Execute a real PTZ action, whether configured manually (see [Camera PTZ configuration](../../cameras/README.md?id=ptz)) or auto-detected. + +```yaml +action: custom:frigate-card-action +frigate_card_action: ptz +[...] +``` + +| Parameter | | Description | +| - | - | - | +| `action` | | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | | Must be `ptz`. | +| `camera` | Currently selected camera | An optional camera ID to execute the action on. | +| `ptz_action` | | Optional action that is of `left`, `right`, `up`, `down`, `zoom_in`, `zoom_out` or `preset`. | +| `ptz_phase` | | Optional parameter that is one of `start` or `stop` to start or stop the movement separately. | +| `ptz_preset` | | Optional preset to execute when the `ptz_action` is `preset`. | + +?> If no `ptz_action` is specified, the camera returns to its "home" position. For a real PTZ camera, the "home" position is the first available preset. If there are no presets, there is no home position. + +## `ptz_controls` + +Show or hide the PTZ controls. + +```yaml +action: custom:frigate-card-action +frigate_card_action: ptz_controls +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `ptz_controls`. | +| `show` | If `true` shows the PTZ controls, if `false` hides them. | + +## `ptz_digital` + +Execute a digital PTZ action. + +```yaml +action: custom:frigate-card-action +frigate_card_action: ptz-digital +[...] +``` + +| Parameter | Default | Description | +| - | - | - | +| `action` | | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | | Must be `ptz-digital`. | +| `target_id` | The currently selected camera or media | The target (camera or media) to execute a digital PTZ action on. Can be a camera ID, or another media ID (e.g. for Frigate, can specify a media/event ID). | +| `ptz_action` | Optional action that is one of `left`, `right`, `up`, `down`, `zoom_in` or `zoom_out`. | +| `ptz_phase` | Optional parameter that is one of `start` or `stop` to start or stop the movement separately. | +| `absolute` | Optional parameter to specify exact absolute pan and zoom settings. See below. | + +?> If no `ptz_action` is specified and no `absolute` value is specified, the camera returns to its "home" position. See [Camera layout configuration](../../cameras/README.md?id=layout-configuration) to configure the default "home" position for digital PTZ. + +### `absolute` + +Set exact digital PTZ pan and zoom parameters. + +| Parameter | Description | +| - | - | +| `pan` | Control camera digital pan. See the `pan` parameter in [Camera layout configuration](../../cameras/README.md?id=layout-configuration). | +| `zoom` | Control camera digital zoom. See the `zoom` parameter in [Camera layout configuration](../../cameras/README.md?id=layout-configuration). | + +## `ptz_multi` + +Execute a PTZ action that intelligently chooses between a real and digital PTZ +action. If the media in question is a live camera with real PTZ support, a real +PTZ action will execute (equivalent to using the [`ptz`](README.md?id=ptz) +action), otherwise a digital PTZ action will be run (equivalent to using the +[`ptz_digital`](README.md?id=ptz_digital) action). + +?> If the camera supports _any_ real PTZ action, _all_ actions will attempt to make real PTZ calls. + +```yaml +action: custom:frigate-card-action +frigate_card_action: ptz-multi +[...] +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `ptz-digital`. | +| `ptz_action` | Optional action that is one of `left`, `right`, `up`, `down`, `zoom_in` or `zoom_out`. | +| `ptz_phase` | Optional parameter that is one of `start` or `stop` to start or stop the movement separately. | +| `ptz_preset` | Optional preset to execute when the `ptz_action` is `preset`. | + +?> If no `ptz_action` is specified, the camera returns to its "home" position. + +## `recording` + +Change to the `recording` view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: recording +``` + +## `recordings` + +Change to the `recordings` view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: recordings +``` + +## `screenshot` + +Take a screenshot of the selected media (e.g. a still from a video). + +```yaml +action: custom:frigate-card-action +frigate_card_action: screenshot +``` + +## `sleep` + +Take no action for a given duration. Useful to pause between multiple other actions. + +```yaml +action: custom:frigate-card-action +frigate_card_action: sleep +``` + +| Parameter | Description | +| - | - | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `sleep`. | +| `duration` | A duration object. See below. | + +### `duration` + +The `duration` block configures how long the `sleep` should last. + +| Parameter | Description | +| - | - | +| `h` | Hours to sleep for. | +| `m` | Minutes to sleep for. | +| `s` | Seconds to sleep for. | +| `ms` | Milliseconds to sleep for. | + +?> Multiple values can be combined, e.g. `{ m: 2, s: 30}` will sleep for `2.5` minutes. + +## `snapshot` + +Change to the `snapshot` view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: snapshot +``` + +## `snapshots` + +Change to the `snapshots` view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: snapshots +``` + +## `timeline` + +Change to the `timeline` view. + +```yaml +action: custom:frigate-card-action +frigate_card_action: timeline +``` + +## `unmute` + +Unmute the selected media. + +```yaml +action: custom:frigate-card-action +frigate_card_action: unmute +``` + +## Fully expanded reference + +[](../../common/expanded-warning.md ':include') + +```yaml +elements: + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-a-circle + title: Select Front Door + tap_action: + action: custom:frigate-card-action + frigate_card_action: camera_select + camera: camera.front_door + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-b-circle + title: Open Camera UI + tap_action: + action: custom:frigate-card-action + frigate_card_action: camera_ui + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-c-circle + title: Change Zoom + tap_action: + action: custom:frigate-card-action + frigate_card_action: change_zoom + pan: + x: 50 + y: 50 + zoom: 1 + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-d-circle + title: Show most recent clip + tap_action: + action: custom:frigate-card-action + frigate_card_action: clip + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-e-circle + title: Show clips + tap_action: + action: custom:frigate-card-action + frigate_card_action: clips + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-f-circle + title: Show default view + tap_action: + action: custom:frigate-card-action + frigate_card_action: default + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-g-circle + title: Show diagnostics + tap_action: + action: custom:frigate-card-action + frigate_card_action: diagnostics + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-h-circle + title: Show grid + tap_action: + action: custom:frigate-card-action + frigate_card_action: display_mode_select + display_mode: grid + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-i-circle + title: Download media + tap_action: + action: custom:frigate-card-action + frigate_card_action: download + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-j-circle + title: Expand + tap_action: + action: custom:frigate-card-action + frigate_card_action: expand + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-k-circle + title: Fullscreen + tap_action: + action: custom:frigate-card-action + frigate_card_action: fullscreen + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-l-circle + title: Show image view + tap_action: + action: custom:frigate-card-action + frigate_card_action: image + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-m-circle + title: Show live view + tap_action: + action: custom:frigate-card-action + frigate_card_action: live + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-n-circle + title: Turn off substream + tap_action: + action: custom:frigate-card-action + frigate_card_action: live_substream_off + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-o-circle + title: Turn on substream + tap_action: + action: custom:frigate-card-action + frigate_card_action: live_substream_on + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-n-circle + title: Select HD substream + tap_action: + action: custom:frigate-card-action + frigate_card_action: live_substream_select + camera: camera.front_door_hd + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-o-circle + title: Log to console + tap_action: + action: custom:frigate-card-action + frigate_card_action: log + message: "Hello, world!" + level: debug + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-m-circle + title: Media player play + tap_action: + action: custom:frigate-card-action + frigate_card_action: media_player + media_player: media_player.nesthub50be + media_player_action: play + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-n-circle + title: Media player stop + tap_action: + action: custom:frigate-card-action + frigate_card_action: media_player + media_player: media_player.nesthub + media_player_action: stop + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-o-circle + title: Toggle hidden menu + tap_action: + action: custom:frigate-card-action + frigate_card_action: menu_toggle + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-p-circle + title: Microphone mute + tap_action: + action: custom:frigate-card-action + frigate_card_action: microphone_mute + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-q-circle + title: Microphone unmute + tap_action: + action: custom:frigate-card-action + frigate_card_action: microphone_unmute + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-r-circle + title: Mute + tap_action: + action: custom:frigate-card-action + frigate_card_action: mute + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-s-circle + title: Pause + tap_action: + action: custom:frigate-card-action + frigate_card_action: pause + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-t-circle + title: Play + tap_action: + action: custom:frigate-card-action + frigate_card_action: play + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-u-circle + title: Real PTZ Preset + tap_action: + action: custom:frigate-card-action + frigate_card_action: ptz + ptz_action: preset + ptz_preset: doorway + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-v-circle + title: Show PTZ Controls + tap_action: + action: custom:frigate-card-action + frigate_card_action: ptz_controls + enabled: true + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-w-circle + title: Go to precise digital location + tap_action: + action: custom:frigate-card-action + frigate_card_action: ptz_digital + absolute: + zoom: 5 + pan: + x: 58 + y: 14 + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-x-circle + title: Smart select between real and digital PTZ + tap_action: + action: custom:frigate-card-action + frigate_card_action: ptz_multi + ptz_action: left + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-y-circle + title: Show most recent recording + tap_action: + action: custom:frigate-card-action + frigate_card_action: recording + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-a-circle-outline + title: Show recordings + tap_action: + action: custom:frigate-card-action + frigate_card_action: recordings + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-b-circle-outline + title: Screenshot + tap_action: + action: custom:frigate-card-action + frigate_card_action: screenshot + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-c-circle-outline + title: Sleep + tap_action: + action: custom:frigate-card-action + frigate_card_action: sleep + duration: + h: 1 + m: 20 + s: 56 + ms: 422 + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-d-circle-outline + title: Show most recent snapshot + tap_action: + action: custom:frigate-card-action + frigate_card_action: snapshot + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-e-circle-outline + title: Show snapshots + tap_action: + action: custom:frigate-card-action + frigate_card_action: snapshots + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-f-circle-outline + title: Show timeline + tap_action: + action: custom:frigate-card-action + frigate_card_action: timeline + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-g-circle-outline + title: Unmute + tap_action: + action: custom:frigate-card-action + frigate_card_action: unmute +``` diff --git a/docs/configuration/actions/custom/_sidebar.md b/docs/configuration/actions/custom/_sidebar.md new file mode 100644 index 00000000..e2d1629d --- /dev/null +++ b/docs/configuration/actions/custom/_sidebar.md @@ -0,0 +1,27 @@ +* [Getting Started](../../../README.md) +* [Configuration](../../README.md) + * [`actions`](../README.md) + * [Custom Actions](README.md) + * [Stock Actions](../stock/README.md) + * [`automations`](../../automations.md) + * [`cameras`](../../cameras/README.md) + * [`conditions`](../../conditions.md) + * [`dimensions`](../../dimensions.md) + * [`elements`](../../elements.md) + * [`image`](../../image.md) + * [`live`](../../live.md) + * [`media_gallery`](../../media-gallery.md) + * [`media_viewer`](../../media-viewer.md) + * [`menu`](../../menu.md) + * [`overrides`](../../overrides.md) + * [`performance`](../../performance.md) + * [`profiles`](../../profiles.md) + * [`timeline`](../../timeline.md) + * [`view`](../../view.md) +* [Screenshots](../../../screenshots.md) +* [Troubleshooting](../../../troubleshooting.md) +* [Usage](../../../usage/README.md) + +--- + +* [Developing](../../../developing.md) \ No newline at end of file diff --git a/docs/configuration/actions/stock/README.md b/docs/configuration/actions/stock/README.md new file mode 100644 index 00000000..6fdcfd03 --- /dev/null +++ b/docs/configuration/actions/stock/README.md @@ -0,0 +1,120 @@ +# Stock Actions + +## `call-service` + +Call a service. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). + +```yaml +action: call-service +[...] +``` + +## `more-info` + +Open the "more-info" dialog for an entity. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). + +```yaml +action: more-info +[...] +``` + +## `navigate` + +Navigate to a particular dashboard path. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). + +```yaml +action: navigate +[...] +``` + +## `toggle` + +Toggle an entity. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). + +```yaml +action: toggle +[...] +``` + +## `url` + +Navigate to an arbitrary URL. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). + +```yaml +action: url +[...] +``` + +## Fully expanded reference + +[](../../common/expanded-warning.md ':include') + +Reference: [Home Assistant Actions](https://www.home-assistant.io/dashboards/actions/). + +```yaml +elements: + - type: icon + icon: mdi:numeric-1-box + title: More info action + style: + left: 200px + top: 50px + entity: light.office_main_lights + tap_action: + action: more-info + - type: icon + icon: mdi:numeric-2-box + title: Toggle action + style: + left: 200px + top: 100px + entity: light.office_main_lights + tap_action: + action: toggle + - type: icon + icon: mdi:numeric-3-box + title: Call Service action + style: + left: 200px + top: 150px + tap_action: + action: call-service + service: homeassistant.toggle + data: + entity_id: light.office_main_lights + - type: icon + icon: mdi:numeric-4-box + title: Navigate action + style: + left: 200px + top: 200px + tap_action: + action: navigate + navigation_path: /lovelace/2 + - type: icon + icon: mdi:numeric-5-box + title: URL action + style: + left: 200px + top: 250px + tap_action: + action: url + url_path: https://www.home-assistant.io/ + - type: icon + icon: mdi:numeric-6-box + title: None action + style: + left: 200px + top: 300px + tap_action: + action: none + - type: icon + icon: mdi:numeric-7-box + title: Custom action + style: + left: 200px + top: 350px + tap_action: + action: fire-dom-event + key: value +``` diff --git a/docs/configuration/actions/stock/_sidebar.md b/docs/configuration/actions/stock/_sidebar.md new file mode 100644 index 00000000..3858987a --- /dev/null +++ b/docs/configuration/actions/stock/_sidebar.md @@ -0,0 +1,27 @@ +* [Getting Started](../../../README.md) +* [Configuration](../../README.md) + * [`actions`](../README.md) + * [Custom Actions](../custom/README.md) + * [Stock Actions](README.md) + * [`automations`](../../automations.md) + * [`cameras`](../../cameras/README.md) + * [`conditions`](../../conditions.md) + * [`dimensions`](../../dimensions.md) + * [`elements`](../../elements.md) + * [`image`](../../image.md) + * [`live`](../../live.md) + * [`media_gallery`](../../media-gallery.md) + * [`media_viewer`](../../media-viewer.md) + * [`menu`](../../menu.md) + * [`overrides`](../../overrides.md) + * [`performance`](../../performance.md) + * [`profiles`](../../profiles.md) + * [`timeline`](../../timeline.md) + * [`view`](../../view.md) +* [Screenshots](../../../screenshots.md) +* [Troubleshooting](../../../troubleshooting.md) +* [Usage](../../../usage/README.md) + +--- + +* [Developing](../../../developing.md) \ No newline at end of file diff --git a/docs/configuration/automations.md b/docs/configuration/automations.md index 19580ab1..37a1dc39 100644 --- a/docs/configuration/automations.md +++ b/docs/configuration/automations.md @@ -1,6 +1,6 @@ # `automations` -Automatically take [actions](actions.md) based on [conditions](conditions.md) being met. +Automatically take [actions](actions/README.md) based on [conditions](conditions.md) being met. ?> To change configuration conditionally use [overrides](overrides.md). @@ -17,8 +17,8 @@ automations: | Option | Default | Description | | - | - | - | | `conditions` | | A list of [conditions](conditions.md) that must evaluate to `true` in order to trigger the automation. | -| `actions` | | An optional list of [actions](actions.md) that will be run when the [conditions](conditions.md) evaluate `true`. | -| `actions_not` | | An optional list of [actions](actions.md) that will be run when the [conditions](conditions.md) evaluate `false`. | +| `actions` | | An optional list of [actions](actions/README.md) that will be run when the [conditions](conditions.md) evaluate `true`. | +| `actions_not` | | An optional list of [actions](actions/README.md) that will be run when the [conditions](conditions.md) evaluate `false`. | # Fully expanded reference diff --git a/docs/configuration/cameras/README.md b/docs/configuration/cameras/README.md index 31124162..12f8cd92 100644 --- a/docs/configuration/cameras/README.md +++ b/docs/configuration/cameras/README.md @@ -26,7 +26,7 @@ cameras_global: | `engine` | `auto` | The camera engine to use. If `auto` the card will attempt to choose the correct engine from the specified options. See [Engine](engine.md). | | `frigate` | | Options for Frigate cameras. See [Frigate camera engine configuration](engine.md?id=frigate). | | `icon` | Autodetected from `camera_entity` if that is specified. | The icon to use for this camera in the camera menu and in the next & previous controls when using the `icon` style. | -| `id` | `camera_entity`, `webrtc_card.entity` or `frigate.camera_name` if set (in that preference order). | An optional identifier to use throughout the card configuration to refer unambiguously to this camera. This `id` may be used in [conditions](../conditions.md), dependencies or custom [actions](../actions.md) to refer to a given camera unambiguously. | +| `id` | `camera_entity`, `webrtc_card.entity` or `frigate.camera_name` if set (in that preference order). | An optional identifier to use throughout the card configuration to refer unambiguously to this camera. This `id` may be used in [conditions](../conditions.md), dependencies or custom [actions](../actions/README.md) to refer to a given camera unambiguously. | | `live_provider` | `auto` | The choice of live stream provider. See [Live Provider](live-provider.md).| | `title` | Autodetected from `camera_entity` if that is specified. | A friendly name for this camera to use in the card. | | `triggers` | | Define what should cause this camera to update/trigger. See below. | @@ -176,6 +176,66 @@ See [media layout examples](../../examples.md?id=media-layout). ![](../../images/media_layout/pan-zoom.png "Panning and zooming :size=400") +## `ptz` + +Configure the PTZ actions taken for a camera (not to be confused with configuration of the PTZ _controls_, see [Live PTZ Controls](../live.md?id=ptz) or [Media Viewer PTZ Controls](../media-viewer.md?id=ptz)). Manually configured actions override any auto-detected actions. + +```yaml +cameras: + - camera_entity: camera.office + ptz: + [...] +``` + +### Movement types + +Generally PTZ cameras/integrations may support two kinds of PTZ actions: + +* `relative`: Single relative steps, e.g. "Pan to the left one step". +* `continuous`: Separate start and stop, e.g. "Start panning to the left", following by a later command "Stop panning". + +The card supports both, and with the help of the +`r2c_delay_between_calls_seconds` and `c2r_delay_between_calls_seconds` can +translate between them where necessary. See the [ONVIF +specification](https://www.onvif.org/specs/srv/ptz/ONVIF-PTZ-Service-Spec.pdf) +for more details on the distinction between `relative` and `continuous`. + +The card UI (e.g. PTZ controls) will always try to call the `continuous` variety +to allow for precise/smooth controls, and if unavailable will translate multiple +`relative` steps with optional delays between each step. Manually configured +[actions](../actions/README.md) may be configured to call either variety. + +?> Frigate auto-detected PTZ actions will always be `continuous` as this is what +the integration currently offers. + +### Parameters + +| Option | Default | Description | +| - | - | - | +| `actions_left`, `actions_right`, `actions_up`, `actions_down`, `actions_zoom_in`, `actions_zoom_out`, `actions_home` | Set by camera [engine](./engine.md) of the selected camera | The [call-service](../actions/stock/README.md?id=call-service) action that will be called for each PTZ action for relative movements. | +| `actions_left_start`, `actions_left_stop`, `actions_right_start`, `actions_right_stop`,`actions_up_start`, `actions_up_stop`,`actions_down_start`, `actions_down_stop`,`actions_zoom_in_start`, `actions_zoom_in_stop`,`actions_zoom_out_start`, `actions_zoom_out_stop` | Set by camera [engine](./engine.md) of the selected camera | The [call-service](../actions/stock/README.md?id=call-service) action that will be called for each PTZ action for continous movements. Both a `_start` and `_stop` variety must be provided for an action to be usable. | +| `c2r_delay_between_calls_seconds` | `0.2` | When the camera is configured with continuous actions only (e.g. `left_start` and `left_stop`, but not `left`), if something requests a relative action (e.g. a manually configured [action](../actions/README.md)), then `start` will be called, followed by a delay of this number of seconds and finally `stop` will be called. Cameras / integrations that are slower to respond to continuous steps may need to increase this value to avoid the continuous motion being too small. Cameras / integrations that are rapid to respond may need to decrease this value to avoid the "relative step" being too large. | +| `data_left`, `data_right`, `data_up`, `data_down`, `data_zoom_in`, `data_zoom_out`, `data_home` | | Shorthand for relative actions that call the service defined by the `service` parameter, with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[action]`. If both `actions_X` and `data_X` are specified, `actions_X` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). | +| `data_left_start`, `data_left_stop`, `data_right_start`, `data_right_stop`, `data_up_start`, `data_up_stop`, `data_down_start`, `data_down_stop`, `data_zoom_in_start`, `data_zoom_in_stop`, `data_zoom_out_start`, `data_zoom_out_stop` | | Shorthand for continuous actions that call the service defined by the `service` parameter, with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[action]_start` and `actions_[action]_stop`. If both `actions_X_*` and `data_X_*` are specified, `actions_X_*` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). Both a `_start` and `_stop` variety must be provided for an action to be usable. | +| `presets` | | PTZ preset actions. See below. | +| `r2c_delay_between_calls_seconds` | `0.5` | When the camera is configured with relative actions only (e.g. `left` but not `left_start` and `left_stop`), if something requests a continuous action (e.g. the card PTZ controls have a button held down), then a delay of this number of seconds will be inserted between each call of the relative action. Cameras / integrations that are slower to respond to relative steps may need to increase this value to avoid multiple simultaneous actions being sent. Cameras / integrations that are rapid to respond may need to decrease this value to increase the appearance of one single continuous motion. | +| `service` | | An optional Home Assistant service to call when the `data_` parameters are used. | + +### `presets` + +Configures named PTZ presets. If a preset of this name is auto-detected, these configured actions will take precedence. + +```yaml +cameras: + - camera_entity: camera.office + ptz: + presets: + [preset_name]: + [action]: +``` + +`[action]` is any [call-service](../actions/stock/README.md?id=call-service) action. + ## `triggers` The `triggers` block configures what triggers a camera. Triggering can be used @@ -314,6 +374,61 @@ cameras: pan: x: 50 y: 50 + - camera_entity: camera.manual-ptz + ptz: + c2r_delay_between_calls_seconds: 0.2 + r2c_delay_between_calls_seconds: 0.5 + # Relative action (only `left` shown) + actions_left: + action: call-service + service: service.of_your_choice + data: + device: '048123' + cmd: left + # Continuous action (only `right` shown) + actions_right_start: + action: call-service + service: service.of_your_choice + data: + device: '048123' + cmd: right + phase: start + actions_right_stop: + action: call-service + service: service.of_your_choice + data: + device: '048123' + phase: stop + # Equivalent relative short form (only `up` shown) + service: service.send_command + data_up: + device: '048123' + cmd: up + # Equivalent continuous short form (only `down` shown) + service: service.send_command + data_up_start: + device: '048123' + cmd: down + phase: start + data_up_stop: + device: '048123' + cmd: down + phase: stop + presets: + # Preset using long form. + armchair: + action: call-service + service: service.of_your_choice + data: + device: '048123' + cmd: preset + preset: armchair + # Preset using short form. + service: service.of_your_choice + window: + device: '048123' + cmd: preset + preset: window cameras_global: live_provider: ha ``` diff --git a/docs/configuration/cameras/_sidebar.md b/docs/configuration/cameras/_sidebar.md index 07620600..6ab6e00b 100644 --- a/docs/configuration/cameras/_sidebar.md +++ b/docs/configuration/cameras/_sidebar.md @@ -1,23 +1,23 @@ * [Getting Started](../../README.md) * [Configuration](../README.md) - * [`actions`](../actions.md) - * [`automations`](../automations.md) - * [`cameras`](README.md) - * [`live_provider`](live-provider.md) - * [`engine`](engine.md) - * [`conditions`](../conditions.md) - * [`dimensions`](../dimensions.md) - * [`elements`](../elements.md) - * [`image`](../image.md) - * [`live`](../live.md) - * [`media_gallery`](../media-gallery.md) - * [`media_viewer`](../media-viewer.md) - * [`menu`](../menu.md) - * [`overrides`](../overrides.md) - * [`performance`](../performance.md) - * [`profiles`](../profiles.md) - * [`timeline`](../timeline.md) - * [`view`](../view.md) + * [`actions`](../actions/README.md) + * [`automations`](../automations.md) + * [`cameras`](README.md) + * [`live_provider`](live-provider.md) + * [`engine`](engine.md) + * [`conditions`](../conditions.md) + * [`dimensions`](../dimensions.md) + * [`elements`](../elements.md) + * [`image`](../image.md) + * [`live`](../live.md) + * [`media_gallery`](../media-gallery.md) + * [`media_viewer`](../media-viewer.md) + * [`menu`](../menu.md) + * [`overrides`](../overrides.md) + * [`performance`](../performance.md) + * [`profiles`](../profiles.md) + * [`timeline`](../timeline.md) + * [`view`](../view.md) * [Screenshots](../../screenshots.md) * [Troubleshooting](../../troubleshooting.md) * [Usage](../../usage/README.md) diff --git a/docs/configuration/conditions.md b/docs/configuration/conditions.md index 40e59550..3a26792b 100644 --- a/docs/configuration/conditions.md +++ b/docs/configuration/conditions.md @@ -66,6 +66,24 @@ conditions: | `condition` | Must be `interaction`. | | `interaction` | If `true` the condition is satisfied if the card has had human interaction within `view.interaction_seconds` elapsed seconds. If `false` the condition is satisfied if the card has **NOT** had human interaction in that time. | +## `key` + +```yaml +conditions: + - condition: key + [...] +``` + +| Parameter | Default | Description | +| - | - | - | +| `condition` | - | Must be `key`. | +| `alt` | `false` | An optional value to match whether the `alt` key is being held. | +| `ctrl` | `false` | An optional value to match whether the `ctrl` key is being held. | +| `key` | | Any [keyboard key value](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values), e.g. `ArrowLeft`. | +| `meta` | `false` | An optional value to match whether the `meta` key is being held. | +| `shift` | `false` | An optional value to match whether the `shift` key is being held. | +| `state` | `down` | An optional value to match the state of the. Must be one of `down` or `up`. | + ## `media_loaded` ```yaml @@ -77,7 +95,7 @@ conditions: | Parameter | Description | | - | - | | `condition` | Must be `media_loaded`. | -| `media_loaded` | If `true` the condition is satisfied if there is media load**ED** (not load**ING**) in the card (e.g. a clip, snapshot or live view). This may be used to hide controls during media loading or when a message (not media) is being displayed. Note that if `true` this +| `media_loaded` | If `true` the condition is satisfied if there is media load**ED** (not load**ING**) in the card (e.g. a clip, snapshot or live view). This may be used to hide controls during media loading or when a message (not media) is being displayed. | ## `microphone` @@ -169,7 +187,7 @@ conditions: media is fetched. When including views as part of a [condition](conditions.md), you may need to refer to this special `media` view. -# Fully expanded reference +## Fully expanded reference [](common/expanded-warning.md ':include') @@ -184,6 +202,13 @@ conditions: fullscreen: true - condition: interaction interaction: true + - condition: key + alt: false + ctrl: false + key: F + meta: false + shift: false + state: down - condition: media_loaded media_loaded: true - condition: microphone diff --git a/docs/configuration/elements.md b/docs/configuration/elements.md index c98e48ef..992a89e7 100644 --- a/docs/configuration/elements.md +++ b/docs/configuration/elements.md @@ -10,8 +10,8 @@ elements: - [element_2] ``` -?> The Frigate Card allows either a single [action](actions.md) (as in stock Home -Assistant) or list of [actions](actions.md) to be defined for each class of user interaction +?> The Frigate Card allows either a single [action](actions/README.md) (as in stock Home +Assistant) or list of [actions](actions/README.md) to be defined for each class of user interaction (e.g. `tap`, `double_tap`, `hold`, etc). See [an example of multiple actions](../examples.md?id=multiple-actions). ## `conditional` @@ -81,7 +81,7 @@ Parameters for this element are identical to the parameters of the [stock Home A | `selected` | `false` | Whether or not to show this item as selected. | | `state_color` | `true` | Whether or not the title and icon should be stylized based on state. | | `style` | | Position and style the element using CSS. | -| `tap_action`, `double_tap_action`, `hold_action`, `start_tap`, `end_tap` | | The [actions](actions.md) to take when this item is interacted with. | +| `tap_action`, `double_tap_action`, `hold_action`, `start_tap`, `end_tap` | | The [actions](actions/README.md) to take when this item is interacted with. | | `title` | | An optional title to display. | ## `custom:frigate-card-menu-submenu-select` @@ -185,7 +185,7 @@ elements: ## Fully expanded reference -> [Actions](actions.md) are omitted for simplicity. +> [Actions](actions/README.md) are omitted for simplicity. [](common/expanded-warning.md ':include') diff --git a/docs/configuration/image.md b/docs/configuration/image.md index 2800033d..2f56f6fa 100644 --- a/docs/configuration/image.md +++ b/docs/configuration/image.md @@ -9,15 +9,14 @@ image: | Option | Default | Description | | - | - | - | -| `actions` | | [Actions](actions.md) to use for the `image` view.| +| `actions` | | [Actions](actions/README.md) to use for the `image` view.| | `mode` | `url` | Mode of the the `image` view. Value must be one of `url` (to fetch an arbitrary image URL), `camera` (to show a still of the currently selected camera using either `camera_entity` or `webrtc_card.entity` in that order of precedence), or `screensaver` (to show an [embedded stock Frigate card logo](https://github.com/dermotduffy/frigate-hass-card/blob/main/src/images/frigate-bird-in-sky.jpg)). In either `url` or `camera` mode, the `screensaver` content is used as a fallback if a URL is not specified or cannot be derived. | | `refresh_seconds` | 0 | The image will be refreshed at least every `refresh_seconds` (it may refresh more frequently, e.g. whenever Home Assistant updates its camera security token). `0` implies no refreshing. | | `url` | | A static image URL to be used when the `mode` is set to `url` or when a temporary image is required (e.g. may appear momentarily prior to load of a camera snapshot in the `camera` mode). Note that a `_t=[timestsamp]` query parameter will be automatically added to all URLs such that the image will not be cached by the browser. | -| `zoomable` | `true` | Whether or not the image can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | ?> When `mode` is set to `camera` this is effectively providing the same image as the `image` [live provider](cameras/live-provider.md) would show in the live camera carousel. -# Fully expanded reference +## Fully expanded reference [](common/expanded-warning.md ':include') @@ -25,7 +24,6 @@ image: image: mode: url refresh_seconds: 0 - zoomable: true actions: entity: light.office_main_lights tap_action: diff --git a/docs/configuration/live.md b/docs/configuration/live.md index acd7f509..51b144cc 100644 --- a/docs/configuration/live.md +++ b/docs/configuration/live.md @@ -9,7 +9,7 @@ live: | Option | Default | Description | | - | - | - | -| `actions` | | [Actions](actions.md) to use for the `live` view. | +| `actions` | | [Actions](actions/README.md) to use for the `live` view. | | `auto_mute` | `[unselected, hidden, microphone]` | A list of conditions in which live camera feeds are muted. `unselected` will automatically mute when a camera is unselected in the carousel, `hidden` will automatically mute when the browser/tab becomes hidden or `microphone` will automatically mute after the microphone is muted as long as the camera stays selected (see the `live.microphone.mute_after_microphone_mute_seconds` to control how long after). Use an empty list (`[]`) to never automatically mute. Note that if `auto_play` is enabled, the stream may mute itself automatically in order to honor the `auto_play` setting, as some browsers will not auto play media that is unmuted -- that is to say, where necessary, the `auto_play` parameter will take priority over the `auto_mute` parameter.| | `auto_pause` | `[]` | A list of conditions in which live camera feeds are automatically paused. `unselected` will automatically pause when a camera is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause. **Caution**: Some live providers (e.g. `jsmpeg`) may not offer human-accessible means to resume play if it is paused, unless the `auto_play` option is used.| | `auto_play` | `[selected, visible]` | A list of conditions in which live camera feeds are automatically played.`selected` will automatically play when a camera is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play. Some live providers (e.g. `webrtc-card`, `jsmpeg`) do not support the prevention of automatic play on initial load, but should still respect the value of this flag on play-after-pause.| @@ -39,8 +39,8 @@ live: | - | - | - | | `builtin` | `true` | Whether to show the built in (browser) video controls on live video. | | `next_previous` | | Configures how the "Next & Previous" controls are shown on the `live` view. See below. | -| `thumbnails` | | | Configures how thumbnails are shown on the `live` view. See below. | -| `timeline` | | | Configures how the mini-timeline is shown on the `live` view. See below. | +| `thumbnails` | | Configures how thumbnails are shown on the `live` view. See below. | +| `timeline` | | Configures how the mini-timeline is shown on the `live` view. See below. | | `title` | | Configures how the camera title is shown on the `live` view. See below. | ### `next_previous` @@ -59,6 +59,29 @@ live: | `size` | `48` | The size of the next/previous controls in pixels. Must be >= `20`. | | `style` | `chevrons` | When viewing live cameras, what kind of controls to show to move to the previous/next camera. Acceptable values: `chevrons`, `icons`, `none` . | +### `ptz` + +Configures the PTZ (Pan Tilt Zoom) controls. + +```yaml +live: + controls: + ptz: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `hide_home` | `false` | When `true` the Home button of the control is hidden | +| `hide_pan_tilt` | `false` | When `true` the Pan & Tilt buttons of the control is hidden | +| `hide_zoom` | `false` | When `true` the Zoom button of the control is hidden | +| `mode` | `auto` | If `on` or `off` will always or never show PTZ controls respectively, if `auto` will show PTZ controls only if the camera supports real PTZ. | +| `orientation` | `horizontal` | Whether to show a `vertical` or `horizontal` PTZ control. | +| `position` | `bottom-right` | Whether to position the control on the `top-left`, `top-right`, `bottom-left` or `bottom-right`. This may be overridden by using the `style` parameter to precisely control placement. | +| `style` | | Optionally position and style the element using CSS. Similar to [Picture Element styling](https://www.home-assistant.io/dashboards/picture-elements/#how-to-use-the-style-object), except without any default, e.g. `left: 42%` | + +To configure the PTZ _actions_ taken for a particular camera, see [Camera PTZ Settings](./cameras/README.md?id=ptz). + ### `thumbnails` Configures how thumbnails are shown on the live view. @@ -154,29 +177,6 @@ live: See [Using 2-way audio](../usage/2-way-audio.md) for more information about the very particular requirements that must be followed for 2-way audio to work. -## `ptz` - -Controls a PTZ (Pan Tilt Zoom) overlay on the `live` view. - -```yaml -live: - ptz: - [...] -``` - -| Option | Default | Description | -| - | - | - | -| `actions_left`, `actions_right`, `actions_up`, `actions_down`, `actions_zoom_in`, `actions_zoom_out`, `actions_home` | Set by camera [engine](cameras/engine.md) of the selected camera | The [actions](actions.md) to call when this icon is interacted with. | -| `data_left`, `data_right`, `data_up`, `data_down`, `data_zoom_in`, `data_zoom_out`, `data_home` | | Shorthand for a `tap_action` that calls the `service` with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[button]`. If both `actions_X` and `data_X` are specified, `actions_X` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). | -| `hide_home` | `false` | When `true` the Home button of the control is hidden | -| `hide_pan_tilt` | `false` | When `true` the Pan & Tilt buttons of the control is hidden | -| `hide_zoom` | `false` | When `true` the Zoom button of the control is hidden | -| `mode` | `on` | When `on` will show a PTZ control if so configured (manually, or by the camera engine), if `off` will not show any control. | -| `orientation` | `horizontal` | Whether to show a `vertical` or `horizontal` PTZ control. | -| `position` | `bottom-right` | Whether to position the control on the `top-left`, `top-right`, `bottom-left` or `bottom-right`. This may be overridden by using the `style` parameter to precisely control placement. | -| `service` | | An optional Home Assistant service to call when the `data_` parameters are used. | -| `style` | | Optionally position and style the element using CSS. Similar to [Picture Element styling](https://www.home-assistant.io/dashboards/picture-elements/#how-to-use-the-style-object), except without any default, e.g. `left: 42%` | - ## Fully expanded reference [](common/expanded-warning.md ':include') @@ -203,6 +203,16 @@ live: next_previous: style: chevrons size: 48 + ptz: + mode: auto + position: bottom-right + orientation: horizontal + hide_pan_tilt: false + hide_zoom: false + hide_home: false + style: + # Optionally override the default style. + right: 5% thumbnails: media_type: events events_media_type: all @@ -227,29 +237,6 @@ live: always_connected: false disconnect_seconds: 90 mute_after_microphone_mute_seconds: 60 - ptz: - mode: on - position: bottom-right - orientation: horizontal - hide_pan_tilt: false - hide_zoom: false - hide_home: false - style: - # Optionally override the default style. - right: 5% - # Manually specifying actions. - actions_left: - tap_action: - action: call-service - service: sonoff.send_command - service_data: - device: '048123' - cmd: left - # Equivalent short form PTZ actions (only right button shown) - service: sonoff.send_command - data_right: - device: '048123' - cmd: right display: mode: single grid_selected_width_factor: 2 diff --git a/docs/configuration/media-gallery.md b/docs/configuration/media-gallery.md index 8a24347b..bd7a611b 100644 --- a/docs/configuration/media-gallery.md +++ b/docs/configuration/media-gallery.md @@ -9,7 +9,7 @@ media_gallery: | Option | Default | Description | | - | - | - | -| `actions` | | [Actions](actions.md) to use for all views that use the `media_gallery` (e.g. `clips`, `snapshots`, `recordings`). | +| `actions` | | [Actions](actions/README.md) to use for all views that use the `media_gallery` (e.g. `clips`, `snapshots`, `recordings`). | | `controls` | | Configuration for the Media viewer controls. See below. | ## `controls` diff --git a/docs/configuration/media-viewer.md b/docs/configuration/media-viewer.md index e17074a2..751efaba 100644 --- a/docs/configuration/media-viewer.md +++ b/docs/configuration/media-viewer.md @@ -9,7 +9,7 @@ media_viewer: | Option | Default | Description | | - | - | - | -| `actions` | | [Actions](actions.md) to use for all views that use the `media_viewer` (e.g. `clip`, `snapshot`). | +| `actions` | | [Actions](actions/README.md) to use for all views that use the `media_viewer` (e.g. `clip`, `snapshot`). | | `auto_mute` | `[unselected, hidden]` | A list of conditions in which media items are muted. `unselected` will automatically mute when a media item is unselected in the carousel and `hidden` will automatically mute when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically mute.| | `auto_pause` | `[unselected, hidden]` | A list of conditions in which media items are automatically paused. `unselected` will automatically pause when a media item is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause.| | `auto_play` | `[selected, visible]` | A list of conditions in which media items are automatically played.`selected` will automatically play when a media item is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play.| @@ -55,6 +55,29 @@ media_viewer: | `size` | `48` | The size of the next/previous controls in pixels. Must be >= `20`.| | `style` | `thumbnails` | When viewing media, what kind of controls to show to move to the previous/next media item. Acceptable values: `thumbnails`, `chevrons`, `none` . | +### `ptz` + +Configures the PTZ (Pan Tilt Zoom) controls. As the media viewer is never +viewing live view, the PTZ controls in this context always refer to digital (vs +real) panning and zooming. + +```yaml +media_viewer: + controls: + ptz: + [...] +``` + +| Option | Default | Description | +| - | - | - | +| `hide_home` | `false` | When `true` the Home button of the control is hidden | +| `hide_pan_tilt` | `false` | When `true` the Pan & Tilt buttons of the control is hidden | +| `hide_zoom` | `false` | When `true` the Zoom button of the control is hidden | +| `mode` | `off` | If `on` or `off` will always or never show PTZ controls respectively. | +| `orientation` | `horizontal` | Whether to show a `vertical` or `horizontal` PTZ control. | +| `position` | `bottom-right` | Whether to position the control on the `top-left`, `top-right`, `bottom-left` or `bottom-right`. This may be overridden by using the `style` parameter to precisely control placement. | +| `style` | | Optionally position and style the element using CSS. Similar to [Picture Element styling](https://www.home-assistant.io/dashboards/picture-elements/#how-to-use-the-style-object), except without any default, e.g. `left: 42%` | + ### `thumbnails` Configures how thumbnails are shown on the media viewer. @@ -157,6 +180,16 @@ media_viewer: next_previous: size: 48 style: thumbnails + ptz: + mode: off + position: bottom-right + orientation: horizontal + hide_pan_tilt: false + hide_zoom: false + hide_home: false + style: + # Optionally override the default style. + right: 5% thumbnails: size: 100 mode: none diff --git a/docs/configuration/menu.md b/docs/configuration/menu.md index 093f8e11..7c956cb2 100644 --- a/docs/configuration/menu.md +++ b/docs/configuration/menu.md @@ -33,7 +33,6 @@ menu: | `camera_ui` | The `camera_ui` menu button: brings the user to a context-appropriate page on the UI of their camera engine (e.g. the Frigate camera homepage). Will only appear if the camera engine supports a camera UI (e.g. if `frigate.url` option is set for `frigate` engine users).| | `cameras` | The camera selection submenu. Will only appear if multiple cameras are configured. | | `clips` | The `clips` view menu button: brings the user to the `clips` view on tap and the most-recent `clip` view on hold. | -| `default_zoom` | The `default_zoom` button allows easily returning the camera to default pan/zoom. | | `display_mode` | The `display_mode` button allows changing between single and grid views. | | `download` | The `download` menu button: allow direct download of the media being displayed.| | `expand` | The `expand` menu button: expand the card into a popup/dialog. | @@ -41,9 +40,10 @@ menu: | `fullscreen` | The `fullscreen` menu button: expand the card to consume the fullscreen. | | `image` | The `image` view menu button: brings the user to the static `image` view. | | `live` | The `live` view menu button: brings the user to the `live` view. | -| `media_player` | The `media_player` menu button: sends the visible media to a remote media player. Supports Frigate clips, snapshots and live camera (only for cameras that specify a `camera_entity` and only using the default HA stream (equivalent to the `ha` live provider). `jsmpeg` or `webrtc-card` are not supported, although live can still be played as long as `camera_entity` is specified. In the player list, a `tap` will send the media to the player, a `hold` will stop the media on the player. | +| `media_player` | The `media_player` menu button: sends the visible media to a remote media player. Supports Frigate clips, snapshots and live camera (only for cameras that specify a `camera_entity` and only using the default HA stream (equivalent to the `ha` live provider)). `jsmpeg` or `webrtc-card` are not supported, although live can still be played as long as `camera_entity` is specified. In the player list, a `tap` will send the media to the player, a `hold` will stop the media on the player. | | `microphone` | The `microphone` button allows usage of 2-way audio in certain configurations. See [Using 2-way audio](../usage/2-way-audio.md). | -| `ptz` | The `show_ptz` button shows or hide the PTZ controls. | +| `ptz_controls` | The `ptz_controls` button shows or hides the PTZ controls. | +| `ptz_home` | The `ptz_home` button allows easily returning the camera to default home position. | | `recordings` | The `recordings` view menu button: brings the user to the `recordings` view on tap and the most-recent `recording` view on hold. | | `screenshot` | The `screenshot` menu button: take a screenshot of the loaded media (e.g. a still from a video). | | `snapshots` | The `snapshots` view menu button: brings the user to the `clips` view on tap and the most-recent `snapshot` view on hold. | @@ -54,7 +54,7 @@ menu: | Option | Default | Description | | - | - | - | | `alignment` | `matching` | Whether this button should have an alignment that is `matching` the menu alignment or `opposing` the menu. Can be used to create two separate groups of buttons on the menu. `priority` orders buttons within a given `alignment`. | -| `enabled` | `true` for `frigate`, `cameras`, `substreams`, `live`, `clips`, `snapshots`, `timeline`, `download`, `camera_ui`, `fullscreen`, `media_player`, `display_mode` and `default_zoom`. `false` for `image`, `expand`, `microphone`, `mute`, `play`, `recordings`, `screenshot`, `ptz` | Whether or not to show the button. | +| `enabled` | `true` for `frigate`, `cameras`, `substreams`, `live`, `clips`, `snapshots`, `timeline`, `download`, `camera_ui`, `fullscreen`, `media_player`, `display_mode` and `ptz_home`. `false` for `image`, `expand`, `microphone`, `mute`, `play`, `recordings`, `screenshot`, `ptz_controls` | Whether or not to show the button. | | `icon` | | An icon to overriding the default for that button, e.g. `mdi:camera-front`. | | `priority` | `50` | The button priority. Higher priority buttons are ordered closer to the start of the menu alignment (i.e. a button with priority `70` will order further to the left than a button with priority `60`, when the menu alignment is `left`). Minimum `0`, maximum `100`.| @@ -91,11 +91,6 @@ menu: enabled: true alignment: matching icon: mdi:video-switch - default_zoom: - priority: 50 - enabled: true - alignment: matching - icon: mdi:magnify-close substreams: priority: 50 enabled: true @@ -167,11 +162,16 @@ menu: enabled: false alignment: matching icon: mdi:play - show_ptz: + ptz_controls: priority: 50 enabled: false alignment: matching icon: mdi:pan + ptz_home: + priority: 50 + enabled: true + alignment: matching + icon: mdi:home button_size: 40 position: top style: hidden diff --git a/docs/configuration/view.md b/docs/configuration/view.md index cd3d2b1e..2315cc91 100644 --- a/docs/configuration/view.md +++ b/docs/configuration/view.md @@ -9,11 +9,12 @@ view: | Option | Default | Description | | - | - | - | -| `actions` | | [Actions](actions.md) to use for all views, individual actions may be overriden by view-specific actions. | +| `actions` | | [Actions](actions/README.md) to use for all views, individual actions may be overriden by view-specific actions. | | `camera_select` | `current` | The [view](view.md?id=supported-views) to show when a new camera is selected (e.g. in the camera menu). If `current` the view is unchanged when a new camera is selected. | | `dark_mode` | `off` | Whether or not to turn dark mode `on`, `off` or `auto` to automatically turn on if the card `interaction_seconds` has expired (i.e. card has been left unattended for that period of time) or if dark mode is enabled in the HA profile theme setting. Dark mode dims the brightness by `25%`.| | `default` | `live` | The view to show in the card by default. The default camera is the first one listed. See [Supported Views](view.md?id=supported-views) below. | | `interaction_seconds` | `300` | After a mouse/touch interaction with the card, it will be considered "interacted with" until this number of seconds elapses without further interaction. May be used as part of an [interaction condition](conditions.md?id=interaction) or with `reset_after_interaction` to reset the view after the interaction is complete. `0` means no interactions are reported / acted upon. | +| `keyboard_shortcuts` | See [usage](../usage/keyboard-shortcuts.md) for defaults. | Configure keyboard shortcuts. See below. | | `render_entities` | | **YAML only**: A list of entity ids that should cause the card to re-render 'in-place'. The view/camera is not changed. `update_*` flags do not pertain/relate to the behavior of this flag. This should **very** rarely be needed, but could be useful if the card is both setting and changing HA state of the same object as could be the case for some complex `card_mod` scenarios ([example](https://github.com/dermotduffy/frigate-hass-card/issues/343)). | | `reset_after_interaction` | `true` | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | | `triggers` | | How to react when a camera is [triggered](cameras/README.md?id=triggers). | @@ -22,6 +23,25 @@ view: | `update_force` | `false` | Whether automated card updates should ignore user interaction. | | `update_seconds` | `0` | A number of seconds after which to automatically update/refresh the default view. If the default view occurs sooner (e.g. manually) the timer will start over. `0` disables this functionality.| +## `keyboard_shortcuts` + +Configure the key-bindings for the builtin keyboard shortcuts. See [usage](../usage/keyboard-shortcuts.md) information for defaults on keyboard shortcuts. + +| Option | Default | Description | +| - | - | - | +| `enabled` | `true` | If `true`, keyboard shortcuts are enabled. If `false`, they are disabled. | +| `ptz_left`, `ptz_right`, `ptz_up`, `ptz_down`, `ptz_zoom_in`, `ptz_zoom_out`, `ptz_home` | See [usage](../usage/keyboard-shortcuts.md) for defaults. | An object that configures the key binding for a given pre-configured action. See below. | + +### Keyboard Shortcut Configuration + +| Option | Default | Description | +| - | - | - | +| key | | Any [keyboard key value](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values), e.g. `ArrowLeft` | +| ctrl | `false` | If `true` requires the `ctrl` key to be held. | +| shift | `false` | If `true` requires the `shift` key to be held. | +| alt | `false` | If `true` requires the `alt` key to be held. | +| meta | `false` | If `true` requires the `meta` key to be held. | + ## `triggers` The `triggers` block controls how the card reacts when a camera is triggered (note that _what_ triggers the camera is controlled by the [`triggers`](cameras/README.md?id=triggers) block within the config for a given camera). This can be used for a variety of purposes, such as allowing the card to automatically change to `live` for a camera that triggers. @@ -102,6 +122,22 @@ view: interaction_mode: inactive trigger: default untrigger: none + keyboard_shortcuts: + enabled: true + ptz_left: + key: 'ArrowLeft' + ptz_right: + key: 'ArrowRight' + ptz_up: + key: 'ArrowUp' + ptz_down: + key: 'ArrowDown' + ptz_zoom_in: + key: '+' + ptz_zoom_out: + key: '-' + ptz_home: + key: 'h' actions: entity: light.office_main_lights tap_action: diff --git a/docs/examples.md b/docs/examples.md index 5c2aa999..bf623e6e 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -37,6 +37,8 @@ dimensions: ## Automation +### Responding to fullscreen + This example will automatically turn on the first configured substream when the card is put in fullscreen mode, and turn off the substream when exiting fullscreen mode. @@ -68,6 +70,49 @@ automations: frigate_card_action: live_substream_off ``` +### Responding to key input + +In addition to a handful of reconfigurable [built-in keyboard shortcuts](./usage/keyboard-shortcuts.md), `automations` can be used to take any action based on any keyboard input. These examples use [`key` conditions](./configuration/conditions.md?id=key) to assess keyboard state before taking action. + +#### Change to `live` temporarily + +In this example, the view will change to `live`, when `Alt+Z` is pressed, and change to the `clips` view `5` seconds later. + +```yaml +automations: + - conditions: + - condition: key + key: z + alt: true + actions: + - action: custom:frigate-card-action + frigate_card_action: live + - action: custom:frigate-card-action + frigate_card_action: sleep + duration: + s: 5 + - action: custom:frigate-card-action + frigate_card_action: clips +``` + +#### Change to `live` while key _held_ down + +In this example, the view will change to `live`, when `Alt+Z` is _held_ down, and immediately change to `clips` when _released_. + +```yaml +automations: + - conditions: + - condition: key + key: z + alt: true + actions: + - action: custom:frigate-card-action + frigate_card_action: live + actions_not: + - action: custom:frigate-card-action + frigate_card_action: clips +``` + ## `card-mod` This card allows the use of @@ -162,7 +207,7 @@ elements: tap_action: action: call-service service: amcrest.ptz_control - service_data: + data: entity_id: camera.kitchen movement: up ``` @@ -374,7 +419,7 @@ elements: ## Multiple actions -This example shows how to configure multiple actions for a single Frigate card user interaction, in this case both selecting a different camera and changing the view on `tap`. Note that multiple actions are not supported on stock Picture Elements, see [actions](configuration/actions.md) for more information. +This example shows how to configure multiple actions for a single Frigate card user interaction, in this case both selecting a different camera and changing the view on `tap`. Note that multiple actions are not supported on stock Picture Elements, see [actions](configuration/actions/README.md) for more information. ```yaml type: custom:frigate-card diff --git a/docs/usage/_sidebar.md b/docs/usage/_sidebar.md index 9b69f6a3..d129cda7 100644 --- a/docs/usage/_sidebar.md +++ b/docs/usage/_sidebar.md @@ -4,9 +4,10 @@ * [Screenshots](../screenshots.md) * [Troubleshooting](../troubleshooting.md) * [Usage](README.md) - * [2-way audio](2-way-audio.md) - * [Casting](casting.md) - * [URL Actions](url-actions.md) + * [2-way audio](2-way-audio.md) + * [Casting](casting.md) + * [Keyboard Shortcuts](keyboard-shortcuts.md) + * [URL Actions](url-actions.md) --- diff --git a/docs/usage/keyboard-shortcuts.md b/docs/usage/keyboard-shortcuts.md new file mode 100644 index 00000000..c7c07bd7 --- /dev/null +++ b/docs/usage/keyboard-shortcuts.md @@ -0,0 +1,18 @@ +# Keyboard Shortcuts + +There are two ways to have the card respond to key input: + +* As a convenience, the card supports a small number of built in shortcuts with pre-defined default bindings. See below for these built in shortcuts. Use the [`keyboard_shortcuts`](../configuration/view.md?id=keyboard_shortcuts) configuration to change their bindings. +* More generally, _any_ [action](../configuration/actions/README.md) can be configured to run in response to keyboard input as part of an [automation](../configuration/automations.md), even if that action does not have a pre-defined shortcut. See [keyboard automation example](../examples.md?id=responding-to-key-input) to show how to execute any arbitrary action(s) in response to keyboard activity. + +## Built-in shortcuts + +| Name | Default key binding | Action | Description | +| - | - | - | - | +| `ptz_down` | `ArrowDown` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ move down. | +| `ptz_home` | `h` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ home / default. | +| `ptz_left` | `ArrowLeft` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ move left. | +| `ptz_right` | `ArrowRight` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ move right. | +| `ptz_up` | `ArrowUp` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ move up. | +| `ptz_zoom_in` | `+` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ zoom in. | +| `ptz_zoom_out` | `-` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ zoom out. | diff --git a/docs/usage/url-actions.md b/docs/usage/url-actions.md index 0dbbcbd8..fa026bcd 100644 --- a/docs/usage/url-actions.md +++ b/docs/usage/url-actions.md @@ -1,7 +1,7 @@ # URL Actions It is possible to pass the Frigate card one or more -[actions](../configuration/actions.md) from the URL (e.g. select a particular +[actions](../configuration/actions/README.md) from the URL (e.g. select a particular camera, open the live view in expanded mode, etc). ### When actions are executed @@ -44,7 +44,7 @@ unless the action is targeted with a `CARD_ID` as shown above. ## Supported Actions -Only a subset of all [actions](../configuration/actions.md) are supported in URL form. +Only a subset of all [actions](../configuration/actions/README.md) are supported in URL form. | Action | Supported in URL | Explanation | | - | - | - | @@ -68,7 +68,7 @@ Only a subset of all [actions](../configuration/actions.md) are supported in URL | `recording` | :white_check_mark: | | | `recordings` | :white_check_mark: | | | `screenshot`| :heavy_multiplication_x: | Latest media information is not available on initial render. | -| `show_ptz` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/frigate-hass-card/issues) if you need this. | +| `ptz_controls` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/frigate-hass-card/issues) if you need this. | | `snapshot` | :white_check_mark: | | | `snapshots` | :white_check_mark: | | diff --git a/package.json b/package.json index a188473e..fb25a6bf 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "@types/masonry-layout": "^4.2.5", "@typescript-eslint/eslint-plugin": "^7.12.0", "@typescript-eslint/parser": "^7.12.0", - "@vitest/coverage-istanbul": "^1.5.0", + "@vitest/coverage-istanbul": "^1.6.0", "docsify-cli": "^4.4.4", "eslint": "^8.57.0", "eslint-config-airbnb-base": "^15.0.0", @@ -82,6 +82,7 @@ "sass": "^1.54.9", "ts-prune": "^0.10.3", "typescript": "^5.4.5", + "type-fest": "^4.18.0", "vitest": "^1.5.0", "vitest-mock-extended": "^1.3.1" }, diff --git a/src/action-handler-directive.ts b/src/action-handler-directive.ts index 5a7a4448..387654c2 100644 --- a/src/action-handler-directive.ts +++ b/src/action-handler-directive.ts @@ -92,6 +92,16 @@ class ActionHandler extends HTMLElement implements ActionHandlerInterface { } }; + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const endTap = (_ev: Event): void => { + this.holdTimer.stop(); + + if (this.started) { + this.started = false; + fireEvent(element, 'action', { action: 'end_tap' }); + } + }; + const end = (ev: Event): void => { const options = element.actionHandlerOptions; if (!options?.allowPropagation) { @@ -109,10 +119,7 @@ class ActionHandler extends HTMLElement implements ActionHandlerInterface { return; } - this.holdTimer.stop(); - - this.started = false; - fireEvent(element, 'action', { action: 'end_tap' }); + endTap(ev); if (options?.hasHold && this.held) { fireEvent(element, 'action', { action: 'hold' }); @@ -147,6 +154,9 @@ class ActionHandler extends HTMLElement implements ActionHandlerInterface { element.addEventListener('click', end); element.addEventListener('keyup', handleEnter); + + // If the mouse leaves the element, this is considered the end of the interaction. + element.addEventListener('mouseleave', endTap); } } diff --git a/src/camera-manager/browse-media/engine-browse-media.ts b/src/camera-manager/browse-media/engine-browse-media.ts index d12d94f0..6f7e236d 100644 --- a/src/camera-manager/browse-media/engine-browse-media.ts +++ b/src/camera-manager/browse-media/engine-browse-media.ts @@ -31,6 +31,7 @@ import { import { BrowseMediaCamera } from './camera'; import { BrowseMediaViewMediaFactory } from './media'; import { BrowseMediaMetadata } from './types'; +import { getPTZCapabilitiesFromCameraConfig } from '../utils/ptz'; /** * A utility method to determine if a browse media object matches against a @@ -154,6 +155,7 @@ export class BrowseMediaCameraManagerEngine seek: false, snapshots: true, substream: true, + ptz: getPTZCapabilitiesFromCameraConfig(cameraConfig) ?? undefined, }, { disable: cameraConfig.capabilities?.disable, diff --git a/src/camera-manager/camera.ts b/src/camera-manager/camera.ts index c1bf6b14..c987b9f3 100644 --- a/src/camera-manager/camera.ts +++ b/src/camera-manager/camera.ts @@ -8,10 +8,10 @@ import { subscribeToTrigger, } from '../utils/ha'; import { EntityRegistryManager } from '../utils/ha/entity-registry'; +import { Capabilities } from './capabilities'; import { CameraManagerEngine } from './engine'; import { CameraNoIDError } from './error'; import { CameraEventCallback } from './types'; -import { Capabilities } from './capabilities'; type DestroyCallback = () => Promise; diff --git a/src/camera-manager/capabilities.ts b/src/camera-manager/capabilities.ts index 29c79456..cb3e07be 100644 --- a/src/camera-manager/capabilities.ts +++ b/src/camera-manager/capabilities.ts @@ -54,6 +54,18 @@ export class Capabilities { return this._capabilities.ptz ?? null; } + public hasPTZCapability(): boolean { + return !!( + this._capabilities.ptz?.down?.length || + this._capabilities.ptz?.up?.length || + this._capabilities.ptz?.left?.length || + this._capabilities.ptz?.right?.length || + this._capabilities.ptz?.zoomIn?.length || + this._capabilities.ptz?.zoomOut?.length || + this._capabilities.ptz?.presets?.length + ); + } + public getRawCapabilities(): CapabilitiesRaw { return this._capabilities; } diff --git a/src/camera-manager/engine.ts b/src/camera-manager/engine.ts index d9d09971..a17c0110 100644 --- a/src/camera-manager/engine.ts +++ b/src/camera-manager/engine.ts @@ -1,5 +1,5 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { CameraConfig, PTZAction, PTZPhase } from '../config/types'; +import { CameraConfig, ActionPhase } from '../config/types'; import { ExtendedHomeAssistant } from '../types'; import { EntityRegistryManager } from '../utils/ha/entity-registry'; import { ViewMedia } from '../view/media'; @@ -27,6 +27,7 @@ import { RecordingSegmentsQuery, RecordingSegmentsQueryResultsMap, } from './types'; +import { PTZAction } from '../config/ptz'; export const CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT = 10000; @@ -139,7 +140,7 @@ export interface CameraManagerEngine { cameraConfig: CameraConfig, action: PTZAction, options?: { - phase?: PTZPhase; + phase?: ActionPhase; preset?: string; }, ): Promise; diff --git a/src/camera-manager/frigate/camera.ts b/src/camera-manager/frigate/camera.ts index fdef3229..f00d1117 100644 --- a/src/camera-manager/frigate/camera.ts +++ b/src/camera-manager/frigate/camera.ts @@ -3,7 +3,10 @@ import uniq from 'lodash-es/uniq'; import { CameraConfig } from '../../config/types'; import { localize } from '../../localize/localize'; import { PTZCapabilities, PTZMovementType } from '../../types'; -import { errorToConsole } from '../../utils/basic'; +import { + errorToConsole, + recursivelyMergeObjectsConcatenatingArraysUniquely, +} from '../../utils/basic'; import { subscribeToTrigger } from '../../utils/ha'; import { EntityRegistryManager } from '../../utils/ha/entity-registry'; import { Entity } from '../../utils/ha/entity-registry/types'; @@ -13,6 +16,7 @@ import { CameraInitializationError } from '../error'; import { getCameraEntityFromConfig } from '../utils/camera-entity-from-config'; import { getPTZInfo } from './requests'; import { PTZInfo, frigateEventChangeTriggerResponseSchema } from './types'; +import { getPTZCapabilitiesFromCameraConfig } from '../utils/ptz'; const CAMERA_BIRDSEYE = 'birdseye' as const; @@ -97,7 +101,18 @@ export class FrigateCamera extends Camera { protected async _initializeCapabilities(hass: HomeAssistant): Promise { const config = this.getConfig(); - const ptz = await this._getPTZCapabilities(hass, config); + + const configPTZCapabilities = getPTZCapabilitiesFromCameraConfig(this.getConfig()); + const frigatePTZCapabilities = await this._getPTZCapabilities(hass, config); + const combinedPTZCapabilities = + configPTZCapabilities || frigatePTZCapabilities + ? recursivelyMergeObjectsConcatenatingArraysUniquely( + {}, + configPTZCapabilities, + frigatePTZCapabilities, + ) + : null; + const birdseye = isBirdseye(config); this._capabilities = new Capabilities( { @@ -110,7 +125,7 @@ export class FrigateCamera extends Camera { live: true, menu: true, substream: true, - ...(ptz && { ptz: ptz }), + ...(combinedPTZCapabilities && { ptz: combinedPTZCapabilities }), }, { disable: config.capabilities?.disable, @@ -153,20 +168,25 @@ export class FrigateCamera extends Camera { return null; } + // Note: The Frigate integration only supports continuous PTZ movements + // (regardless of the actual underlying camera capability). const panTilt: PTZMovementType[] = [ ...(ptzInfo.features?.includes('pt') ? ['continuous' as const] : []), - ...(ptzInfo.features?.includes('pt-r') ? ['relative' as const] : []), ]; const zoom: PTZMovementType[] = [ ...(ptzInfo.features?.includes('zoom') ? ['continuous' as const] : []), - ...(ptzInfo.features?.includes('zoom-r') ? ['relative' as const] : []), ]; const presets = ptzInfo.presets; if (panTilt.length || zoom.length || presets?.length) { return { - ...(panTilt && { panTilt: panTilt }), - ...(zoom && { zoom: zoom }), + ...(panTilt && { + left: panTilt, + right: panTilt, + up: panTilt, + down: panTilt, + }), + ...(zoom && { zoomIn: zoom, zoomOut: zoom }), ...(presets && { presets: presets }), }; } diff --git a/src/camera-manager/frigate/engine-frigate.ts b/src/camera-manager/frigate/engine-frigate.ts index de6ef537..0f01bae3 100644 --- a/src/camera-manager/frigate/engine-frigate.ts +++ b/src/camera-manager/frigate/engine-frigate.ts @@ -4,7 +4,8 @@ import isEqual from 'lodash-es/isEqual'; import orderBy from 'lodash-es/orderBy'; import throttle from 'lodash-es/throttle'; import uniqWith from 'lodash-es/uniqWith'; -import { CameraConfig, PTZAction, PTZPhase } from '../../config/types'; +import { PTZAction } from '../../config/ptz'; +import { ActionPhase, CameraConfig } from '../../config/types'; import { ExtendedHomeAssistant } from '../../types'; import { allPromises, @@ -19,8 +20,8 @@ import { ViewMediaClassifier } from '../../view/media-classifier'; import { RecordingSegmentsCache, RequestCache } from '../cache'; import { Camera } from '../camera'; import { - CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT, CameraManagerEngine, + CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT, } from '../engine'; import { GenericCameraManagerEngine } from '../generic/engine-generic'; import { DateRange } from '../range'; @@ -61,12 +62,12 @@ import { FrigateCamera, isBirdseye } from './camera'; import { FrigateViewMediaFactory } from './media'; import { FrigateViewMediaClassifier } from './media-classifier'; import { - NativeFrigateEventQuery, - NativeFrigateRecordingSegmentsQuery, - getEventSummary, getEvents, + getEventSummary, getRecordingSegments, getRecordingsSummary, + NativeFrigateEventQuery, + NativeFrigateRecordingSegmentsQuery, retainEvent, } from './requests'; import { @@ -1015,7 +1016,7 @@ export class FrigateCameraManagerEngine cameraConfig: CameraConfig, action: PTZAction, options?: { - phase?: PTZPhase; + phase?: ActionPhase; preset?: string; }, ): Promise { diff --git a/src/camera-manager/generic/engine-generic.ts b/src/camera-manager/generic/engine-generic.ts index 971aec8b..dc69f35e 100644 --- a/src/camera-manager/generic/engine-generic.ts +++ b/src/camera-manager/generic/engine-generic.ts @@ -1,8 +1,9 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { CameraConfig, PTZAction, PTZPhase } from '../../config/types'; -import { ExtendedHomeAssistant } from '../../types'; +import { PTZAction, PTZ_PAN_TILT_ACTIONS, PTZ_ZOOM_ACTIONS } from '../../config/ptz'; +import { ActionPhase, CameraConfig } from '../../config/types'; +import { ExtendedHomeAssistant, PTZCapabilities, PTZMovementType } from '../../types'; import { getEntityIcon, getEntityTitle } from '../../utils/ha'; import { EntityRegistryManager } from '../../utils/ha/entity-registry'; import { ViewMedia } from '../../view/media'; @@ -35,6 +36,7 @@ import { } from '../types'; import { getCameraEntityFromConfig } from '../utils/camera-entity-from-config'; import { getDefaultGo2RTCEndpoint } from '../utils/go2rtc-endpoint'; +import { getPTZCapabilitiesFromCameraConfig } from '../utils/ptz'; export class GenericCameraManagerEngine implements CameraManagerEngine { protected _eventCallback?: CameraEventCallback; @@ -64,6 +66,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { seek: false, snapshots: false, substream: true, + ptz: getPTZCapabilitiesFromCameraConfig(cameraConfig) ?? undefined, }, { disable: cameraConfig.capabilities?.disable, @@ -222,7 +225,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { _cameraConfig: CameraConfig, _action: PTZAction, _options?: { - phase?: PTZPhase; + phase?: ActionPhase; preset?: string; }, ): Promise { diff --git a/src/camera-manager/manager.ts b/src/camera-manager/manager.ts index e73776de..9bae0252 100644 --- a/src/camera-manager/manager.ts +++ b/src/camera-manager/manager.ts @@ -3,7 +3,8 @@ import cloneDeep from 'lodash-es/cloneDeep'; import sum from 'lodash-es/sum'; import PQueue from 'p-queue'; import { CardCameraAPI } from '../card-controller/types.js'; -import { CameraConfig, CamerasConfig, PTZAction, PTZPhase } from '../config/types.js'; +import { PTZAction } from '../config/ptz.js'; +import { ActionPhase, CameraConfig, CamerasConfig } from '../config/types.js'; import { MEDIA_CHUNK_SIZE_DEFAULT } from '../const.js'; import { localize } from '../localize/localize.js'; import { @@ -15,6 +16,7 @@ import { } from '../utils/basic.js'; import { getCameraID } from '../utils/camera.js'; import { log } from '../utils/debug.js'; +import { getConfiguredPTZAction } from './utils/ptz.js'; import { ViewMedia } from '../view/media.js'; import { Capabilities } from './capabilities.js'; import { CameraManagerEngineFactory } from './engine-factory.js'; @@ -771,18 +773,26 @@ export class CameraManager { public async executePTZAction( cameraID: string, action: PTZAction, - options: { - phase?: PTZPhase; + options?: { + phase?: ActionPhase; preset?: string; }, ): Promise { - const hass = this._api.getHASSManager().getHASS(); - const engine = this._store.getEngineForCameraID(cameraID); const cameraConfig = this._store.getCameraConfig(cameraID); - - if (!engine || !cameraConfig || !hass) { + if (!cameraConfig) { return; } - return engine.executePTZAction(hass, cameraConfig, action, options); + const configuredAction = getConfiguredPTZAction(cameraConfig, action, options); + if (configuredAction) { + return await this._api.getActionsManager().executeActions(configuredAction); + } + + const hass = this._api.getHASSManager().getHASS(); + const engine = this._store.getEngineForCameraID(cameraID); + + if (!engine || !hass) { + return; + } + return await engine.executePTZAction(hass, cameraConfig, action, options); } } diff --git a/src/camera-manager/utils/ptz.ts b/src/camera-manager/utils/ptz.ts new file mode 100644 index 00000000..78a6ccd0 --- /dev/null +++ b/src/camera-manager/utils/ptz.ts @@ -0,0 +1,82 @@ +import { PTZAction, PTZBaseAction } from '../../config/ptz'; +import { ActionPhase, ActionType, CameraConfig } from '../../config/types'; +import { PTZCapabilities, PTZMovementType } from '../../types'; + +export const getConfiguredPTZAction = ( + cameraConfig: CameraConfig, + action: PTZAction, + options?: { + phase?: ActionPhase; + preset?: string; + }, +): ActionType | ActionType[] | null => { + if (action === 'preset') { + return (options?.preset ? cameraConfig.ptz.presets?.[options.preset] : null) ?? null; + } + + if (options?.phase) { + return cameraConfig.ptz[`actions_${action}_${options.phase}`] ?? null; + } + + return cameraConfig.ptz[`actions_${action}`] ?? null; +}; + +const hasConfiguredPTZAction = ( + cameraConfig: CameraConfig, + action: PTZBaseAction, + options?: { + phase?: ActionPhase; + preset?: string; + }, +): boolean => { + return !!getConfiguredPTZAction(cameraConfig, action, options); +}; + +export const getConfiguredPTZMovementType = ( + cameraConfig: CameraConfig, + action: PTZBaseAction, +): PTZMovementType[] | null => { + const continuous = + hasConfiguredPTZAction(cameraConfig, action, { phase: 'start' }) && + hasConfiguredPTZAction(cameraConfig, action, { phase: 'stop' }); + const relative = hasConfiguredPTZAction(cameraConfig, action); + + return continuous || relative + ? [ + ...(continuous ? ['continuous' as const] : []), + ...(relative ? ['relative' as const] : []), + ] + : null; +}; + +export const getPTZCapabilitiesFromCameraConfig = ( + cameraConfig: CameraConfig, +): PTZCapabilities | null => { + const left = getConfiguredPTZMovementType(cameraConfig, 'left'); + const right = getConfiguredPTZMovementType(cameraConfig, 'right'); + const up = getConfiguredPTZMovementType(cameraConfig, 'up'); + const down = getConfiguredPTZMovementType(cameraConfig, 'down'); + const zoomIn = getConfiguredPTZMovementType(cameraConfig, 'zoom_in'); + const zoomOut = getConfiguredPTZMovementType(cameraConfig, 'zoom_out'); + const presets = cameraConfig.ptz.presets + ? Object.keys(cameraConfig.ptz.presets) + : undefined; + + return left?.length || + right?.length || + up?.length || + down?.length || + zoomIn?.length || + zoomOut?.length || + presets?.length + ? { + left: left ?? undefined, + right: right ?? undefined, + up: up ?? undefined, + down: down ?? undefined, + zoomIn: zoomIn ?? undefined, + zoomOut: zoomOut ?? undefined, + presets: presets, + } + : null; +}; diff --git a/src/card-controller/actions-manager.ts b/src/card-controller/actions-manager.ts deleted file mode 100644 index 08eff63c..00000000 --- a/src/card-controller/actions-manager.ts +++ /dev/null @@ -1,285 +0,0 @@ -import { z } from 'zod'; -import { - Actions, - ActionsConfig, - ActionType, - FrigateCardCustomAction, -} from '../config/types.js'; -import { - convertActionToFrigateCardCustomAction, - frigateCardHandleAction, - frigateCardHandleActionConfig, - getActionConfigGivenAction, -} from '../utils/action.js'; -import { getStreamCameraID } from '../utils/substream.js'; -import { generateViewContextForZoomChange } from '../components-lib/zoom/zoom-view-context.js'; -import { CardActionsManagerAPI } from './types.js'; - -const interactionSchema = z.object({ - action: z.enum(['tap', 'double_tap', 'hold', 'start_tap', 'end_tap']), -}); -export type Interaction = z.infer; - -const interactionEventSchema = z.object({ - detail: interactionSchema, -}); - -export class ActionsManager { - protected _api: CardActionsManagerAPI; - - constructor(api: CardActionsManagerAPI) { - this._api = api; - } - - /** - * Merge card-wide and view-specific actions. - * @returns A combined set of action. - */ - public getMergedActions(): ActionsConfig { - const view = this._api.getViewManager().getView(); - if (this._api.getMessageManager().hasMessage()) { - return {}; - } - - const config = this._api.getConfigManager().getConfig(); - let specificActions: Actions | undefined = undefined; - if (view?.is('live')) { - specificActions = config?.live.actions; - } else if (view?.isGalleryView()) { - specificActions = config?.media_gallery?.actions; - } else if (view?.isViewerView()) { - specificActions = config?.media_viewer.actions; - } else if (view?.is('image')) { - specificActions = config?.image?.actions; - } else { - return {}; - } - return { ...config?.view.actions, ...specificActions }; - } - - /** - * Handle an human interaction called on an element (e.g. 'tap'). - */ - public handleInteractionEvent = (ev: Event): void => { - const result = interactionEventSchema.safeParse(ev); - if (!result.success) { - return; - } - const interaction = result.data.detail.action; - const hass = this._api.getHASSManager().getHASS(); - const config = this.getMergedActions(); - const actionConfig = getActionConfigGivenAction(interaction, config); - if ( - hass && - config && - interaction && - // Don't call frigateCardHandleActionConfig() unless there is explicitly an - // action defined (as it uses a default that is unhelpful for views that - // have default tap/click actions). - actionConfig - ) { - frigateCardHandleActionConfig( - this._api.getCardElementManager().getElement(), - hass, - config, - interaction, - actionConfig, - ); - } - }; - - public handleActionEvent = (ev: Event): void => { - if (!('detail' in ev)) { - // The event may not be a CustomEvent object, see: - // https://github.com/custom-cards/custom-card-helpers/blob/master/src/fire-event.ts#L70 - return; - } - - const frigateCardAction = convertActionToFrigateCardCustomAction(ev.detail); - if (frigateCardAction) { - this.executeFrigateAction(frigateCardAction); - } - }; - - /** - * Small convenience method to call frigateCardHandleAction without the caller - * needing hass or the element. - */ - public executeActions(actions: ActionType | ActionType[]): void { - const hass = this._api.getHASSManager().getHASS(); - if (!hass) { - return; - } - - frigateCardHandleAction( - this._api.getCardElementManager().getElement(), - hass, - {}, - actions, - ); - } - - /** - * Execute a card action. - * @param frigateCardAction - * @returns `true` if an action is executed. - */ - public async executeFrigateAction( - frigateCardAction: FrigateCardCustomAction, - ): Promise { - const config = this._api.getConfigManager().getConfig(); - const mediaLoadedInfoManager = this._api.getMediaLoadedInfoManager(); - - if ( - // Command not intended for this card (e.g. query string command). - frigateCardAction.card_id && - config?.card_id !== frigateCardAction.card_id - ) { - return; - } - - // Note: This function needs to process (view-related) commands even when - // _view has not yet been initialized (since it may be used to set a view - // via the querystring). - const view = this._api.getViewManager().getView(); - - const action = frigateCardAction.frigate_card_action; - - switch (action) { - case 'default': - this._api.getViewManager().setViewDefault(); - break; - case 'clip': - case 'clips': - case 'image': - case 'live': - case 'recording': - case 'recordings': - case 'snapshot': - case 'snapshots': - case 'timeline': - this._api.getViewManager().setViewByParameters({ - viewName: action, - cameraID: view?.camera, - }); - break; - case 'download': - await this._api.getDownloadManager().downloadViewerMedia(); - break; - case 'camera_ui': - this._api.getCameraURLManager().openURL(); - break; - case 'expand': - this._api.getExpandManager().toggleExpanded(); - break; - case 'fullscreen': - this._api.getFullscreenManager().toggleFullscreen(); - break; - case 'menu_toggle': - // This is a rare code path: this would only be used if someone has a - // menu toggle action configured outside of the menu itself (e.g. - // picture elements). - this._api.getCardElementManager().toggleMenu(); - break; - case 'camera_select': - const selectCameraID = - frigateCardAction.camera ?? - (frigateCardAction.triggered - ? this._api.getTriggersManager().getMostRecentlyTriggeredCameraID() - : null); - if (selectCameraID && view) { - const viewOnCameraSelect = config?.view.camera_select ?? 'current'; - const targetViewName = - viewOnCameraSelect === 'current' ? view.view : viewOnCameraSelect; - this._api.getViewManager().setViewByParameters({ - viewName: targetViewName, - cameraID: selectCameraID, - failSafe: true, - }); - } - break; - case 'live_substream_select': { - this._api.getViewManager().setViewWithSubstream(frigateCardAction.camera); - break; - } - case 'live_substream_off': { - this._api.getViewManager().setViewWithoutSubstream(); - break; - } - case 'live_substream_on': { - this._api.getViewManager().setViewWithSubstream(); - break; - } - case 'media_player': - const mediaPlayer = frigateCardAction.media_player; - const mediaPlayerController = this._api.getMediaPlayerManager(); - const media = view?.queryResults?.getSelectedResult() ?? null; - - if (frigateCardAction.media_player_action === 'stop') { - await mediaPlayerController.stop(mediaPlayer); - } else if (view?.is('live')) { - await mediaPlayerController.playLive(mediaPlayer, getStreamCameraID(view)); - } else if (view?.isViewerView() && media) { - await mediaPlayerController.playMedia(mediaPlayer, media); - } - break; - case 'diagnostics': - this._api.getViewManager().setViewByParameters({ viewName: 'diagnostics' }); - break; - case 'microphone_mute': - this._api.getMicrophoneManager().mute(); - break; - case 'microphone_unmute': - await this._api.getMicrophoneManager().unmute(); - break; - case 'mute': - await mediaLoadedInfoManager.get()?.player?.mute(); - break; - case 'unmute': - await mediaLoadedInfoManager.get()?.player?.unmute(); - break; - case 'play': - await mediaLoadedInfoManager.get()?.player?.play(); - break; - case 'pause': - await mediaLoadedInfoManager.get()?.player?.pause(); - break; - case 'screenshot': - await this._api.getDownloadManager().downloadScreenshot(); - break; - case 'display_mode_select': - this._api - .getViewManager() - .setViewWithNewDisplayMode(frigateCardAction.display_mode); - break; - case 'ptz': - const cameraID = this._api.getViewManager().getView()?.camera; - if (cameraID) { - this._api - .getCameraManager() - .executePTZAction(cameraID, frigateCardAction.ptz_action, { - phase: frigateCardAction.ptz_phase, - preset: frigateCardAction.ptz_preset, - }); - } - break; - case 'show_ptz': - this._api.getViewManager().setViewWithMergedContext({ - live: { ptzVisible: frigateCardAction.show_ptz }, - }); - break; - case 'change_zoom': - this._api.getViewManager().setViewWithMergedContext( - generateViewContextForZoomChange(frigateCardAction.target_id, { - zoom: { - pan: frigateCardAction.pan, - zoom: frigateCardAction.zoom, - }, - }), - ); - break; - default: - console.warn(`Frigate card received unknown card action: ${action}`); - } - } -} diff --git a/src/card-controller/actions/actions-manager.ts b/src/card-controller/actions/actions-manager.ts new file mode 100644 index 00000000..79bea074 --- /dev/null +++ b/src/card-controller/actions/actions-manager.ts @@ -0,0 +1,121 @@ +import { z } from 'zod'; +import { Actions, ActionsConfig, ActionType } from '../../config/types.js'; +import { getActionConfigGivenAction } from '../../utils/action.js'; +import { ActionSet } from './actions/set.js'; +import { CardActionsManagerAPI } from '../types.js'; +import { ActionExecutionRequest, AuxillaryActionConfig } from './types.js'; +import { ActionContext } from 'action'; + +const INTERACTIONS = ['tap', 'double_tap', 'hold', 'start_tap', 'end_tap'] as const; +export type InteractionName = (typeof INTERACTIONS)[number]; + +const interactionSchema = z.object({ + action: z.enum(INTERACTIONS), +}); +export type Interaction = z.infer; + +const interactionEventSchema = z.object({ + detail: interactionSchema, +}); + +export class ActionsManager { + protected _api: CardActionsManagerAPI; + protected _actionsInFlight: ActionSet[] = []; + protected _actionContext: ActionContext = {}; + + constructor(api: CardActionsManagerAPI) { + this._api = api; + } + + /** + * Merge card-wide and view-specific actions. + * @returns A combined set of action. + */ + public getMergedActions(): ActionsConfig { + const view = this._api.getViewManager().getView(); + if (this._api.getMessageManager().hasMessage()) { + return {}; + } + + const config = this._api.getConfigManager().getConfig(); + let specificActions: Actions | undefined = undefined; + if (view?.is('live')) { + specificActions = config?.live.actions; + } else if (view?.isGalleryView()) { + specificActions = config?.media_gallery?.actions; + } else if (view?.isViewerView()) { + specificActions = config?.media_viewer.actions; + } else if (view?.is('image')) { + specificActions = config?.image?.actions; + } else { + return {}; + } + return { ...config?.view.actions, ...specificActions }; + } + + /** + * Handle an human interaction called on an element (e.g. 'tap'). + */ + public handleInteractionEvent = (ev: Event): void => { + const result = interactionEventSchema.safeParse(ev); + if (!result.success) { + return; + } + const interaction = result.data.detail.action; + const config = this.getMergedActions(); + const actionConfig = getActionConfigGivenAction(interaction, config); + if ( + config && + interaction && + // Don't call frigateCardHandleActionConfig() unless there is explicitly an + // action defined (as it uses a default that is unhelpful for views that + // have default tap/click actions). + actionConfig + ) { + this.executeActions(actionConfig, config); + } + }; + + /** + * This method is called when an ll-custom event is fired. This is used by + * cards to fire custom actions. This card itself should not call this, but + * embedded elements may. + */ + public handleCustomActionEvent = (ev: Event): void => { + if (!('detail' in ev)) { + // The event may not be a CustomEvent object, see: + // https://github.com/custom-cards/custom-card-helpers/blob/master/src/fire-event.ts#L70 + return; + } + this.executeActions(ev.detail as ActionType); + }; + + /** + * This method handles actions requested by components of the Frigate card + * itself (e.g. menu, PTZ controller). + */ + public handleActionExecutionRequestEvent = async ( + ev: CustomEvent, + ): Promise => { + await this.executeActions(ev.detail.action, ev.detail.config); + }; + + public uninitialize(): void { + // If there are any long-running actions, ensure they are stopped. + this._actionsInFlight.forEach((actionSet) => actionSet.stop()); + } + + public async executeActions( + action: ActionType | ActionType[], + config?: AuxillaryActionConfig, + ): Promise { + const actionSet = new ActionSet(this._actionContext, action, { + config: config, + cardID: this._api.getConfigManager().getConfig()?.card_id, + }); + + this._actionsInFlight.push(actionSet); + await actionSet.execute(this._api); + this._actionsInFlight = this._actionsInFlight.filter((a) => a !== actionSet); + } +} diff --git a/src/card-controller/actions/actions/base.ts b/src/card-controller/actions/actions/base.ts new file mode 100644 index 00000000..12533296 --- /dev/null +++ b/src/card-controller/actions/actions/base.ts @@ -0,0 +1,29 @@ +import { ActionContext } from 'action'; +import { FrigateCardCustomAction } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { Action, AuxillaryActionConfig } from '../types'; + +export class BaseAction implements Action { + protected _context: ActionContext; + protected _action: T; + protected _config?: AuxillaryActionConfig; + + constructor(context: ActionContext, action: T, config?: AuxillaryActionConfig) { + this._context = context; + this._action = action; + this._config = config; + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public async execute(_api: CardActionsAPI): Promise { + // Pass. + } + + public async stop(): Promise { + // Pass. + } +} + +export class FrigateCardAction< + T extends FrigateCardCustomAction, +> extends BaseAction {} diff --git a/src/card-controller/actions/actions/camera-select.ts b/src/card-controller/actions/actions/camera-select.ts new file mode 100644 index 00000000..c5f82ce2 --- /dev/null +++ b/src/card-controller/actions/actions/camera-select.ts @@ -0,0 +1,26 @@ +import { CameraSelectActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class CameraSelectAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + const selectCameraID = + this._action.camera ?? + (this._action.triggered + ? api.getTriggersManager().getMostRecentlyTriggeredCameraID() + : null); + const view = api.getViewManager().getView(); + const config = api.getConfigManager().getConfig(); + + if (selectCameraID && view) { + const viewOnCameraSelect = config?.view.camera_select ?? 'current'; + const targetViewName = + viewOnCameraSelect === 'current' ? view.view : viewOnCameraSelect; + api.getViewManager().setViewByParameters({ + viewName: targetViewName, + cameraID: selectCameraID, + failSafe: true, + }); + } + } +} diff --git a/src/card-controller/actions/actions/camera-ui.ts b/src/card-controller/actions/actions/camera-ui.ts new file mode 100644 index 00000000..148788c9 --- /dev/null +++ b/src/card-controller/actions/actions/camera-ui.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class CameraUIAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + api.getCameraURLManager().openURL(); + } +} diff --git a/src/card-controller/actions/actions/default.ts b/src/card-controller/actions/actions/default.ts new file mode 100644 index 00000000..5fa12f40 --- /dev/null +++ b/src/card-controller/actions/actions/default.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class DefaultAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + api.getViewManager().setViewDefault(); + } +} diff --git a/src/card-controller/actions/actions/display-mode-select.ts b/src/card-controller/actions/actions/display-mode-select.ts new file mode 100644 index 00000000..adacf29d --- /dev/null +++ b/src/card-controller/actions/actions/display-mode-select.ts @@ -0,0 +1,9 @@ +import { DisplayModeActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class DisplayModeSelectAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + await api.getViewManager().setViewWithNewDisplayMode(this._action.display_mode); + } +} diff --git a/src/card-controller/actions/actions/download.ts b/src/card-controller/actions/actions/download.ts new file mode 100644 index 00000000..5103202e --- /dev/null +++ b/src/card-controller/actions/actions/download.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class DownloadAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + await api.getDownloadManager().downloadViewerMedia(); + } +} diff --git a/src/card-controller/actions/actions/expand.ts b/src/card-controller/actions/actions/expand.ts new file mode 100644 index 00000000..94d80d48 --- /dev/null +++ b/src/card-controller/actions/actions/expand.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class ExpandAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + api.getExpandManager().toggleExpanded(); + } +} diff --git a/src/card-controller/actions/actions/fullscreen.ts b/src/card-controller/actions/actions/fullscreen.ts new file mode 100644 index 00000000..411b08d2 --- /dev/null +++ b/src/card-controller/actions/actions/fullscreen.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class FullscreenAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + api.getFullscreenManager().toggleFullscreen(); + } +} diff --git a/src/card-controller/actions/actions/generic.ts b/src/card-controller/actions/actions/generic.ts new file mode 100644 index 00000000..9b7fda95 --- /dev/null +++ b/src/card-controller/actions/actions/generic.ts @@ -0,0 +1,20 @@ +import { ActionConfig, handleActionConfig } from '@dermotduffy/custom-card-helpers'; +import { CardActionsAPI } from '../../types'; +import { BaseAction } from './base'; + +/** + * Handles generic HA (non-Frigate) actions (e.g. 'more-info') + */ +export class GenericAction extends BaseAction { + public async execute(api: CardActionsAPI): Promise { + const hass = api.getHASSManager().getHASS(); + if (hass) { + handleActionConfig( + api.getCardElementManager().getElement(), + hass, + this._config ?? {}, + this._action, + ); + } + } +} diff --git a/src/card-controller/actions/actions/log.ts b/src/card-controller/actions/actions/log.ts new file mode 100644 index 00000000..50302f37 --- /dev/null +++ b/src/card-controller/actions/actions/log.ts @@ -0,0 +1,10 @@ +import { LogActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class LogAction extends FrigateCardAction { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public async execute(_api: CardActionsAPI): Promise { + console[this._action.level](this._action.message); + } +} diff --git a/src/card-controller/actions/actions/media-player.ts b/src/card-controller/actions/actions/media-player.ts new file mode 100644 index 00000000..8ecfc574 --- /dev/null +++ b/src/card-controller/actions/actions/media-player.ts @@ -0,0 +1,21 @@ +import { MediaPlayerActionConfig } from '../../../config/types'; +import { getStreamCameraID } from '../../../utils/substream'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class MediaPlayerAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + const mediaPlayer = this._action.media_player; + const mediaPlayerController = api.getMediaPlayerManager(); + const view = api.getViewManager().getView(); + const media = view?.queryResults?.getSelectedResult() ?? null; + + if (this._action.media_player_action === 'stop') { + await mediaPlayerController.stop(mediaPlayer); + } else if (view?.is('live')) { + await mediaPlayerController.playLive(mediaPlayer, getStreamCameraID(view)); + } else if (view?.isViewerView() && media) { + await mediaPlayerController.playMedia(mediaPlayer, media); + } + } +} diff --git a/src/card-controller/actions/actions/menu-toggle.ts b/src/card-controller/actions/actions/menu-toggle.ts new file mode 100644 index 00000000..1cbac07d --- /dev/null +++ b/src/card-controller/actions/actions/menu-toggle.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class MenuToggleAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + api.getCardElementManager().toggleMenu(); + } +} diff --git a/src/card-controller/actions/actions/microphone-mute.ts b/src/card-controller/actions/actions/microphone-mute.ts new file mode 100644 index 00000000..c7a6c1bb --- /dev/null +++ b/src/card-controller/actions/actions/microphone-mute.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class MicrophoneMuteAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + api.getMicrophoneManager().mute(); + } +} diff --git a/src/card-controller/actions/actions/microphone-unmute.ts b/src/card-controller/actions/actions/microphone-unmute.ts new file mode 100644 index 00000000..8757b2a8 --- /dev/null +++ b/src/card-controller/actions/actions/microphone-unmute.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class MicrophoneUnmuteAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + await api.getMicrophoneManager().unmute(); + } +} diff --git a/src/card-controller/actions/actions/mute.ts b/src/card-controller/actions/actions/mute.ts new file mode 100644 index 00000000..3c43b8d0 --- /dev/null +++ b/src/card-controller/actions/actions/mute.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class MuteAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + await api.getMediaLoadedInfoManager().get()?.player?.mute(); + } +} diff --git a/src/card-controller/actions/actions/pause.ts b/src/card-controller/actions/actions/pause.ts new file mode 100644 index 00000000..f77d657b --- /dev/null +++ b/src/card-controller/actions/actions/pause.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class PauseAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + await api.getMediaLoadedInfoManager().get()?.player?.pause(); + } +} diff --git a/src/card-controller/actions/actions/play.ts b/src/card-controller/actions/actions/play.ts new file mode 100644 index 00000000..1d0707fe --- /dev/null +++ b/src/card-controller/actions/actions/play.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class PlayAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + await api.getMediaLoadedInfoManager().get()?.player?.play(); + } +} diff --git a/src/card-controller/actions/actions/ptz-controls.ts b/src/card-controller/actions/actions/ptz-controls.ts new file mode 100644 index 00000000..6bf0e976 --- /dev/null +++ b/src/card-controller/actions/actions/ptz-controls.ts @@ -0,0 +1,11 @@ +import { PTZControlsActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class PTZControlsAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + api.getViewManager().setViewWithMergedContext({ + ptzControls: { enabled: this._action.enabled }, + }); + } +} diff --git a/src/card-controller/actions/actions/ptz-digital.ts b/src/card-controller/actions/actions/ptz-digital.ts new file mode 100644 index 00000000..1f8bec54 --- /dev/null +++ b/src/card-controller/actions/actions/ptz-digital.ts @@ -0,0 +1,126 @@ +import clamp from 'lodash-es/clamp'; +import { + PartialZoomSettings, + ZOOM_DEFAULT_PAN_X, + ZOOM_DEFAULT_PAN_Y, + ZOOM_DEFAULT_SCALE, +} from '../../../components-lib/zoom/types'; +import { generateViewContextForZoom } from '../../../components-lib/zoom/zoom-view-context'; +import { PTZDigitialActionConfig, ZOOM_MAX, ZOOM_MIN } from '../../../config/types'; +import { getPTZTarget } from '../../../utils/ptz'; +import { Timer } from '../../../utils/timer'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; +import { TargetedActionContext } from '../types'; +import { + setInProgressForThisTarget, + stopInProgressForThisTarget, +} from '../utils/action-state'; + +const STEP_DELAY_SECONDS = 0.1; +const STEP_ZOOM = 0.1; +const STEP_PAN = 5; + +declare module 'action' { + interface ActionContext { + ptzDigital?: TargetedActionContext; + } +} + +export class PTZDigitalAction extends FrigateCardAction { + protected _timer = new Timer(); + + protected async _stepChange(api: CardActionsAPI, targetID: string): Promise { + api.getViewManager().setViewWithMergedContext( + generateViewContextForZoom(targetID, { + requested: this._convertActionToZoomSettings( + api.getViewManager().getView()?.context?.zoom?.[targetID]?.observed, + ), + }), + ); + } + + public async stop(): Promise { + this._timer.stop(); + } + + public async execute(api: CardActionsAPI): Promise { + const view = api.getViewManager().getView(); + if (!view) { + return; + } + + const targetID = + this._action.target_id ?? + getPTZTarget(view, { type: 'digital', cameraManager: api.getCameraManager() }) + ?.targetID; + if (!targetID) { + return; + } + + if (!!this._action.absolute || !this._action.ptz_phase) { + return await this._stepChange(api, targetID); + } + + /* istanbul ignore else: the else path cannot be reached -- @preserve */ + if (this._action.ptz_phase === 'start') { + stopInProgressForThisTarget(targetID, this._context.ptzDigital); + setInProgressForThisTarget(targetID, this._context, 'ptzDigital', this); + + await this._stepChange(api, targetID); + this._timer.startRepeated(STEP_DELAY_SECONDS, () => + this._stepChange(api, targetID), + ); + } else if (this._action.ptz_phase === 'stop') { + stopInProgressForThisTarget(targetID, this._context.ptzDigital); + delete this._context.ptzDigital?.[targetID]; + } + } + + protected _convertActionToZoomSettings( + base?: PartialZoomSettings, + ): PartialZoomSettings { + if (!this._action.absolute && !this._action.ptz_action) { + // If neither an absolute position nor an action are specified, the request + // is assumed to be to return to default. + return {}; + } + + if (this._action.absolute) { + return this._action.absolute; + } + + const zoom = base?.zoom ?? ZOOM_DEFAULT_SCALE; + const pan = { + x: base?.pan?.x ?? ZOOM_DEFAULT_PAN_X, + y: base?.pan?.y ?? ZOOM_DEFAULT_PAN_Y, + }; + + const zoomDelta = + this._action.ptz_action === 'zoom_in' + ? STEP_ZOOM + : this._action.ptz_action === 'zoom_out' + ? -STEP_ZOOM + : 0; + const xDelta = + this._action.ptz_action === 'left' + ? -STEP_PAN + : this._action.ptz_action === 'right' + ? STEP_PAN + : 0; + const yDelta = + this._action.ptz_action === 'up' + ? -STEP_PAN + : this._action.ptz_action === 'down' + ? STEP_PAN + : 0; + + return { + zoom: clamp(zoom + zoomDelta, ZOOM_MIN, ZOOM_MAX), + pan: { + x: clamp(pan.x + xDelta, 0, 100), + y: clamp(pan.y + yDelta, 0, 100), + }, + }; + } +} diff --git a/src/card-controller/actions/actions/ptz-multi.ts b/src/card-controller/actions/actions/ptz-multi.ts new file mode 100644 index 00000000..1207a50c --- /dev/null +++ b/src/card-controller/actions/actions/ptz-multi.ts @@ -0,0 +1,60 @@ +import { PTZMultiActionConfig } from '../../../config/types'; +import { createPTZAction, createPTZDigitalAction } from '../../../utils/action'; +import { PTZType, getPTZTarget, hasCameraTruePTZ } from '../../../utils/ptz'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; +import { PTZAction } from './ptz'; +import { PTZDigitalAction } from './ptz-digital'; + +export class PTZMultiAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + const view = api.getViewManager().getView(); + let targetID: string | null = null; + let type: PTZType | null = null; + + if (this._action.target_id) { + targetID = this._action.target_id; + type = hasCameraTruePTZ(api.getCameraManager(), targetID) ? 'ptz' : 'digital'; + } else if (view) { + const multiTarget = getPTZTarget(view, { cameraManager: api.getCameraManager() }); + targetID = multiTarget?.targetID ?? null; + type = multiTarget?.type ?? null; + } + + if (!targetID || type === null) { + return; + } + + (type === 'ptz' + ? this._toPTZAction(targetID) + : this._toPTZDigitalAction(targetID) + ).execute(api); + } + + protected _toPTZAction(targetID: string): PTZAction { + return new PTZAction( + this._context, + createPTZAction({ + cardID: this._action.card_id, + cameraID: targetID, + ptzAction: this._action.ptz_action, + ptzPhase: this._action.ptz_phase, + ptzPreset: this._action.ptz_preset, + }), + this._config, + ); + } + + protected _toPTZDigitalAction(targetID: string): PTZDigitalAction { + return new PTZDigitalAction( + this._context, + createPTZDigitalAction({ + cardID: this._action.card_id, + ptzPhase: this._action.ptz_phase, + ptzAction: this._action.ptz_action, + targetID: targetID, + }), + this._config, + ); + } +} diff --git a/src/card-controller/actions/actions/ptz.ts b/src/card-controller/actions/actions/ptz.ts new file mode 100644 index 00000000..17cf7a0b --- /dev/null +++ b/src/card-controller/actions/actions/ptz.ts @@ -0,0 +1,121 @@ +import { PTZActionConfig } from '../../../config/types'; +import { getPTZTarget, ptzActionToCapabilityKey } from '../../../utils/ptz'; +import { Timer } from '../../../utils/timer'; +import { CardActionsAPI } from '../../types'; +import { + setInProgressForThisTarget, + stopInProgressForThisTarget, +} from '../utils/action-state'; +import { FrigateCardAction } from './base'; + +interface PTZContext { + [cameraID: string]: { + inProgressAction?: PTZAction; + }; +} + +declare module 'action' { + interface ActionContext { + ptz?: PTZContext; + } +} + +export class PTZAction extends FrigateCardAction { + protected _timer = new Timer(); + + public async stop(): Promise { + this._timer.stop(); + } + + public async execute(api: CardActionsAPI): Promise { + const view = api.getViewManager().getView(); + if (!view) { + return; + } + + const ptzCameraID = + this._action.camera ?? + getPTZTarget(view, { type: 'ptz', cameraManager: api.getCameraManager() }) + ?.targetID ?? + null; + const ptzCapabilities = ptzCameraID + ? api + .getCameraManager() + .getCameraCapabilities(ptzCameraID) + ?.getPTZCapabilities() + : null; + const ptzConfiguration = ptzCameraID + ? api.getCameraManager().getStore().getCameraConfig(ptzCameraID)?.ptz + : null; + if (!ptzCameraID || !ptzCapabilities || !ptzConfiguration) { + return; + } + + if (!this._action.ptz_action) { + if (ptzCapabilities.presets && ptzCapabilities.presets.length >= 1) { + await api.getCameraManager().executePTZAction(ptzCameraID, 'preset', { + phase: this._action.ptz_phase, + preset: ptzCapabilities.presets[0], + }); + } + return; + } + + const capabilityKey = ptzActionToCapabilityKey(this._action.ptz_action); + if ( + (capabilityKey && + ptzCapabilities[capabilityKey]?.includes( + this._action.ptz_phase ? 'continuous' : 'relative', + )) || + this._action.ptz_action === 'preset' + ) { + // Scenario: Camera natively supports requested move type. + return await api + .getCameraManager() + .executePTZAction(ptzCameraID, this._action.ptz_action, { + phase: this._action.ptz_phase, + preset: this._action.ptz_preset, + }); + } + + if (this._action.ptz_phase === 'start') { + // Scenario: Asked to start a continuous move, camera only supports relative moves natively. + stopInProgressForThisTarget(ptzCameraID, this._context.ptz); + setInProgressForThisTarget(ptzCameraID, this._context, 'ptz', this); + + const singleStep = async (): Promise => { + this._action.ptz_action && + (await api + .getCameraManager() + .executePTZAction(ptzCameraID, this._action.ptz_action, { + preset: this._action.ptz_preset, + })); + // Only start the timer for the next step after this step returns. + this._timer.start(ptzConfiguration.r2c_delay_between_calls_seconds, singleStep); + }; + + await singleStep(); + } else if (this._action.ptz_phase === 'stop') { + // Scenario: Asked to stop continuous move, camera only supports relative moves natively. + stopInProgressForThisTarget(ptzCameraID, this._context.ptz); + } else { + // Relative move (but camera only supports continuous). + await api + .getCameraManager() + .executePTZAction(ptzCameraID, this._action.ptz_action, { + preset: this._action.ptz_preset, + phase: 'start', + }); + + this._timer.start(ptzConfiguration.c2r_delay_between_calls_seconds, async () => { + this._action.ptz_action && + (await api + .getCameraManager() + .executePTZAction(ptzCameraID, this._action.ptz_action, { + preset: this._action.ptz_preset, + phase: 'stop', + })); + }); + } + } +} diff --git a/src/card-controller/actions/actions/screenshot.ts b/src/card-controller/actions/actions/screenshot.ts new file mode 100644 index 00000000..573b69a6 --- /dev/null +++ b/src/card-controller/actions/actions/screenshot.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class ScreenshotAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + await api.getDownloadManager().downloadScreenshot(); + } +} diff --git a/src/card-controller/actions/actions/set.ts b/src/card-controller/actions/actions/set.ts new file mode 100644 index 00000000..2e87c4c2 --- /dev/null +++ b/src/card-controller/actions/actions/set.ts @@ -0,0 +1,44 @@ +import { ActionContext } from 'action'; +import { ActionType } from '../../../config/types'; +import { arrayify } from '../../../utils/basic'; +import { CardActionsAPI } from '../../types'; +import { ActionFactory } from '../factory'; +import { Action, AuxillaryActionConfig } from '../types'; + +export class ActionSet implements Action { + protected _context: ActionContext; + protected _actions: Action[] = []; + protected _factory = new ActionFactory(); + protected _stopped = false; + + constructor( + context: ActionContext, + actions: ActionType | ActionType[], + options?: { + config?: AuxillaryActionConfig; + cardID?: string; + }, + ) { + this._context = context; + for (const actionObj of arrayify(actions)) { + const action = this._factory.createAction(context, actionObj, options); + if (action) { + this._actions.push(action); + } + } + } + + public async execute(api: CardActionsAPI): Promise { + for (const action of this._actions) { + if (this._stopped) { + break; + } + + await action.execute(api); + } + } + + public async stop(): Promise { + this._stopped = true; + } +} diff --git a/src/card-controller/actions/actions/sleep.ts b/src/card-controller/actions/actions/sleep.ts new file mode 100644 index 00000000..3bf10c68 --- /dev/null +++ b/src/card-controller/actions/actions/sleep.ts @@ -0,0 +1,12 @@ +import { SleepActionConfig } from '../../../config/types'; +import { sleep } from '../../../utils/basic'; +import { CardActionsAPI } from '../../types'; +import { timeDeltaToSeconds } from '../utils/time-delta'; +import { FrigateCardAction } from './base'; + +export class SleepAction extends FrigateCardAction { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public async execute(_api: CardActionsAPI): Promise { + await sleep(timeDeltaToSeconds(this._action.duration)); + } +} diff --git a/src/card-controller/actions/actions/substream-off.ts b/src/card-controller/actions/actions/substream-off.ts new file mode 100644 index 00000000..6e84e04a --- /dev/null +++ b/src/card-controller/actions/actions/substream-off.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class SubstreamOffAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + api.getViewManager().setViewWithoutSubstream(); + } +} diff --git a/src/card-controller/actions/actions/substream-on.ts b/src/card-controller/actions/actions/substream-on.ts new file mode 100644 index 00000000..0fd13310 --- /dev/null +++ b/src/card-controller/actions/actions/substream-on.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class SubstreamOnAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + api.getViewManager().setViewWithSubstream(); + } +} diff --git a/src/card-controller/actions/actions/substream-select.ts b/src/card-controller/actions/actions/substream-select.ts new file mode 100644 index 00000000..7935ca5d --- /dev/null +++ b/src/card-controller/actions/actions/substream-select.ts @@ -0,0 +1,9 @@ +import { SubstreamSelectActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class SubstreamSelectAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + api.getViewManager().setViewWithSubstream(this._action.camera); + } +} diff --git a/src/card-controller/actions/actions/unmute.ts b/src/card-controller/actions/actions/unmute.ts new file mode 100644 index 00000000..81043271 --- /dev/null +++ b/src/card-controller/actions/actions/unmute.ts @@ -0,0 +1,9 @@ +import { GeneralActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class UnmuteAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + await api.getMediaLoadedInfoManager().get()?.player?.unmute(); + } +} diff --git a/src/card-controller/actions/actions/view.ts b/src/card-controller/actions/actions/view.ts new file mode 100644 index 00000000..045b65de --- /dev/null +++ b/src/card-controller/actions/actions/view.ts @@ -0,0 +1,16 @@ +import { ViewActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class ViewAction extends FrigateCardAction { + public async execute(api: CardActionsAPI): Promise { + api.getViewManager().setViewByParameters({ + viewName: this._action.frigate_card_action, + + // Note: This function needs to process (view-related) commands even when + // _view has not yet been initialized (since it may be used to set a view + // via the querystring). + cameraID: api.getViewManager().getView()?.camera, + }); + } +} diff --git a/src/card-controller/actions/factory.ts b/src/card-controller/actions/factory.ts new file mode 100644 index 00000000..0548ab0c --- /dev/null +++ b/src/card-controller/actions/factory.ts @@ -0,0 +1,133 @@ +import { ActionConfig } from '@dermotduffy/custom-card-helpers'; +import { ActionContext } from 'action'; +import { ActionType } from '../../config/types'; +import { convertActionToCardCustomAction } from '../../utils/action'; +import { CameraSelectAction } from './actions/camera-select'; +import { CameraUIAction } from './actions/camera-ui'; +import { DefaultAction } from './actions/default'; +import { DisplayModeSelectAction } from './actions/display-mode-select'; +import { DownloadAction } from './actions/download'; +import { ExpandAction } from './actions/expand'; +import { FullscreenAction } from './actions/fullscreen'; +import { GenericAction } from './actions/generic'; +import { LogAction } from './actions/log'; +import { MediaPlayerAction } from './actions/media-player'; +import { MenuToggleAction } from './actions/menu-toggle'; +import { MicrophoneMuteAction } from './actions/microphone-mute'; +import { MicrophoneUnmuteAction } from './actions/microphone-unmute'; +import { MuteAction } from './actions/mute'; +import { PauseAction } from './actions/pause'; +import { PlayAction } from './actions/play'; +import { PTZAction } from './actions/ptz'; +import { PTZDigitalAction } from './actions/ptz-digital'; +import { PTZMultiAction } from './actions/ptz-multi'; +import { ScreenshotAction } from './actions/screenshot'; +import { PTZControlsAction } from './actions/ptz-controls'; +import { SleepAction } from './actions/sleep'; +import { SubstreamOffAction } from './actions/substream-off'; +import { SubstreamOnAction } from './actions/substream-on'; +import { SubstreamSelectAction } from './actions/substream-select'; +import { UnmuteAction } from './actions/unmute'; +import { ViewAction } from './actions/view'; +import { Action, AuxillaryActionConfig } from './types'; + +export class ActionFactory { + public createAction( + context: ActionContext, + action: ActionType, + options?: { + config?: AuxillaryActionConfig; + cardID?: string; + }, + ): Action | null { + const frigateCardAction = convertActionToCardCustomAction(action); + if (action.action !== 'fire-dom-event' || !frigateCardAction) { + // * There is a slight typing (but not functional) difference between + // ActionType in this card and ActionConfig in `custom-card-helpers`. See + // `ExtendedConfirmationRestrictionConfig` in `types.ts` for the source and + // reason behind this difference. + return new GenericAction(context, action as ActionConfig, options?.config); + } + + if ( + // Command not intended for this card (e.g. query string command). + frigateCardAction.card_id && + frigateCardAction.card_id !== options?.cardID + ) { + return null; + } + + switch (frigateCardAction.frigate_card_action) { + case 'default': + return new DefaultAction(context, frigateCardAction, options?.config); + case 'clip': + case 'clips': + case 'image': + case 'live': + case 'recording': + case 'recordings': + case 'snapshot': + case 'snapshots': + case 'timeline': + case 'diagnostics': + return new ViewAction(context, frigateCardAction, options?.config); + case 'sleep': + return new SleepAction(context, frigateCardAction, options?.config); + case 'download': + return new DownloadAction(context, frigateCardAction, options?.config); + case 'camera_ui': + return new CameraUIAction(context, frigateCardAction, options?.config); + case 'expand': + return new ExpandAction(context, frigateCardAction, options?.config); + case 'fullscreen': + return new FullscreenAction(context, frigateCardAction, options?.config); + case 'menu_toggle': + // This is a rare code path: this would only be used if someone has a + // menu toggle action configured outside of the menu itself. + return new MenuToggleAction(context, frigateCardAction, options?.config); + case 'camera_select': + return new CameraSelectAction(context, frigateCardAction, options?.config); + case 'live_substream_select': + return new SubstreamSelectAction(context, frigateCardAction, options?.config); + case 'live_substream_off': + return new SubstreamOffAction(context, frigateCardAction, options?.config); + case 'live_substream_on': + return new SubstreamOnAction(context, frigateCardAction, options?.config); + case 'media_player': + return new MediaPlayerAction(context, frigateCardAction, options?.config); + case 'microphone_mute': + return new MicrophoneMuteAction(context, frigateCardAction, options?.config); + case 'microphone_unmute': + return new MicrophoneUnmuteAction(context, frigateCardAction, options?.config); + case 'mute': + return new MuteAction(context, frigateCardAction, options?.config); + case 'unmute': + return new UnmuteAction(context, frigateCardAction, options?.config); + case 'play': + return new PlayAction(context, frigateCardAction, options?.config); + case 'pause': + return new PauseAction(context, frigateCardAction, options?.config); + case 'screenshot': + return new ScreenshotAction(context, frigateCardAction, options?.config); + case 'display_mode_select': + return new DisplayModeSelectAction(context, frigateCardAction, options?.config); + case 'ptz': + return new PTZAction(context, frigateCardAction, options?.config); + case 'ptz_digital': + return new PTZDigitalAction(context, frigateCardAction, options?.config); + case 'ptz_multi': + return new PTZMultiAction(context, frigateCardAction, options?.config); + case 'ptz_controls': + return new PTZControlsAction(context, frigateCardAction, options?.config); + case 'log': + return new LogAction(context, frigateCardAction, options?.config); + } + + /* istanbul ignore next: this path cannot be reached -- @preserve */ + console.warn( + `Frigate card received unknown card action: ${frigateCardAction['frigate_card_action']}`, + ); + /* istanbul ignore next: this path cannot be reached -- @preserve */ + return null; + } +} diff --git a/src/card-controller/actions/types.ts b/src/card-controller/actions/types.ts new file mode 100644 index 00000000..5eeb4f0f --- /dev/null +++ b/src/card-controller/actions/types.ts @@ -0,0 +1,23 @@ +import { ActionType } from "../../config/types"; +import { CardActionsAPI } from "../types"; + +export interface AuxillaryActionConfig { + camera_image?: string; + entity?: string; +} + +export interface Action { + execute(api: CardActionsAPI): Promise; + stop(): Promise; +} + +export interface ActionExecutionRequest { + action: ActionType[] | ActionType; + config?: AuxillaryActionConfig; +} + +export interface TargetedActionContext { + [targetID: string]: { + inProgressAction?: Action; + }; +} diff --git a/src/card-controller/actions/utils/action-state.ts b/src/card-controller/actions/utils/action-state.ts new file mode 100644 index 00000000..3884800f --- /dev/null +++ b/src/card-controller/actions/utils/action-state.ts @@ -0,0 +1,25 @@ +import merge from 'lodash-es/merge'; +import { Action, TargetedActionContext } from '../types'; +import { ActionContext } from 'action'; + +export const stopInProgressForThisTarget = ( + targetID: string, + context?: TargetedActionContext, +): void => { + context?.[targetID]?.inProgressAction?.stop(); +}; + +export const setInProgressForThisTarget = ( + targetID: string, + context: ActionContext, + contextKey: keyof ActionContext, + action: Action, +) => { + merge(context, { + [contextKey]: { + [targetID]: { + inProgressAction: action, + }, + }, + }); +}; diff --git a/src/card-controller/actions/utils/execution-request.ts b/src/card-controller/actions/utils/execution-request.ts new file mode 100644 index 00000000..39ee47bc --- /dev/null +++ b/src/card-controller/actions/utils/execution-request.ts @@ -0,0 +1,38 @@ +import { dispatchFrigateCardEvent } from '../../../utils/basic'; +import { ActionExecutionRequest } from '../types'; + +export const dispatchActionExecutionRequest = ( + element: HTMLElement, + request: ActionExecutionRequest, +) => { + dispatchFrigateCardEvent(element, 'action:execution-request', request); +}; + +export interface ActionExecutionRequestEventTarget extends EventTarget { + addEventListener( + event: 'frigate-card:action:execution-request', + listener: ( + this: ActionExecutionRequestEventTarget, + ev: CustomEvent, + ) => void, + options?: AddEventListenerOptions | boolean, + ): void; + addEventListener( + type: string, + callback: EventListenerOrEventListenerObject, + options?: AddEventListenerOptions | boolean, + ): void; + removeEventListener( + event: 'frigate-card:action:execution-request', + listener: ( + this: ActionExecutionRequestEventTarget, + ev: CustomEvent, + ) => void, + options?: boolean | EventListenerOptions, + ): void; + removeEventListener( + type: string, + callback: EventListenerOrEventListenerObject, + options?: boolean | EventListenerOptions, + ): void; +} diff --git a/src/card-controller/actions/utils/time-delta.ts b/src/card-controller/actions/utils/time-delta.ts new file mode 100644 index 00000000..ac064acd --- /dev/null +++ b/src/card-controller/actions/utils/time-delta.ts @@ -0,0 +1,10 @@ +import { TimeDelta } from '../../../config/types'; + +export const timeDeltaToSeconds = (timeDelta: TimeDelta): number => { + return ( + (timeDelta.h ?? 0) * 3600 + + (timeDelta.m ?? 0) * 60 + + (timeDelta.s ?? 0) + + (timeDelta.ms ?? 0) / 1000 + ); +}; diff --git a/src/card-controller/automations-manager.ts b/src/card-controller/automations-manager.ts index 1da364d8..dbc38abb 100644 --- a/src/card-controller/automations-manager.ts +++ b/src/card-controller/automations-manager.ts @@ -1,14 +1,13 @@ -import { Automation, AutomationActions, Automations } from '../config/types.js'; +import { Automation, AutomationActions } from '../config/types.js'; import { localize } from '../localize/localize.js'; -import { frigateCardHandleAction } from '../utils/action.js'; -import { CardAutomationsAPI } from './types.js'; +import { CardAutomationsAPI, TaggedAutomations } from './types.js'; const MAX_NESTED_AUTOMATION_EXECUTIONS = 10; export class AutomationsManager { protected _api: CardAutomationsAPI; - protected _automations: Automations; + protected _automations: TaggedAutomations = []; protected _priorEvaluations: Map = new Map(); // A counter to avoid infinite loops, increases every time actions are run, @@ -19,10 +18,12 @@ export class AutomationsManager { this._api = api; } - public setAutomationsFromConfig() { - this._automations = this._api - .getConfigManager() - .getNonOverriddenConfig()?.automations; + public deleteAutomations(tag?: unknown) { + this._automations = this._automations.filter((automation) => automation.tag !== tag); + } + + public addAutomations(automations: TaggedAutomations): void { + this._automations.push(...automations); } public execute(): void { @@ -34,8 +35,8 @@ export class AutomationsManager { return; } - const actionsToRun: AutomationActions[] = []; - for (const automation of this._automations ?? []) { + const actionsToRun: AutomationActions = []; + for (const automation of this._automations) { const shouldExecute = this._api .getConditionsManager() .evaluateConditions(automation.conditions); @@ -43,27 +44,27 @@ export class AutomationsManager { const priorEvaluation = this._priorEvaluations.get(automation); this._priorEvaluations.set(automation, shouldExecute); if (shouldExecute !== priorEvaluation && actions) { - actionsToRun.push(actions); + actionsToRun.push(...actions); } } - ++this._nestedAutomationExecutions; - if (this._nestedAutomationExecutions > MAX_NESTED_AUTOMATION_EXECUTIONS) { - this._api.getMessageManager().setMessageIfHigherPriority({ - type: 'error', - message: localize('error.too_many_automations'), - }); + if (!actionsToRun.length) { return; } - actionsToRun.forEach((actions) => { - frigateCardHandleAction( - this._api.getCardElementManager().getElement(), - hass, - {}, - actions, - ); - }); - --this._nestedAutomationExecutions; + const runActions = async (actions: AutomationActions): Promise => { + ++this._nestedAutomationExecutions; + if (this._nestedAutomationExecutions > MAX_NESTED_AUTOMATION_EXECUTIONS) { + this._api.getMessageManager().setMessageIfHigherPriority({ + type: 'error', + message: localize('error.too_many_automations'), + }); + return; + } + + await this._api.getActionsManager().executeActions(actions); + --this._nestedAutomationExecutions; + }; + runActions(actionsToRun); } } diff --git a/src/card-controller/card-element-manager.ts b/src/card-controller/card-element-manager.ts index c586173e..6cc3a462 100644 --- a/src/card-controller/card-element-manager.ts +++ b/src/card-controller/card-element-manager.ts @@ -4,11 +4,12 @@ import { setOrRemoveAttribute } from '../utils/basic'; import { isCardInPanel } from '../utils/ha'; import { InitializationAspect } from './initialization-manager'; import { CardElementAPI } from './types'; +import { ActionExecutionRequestEventTarget } from './actions/utils/execution-request'; export type ScrollCallback = () => void; export type MenuToggleCallback = () => void; -export type CardHTMLElement = LitElement & ReactiveControllerHost & ActionEventTarget; +export type CardHTMLElement = LitElement & ReactiveControllerHost & ActionEventTarget & ActionExecutionRequestEventTarget; export class CardElementManager { protected _api: CardElementAPI; @@ -62,19 +63,21 @@ export class CardElementManager { this._api.getExpandManager().initialize(); this._api.getMediaLoadedInfoManager().initialize(); this._api.getMicrophoneManager().initialize(); + this._api.getKeyboardStateManager().initialize(); // Whether or not the card is in panel mode on the dashboard. setOrRemoveAttribute(this._element, isCardInPanel(this._element), 'panel'); + setOrRemoveAttribute(this._element, true, 'tabindex', '0'); this._api.getFullscreenManager().connect(); - + this._element.addEventListener( 'mousemove', this._api.getInteractionManager().reportInteraction, ); this._element.addEventListener( 'll-custom', - this._api.getActionsManager().handleActionEvent, + this._api.getActionsManager().handleCustomActionEvent, ); this._element.addEventListener( 'action', @@ -84,6 +87,10 @@ export class CardElementManager { 'action', this._api.getInteractionManager().reportInteraction, ); + this._element.addEventListener( + 'frigate-card:action:execution-request', + this._api.getActionsManager().handleActionExecutionRequestEvent, + ); // Listen for HA `navigate` actions. // See: https://github.com/home-assistant/frontend/blob/273992c8e9c3062c6e49481b6d7d688a07067232/src/common/navigate.ts#L43 @@ -106,23 +113,25 @@ export class CardElementManager { public elementDisconnected(): void { setOrRemoveAttribute(this._element, false, 'panel'); + setOrRemoveAttribute(this._element, false, 'tabindex'); // When the dashboard 'tab' is changed, the media is effectively unloaded. this._api.getMediaLoadedInfoManager().clear(); this._api.getFullscreenManager().disconnect(); + this._api.getKeyboardStateManager().uninitialize(); + this._api.getActionsManager().uninitialize(); // Uninitialize cameras to cause them to reinitialize on // reconnection, to ensure the state subscription/unsubscription works // correctly for triggers. this._api.getInitializationManager().uninitialize(InitializationAspect.CAMERAS), - - this._element.removeEventListener( - 'mousemove', - this._api.getInteractionManager().reportInteraction, - ); + this._element.removeEventListener( + 'mousemove', + this._api.getInteractionManager().reportInteraction, + ); this._element.removeEventListener( 'll-custom', - this._api.getActionsManager().handleActionEvent, + this._api.getActionsManager().handleCustomActionEvent, ); this._element.removeEventListener( 'action', @@ -132,6 +141,10 @@ export class CardElementManager { 'action', this._api.getInteractionManager().reportInteraction, ); + this._element.removeEventListener( + 'frigate-card:action:execution-request', + this._api.getActionsManager().handleActionExecutionRequestEvent, + ); window.removeEventListener( 'location-changed', diff --git a/src/card-controller/conditions-manager.ts b/src/card-controller/conditions-manager.ts index 4f8b243e..641a8e71 100644 --- a/src/card-controller/conditions-manager.ts +++ b/src/card-controller/conditions-manager.ts @@ -16,7 +16,7 @@ import { Overrides, } from '../config/types'; import { desparsifyArrays } from '../utils/basic'; -import { CardConditionAPI } from './types'; +import { CardConditionAPI, KeysState } from './types'; interface MicrophoneConditionState { connected?: boolean; @@ -35,6 +35,7 @@ interface ConditionState { interaction?: boolean; microphone?: MicrophoneConditionState; user?: CurrentUser; + keys?: KeysState; } export class ConditionsEvaluateRequestEvent extends Event { @@ -190,7 +191,9 @@ export class ConditionsManager { const config = this._api.getConfigManager().getConfig(); const conditions: FrigateCardCondition[] = []; config?.overrides?.forEach((override) => conditions.push(...override.conditions)); - config?.automations?.forEach((automation) => conditions.push(...automation.conditions)); + config?.automations?.forEach((automation) => + conditions.push(...automation.conditions), + ); // Element conditions can be arbitrarily nested underneath conditionals and // custom elements that this card may not known. Here we recursively parse @@ -323,6 +326,20 @@ export class ConditionsManager { (conditionObj.muted === undefined || state.microphone?.muted === conditionObj.muted) ); + case 'key': + return ( + !!state.keys && + conditionObj.key in state.keys && + (conditionObj.state ?? 'down') === state.keys[conditionObj.key].state && + (conditionObj.ctrl === undefined || + conditionObj.ctrl === !!state.keys[conditionObj.key].ctrl) && + (conditionObj.alt === undefined || + conditionObj.alt === !!state.keys[conditionObj.key].alt) && + (conditionObj.meta === undefined || + conditionObj.meta === !!state.keys[conditionObj.key].meta) && + (conditionObj.shift === undefined || + conditionObj.shift === !!state.keys[conditionObj.key].shift) + ); } } diff --git a/src/card-controller/config-manager.ts b/src/card-controller/config/config-manager.ts similarity index 85% rename from src/card-controller/config-manager.ts rename to src/card-controller/config/config-manager.ts index 947b530b..a2b3fa5e 100644 --- a/src/card-controller/config-manager.ts +++ b/src/card-controller/config/config-manager.ts @@ -1,17 +1,19 @@ import isEqual from 'lodash-es/isEqual'; -import { isConfigUpgradeable } from '../config/management'; +import { isConfigUpgradeable } from '../../config/management.js'; import { CardWideConfig, FrigateCardConfig, frigateCardConfigSchema, RawFrigateCardConfig, -} from '../config/types'; -import { localize } from '../localize/localize'; -import { setProfiles } from '../config/profiles'; -import { getParseErrorPaths } from '../utils/zod.js'; -import { getOverriddenConfig } from './conditions-manager'; -import { InitializationAspect } from './initialization-manager'; -import { CardConfigAPI } from './types'; +} from '../../config/types.js'; +import { localize } from '../../localize/localize.js'; +import { setProfiles } from '../../config/profiles/index.js'; +import { getParseErrorPaths } from '../../utils/zod.js'; +import { getOverriddenConfig } from '../conditions-manager.js'; +import { InitializationAspect } from '../initialization-manager.js'; +import { CardConfigAPI } from '../types.js'; +import { setAutomationsFromConfig } from './load-automations.js'; +import { setKeyboardShortcutsFromConfig } from './load-keyboard-shortcuts.js'; export class ConfigManager { protected _api: CardConfigAPI; @@ -92,9 +94,10 @@ export class ConfigManager { this._api.getMediaLoadedInfoManager().clear(); this._api.getViewManager().reset(); this._api.getMessageManager().reset(); - this._api.getAutomationsManager().setAutomationsFromConfig(); this._api.getStyleManager().setPerformance(); this._api.getCardElementManager().update(); + setKeyboardShortcutsFromConfig(this._api, this); + setAutomationsFromConfig(this._api); this.computeOverrideConfig(); } diff --git a/src/card-controller/config/load-automations.ts b/src/card-controller/config/load-automations.ts new file mode 100644 index 00000000..8c6b7ffa --- /dev/null +++ b/src/card-controller/config/load-automations.ts @@ -0,0 +1,8 @@ +import { CardConfigLoaderAPI } from '../types'; + +export const setAutomationsFromConfig = (api: CardConfigLoaderAPI) => { + api.getAutomationsManager().deleteAutomations(); + api + .getAutomationsManager() + .addAutomations(api.getConfigManager().getNonOverriddenConfig()?.automations ?? []); +}; diff --git a/src/card-controller/config/load-keyboard-shortcuts.ts b/src/card-controller/config/load-keyboard-shortcuts.ts new file mode 100644 index 00000000..e8f8f895 --- /dev/null +++ b/src/card-controller/config/load-keyboard-shortcuts.ts @@ -0,0 +1,130 @@ +import { + KeyboardShortcuts, + PTZKeyboardShortcutName, +} from '../../config/keyboard-shortcuts'; +import { PTZAction } from '../../config/ptz'; +import { CardConfigLoaderAPI, TaggedAutomations } from '../types'; +import { createPTZMultiAction } from '../../utils/action'; + +export const setKeyboardShortcutsFromConfig = ( + api: CardConfigLoaderAPI, + tag: unknown, +) => { + api.getAutomationsManager().deleteAutomations(tag); + + const shortcuts = api.getConfigManager().getConfig()?.view.keyboard_shortcuts; + if (!shortcuts) { + return; + } + + const automations = convertKeyboardShortcutsToAutomations(tag, shortcuts); + if (automations.length) { + api.getAutomationsManager().addAutomations(automations); + } +}; + +const ptzKeyboardShortcutToPTZAction = ( + ptzKbs: PTZKeyboardShortcutName, +): PTZAction | null => { + switch (ptzKbs) { + case 'ptz_left': + return 'left'; + case 'ptz_right': + return 'right'; + case 'ptz_up': + return 'up'; + case 'ptz_down': + return 'down'; + case 'ptz_zoom_in': + return 'zoom_in'; + case 'ptz_zoom_out': + return 'zoom_out'; + } + /* istanbul ignore next: No (current) way to reach this code -- @preserve */ + return null; +}; + +const convertKeyboardShortcutsToAutomations = ( + tag: unknown, + shortcuts: KeyboardShortcuts, +): TaggedAutomations => { + if (!shortcuts.enabled) { + return []; + } + + const automations: TaggedAutomations = []; + + for (const name of [ + 'ptz_down', + 'ptz_left', + 'ptz_right', + 'ptz_up', + 'ptz_zoom_in', + 'ptz_zoom_out', + ] as const) { + const shortcut = shortcuts[name]; + const ptzAction = ptzKeyboardShortcutToPTZAction(name); + if (!shortcut || !ptzAction) { + continue; + } + + automations.push({ + conditions: [ + { + condition: 'key' as const, + key: shortcut.key, + state: 'down', + shift: shortcut.shift, + ctrl: shortcut.ctrl, + alt: shortcut.alt, + meta: shortcut.meta, + }, + ], + actions: [ + createPTZMultiAction({ + ptzAction: ptzAction, + ptzPhase: 'start', + }), + ], + tag: tag, + }); + + automations.push({ + conditions: [ + { + condition: 'key' as const, + key: shortcut.key, + state: 'up', + }, + ], + actions: [ + createPTZMultiAction({ + ptzAction: ptzAction, + ptzPhase: 'stop', + }), + ], + tag: tag, + }); + } + + const homeShortcut = shortcuts.ptz_home; + if (homeShortcut) { + automations.push({ + conditions: [ + { + condition: 'key' as const, + key: homeShortcut.key, + state: 'down', + shift: homeShortcut.shift, + ctrl: homeShortcut.ctrl, + alt: homeShortcut.alt, + meta: homeShortcut.meta, + }, + ], + actions: [createPTZMultiAction()], + tag: tag, + }); + } + + return automations; +}; diff --git a/src/card-controller/controller.ts b/src/card-controller/controller.ts index e44e6d8a..ca69fff8 100644 --- a/src/card-controller/controller.ts +++ b/src/card-controller/controller.ts @@ -5,7 +5,7 @@ import { FrigateCardConfig } from '../config/types'; import { EntityRegistryManager } from '../utils/ha/entity-registry'; import { EntityCache } from '../utils/ha/entity-registry/cache'; import { ResolvedMediaCache } from '../utils/ha/resolved-media'; -import { ActionsManager } from './actions-manager'; +import { ActionsManager } from './actions/actions-manager'; import { AutoUpdateManager } from './auto-update-manager'; import { AutomationsManager } from './automations-manager'; import { CameraURLManager } from './camera-url-manager'; @@ -16,7 +16,7 @@ import { ScrollCallback, } from './card-element-manager'; import { ConditionsManager, ConditionsManagerListener } from './conditions-manager'; -import { ConfigManager } from './config-manager'; +import { ConfigManager } from './config/config-manager'; import { DownloadManager } from './download-manager'; import { ExpandManager } from './expand-manager'; import { FullscreenManager } from './fullscreen-manager'; @@ -45,6 +45,7 @@ import { CardHASSAPI, CardInitializerAPI, CardInteractionAPI, + CardKeyboardStateAPI, CardMediaLoadedAPI, CardMediaPlayerAPI, CardMessageAPI, @@ -55,6 +56,7 @@ import { CardViewAPI, } from './types'; import { ViewManager } from './view-manager'; +import { KeyboardStateManager } from './keyboard-state-manager'; export class CardController implements @@ -72,6 +74,7 @@ export class CardController CardHASSAPI, CardInitializerAPI, CardInteractionAPI, + CardKeyboardStateAPI, CardMediaLoadedAPI, CardMediaPlayerAPI, CardMessageAPI, @@ -101,6 +104,7 @@ export class CardController protected _hassManager = new HASSManager(this); protected _initializationManager = new InitializationManager(this); protected _interactionManager = new InteractionManager(this); + protected _keyboardStateManager = new KeyboardStateManager(this); protected _mediaLoadedInfoManager = new MediaLoadedInfoManager(this); protected _mediaPlayerManager = new MediaPlayerManager(this); protected _messageManager = new MessageManager(this); @@ -195,6 +199,10 @@ export class CardController return this._interactionManager; } + public getKeyboardStateManager(): KeyboardStateManager { + return this._keyboardStateManager; + } + public getMediaLoadedInfoManager(): MediaLoadedInfoManager { return this._mediaLoadedInfoManager; } diff --git a/src/card-controller/keyboard-state-manager.ts b/src/card-controller/keyboard-state-manager.ts new file mode 100644 index 00000000..53a24a6c --- /dev/null +++ b/src/card-controller/keyboard-state-manager.ts @@ -0,0 +1,59 @@ +import { CardKeyboardStateAPI, KeysState } from './types'; +import isEqual from 'lodash/isEqual'; + +export class KeyboardStateManager { + protected _api: CardKeyboardStateAPI; + protected _state: KeysState = {}; + + constructor(api: CardKeyboardStateAPI) { + this._api = api; + } + + public initialize(): void { + const element = this._api.getCardElementManager().getElement(); + element.addEventListener('keydown', this._handleKeydown); + element.addEventListener('keyup', this._handleKeyup); + element.addEventListener('blur', this._handleBlur); + } + + public uninitialize(): void { + const element = this._api.getCardElementManager().getElement(); + element.removeEventListener('keydown', this._handleKeydown); + element.removeEventListener('keyup', this._handleKeyup); + element.removeEventListener('blur', this._handleBlur); + } + + protected _handleKeydown = (ev: KeyboardEvent): void => { + const keyObj = { + state: 'down' as const, + ctrl: ev.ctrlKey, + alt: ev.altKey, + meta: ev.metaKey, + shift: ev.shiftKey, + }; + + if (!isEqual(this._state[ev.key], keyObj)) { + this._state[ev.key] = keyObj; + this._processStateChange(); + } + }; + + protected _handleKeyup = (ev: KeyboardEvent): void => { + if (ev.key in this._state && this._state[ev.key].state === 'down') { + this._state[ev.key].state = 'up'; + this._processStateChange(); + } + }; + + protected _handleBlur = (): void => { + if (Object.keys(this._state).length) { + // State is emptied if the element loses focus. + this._state = {}; + this._processStateChange(); + } + }; + + protected _processStateChange(): void { + this._api.getConditionsManager().setState({ keys: this._state }); + } +} diff --git a/src/card-controller/query-string-manager.ts b/src/card-controller/query-string-manager.ts index f118f3be..15d3a1a6 100644 --- a/src/card-controller/query-string-manager.ts +++ b/src/card-controller/query-string-manager.ts @@ -1,8 +1,5 @@ -import { FrigateCardCustomAction, FrigateCardViewAction } from '../config/types'; -import { - createFrigateCardCameraAction, - createFrigateCardSimpleAction -} from '../utils/action.js'; +import { FrigateCardCustomAction, ViewActionConfig } from '../config/types'; +import { createCameraAction, createGeneralAction } from '../utils/action.js'; import { CardQueryStringAPI } from './types'; import { ViewManagerSetViewParameters } from './view-manager'; @@ -56,14 +53,15 @@ export class QueryStringManager { } protected _executeNonViewRelated(intent: QueryStringViewIntent): void { - // Only execute non-view actions when the card has rendered at least once. - if (!this._api.getCardElementManager().hasUpdated()) { + if ( + // Only execute non-view actions when the card has rendered at least once. + !this._api.getCardElementManager().hasUpdated() || + !intent.other?.length + ) { return; } - intent.other?.forEach((action) => - this._api.getActionsManager().executeFrigateAction(action), - ); + this._api.getActionsManager().executeActions(intent.other); } protected _calculateIntent(): QueryStringViewIntent { @@ -105,7 +103,7 @@ export class QueryStringManager { case 'camera_select': case 'live_substream_select': if (value) { - customAction = createFrigateCardCameraAction(action, value, { + customAction = createCameraAction(action, value, { cardID: cardID, }); } @@ -125,7 +123,7 @@ export class QueryStringManager { case 'snapshot': case 'snapshots': case 'timeline': - customAction = createFrigateCardSimpleAction(action, { + customAction = createGeneralAction(action, { cardID: cardID, }); break; @@ -143,7 +141,7 @@ export class QueryStringManager { protected _isViewAction = ( action: FrigateCardCustomAction, - ): action is FrigateCardViewAction => { + ): action is ViewActionConfig => { switch (action.frigate_card_action) { case 'clip': case 'clips': diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index 33c4df07..d289f9c5 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -2,12 +2,12 @@ import type { CameraManager } from '../camera-manager/manager'; import type { ConditionsManager } from './conditions-manager'; import type { EntityRegistryManager } from '../utils/ha/entity-registry'; import type { ResolvedMediaCache } from '../utils/ha/resolved-media'; -import type { ActionsManager } from './actions-manager'; +import type { ActionsManager } from './actions/actions-manager'; import type { AutoUpdateManager } from './auto-update-manager'; import type { AutomationsManager } from './automations-manager'; import type { CameraURLManager } from './camera-url-manager'; import type { CardElementManager } from './card-element-manager'; -import type { ConfigManager } from './config-manager'; +import type { ConfigManager } from './config/config-manager'; import type { DownloadManager } from './download-manager'; import type { ExpandManager } from './expand-manager'; import type { FullscreenManager } from './fullscreen-manager'; @@ -22,17 +22,22 @@ import type { StyleManager } from './style-manager'; import type { TriggersManager } from './triggers-manager'; import type { ViewManager } from './view-manager'; import type { QueryStringManager } from './query-string-manager'; +import { KeyboardStateManager } from './keyboard-state-manager'; +import { Automation } from '../config/types'; -/** - * This defines a series of limited APIs that various manager helpers use to - * control the card. Explicitly specifying them helps make coupling intentional - * and avoids cyclic importing. - */ +// ************************************************************************* +// Manager APIs +// This defines a series of limited APIs that various managers use to control +// the card. Explicitly specifying them helps make coupling intentional and +// reduce cyclic dependencies. +// ************************************************************************* -export interface CardActionsManagerAPI { +export interface CardActionsAPI { + getActionsManager(): ActionsManager; getCameraManager(): CameraManager; getCameraURLManager(): CameraURLManager; getCardElementManager(): CardElementManager; + getConditionsManager(): ConditionsManager; getConfigManager(): ConfigManager; getDownloadManager(): DownloadManager; getExpandManager(): ExpandManager; @@ -45,11 +50,12 @@ export interface CardActionsManagerAPI { getTriggersManager(): TriggersManager; getViewManager(): ViewManager; } +export type CardActionsManagerAPI = CardActionsAPI; export interface CardAutomationsAPI { + getActionsManager(): ActionsManager; getCardElementManager(): CardElementManager; getConditionsManager(): ConditionsManager; - getConfigManager(): ConfigManager; getHASSManager(): HASSManager; getMessageManager(): MessageManager; } @@ -62,6 +68,7 @@ export interface CardAutoRefreshAPI { } export interface CardCameraAPI { + getActionsManager(): ActionsManager; getConfigManager(): ConfigManager; getEntityRegistryManager(): EntityRegistryManager; getHASSManager(): HASSManager; @@ -84,6 +91,7 @@ export interface CardConfigAPI { getAutomationsManager(): AutomationsManager; getCardElementManager(): CardElementManager; getConditionsManager(): ConditionsManager; + getConfigManager(): ConfigManager; getInitializationManager(): InitializationManager; getMediaLoadedInfoManager(): MediaLoadedInfoManager; getMessageManager(): MessageManager; @@ -91,6 +99,11 @@ export interface CardConfigAPI { getViewManager(): ViewManager; } +export interface CardConfigLoaderAPI { + getConfigManager(): ConfigManager; + getAutomationsManager(): AutomationsManager; +} + export interface CardDownloadAPI { getCameraManager(): CameraManager; getHASSManager(): HASSManager; @@ -106,6 +119,7 @@ export interface CardElementAPI { getFullscreenManager(): FullscreenManager; getInitializationManager(): InitializationManager; getInteractionManager(): InteractionManager; + getKeyboardStateManager(): KeyboardStateManager; getMediaLoadedInfoManager(): MediaLoadedInfoManager; getMicrophoneManager(): MicrophoneManager; getQueryStringManager(): QueryStringManager; @@ -159,6 +173,12 @@ export interface CardInteractionAPI { getViewManager(): ViewManager; } +export interface CardKeyboardStateAPI { + getCardElementManager(): CardElementManager; + getConditionsManager(): ConditionsManager; + getConfigManager(): ConfigManager; +} + export interface CardMediaLoadedAPI { getCardElementManager(): CardElementManager; getConditionsManager(): ConditionsManager; @@ -224,3 +244,21 @@ export interface CardViewAPI { getStyleManager(): StyleManager; getTriggersManager(): TriggersManager; } + +// ************************************************************************* +// Common Types +// ************************************************************************* + +export interface KeysState { + [key: string]: { + state: 'down' | 'up'; + ctrl: boolean; + shift: boolean; + alt: boolean; + meta: boolean; + } +} +interface TaggedAutomation extends Automation { + tag?: unknown; +} +export type TaggedAutomations = TaggedAutomation[]; diff --git a/src/card.ts b/src/card.ts index c6b49571..350fde22 100644 --- a/src/card.ts +++ b/src/card.ts @@ -284,6 +284,7 @@ class FrigateCard extends LitElement { @frigate-card:media:pause=${ () => this.requestUpdate() /* Refresh play/pause menu button */ } + @frigate-card:focus=${() => this.focus()} > ${renderMenuAbove ? this._renderMenu() : ''}
      diff --git a/src/components-lib/key-assigner-controller.ts b/src/components-lib/key-assigner-controller.ts new file mode 100644 index 00000000..c9e628cb --- /dev/null +++ b/src/components-lib/key-assigner-controller.ts @@ -0,0 +1,83 @@ +import { LitElement, ReactiveController } from 'lit'; +import isEqual from 'lodash-es/isEqual'; +import { KeyboardShortcut } from '../config/keyboard-shortcuts'; +import { setOrRemoveAttribute } from '../utils/basic'; + +export class KeyAssignerController implements ReactiveController { + protected _host: LitElement; + protected _assigning = false; + protected _value: KeyboardShortcut | null = null; + + constructor(host: LitElement) { + this._host = host; + this._host.addController(this); + } + + public setValue(value: KeyboardShortcut | null): void { + if (!isEqual(value, this._value)) { + this._value = value; + this._host.requestUpdate(); + + this._host.dispatchEvent( + new CustomEvent('value-changed', { + detail: { + value: this._value, + }, + }), + ); + } + } + public getValue(): KeyboardShortcut | null { + return this._value; + } + public hasValue(): boolean { + return !!this._value; + } + + public isAssigning(): boolean { + return this._assigning; + } + public toggleAssigning(): void { + this._setAssigning(!this._assigning); + } + protected _setAssigning(assigning: boolean): void { + this._assigning = assigning; + setOrRemoveAttribute(this._host, this._assigning, 'assigning'); + + if (this._assigning) { + this._host.addEventListener('keydown', this._keydownEventHandler); + } else { + this._host.removeEventListener('keydown', this._keydownEventHandler); + } + + this._host.requestUpdate(); + } + + protected _blurEventHandler = (): void => { + this._setAssigning(false); + }; + + protected _keydownEventHandler = (ev: KeyboardEvent): void => { + // Don't allow _only_ a modifier. + if (!ev.key || ['Control', 'Alt', 'Shift', 'Meta'].includes(ev.key)) { + return; + } + + this.setValue({ + key: ev.key, + ctrl: ev.ctrlKey, + alt: ev.altKey, + shift: ev.shiftKey, + meta: ev.metaKey, + }); + this._setAssigning(false); + }; + + public hostConnected(): void { + this._host.addEventListener('blur', this._blurEventHandler); + } + + public hostDisconnected(): void { + this._host.removeEventListener('blur', this._blurEventHandler); + } +} diff --git a/src/components-lib/live/live-controller.ts b/src/components-lib/live/live-controller.ts index b7cd577f..7a63055a 100644 --- a/src/components-lib/live/live-controller.ts +++ b/src/components-lib/live/live-controller.ts @@ -20,7 +20,6 @@ interface LiveViewContext { // camera to be live rather than the camera selected in the view). overrides?: Map; - ptzVisible?: boolean; fetchThumbnails?: boolean; } diff --git a/src/components-lib/menu-button-controller.ts b/src/components-lib/menu-button-controller.ts index 5fa25a9a..0c4983c0 100644 --- a/src/components-lib/menu-button-controller.ts +++ b/src/components-lib/menu-button-controller.ts @@ -14,17 +14,17 @@ import { FRIGATE_BUTTON_MENU_ICON } from '../const'; import { localize } from '../localize/localize.js'; import { MediaLoadedInfo } from '../types'; import { - createFrigateCardCameraAction, - createFrigateCardChangeZoomAction, - createFrigateCardDisplayModeAction, - createFrigateCardMediaPlayerAction, - createFrigateCardShowPTZAction, - createFrigateCardSimpleAction, + createCameraAction, + createPTZMultiAction, + createDisplayModeAction, + createMediaPlayerAction, + createPTZControlsAction, + createGeneralAction, } from '../utils/action'; import { isTruthy } from '../utils/basic'; import { getEntityIcon, getEntityTitle } from '../utils/ha'; -import { hasUsablePTZ } from '../utils/ptz'; -import { hasSubstream } from '../utils/substream'; +import { getPTZTarget } from '../utils/ptz'; +import { getStreamCameraID, hasSubstream } from '../utils/substream'; import { View } from '../view/view'; import { getCameraIDsForViewName } from '../view/view-to-cameras'; @@ -95,8 +95,8 @@ export class MenuButtonController { this._getMuteUnmuteButton(config, options?.currentMediaLoadedInfo), this._getScreenshotButton(config, options?.currentMediaLoadedInfo), this._getDisplayModeButton(config, cameraManager, view), - this._getPTZButton(config, cameraManager, view), - this._getDefaultZoomButton(config, view), + this._getPTZControlsButton(config, cameraManager, view), + this._getPTZHomeButton(config, cameraManager, view), ...this._dynamicMenuButtons.map((button) => ({ style: this._getStyleFromActions(config, view, button, options), @@ -115,11 +115,9 @@ export class MenuButtonController { title: localize('config.menu.buttons.frigate'), tap_action: config.menu?.style === 'hidden' - ? (createFrigateCardSimpleAction('menu_toggle') as FrigateCardCustomAction) - : (createFrigateCardSimpleAction('default') as FrigateCardCustomAction), - hold_action: createFrigateCardSimpleAction( - 'diagnostics', - ) as FrigateCardCustomAction, + ? (createGeneralAction('menu_toggle') as FrigateCardCustomAction) + : (createGeneralAction('default') as FrigateCardCustomAction), + hold_action: createGeneralAction('diagnostics') as FrigateCardCustomAction, }; } @@ -135,7 +133,7 @@ export class MenuButtonController { const menuItems = Array.from( cameraManager.getStore().getCameraConfigEntries(menuCameraIDs), ([cameraID, config]) => { - const action = createFrigateCardCameraAction('camera_select', cameraID); + const action = createCameraAction('camera_select', cameraID); const metadata = cameraManager.getCameraMetadata(cameraID); return { @@ -175,7 +173,7 @@ export class MenuButtonController { (cameraID) => cameraID !== view.camera, ); const streams = [view.camera, ...substreams]; - const substreamAwareCameraID = this._getSubstreamAwareCameraID(view); + const substreamAwareCameraID = getStreamCameraID(view); if (streams.length === 2) { // If there are only two dependencies (the main camera, and 1 other) @@ -187,16 +185,13 @@ export class MenuButtonController { title: localize('config.menu.buttons.substreams'), ...config.menu.buttons.substreams, type: 'custom:frigate-card-menu-icon', - tap_action: createFrigateCardSimpleAction( + tap_action: createGeneralAction( hasSubstream(view) ? 'live_substream_off' : 'live_substream_on', ) as FrigateCardCustomAction, }; } else if (streams.length > 2) { const menuItems = Array.from(streams, (streamID) => { - const action = createFrigateCardCameraAction( - 'live_substream_select', - streamID, - ); + const action = createCameraAction('live_substream_select', streamID); const metadata = cameraManager.getCameraMetadata(streamID) ?? undefined; const cameraConfig = cameraManager.getStore().getCameraConfig(streamID); return { @@ -236,7 +231,7 @@ export class MenuButtonController { type: 'custom:frigate-card-menu-icon', title: localize('config.view.views.live'), style: view.is('live') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction('live') as FrigateCardCustomAction, + tap_action: createGeneralAction('live') as FrigateCardCustomAction, } : null; } @@ -253,8 +248,8 @@ export class MenuButtonController { type: 'custom:frigate-card-menu-icon', title: localize('config.view.views.clips'), style: view?.is('clips') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction('clips') as FrigateCardCustomAction, - hold_action: createFrigateCardSimpleAction('clip') as FrigateCardCustomAction, + tap_action: createGeneralAction('clips') as FrigateCardCustomAction, + hold_action: createGeneralAction('clip') as FrigateCardCustomAction, } : null; } @@ -271,12 +266,8 @@ export class MenuButtonController { type: 'custom:frigate-card-menu-icon', title: localize('config.view.views.snapshots'), style: view?.is('snapshots') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction( - 'snapshots', - ) as FrigateCardCustomAction, - hold_action: createFrigateCardSimpleAction( - 'snapshot', - ) as FrigateCardCustomAction, + tap_action: createGeneralAction('snapshots') as FrigateCardCustomAction, + hold_action: createGeneralAction('snapshot') as FrigateCardCustomAction, } : null; } @@ -293,12 +284,8 @@ export class MenuButtonController { type: 'custom:frigate-card-menu-icon', title: localize('config.view.views.recordings'), style: view.is('recordings') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction( - 'recordings', - ) as FrigateCardCustomAction, - hold_action: createFrigateCardSimpleAction( - 'recording', - ) as FrigateCardCustomAction, + tap_action: createGeneralAction('recordings') as FrigateCardCustomAction, + hold_action: createGeneralAction('recording') as FrigateCardCustomAction, } : null; } @@ -315,7 +302,7 @@ export class MenuButtonController { type: 'custom:frigate-card-menu-icon', title: localize('config.view.views.image'), style: view?.is('image') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction('image') as FrigateCardCustomAction, + tap_action: createGeneralAction('image') as FrigateCardCustomAction, } : null; } @@ -332,9 +319,7 @@ export class MenuButtonController { type: 'custom:frigate-card-menu-icon', title: localize('config.view.views.timeline'), style: view.is('timeline') ? this._getEmphasizedStyle() : {}, - tap_action: createFrigateCardSimpleAction( - 'timeline', - ) as FrigateCardCustomAction, + tap_action: createGeneralAction('timeline') as FrigateCardCustomAction, } : null; } @@ -358,7 +343,7 @@ export class MenuButtonController { ...config.menu.buttons.download, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.download'), - tap_action: createFrigateCardSimpleAction('download') as FrigateCardCustomAction, + tap_action: createGeneralAction('download') as FrigateCardCustomAction, }; } return null; @@ -374,9 +359,7 @@ export class MenuButtonController { ...config.menu.buttons.camera_ui, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.camera_ui'), - tap_action: createFrigateCardSimpleAction( - 'camera_ui', - ) as FrigateCardCustomAction, + tap_action: createGeneralAction('camera_ui') as FrigateCardCustomAction, } : null; } @@ -402,16 +385,16 @@ export class MenuButtonController { style: forbidden || muted ? {} : this._getEmphasizedStyle(true), ...(!forbidden && buttonType === 'momentary' && { - start_tap_action: createFrigateCardSimpleAction( + start_tap_action: createGeneralAction( 'microphone_unmute', ) as FrigateCardCustomAction, - end_tap_action: createFrigateCardSimpleAction( + end_tap_action: createGeneralAction( 'microphone_mute', ) as FrigateCardCustomAction, }), ...(!forbidden && buttonType === 'toggle' && { - tap_action: createFrigateCardSimpleAction( + tap_action: createGeneralAction( muted ? 'microphone_unmute' : 'microphone_mute', ) as FrigateCardCustomAction, }), @@ -429,7 +412,7 @@ export class MenuButtonController { ...config.menu.buttons.expand, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.expand'), - tap_action: createFrigateCardSimpleAction('expand') as FrigateCardCustomAction, + tap_action: createGeneralAction('expand') as FrigateCardCustomAction, style: inExpandedMode ? this._getEmphasizedStyle() : {}, }; } @@ -444,9 +427,7 @@ export class MenuButtonController { ...config.menu.buttons.fullscreen, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.fullscreen'), - tap_action: createFrigateCardSimpleAction( - 'fullscreen', - ) as FrigateCardCustomAction, + tap_action: createGeneralAction('fullscreen') as FrigateCardCustomAction, style: inFullscreenMode ? this._getEmphasizedStyle() : {}, } : null; @@ -469,8 +450,8 @@ export class MenuButtonController { .map((playerEntityID) => { const title = getEntityTitle(hass, playerEntityID) || playerEntityID; const state = hass.states[playerEntityID]; - const playAction = createFrigateCardMediaPlayerAction(playerEntityID, 'play'); - const stopAction = createFrigateCardMediaPlayerAction(playerEntityID, 'stop'); + const playAction = createMediaPlayerAction(playerEntityID, 'play'); + const stopAction = createMediaPlayerAction(playerEntityID, 'stop'); const disabled = !state || state.state === 'unavailable'; return { @@ -512,7 +493,7 @@ export class MenuButtonController { ...config.menu.buttons.play, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.play'), - tap_action: createFrigateCardSimpleAction( + tap_action: createGeneralAction( paused ? 'play' : 'pause', ) as FrigateCardCustomAction, }; @@ -535,7 +516,7 @@ export class MenuButtonController { ...config.menu.buttons.mute, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.mute'), - tap_action: createFrigateCardSimpleAction( + tap_action: createGeneralAction( muted ? 'unmute' : 'mute', ) as FrigateCardCustomAction, }; @@ -553,9 +534,7 @@ export class MenuButtonController { ...config.menu.buttons.screenshot, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.screenshot'), - tap_action: createFrigateCardSimpleAction( - 'screenshot', - ) as FrigateCardCustomAction, + tap_action: createGeneralAction('screenshot') as FrigateCardCustomAction, }; } return null; @@ -577,65 +556,75 @@ export class MenuButtonController { title: isGrid ? localize('display_modes.single') : localize('display_modes.grid'), - tap_action: createFrigateCardDisplayModeAction(isGrid ? 'single' : 'grid'), + tap_action: createDisplayModeAction(isGrid ? 'single' : 'grid'), }; } return null; } - protected _getSubstreamAwareCameraID(view: View): string { - return view.is('live') - ? view.context?.live?.overrides?.get(view.camera) ?? view.camera - : view.camera; - } - - protected _getPTZButton( + protected _getPTZControlsButton( config: FrigateCardConfig, cameraManager: CameraManager, view: View, ): MenuItem | null { - const substreamAwareCameraCapabilities = cameraManager.getCameraCapabilities( - this._getSubstreamAwareCameraID(view), - ); + const ptzConfig = view.is('live') + ? config.live.controls.ptz + : view.isViewerView() + ? config.media_viewer.controls.ptz + : null; - if ( - view.is('live') && - hasUsablePTZ(substreamAwareCameraCapabilities, config.live.controls.ptz) - ) { + if (!ptzConfig || ptzConfig.mode === 'off') { + return null; + } + + const ptzTarget = getPTZTarget(view, { + cameraManager: cameraManager, + ...(ptzConfig.mode === 'auto' && { type: 'ptz' }), + }); + + if (ptzTarget) { const isOn = - view.context?.live?.ptzVisible === false - ? false - : config.live.controls.ptz.mode === 'on'; + view.context?.ptzControls?.enabled !== false && + (ptzConfig.mode === 'on' || + (ptzConfig.mode === 'auto' && ptzTarget.type === 'ptz')); return { icon: 'mdi:pan', - ...config.menu.buttons.ptz, + ...config.menu.buttons.ptz_controls, style: isOn ? this._getEmphasizedStyle() : {}, type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.ptz'), - tap_action: createFrigateCardShowPTZAction(!isOn), + title: localize('config.menu.buttons.ptz_controls'), + tap_action: createPTZControlsAction(!isOn), }; } return null; } - protected _getDefaultZoomButton( + protected _getPTZHomeButton( config: FrigateCardConfig, + cameraManager: CameraManager, view: View, ): MenuItem | null { - const targetID = view.isViewerView() - ? view.queryResults?.getSelectedResult()?.getID() ?? null - : this._getSubstreamAwareCameraID(view); + const target = getPTZTarget(view, { + cameraManager: cameraManager, + }); - if (!targetID || (view.context?.zoom?.[targetID]?.isDefault ?? true)) { + if ( + !target || + ((target.type === 'digital' && + view.context?.zoom?.[target.targetID]?.observed?.isDefault) ?? + true) + ) { return null; } return { - icon: 'mdi:magnify-close', - ...config.menu.buttons.default_zoom, + icon: 'mdi:home', + ...config.menu.buttons.ptz_home, type: 'custom:frigate-card-menu-icon', - title: localize('config.menu.buttons.default_zoom'), - tap_action: createFrigateCardChangeZoomAction(targetID) as FrigateCardCustomAction, + title: localize('config.menu.buttons.ptz_home'), + tap_action: createPTZMultiAction({ + targetID: target.targetID, + }) as FrigateCardCustomAction, }; } diff --git a/src/components-lib/menu-controller.ts b/src/components-lib/menu-controller.ts index 9f773a56..f61e4131 100644 --- a/src/components-lib/menu-controller.ts +++ b/src/components-lib/menu-controller.ts @@ -10,12 +10,12 @@ import type { import { FRIGATE_BUTTON_MENU_ICON } from '../const.js'; import { StateParameters } from '../types.js'; import { - convertActionToFrigateCardCustomAction, - frigateCardHandleActionConfig, + convertActionToCardCustomAction, getActionConfigGivenAction, } from '../utils/action'; import { arrayify, isTruthy, setOrRemoveAttribute } from '../utils/basic.js'; import { refreshDynamicStateParameters } from '../utils/ha/index.js'; +import { dispatchActionExecutionRequest } from '../card-controller/actions/utils/execution-request.js'; export class MenuController { protected _host: LitElement; @@ -95,7 +95,6 @@ export class MenuController { } public actionHandler( - hass: HomeAssistant, ev: HASSDomEvent<{ action: string; config?: ActionsConfig }>, config?: ActionsConfig, ): void { @@ -134,7 +133,10 @@ export class MenuController { } if (toggleLessActions.length) { - frigateCardHandleActionConfig(this._host, hass, config, interaction, actions); + dispatchActionExecutionRequest(this._host, { + action: actions, + config: config, + }); } if (this._isHidingMenu()) { @@ -209,7 +211,7 @@ export class MenuController { } protected _isMenuToggleAction(action: ActionType): boolean { - const frigateCardAction = convertActionToFrigateCardCustomAction(action); + const frigateCardAction = convertActionToCardCustomAction(action); return !!frigateCardAction && frigateCardAction.frigate_card_action == 'menu_toggle'; } } diff --git a/src/components-lib/ptz-controller.ts b/src/components-lib/ptz-controller.ts deleted file mode 100644 index 5399574a..00000000 --- a/src/components-lib/ptz-controller.ts +++ /dev/null @@ -1,170 +0,0 @@ -import { HASSDomEvent, HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { CameraManager } from '../camera-manager/manager'; -import { - Actions, - ActionsConfig, - FrigateCardPTZAction, - FrigateCardPTZActions, - FrigateCardPTZConfig, - PTZAction, - PTZControlAction, - PTZ_CONTROL_ACTIONS, -} from '../config/types'; -import { - frigateCardHandleActionConfig, - getActionConfigGivenAction, -} from '../utils/action'; - -export class PTZController { - private _host: HTMLElement; - - private _config: FrigateCardPTZConfig | null = null; - private _hass: HomeAssistant | null = null; - private _cameraManager: CameraManager | null = null; - private _cameraID: string | null = null; - private _actions: FrigateCardPTZActions | null = null; - private _forceVisibility?: boolean; - - constructor(host: HTMLElement) { - this._host = host; - } - - public setConfig(config?: FrigateCardPTZConfig) { - this._config = config ?? null; - - this._host.setAttribute('data-orientation', config?.orientation ?? 'horizontal'); - this._host.setAttribute('data-position', config?.position ?? 'bottom-right'); - this._host.setAttribute( - 'style', - Object.entries(config?.style ?? {}) - .map(([k, v]) => `${k}:${v}`) - .join(';'), - ); - } - - public getConfig(): FrigateCardPTZConfig | null { - return this._config; - } - - public setHASS(hass?: HomeAssistant) { - this._hass = hass ?? null; - } - - public setCamera(cameraManager?: CameraManager, cameraID?: string) { - this._cameraManager = cameraManager ?? null; - this._cameraID = cameraID ?? null; - - this._calculateActions(); - } - - public setForceVisibility(forceVisibility?: boolean): void { - this._forceVisibility = forceVisibility; - } - - public handleAction( - ev: HASSDomEvent<{ action: string }>, - config?: ActionsConfig | null, - ): void { - // Nothing else has the configuration for this action, so don't let it - // propagate further. - ev.stopPropagation(); - - const interaction: string = ev.detail.action; - const action = getActionConfigGivenAction(interaction, config); - if (config && action && this._hass) { - frigateCardHandleActionConfig(this._host, this._hass, config, interaction, action); - } - } - - public getPTZActions(actionName: PTZControlAction): Actions | null { - const propertyName = 'actions_' + actionName; - return this._config?.[propertyName] ?? this._actions?.[propertyName] ?? null; - } - - private _hasAnyAction(): boolean { - for (const actionName of PTZ_CONTROL_ACTIONS) { - if ('actions_' + actionName in (this._actions ?? {})) { - return true; - } - } - return false; - } - - public shouldDisplay(): boolean { - return this._forceVisibility === false - ? false - : this._config?.mode === 'on' && this._hasAnyAction(); - } - - private _calculateActions(): void { - const getDefaultAction = ( - ptzAction: PTZAction, - options?: { - phase?: 'start' | 'stop'; - preset?: string; - }, - ): FrigateCardPTZAction => ({ - action: 'fire-dom-event', - frigate_card_action: 'ptz', - ptz_action: ptzAction, - ...(options?.phase && { ptz_phase: options.phase }), - ...(options?.preset && { ptz_preset: options.preset }), - }); - - const getDefaultActions = ( - ptzAction: PTZAction, - continuous: boolean, - preset?: string, - ): Actions => - continuous - ? { - start_tap_action: getDefaultAction(ptzAction, { - phase: 'start', - preset: preset, - }), - end_tap_action: getDefaultAction(ptzAction, { - phase: 'stop', - preset: preset, - }), - } - : { - tap_action: getDefaultAction(ptzAction, { preset: preset }), - }; - - if (!this._cameraManager || !this._cameraID) { - return; - } - - const ptzCapabilities = this._cameraManager.getCameraCapabilities( - this._cameraID, - )?.getPTZCapabilities(); - - const defaultActions: FrigateCardPTZActions = {}; - const panTilt = ptzCapabilities?.panTilt; - const zoom = ptzCapabilities?.zoom; - const presets = ptzCapabilities?.presets; - - if (panTilt?.length) { - const continuous = panTilt.includes('continuous'); - defaultActions.actions_up = getDefaultActions('up', continuous); - defaultActions.actions_down = getDefaultActions('down', continuous); - defaultActions.actions_left = getDefaultActions('left', continuous); - defaultActions.actions_right = getDefaultActions('right', continuous); - } - - if (zoom?.length) { - const continuous = zoom.includes('continuous'); - defaultActions.actions_zoom_in = getDefaultActions('zoom_in', continuous); - defaultActions.actions_zoom_out = getDefaultActions('zoom_out', continuous); - } - - if (presets?.length) { - defaultActions.actions_home = getDefaultActions('preset', false, presets[0]); - } - - this._actions = { - ...defaultActions, - ...this._config, - }; - } -} diff --git a/src/components-lib/ptz/ptz-controller.ts b/src/components-lib/ptz/ptz-controller.ts new file mode 100644 index 00000000..88af5a20 --- /dev/null +++ b/src/components-lib/ptz/ptz-controller.ts @@ -0,0 +1,145 @@ +import { HASSDomEvent, HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { CameraManager } from '../../camera-manager/manager'; +import { dispatchActionExecutionRequest } from '../../card-controller/actions/utils/execution-request'; +import { PTZAction } from '../../config/ptz'; +import { Actions, ActionsConfig, PTZControlsConfig } from '../../config/types'; +import { createPTZMultiAction, getActionConfigGivenAction } from '../../utils/action'; +import { PTZActionNameToMultiAction, PTZActionPresence } from './types'; + +export class PTZController { + private _host: HTMLElement; + + private _config: PTZControlsConfig | null = null; + private _hass: HomeAssistant | null = null; + private _cameraManager: CameraManager | null = null; + private _cameraID: string | null = null; + + private _forceVisibility?: boolean; + + constructor(host: HTMLElement) { + this._host = host; + } + + public setConfig(config?: PTZControlsConfig) { + this._config = config ?? null; + + this._host.setAttribute('data-orientation', config?.orientation ?? 'horizontal'); + this._host.setAttribute('data-position', config?.position ?? 'bottom-right'); + this._host.setAttribute( + 'style', + Object.entries(config?.style ?? {}) + .map(([k, v]) => `${k}:${v}`) + .join(';'), + ); + } + + public getConfig(): PTZControlsConfig | null { + return this._config; + } + + public setCamera(cameraManager?: CameraManager, cameraID?: string): void { + this._cameraManager = cameraManager ?? null; + this._cameraID = cameraID ?? null; + } + + public setForceVisibility(forceVisibility?: boolean): void { + this._forceVisibility = forceVisibility; + } + + public handleAction( + ev: HASSDomEvent<{ action: string }>, + config?: ActionsConfig | null, + ): void { + // Nothing else has the configuration for this action, so don't let it + // propagate further. + ev.stopPropagation(); + + const interaction: string = ev.detail.action; + const action = getActionConfigGivenAction(interaction, config); + if (action) { + dispatchActionExecutionRequest(this._host, { + action: action, + ...(config && { config: config }), + }); + } + } + + public hasUsefulAction(): PTZActionPresence { + const allUsefulActions = { + pt: true, + z: true, + home: true, + }; + if (!this._cameraID) { + // Will use digital PTZ. + return allUsefulActions; + } + const capabilities = this._cameraManager?.getCameraCapabilities(this._cameraID); + if (!capabilities || !capabilities.hasPTZCapability()) { + // Will use digital PTZ. + return allUsefulActions; + } + + const ptzCapabilities = capabilities.getPTZCapabilities(); + return { + pt: + !!ptzCapabilities?.up || + !!ptzCapabilities?.down || + !!ptzCapabilities?.left || + !!ptzCapabilities?.right, + z: !!ptzCapabilities?.zoomIn || !!ptzCapabilities?.zoomOut, + home: !!ptzCapabilities?.presets?.length, + }; + } + + public shouldDisplay(): boolean { + return this._forceVisibility !== undefined + ? this._forceVisibility + : this._config?.mode === 'auto' + ? !!this._cameraID && + !!this._cameraManager?.getCameraCapabilities(this._cameraID)?.hasPTZCapability() + : this._config?.mode === 'on'; + } + + public getPTZActions(): PTZActionNameToMultiAction { + const getDefaultActions = (options?: { + ptzAction?: PTZAction; + preset?: string; + }): Actions => ({ + start_tap_action: createPTZMultiAction({ + ptzAction: options?.ptzAction, + ptzPhase: 'start', + ptzPreset: options?.preset, + }), + end_tap_action: createPTZMultiAction({ + ptzAction: options?.ptzAction, + ptzPhase: 'stop', + ptzPreset: options?.preset, + }), + }); + + const actions: PTZActionNameToMultiAction = {}; + actions.up = getDefaultActions({ + ptzAction: 'up', + }); + actions.down = getDefaultActions({ + ptzAction: 'down', + }); + actions.left = getDefaultActions({ + ptzAction: 'left', + }); + actions.right = getDefaultActions({ + ptzAction: 'right', + }); + actions.zoom_in = getDefaultActions({ + ptzAction: 'zoom_in', + }); + actions.zoom_out = getDefaultActions({ + ptzAction: 'zoom_out', + }); + actions.home = { + tap_action: createPTZMultiAction(), + }; + return actions; + } +} diff --git a/src/components-lib/ptz/types.ts b/src/components-lib/ptz/types.ts new file mode 100644 index 00000000..2c71cc60 --- /dev/null +++ b/src/components-lib/ptz/types.ts @@ -0,0 +1,21 @@ +import { PTZControlAction } from '../../config/ptz'; +import { Actions } from '../../config/types'; + +interface PTZControlsViewContext { + enabled?: boolean; +} +declare module 'view' { + interface ViewContext { + ptzControls?: PTZControlsViewContext; + } +} + +export type PTZActionNameToMultiAction = { + [K in PTZControlAction]?: Actions; +}; + +export interface PTZActionPresence { + pt: boolean; + z: boolean; + home: boolean; +} diff --git a/src/components-lib/zoom/types.ts b/src/components-lib/zoom/types.ts index 04f92855..533c8209 100644 --- a/src/components-lib/zoom/types.ts +++ b/src/components-lib/zoom/types.ts @@ -1,11 +1,29 @@ -export interface ZoomConfig { - pan?: { - x?: number; - y?: number; +import { PartialDeep } from 'type-fest'; + +export const ZOOM_DEFAULT_PAN_X = 50; +export const ZOOM_DEFAULT_PAN_Y = 50; +export const ZOOM_DEFAULT_SCALE = 1; +export const ZOOM_PRECISION = 4; + +export interface ZoomSettingsBase { + pan: { + x: number; + y: number; }; - zoom?: number; + zoom: number; } -export interface ZoomDefault { +export type PartialZoomSettings = PartialDeep; + +export interface ZoomSettingsObserved extends ZoomSettingsBase { isDefault: boolean; + unzoomed: boolean; } + +export const isZoomEmpty = (settings?: PartialZoomSettings | null): boolean => { + return ( + settings?.pan?.x === undefined && + settings?.pan?.y === undefined && + settings?.zoom === undefined + ); +}; diff --git a/src/components-lib/zoom/zoom-controller.ts b/src/components-lib/zoom/zoom-controller.ts index 8a6aeec6..7144bdd2 100644 --- a/src/components-lib/zoom/zoom-controller.ts +++ b/src/components-lib/zoom/zoom-controller.ts @@ -1,17 +1,20 @@ import Panzoom, { PanzoomEventDetail, PanzoomObject } from '@dermotduffy/panzoom'; -import debounce from 'lodash-es/debounce'; +import throttle from 'lodash-es/throttle'; import round from 'lodash-es/round'; import { arefloatsApproximatelyEqual, dispatchFrigateCardEvent, isHoverableDevice, } from '../../utils/basic'; -import { ZoomConfig } from './types'; - -const ZOOM_DEFAULT_PAN_X = 50; -const ZOOM_DEFAULT_PAN_Y = 50; -const ZOOM_DEFAULT_SCALE = 1; -const ZOOM_PRECISION = 4; +import { + PartialZoomSettings, + ZOOM_DEFAULT_PAN_X, + ZOOM_DEFAULT_PAN_Y, + ZOOM_DEFAULT_SCALE, + ZOOM_PRECISION, + ZoomSettingsObserved, + isZoomEmpty, +} from './types'; export class ZoomController { protected _element: HTMLElement; @@ -26,15 +29,14 @@ export class ZoomController { // Should clicks be allowed to propagate, or consumed as a pan/zoom action? protected _allowClick = true; - protected _defaultConfig: ZoomConfig | null; - protected _config: ZoomConfig | null; + protected _defaultSettings: PartialZoomSettings | null; + protected _settings: PartialZoomSettings | null; - // When the user pans/zooms changes may be created at a very high rate. - protected _debouncedChangeHandler = debounce(this._changeHandler.bind(this), 200); - - // Multiple calls to setConfig() or setDefaultConfig() or resizes should only - // update once. - protected _debouncedUpdater = debounce(this._updateBasedOnConfig.bind(this), 200); + // These values should be suitably less than the value of STEP_DELAY_SECONDS + // in the ptz-digital action, in order to ensure smooth movements of the + // digital PTZ actions. + protected _debouncedChangeHandler = throttle(this._changeHandler.bind(this), 50); + protected _debouncedUpdater = throttle(this._updateBasedOnConfig.bind(this), 50); protected _resizeObserver = new ResizeObserver(this._debouncedUpdater); @@ -70,6 +72,11 @@ export class ZoomController { // handler in the viewer). if (!this._allowClick) { ev.stopPropagation(); + + // Even though the click is stopped,the card still needs to gain focus so + // that keyboard shortcuts will work immediately after the card is clicked + // upon. + dispatchFrigateCardEvent(this._element, 'focus'); } this._allowClick = true; }; @@ -97,11 +104,14 @@ export class ZoomController { constructor( element: HTMLElement, - options?: { config?: ZoomConfig | null; defaultConfig?: ZoomConfig | null }, + options?: { + config?: PartialZoomSettings | null; + defaultConfig?: PartialZoomSettings | null; + }, ) { this._element = element; - this._config = options?.config ?? null; - this._defaultConfig = options?.defaultConfig ?? null; + this._settings = options?.config ?? null; + this._defaultSettings = options?.defaultConfig ?? null; } public activate(): void { @@ -182,44 +192,47 @@ export class ZoomController { this._element.removeEventListener('panzoomchange', this._debouncedChangeHandler); } - public setDefaultConfig(config: ZoomConfig | null): void { - this._defaultConfig = config; + public setDefaultSettings(config: PartialZoomSettings | null): void { + this._defaultSettings = config; this._debouncedUpdater(); } - public setConfig(config: ZoomConfig): void { - this._config = config; + public setSettings(config: PartialZoomSettings | null): void { + this._settings = config; this._debouncedUpdater(); } protected _changeHandler(ev: Event): void { const pz = (>ev).detail; - - const isUnzoomed = this._isUnzoomed(pz.scale); - const isAtDefault = this._isAtDefaultZoomAndPan(pz.x, pz.y, pz.scale); + const unzoomed = this._isUnzoomed(pz.scale); // Take care here to only dispatch the zoomed/unzoomed events when the // absolute state changes (rather than on every single zoom adjustment). - if (isUnzoomed && this._zoomed) { + if (unzoomed && this._zoomed) { this._zoomed = false; this._setTouchAction(true); dispatchFrigateCardEvent(this._element, 'zoom:unzoomed'); - } else if (!isUnzoomed && !this._zoomed) { + } else if (!unzoomed && !this._zoomed) { this._zoomed = true; this._setTouchAction(false); dispatchFrigateCardEvent(this._element, 'zoom:zoomed'); } - if (isAtDefault && !this._default) { - this._default = true; - dispatchFrigateCardEvent(this._element, 'zoom:default', { isDefault: true }); - } else if (!isAtDefault && this._default) { - this._default = false; - dispatchFrigateCardEvent(this._element, 'zoom:default', { isDefault: false }); - } + const converted = this._convertXYPanToPercent(pz.x, pz.y, pz.scale); + const observed: ZoomSettingsObserved = { + pan: { + x: converted?.x ?? ZOOM_DEFAULT_PAN_X, + y: converted?.y ?? ZOOM_DEFAULT_PAN_Y, + }, + zoom: pz.scale, + isDefault: this._isAtDefaultZoomAndPan(pz.x, pz.y, pz.scale), + unzoomed: unzoomed, + }; + + dispatchFrigateCardEvent(this._element, 'zoom:change', observed); } - protected _isZoomEqual(a: ZoomConfig, b: ZoomConfig): boolean { + protected _isZoomEqual(a: PartialZoomSettings, b: PartialZoomSettings): boolean { // The ?? clauses below cannot be reached since this function is only ever // used fully specified by this object. It's kept as-is for completeness. return ( @@ -247,16 +260,8 @@ export class ZoomController { ); } - protected _isZoomEmpty(config?: ZoomConfig | null): boolean { - return ( - config?.pan?.x === undefined && - config?.pan?.y === undefined && - config?.zoom === undefined - ); - } - - protected _getConfigToUse(): ZoomConfig | null { - return this._isZoomEmpty(this._config) ? this._defaultConfig : this._config; + protected _getConfigToUse(): PartialZoomSettings | null { + return isZoomEmpty(this._settings) ? this._defaultSettings : this._settings; } protected _updateBasedOnConfig(): void { @@ -292,6 +297,9 @@ export class ZoomController { } this._panzoom.zoom(desiredScale, { + // Zoom is stepped, not animated. If it is animated, there is interaction + // between the zoom and the pan below, and the pan would need to be + // delayed until after the zoom is complete. animate: false, }); @@ -300,10 +308,12 @@ export class ZoomController { // situation where we need to ensure the zoom completes first. Using // `requestAnimationFrame` appears to reliably allow the zoom to finish // rendering first, before the pain is applied. + // // See: https://github.com/timmywil/panzoom?tab=readme-ov-file#a-note-on-the-async-nature-of-panzoom window.requestAnimationFrame(() => { this._panzoom?.pan(x, y, { - animate: false, + animate: true, + duration: 100, }); }); } @@ -332,6 +342,28 @@ export class ZoomController { }; } + protected _convertXYPanToPercent( + x: number, + y: number, + scale: number, + ): { x: number; y: number } | null { + const minMax = this._getTransformMinMax(scale, this._panzoom?.getScale()); + if (minMax === null) { + return null; + } + + return { + x: + ((-x + Math.abs(minMax.minX)) / + (Math.abs(minMax.maxX) + Math.abs(minMax.minX))) * + 100, + y: + ((-y + Math.abs(minMax.minY)) / + (Math.abs(minMax.maxY) + Math.abs(minMax.minY))) * + 100, + }; + } + protected _getTransformMinMax( desiredScale: number, currentScale?: number, @@ -375,14 +407,14 @@ export class ZoomController { } protected _isAtDefaultZoomAndPan(x: number, y: number, scale: number): boolean { - if (!this._defaultConfig) { + if (!this._defaultSettings) { return this._isUnzoomed(scale); } const convertedDefault = this._convertPercentToXYPan( - this._defaultConfig.pan?.x ?? ZOOM_DEFAULT_PAN_X, - this._defaultConfig.pan?.y ?? ZOOM_DEFAULT_PAN_Y, - this._defaultConfig.zoom ?? ZOOM_DEFAULT_SCALE, + this._defaultSettings.pan?.x ?? ZOOM_DEFAULT_PAN_X, + this._defaultSettings.pan?.y ?? ZOOM_DEFAULT_PAN_Y, + this._defaultSettings.zoom ?? ZOOM_DEFAULT_SCALE, ); if (!convertedDefault) { return true; @@ -393,7 +425,7 @@ export class ZoomController { arefloatsApproximatelyEqual(y, convertedDefault.y) && arefloatsApproximatelyEqual( scale, - this._defaultConfig.zoom ?? + this._defaultSettings.zoom ?? // The ZOOM_DEFAULT_SCALE clause below cannot be reached since when // this._defaultConfig.zoom is undefined, convertedDefault will end up // null above and this function will have already returned. diff --git a/src/components-lib/zoom/zoom-view-context.ts b/src/components-lib/zoom/zoom-view-context.ts index bd8b169a..bd13e89c 100644 --- a/src/components-lib/zoom/zoom-view-context.ts +++ b/src/components-lib/zoom/zoom-view-context.ts @@ -1,15 +1,13 @@ import { ViewContext } from 'view'; -import { ZoomConfig, ZoomDefault } from './types.js'; import { dispatchViewContextChangeEvent } from '../../view/view.js'; +import { ZoomSettingsObserved, PartialZoomSettings } from './types.js'; interface ZoomViewContext { + observed?: ZoomSettingsObserved; + // Populate this to request zoom to a particular scale/x/y. An empty object // will reset to default, null will make no change. - zoom?: ZoomConfig | null; - - // This will be populated with whether or not the current zoom is at the - // default level. - isDefault?: boolean; + requested?: PartialZoomSettings | null; } interface ZoomsViewContext { @@ -22,36 +20,37 @@ declare module 'view' { } } -export const generateViewContextForZoomChange = ( +export const generateViewContextForZoom = ( targetID: string, options?: { - zoom?: ZoomConfig | null; - isDefault?: boolean; + observed?: ZoomSettingsObserved; + requested?: PartialZoomSettings | null; }, ): ViewContext | null => { return { zoom: { [targetID]: { - zoom: options?.zoom ?? null, - ...(options?.isDefault !== undefined && { isDefault: options.isDefault }), + observed: options?.observed ?? undefined, + requested: options?.requested ?? null, }, }, }; }; /** - * Convenience wrapper to convert a zoom default into a dispatched view context + * Convenience wrapper to convert zoom settings into a dispatched view context * change. */ -export const handleZoomDefaultEvent = ( +export const handleZoomSettingsObservedEvent = ( element: EventTarget, - ev: CustomEvent, + ev: CustomEvent, targetID?: string, ): void => { - targetID && dispatchViewContextChangeEvent( - element, - generateViewContextForZoomChange(targetID, { - isDefault: ev.detail.isDefault, - }), - ); + targetID && + dispatchViewContextChangeEvent( + element, + generateViewContextForZoom(targetID, { + observed: ev.detail, + }), + ); }; diff --git a/src/components/image.ts b/src/components/image.ts index 5a1850d3..63335d86 100644 --- a/src/components/image.ts +++ b/src/components/image.ts @@ -9,13 +9,10 @@ import { unsafeCSS, } from 'lit'; import { customElement, property } from 'lit/decorators.js'; -import { guard } from 'lit/directives/guard.js'; import { live } from 'lit/directives/live.js'; import { createRef, ref, Ref } from 'lit/directives/ref.js'; import isEqual from 'lodash-es/isEqual'; import { CachedValueController } from '../components-lib/cached-value-controller.js'; -import { ZoomDefault } from '../components-lib/zoom/types.js'; -import { handleZoomDefaultEvent } from '../components-lib/zoom/zoom-view-context.js'; import { CameraConfig, ImageViewConfig } from '../config/types.js'; import defaultImage from '../images/frigate-bird-in-sky.jpg'; import { localize } from '../localize/localize.js'; @@ -31,6 +28,7 @@ import { } from '../utils/media-info.js'; import { View } from '../view/view.js'; import { dispatchErrorMessageEvent } from './message.js'; +import { CameraManager } from '../camera-manager/manager.js'; // See TOKEN_CHANGE_INTERVAL in https://github.com/home-assistant/core/blob/dev/homeassistant/components/camera/__init__.py . const HASS_REJECTION_CUTOFF_MS = 5 * 60 * 1000; @@ -46,6 +44,9 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay @property({ attribute: false }) public cameraConfig?: CameraConfig; + @property({ attribute: false }) + public cameraManager?: CameraManager; + // Using contentsChanged to ensure overridden configs (e.g. when the // 'show_image_during_load' option is true for live views, an overridden // config may be used here). @@ -155,10 +156,6 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay () => dispatchMediaPauseEvent(this), ); } - - if (changedProps.has('imageConfig') && this.imageConfig?.zoomable) { - import('./zoomer.js'); - } } // If the camera or view changed, immediately discard the old value (view to @@ -279,67 +276,46 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay } } - protected _useZoomIfRequired(template: TemplateResult): TemplateResult { - const targetID = this.cameraConfig?.id; - const zoomConfig = targetID ? this.view?.context?.zoom?.[targetID]?.zoom : undefined; - - return this.imageConfig?.zoomable - ? html` - this.cameraConfig?.dimensions?.layout - ? { - pan: this.cameraConfig.dimensions.layout.pan, - zoom: this.cameraConfig.dimensions.layout.zoom, - } - : undefined, - )} - .config=${zoomConfig} - @frigate-card:zoom:default=${(ev: CustomEvent) => - handleZoomDefaultEvent(this, ev, targetID)} - > - ${template} - ` - : template; - } - protected render(): TemplateResult | void { const src = this._cachedValueController?.value; // Note the use of live() below to ensure the update will restore the image // src if it's been changed via _forceSafeImage(). return src - ? this._useZoomIfRequired(html` { - const mediaLoadedInfo = createMediaLoadedInfo(ev, { - player: this, - capabilities: { - supportsPause: !!this.imageConfig?.refresh_seconds, - }, - }); - // Avoid the media being reported as repeatedly loading unless the - // media info changes. - if (mediaLoadedInfo && !isEqual(this._mediaLoadedInfo, mediaLoadedInfo)) { - this._mediaLoadedInfo = mediaLoadedInfo; - dispatchExistingMediaLoadedInfoAsEvent(this, mediaLoadedInfo); - } - }} - @error=${() => { - if (this.imageConfig?.mode === 'camera') { - // In camera mode, the user has likely not made an error, but HA - // may be unavailble, so show the stock image. Don't let the URL - // override the stock image in this case, as this could create an - // error loop if that URL subsequently failed to load. - this._forceSafeImage(true); - } else if (this.imageConfig?.mode === 'url') { - // In url mode, the user likely specified a URL that cannot be - // resolved. Show an error message. - dispatchErrorMessageEvent(this, localize('error.image_load_error'), { - context: this.imageConfig, + ? html` + { + const mediaLoadedInfo = createMediaLoadedInfo(ev, { + player: this, + capabilities: { + supportsPause: !!this.imageConfig?.refresh_seconds, + }, }); - } - }} - />`) + // Avoid the media being reported as repeatedly loading unless the + // media info changes. + if (mediaLoadedInfo && !isEqual(this._mediaLoadedInfo, mediaLoadedInfo)) { + this._mediaLoadedInfo = mediaLoadedInfo; + dispatchExistingMediaLoadedInfoAsEvent(this, mediaLoadedInfo); + } + }} + @error=${() => { + if (this.imageConfig?.mode === 'camera') { + // In camera mode, the user has likely not made an error, but HA + // may be unavailble, so show the stock image. Don't let the URL + // override the stock image in this case, as this could create an + // error loop if that URL subsequently failed to load. + this._forceSafeImage(true); + } else if (this.imageConfig?.mode === 'url') { + // In url mode, the user likely specified a URL that cannot be + // resolved. Show an error message. + dispatchErrorMessageEvent(this, localize('error.image_load_error'), { + context: this.imageConfig, + }); + } + }} + /> + ` : html``; } diff --git a/src/components/key-assigner.ts b/src/components/key-assigner.ts new file mode 100644 index 00000000..3312dfec --- /dev/null +++ b/src/components/key-assigner.ts @@ -0,0 +1,93 @@ +import { + CSSResultGroup, + html, + LitElement, + PropertyValues, + TemplateResult, + unsafeCSS, +} from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; +import { KeyAssignerController } from '../components-lib/key-assigner-controller'; +import { KeyboardShortcut } from '../config/keyboard-shortcuts'; +import keyAssignerStyle from '../scss/key-assigner.scss'; +import { localize } from '../localize/localize'; + +@customElement('frigate-card-key-assigner') +export class FrigateCardKeyAssigner extends LitElement { + @property({ attribute: false }) + public label?: string; + + @property({ attribute: false }) + public value?: KeyboardShortcut | null; + + protected _controller = new KeyAssignerController(this); + + protected willUpdate(changedProps: PropertyValues): void { + if (changedProps.has('value')) { + this._controller.setValue(this.value ?? null); + } + } + + protected render(): TemplateResult | void { + if (!this.label) { + return; + } + + const renderKey = (key: string) => { + return html`
      +
      ${key}
      +
      `; + }; + + return html` +
      ${this.label}
      + { + this._controller.toggleAssigning(); + }} + > + + + ${ + this._controller.isAssigning() + ? localize('key_assigner.assigning') + : localize('key_assigner.assign') + } + + + ${ + this._controller.hasValue() + ? html` { + this._controller.setValue(null); + }} + > + + ${localize('key_assigner.unassign')} + ` + : '' + } +
      + ${this.value?.ctrl ? renderKey(localize('key_assigner.modifiers.ctrl')) : ''} + ${this.value?.shift ? renderKey(localize('key_assigner.modifiers.shift')) : ''} + ${this.value?.meta ? renderKey(localize('key_assigner.modifiers.meta')) : ''} + ${this.value?.alt ? renderKey(localize('key_assigner.modifiers.alt')) : ''} + ${this.value?.key ? renderKey(this.value.key) : ''} +
      + `; + } + + static get styles(): CSSResultGroup { + return unsafeCSS(keyAssignerStyle); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'frigate-card-key-assigner': FrigateCardKeyAssigner; + } +} diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 8251fc07..9a1910b5 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -21,8 +21,6 @@ import { import { ReadonlyMicrophoneManager } from '../../card-controller/microphone-manager.js'; import { LiveController } from '../../components-lib/live/live-controller.js'; import { MediaGridSelected } from '../../components-lib/media-grid-controller.js'; -import { ZoomConfig, ZoomDefault } from '../../components-lib/zoom/types.js'; -import { handleZoomDefaultEvent } from '../../components-lib/zoom/zoom-view-context.js'; import { CameraConfig, CardWideConfig, @@ -62,6 +60,12 @@ import { FrigateCardTitleControl, getDefaultTitleConfigForView, } from '../title-control.js'; +import { + PartialZoomSettings, + ZoomSettingsObserved, +} from '../../components-lib/zoom/types.js'; +import { handleZoomSettingsObservedEvent } from '../../components-lib/zoom/zoom-view-context.js'; +import { getStreamCameraID } from '../../utils/substream.js'; const FRIGATE_CARD_LIVE_PROVIDER = 'frigate-card-live-provider'; @@ -503,9 +507,9 @@ export class FrigateCardLiveCarousel extends LitElement { .liveConfig=${liveConfig} .hass=${this.hass} .cardWideConfig=${this.cardWideConfig} - .zoomConfig=${this.view?.context?.zoom?.[cameraID]?.zoom} - @frigate-card:zoom:default=${(ev: CustomEvent) => - handleZoomDefaultEvent(this, ev, cameraID)} + .zoomSettings=${this.view?.context?.zoom?.[cameraID]?.requested} + @frigate-card:zoom:change=${(ev: CustomEvent) => + handleZoomSettingsObservedEvent(this, ev, cameraID)} >
      @@ -633,11 +637,11 @@ export class FrigateCardLiveCarousel extends LitElement { ${cameraMetadataCurrent && titleConfig @@ -694,7 +698,7 @@ export class FrigateCardLiveProvider public microphoneStream?: MediaStream; @property({ attribute: false }) - public zoomConfig?: ZoomConfig | null; + public zoomSettings?: PartialZoomSettings | null; @state() protected _isVideoMediaLoaded = false; @@ -857,7 +861,7 @@ export class FrigateCardLiveProvider protected _useZoomIfRequired(template: TemplateResult): TemplateResult { return this.liveConfig?.zoomable ? html` + .defaultSettings=${guard([this.cameraConfig?.dimensions?.layout], () => this.cameraConfig?.dimensions?.layout ? { pan: this.cameraConfig.dimensions.layout.pan, @@ -865,7 +869,7 @@ export class FrigateCardLiveProvider } : undefined, )} - .config=${this.zoomConfig} + .settings=${this.zoomSettings} @frigate-card:zoom:zoomed=${() => this.setControls(false)} @frigate-card:zoom:unzoomed=${() => this.setControls()} > @@ -944,17 +948,17 @@ export class FrigateCardLiveProvider ` : provider === 'go2rtc' ? html` - ` + ${ref(this._refProvider)} + class=${classMap(providerClasses)} + .hass=${this.hass} + .cameraConfig=${this.cameraConfig} + .cameraEndpoints=${this.cameraEndpoints} + .microphoneStream=${this.microphoneStream} + .microphoneConfig=${this.liveConfig.microphone} + ?controls=${this.liveConfig.controls.builtin} + @frigate-card:media:loaded=${this._videoMediaShowHandler.bind(this)} + > + ` : provider === 'webrtc-card' ? html` this.hass && this._controller.actionHandler(this.hass, ev)} + @action=${(ev) => this._controller.actionHandler(ev)} > `; } else if (button.type === 'custom:frigate-card-menu-submenu-select') { @@ -54,7 +54,7 @@ export class FrigateCardMenu extends LitElement { .hass=${this.hass} .submenuSelect=${button} .entityRegistryManager=${this.entityRegistryManager} - @action=${(ev) => this.hass && this._controller.actionHandler(this.hass, ev)} + @action=${(ev) => this._controller.actionHandler(ev)} > `; } @@ -84,8 +84,7 @@ export class FrigateCardMenu extends LitElement { hasDoubleClick: frigateCardHasAction(button.double_tap_action), })} .label=${buttonState.title || ''} - @action=${(ev) => - this.hass && this._controller.actionHandler(this.hass, ev, button)} + @action=${(ev) => this._controller.actionHandler(ev, button)} > ${svgPath ? html`` @@ -106,17 +105,13 @@ export class FrigateCardMenu extends LitElement { return html`
      ${matchingButtons.map((button) => this._renderButton(button))}
      ${opposingButtons.map((button) => this._renderButton(button))}
      `; diff --git a/src/components/ptz.ts b/src/components/ptz.ts index eed0d6e2..45355010 100644 --- a/src/components/ptz.ts +++ b/src/components/ptz.ts @@ -1,18 +1,19 @@ -import { HASSDomEvent, HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { HASSDomEvent } from '@dermotduffy/custom-card-helpers'; import { CSSResultGroup, - html, LitElement, PropertyValues, TemplateResult, - unsafeCSS + html, + unsafeCSS, } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { actionHandler } from '../action-handler-directive.js'; import { CameraManager } from '../camera-manager/manager.js'; -import { PTZController } from '../components-lib/ptz-controller.js'; -import { Actions, FrigateCardPTZConfig } from '../config/types.js'; +import { PTZController } from '../components-lib/ptz/ptz-controller.js'; +import { PTZActionPresence } from '../components-lib/ptz/types.js'; +import { Actions, PTZControlsConfig } from '../config/types.js'; import { localize } from '../localize/localize.js'; import ptzStyle from '../scss/ptz.scss'; import { frigateCardHasAction } from '../utils/action.js'; @@ -20,10 +21,7 @@ import { frigateCardHasAction } from '../utils/action.js'; @customElement('frigate-card-ptz') export class FrigateCardPTZ extends LitElement { @property({ attribute: false }) - public hass?: HomeAssistant; - - @property({ attribute: false }) - public config?: FrigateCardPTZConfig; + public config?: PTZControlsConfig; @property({ attribute: false }) public cameraManager?: CameraManager; @@ -35,20 +33,22 @@ export class FrigateCardPTZ extends LitElement { public forceVisibility?: boolean; protected _controller = new PTZController(this); + protected _actions = this._controller.getPTZActions(); + protected _actionPresence: PTZActionPresence | null = null; protected willUpdate(changedProps: PropertyValues): void { if (changedProps.has('config')) { this._controller.setConfig(this.config); } - if (changedProps.has('hass')) { - this._controller.setHASS(this.hass); - } if (changedProps.has('cameraManager') || changedProps.has('cameraID')) { this._controller.setCamera(this.cameraManager, this.cameraID); } if (changedProps.has('forceVisibility')) { this._controller.setForceVisibility(this.forceVisibility); } + if (changedProps.has('cameraID') || changedProps.has('cameraManager')) { + this._actionPresence = this._controller.hasUsefulAction(); + } } protected render(): TemplateResult | void { @@ -59,62 +59,48 @@ export class FrigateCardPTZ extends LitElement { const renderIcon = ( name: string, icon: string, - actions: Actions | null, + actions?: Actions | null, ): TemplateResult => { const classes = { [name]: true, disabled: !actions, }; - return html`) => - this._controller.handleAction(ev, actions)} - >`; + return actions + ? html`) => + this._controller.handleAction(ev, actions)} + >` + : html``; }; const config = this._controller.getConfig(); - const actionsZoomIn = this._controller.getPTZActions('zoom_in'); - const actionsZoomOut = this._controller.getPTZActions('zoom_out'); - const actionsHome = this._controller.getPTZActions('home'); - return html`
      - ${!config?.hide_pan_tilt + ${!config?.hide_pan_tilt && this._actionPresence?.pt ? html`
      - ${renderIcon( - 'right', - 'mdi:arrow-right', - this._controller.getPTZActions('right'), - )} - ${renderIcon( - 'left', - 'mdi:arrow-left', - this._controller.getPTZActions('left'), - )} - ${renderIcon('up', 'mdi:arrow-up', this._controller.getPTZActions('up'))} - ${renderIcon( - 'down', - 'mdi:arrow-down', - this._controller.getPTZActions('down'), - )} + ${renderIcon('right', 'mdi:arrow-right', this._actions.right)} + ${renderIcon('left', 'mdi:arrow-left', this._actions.left)} + ${renderIcon('up', 'mdi:arrow-up', this._actions.up)} + ${renderIcon('down', 'mdi:arrow-down', this._actions.down)}
      ` : ''} - ${!config?.hide_zoom && (actionsZoomIn || actionsZoomOut) + ${!config?.hide_zoom && this._actionPresence?.z ? html`
      - ${renderIcon('zoom_in', 'mdi:plus', actionsZoomIn)} - ${renderIcon('zoom_out', 'mdi:minus', actionsZoomOut)} + ${renderIcon('zoom_in', 'mdi:plus', this._actions.zoom_in)} + ${renderIcon('zoom_out', 'mdi:minus', this._actions.zoom_out)}
      ` : html``} - ${!config?.hide_home && actionsHome - ? html` -
      ${renderIcon('home', 'mdi:home', actionsHome)}
      - ` + ${!config?.hide_home && this._actionPresence?.home + ? html`
      + ${renderIcon('home', 'mdi:home', this._actions.home)} +
      ` : html``}
      `; } diff --git a/src/components/viewer.ts b/src/components/viewer.ts index 1d3b4694..d8deceda 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -12,8 +12,8 @@ import { ifDefined } from 'lit/directives/if-defined.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js'; import { CameraManager } from '../camera-manager/manager.js'; import { MediaGridSelected } from '../components-lib/media-grid-controller.js'; -import { ZoomDefault } from '../components-lib/zoom/types.js'; -import { handleZoomDefaultEvent } from '../components-lib/zoom/zoom-view-context.js'; +import { ZoomSettingsObserved } from '../components-lib/zoom/types.js'; +import { handleZoomSettingsObservedEvent } from '../components-lib/zoom/zoom-view-context.js'; import { dispatchMessageEvent, renderMessage, @@ -76,6 +76,7 @@ import { VideoContentType, ViewMedia } from '../view/media.js'; import { View } from '../view/view.js'; import type { EmblaCarouselPlugins } from './carousel.js'; import './next-prev-control.js'; +import './ptz'; import './surround.js'; import './title-control.js'; import { @@ -501,6 +502,13 @@ export class FrigateCardViewerCarousel extends LitElement { }} > + ${this.view + ? html` + ` + : ''}
      @@ -876,7 +884,7 @@ export class FrigateCardViewerProvider return this.viewerConfig?.zoomable ? html` + .defaultSettings=${guard([cameraConfig?.dimensions?.layout], () => cameraConfig?.dimensions?.layout ? { pan: cameraConfig.dimensions.layout.pan, @@ -884,11 +892,13 @@ export class FrigateCardViewerProvider } : undefined, )} - .config=${mediaID ? this.view?.context?.zoom?.[mediaID]?.zoom : undefined} + .settings=${mediaID + ? this.view?.context?.zoom?.[mediaID]?.requested + : undefined} @frigate-card:zoom:zoomed=${() => this.setControls(false)} @frigate-card:zoom:unzoomed=${() => this.setControls()} - @frigate-card:zoom:default=${(ev: CustomEvent) => - handleZoomDefaultEvent(this, ev, mediaID)} + @frigate-card:zoom:change=${(ev: CustomEvent) => + handleZoomSettingsObservedEvent(this, ev, mediaID)} > ${template} ` @@ -995,6 +1005,6 @@ declare global { 'frigate-card-viewer-carousel': FrigateCardViewerCarousel; 'frigate-card-viewer': FrigateCardViewer; 'frigate-card-viewer-grid': FrigateCardViewerGrid; - FRIGATE_CARD_VIEWER_PROVIDER: FrigateCardViewerProvider; + 'frigate-card-viewer-provider': FrigateCardViewerProvider; } } diff --git a/src/components/views.ts b/src/components/views.ts index f5d08c0e..eefb89bc 100644 --- a/src/components/views.ts +++ b/src/components/views.ts @@ -171,7 +171,7 @@ export class FrigateCardViews extends LitElement { .view=${this.view} .hass=${this.hass} .cameraConfig=${cameraConfig} - .supportZoom=${true} + .cameraManager=${this.cameraManager} > ` : ``} diff --git a/src/components/zoomer.ts b/src/components/zoomer.ts index 7c690060..9a44c838 100644 --- a/src/components/zoomer.ts +++ b/src/components/zoomer.ts @@ -7,19 +7,19 @@ import { TemplateResult, } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import { ZoomConfig } from '../components-lib/zoom/types.js'; import { ZoomController } from '../components-lib/zoom/zoom-controller.js'; import { setOrRemoveAttribute } from '../utils/basic.js'; +import { PartialZoomSettings } from '../components-lib/zoom/types.js'; @customElement('frigate-card-zoomer') export class FrigateCardZoomer extends LitElement { protected _zoom: ZoomController | null = null; @property({ attribute: false }) - public defaultConfig?: ZoomConfig; + public defaultSettings?: PartialZoomSettings; @property({ attribute: false }) - public config?: ZoomConfig | null; + public settings?: PartialZoomSettings | null; @state() protected _zoomed = false; @@ -48,19 +48,19 @@ export class FrigateCardZoomer extends LitElement { } if (this._zoom) { - if (changedProps.has('defaultConfig')) { - this._zoom.setDefaultConfig(this.defaultConfig ?? null); + if (changedProps.has('defaultSettings')) { + this._zoom.setDefaultSettings(this.defaultSettings ?? null); } // If config is null, make no change to the zoom. - if (changedProps.has('config') && this.config) { - this._zoom.setConfig(this.config); + if (changedProps.has('settings') && this.settings) { + this._zoom.setSettings(this.settings); } } else { // Ensure that the configuration will be set before activation (vs // activating in `connectedCallback`). this._zoom = new ZoomController(this, { - config: this.config, - defaultConfig: this.defaultConfig, + config: this.settings, + defaultConfig: this.defaultSettings, }); this._zoom.activate(); } diff --git a/src/config/keyboard-shortcuts.ts b/src/config/keyboard-shortcuts.ts new file mode 100644 index 00000000..3c43ea20 --- /dev/null +++ b/src/config/keyboard-shortcuts.ts @@ -0,0 +1,47 @@ +import { z } from 'zod'; + +const keyboardShortcut = z.object({ + key: z.string(), + ctrl: z.boolean().optional(), + shift: z.boolean().optional(), + alt: z.boolean().optional(), + meta: z.boolean().optional(), +}); +export type KeyboardShortcut = z.infer; + +export const keyboardShortcutsDefault = { + enabled: true, + ptz_left: { key: 'ArrowLeft' }, + ptz_right: { key: 'ArrowRight' }, + ptz_up: { key: 'ArrowUp' }, + ptz_down: { key: 'ArrowDown' }, + ptz_zoom_in: { key: '+' }, + ptz_zoom_out: { key: '-' }, + ptz_home: { key: 'h' }, +}; + +export const keyboardShortcutsSchema = z.object({ + enabled: z.boolean().default(keyboardShortcutsDefault.enabled), + ptz_left: keyboardShortcut.nullable().default(keyboardShortcutsDefault.ptz_left), + ptz_right: keyboardShortcut.nullable().default(keyboardShortcutsDefault.ptz_right), + ptz_up: keyboardShortcut.nullable().default(keyboardShortcutsDefault.ptz_up), + ptz_down: keyboardShortcut.nullable().default(keyboardShortcutsDefault.ptz_down), + ptz_zoom_in: keyboardShortcut.nullable().default(keyboardShortcutsDefault.ptz_zoom_in), + ptz_zoom_out: keyboardShortcut + .nullable() + .default(keyboardShortcutsDefault.ptz_zoom_out), + ptz_home: keyboardShortcut.nullable().default(keyboardShortcutsDefault.ptz_home), +}); +export type KeyboardShortcuts = z.infer; + + +const KEYBOARD_SHORTCUT_PTZ_NAMES = [ + 'ptz_down', + 'ptz_home', + 'ptz_left', + 'ptz_right', + 'ptz_up', + 'ptz_zoom_in', + 'ptz_zoom_out', +] as const; +export type PTZKeyboardShortcutName = (typeof KEYBOARD_SHORTCUT_PTZ_NAMES)[number]; diff --git a/src/config/management.ts b/src/config/management.ts index 454826ee..a5a0c39e 100644 --- a/src/config/management.ts +++ b/src/config/management.ts @@ -14,6 +14,7 @@ import { CONF_CAMERAS_GLOBAL_DIMENSIONS_LAYOUT, CONF_CAMERAS_GLOBAL_IMAGE, CONF_CAMERAS_GLOBAL_JSMPEG, + CONF_CAMERAS_GLOBAL_PTZ, CONF_CAMERAS_GLOBAL_WEBRTC_CARD, CONF_ELEMENTS, CONF_LIVE_CONTROLS_THUMBNAILS_EVENTS_MEDIA_TYPE, @@ -545,6 +546,116 @@ const upgradePTZElementsToLive = function (): (data: unknown) => boolean { }; }; +const ptzActionsToCamerasGlobalTransform = (data: unknown): unknown => { + if (typeof data !== 'object' || !data) { + return undefined; + } + + const NON_PRESET_DATA_KEYS = [ + 'data_left', + 'data_right', + 'data_up', + 'data_down', + 'data_zoom_in', + 'data_zoom_out', + 'service', + ]; + + const NON_PRESET_ACTION_KEYS = [ + // 'actions_' will overwrite 'data_*' if there's duplication. + 'actions_left', + 'actions_right', + 'actions_up', + 'actions_down', + 'actions_zoom_in', + 'actions_zoom_out', + ]; + + const PRESET_TRANSFORM_KEYS = ['data_home', 'actions_home']; + const TRANSFORM_KEYS = [ + ...NON_PRESET_DATA_KEYS, + ...NON_PRESET_ACTION_KEYS, + ...PRESET_TRANSFORM_KEYS, + ]; + + const keys = Object.keys(data); + const hasTransformable = keys.some((key) => TRANSFORM_KEYS.includes(key)); + if (!hasTransformable) { + return undefined; + } + + const output = {}; + + NON_PRESET_DATA_KEYS.filter((key) => key in data).reduce((obj, key) => { + obj[key] = data[key]; + return obj; + }, output); + + NON_PRESET_ACTION_KEYS.filter((key) => key in data).reduce((obj, key) => { + if (typeof data[key] === 'object' && 'tap_action' in data[key]) { + obj[key] = data[key]['tap_action']; + } + return obj; + }, output); + + const createPresets = () => { + output['presets'] = + 'presets' in data && typeof data['presets'] === 'object' && !!data['presets'] + ? data['presets'] + : {}; + }; + + if ( + 'actions_home' in data && + typeof data['actions_home'] === 'object' && + data['actions_home'] && + 'tap_action' in data['actions_home'] + ) { + createPresets(); + output['presets']['home'] = data['actions_home']['tap_action']; + } else if ( + 'data_home' in data && + typeof data['data_home'] === 'object' && + data['data_home'] && + typeof data['service'] === 'string' + ) { + createPresets(); + output['presets']['service'] = data['service']; + output['presets']['data_home'] = data['data_home']; + } + + return output; +}; + +const ptzControlSettingsTransform = (data: unknown): unknown => { + if (typeof data !== 'object' || !data) { + return data; + } + + const TRANSFORM_KEYS = [ + 'mode', + 'position', + 'orientation', + 'hide_pan_tilt', + 'hide_zoom', + 'hide_home', + 'style', + ]; + + const keys = Object.keys(data); + const hasSomethingToFilter = keys.some((key) => !TRANSFORM_KEYS.includes(key)); + if (!hasSomethingToFilter) { + return undefined; + } + + return keys + .filter((key) => TRANSFORM_KEYS.includes(key)) + .reduce((obj, key) => { + obj[key] = data[key]; + return obj; + }, {}); +}; + const UPGRADES = [ // v4.0.0 -> v4.1.0 upgradeArrayOfObjects( @@ -681,7 +792,7 @@ const UPGRADES = [ upgradeArrayOfObjects( CONF_CAMERAS, upgradeMoveToWithOverrides('hide', 'capabilities', { - transform: (val) => (val === true ? { disable_except: 'substream' } : null), + transform: (val) => (val === true ? { disable_except: ['substream'] } : null), }), ), upgradeMoveToWithOverrides('performance.profile', CONF_PROFILES, { @@ -689,4 +800,9 @@ const UPGRADES = [ transform: (val) => (val === 'low' ? ['low-performance'] : null), }), upgradeArrayOfObjects(CONF_OVERRIDES, upgradeMoveTo('overrides', 'merge')), + upgradeMoveToWithOverrides('live.controls.ptz', CONF_CAMERAS_GLOBAL_PTZ, { + transform: ptzActionsToCamerasGlobalTransform, + keepOriginal: true, + }), + upgradeWithOverrides('live.controls.ptz', ptzControlSettingsTransform), ]; diff --git a/src/config/ptz.ts b/src/config/ptz.ts new file mode 100644 index 00000000..3dd77e98 --- /dev/null +++ b/src/config/ptz.ts @@ -0,0 +1,12 @@ +export const PTZ_PAN_TILT_ACTIONS = ['left', 'right', 'up', 'down'] as const; +export const PTZ_ZOOM_ACTIONS = ['zoom_in', 'zoom_out'] as const; +const PTZ_BASE_ACTIONS = [...PTZ_PAN_TILT_ACTIONS, ...PTZ_ZOOM_ACTIONS] as const; +export type PTZBaseAction = (typeof PTZ_BASE_ACTIONS)[number]; + +// PTZ actions as used by the PTZ control (includes a 'home' button). +const PTZ_CONTROL_ACTIONS = [...PTZ_BASE_ACTIONS, 'home'] as const; +export type PTZControlAction = (typeof PTZ_CONTROL_ACTIONS)[number]; + +// PTZ actions as used by the camera manager (includes generic presets). +export const PTZ_ACTIONS = [...PTZ_BASE_ACTIONS, 'preset'] as const; +export type PTZAction = (typeof PTZ_ACTIONS)[number]; diff --git a/src/config/types.ts b/src/config/types.ts index 6f2d6dd3..fdf7b372 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -11,6 +11,11 @@ import { z } from 'zod'; import { MEDIA_CHUNK_SIZE_DEFAULT, MEDIA_CHUNK_SIZE_MAX } from '../const.js'; import { capabilityKeys } from '../types.js'; import { deepRemoveDefaults } from '../utils/zod.js'; +import { + keyboardShortcutsDefault, + keyboardShortcutsSchema, +} from './keyboard-shortcuts.js'; +import { PTZ_ACTIONS } from './ptz'; // ************************************************************************* // Common Configuration Constants @@ -23,6 +28,7 @@ const FRIGATE_MENU_PRIORITY_DEFAULT = 50; export const FRIGATE_MENU_PRIORITY_MAX = 100; export const FRIGATE_CARD_VIEWS_USER_SPECIFIED = [ + 'diagnostics', 'live', 'clip', 'clips', @@ -67,18 +73,8 @@ export const MEDIA_MUTE_CONDITIONS = [ ] as const; export type AutoMuteCondition = (typeof MEDIA_MUTE_CONDITIONS)[number]; -const PTZ_BASE_ACTIONS = ['left', 'right', 'up', 'down', 'zoom_in', 'zoom_out'] as const; - -// PTZ actions as used by the PTZ control (includes a 'home' button). -export const PTZ_CONTROL_ACTIONS = [...PTZ_BASE_ACTIONS, 'home'] as const; -export type PTZControlAction = (typeof PTZ_CONTROL_ACTIONS)[number]; - -// PTZ actions as used by the camera manager (includes generic presets). -const PTZ_ACTIONS = [...PTZ_BASE_ACTIONS, 'preset'] as const; -export type PTZAction = (typeof PTZ_ACTIONS)[number]; - -const PTZ_PHASES = ['start', 'stop'] as const; -export type PTZPhase = (typeof PTZ_PHASES)[number]; +const ACTION_PHASES = ['start', 'stop'] as const; +export type ActionPhase = (typeof ACTION_PHASES)[number]; const CAMERA_TRIGGER_EVENT_TYPES = [ // An event whether or not it has any media yet associated with it. @@ -90,15 +86,20 @@ const CAMERA_TRIGGER_EVENT_TYPES = [ ] as const; export type CameraTriggerEventType = (typeof CAMERA_TRIGGER_EVENT_TYPES)[number]; +const cardIDRegex = /^[-\w]+$/; + // ************************************************************************* // Pan / Zoom // ************************************************************************* +export const ZOOM_MIN = 1; +export const ZOOM_MAX = 10; + const panSchema = z.object({ x: z.number().min(0).max(100).optional(), y: z.number().min(0).max(100).optional(), }); -const zoomSchema = z.number().min(1).max(10); +const zoomSchema = z.number().min(ZOOM_MIN).max(ZOOM_MAX); // ************************************************************************* // View Display Mode @@ -224,7 +225,7 @@ export const frigateCardCustomActionsBaseSchema = customActionSchema.extend({ // Card this command is intended for. card_id: z .string() - .regex(/^\w+$/, 'card_id parameter can only contain [a-z][A-Z][0-9_]') + .regex(cardIDRegex, 'card_id parameter can only contain [a-z][A-Z][0-9_]-') .optional(), }); @@ -235,7 +236,6 @@ export const frigateCardCustomActionsBaseSchema = customActionSchema.extend({ const FRIGATE_CARD_GENERAL_ACTIONS = [ 'camera_ui', 'default', - 'diagnostics', 'download', 'expand', 'fullscreen', @@ -252,70 +252,120 @@ const FRIGATE_CARD_GENERAL_ACTIONS = [ ] as const; export type FrigateCardGeneralAction = (typeof FRIGATE_CARD_GENERAL_ACTIONS)[number]; -const frigateCardViewActionSchema = frigateCardCustomActionsBaseSchema.extend({ +const viewActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ frigate_card_action: z.enum(FRIGATE_CARD_VIEWS_USER_SPECIFIED), }); -export type FrigateCardViewAction = z.infer; +export type ViewActionConfig = z.infer; -const frigateCardGeneralActionSchema = frigateCardCustomActionsBaseSchema.extend({ +const generalActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ frigate_card_action: z.enum(FRIGATE_CARD_GENERAL_ACTIONS), }); +export type GeneralActionConfig = z.infer; -const frigateCardCameraSelectActionSchema = frigateCardCustomActionsBaseSchema.extend({ +const cameraSelectActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ frigate_card_action: z.literal('camera_select'), camera: z.string().optional(), triggered: z.boolean().optional(), }); +export type CameraSelectActionConfig = z.infer; -const frigateCardLiveDependencySelectActionSchema = - frigateCardCustomActionsBaseSchema.extend({ - frigate_card_action: z.literal('live_substream_select'), - camera: z.string(), - }); +const substreamSelectActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ + frigate_card_action: z.literal('live_substream_select'), + camera: z.string(), +}); +export type SubstreamSelectActionConfig = z.infer< + typeof substreamSelectActionConfigSchema +>; -const frigateCardMediaPlayerActionSchema = frigateCardCustomActionsBaseSchema.extend({ +const mediaPlayerActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ frigate_card_action: z.literal('media_player'), media_player: z.string(), media_player_action: z.enum(['play', 'stop']), }); +export type MediaPlayerActionConfig = z.infer; -const frigateCardViewDisplayModeActionSchema = frigateCardCustomActionsBaseSchema.extend( - { - frigate_card_action: z.literal('display_mode_select'), - display_mode: viewDisplayModeSchema, - }, -); +const viewDisplayModeActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ + frigate_card_action: z.literal('display_mode_select'), + display_mode: viewDisplayModeSchema, +}); +export type DisplayModeActionConfig = z.infer; -const frigateCardPTZActionSchema = frigateCardCustomActionsBaseSchema.extend({ +const ptzActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ frigate_card_action: z.literal('ptz'), - ptz_action: z.enum(PTZ_ACTIONS), - ptz_phase: z.enum(PTZ_PHASES).optional(), + camera: z.string().optional(), + ptz_action: z.enum(PTZ_ACTIONS).optional(), + ptz_phase: z.enum(ACTION_PHASES).optional(), ptz_preset: z.string().optional(), }); -export type FrigateCardPTZAction = z.infer; +export type PTZActionConfig = z.infer; -const frigateCardShowPTZActionSchema = frigateCardCustomActionsBaseSchema.extend({ - frigate_card_action: z.literal('show_ptz'), - show_ptz: z.boolean(), +const ptzDigitalActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ + frigate_card_action: z.literal('ptz_digital'), + target_id: z.string().optional(), + absolute: z + .object({ + zoom: zoomSchema.optional(), + pan: panSchema.optional(), + }) + .optional(), + ptz_action: z.enum(PTZ_ACTIONS).optional(), + ptz_phase: z.enum(ACTION_PHASES).optional(), }); +export type PTZDigitialActionConfig = z.infer; -const frigateCardChangeZoomActionSchema = frigateCardCustomActionsBaseSchema.extend({ - frigate_card_action: z.literal('change_zoom'), - target_id: z.string(), - zoom: zoomSchema.optional(), - pan: panSchema.optional(), +const ptzMultiActionSchema = frigateCardCustomActionsBaseSchema.extend({ + frigate_card_action: z.literal('ptz_multi'), + target_id: z.string().optional(), + + ptz_action: z.enum(PTZ_ACTIONS).optional(), + ptz_phase: z.enum(ACTION_PHASES).optional(), + ptz_preset: z.string().optional(), }); +export type PTZMultiActionConfig = z.infer; + +const ptzControlsActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ + frigate_card_action: z.literal('ptz_controls'), + enabled: z.boolean(), +}); +export type PTZControlsActionConfig = z.infer; + +const timeDeltaSchema = z.object({ + ms: z.number().optional(), + s: z.number().optional(), + m: z.number().optional(), + h: z.number().optional(), +}); +export type TimeDelta = z.infer; + +const sleepActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ + frigate_card_action: z.literal('sleep'), + duration: timeDeltaSchema.optional().default({ s: 1 }), +}); +export type SleepActionConfig = z.infer; + +const LOG_ACTIONS_LEVELS = ['debug', 'info', 'warn', 'error'] as const; +export type LogActionLevel = (typeof LOG_ACTIONS_LEVELS)[number]; + +const logActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ + frigate_card_action: z.literal('log'), + message: z.string(), + level: z.enum(LOG_ACTIONS_LEVELS).default('info'), +}); +export type LogActionConfig = z.infer; export const frigateCardCustomActionSchema = z.union([ - frigateCardCameraSelectActionSchema, - frigateCardChangeZoomActionSchema, - frigateCardGeneralActionSchema, - frigateCardLiveDependencySelectActionSchema, - frigateCardMediaPlayerActionSchema, - frigateCardPTZActionSchema, - frigateCardShowPTZActionSchema, - frigateCardViewActionSchema, - frigateCardViewDisplayModeActionSchema, + cameraSelectActionConfigSchema, + generalActionConfigSchema, + substreamSelectActionConfigSchema, + logActionConfigSchema, + mediaPlayerActionConfigSchema, + ptzActionConfigSchema, + ptzDigitalActionConfigSchema, + ptzMultiActionSchema, + ptzControlsActionConfigSchema, + viewActionConfigSchema, + viewDisplayModeActionConfigSchema, + sleepActionConfigSchema, ]); export type FrigateCardCustomAction = z.infer; @@ -572,6 +622,15 @@ const microphoneConditionSchema = z.object({ connected: z.boolean().optional(), muted: z.boolean().optional(), }); +const keyConditionSchema = z.object({ + condition: z.literal('key'), + key: z.string(), + state: z.enum(['down', 'up']).optional(), + ctrl: z.boolean().optional(), + shift: z.boolean().optional(), + alt: z.boolean().optional(), + meta: z.boolean().optional(), +}); export const frigateCardConditionSchema = z.discriminatedUnion('condition', [ // Stock conditions: @@ -590,6 +649,7 @@ export const frigateCardConditionSchema = z.discriminatedUnion('condition', [ triggeredConditionSchema, interactionConditionSchema, microphoneConditionSchema, + keyConditionSchema, ]); export type FrigateCardCondition = z.infer; @@ -664,6 +724,129 @@ const aspectRatioSchema = z .transform((input) => input.split(/[:\/]/).map((d) => Number(d))), ); +// ************************************************************************* +// PTZ Configuration +// ************************************************************************* + +const ptzCameraConfigDefaults = { + r2c_delay_between_calls_seconds: 0.5, + c2r_delay_between_calls_seconds: 0.2, +}; + +// To avoid lots of YAML duplication, provide an easy way to just specify the +// service data as actions for each PTZ action, and it will be preprocessed +// into the full form. This also provides compatability with the AlexIT/WebRTC +// PTZ configuration. +const dataPTZFormatToFullFormat = function ( + suffix: string, +): (data: unknown) => unknown { + return (data) => { + if (!data || typeof data !== 'object' || !data['service']) { + return data; + } + const out = { ...data }; + Object.keys(data).forEach((key) => { + const match = key.match(/^data_(.+)$/); + const name = match?.[1]; + if (name && !(`${suffix}${name}` in data)) { + out[`${suffix}${name}`] = { + action: 'call-service', + service: data['service'], + data: data[key], + }; + delete out[key]; + delete out['service']; + } + }); + return out; + }; +}; + +const ptzCameraConfigSchema = z.preprocess( + dataPTZFormatToFullFormat('actions_'), + z + .object({ + actions_left: callServiceActionSchema.optional(), + actions_left_start: callServiceActionSchema.optional(), + actions_left_stop: callServiceActionSchema.optional(), + + actions_right: callServiceActionSchema.optional(), + actions_right_start: callServiceActionSchema.optional(), + actions_right_stop: callServiceActionSchema.optional(), + + actions_up: callServiceActionSchema.optional(), + actions_up_start: callServiceActionSchema.optional(), + actions_up_stop: callServiceActionSchema.optional(), + + actions_down: callServiceActionSchema.optional(), + actions_down_start: callServiceActionSchema.optional(), + actions_down_stop: callServiceActionSchema.optional(), + + actions_zoom_in: callServiceActionSchema.optional(), + actions_zoom_in_start: callServiceActionSchema.optional(), + actions_zoom_in_stop: callServiceActionSchema.optional(), + + actions_zoom_out: callServiceActionSchema.optional(), + actions_zoom_out_start: callServiceActionSchema.optional(), + actions_zoom_out_stop: callServiceActionSchema.optional(), + + // The number of seconds between subsequent relative calls when converting a + // relative request into a continuous request. + r2c_delay_between_calls_seconds: z + .number() + .default(ptzCameraConfigDefaults.r2c_delay_between_calls_seconds), + + // The number of seconds between the start/stop call when converting a + // continuous request into a relative request. + c2r_delay_between_calls_seconds: z + .number() + .default(ptzCameraConfigDefaults.c2r_delay_between_calls_seconds), + + presets: z + .preprocess( + dataPTZFormatToFullFormat(''), + z.union([ + z.record(callServiceActionSchema), + + // This is used by the data_ style of action. + z.object({ service: z.string().optional() }), + ]), + ) + .optional(), + + // This is used by the data_ style of action. + service: z.string().optional(), + }) + // We allow passthrough as there may be user-configured presets as "actions_" . + .passthrough(), +); + +const ptzControlsDefaults = { + orientation: 'horizontal' as const, + mode: 'auto' as const, + hide_pan_tilt: false, + hide_zoom: false, + hide_home: false, + position: 'bottom-right' as const, +}; + +export const ptzControlsConfigSchema = z.object({ + mode: z.enum(['off', 'auto', 'on']).default(ptzControlsDefaults.mode), + position: z + .enum(['top-left', 'top-right', 'bottom-left', 'bottom-right']) + .default(ptzControlsDefaults.position), + orientation: z + .enum(['vertical', 'horizontal']) + .default(ptzControlsDefaults.orientation), + + hide_pan_tilt: z.boolean().default(ptzControlsDefaults.hide_pan_tilt), + hide_zoom: z.boolean().default(ptzControlsDefaults.hide_zoom), + hide_home: z.boolean().default(ptzControlsDefaults.hide_home), + + style: z.object({}).passthrough().optional(), +}); +export type PTZControlsConfig = z.infer; + // ************************************************************************* // Image Configuration // Image config base options are used both for the `image` live provider and the @@ -683,13 +866,15 @@ const IMAGE_MODES = ['screensaver', 'camera', 'url'] as const; const imageConfigDefault = { mode: 'url' as const, zoomable: true, + controls: { + ptz: ptzControlsDefaults, + }, ...imageBaseConfigDefault, }; const imageConfigSchema = imageBaseConfigSchema .extend({ mode: z.enum(IMAGE_MODES).default(imageConfigDefault.mode), - zoomable: z.boolean().default(imageConfigDefault.zoomable), }) .merge(actionsSchema) .default(imageConfigDefault); @@ -929,70 +1114,6 @@ const jsmpegConfigSchema = z.object({ .optional(), }); -const frigateCardPTZActions = z.object({ - actions_left: actionsBaseSchema.optional(), - actions_right: actionsBaseSchema.optional(), - actions_up: actionsBaseSchema.optional(), - actions_down: actionsBaseSchema.optional(), - actions_zoom_in: actionsBaseSchema.optional(), - actions_zoom_out: actionsBaseSchema.optional(), - actions_home: actionsBaseSchema.optional(), -}); -export type FrigateCardPTZActions = z.infer; - -const livePTZControlsDefaults = { - orientation: 'horizontal' as const, - mode: 'on' as const, - hide_pan_tilt: false, - hide_zoom: false, - hide_home: false, - position: 'bottom-right' as const, -}; - -export const frigateCardPTZSchema = z.preprocess( - // To avoid lots of YAML duplication, provide an easy way to just specify the - // service data as actions for each PTZ icon, and it will be preprocessed into - // the full form. This also provides compatability with the AlexIT/WebRTC PTZ - // configuration. - (data) => { - if (!data || typeof data !== 'object' || !data['service']) { - return data; - } - const out = { ...data }; - PTZ_CONTROL_ACTIONS.forEach((name) => { - if (`data_${name}` in data && !(`actions_${name}` in data)) { - out[`actions_${name}`] = { - tap_action: { - action: 'call-service', - service: data['service'], - data: data[`data_${name}`], - }, - }; - delete out[`data_${name}`]; - } - }); - return out; - }, - frigateCardPTZActions.extend({ - mode: z.enum(['off', 'on']).default(livePTZControlsDefaults.mode), - position: z - .enum(['top-left', 'top-right', 'bottom-left', 'bottom-right']) - .default(livePTZControlsDefaults.position), - - orientation: z - .enum(['vertical', 'horizontal']) - .default(livePTZControlsDefaults.orientation), - - hide_pan_tilt: z.boolean().default(livePTZControlsDefaults.hide_pan_tilt), - hide_zoom: z.boolean().default(livePTZControlsDefaults.hide_zoom), - hide_home: z.boolean().default(livePTZControlsDefaults.hide_home), - - service: z.string().optional(), - style: z.object({}).passthrough().optional(), - }), -); -export type FrigateCardPTZConfig = z.infer; - const liveThumbnailControlsDefaults = { ...thumbnailControlsDefaults, media_type: 'events' as const, @@ -1018,7 +1139,7 @@ const liveConfigDefault = { size: 48, style: 'chevrons' as const, }, - ptz: livePTZControlsDefaults, + ptz: ptzControlsDefaults, thumbnails: liveThumbnailControlsDefaults, timeline: miniTimelineConfigDefault, }, @@ -1068,7 +1189,7 @@ const liveConfigSchema = z ), }) .default(liveConfigDefault.controls.next_previous), - ptz: frigateCardPTZSchema.default(liveConfigDefault.controls.ptz), + ptz: ptzControlsConfigSchema.default(liveConfigDefault.controls.ptz), thumbnails: livethumbnailsControlSchema.default( liveConfigDefault.controls.thumbnails, ), @@ -1154,6 +1275,7 @@ const cameraConfigDefault = { file_pattern: '%H-%M-%S' as const, }, }, + ptz: ptzCameraConfigDefaults, triggers: { motion: false, occupancy: false, @@ -1251,6 +1373,8 @@ export const cameraConfigSchema = z cast: castSchema.optional(), + ptz: ptzCameraConfigSchema.default(cameraConfigDefault.ptz), + dimensions: z .object({ aspect_ratio: aspectRatioSchema.optional(), @@ -1289,6 +1413,7 @@ const viewConfigDefault = { }, untrigger_seconds: 0, }, + keyboard_shortcuts: keyboardShortcutsDefault, }; export const triggersSchema = z.object({ @@ -1335,6 +1460,9 @@ const viewConfigSchema = z render_entities: z.string().array().optional(), dark_mode: z.enum(['on', 'off', 'auto']).optional(), triggers: triggersSchema.default(viewConfigDefault.triggers), + keyboard_shortcuts: keyboardShortcutsSchema.default( + viewConfigDefault.keyboard_shortcuts, + ), }) .merge(actionsSchema) .default(viewConfigDefault); @@ -1371,7 +1499,7 @@ const menuConfigDefault = { camera_ui: visibleButtonDefault, cameras: visibleButtonDefault, clips: visibleButtonDefault, - default_zoom: visibleButtonDefault, + ptz_home: visibleButtonDefault, display_mode: visibleButtonDefault, download: visibleButtonDefault, expand: hiddenButtonDefault, @@ -1386,7 +1514,7 @@ const menuConfigDefault = { }, mute: hiddenButtonDefault, play: hiddenButtonDefault, - ptz: hiddenButtonDefault, + ptz_controls: hiddenButtonDefault, recordings: hiddenButtonDefault, screenshot: hiddenButtonDefault, snapshots: visibleButtonDefault, @@ -1417,8 +1545,8 @@ export const menuConfigSchema = z camera_ui: visibleButtonSchema.default(menuConfigDefault.buttons.camera_ui), cameras: visibleButtonSchema.default(menuConfigDefault.buttons.cameras), clips: visibleButtonSchema.default(menuConfigDefault.buttons.clips), - default_zoom: visibleButtonSchema.default( - menuConfigDefault.buttons.default_zoom, + ptz_home: visibleButtonSchema.default( + menuConfigDefault.buttons.ptz_home, ), display_mode: visibleButtonSchema.default( menuConfigDefault.buttons.display_mode, @@ -1441,7 +1569,7 @@ export const menuConfigSchema = z .default(menuConfigDefault.buttons.microphone), mute: hiddenButtonSchema.default(menuConfigDefault.buttons.mute), play: hiddenButtonSchema.default(menuConfigDefault.buttons.play), - ptz: hiddenButtonSchema.default(menuConfigDefault.buttons.ptz), + ptz_controls: hiddenButtonSchema.default(menuConfigDefault.buttons.ptz_controls), recordings: hiddenButtonSchema.default(menuConfigDefault.buttons.recordings), screenshot: hiddenButtonSchema.default(menuConfigDefault.buttons.screenshot), snapshots: visibleButtonSchema.default(menuConfigDefault.buttons.snapshots), @@ -1477,6 +1605,10 @@ const viewerConfigDefault = { }, thumbnails: thumbnailControlsDefaults, timeline: miniTimelineConfigDefault, + ptz: { + ...ptzControlsDefaults, + mode: 'off' as const, + } }, }; @@ -1526,6 +1658,10 @@ const viewerConfigSchema = z next_previous: viewerNextPreviousControlConfigSchema.default( viewerConfigDefault.controls.next_previous, ), + ptz: ptzControlsConfigSchema.extend({ + // The media_viewer ptz has no 'auto' mode. + mode: z.enum(['off', 'on']).default(viewerConfigDefault.controls.ptz.mode), + }).default(viewerConfigDefault.controls.ptz), thumbnails: thumbnailsControlSchema.default( viewerConfigDefault.controls.thumbnails, ), @@ -1634,8 +1770,7 @@ const automationSchema = z.object({ }); export type Automation = z.infer; -const automationsSchema = automationSchema.array().optional(); -export type Automations = z.infer; +const automationsSchema = automationSchema.array(); // ************************************************************************* // Performance Configuration @@ -1727,7 +1862,7 @@ export const frigateCardConfigSchema = z.object({ timeline: timelineConfigSchema, performance: performanceConfigSchema, debug: debugConfigSchema, - automations: automationsSchema, + automations: automationsSchema.optional(), profiles: profilesSchema, @@ -1739,7 +1874,7 @@ export const frigateCardConfigSchema = z.object({ // Card ID (used for query string commands). Restrict contents to only values // that be easily used in a URL. - card_id: z.string().regex(/^\w+$/).optional(), + card_id: z.string().regex(cardIDRegex).optional(), // Stock lovelace card config. type: z.string(), diff --git a/src/const.ts b/src/const.ts index b3d9c9ec..0593f1e5 100644 --- a/src/const.ts +++ b/src/const.ts @@ -57,7 +57,7 @@ export const CONF_CAMERAS_ARRAY_DEPENDENCIES_ALL_CAMERAS = `${CONF_CAMERAS}.#.dependencies.all_cameras` as const; export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_FIT = `${CONF_CAMERAS}.#.dimensions.layout.fit` as const; - export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_PAN_X = +export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_PAN_X = `${CONF_CAMERAS}.#.dimensions.layout.pan.x` as const; export const CONF_CAMERAS_ARRAY_DIMENSIONS_LAYOUT_PAN_Y = `${CONF_CAMERAS}.#.dimensions.layout.pan.y` as const; @@ -97,6 +97,7 @@ export const CONF_CAMERAS_GLOBAL_IMAGE_REFRESH_SECONDS = `${CONF_CAMERAS_GLOBAL}.image.refresh_seconds` as const; export const CONF_CAMERAS_GLOBAL_DIMENSIONS_LAYOUT = `${CONF_CAMERAS_GLOBAL}.dimensions.layout` as const; +export const CONF_CAMERAS_GLOBAL_PTZ = `${CONF_CAMERAS_GLOBAL}.ptz` as const; export const CONF_ELEMENTS = 'elements' as const; @@ -105,6 +106,23 @@ export const CONF_VIEW_CAMERA_SELECT = `${CONF_VIEW}.camera_select` as const; export const CONF_VIEW_DARK_MODE = `${CONF_VIEW}.dark_mode` as const; export const CONF_VIEW_DEFAULT = `${CONF_VIEW}.default` as const; export const CONF_VIEW_INTERACTION_SECONDS = `${CONF_VIEW}.interaction_seconds` as const; +export const CONF_VIEW_KEYBOARD_SHORTCUTS = `${CONF_VIEW}.keyboard_shortcuts` as const; +export const CONF_VIEW_KEYBOARD_SHORTCUTS_ENABLED = + `${CONF_VIEW}.keyboard_shortcuts.enabled` as const; +export const CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_LEFT = + `${CONF_VIEW_KEYBOARD_SHORTCUTS}.ptz_left` as const; +export const CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_RIGHT = + `${CONF_VIEW_KEYBOARD_SHORTCUTS}.ptz_right` as const; +export const CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_UP = + `${CONF_VIEW_KEYBOARD_SHORTCUTS}.ptz_up` as const; +export const CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_DOWN = + `${CONF_VIEW_KEYBOARD_SHORTCUTS}.ptz_down` as const; +export const CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_ZOOM_IN = + `${CONF_VIEW_KEYBOARD_SHORTCUTS}.ptz_zoom_in` as const; +export const CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_ZOOM_OUT = + `${CONF_VIEW_KEYBOARD_SHORTCUTS}.ptz_zoom_out` as const; +export const CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_HOME = + `${CONF_VIEW_KEYBOARD_SHORTCUTS}.ptz_home` as const; export const CONF_VIEW_UPDATE_CYCLE_CAMERA = `${CONF_VIEW}.update_cycle_camera` as const; export const CONF_VIEW_UPDATE_FORCE = `${CONF_VIEW}.update_force` as const; export const CONF_VIEW_UPDATE_SECONDS = `${CONF_VIEW}.update_seconds` as const; diff --git a/src/declarations.d.ts b/src/declarations.d.ts index 9fd8e18c..6563f776 100644 --- a/src/declarations.d.ts +++ b/src/declarations.d.ts @@ -5,3 +5,7 @@ declare module 'view' { // eslint-disable-next-line @typescript-eslint/no-empty-interface interface ViewContext {} } +declare module 'action' { + // eslint-disable-next-line @typescript-eslint/no-empty-interface + interface ActionContext {} +} diff --git a/src/editor.ts b/src/editor.ts index f79390e8..2c378b42 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -192,6 +192,15 @@ import { CONF_VIEW_DARK_MODE, CONF_VIEW_DEFAULT, CONF_VIEW_INTERACTION_SECONDS, + CONF_VIEW_KEYBOARD_SHORTCUTS, + CONF_VIEW_KEYBOARD_SHORTCUTS_ENABLED, + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_DOWN, + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_HOME, + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_LEFT, + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_RIGHT, + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_UP, + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_ZOOM_IN, + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_ZOOM_OUT, CONF_VIEW_RESET_AFTER_INTERACTION, CONF_VIEW_TRIGGERS, CONF_VIEW_TRIGGERS_ACTIONS, @@ -215,6 +224,8 @@ import { getEntityTitle, sideLoadHomeAssistantElements, } from './utils/ha'; +import './components/key-assigner.js'; +import { KeyboardShortcut } from './config/keyboard-shortcuts.js'; const MENU_BUTTONS = 'buttons'; const MENU_CAMERAS = 'cameras'; @@ -251,6 +262,7 @@ const MENU_OPTIONS = 'options'; const MENU_PERFORMANCE_FEATURES = 'performance.features'; const MENU_PERFORMANCE_STYLE = 'performance.style'; const MENU_TIMELINE_CONTROLS_THUMBNAILS = 'timeline.controls.thumbnails'; +const MENU_VIEW_KEYBOARD_SHORTCUTS = 'view.keyboard_shortcuts'; const MENU_VIEW_TRIGGERS = 'view.triggers'; const MENU_VIEW_TRIGGERS_ACTIONS = 'view.triggers.actions'; @@ -1111,6 +1123,60 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ); } + protected _renderKeyAssigner(configPath: string, defaultValue: KeyboardShortcut): TemplateResult { + return html` this._valueChangedHandler(configPath, ev)} + >`; + } + + protected _renderViewKeyboardShortcutMenu(): TemplateResult { + return this._putInSubmenu( + MENU_VIEW_KEYBOARD_SHORTCUTS, + true, + `config.${CONF_VIEW_KEYBOARD_SHORTCUTS}.editor_label`, + { name: 'mdi:keyboard' }, + html` + ${this._renderSwitch( + CONF_VIEW_KEYBOARD_SHORTCUTS_ENABLED, + this._defaults.view.keyboard_shortcuts.enabled, + { + label: localize(`config.${CONF_VIEW_KEYBOARD_SHORTCUTS_ENABLED}`), + }, + )} + ${this._renderKeyAssigner( + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_LEFT, + this._defaults.view.keyboard_shortcuts.ptz_left, + )} + ${this._renderKeyAssigner( + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_RIGHT, + this._defaults.view.keyboard_shortcuts.ptz_right, + )} + ${this._renderKeyAssigner( + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_UP, + this._defaults.view.keyboard_shortcuts.ptz_up, + )} + ${this._renderKeyAssigner( + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_DOWN, + this._defaults.view.keyboard_shortcuts.ptz_down, + )} + ${this._renderKeyAssigner( + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_ZOOM_IN, + this._defaults.view.keyboard_shortcuts.ptz_zoom_in, + )} + ${this._renderKeyAssigner( + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_ZOOM_OUT, + this._defaults.view.keyboard_shortcuts.ptz_zoom_out, + )} + ${this._renderKeyAssigner( + CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_HOME, + this._defaults.view.keyboard_shortcuts.ptz_home, + )} + `, + ); + } + /** * Render an editor menu for the card menu buttons. * @param button The name of the button. @@ -2272,6 +2338,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor this._defaults.view.update_cycle_camera, )} ${this._renderViewTriggersMenu()} + ${this._renderViewKeyboardShortcutMenu()}
      ` : ''} @@ -2311,8 +2378,8 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderMenuButton('mute') /* */} ${this._renderMenuButton('screenshot')} ${this._renderMenuButton('display_mode')} - ${this._renderMenuButton('ptz')} - ${this._renderMenuButton('default_zoom')} + ${this._renderMenuButton('ptz_controls')} + ${this._renderMenuButton('ptz_home')} ` : ''} @@ -2787,9 +2854,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor this._updateConfig(newConfig); } - /** - * Return compiled CSS styles. - */ static get styles(): CSSResultGroup { return unsafeCSS(frigate_card_editor_style); } diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json index f6bd7c74..fbbc3de0 100644 --- a/src/localize/languages/ca.json +++ b/src/localize/languages/ca.json @@ -362,7 +362,6 @@ "camera_ui": "Interfície d'usuari de la càmera", "cameras": "Càmeres", "clips": "Clips", - "default_zoom": "", "display_mode": "Mode de visualització", "download": "Descarregar", "enabled": "Botó habilitat", @@ -377,7 +376,8 @@ "mute": "Silenciar / Activar el so", "play": "Reproduir / Pausa", "priority": "Prioritat", - "ptz": "", + "ptz_controls": "", + "ptz_home": "", "recordings": "Enregistraments", "screenshot": "Captura de pantalla", "snapshots": "Imatges instantànies", @@ -437,6 +437,10 @@ }, "default": "Vista per defecte", "interaction_seconds": "Segons després de l'acció de l'usuari per continuar interactuant (0=mai)", + "keyboard_shortcuts": { + "editor_label": "", + "enabled": "" + }, "reset_after_interaction": "Restableix la vista predeterminada després de la interacció de l'usuari", "triggers": { "actions": { @@ -580,6 +584,17 @@ "what": "Què", "where": "On" }, + "key_assigner": { + "assign": "", + "assigning": "", + "modifiers": { + "alt": "", + "ctrl": "", + "meta": "", + "shift": "" + }, + "unassign": "" + }, "media_filter": { "all": "Tots", "camera": "Càmera", @@ -630,4 +645,4 @@ "timeline": { "select_date": "Escolliu la data" } -} +} \ No newline at end of file diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index d145acab..b67be927 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -362,7 +362,7 @@ "camera_ui": "Camera user interface", "cameras": "Cameras", "clips": "Clips", - "default_zoom": "Zoom to default", + "ptz_home": "PTZ Home", "display_mode": "Display mode", "download": "Download", "enabled": "Button enabled", @@ -377,7 +377,7 @@ "mute": "Mute / Unmute", "play": "Play / Pause", "priority": "Priority", - "ptz": "Show PTZ controls", + "ptz_controls": "Show PTZ controls", "recordings": "Recordings", "screenshot": "Screenshot", "snapshots": "Snapshots", @@ -437,6 +437,17 @@ }, "default": "Default view", "interaction_seconds": "Seconds after user action to remain interacted with (0=never)", + "keyboard_shortcuts": { + "editor_label": "Keyboard shortcuts", + "enabled": "Keyboard shortcuts enabled", + "ptz_down": "PTZ Down", + "ptz_home": "PTZ Home", + "ptz_left": "PTZ Left", + "ptz_right": "PTZ Right", + "ptz_up": "PTZ Up", + "ptz_zoom_in": "PTZ Zoom In", + "ptz_zoom_out": "PTZ Zoom Out" + }, "reset_after_interaction": "Reset to the default view after user interaction", "triggers": { "actions": { @@ -580,6 +591,17 @@ "what": "What", "where": "Where" }, + "key_assigner": { + "assign": "Assign", + "assigning": "Assigning", + "modifiers": { + "alt": "Alt", + "ctrl": "Ctrl", + "meta": "Meta", + "shift": "Shift" + }, + "unassign": "Unassign" + }, "media_filter": { "all": "All", "camera": "Camera", diff --git a/src/localize/languages/fr.json b/src/localize/languages/fr.json index 0c639c16..4b72a638 100644 --- a/src/localize/languages/fr.json +++ b/src/localize/languages/fr.json @@ -362,7 +362,6 @@ "camera_ui": "Interface utilisateur de la caméra", "cameras": "Appareils photo", "clips": "Extraits", - "default_zoom": "", "display_mode": "", "download": "Télécharger", "enabled": "Bouton activé", @@ -377,7 +376,8 @@ "mute": "Désactiver/Réactiver le son", "play": "Jouer / Pause", "priority": "Priorité", - "ptz": "", + "ptz_controls": "", + "ptz_home": "", "recordings": "Enregistrements", "screenshot": "Capture d'écran", "snapshots": "Instantanés", @@ -437,6 +437,10 @@ }, "default": "Vue par défaut", "interaction_seconds": "", + "keyboard_shortcuts": { + "editor_label": "", + "enabled": "" + }, "reset_after_interaction": "", "triggers": { "actions": { @@ -580,6 +584,17 @@ "what": "Quoi", "where": "Où" }, + "key_assigner": { + "assign": "", + "assigning": "", + "modifiers": { + "alt": "", + "ctrl": "", + "meta": "", + "shift": "" + }, + "unassign": "" + }, "media_filter": { "all": "Tous", "camera": "Caméra", @@ -630,4 +645,4 @@ "timeline": { "select_date": "Choisir une date" } -} +} \ No newline at end of file diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index cf078f21..eab11dcb 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -362,7 +362,6 @@ "camera_ui": "Interfaccia utente della fotocamera", "cameras": "Telecamere", "clips": "Clip", - "default_zoom": "", "display_mode": "", "download": "Download", "enabled": "Pulsante abilitato", @@ -377,7 +376,8 @@ "mute": "", "play": "", "priority": "Priorità", - "ptz": "", + "ptz_controls": "", + "ptz_home": "", "recordings": "", "screenshot": "", "snapshots": "Istantanee", @@ -437,6 +437,10 @@ }, "default": "Visualizzazione predefinita", "interaction_seconds": "", + "keyboard_shortcuts": { + "editor_label": "", + "enabled": "" + }, "reset_after_interaction": "", "triggers": { "actions": { @@ -580,6 +584,17 @@ "what": "Che cosa", "where": "Dove" }, + "key_assigner": { + "assign": "", + "assigning": "", + "modifiers": { + "alt": "", + "ctrl": "", + "meta": "", + "shift": "" + }, + "unassign": "" + }, "media_filter": { "all": "Tutto", "camera": "Telecamera", @@ -630,4 +645,4 @@ "timeline": { "select_date": "Scegli la data" } -} +} \ No newline at end of file diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index ad57b80a..862c3239 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -362,7 +362,6 @@ "camera_ui": "Interface de usuário da câmera", "cameras": "Selecionar câmera", "clips": "Clipes", - "default_zoom": "", "display_mode": "", "download": "Baixe a mídia do evento", "enabled": "Botão ativado", @@ -377,7 +376,8 @@ "mute": "", "play": "", "priority": "Prioridade", - "ptz": "", + "ptz_controls": "", + "ptz_home": "", "recordings": "Gravações", "screenshot": "", "snapshots": "Instantâneos", @@ -437,6 +437,10 @@ }, "default": "Visualização padrão", "interaction_seconds": "", + "keyboard_shortcuts": { + "editor_label": "", + "enabled": "" + }, "reset_after_interaction": "", "triggers": { "actions": { @@ -580,6 +584,17 @@ "what": "O que", "where": "Onde" }, + "key_assigner": { + "assign": "", + "assigning": "", + "modifiers": { + "alt": "", + "ctrl": "", + "meta": "", + "shift": "" + }, + "unassign": "" + }, "media_filter": { "all": "Todos", "camera": "Câmera", @@ -630,4 +645,4 @@ "timeline": { "select_date": "Escolha a data" } -} +} \ No newline at end of file diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 46cd0f18..8800e74a 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -362,7 +362,6 @@ "camera_ui": "Camera", "cameras": "Selecionar câmera", "clips": "Clipes", - "default_zoom": "", "display_mode": "", "download": "Descarregar mídia do evento", "enabled": "Botão ativado", @@ -377,7 +376,8 @@ "mute": "", "play": "", "priority": "Prioridade", - "ptz": "", + "ptz_controls": "", + "ptz_home": "", "recordings": "", "screenshot": "", "snapshots": "Instantâneos", @@ -437,6 +437,10 @@ }, "default": "Visualização padrão", "interaction_seconds": "", + "keyboard_shortcuts": { + "editor_label": "", + "enabled": "" + }, "reset_after_interaction": "", "triggers": { "actions": { @@ -580,6 +584,17 @@ "what": "O quê", "where": "Onde" }, + "key_assigner": { + "assign": "", + "assigning": "", + "modifiers": { + "alt": "", + "ctrl": "", + "meta": "", + "shift": "" + }, + "unassign": "" + }, "media_filter": { "all": "Todos", "camera": "Camera", @@ -630,4 +645,4 @@ "timeline": { "select_date": "Selecionar a data" } -} +} \ No newline at end of file diff --git a/src/scss/card.scss b/src/scss/card.scss index 0ed212a9..04286562 100644 --- a/src/scss/card.scss +++ b/src/scss/card.scss @@ -18,6 +18,9 @@ max-height: var(--frigate-card-max-height); min-height: var(--frigate-card-min-height); + // Ensure all clicks at the top level work. + pointer-events: all; + // The standard HA header is 56 pixels tall, so that much off the top (header) // and bottom (to maintain center), before doing the calculation of // max-height. This matters on small mobile devices in landscape orientation. diff --git a/src/scss/key-assigner.scss b/src/scss/key-assigner.scss new file mode 100644 index 00000000..01036432 --- /dev/null +++ b/src/scss/key-assigner.scss @@ -0,0 +1,79 @@ +@use 'dotdotdot.scss'; + +:host { + display: flex; + flex-direction: row; + align-items: center; + + // Values match other HA editor components. + padding: 10px; + height: 56px; + border: 1px solid var(--divider-color); +} + +:host([assigning]) ha-button.assign span, +:host([assigning]) ha-button.assign ha-icon { + color: var(--warning-color); +} + +ha-icon { + padding: 10px; +} + +div.label { + width: 100px; + margin-left: 4px; +} + +div.key-row { + flex: 1; + + display: flex; + justify-content: center; + align-items: center; + + padding-left: 10px; + padding-right: 10px; +} + +div.key { + display: flex; + align-items: center; + + height: 90%; + width: min-content; + + margin-left: 5px; + margin-right: 5px; +} + +div.key-inner { + height: 100%; + width: 100%; + + padding-top: 2px; + padding-bottom: 2px; + padding-left: 4px; + padding-right: 4px; + + border: 2px; + border-radius: 4px; + border-style: outset; + border-color: var(--divider-color); + + font-family: monospace; + text-transform: capitalize; +} + +div.unassigned { + font-style: italic; +} + +div.key + div.key:before { + display: flex; + align-items: center; + + margin-right: 5px; + + content: ' + '; +} \ No newline at end of file diff --git a/src/types.ts b/src/types.ts index 06258cf6..a512154e 100644 --- a/src/types.ts +++ b/src/types.ts @@ -93,8 +93,13 @@ export interface CardHelpers { export type PTZMovementType = 'relative' | 'continuous'; export interface PTZCapabilities { - panTilt?: PTZMovementType[]; - zoom?: PTZMovementType[]; + left?: PTZMovementType[]; + right?: PTZMovementType[]; + up?: PTZMovementType[]; + down?: PTZMovementType[]; + zoomIn?: PTZMovementType[]; + zoomOut?: PTZMovementType[]; + presets?: string[]; } diff --git a/src/utils/action.ts b/src/utils/action.ts index cb4e2b18..b3ec8805 100644 --- a/src/utils/action.ts +++ b/src/utils/action.ts @@ -1,24 +1,28 @@ +import { ActionConfig, hasAction } from '@dermotduffy/custom-card-helpers'; +import { ZoomSettingsBase } from '../components-lib/zoom/types.js'; +import { PTZAction } from '../config/ptz.js'; import { - ActionConfig, - handleActionConfig, - hasAction, - HomeAssistant, -} from '@dermotduffy/custom-card-helpers'; -import { - Actions, + ActionPhase, ActionType, + Actions, FrigateCardCustomAction, - frigateCardCustomActionSchema, FrigateCardGeneralAction, FrigateCardUserSpecifiedView, + LogActionConfig, + LogActionLevel, + PTZActionConfig, + PTZDigitialActionConfig, + PTZMultiActionConfig, + frigateCardCustomActionSchema, } from '../config/types.js'; +import { arrayify } from './basic.js'; /** * Convert a generic Action to a FrigateCardCustomAction if it parses correctly. * @param action The generic action configuration. * @returns A FrigateCardCustomAction or null if it cannot be converted. */ -export function convertActionToFrigateCardCustomAction( +export function convertActionToCardCustomAction( action: unknown, ): FrigateCardCustomAction | null { if (!action) { @@ -30,7 +34,7 @@ export function convertActionToFrigateCardCustomAction( return parseResult.success ? parseResult.data : null; } -export function createFrigateCardSimpleAction( +export function createGeneralAction( action: FrigateCardGeneralAction | FrigateCardUserSpecifiedView, options?: { cardID?: string; @@ -43,7 +47,7 @@ export function createFrigateCardSimpleAction( }; } -export function createFrigateCardCameraAction( +export function createCameraAction( action: 'camera_select' | 'live_substream_select', camera: string, options?: { @@ -58,7 +62,7 @@ export function createFrigateCardCameraAction( }; } -export function createFrigateCardMediaPlayerAction( +export function createMediaPlayerAction( mediaPlayer: string, mediaPlayerAction: 'play' | 'stop', options?: { @@ -74,7 +78,7 @@ export function createFrigateCardMediaPlayerAction( }; } -export function createFrigateCardDisplayModeAction( +export function createDisplayModeAction( displayMode: 'single' | 'grid', options?: { cardID?: string; @@ -88,38 +92,87 @@ export function createFrigateCardDisplayModeAction( }; } -export function createFrigateCardShowPTZAction( - showPTZ: boolean, +export function createPTZControlsAction( + enabled: boolean, options?: { cardID?: string; }, ): FrigateCardCustomAction { return { action: 'fire-dom-event', - frigate_card_action: 'show_ptz', - show_ptz: showPTZ, + frigate_card_action: 'ptz_controls', + enabled: enabled, ...(options?.cardID && { card_id: options.cardID }), }; } -export function createFrigateCardChangeZoomAction( - targetID: string, - options?: { - cardID?: string; - pan?: { - x?: number; - y?: number; - }; - zoom?: number; - }, -): FrigateCardCustomAction { +export function createPTZAction(options?: { + cardID?: string; + ptzAction?: PTZAction; + ptzPhase?: ActionPhase; + ptzPreset?: string; + cameraID?: string; +}): PTZActionConfig { return { action: 'fire-dom-event', - frigate_card_action: 'change_zoom', - target_id: targetID, + frigate_card_action: 'ptz', + ...(options?.cardID && { card_id: options.cardID }), + ...(options?.ptzAction && { ptz_action: options.ptzAction }), + ...(options?.ptzPhase && { ptz_phase: options.ptzPhase }), + ...(options?.ptzPreset && { ptz_preset: options.ptzPreset }), + ...(options?.cameraID && { camera: options.cameraID }), + }; +} + +export function createPTZDigitalAction(options?: { + cardID?: string; + ptzPhase?: ActionPhase; + ptzAction?: PTZAction; + absolute?: ZoomSettingsBase; + targetID?: string; +}): PTZDigitialActionConfig { + return { + action: 'fire-dom-event', + frigate_card_action: 'ptz_digital', + ...(options?.cardID && { card_id: options.cardID }), + ...(options?.ptzAction && { ptz_action: options.ptzAction }), + ...(options?.ptzPhase && { ptz_phase: options.ptzPhase }), + ...(options?.absolute && { absolute: options.absolute }), + ...(options?.targetID && { target_id: options.targetID }), + }; +} + +export function createPTZMultiAction(options?: { + cardID?: string; + ptzAction?: PTZAction; + ptzPhase?: ActionPhase; + ptzPreset?: string; + targetID?: string; +}): PTZMultiActionConfig { + return { + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + ...(options?.cardID && { card_id: options.cardID }), + ...(options?.ptzAction && { ptz_action: options.ptzAction }), + ...(options?.ptzPhase && { ptz_phase: options.ptzPhase }), + ...(options?.ptzPreset && { ptz_preset: options.ptzPreset }), + ...(options?.targetID && { target_id: options.targetID }), + }; +} + +export function createLogAction( + message: string, + options?: { + cardID?: string; + level?: LogActionLevel; + }, +): LogActionConfig { + return { + action: 'fire-dom-event', + frigate_card_action: 'log', + message: message, + level: options?.level ?? 'info', ...(options?.cardID && { card_id: options.cardID }), - ...(options?.pan && { pan: options.pan }), - ...(options?.zoom && { zoom: options.zoom }), }; } @@ -150,63 +203,6 @@ export function getActionConfigGivenAction( return null; } -/** - * Frigate card custom version of handleAction - * (https://github.com/custom-cards/custom-card-helpers/blob/master/src/handle-action.ts) - * that handles the custom action events the card supports. - * @param node The node that fired the event. - * @param hass The Home Assistant object. - * @param actionConfig A single action config, array of action configs or - * undefined for the default action config for 'tap'. - * @param action The action string (e.g. 'hold') - * @returns Whether or not an action was executed. - */ -export const frigateCardHandleActionConfig = ( - node: HTMLElement, - hass: HomeAssistant, - config: { - camera_image?: string; - entity?: string; - }, - action: string, - actionConfig?: ActionType | ActionType[] | null, -): boolean => { - // Only allow a tap action to use a default non-config (the more-info config). - if (actionConfig || action == 'tap') { - frigateCardHandleAction(node, hass, config, actionConfig); - return true; - } - return false; -}; - -export const frigateCardHandleAction = ( - node: HTMLElement, - hass: HomeAssistant, - config: { - camera_image?: string; - entity?: string; - }, - actionConfig?: ActionType | ActionType[] | null, -): void => { - // ActionConfig vs ActionType: - // * There is a slight typing (but not functional) difference between - // ActionType in this card and ActionConfig in `custom-card-helpers`. See - // `ExtendedConfirmationRestrictionConfig` in `types.ts` for the source and - // reason behind this difference. - if (Array.isArray(actionConfig)) { - actionConfig.forEach((action) => - handleActionConfig(node, hass, config, action as ActionConfig | undefined), - ); - } else { - handleActionConfig( - node, - hass, - config, - (actionConfig ?? undefined) as ActionConfig | undefined, - ); - } -}; - /** * Determine if an action config has a real action. A modified version of * custom-card-helpers hasAction to also work with arrays of action configs. @@ -216,10 +212,7 @@ export const frigateCardHandleAction = ( export const frigateCardHasAction = (config?: ActionType | ActionType[]): boolean => { // See note above on 'ActionConfig vs ActionType' for why this cast is // necessary and harmless. - if (Array.isArray(config)) { - return !!config.find((item) => hasAction(item as ActionConfig | undefined)); - } - return hasAction(config as ActionConfig | undefined); + return arrayify(config).some((item) => hasAction(item as ActionConfig | undefined)); }; /** diff --git a/src/utils/basic.ts b/src/utils/basic.ts index 4c3c3bda..b3f4ee6e 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -5,9 +5,10 @@ import { format, } from 'date-fns'; import { StyleInfo } from 'lit/directives/style-map'; -import { round } from 'lodash-es'; import isEqualWith from 'lodash-es/isEqualWith'; import mergeWith from 'lodash-es/mergeWith'; +import round from 'lodash-es/round'; +import uniq from 'lodash-es/uniq'; import { FrigateCardError } from '../types'; export type ModifyInterface = Omit & R; @@ -254,6 +255,16 @@ export const recursivelyMergeObjectsNotArrays = (target: T, src1: T, src2: T) return mergeWith(target, src1, src2, (_a, b) => (Array.isArray(b) ? b : undefined)); }; +export const recursivelyMergeObjectsConcatenatingArraysUniquely = ( + target: T, + src1: T, + src2: T, +): T => { + return mergeWith(target, src1, src2, (a, b) => + Array.isArray(a) ? uniq(a.concat(b)) : undefined, + ); +}; + export const aspectRatioToString = (options?: { ratio?: number[]; defaultStatic?: boolean; diff --git a/src/utils/ha/index.ts b/src/utils/ha/index.ts index 3b6e18b2..1d52a860 100644 --- a/src/utils/ha/index.ts +++ b/src/utils/ha/index.ts @@ -301,17 +301,18 @@ export function getEntityIcon( */ export const sideLoadHomeAssistantElements = async (): Promise => { const neededElements = [ - 'ha-selector', - 'ha-menu-button', - 'ha-camera-stream', - 'ha-hls-player', - 'ha-web-rtc-player', - 'ha-icon', - 'ha-circular-progress', - 'ha-icon-button', - 'ha-card', - 'ha-svg-icon', 'ha-button-menu', + 'ha-button', + 'ha-camera-stream', + 'ha-card', + 'ha-circular-progress', + 'ha-hls-player', + 'ha-icon-button', + 'ha-icon', + 'ha-menu-button', + 'ha-selector', + 'ha-svg-icon', + 'ha-web-rtc-player', ]; if (neededElements.every((element) => customElements.get(element))) { diff --git a/src/utils/ptz.ts b/src/utils/ptz.ts index 2cde0016..c4391a4f 100644 --- a/src/utils/ptz.ts +++ b/src/utils/ptz.ts @@ -1,19 +1,75 @@ -import { Capabilities } from '../camera-manager/capabilities'; -import { FrigateCardPTZConfig, PTZ_CONTROL_ACTIONS } from '../config/types'; +import { CameraManager } from '../camera-manager/manager'; +import { PTZAction } from '../config/ptz'; +import { PTZCapabilities } from '../types'; +import { View } from '../view/view'; +import { getStreamCameraID } from './substream'; -export const hasUsablePTZ = ( - capabilities: Capabilities | null, - config: FrigateCardPTZConfig, -): boolean => { - for (const actionName of PTZ_CONTROL_ACTIONS) { - if ('actions_' + actionName in config) { - return true; +export type PTZType = 'digital' | 'ptz'; +interface PTZTarget { + targetID: string; + type: PTZType; +} + +export const getPTZTarget = ( + view: View, + options?: { + type?: PTZType; + cameraManager?: CameraManager; + }, +): PTZTarget | null => { + if (view.isViewerView()) { + const targetID = view.queryResults?.getSelectedResult()?.getID() ?? null; + return options?.type === 'ptz' || !targetID + ? null + : { + targetID: targetID, + type: 'digital', + }; + } else if (view.is('live')) { + const substreamAwareCameraID = getStreamCameraID(view); + let type: PTZType = 'digital'; + + if (options?.type !== 'digital' && options?.cameraManager) { + if (hasCameraTruePTZ(options.cameraManager, substreamAwareCameraID)) { + type = 'ptz'; + } + if (type !== 'ptz' && options?.type === 'ptz') { + return null; + } } + + return { + targetID: substreamAwareCameraID, + type: type, + }; } - const ptzCapabilities = capabilities?.getPTZCapabilities(); - return ( - !!ptzCapabilities?.panTilt?.length || - !!ptzCapabilities?.zoom?.length || - !!ptzCapabilities?.presets?.length - ); + return null; +}; + +export const hasCameraTruePTZ = ( + cameraManager: CameraManager, + cameraID: string, +): boolean => { + return !!cameraManager + .getStore() + .getCamera(cameraID) + ?.getCapabilities() + ?.hasPTZCapability(); +}; + +export const ptzActionToCapabilityKey = ( + action: PTZAction, +): keyof PTZCapabilities | null => { + switch (action) { + case 'left': + case 'right': + case 'up': + case 'down': + return action; + case 'zoom_in': + return 'zoomIn'; + case 'zoom_out': + return 'zoomOut'; + } + return null; }; diff --git a/src/utils/substream.ts b/src/utils/substream.ts index 8ada684e..938eb218 100644 --- a/src/utils/substream.ts +++ b/src/utils/substream.ts @@ -1,7 +1,7 @@ import { View } from '../view/view'; -export const getStreamCameraID = (view: View): string => { - return view?.context?.live?.overrides?.get(view.camera) ?? view.camera; +export const getStreamCameraID = (view: View, cameraID?: string): string => { + return view.context?.live?.overrides?.get(cameraID ?? view.camera) ?? view.camera; }; export const hasSubstream = (view: View): boolean => { diff --git a/src/view/view.ts b/src/view/view.ts index 9e9e54e6..dd9b0ed8 100644 --- a/src/view/view.ts +++ b/src/view/view.ts @@ -64,7 +64,7 @@ export class View { } public static adoptFromViewIfAppropriate(next: View, curr?: View | null): void { - if (!curr) { + if (!curr) { return; } @@ -273,10 +273,7 @@ export class View { export interface FrigateCardViewChangeEventTarget extends EventTarget { addEventListener( event: 'frigate-card:view:change', - listener: ( - this: FrigateCardViewChangeEventTarget, - ev: CustomEvent, - ) => void, + listener: (this: FrigateCardViewChangeEventTarget, ev: CustomEvent) => void, options?: AddEventListenerOptions | boolean, ): void; addEventListener( @@ -286,10 +283,7 @@ export interface FrigateCardViewChangeEventTarget extends EventTarget { ): void; removeEventListener( event: 'frigate-card:view:change', - listener: ( - this: FrigateCardViewChangeEventTarget, - ev: CustomEvent, - ) => void, + listener: (this: FrigateCardViewChangeEventTarget, ev: CustomEvent) => void, options?: boolean | EventListenerOptions, ): void; removeEventListener( diff --git a/tests/camera-manager/capabilities.test.ts b/tests/camera-manager/capabilities.test.ts index 9710e489..b84fc5cc 100644 --- a/tests/camera-manager/capabilities.test.ts +++ b/tests/camera-manager/capabilities.test.ts @@ -68,17 +68,19 @@ describe('Capabilities', () => { it('when unset', () => { const capabilities = new Capabilities({}); expect(capabilities.getPTZCapabilities()).toBeNull(); + expect(capabilities.hasPTZCapability()).toBeFalsy(); }); it('when set', () => { const ptz: PTZCapabilities = { - panTilt: ['continuous' as const], + left: ['continuous' as const], presets: ['1', '2'], }; const capabilities = new Capabilities({ ptz: ptz, }); expect(capabilities.getPTZCapabilities()).toBe(ptz); + expect(capabilities.hasPTZCapability()).toBeTruthy(); }); }); diff --git a/tests/camera-manager/frigate/camera.test.ts b/tests/camera-manager/frigate/camera.test.ts index 7852ae52..15ed29e8 100644 --- a/tests/camera-manager/frigate/camera.test.ts +++ b/tests/camera-manager/frigate/camera.test.ts @@ -191,6 +191,7 @@ describe('FrigateCamera', () => { await camera.initialize(createHASS(), mock()); expect(camera.getCapabilities()?.has('ptz')).toBeFalsy(); + expect(camera.getCapabilities()?.hasPTZCapability()).toBeFalsy(); expect(consoleSpy).toBeCalled(); }); @@ -214,10 +215,15 @@ describe('FrigateCamera', () => { expect(camera.getCapabilities()?.has('ptz')).toBeTruthy(); expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({ - panTilt: ['continuous'], - zoom: ['continuous'], + left: ['continuous'], + right: ['continuous'], + up: ['continuous'], + down: ['continuous'], + zoomIn: ['continuous'], + zoomOut: ['continuous'], presets: ['preset01'], }); + expect(camera.getCapabilities()?.hasPTZCapability()).toBeTruthy(); }); it('when getPTZInfo call succeeds with relative motion', async () => { @@ -240,10 +246,15 @@ describe('FrigateCamera', () => { expect(camera.getCapabilities()?.has('ptz')).toBeTruthy(); expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({ - panTilt: ['relative'], - zoom: ['relative'], + left: [], + right: [], + up: [], + down: [], + zoomIn: [], + zoomOut: [], presets: ['preset01'], }); + expect(camera.getCapabilities()?.hasPTZCapability()).toBeTruthy(); }); }); }); diff --git a/tests/camera-manager/frigate/engine-frigate.test.ts b/tests/camera-manager/frigate/engine-frigate.test.ts index 61acff83..1c0a7cab 100644 --- a/tests/camera-manager/frigate/engine-frigate.test.ts +++ b/tests/camera-manager/frigate/engine-frigate.test.ts @@ -6,10 +6,10 @@ import { FrigateRecordingViewMedia, } from '../../../src/camera-manager/frigate/media'; import { FrigateEvent, eventSchema } from '../../../src/camera-manager/frigate/types.js'; +import { PTZAction } from '../../../src/config/ptz'; import { CameraConfig, FrigateCardView, - PTZAction, RawFrigateCardConfig, } from '../../../src/config/types'; import { ViewMedia } from '../../../src/view/media'; diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts index 8529c37d..ee9b53bc 100644 --- a/tests/camera-manager/manager.test.ts +++ b/tests/camera-manager/manager.test.ts @@ -1070,7 +1070,7 @@ describe('CameraManager', async () => { snapshots: true, ptz: { - panTilt: ['continuous'], + left: ['continuous'], }, }), }, @@ -1102,7 +1102,50 @@ describe('CameraManager', async () => { expect(engine.executePTZAction).not.toBeCalled(); }); - it('successfully', async () => { + it('without hass', async () => { + const api = createCardAPI(); + const engine = mock(); + const manager = createCameraManager(api, engine); + + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(null); + manager.executePTZAction('id', 'left'); + + expect(engine.executePTZAction).not.toBeCalled(); + }); + + it('successfully from config', async () => { + const api = createCardAPI(); + const engine = mock(); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + const action = { + action: 'call-service' as const, + service: 'service', + } + const manager = createCameraManager(api, engine, [ + { + config: createCameraConfig({ + baseCameraConfig, + id: 'another', + ptz: { + actions_left: action, + }, + }), + }, + ]); + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + + manager.executePTZAction('another', 'left'); + + expect(api.getActionsManager().executeActions).toBeCalledWith(action); + expect(engine.executePTZAction).not.toBeCalled(); + }); + + it('successfully from engine', async () => { const api = createCardAPI(); const engine = mock(); const hass = createHASS(); diff --git a/tests/camera-manager/utils/ptz.test.ts b/tests/camera-manager/utils/ptz.test.ts new file mode 100644 index 00000000..44788a86 --- /dev/null +++ b/tests/camera-manager/utils/ptz.test.ts @@ -0,0 +1,191 @@ +import { describe, expect, it, vi } from 'vitest'; +import { + getConfiguredPTZAction, + getConfiguredPTZMovementType, + getPTZCapabilitiesFromCameraConfig, +} from '../../../src/camera-manager/utils/ptz'; +import { createCameraConfig } from '../../test-utils'; +import { PTZAction } from '../../../src/config/ptz'; + +const action = { + action: 'call-service' as const, + service: 'service', + data: { + device: '048123', + cmd: 'preset', + preset: 'window', + }, +}; + +describe('getConfiguredPTZAction', () => { + describe('should return preset', () => { + it('with preset', () => { + expect( + getConfiguredPTZAction( + createCameraConfig({ + ptz: { + presets: { + window: action, + }, + }, + }), + 'preset', + { + preset: 'window', + }, + ), + ).toEqual(action); + }); + + it('without preset', () => { + expect( + getConfiguredPTZAction( + createCameraConfig({ + ptz: { + presets: { + window: action + }, + }, + }), + 'preset', + ), + ).toBeNull(); + }); + }); + + describe('should return continuous action', () => { + it('with action', () => { + expect( + getConfiguredPTZAction( + createCameraConfig({ + ptz: { + actions_left_start: action, + }, + }), + 'left', + { + phase: 'start', + }, + ), + ).toEqual(action); + }); + + it('without action', () => { + expect( + getConfiguredPTZAction( + createCameraConfig({ + ptz: {}, + }), + 'left', + { + phase: 'start', + }, + ), + ).toBeNull(); + }); + }); +}); + +describe('getConfiguredPTZMovementType', () => { + it('with continuous', () => { + expect( + getConfiguredPTZMovementType( + createCameraConfig({ + ptz: { + actions_left_start: action, + actions_left_stop: action, + }, + }), + 'left', + ), + )?.toEqual(['continuous']); + }); + + it('with relative', () => { + expect( + getConfiguredPTZMovementType( + createCameraConfig({ + ptz: { + actions_left: action, + }, + }), + 'left', + ), + )?.toEqual(['relative']); + }); + + it('with continuous and relative', () => { + expect( + getConfiguredPTZMovementType( + createCameraConfig({ + ptz: { + actions_left: action, + actions_left_start: action, + actions_left_stop: action, + }, + }), + 'left', + ), + )?.toEqual(['continuous', 'relative']); + }); + + it('with no actions', () => { + expect( + getConfiguredPTZMovementType( + createCameraConfig({ + ptz: {}, + }), + 'left', + ), + )?.toBeNull(); + }); +}); + +describe('getPTZCapabilitiesFromCameraConfig', () => { + it('with nothing', () => { + expect(getPTZCapabilitiesFromCameraConfig(createCameraConfig()))?.toBeNull(); + }); + + describe('with individual actions', () => { + it.each([ + ['left' as const, 'left'], + ['right' as const, 'right'], + ['up' as const, 'up'], + ['down' as const, 'down'], + ['zoom_in' as const, 'zoomIn'], + ['zoom_out' as const, 'zoomOut'], + ])('%s', async (actionName: PTZAction, capabilityName: string) => { + expect( + getPTZCapabilitiesFromCameraConfig( + createCameraConfig({ + ptz: { + ['actions_' + actionName]: action, + }, + }), + ), + )?.toEqual( + expect.objectContaining({ + [capabilityName]: ['relative'], + }), + ); + }); + }); + + it('with preset', () => { + expect( + getPTZCapabilitiesFromCameraConfig( + createCameraConfig({ + ptz: { + presets: { + window: action, + }, + }, + }), + ), + )?.toEqual( + expect.objectContaining({ + presets: ['window'], + }), + ); + }); +}); diff --git a/tests/card-controller/actions-manager.test.ts b/tests/card-controller/actions-manager.test.ts deleted file mode 100644 index 0da864a7..00000000 --- a/tests/card-controller/actions-manager.test.ts +++ /dev/null @@ -1,914 +0,0 @@ -/* eslint-disable @typescript-eslint/no-non-null-assertion */ -import { afterAll, describe, expect, it, vi } from 'vitest'; -import { mock } from 'vitest-mock-extended'; -import { - ActionType, - FrigateCardCustomAction, - FrigateCardView, - frigateCardCustomActionSchema, -} from '../../src/config/types'; -import { FrigateCardMediaPlayer } from '../../src/types'; -import { - convertActionToFrigateCardCustomAction, - frigateCardHandleAction, - frigateCardHandleActionConfig, - getActionConfigGivenAction, -} from '../../src/utils/action.js'; -import { ActionsManager, Interaction } from '../../src/card-controller/actions-manager'; -import { - createCardAPI, - createConfig, - createHASS, - createMediaLoadedInfo, - createView, - createViewWithMedia, -} from '../test-utils'; - -vi.mock('../../src/utils/action.js'); - -const createAction = ( - action: Record, -): FrigateCardCustomAction | null => { - const result = frigateCardCustomActionSchema.safeParse({ - action: 'custom:frigate-card-action', - ...action, - }); - return result.success ? result.data : null; -}; - -describe('ActionsManager.getMergedActions', () => { - const config = { - view: { - actions: { - tap_action: { - action: 'navigate', - navigation_path: '1', - }, - }, - }, - live: { - actions: { - tap_action: { - action: 'navigate', - navigation_path: '2', - }, - }, - }, - media_gallery: { - actions: { - tap_action: { - action: 'navigate', - navigation_path: '3', - }, - }, - }, - media_viewer: { - actions: { - tap_action: { - action: 'navigate', - navigation_path: '4', - }, - }, - }, - image: { - actions: { - tap_action: { - action: 'navigate', - navigation_path: '5', - }, - }, - }, - }; - - afterAll(() => { - vi.restoreAllMocks(); - }); - - it('should get no merged actions with a message', () => { - const api = createCardAPI(); - vi.mocked(api.getViewManager().getView).mockReturnValue( - createView({ view: 'live' }), - ); - vi.mocked(api.getMessageManager().hasMessage).mockReturnValue(true); - - const manager = new ActionsManager(api); - - expect(manager.getMergedActions()).toEqual({}); - }); - - describe('should get merged actions with live view', () => { - it.each([ - [ - 'live' as const, - { - tap_action: { - action: 'navigate', - navigation_path: '2', - }, - }, - ], - [ - 'clips' as const, - { - tap_action: { - action: 'navigate', - navigation_path: '3', - }, - }, - ], - [ - 'clip' as const, - { - tap_action: { - action: 'navigate', - navigation_path: '4', - }, - }, - ], - [ - 'image' as const, - { - tap_action: { - action: 'navigate', - navigation_path: '5', - }, - }, - ], - ['timeline' as const, {}], - ])('%s', (viewName: FrigateCardView, result: Record) => { - const api = createCardAPI(); - vi.mocked(api.getViewManager().getView).mockReturnValue( - createView({ view: viewName }), - ); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig(config)); - - const manager = new ActionsManager(api); - - expect(manager.getMergedActions()).toEqual(result); - }); - }); -}); - -// @vitest-environment jsdom -describe('ActionsManager.handleInteraction', () => { - it('should handle interaction', () => { - const api = createCardAPI(); - const element = document.createElement('div'); - vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); - const manager = new ActionsManager(api); - - const hass = createHASS(); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); - - const actionForThisInteraction: ActionType = { - action: 'none', - }; - vi.mocked(getActionConfigGivenAction).mockReturnValue(actionForThisInteraction); - - manager.handleInteractionEvent( - new CustomEvent('event', { detail: { action: 'tap' } }), - ); - - expect(frigateCardHandleActionConfig).toBeCalledWith( - element, - hass, - manager.getMergedActions(), - 'tap', - actionForThisInteraction, - ); - }); - - it('should not handle interaction without hass', () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(null); - - // No values of hass. - manager.handleInteractionEvent( - new CustomEvent('event', { detail: { action: 'tap' } }), - ); - expect(frigateCardHandleActionConfig).not.toBeCalledWith(); - }); - - it('should not handle malformed interaction', () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - manager.handleInteractionEvent( - new CustomEvent('event', { - // Malformed interaction type. - detail: { action: 'double_finger_snap' } as unknown as Interaction, - }), - ); - expect(frigateCardHandleActionConfig).not.toBeCalledWith(); - }); -}); - -describe('ActionsManager.handleActionEvent', () => { - it('should handle event', () => { - const action = createAction({ frigate_card_action: 'default' })!; - const event: CustomEvent = new CustomEvent('ll-custom', { - detail: action, - }); - - // The file containing convertActionToFrigateCardCustomAction (action.ts) is - // mocked, so need to provide a value here. - vi.mocked(convertActionToFrigateCardCustomAction).mockReturnValue(action); - - const api = createCardAPI(); - const manager = new ActionsManager(api); - - manager.handleActionEvent(event); - expect(api.getViewManager().setViewDefault).toBeCalled(); - }); - - it('should not handle event without detail', () => { - const action = createAction({ frigate_card_action: 'default' })!; - const event = new Event('ll-custom'); - - // Mock this out just so that if the sentinel in handleActionEvent failed, - // it would still trigger a test failure below. - vi.mocked(convertActionToFrigateCardCustomAction).mockReturnValue(action); - - const api = createCardAPI(); - const manager = new ActionsManager(api); - manager.handleActionEvent(event); - - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - }); - - it('should not handle malformed action', () => { - const action = createAction({ frigate_card_action: 'default' })!; - const event: CustomEvent = new CustomEvent('ll-custom', { - detail: action, - }); - - vi.mocked(convertActionToFrigateCardCustomAction).mockReturnValue(null); - - const api = createCardAPI(); - const manager = new ActionsManager(api); - manager.handleActionEvent(event); - - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - }); -}); - -describe('ActionsManager.executeAction', () => { - it('should not handle actions with different card_id', async () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - card_id: 'foo', - }), - ); - - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - card_id: 'NOT_foo', - frigate_card_action: 'default', - })!, - ); - - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - }); - - it('should handle default action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'default', - })!, - ); - - expect(api.getViewManager().setViewDefault).toBeCalled(); - }); - - describe('should handle view action', async () => { - it.each([ - ['clip' as const], - ['clips' as const], - ['image' as const], - ['live' as const], - ['recording' as const], - ['recordings' as const], - ['snapshot' as const], - ['snapshots' as const], - ['timeline' as const], - ])('%s', async (viewName: FrigateCardView) => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: viewName, - })!, - ); - - expect(api.getViewManager().setViewByParameters).toBeCalledWith( - expect.objectContaining({ - viewName: viewName, - }), - ); - }); - }); - - it('should handle download action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'download', - })!, - ); - - expect(api.getDownloadManager().downloadViewerMedia).toBeCalled(); - }); - - it('should handle camera ui action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'camera_ui', - })!, - ); - - expect(api.getCameraURLManager().openURL).toBeCalled(); - }); - - it('should handle expand action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'expand', - })!, - ); - - expect(api.getExpandManager().toggleExpanded).toBeCalled(); - }); - - it('should handle fullscreen action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'fullscreen', - })!, - ); - - expect(api.getFullscreenManager().toggleFullscreen).toBeCalled(); - }); - - it('should handle menu toggle action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'menu_toggle', - })!, - ); - - expect(api.getCardElementManager().toggleMenu).toBeCalled(); - }); - - describe('should handle camera_select action', () => { - it('with valid camera and view', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); - vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'camera_select', - camera: 'camera', - })!, - ); - - expect(api.getViewManager().setViewByParameters).toBeCalledWith( - expect.objectContaining({ - viewName: 'live', - cameraID: 'camera', - failSafe: true, - }), - ); - }); - - it('without config', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(null); - vi.mocked(api.getViewManager().getView).mockReturnValue( - createView({ - view: 'timeline', - }), - ); - vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'camera_select', - camera: 'camera', - })!, - ); - - expect(api.getViewManager().setViewByParameters).toBeCalledWith( - expect.objectContaining({ - viewName: 'timeline', - cameraID: 'camera', - failSafe: true, - }), - ); - }); - - it('with target view', async () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - view: { - // Change to clips view when the camera changes. - camera_select: 'clips', - }, - }), - ); - vi.mocked(api.getViewManager().getView).mockReturnValue( - createView({ - view: 'live', - }), - ); - vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'camera_select', - camera: 'camera', - })!, - ); - - expect(api.getViewManager().setViewByParameters).toBeCalledWith( - expect.objectContaining({ - viewName: 'clips', - cameraID: 'camera', - failSafe: true, - }), - ); - }); - - it('with triggered camera', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); - vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); - vi.mocked( - api.getTriggersManager().getMostRecentlyTriggeredCameraID, - ).mockReturnValue('camera'); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'camera_select', - triggered: true, - })!, - ); - - expect(api.getViewManager().setViewByParameters).toBeCalledWith( - expect.objectContaining({ - viewName: 'live', - cameraID: 'camera', - failSafe: true, - }), - ); - }); - - it('without camera or triggered camera', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); - vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); - vi.mocked( - api.getTriggersManager().getMostRecentlyTriggeredCameraID, - ).mockReturnValue('camera'); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'camera_select', - })!, - ); - - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); - }); - - it('without a current view', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'camera_select', - camera: 'camera', - })!, - ); - - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); - }); - }); - - it('should handle live_substream_select action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'live_substream_select', - camera: 'substream', - })!, - ); - - expect(api.getViewManager().setViewWithSubstream).toBeCalledWith('substream'); - }); - - it('should handle live_substream_off action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'live_substream_off', - })!, - ); - - expect(api.getViewManager().setViewWithoutSubstream).toBeCalled(); - }); - - it('should handle live_substream_on action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'live_substream_on', - })!, - ); - - expect(api.getViewManager().setViewWithSubstream).toBeCalledWith(); - }); - - describe('should handle media_player action', () => { - it('to stop', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'media_player', - media_player_action: 'stop', - media_player: 'this_is_a_media_player', - })!, - ); - - expect(api.getMediaPlayerManager().stop).toBeCalledWith('this_is_a_media_player'); - }); - - it('to play live', async () => { - const api = createCardAPI(); - vi.mocked(api.getViewManager().getView).mockReturnValue( - createView({ - camera: 'camera', - view: 'live', - }), - ); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'media_player', - media_player_action: 'play', - media_player: 'this_is_a_media_player', - })!, - ); - - expect(api.getMediaPlayerManager().playLive).toBeCalledWith( - 'this_is_a_media_player', - 'camera', - ); - }); - - it('to play media', async () => { - const api = createCardAPI(); - const view = createViewWithMedia({ - camera: 'camera', - view: 'media', - }); - - vi.mocked(api.getViewManager().getView).mockReturnValue(view); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'media_player', - media_player_action: 'play', - media_player: 'this_is_a_media_player', - })!, - ); - - expect(api.getMediaPlayerManager().playMedia).toBeCalledWith( - 'this_is_a_media_player', - view.queryResults?.getSelectedResult(), - ); - }); - - it('to play media without selected media', async () => { - const api = createCardAPI(); - vi.mocked(api.getViewManager().getView).mockReturnValue( - createView({ - view: 'media', - }), - ); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'media_player', - media_player_action: 'play', - media_player: 'this_is_a_media_player', - })!, - ); - - expect(api.getMediaPlayerManager().playMedia).not.toBeCalled(); - }); - }); - - it('should handle diagnostics action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'diagnostics', - })!, - ); - - expect(api.getViewManager().setViewByParameters).toBeCalledWith( - expect.objectContaining({ - viewName: 'diagnostics', - }), - ); - }); - - it('should handle microphone_mute action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'microphone_mute', - })!, - ); - - expect(api.getMicrophoneManager().mute).toBeCalled(); - }); - - it('should handle microphone_unmute action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'microphone_unmute', - })!, - ); - - expect(api.getMicrophoneManager().unmute).toBeCalled(); - }); - - describe('should handle media player action', () => { - it.each([ - ['mute' as const], - ['unmute' as const], - ['play' as const], - ['pause' as const], - ])('%s', async (action: 'mute' | 'unmute' | 'play' | 'pause') => { - const api = createCardAPI(); - const player = mock(); - vi.mocked(api.getMediaLoadedInfoManager().get).mockReturnValue( - createMediaLoadedInfo({ - player: player, - }), - ); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: action, - })!, - ); - - expect(player[action]).toBeCalled(); - }); - }); - - it('should handle screenshot action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'screenshot', - })!, - ); - - expect(api.getDownloadManager().downloadScreenshot).toBeCalled(); - }); - - it('should handle display_mode_select action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'display_mode_select', - display_mode: 'grid', - })!, - ); - - expect(api.getViewManager().setViewWithNewDisplayMode).toBeCalledWith('grid'); - }); - - describe('should handle ptz action', () => { - it('with selected camera', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - vi.mocked(api.getViewManager().getView).mockReturnValue( - createView({ camera: 'camera.office' }), - ); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'ptz', - ptz_action: 'left', - })!, - ); - - expect(api.getCameraManager().executePTZAction).toBeCalledWith( - 'camera.office', - 'left', - { - phase: undefined, - preset: undefined, - }, - ); - }); - - it('without selected camera', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'ptz', - ptz_action: 'left', - })!, - ); - - expect(api.getCameraManager().executePTZAction).not.toBeCalled(); - }); - }); - - it('should handle show_ptz action', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'show_ptz', - show_ptz: true, - })!, - ); - - expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith( - expect.objectContaining({ live: { ptzVisible: true } }), - ); - }); - - describe('should handle change_zoom action', () => { - it('default', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'change_zoom', - target_id: 'camera.office', - })!, - ); - - expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith( - expect.objectContaining({ - zoom: { - 'camera.office': { - zoom: {}, - }, - }, - }), - ); - }); - - it('non-default', async () => { - const api = createCardAPI(); - const manager = new ActionsManager(api); - - await manager.executeFrigateAction( - createAction({ - frigate_card_action: 'change_zoom', - target_id: 'camera.office', - zoom: 2, - pan: { - x: 3, - y: 4, - }, - })!, - ); - - expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith( - expect.objectContaining({ - zoom: { - 'camera.office': { - zoom: { - zoom: 2, - pan: { - x: 3, - y: 4, - }, - }, - }, - }, - }), - ); - }); - }); - - it('should handle unknown action', async () => { - const manager = new ActionsManager(createCardAPI()); - - const spy = vi.spyOn(global.console, 'warn').mockImplementation(() => true); - - await manager.executeFrigateAction( - // Have to manually create the action (vs using `createAction()`) since - // it's malformed. - { - frigate_card_action: 'not_a_real_action', - } as unknown as FrigateCardCustomAction, - ); - - expect(spy).toBeCalledWith( - 'Frigate card received unknown card action: not_a_real_action', - ); - }); -}); - -describe('ActionsManager.executeActions', () => { - it('should execute actions', async () => { - const api = createCardAPI(); - const hass = createHASS(); - const element = document.createElement('div'); - - vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); - - const manager = new ActionsManager(api); - const action = createAction({ - frigate_card_action: 'default', - })!; - manager.executeActions(action); - - expect(frigateCardHandleAction).toBeCalledWith(element, hass, {}, action); - }); - - it('should not execute actions without hass', async () => { - const api = createCardAPI(); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(null); - - const manager = new ActionsManager(api); - manager.executeActions( - createAction({ - frigate_card_action: 'default', - })!, - ); - - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - }); -}); diff --git a/tests/card-controller/actions/actions-manager.test.ts b/tests/card-controller/actions/actions-manager.test.ts new file mode 100644 index 00000000..8da0dde3 --- /dev/null +++ b/tests/card-controller/actions/actions-manager.test.ts @@ -0,0 +1,289 @@ +import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { + ActionsManager, + Interaction, + InteractionName, +} from '../../../src/card-controller/actions/actions-manager'; +import { FrigateCardView } from '../../../src/config/types'; +import { createLogAction } from '../../../src/utils/action'; +import { + createAction, + createCardAPI, + createConfig, + createHASS, + createView, +} from '../../test-utils'; + +describe('ActionsManager', () => { + describe('getMergedActions', () => { + const config = { + view: { + actions: { + tap_action: { + action: 'navigate', + navigation_path: '1', + }, + }, + }, + live: { + actions: { + tap_action: { + action: 'navigate', + navigation_path: '2', + }, + }, + }, + media_gallery: { + actions: { + tap_action: { + action: 'navigate', + navigation_path: '3', + }, + }, + }, + media_viewer: { + actions: { + tap_action: { + action: 'navigate', + navigation_path: '4', + }, + }, + }, + image: { + actions: { + tap_action: { + action: 'navigate', + navigation_path: '5', + }, + }, + }, + }; + + afterAll(() => { + vi.restoreAllMocks(); + }); + + it('should get no merged actions with a message', () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ view: 'live' }), + ); + vi.mocked(api.getMessageManager().hasMessage).mockReturnValue(true); + + const manager = new ActionsManager(api); + + expect(manager.getMergedActions()).toEqual({}); + }); + + describe('should get merged actions with live view', () => { + it.each([ + [ + 'live' as const, + { + tap_action: { + action: 'navigate', + navigation_path: '2', + }, + }, + ], + [ + 'clips' as const, + { + tap_action: { + action: 'navigate', + navigation_path: '3', + }, + }, + ], + [ + 'clip' as const, + { + tap_action: { + action: 'navigate', + navigation_path: '4', + }, + }, + ], + [ + 'image' as const, + { + tap_action: { + action: 'navigate', + navigation_path: '5', + }, + }, + ], + ['timeline' as const, {}], + ])('%s', (viewName: FrigateCardView, result: Record) => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ view: viewName }), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig(config), + ); + + const manager = new ActionsManager(api); + + expect(manager.getMergedActions()).toEqual(result); + }); + }); + }); + + // @vitest-environment jsdom + describe('handleInteractionEvent', () => { + beforeEach(() => { + vi.restoreAllMocks(); + }); + + it('should handle interaction', () => { + const api = createCardAPI(); + const element = document.createElement('div'); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); + vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + actions: { + tap_action: createLogAction("Hello, world!"), + }, + }, + }), + ); + const manager = new ActionsManager(api); + + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined); + manager.handleInteractionEvent( + new CustomEvent('event', { detail: { action: 'tap' } }), + ); + expect(consoleSpy).toBeCalled(); + }); + + describe('should handle unexpected interactions', () => { + it.each([['malformed_type_of_tap' as const], ['double_tap' as const]])( + '%s', + (interaction: string) => { + const api = createCardAPI(); + const element = document.createElement('div'); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); + vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + actions: { + tap_action: createLogAction("Hello, world!"), + }, + }, + }), + ); + const manager = new ActionsManager(api); + + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined); + manager.handleInteractionEvent( + new CustomEvent('event', { + detail: { action: interaction as unknown as InteractionName }, + }), + ); + expect(consoleSpy).not.toBeCalled(); + }, + ); + }); + }); + + describe('handleCustomActionEvent', () => { + beforeEach(() => { + vi.restoreAllMocks(); + }); + + it('should handle event', () => { + const action = createLogAction("Hello, world!"); + const event = new CustomEvent('ll-custom', { + detail: action, + }); + + const api = createCardAPI(); + const manager = new ActionsManager(api); + + const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined); + manager.handleCustomActionEvent(event); + expect(consoleSpy).toBeCalled(); + }); + + it('should not handle event without detail', () => { + const manager = new ActionsManager(createCardAPI()); + + const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined); + manager.handleCustomActionEvent(new Event('ll-custom')); + expect(consoleSpy).not.toBeCalled(); + }); + }); + + describe('handleActionExecutionRequestEvent', () => { + it('should execute actions', async () => { + const api = createCardAPI(); + const manager = new ActionsManager(api); + + const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined); + await manager.handleActionExecutionRequestEvent( + new CustomEvent('frigate-card:action:execution-request', { + detail: { action: createLogAction("Hello, world!") }, + }), + ); + expect(consoleSpy).toBeCalled(); + }); + }); + + describe('executeAction', () => { + it('should execute actions', async () => { + const api = createCardAPI(); + const manager = new ActionsManager(api); + + const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined); + await manager.executeActions(createLogAction("Hello, world!")); + expect(consoleSpy).toBeCalled(); + }); + }); + + describe('uninitialize', () => { + beforeAll(() => { + vi.useFakeTimers(); + }); + afterAll(() => { + vi.useRealTimers(); + }); + + it('should stop actions', async () => { + const api = createCardAPI(); + const manager = new ActionsManager(api); + + const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined); + const promise = manager.executeActions([ + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + createAction({ + frigate_card_action: 'sleep', + duration: { + m: 1, + }, + })!, + createLogAction("Hello, world!"), + ]); + + // Stop inflight actions. + manager.uninitialize(); + + // Advance timers (causes the sleep to end). + vi.runOnlyPendingTimers(); + + await promise; + + // Action set will not continue. + expect(consoleSpy).not.toBeCalled(); + }); + }); +}); diff --git a/tests/card-controller/actions/actions/base.test.ts b/tests/card-controller/actions/actions/base.test.ts new file mode 100644 index 00000000..72ec9e72 --- /dev/null +++ b/tests/card-controller/actions/actions/base.test.ts @@ -0,0 +1,19 @@ +import { it } from 'vitest'; +import { BaseAction } from '../../../../src/card-controller/actions/actions/base'; +import { createCardAPI } from '../../../test-utils'; + +it('should construct', async () => { + const api = createCardAPI(); + const action = new BaseAction( + {}, + { + action: 'fire-dom-event', + }, + ); + + await action.execute(api); + await action.stop(); + + // These methods have no observable effect on the base class, so this test is + // currently only providing coverage and proof of no exceptions! +}); diff --git a/tests/card-controller/actions/actions/camera-select.test.ts b/tests/card-controller/actions/actions/camera-select.test.ts new file mode 100644 index 00000000..7c2abc2c --- /dev/null +++ b/tests/card-controller/actions/actions/camera-select.test.ts @@ -0,0 +1,163 @@ +import { describe, expect, it, vi } from 'vitest'; +import { CameraSelectAction } from '../../../../src/card-controller/actions/actions/camera-select'; +import { createCardAPI, createConfig, createView } from '../../../test-utils'; + +describe('should handle camera_select action', () => { + it('with valid camera and view', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); + vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); + + const action = new CameraSelectAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + camera: 'camera', + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewByParameters).toBeCalledWith( + expect.objectContaining({ + viewName: 'live', + cameraID: 'camera', + failSafe: true, + }), + ); + }); + + it('without config', async () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(null); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + view: 'timeline', + }), + ); + vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); + + const action = new CameraSelectAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + camera: 'camera', + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewByParameters).toBeCalledWith( + expect.objectContaining({ + viewName: 'timeline', + cameraID: 'camera', + failSafe: true, + }), + ); + }); + + it('with target view', async () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + // Change to clips view when the camera changes. + camera_select: 'clips', + }, + }), + ); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + view: 'live', + }), + ); + vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); + + const action = new CameraSelectAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + camera: 'camera', + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewByParameters).toBeCalledWith( + expect.objectContaining({ + viewName: 'clips', + cameraID: 'camera', + failSafe: true, + }), + ); + }); + + it('with triggered camera', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); + vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); + vi.mocked(api.getTriggersManager().getMostRecentlyTriggeredCameraID).mockReturnValue( + 'camera', + ); + + const action = new CameraSelectAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + triggered: true, + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewByParameters).toBeCalledWith( + expect.objectContaining({ + viewName: 'live', + cameraID: 'camera', + failSafe: true, + }), + ); + }); + + it('without camera or triggered camera', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); + vi.mocked(api.getViewManager().isViewSupportedByCamera).mockReturnValue(true); + vi.mocked(api.getTriggersManager().getMostRecentlyTriggeredCameraID).mockReturnValue( + 'camera', + ); + + const action = new CameraSelectAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + }); + + it('without a current view', async () => { + const api = createCardAPI(); + + const action = new CameraSelectAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'camera_select', + camera: 'camera', + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + }); +}); diff --git a/tests/card-controller/actions/actions/camera-ui.test.ts b/tests/card-controller/actions/actions/camera-ui.test.ts new file mode 100644 index 00000000..09703fb1 --- /dev/null +++ b/tests/card-controller/actions/actions/camera-ui.test.ts @@ -0,0 +1,18 @@ +import { expect, it } from 'vitest'; +import { CameraUIAction } from '../../../../src/card-controller/actions/actions/camera-ui'; +import { createCardAPI } from '../../../test-utils'; + +it('should handle camera_ui action', async () => { + const api = createCardAPI(); + const action = new CameraUIAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'camera_ui', + }, + ); + + await action.execute(api); + + expect(api.getCameraURLManager().openURL).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/default.test.ts b/tests/card-controller/actions/actions/default.test.ts new file mode 100644 index 00000000..ac9692c8 --- /dev/null +++ b/tests/card-controller/actions/actions/default.test.ts @@ -0,0 +1,15 @@ +import { expect, it } from "vitest"; +import { DefaultAction } from "../../../../src/card-controller/actions/actions/default"; +import { createCardAPI } from "../../../test-utils"; + +it('should handle default action', async () => { + const api = createCardAPI(); + const action = new DefaultAction({}, { + action: 'fire-dom-event', + frigate_card_action: 'default', + }); + + await action.execute(api); + + expect(api.getViewManager().setViewDefault).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/display-mode-select.test.ts b/tests/card-controller/actions/actions/display-mode-select.test.ts new file mode 100644 index 00000000..1e999a8b --- /dev/null +++ b/tests/card-controller/actions/actions/display-mode-select.test.ts @@ -0,0 +1,16 @@ +import { expect, it } from "vitest"; +import { DisplayModeSelectAction } from "../../../../src/card-controller/actions/actions/display-mode-select"; +import { createCardAPI } from "../../../test-utils"; + +it('should handle default action', async () => { + const api = createCardAPI(); + const action = new DisplayModeSelectAction({}, { + action: 'fire-dom-event', + frigate_card_action: 'display_mode_select', + display_mode: 'grid', + }); + + await action.execute(api); + + expect(api.getViewManager().setViewWithNewDisplayMode).toBeCalledWith('grid'); +}); diff --git a/tests/card-controller/actions/actions/download.test.ts b/tests/card-controller/actions/actions/download.test.ts new file mode 100644 index 00000000..3e9b321d --- /dev/null +++ b/tests/card-controller/actions/actions/download.test.ts @@ -0,0 +1,18 @@ +import { expect, it } from 'vitest'; +import { DownloadAction } from '../../../../src/card-controller/actions/actions/download'; +import { createCardAPI } from '../../../test-utils'; + +it('should handle download action', async () => { + const api = createCardAPI(); + const action = new DownloadAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'download', + }, + ); + + await action.execute(api); + + expect(api.getDownloadManager().downloadViewerMedia).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/expand.test.ts b/tests/card-controller/actions/actions/expand.test.ts new file mode 100644 index 00000000..1a3ac265 --- /dev/null +++ b/tests/card-controller/actions/actions/expand.test.ts @@ -0,0 +1,18 @@ +import { expect, it } from 'vitest'; +import { ExpandAction } from '../../../../src/card-controller/actions/actions/expand'; +import { createCardAPI } from '../../../test-utils'; + +it('should handle expand action', async () => { + const api = createCardAPI(); + const action = new ExpandAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'expand', + }, + ); + + await action.execute(api); + + expect(api.getExpandManager().toggleExpanded).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/fullscreen.test.ts b/tests/card-controller/actions/actions/fullscreen.test.ts new file mode 100644 index 00000000..d678b1a3 --- /dev/null +++ b/tests/card-controller/actions/actions/fullscreen.test.ts @@ -0,0 +1,18 @@ +import { expect, it } from 'vitest'; +import { FullscreenAction } from '../../../../src/card-controller/actions/actions/fullscreen'; +import { createCardAPI } from '../../../test-utils'; + +it('should handle fullscreen action', async () => { + const api = createCardAPI(); + const action = new FullscreenAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'fullscreen', + }, + ); + + await action.execute(api); + + expect(api.getFullscreenManager().toggleFullscreen).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/generic.test.ts b/tests/card-controller/actions/actions/generic.test.ts new file mode 100644 index 00000000..ae84a103 --- /dev/null +++ b/tests/card-controller/actions/actions/generic.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, it, vi } from 'vitest'; +import { createCardAPI, createHASS, createLitElement } from '../../../test-utils'; +import { GenericAction } from '../../../../src/card-controller/actions/actions/generic'; +import { handleActionConfig } from '@dermotduffy/custom-card-helpers'; + +vi.mock('@dermotduffy/custom-card-helpers'); + +describe('should handle generic action', () => { + it('without hass', async () => { + const api = createCardAPI(); + const action = new GenericAction( + {}, + { + action: 'fire-dom-event', + }, + ); + + await action.execute(api); + + expect(handleActionConfig).not.toBeCalled(); + }); + + // @vitest-environment jsdom + it('with hass', async () => { + const api = createCardAPI(); + const hass = createHASS(); + const element = createLitElement(); + vi.mocked(api.getCardElementManager()).getElement.mockReturnValue(element); + vi.mocked(api.getHASSManager()).getHASS.mockReturnValue(hass); + const action = new GenericAction( + {}, + { + action: 'fire-dom-event', + }, + ); + + await action.execute(api); + + expect(handleActionConfig).toBeCalledWith( + element, + hass, + {}, + { action: 'fire-dom-event' }, + ); + }); +}); diff --git a/tests/card-controller/actions/actions/log.test.ts b/tests/card-controller/actions/actions/log.test.ts new file mode 100644 index 00000000..889f32c8 --- /dev/null +++ b/tests/card-controller/actions/actions/log.test.ts @@ -0,0 +1,24 @@ +import { afterEach, expect, it, vi } from 'vitest'; +import { LogAction } from '../../../../src/card-controller/actions/actions/log'; +import { createCardAPI } from '../../../test-utils'; + +afterEach(() => { + vi.resetAllMocks(); +}); + +it('should handle log action', async () => { + const api = createCardAPI(); + const action = new LogAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'log', + message: 'Hello, world!', + level: 'warn', + }, + ); + + const spy = vi.spyOn(global.console, 'warn').mockImplementation(() => true); + await action.execute(api); + expect(spy).toBeCalledWith('Hello, world!'); +}); diff --git a/tests/card-controller/actions/actions/media-player.test.ts b/tests/card-controller/actions/actions/media-player.test.ts new file mode 100644 index 00000000..49a539e9 --- /dev/null +++ b/tests/card-controller/actions/actions/media-player.test.ts @@ -0,0 +1,104 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { MediaPlayerAction } from '../../../../src/card-controller/actions/actions/media-player'; +import { createCardAPI, createView, createViewWithMedia } from '../../../test-utils'; + +afterEach(() => { + vi.resetAllMocks(); +}); + +describe('should handle media_player action', () => { + it('to stop', async () => { + const api = createCardAPI(); + + const action = new MediaPlayerAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'media_player', + media_player_action: 'stop', + media_player: 'this_is_a_media_player', + }, + ); + + await action.execute(api); + + expect(api.getMediaPlayerManager().stop).toBeCalledWith('this_is_a_media_player'); + }); + + it('to play live', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + camera: 'camera', + view: 'live', + }), + ); + + const action = new MediaPlayerAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'media_player', + media_player_action: 'play', + media_player: 'this_is_a_media_player', + }, + ); + + await action.execute(api); + + expect(api.getMediaPlayerManager().playLive).toBeCalledWith( + 'this_is_a_media_player', + 'camera', + ); + }); + + it('to play media', async () => { + const api = createCardAPI(); + const view = createViewWithMedia({ + camera: 'camera', + view: 'media', + }); + + vi.mocked(api.getViewManager().getView).mockReturnValue(view); + + const action = new MediaPlayerAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'media_player', + media_player_action: 'play', + media_player: 'this_is_a_media_player', + }, + ); + + await action.execute(api); + + expect(api.getMediaPlayerManager().playMedia).toBeCalledWith( + 'this_is_a_media_player', + view.queryResults?.getSelectedResult(), + ); + }); + + it('to play media without selected media', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + view: 'media', + }), + ); + + const action = new MediaPlayerAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'media_player', + media_player_action: 'play', + media_player: 'this_is_a_media_player', + }, + ); + + await action.execute(api); + + expect(api.getMediaPlayerManager().playMedia).not.toBeCalled(); + }); +}); diff --git a/tests/card-controller/actions/actions/menu-toggle.test.ts b/tests/card-controller/actions/actions/menu-toggle.test.ts new file mode 100644 index 00000000..c9d1d276 --- /dev/null +++ b/tests/card-controller/actions/actions/menu-toggle.test.ts @@ -0,0 +1,18 @@ +import { expect, it } from 'vitest'; +import { MenuToggleAction } from '../../../../src/card-controller/actions/actions/menu-toggle'; +import { createCardAPI } from '../../../test-utils'; + +it('should handle menu toggle action', async () => { + const api = createCardAPI(); + const action = new MenuToggleAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'menu_toggle', + }, + ); + + await action.execute(api); + + expect(api.getCardElementManager().toggleMenu).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/microphone-mute.test.ts b/tests/card-controller/actions/actions/microphone-mute.test.ts new file mode 100644 index 00000000..6b343c48 --- /dev/null +++ b/tests/card-controller/actions/actions/microphone-mute.test.ts @@ -0,0 +1,18 @@ +import { expect, it } from 'vitest'; +import { MicrophoneMuteAction } from '../../../../src/card-controller/actions/actions/microphone-mute'; +import { createCardAPI } from '../../../test-utils'; + +it('should handle microphone_mute action', async () => { + const api = createCardAPI(); + const action = new MicrophoneMuteAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'microphone_mute', + }, + ); + + await action.execute(api); + + expect(api.getMicrophoneManager().mute).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/microphone-unmute.test.ts b/tests/card-controller/actions/actions/microphone-unmute.test.ts new file mode 100644 index 00000000..dd53b923 --- /dev/null +++ b/tests/card-controller/actions/actions/microphone-unmute.test.ts @@ -0,0 +1,18 @@ +import { expect, it } from 'vitest'; +import { createCardAPI } from '../../../test-utils'; +import { MicrophoneUnmuteAction } from '../../../../src/card-controller/actions/actions/microphone-unmute'; + +it('should handle microphone_unmute action', async () => { + const api = createCardAPI(); + const action = new MicrophoneUnmuteAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'microphone_unmute', + }, + ); + + await action.execute(api); + + expect(api.getMicrophoneManager().unmute).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/mute.test.ts b/tests/card-controller/actions/actions/mute.test.ts new file mode 100644 index 00000000..5ba80cce --- /dev/null +++ b/tests/card-controller/actions/actions/mute.test.ts @@ -0,0 +1,26 @@ +import { expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { MuteAction } from '../../../../src/card-controller/actions/actions/mute'; +import { FrigateCardMediaPlayer } from '../../../../src/types'; +import { createCardAPI, createMediaLoadedInfo } from '../../../test-utils'; + +it('should handle mute action', async () => { + const api = createCardAPI(); + const player = mock(); + vi.mocked(api.getMediaLoadedInfoManager().get).mockReturnValue( + createMediaLoadedInfo({ + player: player, + }), + ); + const action = new MuteAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'mute', + }, + ); + + await action.execute(api); + + expect(player.mute).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/pause.test.ts b/tests/card-controller/actions/actions/pause.test.ts new file mode 100644 index 00000000..733bf8a0 --- /dev/null +++ b/tests/card-controller/actions/actions/pause.test.ts @@ -0,0 +1,26 @@ +import { expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { PauseAction } from '../../../../src/card-controller/actions/actions/pause'; +import { FrigateCardMediaPlayer } from '../../../../src/types'; +import { createCardAPI, createMediaLoadedInfo } from '../../../test-utils'; + +it('should handle pause action', async () => { + const api = createCardAPI(); + const player = mock(); + vi.mocked(api.getMediaLoadedInfoManager().get).mockReturnValue( + createMediaLoadedInfo({ + player: player, + }), + ); + const action = new PauseAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'pause', + }, + ); + + await action.execute(api); + + expect(player.pause).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/play.test.ts b/tests/card-controller/actions/actions/play.test.ts new file mode 100644 index 00000000..f0f3879e --- /dev/null +++ b/tests/card-controller/actions/actions/play.test.ts @@ -0,0 +1,26 @@ +import { expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { PlayAction } from '../../../../src/card-controller/actions/actions/play'; +import { FrigateCardMediaPlayer } from '../../../../src/types'; +import { createCardAPI, createMediaLoadedInfo } from '../../../test-utils'; + +it('should handle play action', async () => { + const api = createCardAPI(); + const player = mock(); + vi.mocked(api.getMediaLoadedInfoManager().get).mockReturnValue( + createMediaLoadedInfo({ + player: player, + }), + ); + const action = new PlayAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'play', + }, + ); + + await action.execute(api); + + expect(player.play).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/ptz-controls.test.ts b/tests/card-controller/actions/actions/ptz-controls.test.ts new file mode 100644 index 00000000..7ab107fb --- /dev/null +++ b/tests/card-controller/actions/actions/ptz-controls.test.ts @@ -0,0 +1,21 @@ +import { expect, it } from 'vitest'; +import { createCardAPI } from '../../../test-utils'; +import { PTZControlsAction } from '../../../../src/card-controller/actions/actions/ptz-controls'; + +it('should handle ptz_controls action', async () => { + const api = createCardAPI(); + const action = new PTZControlsAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_controls', + enabled: true, + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith( + expect.objectContaining({ ptzControls: { enabled: true } }), + ); +}); diff --git a/tests/card-controller/actions/actions/ptz-digital.test.ts b/tests/card-controller/actions/actions/ptz-digital.test.ts new file mode 100644 index 00000000..7652fbc3 --- /dev/null +++ b/tests/card-controller/actions/actions/ptz-digital.test.ts @@ -0,0 +1,479 @@ +import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; +import { PTZDigitalAction } from '../../../../src/card-controller/actions/actions/ptz-digital'; +import { + PartialZoomSettings, + ZoomSettingsObserved, +} from '../../../../src/components-lib/zoom/types'; +import { PTZAction } from '../../../../src/config/ptz'; +import { createCardAPI, createView } from '../../../test-utils'; + +describe('should handle ptz digital action', () => { + const defaultSettings = { + pan: { + x: 50, + y: 50, + }, + zoom: 1, + }; + + const createObserved = ( + observed?: Partial, + ): ZoomSettingsObserved => ({ + ...defaultSettings, + isDefault: true, + unzoomed: true, + ...observed, + }); + + it('should honor absolute parameters', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); + + const action = new PTZDigitalAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_digital', + absolute: { + zoom: 2, + pan: { + x: 3, + y: 4, + }, + }, + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith({ + zoom: { + camera: { + observed: undefined, + requested: { + pan: { + x: 3, + y: 4, + }, + zoom: 2, + }, + }, + }, + }); + }); + + it('should return to default without absolute parameters or action', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); + + const action = new PTZDigitalAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_digital', + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith({ + zoom: { + camera: { + observed: undefined, + requested: {}, + }, + }, + }); + }); + + it('should do nothing without a view', async () => { + const api = createCardAPI(); + + const action = new PTZDigitalAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_digital', + ptz_action: 'left', + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewWithMergedContext).not.toBeCalledWith(); + }); + + it('should do nothing without a camera', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + // There is no media associated with a timeline, so there's no camera to + // change the PTZ settings for. + view: 'timeline', + }), + ); + + const action = new PTZDigitalAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_digital', + ptz_action: 'left', + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewWithMergedContext).not.toBeCalled(); + }); + + describe('should honor ptz_action', () => { + it.each([ + [ + 'zoom_in', + 'zoom_in' as const, + { + zoom: 1.1, + }, + createObserved(), + ], + [ + 'zoom_in at maximum zoom', + 'zoom_in' as const, + { + zoom: 10, + }, + createObserved({ + zoom: 10, + }), + ], + [ + 'zoom_out', + 'zoom_out' as const, + { + zoom: 1.9, + }, + createObserved({ + zoom: 2, + }), + ], + [ + 'zoom_out at minimum zoom', + 'zoom_out' as const, + { + zoom: 1, + }, + createObserved({ + zoom: 1, + }), + ], + [ + 'left', + 'left' as const, + { + pan: { + x: 45, + y: 50, + }, + }, + createObserved({ + pan: { + x: 50, + y: 50, + }, + }), + ], + [ + 'left at left edge', + 'left' as const, + { + pan: { + x: 0, + y: 50, + }, + }, + createObserved({ + pan: { + x: 0, + y: 50, + }, + }), + ], + [ + 'right', + 'right' as const, + { + pan: { + x: 55, + y: 50, + }, + }, + createObserved({ + pan: { + x: 50, + y: 50, + }, + }), + ], + [ + 'right at right edge', + 'right' as const, + { + pan: { + x: 100, + y: 50, + }, + }, + createObserved({ + pan: { + x: 100, + y: 50, + }, + }), + ], + [ + 'up', + 'up' as const, + { + pan: { + x: 50, + y: 45, + }, + }, + createObserved({ + pan: { + x: 50, + y: 50, + }, + }), + ], + [ + 'up at top edge', + 'up' as const, + { + pan: { + x: 50, + y: 0, + }, + }, + createObserved({ + pan: { + x: 50, + y: 0, + }, + }), + ], + [ + 'down', + 'down' as const, + { + pan: { + x: 50, + y: 55, + }, + }, + createObserved({ + pan: { + x: 50, + y: 50, + }, + }), + ], + [ + 'down at bottom edge', + 'down' as const, + { + pan: { + x: 50, + y: 100, + }, + }, + createObserved({ + pan: { + x: 50, + y: 100, + }, + }), + ], + [ + 'action with undefined observed', + 'down' as const, + { + pan: { + x: 50, + y: 55, + }, + }, + ], + ])( + '%s', + async ( + _testTitle: string, + ptzAction: PTZAction, + expectedSettings: PartialZoomSettings, + current?: ZoomSettingsObserved, + ) => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + context: { + zoom: { + camera: { + observed: current, + }, + }, + }, + }), + ); + + const action = new PTZDigitalAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_digital', + ptz_action: ptzAction, + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewWithMergedContext).toBeCalledWith({ + zoom: { + camera: { + observed: undefined, + requested: { + ...defaultSettings, + ...expectedSettings, + }, + }, + }, + }); + }, + ); + }); + + // @vitest-environment jsdom + describe('should honor ptz_phase', () => { + beforeAll(() => { + vi.useFakeTimers(); + }); + + afterAll(() => { + vi.useRealTimers(); + }); + + it('start', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); + + const action = new PTZDigitalAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_digital', + ptz_action: 'right', + ptz_phase: 'start', + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewWithMergedContext).toHaveBeenLastCalledWith({ + zoom: { + camera: { + observed: undefined, + requested: { + ...defaultSettings, + pan: { + x: 55, + y: 50, + }, + }, + }, + }, + }); + + // Update the context to reflect the first step. + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + context: { + zoom: { + camera: { + observed: createObserved({ + pan: { + x: 55, + y: 50, + }, + }), + }, + }, + }, + }), + ); + + vi.runOnlyPendingTimers(); + + expect(api.getViewManager().setViewWithMergedContext).toHaveBeenLastCalledWith({ + zoom: { + camera: { + observed: undefined, + requested: { + ...defaultSettings, + pan: { + x: 60, + y: 50, + }, + }, + }, + }, + }); + expect(api.getViewManager().setViewWithMergedContext).toBeCalledTimes(2); + + action.stop(); + vi.runOnlyPendingTimers(); + + expect(api.getViewManager().setViewWithMergedContext).toBeCalledTimes(2); + }); + + it('stop', async () => { + const api = createCardAPI(); + const context = {}; + vi.mocked(api.getViewManager().getView).mockReturnValue(createView()); + + const startAction = new PTZDigitalAction(context, { + action: 'fire-dom-event', + frigate_card_action: 'ptz_digital', + ptz_action: 'right', + ptz_phase: 'start', + }); + await startAction.execute(api); + + expect(api.getViewManager().setViewWithMergedContext).toHaveBeenLastCalledWith({ + zoom: { + camera: { + observed: undefined, + requested: { + ...defaultSettings, + pan: { + x: 55, + y: 50, + }, + }, + }, + }, + }); + expect(api.getViewManager().setViewWithMergedContext).toBeCalledTimes(1); + + const stopAction = new PTZDigitalAction(context, { + action: 'fire-dom-event', + frigate_card_action: 'ptz_digital', + ptz_phase: 'stop', + }); + await stopAction.execute(api); + + vi.runOnlyPendingTimers(); + + expect(api.getViewManager().setViewWithMergedContext).toBeCalledTimes(1); + }); + }); +}); diff --git a/tests/card-controller/actions/actions/ptz-multi.test.ts b/tests/card-controller/actions/actions/ptz-multi.test.ts new file mode 100644 index 00000000..92ee7590 --- /dev/null +++ b/tests/card-controller/actions/actions/ptz-multi.test.ts @@ -0,0 +1,150 @@ +import { describe, expect, it, vi } from 'vitest'; +import { Capabilities } from '../../../../src/camera-manager/capabilities'; +import { PTZMultiAction } from '../../../../src/card-controller/actions/actions/ptz-multi'; +import { + createCameraManager, + createCardAPI, + createStore, + createView, +} from '../../../test-utils'; + +describe('should handle ptz multi action', () => { + describe.each([ + ['with explicit target_id', 'camera.office'], + ['without explicit target_id', null], + ])('%s', async (_testTitle: string, targetID: string | null) => { + it('should use real ptz when camera has ptz support', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + camera: 'camera.office', + }), + ); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + + const action = new PTZMultiAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + ptz_action: 'left', + ...(targetID && { target_id: targetID }), + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).toBeCalledWith( + 'camera.office', + 'left', + { + phase: undefined, + preset: undefined, + }, + ); + expect(api.getViewManager().setViewWithMergedContext).not.toBeCalled(); + }); + + it('should use digital ptz when camera does not have ptz support', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + camera: 'camera.office', + }), + ); + const store = createStore([ + { + cameraID: 'camera.office', + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + + const action = new PTZMultiAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + ptz_action: 'right', + ...(targetID && { target_id: targetID }), + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).not.toBeCalled(); + expect(api.getViewManager().setViewWithMergedContext).toHaveBeenLastCalledWith({ + zoom: { + 'camera.office': { + observed: undefined, + requested: expect.objectContaining({ + pan: { + x: 55, + y: 50, + }, + zoom: 1, + }), + }, + }, + }); + }); + }); + + it('should do nothing without a view or explicit target_id', async () => { + const api = createCardAPI(); + const store = createStore([ + { + cameraID: 'camera.office', + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + + const action = new PTZMultiAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + ptz_action: 'right', + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).not.toBeCalled(); + expect(api.getViewManager().setViewWithMergedContext).not.toBeCalled(); + }); + + it('should do nothing with a media-less view without an explicit target_id', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + view: 'timeline', + }), + ); + const store = createStore([ + { + cameraID: 'camera.office', + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + + const action = new PTZMultiAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + ptz_action: 'right', + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).not.toBeCalled(); + expect(api.getViewManager().setViewWithMergedContext).not.toBeCalled(); + }); +}); diff --git a/tests/card-controller/actions/actions/ptz.test.ts b/tests/card-controller/actions/actions/ptz.test.ts new file mode 100644 index 00000000..7217d4d8 --- /dev/null +++ b/tests/card-controller/actions/actions/ptz.test.ts @@ -0,0 +1,513 @@ +import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; +import { PTZAction } from '../../../../src/card-controller/actions/actions/ptz'; +import { + createCameraConfig, + createCameraManager, + createCardAPI, + createStore, + createView, +} from '../../../test-utils'; +import { Capabilities } from '../../../../src/camera-manager/capabilities'; + +describe('should handle ptz action', () => { + it('should execute simple action', async () => { + const api = createCardAPI(); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + camera: 'camera.office', + }), + ); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + + const action = new PTZAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + camera: 'camera.office', + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).toBeCalledWith( + 'camera.office', + 'left', + { + phase: undefined, + preset: undefined, + }, + ); + }); + + describe('without explicit camera', () => { + it('when current camera supports PTZ', async () => { + const api = createCardAPI(); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ camera: 'camera.office' }), + ); + + const action = new PTZAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).toBeCalledWith( + 'camera.office', + 'left', + { + phase: undefined, + preset: undefined, + }, + ); + }); + + it('when substream supports PTZ', async () => { + const api = createCardAPI(); + const store = createStore([ + { + cameraID: 'camera.office', + config: createCameraConfig({ + dependencies: { cameras: ['camera.office_hd'] }, + }), + }, + { + cameraID: 'camera.office_hd', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ + camera: 'camera.office', + context: { + live: { + overrides: new Map([['camera.office', 'camera.office_hd']]), + }, + }, + }), + ); + + const action = new PTZAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).toBeCalledWith( + 'camera.office_hd', + 'left', + { + phase: undefined, + preset: undefined, + }, + ); + }); + + it('when no camera supports PTZ', async () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ camera: 'camera.office' }), + ); + + const action = new PTZAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).not.toBeCalled(); + }); + }); + + it('when there is no view', async () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + + const action = new PTZAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).not.toBeCalled(); + }); + + describe('when there is no action', () => { + it('should call first preset', async () => { + const api = createCardAPI(); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ ptz: { presets: ['home'] } }), + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ camera: 'camera.office' }), + ); + + const action = new PTZAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).toBeCalledWith( + 'camera.office', + 'preset', + { + phase: undefined, + preset: 'home', + }, + ); + }); + + it('should not call preset when there are no presets', async () => { + const api = createCardAPI(); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ + ptz: { + left: ['relative'], + presets: [], + }, + }), + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ camera: 'camera.office' }), + ); + + const action = new PTZAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).not.toBeCalled(); + }); + }); + + it('should execute preset', async () => { + const api = createCardAPI(); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ + ptz: { + presets: ['window'], + }, + }), + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ camera: 'camera.office' }), + ); + + const action = new PTZAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'preset', + ptz_preset: 'window', + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).toBeCalledWith( + 'camera.office', + 'preset', + { + phase: undefined, + preset: 'window', + }, + ); + }); + + it('should execute action with phase', async () => { + const api = createCardAPI(); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ + ptz: { + left: ['continuous'], + }, + }), + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ camera: 'camera.office' }), + ); + + const action = new PTZAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + ptz_phase: 'start', + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).toBeCalledWith( + 'camera.office', + 'left', + { + phase: 'start', + }, + ); + }); + + // @vitest-environment jsdom + describe('when relative is requested but unsupported', () => { + beforeAll(() => { + vi.useFakeTimers(); + }); + + afterAll(() => { + vi.useRealTimers(); + }); + + it('should emulate relative', async () => { + const api = createCardAPI(); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ + ptz: { + left: ['continuous'], + }, + }), + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ camera: 'camera.office' }), + ); + + const action = new PTZAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + }, + ); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).toBeCalledWith( + 'camera.office', + 'left', + { + phase: 'start', + }, + ); + + vi.runOnlyPendingTimers(); + expect(api.getCameraManager().executePTZAction).toBeCalledWith( + 'camera.office', + 'left', + { + phase: 'stop', + }, + ); + }); + + it('should honor stop', async () => { + const api = createCardAPI(); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ + ptz: { + left: ['continuous'], + }, + }), + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ camera: 'camera.office' }), + ); + + const context = {}; + const action = new PTZAction(context, { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + }); + + await action.execute(api); + + expect(api.getCameraManager().executePTZAction).toBeCalledTimes(1); + + action.stop(); + vi.runOnlyPendingTimers(); + + expect(api.getCameraManager().executePTZAction).toBeCalledTimes(1); + }); + }); + + describe('when continuous is requested but unsupported', () => { + beforeAll(() => { + vi.useFakeTimers(); + }); + + afterAll(() => { + vi.useRealTimers(); + }); + + it('should emulate continuous', async () => { + const api = createCardAPI(); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ + ptz: { + left: ['relative'], + }, + }), + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ camera: 'camera.office' }), + ); + + const context = {}; + const startAction = new PTZAction( + context, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + ptz_phase: 'start', + }, + ); + await startAction.execute(api); + + expect(api.getCameraManager().executePTZAction).toBeCalledWith( + 'camera.office', + 'left', + { + phase: undefined, + }, + ); + expect(api.getCameraManager().executePTZAction).toBeCalledTimes(1); + + await vi.runOnlyPendingTimersAsync() + expect(api.getCameraManager().executePTZAction).toBeCalledTimes(2); + + await vi.runOnlyPendingTimersAsync() + expect(api.getCameraManager().executePTZAction).toBeCalledTimes(3); + + const stopAction = new PTZAction( + context, + { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + ptz_phase: 'stop', + }, + ); + await stopAction.execute(api); + + // There should be no additional calls. + await vi.runOnlyPendingTimersAsync() + expect(api.getCameraManager().executePTZAction).toBeCalledTimes(3); + }); + + it('should honor stop', async () => { + const api = createCardAPI(); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ + ptz: { + left: ['relative'], + }, + }), + }, + ]); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager(store)); + vi.mocked(api.getViewManager().getView).mockReturnValue( + createView({ camera: 'camera.office' }), + ); + + const context = {}; + const action = new PTZAction(context, { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + ptz_phase: 'start', + }); + + await action.execute(api); + expect(api.getCameraManager().executePTZAction).toBeCalledTimes(1); + + await vi.runOnlyPendingTimersAsync() + expect(api.getCameraManager().executePTZAction).toBeCalledTimes(2); + + action.stop(); + await vi.runOnlyPendingTimersAsync() + + // There should be no additional calls. + expect(api.getCameraManager().executePTZAction).toBeCalledTimes(2); + }); + }); +}); diff --git a/tests/card-controller/actions/actions/screenshot.test.ts b/tests/card-controller/actions/actions/screenshot.test.ts new file mode 100644 index 00000000..3e773aa0 --- /dev/null +++ b/tests/card-controller/actions/actions/screenshot.test.ts @@ -0,0 +1,18 @@ +import { expect, it } from 'vitest'; +import { ScreenshotAction } from '../../../../src/card-controller/actions/actions/screenshot'; +import { createCardAPI } from '../../../test-utils'; + +it('should handle screenshot action', async () => { + const api = createCardAPI(); + const action = new ScreenshotAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'screenshot', + }, + ); + + await action.execute(api); + + expect(api.getDownloadManager().downloadScreenshot).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/set.test.ts b/tests/card-controller/actions/actions/set.test.ts new file mode 100644 index 00000000..e05d6f6a --- /dev/null +++ b/tests/card-controller/actions/actions/set.test.ts @@ -0,0 +1,41 @@ +import { describe, expect, it, vi } from 'vitest'; +import { ActionSet } from '../../../../src/card-controller/actions/actions/set'; +import { createLogAction } from '../../../../src/utils/action'; +import { createCardAPI } from '../../../test-utils'; + +describe('ActionSet', () => { + it('should execute single action', async () => { + const api = createCardAPI(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const set = new ActionSet({}, createLogAction('Hello, world!')); + + const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined); + await set.execute(api); + expect(consoleSpy).toBeCalled(); + }); + + it('should not execute invalid action', async () => { + const api = createCardAPI(); + const set = new ActionSet( + {}, + createLogAction('Hello, world!', { + cardID: 'another-card', + }), + ); + + const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined); + await set.execute(api); + expect(consoleSpy).not.toBeCalled(); + }); + + it('should stop execution', async () => { + const api = createCardAPI(); + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const set = new ActionSet({}, createLogAction('Hello, world!')); + + const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined); + await set.stop(); + await set.execute(api); + expect(consoleSpy).not.toBeCalled(); + }); +}); diff --git a/tests/card-controller/actions/actions/sleep.test.ts b/tests/card-controller/actions/actions/sleep.test.ts new file mode 100644 index 00000000..0515b45a --- /dev/null +++ b/tests/card-controller/actions/actions/sleep.test.ts @@ -0,0 +1,29 @@ +import { afterAll, expect, it, vi } from 'vitest'; +import { createCardAPI } from '../../../test-utils'; +import { SleepAction } from '../../../../src/card-controller/actions/actions/sleep'; +import { sleep } from '../../../../src/utils/basic'; + +vi.mock('../../../../src/utils/basic'); + +afterAll(() => { + vi.restoreAllMocks(); +}); + +it('should handle sleep action', async () => { + const api = createCardAPI(); + const action = new SleepAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'sleep', + duration: { + s: 5, + ms: 200 + }, + }, + ); + + await action.execute(api); + + expect(sleep).toBeCalledWith(5.2); +}); diff --git a/tests/card-controller/actions/actions/substream-off.test.ts b/tests/card-controller/actions/actions/substream-off.test.ts new file mode 100644 index 00000000..149b2d17 --- /dev/null +++ b/tests/card-controller/actions/actions/substream-off.test.ts @@ -0,0 +1,18 @@ +import { expect, it } from 'vitest'; +import { SubstreamOffAction } from '../../../../src/card-controller/actions/actions/substream-off'; +import { createCardAPI } from '../../../test-utils'; + +it('should handle live_substream_off action', async () => { + const api = createCardAPI(); + const action = new SubstreamOffAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_off', + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewWithoutSubstream).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/substream-on.test.ts b/tests/card-controller/actions/actions/substream-on.test.ts new file mode 100644 index 00000000..21ede4bf --- /dev/null +++ b/tests/card-controller/actions/actions/substream-on.test.ts @@ -0,0 +1,18 @@ +import { expect, it } from 'vitest'; +import { SubstreamOnAction } from '../../../../src/card-controller/actions/actions/substream-on'; +import { createCardAPI } from '../../../test-utils'; + +it('should handle live_substream_on action', async () => { + const api = createCardAPI(); + const action = new SubstreamOnAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_on', + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewWithSubstream).toBeCalledWith(); +}); diff --git a/tests/card-controller/actions/actions/substream-select.test.ts b/tests/card-controller/actions/actions/substream-select.test.ts new file mode 100644 index 00000000..7ab186f8 --- /dev/null +++ b/tests/card-controller/actions/actions/substream-select.test.ts @@ -0,0 +1,19 @@ +import { expect, it } from 'vitest'; +import { SubstreamSelectAction } from '../../../../src/card-controller/actions/actions/substream-select'; +import { createCardAPI } from '../../../test-utils'; + +it('should handle live_substream_select action', async () => { + const api = createCardAPI(); + const action = new SubstreamSelectAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'live_substream_select', + camera: 'substream', + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewWithSubstream).toBeCalledWith('substream'); +}); diff --git a/tests/card-controller/actions/actions/unmute.test.ts b/tests/card-controller/actions/actions/unmute.test.ts new file mode 100644 index 00000000..34a59a46 --- /dev/null +++ b/tests/card-controller/actions/actions/unmute.test.ts @@ -0,0 +1,26 @@ +import { expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { UnmuteAction } from '../../../../src/card-controller/actions/actions/unmute'; +import { FrigateCardMediaPlayer } from '../../../../src/types'; +import { createCardAPI, createMediaLoadedInfo } from '../../../test-utils'; + +it('should handle unmute action', async () => { + const api = createCardAPI(); + const player = mock(); + vi.mocked(api.getMediaLoadedInfoManager().get).mockReturnValue( + createMediaLoadedInfo({ + player: player, + }), + ); + const action = new UnmuteAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'unmute', + }, + ); + + await action.execute(api); + + expect(player.unmute).toBeCalled(); +}); diff --git a/tests/card-controller/actions/actions/view.test.ts b/tests/card-controller/actions/actions/view.test.ts new file mode 100644 index 00000000..16f17f79 --- /dev/null +++ b/tests/card-controller/actions/actions/view.test.ts @@ -0,0 +1,36 @@ +import { describe, expect, it } from 'vitest'; +import { ViewAction } from '../../../../src/card-controller/actions/actions/view'; +import { createCardAPI } from '../../../test-utils'; + +describe('should handle view action', () => { + it.each([ + ['clip' as const], + ['clips' as const], + ['diagnostics' as const], + ['image' as const], + ['live' as const], + ['recording' as const], + ['recordings' as const], + ['snapshot' as const], + ['snapshots' as const], + ['timeline' as const], + ])('%s', async (viewName) => { + const api = createCardAPI(); + + const action = new ViewAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: viewName, + }, + ); + + await action.execute(api); + + expect(api.getViewManager().setViewByParameters).toBeCalledWith( + expect.objectContaining({ + viewName: viewName, + }), + ); + }); +}); diff --git a/tests/card-controller/actions/factory.test.ts b/tests/card-controller/actions/factory.test.ts new file mode 100644 index 00000000..84bb954d --- /dev/null +++ b/tests/card-controller/actions/factory.test.ts @@ -0,0 +1,138 @@ +import { describe, expect, it, vi } from 'vitest'; +import { CameraSelectAction } from '../../../src/card-controller/actions/actions/camera-select'; +import { CameraUIAction } from '../../../src/card-controller/actions/actions/camera-ui'; +import { DefaultAction } from '../../../src/card-controller/actions/actions/default'; +import { DisplayModeSelectAction } from '../../../src/card-controller/actions/actions/display-mode-select'; +import { DownloadAction } from '../../../src/card-controller/actions/actions/download'; +import { ExpandAction } from '../../../src/card-controller/actions/actions/expand'; +import { FullscreenAction } from '../../../src/card-controller/actions/actions/fullscreen'; +import { GenericAction } from '../../../src/card-controller/actions/actions/generic'; +import { LogAction } from '../../../src/card-controller/actions/actions/log'; +import { MediaPlayerAction } from '../../../src/card-controller/actions/actions/media-player'; +import { MenuToggleAction } from '../../../src/card-controller/actions/actions/menu-toggle'; +import { MicrophoneMuteAction } from '../../../src/card-controller/actions/actions/microphone-mute'; +import { MicrophoneUnmuteAction } from '../../../src/card-controller/actions/actions/microphone-unmute'; +import { MuteAction } from '../../../src/card-controller/actions/actions/mute'; +import { PauseAction } from '../../../src/card-controller/actions/actions/pause'; +import { PlayAction } from '../../../src/card-controller/actions/actions/play'; +import { PTZAction } from '../../../src/card-controller/actions/actions/ptz'; +import { PTZControlsAction } from '../../../src/card-controller/actions/actions/ptz-controls'; +import { PTZDigitalAction } from '../../../src/card-controller/actions/actions/ptz-digital'; +import { PTZMultiAction } from '../../../src/card-controller/actions/actions/ptz-multi'; +import { ScreenshotAction } from '../../../src/card-controller/actions/actions/screenshot'; +import { SleepAction } from '../../../src/card-controller/actions/actions/sleep'; +import { SubstreamOffAction } from '../../../src/card-controller/actions/actions/substream-off'; +import { SubstreamOnAction } from '../../../src/card-controller/actions/actions/substream-on'; +import { SubstreamSelectAction } from '../../../src/card-controller/actions/actions/substream-select'; +import { UnmuteAction } from '../../../src/card-controller/actions/actions/unmute'; +import { ViewAction } from '../../../src/card-controller/actions/actions/view'; +import { ActionFactory } from '../../../src/card-controller/actions/factory'; +import { FrigateCardCustomAction } from '../../../src/config/types'; + +// @vitest-environment jsdom +describe('ActionFactory', () => { + it('mismatched card-id', () => { + const factory = new ActionFactory(); + expect( + factory.createAction( + {}, + { action: 'fire-dom-event', frigate_card_action: 'clip', card_id: 'card_id' }, + { + cardID: 'different_card_id', + }, + ), + ).toBeNull(); + }); + + describe('generic', () => { + it('non frigate card action', () => { + const factory = new ActionFactory(); + expect(factory.createAction({}, { action: 'fire-dom-event' })).toBeInstanceOf( + GenericAction, + ); + }); + + it('non fire-dom-event', () => { + const factory = new ActionFactory(); + expect(factory.createAction({}, { action: 'more-info' })).toBeInstanceOf( + GenericAction, + ); + }); + }); + + describe('actions', () => { + it.each([ + [{ frigate_card_action: 'camera_select' as const }, CameraSelectAction], + [{ frigate_card_action: 'camera_ui' as const }, CameraUIAction], + [{ frigate_card_action: 'clip' as const }, ViewAction], + [{ frigate_card_action: 'clips' as const }, ViewAction], + [{ frigate_card_action: 'default' as const }, DefaultAction], + [{ frigate_card_action: 'diagnostics' as const }, ViewAction], + [ + { + frigate_card_action: 'display_mode_select' as const, + display_mode: 'single' as const, + }, + DisplayModeSelectAction, + ], + [{ frigate_card_action: 'download' as const }, DownloadAction], + [{ frigate_card_action: 'expand' as const }, ExpandAction], + [{ frigate_card_action: 'fullscreen' as const }, FullscreenAction], + [{ frigate_card_action: 'image' as const }, ViewAction], + [{ frigate_card_action: 'live_substream_off' as const }, SubstreamOffAction], + [{ frigate_card_action: 'live_substream_on' as const }, SubstreamOnAction], + [ + { + frigate_card_action: 'live_substream_select' as const, + camera: 'camera.office', + }, + SubstreamSelectAction, + ], + [{ frigate_card_action: 'live' as const }, ViewAction], + [ + { frigate_card_action: 'log' as const, message: 'Hello, world!' as const }, + LogAction, + ], + [ + { + frigate_card_action: 'media_player' as const, + media_player: 'media_player.foo' as const, + media_player_action: 'play' as const, + }, + MediaPlayerAction, + ], + [{ frigate_card_action: 'menu_toggle' as const }, MenuToggleAction], + [{ frigate_card_action: 'microphone_mute' as const }, MicrophoneMuteAction], + [{ frigate_card_action: 'microphone_unmute' as const }, MicrophoneUnmuteAction], + [{ frigate_card_action: 'mute' as const }, MuteAction], + [{ frigate_card_action: 'pause' as const }, PauseAction], + [{ frigate_card_action: 'play' as const }, PlayAction], + [{ frigate_card_action: 'ptz_digital' as const }, PTZDigitalAction], + [ + { frigate_card_action: 'ptz_multi' as const, ptz_action: 'right' as const }, + PTZMultiAction, + ], + [{ frigate_card_action: 'ptz' as const, ptz_action: 'right' as const }, PTZAction], + [{ frigate_card_action: 'recording' as const }, ViewAction], + [{ frigate_card_action: 'recordings' as const }, ViewAction], + [{ frigate_card_action: 'screenshot' as const }, ScreenshotAction], + [ + { frigate_card_action: 'ptz_controls' as const, enabled: true }, + PTZControlsAction, + ], + [{ frigate_card_action: 'sleep' as const }, SleepAction], + [{ frigate_card_action: 'snapshot' as const }, ViewAction], + [{ frigate_card_action: 'snapshots' as const }, ViewAction], + [{ frigate_card_action: 'timeline' as const }, ViewAction], + [{ frigate_card_action: 'unmute' as const }, UnmuteAction], + ])( + 'frigate_card_action: $frigate_card_action', + (action: Partial, classObject: object) => { + const factory = new ActionFactory(); + expect( + factory.createAction({}, { action: 'fire-dom-event', ...action }), + ).toBeInstanceOf(classObject); + }, + ); + }); +}); diff --git a/tests/card-controller/actions/utils/time-delta.test.ts b/tests/card-controller/actions/utils/time-delta.test.ts new file mode 100644 index 00000000..6efdb63c --- /dev/null +++ b/tests/card-controller/actions/utils/time-delta.test.ts @@ -0,0 +1,20 @@ +import { describe, expect, it } from 'vitest'; +import { timeDeltaToSeconds } from '../../../../src/card-controller/actions/utils/time-delta'; + +describe('timeDeltaToSeconds', () => { + it('hours', () => { + expect(timeDeltaToSeconds({ h: 1 })).toBe(3600); + }); + it('minutes', () => { + expect(timeDeltaToSeconds({ m: 1 })).toBe(60); + }); + it('seconds', () => { + expect(timeDeltaToSeconds({ s: 1 })).toBe(1); + }); + it('milliseconds', () => { + expect(timeDeltaToSeconds({ ms: 1 })).toBe(0.001); + }); + it('combination', () => { + expect(timeDeltaToSeconds({ h: 1, m: 2, s: 3, ms: 4 })).toBe(3723.004); + }); +}); diff --git a/tests/card-controller/automations-manager.test.ts b/tests/card-controller/automations-manager.test.ts index b1e1e4ac..a60fa696 100644 --- a/tests/card-controller/automations-manager.test.ts +++ b/tests/card-controller/automations-manager.test.ts @@ -1,18 +1,25 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { AutomationsManager } from '../../src/card-controller/automations-manager.js'; -import { frigateCardHandleAction } from '../../src/utils/action.js'; -import { createCardAPI, createConfig, createHASS } from '../test-utils.js'; - -vi.mock('../../src/utils/action.js'); +import { createCardAPI, createHASS } from '../test-utils.js'; +import { ActionType } from '../../src/config/types.js'; +import { AuxillaryActionConfig } from '../../src/card-controller/actions/types.js'; describe('AutomationsManager', () => { const actions = [ { - action: 'custom:frigate-card-action', + action: 'fire-dom-event' as const, frigate_card_action: 'clips', }, ]; - const conditions = [{ condition: 'fullscreen', fullscreen: true }]; + const conditions = [{ condition: 'fullscreen' as const, fullscreen: true }]; + const automation = { + conditions: conditions, + actions: actions, + }; + const not_automation = { + conditions: conditions, + actions_not: actions, + }; afterEach(() => { vi.clearAllMocks(); @@ -23,7 +30,8 @@ describe('AutomationsManager', () => { const automationsManager = new AutomationsManager(api); automationsManager.execute(); - expect(frigateCardHandleAction).not.toBeCalled(); + + expect(api.getActionsManager().executeActions).not.toBeCalled(); }); it('should do nothing without automations', () => { @@ -31,105 +39,79 @@ describe('AutomationsManager', () => { vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); const automationsManager = new AutomationsManager(api); - automationsManager.setAutomationsFromConfig(); automationsManager.execute(); - expect(frigateCardHandleAction).not.toBeCalled(); + + expect(api.getActionsManager().executeActions).not.toBeCalled(); }); it('should execute actions', () => { - const config = createConfig({ - automations: [ - { - conditions: conditions, - actions: actions, - }, - ], - }); - const api = createCardAPI(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); - vi.mocked(api.getConfigManager().getNonOverriddenConfig).mockReturnValue(config); const automationsManager = new AutomationsManager(api); - automationsManager.setAutomationsFromConfig(); + automationsManager.addAutomations([automation]); automationsManager.execute(); - expect(frigateCardHandleAction).not.toBeCalled(); + expect(api.getActionsManager().executeActions).not.toBeCalled(); vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(true); automationsManager.execute(); - expect(frigateCardHandleAction).toBeCalledTimes(1); + expect(api.getActionsManager().executeActions).toBeCalledTimes(1); // Automation will not re-fire when condition continues to evaluate the // same. automationsManager.execute(); - expect(frigateCardHandleAction).toBeCalledTimes(1); + expect(api.getActionsManager().executeActions).toBeCalledTimes(1); vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(false); automationsManager.execute(); - expect(frigateCardHandleAction).toBeCalledTimes(1); + expect(api.getActionsManager().executeActions).toBeCalledTimes(1); vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(true); automationsManager.execute(); - expect(frigateCardHandleAction).toBeCalledTimes(2); + expect(api.getActionsManager().executeActions).toBeCalledTimes(2); }); it('should execute actions_not', () => { - const config = createConfig({ - automations: [ - { - conditions: conditions, - actions_not: actions, - }, - ], - }); - const api = createCardAPI(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); - vi.mocked(api.getConfigManager().getNonOverriddenConfig).mockReturnValue(config); vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(false); const automationsManager = new AutomationsManager(api); - automationsManager.setAutomationsFromConfig(); + automationsManager.addAutomations([not_automation]); automationsManager.execute(); - expect(frigateCardHandleAction).toBeCalled(); + expect(api.getActionsManager().executeActions).toBeCalled(); }); it('should prevent automation loops', () => { - const config = createConfig({ - automations: [ - { - conditions: [{ condition: 'fullscreen' as const, fullscreen: true }], - actions: actions, - }, - { - conditions: [{ condition: 'fullscreen' as const, fullscreen: true }], - actions_not: actions, - }, - ], - }); - const api = createCardAPI(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); - vi.mocked(api.getConfigManager().getNonOverriddenConfig).mockReturnValue(config); const automationsManager = new AutomationsManager(api); - automationsManager.setAutomationsFromConfig(); + automationsManager.addAutomations([automation, not_automation]); // Create a setup where one automation action causes another... let evaluation = true; - vi.mocked(frigateCardHandleAction).mockImplementation(() => { - evaluation = !evaluation; - vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue( - evaluation, - ); - automationsManager.execute(); - }); + + vi.mocked(api.getActionsManager().executeActions).mockImplementation( + async ( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _action: ActionType | ActionType[], + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _config?: AuxillaryActionConfig, + ): Promise => { + evaluation = !evaluation; + vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue( + evaluation, + ); + automationsManager.execute(); + }, + ); vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(evaluation); @@ -143,6 +125,24 @@ describe('AutomationsManager', () => { }), ); - expect(frigateCardHandleAction).toBeCalledTimes(10); + expect(api.getActionsManager().executeActions).toBeCalledTimes(10); + }); + + it('should delete automations', () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + + const automationsManager = new AutomationsManager(api); + automationsManager.addAutomations([automation]); + + vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(true); + + automationsManager.execute(); + expect(api.getActionsManager().executeActions).toBeCalledTimes(1); + + automationsManager.deleteAutomations(); + + automationsManager.execute(); + expect(api.getActionsManager().executeActions).toBeCalledTimes(1); }); }); diff --git a/tests/card-controller/card-element-manager.test.ts b/tests/card-controller/card-element-manager.test.ts index 664c1faa..12fced9c 100644 --- a/tests/card-controller/card-element-manager.test.ts +++ b/tests/card-controller/card-element-manager.test.ts @@ -119,7 +119,7 @@ describe('CardElementManager', () => { ); expect(addEventListener).toBeCalledWith( 'll-custom', - api.getActionsManager().handleActionEvent, + api.getActionsManager().handleCustomActionEvent, ); expect(addEventListener).toBeCalledWith( 'action', @@ -169,7 +169,7 @@ describe('CardElementManager', () => { ); expect(removeEventListener).toBeCalledWith( 'll-custom', - api.getActionsManager().handleActionEvent, + api.getActionsManager().handleCustomActionEvent, ); expect(removeEventListener).toBeCalledWith( 'action', @@ -185,6 +185,10 @@ describe('CardElementManager', () => { ); expect(windowRemoveEventListener).toBeCalledWith('popstate', expect.anything()); + expect(api.getMediaLoadedInfoManager().clear).toBeCalled(); + expect(api.getFullscreenManager().disconnect).toBeCalled(); + expect(api.getKeyboardStateManager().uninitialize).toBeCalled(); + expect(api.getActionsManager().uninitialize).toBeCalled(); expect(api.getInitializationManager().uninitialize).toBeCalledWith('cameras'); }); }); diff --git a/tests/card-controller/conditions-manager.test.ts b/tests/card-controller/conditions-manager.test.ts index 5c02be57..e0327403 100644 --- a/tests/card-controller/conditions-manager.test.ts +++ b/tests/card-controller/conditions-manager.test.ts @@ -930,5 +930,60 @@ describe('ConditionsManager', () => { expect(manager.evaluateConditions(conditions)).toBeTruthy(); }); }); + + describe('with key condition', () => { + it('simple keypress', () => { + const manager = new ConditionsManager(createCardAPI()); + const conditions = [{ condition: 'key' as const, key: 'a' }]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); + manager.setState({ + keys: { + a: { state: 'down', ctrl: false, shift: false, alt: false, meta: false }, + }, + }); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); + manager.setState({ + keys: { + a: { state: 'up', ctrl: false, shift: false, alt: false, meta: false }, + }, + }); + + expect(manager.evaluateConditions(conditions)).toBeFalsy(); + }); + + it('keypress with modifiers', () => { + const manager = new ConditionsManager(createCardAPI()); + const conditions = [ + { + condition: 'key' as const, + key: 'a', + state: 'down' as const, + ctrl: true, + shift: true, + alt: true, + meta: true, + }, + ]; + expect(manager.evaluateConditions(conditions)).toBeFalsy(); + manager.setState({ + keys: { + a: { state: 'down', ctrl: false, shift: false, alt: false, meta: false }, + }, + }); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); + manager.setState({ + keys: { + a: { state: 'down', ctrl: true, shift: true, alt: true, meta: false }, + }, + }); + expect(manager.evaluateConditions(conditions)).toBeFalsy(); + manager.setState({ + keys: { + a: { state: 'down', ctrl: true, shift: true, alt: true, meta: true }, + }, + }); + expect(manager.evaluateConditions(conditions)).toBeTruthy(); + }); + }); }); }); diff --git a/tests/card-controller/config-manager.test.ts b/tests/card-controller/config/config-manager.test.ts similarity index 94% rename from tests/card-controller/config-manager.test.ts rename to tests/card-controller/config/config-manager.test.ts index 7bbb2f2b..de06f683 100644 --- a/tests/card-controller/config-manager.test.ts +++ b/tests/card-controller/config/config-manager.test.ts @@ -1,12 +1,12 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { ZodError } from 'zod'; -import { frigateCardConfigSchema } from '../../src/config/types'; -import { getOverriddenConfig } from '../../src/card-controller/conditions-manager'; -import { ConfigManager } from '../../src/card-controller/config-manager'; -import { InitializationAspect } from '../../src/card-controller/initialization-manager'; -import { createCardAPI, createConfig } from '../test-utils'; +import { frigateCardConfigSchema } from '../../../src/config/types'; +import { getOverriddenConfig } from '../../../src/card-controller/conditions-manager'; +import { ConfigManager } from '../../../src/card-controller/config/config-manager'; +import { InitializationAspect } from '../../../src/card-controller/initialization-manager'; +import { createCardAPI, createConfig } from '../../test-utils'; -vi.mock('../../src/card-controller/conditions-manager.js'); +vi.mock('../../../src/card-controller/conditions-manager.js'); describe('ConfigManager', () => { beforeEach(() => { @@ -97,7 +97,7 @@ describe('ConfigManager', () => { expect(api.getMediaLoadedInfoManager().clear).toBeCalled(); expect(api.getViewManager().reset).toBeCalled(); expect(api.getMessageManager().reset).toBeCalled(); - expect(api.getAutomationsManager().setAutomationsFromConfig).toBeCalled(); + expect(api.getAutomationsManager().addAutomations).toBeCalled(); expect(api.getStyleManager().setPerformance).toBeCalled(); expect(api.getCardElementManager().update).toBeCalled(); }); diff --git a/tests/card-controller/config/load-automations.test.ts b/tests/card-controller/config/load-automations.test.ts new file mode 100644 index 00000000..e246499d --- /dev/null +++ b/tests/card-controller/config/load-automations.test.ts @@ -0,0 +1,38 @@ +import { describe, expect, it, vi } from 'vitest'; +import { createCardAPI, createConfig } from '../../test-utils'; +import { setAutomationsFromConfig } from '../../../src/card-controller/config/load-automations'; + +describe('setAutomationsFromConfig', () => { + it('without config', () => { + const api = createCardAPI(); + setAutomationsFromConfig(api); + + expect(api.getAutomationsManager().deleteAutomations).toBeCalled(); + expect(api.getAutomationsManager().addAutomations).toBeCalledWith([]); + }); + + it('with config', () => { + const automations = [ + { + actions: [ + { + action: 'fire-dom-event' as const, + frigate_card_action: 'clips', + }, + ], + conditions: [{ condition: 'fullscreen' as const, fullscreen: true }], + }, + ]; + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getNonOverriddenConfig).mockReturnValue( + createConfig({ + automations: automations, + }), + ); + + setAutomationsFromConfig(api); + + expect(api.getAutomationsManager().deleteAutomations).toBeCalled(); + expect(api.getAutomationsManager().addAutomations).toBeCalledWith(automations); + }); +}); diff --git a/tests/card-controller/config/load-keyboard-shortcuts.test.ts b/tests/card-controller/config/load-keyboard-shortcuts.test.ts new file mode 100644 index 00000000..282fd433 --- /dev/null +++ b/tests/card-controller/config/load-keyboard-shortcuts.test.ts @@ -0,0 +1,143 @@ +import { describe, expect, it, vi } from 'vitest'; +import { createCardAPI, createConfig } from '../../test-utils'; +import { setKeyboardShortcutsFromConfig } from '../../../src/card-controller/config/load-keyboard-shortcuts'; +import { PTZKeyboardShortcutName } from '../../../src/config/keyboard-shortcuts'; +import { PTZAction } from '../../../src/config/ptz'; + +describe('setKeyboardShortcutsFromConfig', () => { + it('without shortcuts', () => { + const api = createCardAPI(); + setKeyboardShortcutsFromConfig(api, 'tag'); + + expect(api.getAutomationsManager().deleteAutomations).toBeCalledWith('tag'); + expect(api.getAutomationsManager().addAutomations).not.toBeCalled(); + }); + + it('with shortcuts disabled', () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + keyboard_shortcuts: { + enabled: false, + }, + }, + }), + ); + setKeyboardShortcutsFromConfig(api, 'tag'); + + expect(api.getAutomationsManager().deleteAutomations).toBeCalledWith('tag'); + expect(api.getAutomationsManager().addAutomations).not.toBeCalled(); + }); + + describe('PTZ shortcuts', () => { + describe('actions', () => { + it.each([ + ['ptz_left' as const, 'left' as const], + ['ptz_right' as const, 'right' as const], + ['ptz_up' as const, 'up' as const], + ['ptz_down' as const, 'down' as const], + ['ptz_zoom_in' as const, 'zoom_in' as const], + ['ptz_zoom_out' as const, 'zoom_out' as const], + ])('%s', (name: PTZKeyboardShortcutName, ptzAction: PTZAction) => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + keyboard_shortcuts: { + enabled: true, + ptz_home: null, + ptz_left: null, + ptz_right: null, + ptz_up: null, + ptz_down: null, + ptz_zoom_in: null, + ptz_zoom_out: null, + [name]: { key: 'z' }, + }, + }, + }), + ); + + setKeyboardShortcutsFromConfig(api, 'tag'); + + expect(api.getAutomationsManager().deleteAutomations).toBeCalledWith('tag'); + expect(api.getAutomationsManager().addAutomations).toBeCalledWith([ + { + actions: [ + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + ptz_action: ptzAction, + ptz_phase: 'start', + }, + ], + conditions: [ + { + alt: undefined, + condition: 'key', + ctrl: undefined, + key: 'z', + meta: undefined, + shift: undefined, + state: 'down', + }, + ], + tag: 'tag', + }, + { + actions: [ + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + ptz_action: ptzAction, + ptz_phase: 'stop', + }, + ], + conditions: [ + { + condition: 'key', + key: 'z', + state: 'up', + }, + ], + tag: 'tag', + }, + ]); + }); + + it('ptz_home', () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + + setKeyboardShortcutsFromConfig(api, 'tag'); + + expect(api.getAutomationsManager().deleteAutomations).toBeCalledWith('tag'); + expect(api.getAutomationsManager().addAutomations).toBeCalledWith( + expect.arrayContaining([ + { + actions: [ + { + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + }, + ], + conditions: [ + { + alt: undefined, + condition: 'key', + ctrl: undefined, + key: 'h', + meta: undefined, + shift: undefined, + state: 'down', + }, + ], + tag: 'tag', + }, + ]), + ); + }); + }); + }); +}); diff --git a/tests/card-controller/controller.test.ts b/tests/card-controller/controller.test.ts index b8e6b87b..ca4f6d7b 100644 --- a/tests/card-controller/controller.test.ts +++ b/tests/card-controller/controller.test.ts @@ -1,7 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { CameraManager } from '../../src/camera-manager/manager'; -import { FrigateCardEditor } from '../../src/editor'; -import { ActionsManager } from '../../src/card-controller/actions-manager'; +import { ActionsManager } from '../../src/card-controller/actions/actions-manager'; import { AutoUpdateManager } from '../../src/card-controller/auto-update-manager'; import { AutomationsManager } from '../../src/card-controller/automations-manager'; import { CameraURLManager } from '../../src/card-controller/camera-url-manager'; @@ -10,7 +9,7 @@ import { CardHTMLElement, } from '../../src/card-controller/card-element-manager'; import { ConditionsManager } from '../../src/card-controller/conditions-manager'; -import { ConfigManager } from '../../src/card-controller/config-manager'; +import { ConfigManager } from '../../src/card-controller/config/config-manager'; import { CardController } from '../../src/card-controller/controller'; import { DownloadManager } from '../../src/card-controller/download-manager'; import { ExpandManager } from '../../src/card-controller/expand-manager'; @@ -18,6 +17,7 @@ import { FullscreenManager } from '../../src/card-controller/fullscreen-manager' import { HASSManager } from '../../src/card-controller/hass-manager'; import { InitializationManager } from '../../src/card-controller/initialization-manager'; import { InteractionManager } from '../../src/card-controller/interaction-manager'; +import { KeyboardStateManager } from '../../src/card-controller/keyboard-state-manager'; import { MediaLoadedInfoManager } from '../../src/card-controller/media-info-manager'; import { MediaPlayerManager } from '../../src/card-controller/media-player-manager'; import { MessageManager } from '../../src/card-controller/message-manager'; @@ -26,23 +26,25 @@ import { QueryStringManager } from '../../src/card-controller/query-string-manag import { StyleManager } from '../../src/card-controller/style-manager'; import { TriggersManager } from '../../src/card-controller/triggers-manager'; import { ViewManager } from '../../src/card-controller/view-manager'; +import { FrigateCardEditor } from '../../src/editor'; import { EntityRegistryManager } from '../../src/utils/ha/entity-registry'; import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media'; vi.mock('../../src/camera-manager/manager'); -vi.mock('../../src/card-controller/actions-manager'); +vi.mock('../../src/card-controller/actions/actions-manager'); vi.mock('../../src/card-controller/auto-update-manager'); vi.mock('../../src/card-controller/automations-manager'); vi.mock('../../src/card-controller/camera-url-manager'); vi.mock('../../src/card-controller/card-element-manager'); vi.mock('../../src/card-controller/conditions-manager'); -vi.mock('../../src/card-controller/config-manager'); +vi.mock('../../src/card-controller/config/config-manager'); vi.mock('../../src/card-controller/download-manager'); vi.mock('../../src/card-controller/expand-manager'); vi.mock('../../src/card-controller/fullscreen-manager'); vi.mock('../../src/card-controller/hass-manager'); vi.mock('../../src/card-controller/initialization-manager'); vi.mock('../../src/card-controller/interaction-manager'); +vi.mock('../../src/card-controller/keyboard-state-manager'); vi.mock('../../src/card-controller/media-info-manager'); vi.mock('../../src/card-controller/media-player-manager'); vi.mock('../../src/card-controller/message-manager'); @@ -187,6 +189,12 @@ describe('CardController', () => { ); }); + it('getKeyboardStateManager', () => { + expect(createController().getKeyboardStateManager()).toBe( + vi.mocked(KeyboardStateManager).mock.instances[0], + ); + }); + it('getMediaLoadedInfoManager', () => { expect(createController().getMediaLoadedInfoManager()).toBe( vi.mocked(MediaLoadedInfoManager).mock.instances[0], diff --git a/tests/card-controller/keyboard-state-manager.test.ts b/tests/card-controller/keyboard-state-manager.test.ts new file mode 100644 index 00000000..36f8e1ff --- /dev/null +++ b/tests/card-controller/keyboard-state-manager.test.ts @@ -0,0 +1,86 @@ +import { describe, expect, it, vi } from 'vitest'; +import { KeyboardStateManager } from '../../src/card-controller/keyboard-state-manager'; +import { createCardAPI, createLitElement } from '../test-utils'; + +// @vitest-environment jsdom +describe('KeyboardStateManager', () => { + it('should construct', () => { + expect(new KeyboardStateManager(createCardAPI())).toBeTruthy(); + }); + + it('should set state on keydown', () => { + const api = createCardAPI(); + const element = createLitElement(); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); + const manager = new KeyboardStateManager(api); + manager.initialize(); + + element.dispatchEvent(new KeyboardEvent('keydown', { key: 'a' })); + + expect(api.getConditionsManager().setState).toHaveBeenCalledWith({ + keys: { + a: { state: 'down', ctrl: false, alt: false, meta: false, shift: false }, + }, + }); + + element.dispatchEvent(new KeyboardEvent('keydown', { key: 'a' })); + + // Duplicate keydown should not re-set the state. + expect(api.getConditionsManager().setState).toBeCalledTimes(1); + }); + + it('should set state on keyup', () => { + const api = createCardAPI(); + const element = createLitElement(); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); + const manager = new KeyboardStateManager(api); + manager.initialize(); + + element.dispatchEvent(new KeyboardEvent('keyup', { key: 'a' })); + + // Key not held down in the first place should not update the state. + expect(api.getConditionsManager().setState).not.toBeCalled(); + + element.dispatchEvent(new KeyboardEvent('keydown', { key: 'a' })); + element.dispatchEvent(new KeyboardEvent('keyup', { key: 'a' })); + + expect(api.getConditionsManager().setState).toBeCalledTimes(2); + expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({ + keys: { + a: { state: 'up', ctrl: false, alt: false, meta: false, shift: false }, + }, + }); + }); + + it('should set state on focus loss', () => { + const api = createCardAPI(); + const element = createLitElement(); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); + const manager = new KeyboardStateManager(api); + manager.initialize(); + + element.dispatchEvent(new FocusEvent('blur')); + expect(api.getConditionsManager().setState).not.toBeCalled(); + + element.dispatchEvent(new KeyboardEvent('keydown', { key: 'a' })); + element.dispatchEvent(new FocusEvent('blur')); + + expect(api.getConditionsManager().setState).toBeCalledTimes(2); + expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({ + keys: {}, + }); + }); + + it('should not act after uninitialization', () => { + const api = createCardAPI(); + const element = createLitElement(); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); + const manager = new KeyboardStateManager(api); + manager.initialize(); + manager.uninitialize(); + + element.dispatchEvent(new KeyboardEvent('keydown', { key: 'a' })); + + expect(api.getConditionsManager().setState).not.toBeCalled(); + }); +}); diff --git a/tests/card-controller/query-string-manager.test.ts b/tests/card-controller/query-string-manager.test.ts index eb9ee80c..7d1c6427 100644 --- a/tests/card-controller/query-string-manager.test.ts +++ b/tests/card-controller/query-string-manager.test.ts @@ -1,10 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { QueryStringManager } from '../../src/card-controller/query-string-manager'; -import { - FrigateCardGeneralAction, - FrigateCardUserSpecifiedView, -} from '../../src/config/types'; import { createCardAPI } from '../test-utils'; const setQueryString = (qs: string): void => { @@ -28,7 +24,7 @@ describe('QueryStringManager', () => { manager.executeAll(); expect(manager.hasViewRelatedActions()).toBeFalsy(); - expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); + expect(api.getActionsManager().executeActions).not.toBeCalled(); expect(api.getViewManager().setViewByParameters).not.toBeCalled(); }); @@ -76,11 +72,13 @@ describe('QueryStringManager', () => { manager.executeAll(); expect(manager.hasViewRelatedActions()).toBeFalsy(); - expect(api.getActionsManager().executeFrigateAction).toBeCalledWith({ - action: 'fire-dom-event', - card_id: 'id', - frigate_card_action: action, - }); + expect(api.getActionsManager().executeActions).toBeCalledWith([ + { + action: 'fire-dom-event', + card_id: 'id', + frigate_card_action: action, + }, + ]); }); }); @@ -97,7 +95,7 @@ describe('QueryStringManager', () => { expect(api.getViewManager().setViewDefault).toBeCalled(); expect(manager.hasViewRelatedActions()).toBeTruthy(); - expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); + expect(api.getActionsManager().executeActions).not.toBeCalled(); expect(api.getViewManager().setViewByParameters).not.toBeCalled(); }); @@ -114,7 +112,7 @@ describe('QueryStringManager', () => { }); expect(manager.hasViewRelatedActions()).toBeTruthy(); - expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); + expect(api.getActionsManager().executeActions).not.toBeCalled(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); }); @@ -131,7 +129,7 @@ describe('QueryStringManager', () => { }); expect(manager.hasViewRelatedActions()).toBeTruthy(); - expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); + expect(api.getActionsManager().executeActions).not.toBeCalled(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); }); @@ -147,7 +145,7 @@ describe('QueryStringManager', () => { manager.executeAll(); expect(manager.hasViewRelatedActions()).toBeFalsy(); - expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); + expect(api.getActionsManager().executeActions).not.toBeCalled(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); expect(api.getViewManager().setViewByParameters).not.toBeCalled(); }, @@ -165,7 +163,7 @@ describe('QueryStringManager', () => { manager.executeAll(); expect(manager.hasViewRelatedActions()).toBeFalsy(); - expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); + expect(api.getActionsManager().executeActions).not.toBeCalled(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); expect(api.getViewManager().setViewByParameters).not.toBeCalled(); expect(consoleSpy).toBeCalled(); @@ -212,7 +210,7 @@ describe('QueryStringManager', () => { manager.executeAll(); - expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); + expect(api.getActionsManager().executeActions).not.toBeCalled(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); expect(api.getViewManager().setViewByParameters).not.toBeCalled(); }); @@ -296,7 +294,7 @@ describe('QueryStringManager', () => { manager.executeViewRelated(); - expect(api.getActionsManager().executeFrigateAction).not.toBeCalled(); + expect(api.getActionsManager().executeActions).not.toBeCalled(); }); }); }); diff --git a/tests/components-lib/key-assigner-controller.test.ts b/tests/components-lib/key-assigner-controller.test.ts new file mode 100644 index 00000000..9e1c1530 --- /dev/null +++ b/tests/components-lib/key-assigner-controller.test.ts @@ -0,0 +1,131 @@ +import { describe, expect, it, vi } from 'vitest'; +import { KeyAssignerController } from '../../src/components-lib/key-assigner-controller'; +import { createLitElement } from '../test-utils'; + +// @vitest-environment jsdom +describe('KeyAssignerController', () => { + it('should be creatable', () => { + const controller = new KeyAssignerController(createLitElement()); + expect(controller).toBeTruthy(); + }); + + describe('should manage value', () => { + it('should have no value to start', () => { + const controller = new KeyAssignerController(createLitElement()); + expect(controller.hasValue()).toBeFalsy(); + }); + + it('should set value', () => { + const element = createLitElement(); + const valueChangeHandler = vi.fn(); + element.addEventListener('value-changed', valueChangeHandler); + const controller = new KeyAssignerController(element); + + controller.setValue({ key: 'ArrowLeft' }); + + expect(controller.hasValue()).toBeTruthy(); + expect(controller.getValue()).toEqual({ key: 'ArrowLeft' }); + expect(element.requestUpdate).toBeCalled(); + expect(valueChangeHandler).toBeCalledWith( + expect.objectContaining({ + detail: { value: { key: 'ArrowLeft' } }, + }), + ); + + // Set again with the same value. + controller.setValue({ key: 'ArrowLeft' }); + expect(element.requestUpdate).toBeCalledTimes(1); + expect(valueChangeHandler).toBeCalledTimes(1); + }); + }); + + describe('should manage assignment state', () => { + it('should not be assigned to start', () => { + const element = createLitElement(); + const controller = new KeyAssignerController(element); + expect(controller.isAssigning()).toBeFalsy(); + expect(element.getAttribute('assigning')).toBeNull(); + }); + + it('should toggle assigning', () => { + const element = createLitElement(); + const controller = new KeyAssignerController(element); + controller.toggleAssigning(); + expect(element.requestUpdate).toBeCalled(); + expect(controller.isAssigning()).toBeTruthy(); + expect(element.getAttribute('assigning')).toBe(''); + + expect(controller.hasValue()).toBeFalsy(); + element.dispatchEvent(new KeyboardEvent('keydown', { key: 'a' })); + + expect(controller.hasValue()).toBeTruthy(); + expect(controller.isAssigning()).toBeFalsy(); + + controller.setValue(null); + + // A key sent when not assigning will do nothing. + element.dispatchEvent(new KeyboardEvent('keydown', { key: 'a' })); + expect(controller.hasValue()).toBeFalsy(); + }); + + it('should not assign when focus lost', () => { + const element = createLitElement(); + const controller = new KeyAssignerController(element); + + controller.hostConnected(); + + controller.toggleAssigning(); + expect(controller.isAssigning()).toBeTruthy(); + + element.dispatchEvent(new FocusEvent('blur')); + expect(controller.isAssigning()).toBeFalsy(); + + controller.hostDisconnected(); + }); + }); + + describe('should manage key down', () => { + it('should reject modifiers only', () => { + const element = createLitElement(); + const controller = new KeyAssignerController(element); + controller.toggleAssigning(); + + element.dispatchEvent(new KeyboardEvent('keydown', { key: 'Control' })); + expect(controller.hasValue()).toBeFalsy(); + }); + + it('should reject empty key', () => { + const element = createLitElement(); + const controller = new KeyAssignerController(element); + controller.toggleAssigning(); + + element.dispatchEvent(new KeyboardEvent('keydown', { key: '' })); + expect(controller.hasValue()).toBeFalsy(); + }); + + it('should accept valid key', () => { + const element = createLitElement(); + const controller = new KeyAssignerController(element); + controller.toggleAssigning(); + + element.dispatchEvent( + new KeyboardEvent('keydown', { + key: 'ArrowLeft', + ctrlKey: true, + shiftKey: true, + altKey: true, + metaKey: true, + }), + ); + expect(controller.hasValue()).toBeTruthy(); + expect(controller.getValue()).toEqual({ + key: 'ArrowLeft', + ctrl: true, + shift: true, + alt: true, + meta: true, + }); + expect(controller.isAssigning()).toBeFalsy(); + }); + }); +}); diff --git a/tests/components-lib/menu-button-controller.test.ts b/tests/components-lib/menu-button-controller.test.ts index f7bdc4e7..ed9821b7 100644 --- a/tests/components-lib/menu-button-controller.test.ts +++ b/tests/components-lib/menu-button-controller.test.ts @@ -18,7 +18,7 @@ import { ViewDisplayMode, } from '../../src/config/types'; import { FrigateCardMediaPlayer } from '../../src/types'; -import { createFrigateCardSimpleAction } from '../../src/utils/action'; +import { createGeneralAction } from '../../src/utils/action'; import { ViewMedia } from '../../src/view/media'; import { MediaQueriesResults } from '../../src/view/media-queries-results'; import { View } from '../../src/view/view'; @@ -36,6 +36,7 @@ import { createView, TestViewMedia, } from '../test-utils'; +import { Capabilities } from '../../src/camera-manager/capabilities'; vi.mock('../../src/utils/media-player-controller.js'); vi.mock('../../src/card-controller/microphone-manager.js'); @@ -88,8 +89,8 @@ describe('MenuButtonController', () => { priority: 50, type: 'custom:frigate-card-menu-icon', title: 'Frigate menu / Default view', - tap_action: createFrigateCardSimpleAction('menu_toggle'), - hold_action: createFrigateCardSimpleAction('diagnostics'), + tap_action: createGeneralAction('menu_toggle'), + hold_action: createGeneralAction('diagnostics'), }); }); @@ -104,8 +105,8 @@ describe('MenuButtonController', () => { priority: 50, type: 'custom:frigate-card-menu-icon', title: 'Frigate menu / Default view', - tap_action: createFrigateCardSimpleAction('default'), - hold_action: createFrigateCardSimpleAction('diagnostics'), + tap_action: createGeneralAction('default'), + hold_action: createGeneralAction('diagnostics'), }); }); }); @@ -1355,13 +1356,14 @@ describe('MenuButtonController', () => { describe('should have show ptz button', () => { it('when the selected camera is not PTZ enabled', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( - createCapabilities(), - ); + const store = createStore([ + { + cameraID: 'camera-1', + }, + ]); const buttons = calculateButtons(controller, { - cameraManager: cameraManager, + cameraManager: createCameraManager(store), view: createView({ view: 'live' }), }); @@ -1373,13 +1375,15 @@ describe('MenuButtonController', () => { }); it('when not in live view', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( - createCapabilities({ ptz: { panTilt: ['relative'] } }), - ); + const store = createStore([ + { + cameraID: 'camera-1', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); const buttons = calculateButtons(controller, { - cameraManager: cameraManager, + cameraManager: createCameraManager(store), view: createView({ view: 'clips' }), }); @@ -1391,11 +1395,16 @@ describe('MenuButtonController', () => { }); it('when the selected camera is PTZ enabled', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( - createCapabilities({ ptz: { panTilt: ['relative'] } }), - ); - const buttons = calculateButtons(controller, { cameraManager: cameraManager }); + const store = createStore([ + { + cameraID: 'camera-1', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); + + const buttons = calculateButtons(controller, { + cameraManager: createCameraManager(store), + }); expect(buttons).toContainEqual({ enabled: false, @@ -1406,25 +1415,28 @@ describe('MenuButtonController', () => { }, tap_action: { action: 'fire-dom-event', - frigate_card_action: 'show_ptz', - show_ptz: false, + frigate_card_action: 'ptz_controls', + enabled: false, }, title: 'Show PTZ controls', type: 'custom:frigate-card-menu-icon', }); }); - it('when the context has PTZ visiblity turned off', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getCameraCapabilities).mockReturnValue( - createCapabilities({ ptz: { panTilt: ['relative'] } }), - ); + it('when the context has PTZ disabled', () => { + const store = createStore([ + { + cameraID: 'camera-1', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); + const view = createView({ camera: 'camera-1', - context: { live: { ptzVisible: false } }, + context: { ptzControls: { enabled: false } }, }); const buttons = calculateButtons(controller, { - cameraManager: cameraManager, + cameraManager: createCameraManager(store), view: view, }); @@ -1435,8 +1447,8 @@ describe('MenuButtonController', () => { style: {}, tap_action: { action: 'fire-dom-event', - frigate_card_action: 'show_ptz', - show_ptz: true, + frigate_card_action: 'ptz_controls', + enabled: true, }, title: 'Show PTZ controls', type: 'custom:frigate-card-menu-icon', @@ -1444,24 +1456,16 @@ describe('MenuButtonController', () => { }); it('when a substream is PTZ enabled', () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera-1', - config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), - }, - { cameraID: 'camera-2' }, - ]), - ); - vi.mocked(cameraManager.getCameraCapabilities).mockImplementation( - (cameraID: string) => { - if (cameraID === 'camera-2') { - return createCapabilities({ ptz: { panTilt: ['relative'] } }); - } - return createCapabilities(); + const store = createStore([ + { + cameraID: 'camera-1', + config: createCameraConfig({ dependencies: { cameras: ['camera-2'] } }), }, - ); + { + cameraID: 'camera-2', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); const view = createView({ camera: 'camera-1', context: { @@ -1471,7 +1475,7 @@ describe('MenuButtonController', () => { }, }); const buttons = calculateButtons(controller, { - cameraManager: cameraManager, + cameraManager: createCameraManager(store), view: view, }); @@ -1484,8 +1488,8 @@ describe('MenuButtonController', () => { }, tap_action: { action: 'fire-dom-event', - frigate_card_action: 'show_ptz', - show_ptz: false, + frigate_card_action: 'ptz_controls', + enabled: false, }, title: 'Show PTZ controls', type: 'custom:frigate-card-menu-icon', @@ -1493,7 +1497,7 @@ describe('MenuButtonController', () => { }); }); - describe('should have change zoom button', () => { + describe('should have ptz home button', () => { it.each([ ['live' as const, true, false], ['live' as const, undefined, false], @@ -1521,13 +1525,23 @@ describe('MenuButtonController', () => { results: [new TestViewMedia({ id: 'media-1' })], selectedIndex: 0, }), - context: { - zoom: { - [targetID]: { - isDefault: isDefault, + ...(isDefault !== undefined && { + context: { + zoom: { + [targetID]: { + observed: { + isDefault: isDefault, + unzoomed: false, + zoom: 1, + pan: { + x: 50, + y: 50, + }, + }, + }, }, }, - }, + }), }); const buttons = calculateButtons(controller, { cameraManager: cameraManager, @@ -1537,19 +1551,19 @@ describe('MenuButtonController', () => { if (expectedResult) { expect(buttons).toContainEqual({ enabled: true, - icon: 'mdi:magnify-close', + icon: 'mdi:home', priority: 50, tap_action: { action: 'fire-dom-event', - frigate_card_action: 'change_zoom', + frigate_card_action: 'ptz_multi', target_id: targetID, }, - title: 'Zoom to default', + title: 'PTZ Home', type: 'custom:frigate-card-menu-icon', }); } else { expect(buttons).not.toContainEqual( - expect.objectContaining({ title: 'Set zoom to default' }), + expect.objectContaining({ title: 'Digital zoom to default' }), ); } }, diff --git a/tests/components-lib/menu-controller.test.ts b/tests/components-lib/menu-controller.test.ts index 1467ea47..58d26cde 100644 --- a/tests/components-lib/menu-controller.test.ts +++ b/tests/components-lib/menu-controller.test.ts @@ -362,53 +362,60 @@ describe('MenuController', () => { describe('should handle actions', () => { it('should bail without config', () => { const controller = new MenuController(createLitElement()); - controller.actionHandler(createHASS(), createEvent('tap')); + controller.actionHandler(createEvent('tap')); expect(vi.mocked(handleActionConfig)).not.toBeCalled(); }); it('should execute simple action in non-hidden menu', () => { const host = createLitElement(); - const hass = createHASS(); + const handler = vi.fn(); + host.addEventListener('frigate-card:action:execution-request', handler); + const controller = new MenuController(host); - controller.actionHandler(hass, createEvent('tap'), tapActionConfig); - expect(vi.mocked(handleActionConfig)).toBeCalledWith( - host, - hass, - tapActionConfig, - action, + controller.actionHandler(createEvent('tap'), tapActionConfig); + expect(handler).toBeCalledWith( + expect.objectContaining({ + detail: { action: [action], config: tapActionConfig }, + }), ); - expect(controller.isExpanded()).toBeFalsy(); }); it('should execute simple action in with config in event', () => { const host = createLitElement(); - const hass = createHASS(); + const handler = vi.fn(); + host.addEventListener('frigate-card:action:execution-request', handler); + const controller = new MenuController(host); - controller.actionHandler(hass, createEvent('tap', tapActionConfig)); - expect(vi.mocked(handleActionConfig)).toBeCalledWith( - host, - hass, - tapActionConfig, - action, + controller.actionHandler(createEvent('tap', tapActionConfig)); + expect(handler).toBeCalledWith( + expect.objectContaining({ + detail: { action: [action], config: tapActionConfig }, + }), ); }); it('should execute simple array of actions in non-hidden menu', () => { const host = createLitElement(); - const hass = createHASS(); + const handler = vi.fn(); + host.addEventListener('frigate-card:action:execution-request', handler); + const controller = new MenuController(host); - controller.actionHandler(hass, createEvent('tap'), tapActionConfigMulti); - expect(vi.mocked(handleActionConfig)).toBeCalledTimes(3); + controller.actionHandler(createEvent('tap'), tapActionConfigMulti); + + expect(handler).toBeCalledWith( + expect.objectContaining({ + detail: { action: [action, action, action], config: tapActionConfigMulti }, + }), + ); }); describe('should close menu', () => { it('tap', () => { const host = createLitElement(); - const hass = createHASS(); const controller = new MenuController(host); controller.setMenuConfig( createMenuConfig({ @@ -419,13 +426,12 @@ describe('MenuController', () => { controller.setExpanded(true); expect(controller.isExpanded()).toBeTruthy(); - controller.actionHandler(hass, createEvent('tap'), tapActionConfig); + controller.actionHandler(createEvent('tap'), tapActionConfig); expect(controller.isExpanded()).toBeFalsy(); }); it('end_tap', () => { const host = createLitElement(); - const hass = createHASS(); const controller = new MenuController(host); controller.setMenuConfig( createMenuConfig({ @@ -436,7 +442,7 @@ describe('MenuController', () => { controller.setExpanded(true); expect(controller.isExpanded()).toBeTruthy(); - controller.actionHandler(hass, createEvent('end_tap'), { + controller.actionHandler(createEvent('end_tap'), { end_tap_action: action, }); expect(controller.isExpanded()).toBeFalsy(); @@ -446,7 +452,6 @@ describe('MenuController', () => { describe('should not close menu', () => { it('start_tap with later action', () => { const host = createLitElement(); - const hass = createHASS(); const controller = new MenuController(host); controller.setMenuConfig( createMenuConfig({ @@ -457,7 +462,7 @@ describe('MenuController', () => { controller.setExpanded(true); expect(controller.isExpanded()).toBeTruthy(); - controller.actionHandler(hass, createEvent('start_tap'), { + controller.actionHandler(createEvent('start_tap'), { start_tap_action: action, end_tap_action: action, }); @@ -466,7 +471,6 @@ describe('MenuController', () => { it('with a menu toggle action', () => { const host = createLitElement(); - const hass = createHASS(); const controller = new MenuController(host); controller.setMenuConfig( createMenuConfig({ @@ -477,7 +481,7 @@ describe('MenuController', () => { controller.setExpanded(false); expect(controller.isExpanded()).toBeFalsy(); - controller.actionHandler(hass, createEvent('tap'), { + controller.actionHandler(createEvent('tap'), { camera_entity: 'foo', tap_action: menuToggleAction, }); @@ -497,7 +501,7 @@ describe('MenuController', () => { controller.setExpanded(true); expect(controller.isExpanded()).toBeTruthy(); - controller.actionHandler(hass, createEvent('end_tap'), tapActionConfig); + controller.actionHandler(createEvent('end_tap'), tapActionConfig); expect(controller.isExpanded()).toBeTruthy(); }); }); diff --git a/tests/components-lib/ptz-controller.test.ts b/tests/components-lib/ptz-controller.test.ts deleted file mode 100644 index c64b792f..00000000 --- a/tests/components-lib/ptz-controller.test.ts +++ /dev/null @@ -1,316 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { PTZController } from '../../src/components-lib/ptz-controller'; -import { - FrigateCardPTZConfig, - frigateCardPTZSchema, - PTZControlAction, -} from '../../src/config/types'; -import { - frigateCardHandleActionConfig, - getActionConfigGivenAction, -} from '../../src/utils/action.js'; -import { - createCapabilities, - createCameraManager, - createHASS, -} from '../test-utils'; - -vi.mock('../../src/utils/action.js'); - -const createConfig = (config?: Partial): FrigateCardPTZConfig => { - return frigateCardPTZSchema.parse({ - ...config, - }); -}; - -// @vitest-environment jsdom -describe('PTZController', () => { - beforeEach(() => { - vi.resetAllMocks(); - }); - - it('should be creatable', () => { - const controller = new PTZController(document.createElement('div')); - expect(controller).toBeTruthy(); - }); - - it('should get config creatable', () => { - const controller = new PTZController(document.createElement('div')); - const config = createConfig(); - controller.setConfig(config); - expect(controller.getConfig()).toBe(config); - }); - - describe('should set element attributes', () => { - describe('orientation', () => { - describe('with config', () => { - it.each([['horizontal' as const], ['vertical' as const]])( - '%s', - (orientation: 'horizontal' | 'vertical') => { - const element = document.createElement('div'); - const controller = new PTZController(element); - controller.setConfig(createConfig({ orientation: orientation })); - expect(element.getAttribute('data-orientation')).toBe(orientation); - }, - ); - }); - it('without config', () => { - const element = document.createElement('div'); - const controller = new PTZController(element); - controller.setConfig(); - expect(element.getAttribute('data-orientation')).toBe('horizontal'); - }); - }); - describe('position', () => { - describe('with config', () => { - it.each([ - ['top-left' as const], - ['top-right' as const], - ['bottom-left' as const], - ['bottom-right' as const], - ])( - '%s', - (position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right') => { - const element = document.createElement('div'); - const controller = new PTZController(element); - controller.setConfig(createConfig({ position: position })); - expect(element.getAttribute('data-position')).toBe(position); - }, - ); - }); - it('without config', () => { - const element = document.createElement('div'); - const controller = new PTZController(element); - controller.setConfig(); - expect(element.getAttribute('data-position')).toBe('bottom-right'); - }); - }); - it('with style in config', () => { - const element = document.createElement('div'); - const controller = new PTZController(element); - controller.setConfig(createConfig({ style: { transform: 'none', left: '50%' } })); - expect(element.getAttribute('style')).toBe('transform:none;left:50%'); - }); - }); - - describe('should respect mode', () => { - it('off', () => { - const controller = new PTZController(document.createElement('div')); - expect(controller.shouldDisplay()).toBeFalsy(); - }); - it('off but forced on', () => { - const controller = new PTZController(document.createElement('div')); - controller.setForceVisibility(true); - // No actions, no rendering, no matter what. - expect(controller.shouldDisplay()).toBeFalsy(); - }); - it('on without actions', () => { - const controller = new PTZController(document.createElement('div')); - controller.setConfig(createConfig({ mode: 'on' })); - expect(controller.shouldDisplay()).toBeFalsy(); - }); - it('on with actions', () => { - const controller = new PTZController(document.createElement('div')); - controller.setConfig(createConfig({ mode: 'on', actions_left: {} })); - controller.setCamera(createCameraManager(), 'camera.office'); - expect(controller.shouldDisplay()).toBeTruthy(); - }); - it('on with actions but forced off', () => { - const controller = new PTZController(document.createElement('div')); - controller.setConfig(createConfig({ mode: 'on', actions_left: {} })); - controller.setCamera(createCameraManager(), 'camera.office'); - controller.setForceVisibility(false); - expect(controller.shouldDisplay()).toBeFalsy(); - }); - }); - - describe('should get PTZ actions', () => { - it('without config', () => { - const controller = new PTZController(document.createElement('div')); - expect(controller.getPTZActions('left')).toBeNull(); - }); - - describe('using defaults', () => { - describe('with continous PTZ', () => { - it.each([ - ['left' as const], - ['right' as const], - ['up' as const], - ['down' as const], - ['zoom_in' as const], - ['zoom_out' as const], - ])('%s', (actionName: PTZControlAction) => { - const controller = new PTZController(document.createElement('div')); - controller.setConfig(createConfig()); - - const cameraManager = createCameraManager(); - vi.mocked(cameraManager).getCameraCapabilities.mockReturnValue( - createCapabilities({ - ptz: { - panTilt: ['continuous'], - zoom: ['continuous'], - }, - }), - ); - controller.setCamera(cameraManager, 'camera.office'); - - expect(controller.getPTZActions(actionName)).toEqual({ - start_tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'ptz', - ptz_action: actionName, - ptz_phase: 'start', - }, - end_tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'ptz', - ptz_action: actionName, - ptz_phase: 'stop', - }, - }); - }); - }); - - describe('with relative PTZ', () => { - it.each([ - ['left' as const], - ['right' as const], - ['up' as const], - ['down' as const], - ['zoom_in' as const], - ['zoom_out' as const], - ])('%s', (actionName: PTZControlAction) => { - const controller = new PTZController(document.createElement('div')); - controller.setConfig(createConfig()); - - const cameraManager = createCameraManager(); - vi.mocked(cameraManager).getCameraCapabilities.mockReturnValue( - createCapabilities({ - ptz: { - panTilt: ['relative'], - zoom: ['relative'], - }, - }), - ); - controller.setCamera(cameraManager, 'camera.office'); - - expect(controller.getPTZActions(actionName)).toEqual({ - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'ptz', - ptz_action: actionName, - }, - }); - }); - }); - - it('home', () => { - const controller = new PTZController(document.createElement('div')); - controller.setConfig(createConfig()); - - const cameraManager = createCameraManager(); - vi.mocked(cameraManager).getCameraCapabilities.mockReturnValue( - createCapabilities({ - ptz: { - presets: ['preset-foo'], - }, - }), - ); - controller.setCamera(cameraManager, 'camera.office'); - - expect(controller.getPTZActions('home')).toEqual({ - tap_action: { - action: 'fire-dom-event', - frigate_card_action: 'ptz', - ptz_action: 'preset', - ptz_preset: 'preset-foo', - }, - }); - }); - }); - - describe('using config', () => { - it.each([ - ['left' as const], - ['right' as const], - ['up' as const], - ['down' as const], - ['zoom_in' as const], - ['zoom_out' as const], - ])('configured %s', (actionName: PTZControlAction) => { - const controller = new PTZController(document.createElement('div')); - controller.setConfig( - createConfig({ - [`actions_${actionName}`]: { - argument: actionName, - }, - }), - ); - controller.setCamera(createCameraManager(), 'camera.office'); - - expect(controller.getPTZActions(actionName)).toEqual({ - argument: actionName, - }); - }); - - it('configured home', () => { - const controller = new PTZController(document.createElement('div')); - controller.setConfig( - createConfig({ - actions_home: { - argument: 'home', - }, - }), - ); - controller.setCamera(createCameraManager(), 'camera.office'); - - expect(controller.getPTZActions('home')).toEqual({ - argument: 'home', - }); - }); - }); - }); - - describe('should handle action', () => { - it('without hass or action', () => { - const controller = new PTZController(document.createElement('div')); - controller.setHASS(); - controller.setCamera(); - controller.handleAction( - new CustomEvent<{ action: string }>('@action', { detail: { action: 'tap' } }), - ); - expect(frigateCardHandleActionConfig).not.toBeCalled(); - }); - - it('with action', () => { - const element = document.createElement('div'); - const controller = new PTZController(element); - const hass = createHASS(); - controller.setHASS(hass); - controller.setConfig( - createConfig({ - [`actions_left`]: {}, - }), - ); - const tapAction = { - action: 'none' as const, - }; - const actionsConfig = { - tap_action: tapAction, - }; - vi.mocked(getActionConfigGivenAction).mockReturnValue(tapAction); - - controller.handleAction( - new CustomEvent<{ action: string }>('@action', { detail: { action: 'tap' } }), - actionsConfig, - ); - expect(frigateCardHandleActionConfig).toBeCalledWith( - element, - hass, - actionsConfig, - 'tap', - actionsConfig.tap_action, - ); - }); - }); -}); diff --git a/tests/components-lib/ptz/ptz-controller.test.ts b/tests/components-lib/ptz/ptz-controller.test.ts new file mode 100644 index 00000000..5d5f9519 --- /dev/null +++ b/tests/components-lib/ptz/ptz-controller.test.ts @@ -0,0 +1,378 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { Capabilities } from '../../../src/camera-manager/capabilities'; +import { PTZController } from '../../../src/components-lib/ptz/ptz-controller'; +import { PTZControlAction } from '../../../src/config/ptz'; +import { PTZControlsConfig, ptzControlsConfigSchema } from '../../../src/config/types'; +import { createCameraManager, createCapabilities, createStore } from '../../test-utils'; + +const createConfig = (config?: Partial): PTZControlsConfig => { + return ptzControlsConfigSchema.parse({ + ...config, + }); +}; + +// @vitest-environment jsdom +describe('PTZController', () => { + beforeEach(() => { + vi.resetAllMocks(); + }); + + it('should be creatable', () => { + const controller = new PTZController(document.createElement('div')); + expect(controller).toBeTruthy(); + }); + + it('should get config', () => { + const controller = new PTZController(document.createElement('div')); + const config = createConfig(); + controller.setConfig(config); + expect(controller.getConfig()).toBe(config); + }); + + describe('should set element attributes', () => { + describe('orientation', () => { + describe('with config', () => { + it.each([['horizontal' as const], ['vertical' as const]])( + '%s', + (orientation: 'horizontal' | 'vertical') => { + const element = document.createElement('div'); + const controller = new PTZController(element); + controller.setConfig(createConfig({ orientation: orientation })); + expect(element.getAttribute('data-orientation')).toBe(orientation); + }, + ); + }); + it('without config', () => { + const element = document.createElement('div'); + const controller = new PTZController(element); + controller.setConfig(); + expect(element.getAttribute('data-orientation')).toBe('horizontal'); + }); + }); + describe('position', () => { + describe('with config', () => { + it.each([ + ['top-left' as const], + ['top-right' as const], + ['bottom-left' as const], + ['bottom-right' as const], + ])( + '%s', + (position: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right') => { + const element = document.createElement('div'); + const controller = new PTZController(element); + controller.setConfig(createConfig({ position: position })); + expect(element.getAttribute('data-position')).toBe(position); + }, + ); + }); + it('without config', () => { + const element = document.createElement('div'); + const controller = new PTZController(element); + controller.setConfig(); + expect(element.getAttribute('data-position')).toBe('bottom-right'); + }); + }); + it('with style in config', () => { + const element = document.createElement('div'); + const controller = new PTZController(element); + controller.setConfig(createConfig({ style: { transform: 'none', left: '50%' } })); + expect(element.getAttribute('style')).toBe('transform:none;left:50%'); + }); + }); + + describe('should respect mode', () => { + it('off', () => { + const controller = new PTZController(document.createElement('div')); + expect(controller.shouldDisplay()).toBeFalsy(); + }); + it('forced on', () => { + const controller = new PTZController(document.createElement('div')); + controller.setForceVisibility(true); + + expect(controller.shouldDisplay()).toBeTruthy(); + }); + it('forced off', () => { + const controller = new PTZController(document.createElement('div')); + controller.setForceVisibility(false); + expect(controller.shouldDisplay()).toBeFalsy(); + }); + + it('configured on', () => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig(createConfig({ mode: 'on' })); + expect(controller.shouldDisplay()).toBeTruthy(); + }); + it('configured off', () => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig(createConfig({ mode: 'off' })); + expect(controller.shouldDisplay()).toBeFalsy(); + }); + + it('auto without capability', () => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig(createConfig({ mode: 'auto' })); + controller.setCamera(createCameraManager(), 'camera.office'); + expect(controller.shouldDisplay()).toBeFalsy(); + }); + it('auto with capability', () => { + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); + const cameraManager = createCameraManager(store); + vi.mocked(cameraManager).getCameraCapabilities.mockReturnValue( + createCapabilities({ + ptz: { + left: ['relative'], + }, + }), + ); + + const controller = new PTZController(document.createElement('div')); + controller.setConfig(createConfig({ mode: 'auto' })); + controller.setCamera(cameraManager, 'camera.office'); + expect(controller.shouldDisplay()).toBeTruthy(); + }); + }); + + describe('should get PTZ actions', () => { + it.each([ + ['left' as const], + ['right' as const], + ['up' as const], + ['down' as const], + ['zoom_in' as const], + ['zoom_out' as const], + ])('%s', (actionName: PTZControlAction) => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig(createConfig()); + + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ + ptz: { + left: ['relative'], + right: ['relative'], + up: ['relative'], + down: ['relative'], + zoomIn: ['relative'], + zoomOut: ['relative'], + }, + }), + }, + ]); + + const cameraManager = createCameraManager(store); + controller.setCamera(cameraManager, 'camera.office'); + + expect(controller.getPTZActions()?.[actionName]).toEqual({ + start_tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + ptz_action: actionName, + ptz_phase: 'start', + }, + end_tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + ptz_action: actionName, + ptz_phase: 'stop', + }, + }); + }); + + it('home', () => { + const controller = new PTZController(document.createElement('div')); + controller.setConfig(createConfig()); + + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: new Capabilities({ + ptz: { + left: ['relative'], + right: ['relative'], + up: ['relative'], + down: ['relative'], + zoomIn: ['relative'], + zoomOut: ['relative'], + }, + }), + }, + ]); + + const cameraManager = createCameraManager(store); + controller.setCamera(cameraManager, 'camera.office'); + + expect(controller.getPTZActions()['home']).toEqual({ + tap_action: { + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + }, + }); + }); + }); + + describe('should handle action', () => { + it('successfully', () => { + const action = { + action: 'more-info' as const, + }; + const config = { + tap_action: action, + camera_entity: 'camera.office', + }; + + const element = document.createElement('div'); + const handler = vi.fn(); + element.addEventListener('frigate-card:action:execution-request', handler); + + const controller = new PTZController(element); + controller.setCamera(); + controller.handleAction( + new CustomEvent<{ action: string }>('@action', { detail: { action: 'tap' } }), + config, + ); + + expect(handler).toBeCalledWith( + expect.objectContaining({ + detail: { + action: action, + config: config, + }, + }), + ); + }); + + it('should not call action without actions config', () => { + const element = document.createElement('div'); + const handler = vi.fn(); + element.addEventListener('frigate-card:action:execution-request', handler); + + const controller = new PTZController(element); + controller.setCamera(); + controller.handleAction( + new CustomEvent<{ action: string }>('@action', { detail: { action: 'tap' } }), + ); + + expect(handler).not.toBeCalled(); + }); + + it('should not call action without hass', () => { + const element = document.createElement('div'); + const handler = vi.fn(); + element.addEventListener('frigate-card:action:execution-request', handler); + + const controller = new PTZController(element); + controller.setCamera(); + controller.handleAction( + new CustomEvent<{ action: string }>('@action', { detail: { action: 'tap' } }), + ); + + expect(handler).not.toBeCalled(); + }); + }); + + describe('should identify useful actions', () => { + it('without a camera', () => { + const controller = new PTZController(document.createElement('div')); + expect(controller.hasUsefulAction()).toEqual({ + pt: true, + z: true, + home: true, + }); + }); + + it('without camera PTZ capabilities', () => { + const controller = new PTZController(document.createElement('div')); + + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: createCapabilities({ + ptz: {}, + }), + }, + ]); + const cameraManager = createCameraManager(store); + controller.setCamera(cameraManager, 'camera.office'); + + expect(controller.hasUsefulAction()).toEqual({ + pt: true, + z: true, + home: true, + }); + }); + + it('with camera pan and tilt capabilities', () => { + const controller = new PTZController(document.createElement('div')); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: createCapabilities({ + ptz: { + left: ['relative'], + right: ['relative'], + up: ['relative'], + down: ['relative'], + }, + }), + }, + ]); + controller.setCamera(createCameraManager(store), 'camera.office'); + + expect(controller.hasUsefulAction()).toEqual({ + pt: true, + z: false, + home: false, + }); + }); + + it('with camera zoom capabilities', () => { + const controller = new PTZController(document.createElement('div')); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: createCapabilities({ + ptz: { + zoomIn: ['relative'], + zoomOut: ['relative'], + }, + }), + }, + ]); + controller.setCamera(createCameraManager(store), 'camera.office'); + + expect(controller.hasUsefulAction()).toEqual({ + pt: false, + z: true, + home: false, + }); + }); + + it('with camera presets', () => { + const controller = new PTZController(document.createElement('div')); + const store = createStore([ + { + cameraID: 'camera.office', + capabilities: createCapabilities({ + ptz: { + presets: ['door'], + }, + }), + }, + ]); + controller.setCamera(createCameraManager(store), 'camera.office'); + + expect(controller.hasUsefulAction()).toEqual({ + pt: false, + z: false, + home: true, + }); + }); + }); +}); diff --git a/tests/components-lib/zoom/zoom-controller.test.ts b/tests/components-lib/zoom/zoom-controller.test.ts index 46fa22e2..ed4a3689 100644 --- a/tests/components-lib/zoom/zoom-controller.test.ts +++ b/tests/components-lib/zoom/zoom-controller.test.ts @@ -5,7 +5,7 @@ import { ZoomController } from '../../../src/components-lib/zoom/zoom-controller import { ResizeObserverMock, requestAnimationFrameMock } from '../../test-utils'; vi.mock('@dermotduffy/panzoom'); -vi.mock('lodash-es/debounce', () => ({ +vi.mock('lodash-es/throttle', () => ({ default: vi.fn((fn) => fn), })); @@ -311,8 +311,8 @@ describe('ZoomController', () => { const element = document.createElement('div'); setElementToDefaultCardSize(element); - const defaultFunc = vi.fn(); - element.addEventListener('frigate-card:zoom:default', defaultFunc); + const changeFunc = vi.fn(); + element.addEventListener('frigate-card:zoom:change', changeFunc); vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); createAndRegisterZoom(element); @@ -327,8 +327,11 @@ describe('ZoomController', () => { }, }); element.dispatchEvent(ev_1); - expect(defaultFunc).toBeCalledWith( - expect.objectContaining({ detail: { isDefault: false } }), + + expect(changeFunc).toHaveBeenLastCalledWith( + expect.objectContaining({ + detail: expect.objectContaining({ isDefault: false }), + }), ); const ev_2 = new CustomEvent('panzoomchange', { @@ -341,8 +344,11 @@ describe('ZoomController', () => { }, }); element.dispatchEvent(ev_2); - expect(defaultFunc).toBeCalledWith( - expect.objectContaining({ detail: { isDefault: true } }), + + expect(changeFunc).toHaveBeenLastCalledWith( + expect.objectContaining({ + detail: expect.objectContaining({ isDefault: true }), + }), ); }); @@ -350,12 +356,12 @@ describe('ZoomController', () => { const element = document.createElement('div'); setElementToDefaultCardSize(element); - const defaultFunc = vi.fn(); - element.addEventListener('frigate-card:zoom:default', defaultFunc); + const changeFunc = vi.fn(); + element.addEventListener('frigate-card:zoom:change', changeFunc); vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); const controller = createAndRegisterZoom(element); - controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } }); + controller.setDefaultSettings({ zoom: 2, pan: { x: 3, y: 4 } }); const ev_1 = new CustomEvent('panzoomchange', { detail: { @@ -367,8 +373,11 @@ describe('ZoomController', () => { }, }); element.dispatchEvent(ev_1); - expect(defaultFunc).toHaveBeenLastCalledWith( - expect.objectContaining({ detail: { isDefault: false } }), + + expect(changeFunc).toHaveBeenLastCalledWith( + expect.objectContaining({ + detail: expect.objectContaining({ isDefault: false }), + }), ); const ev_2 = new CustomEvent('panzoomchange', { @@ -381,8 +390,11 @@ describe('ZoomController', () => { }, }); element.dispatchEvent(ev_2); - expect(defaultFunc).toHaveBeenLastCalledWith( - expect.objectContaining({ detail: { isDefault: true } }), + + expect(changeFunc).toHaveBeenLastCalledWith( + expect.objectContaining({ + detail: expect.objectContaining({ isDefault: true }), + }), ); }); @@ -390,8 +402,8 @@ describe('ZoomController', () => { const element = document.createElement('div'); setElementToDefaultCardSize(element); - const defaultFunc = vi.fn(); - element.addEventListener('frigate-card:zoom:default', defaultFunc); + const changeFunc = vi.fn(); + element.addEventListener('frigate-card:zoom:change', changeFunc); vi.mocked(Panzoom).mockReturnValueOnce(createMockPanZoom()); const controller = createAndRegisterZoom(element); @@ -406,11 +418,14 @@ describe('ZoomController', () => { }, }); element.dispatchEvent(ev_1); - expect(defaultFunc).toHaveBeenLastCalledWith( - expect.objectContaining({ detail: { isDefault: false } }), + + expect(changeFunc).toHaveBeenLastCalledWith( + expect.objectContaining({ + detail: expect.objectContaining({ isDefault: false }), + }), ); - controller.setDefaultConfig({}); + controller.setDefaultSettings({}); const ev_2 = new CustomEvent('panzoomchange', { detail: { @@ -422,8 +437,11 @@ describe('ZoomController', () => { }, }); element.dispatchEvent(ev_2); - expect(defaultFunc).toHaveBeenLastCalledWith( - expect.objectContaining({ detail: { isDefault: true } }), + + expect(changeFunc).toHaveBeenLastCalledWith( + expect.objectContaining({ + detail: expect.objectContaining({ isDefault: true }), + }), ); }); }); @@ -438,7 +456,7 @@ describe('ZoomController', () => { setElementToDefaultCardSize(element); const controller = new ZoomController(element); - controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } }); + controller.setDefaultSettings({ zoom: 2, pan: { x: 3, y: 4 } }); // Controller was not activated, config setting will not update pan/zoom. expect(panzoom.zoom).not.toBeCalled(); @@ -448,16 +466,16 @@ describe('ZoomController', () => { expect(Panzoom).toBeCalledWith( expect.anything(), expect.objectContaining({ - contain: "outside", + contain: 'outside', cursor: undefined, maxScale: 10, minScale: 1, noBind: true, - touchAction: "", + touchAction: '', startScale: 2, startX: 115.62, startY: 63.6525, - }) + }), ); }); @@ -469,12 +487,15 @@ describe('ZoomController', () => { setElementToDefaultCardSize(element); const controller = createAndRegisterZoom(element); - controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } }); + controller.setDefaultSettings({ zoom: 2, pan: { x: 3, y: 4 } }); triggerResizeObserver(); expect(panzoom.zoom).toBeCalledWith(2, { animate: false }); - expect(panzoom.pan).toBeCalledWith(115.62, 63.6525, { animate: false }); + expect(panzoom.pan).toBeCalledWith(115.62, 63.6525, { + animate: true, + duration: 100, + }); }); it('with set of config when a default is already set', () => { @@ -487,23 +508,25 @@ describe('ZoomController', () => { const controller = createAndRegisterZoom(element); // This call will do nothing since this is what zoom/pan already are. - controller.setDefaultConfig({ zoom: 1, pan: { x: 0, y: 0 } }); + controller.setDefaultSettings({ zoom: 1, pan: { x: 0, y: 0 } }); expect(panzoom.zoom).not.toBeCalled(); expect(panzoom.pan).not.toBeCalled(); - - controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } }); + + controller.setDefaultSettings({ zoom: 2, pan: { x: 3, y: 4 } }); expect(panzoom.zoom).toHaveBeenNthCalledWith(1, 2, { animate: false }); expect(panzoom.pan).toHaveBeenNthCalledWith(1, 115.62, 63.6525, { - animate: false, + animate: true, + duration: 100, }); - controller.setConfig({ zoom: 3, pan: { x: 5, y: 6 } }); + controller.setSettings({ zoom: 3, pan: { x: 5, y: 6 } }); expect(panzoom.zoom).toHaveBeenNthCalledWith(2, 3, { animate: false }); expect(panzoom.pan).toHaveBeenNthCalledWith(2, 147.6, 81.18, { - animate: false, + animate: true, + duration: 100, }); }); @@ -516,30 +539,31 @@ describe('ZoomController', () => { const controller = createAndRegisterZoom(element); - controller.setConfig({ zoom: 1 }); + controller.setSettings({ zoom: 1 }); expect(panzoom.zoom).not.toHaveBeenCalled(); - controller.setConfig({ pan: { x: 50, y: 50 } }); + controller.setSettings({ pan: { x: 50, y: 50 } }); expect(panzoom.zoom).not.toHaveBeenCalled(); - controller.setConfig({ zoom: 1, pan: { x: 50, y: 50 } }); + controller.setSettings({ zoom: 1, pan: { x: 50, y: 50 } }); expect(panzoom.zoom).not.toHaveBeenCalled(); - controller.setConfig({}); + controller.setSettings({}); expect(panzoom.zoom).not.toHaveBeenCalled(); - controller.setConfig({ zoom: 2 }); + controller.setSettings({ zoom: 2 }); expect(panzoom.zoom).toBeCalledTimes(1); expect(panzoom.pan).toBeCalledTimes(1); expect(panzoom.zoom).toHaveBeenNthCalledWith(1, 2, { animate: false }); expect(panzoom.pan).toHaveBeenNthCalledWith(1, 0, 0, { - animate: false, + animate: true, + duration: 100, }); vi.mocked(panzoom.getScale).mockReturnValue(2); vi.mocked(panzoom.getPan).mockReturnValue({ x: 0, y: 0 }); - controller.setConfig({ zoom: 2 }); + controller.setSettings({ zoom: 2 }); expect(panzoom.zoom).toBeCalledTimes(1); expect(panzoom.pan).toBeCalledTimes(1); @@ -553,15 +577,16 @@ describe('ZoomController', () => { setElementToDefaultCardSize(element); const controller = createAndRegisterZoom(element); - controller.setDefaultConfig({ zoom: 2, pan: { x: 3, y: 4 } }); + controller.setDefaultSettings({ zoom: 2, pan: { x: 3, y: 4 } }); mockClear(panzoom); - controller.setConfig({}); + controller.setSettings({}); // Should fall back to default. expect(panzoom.zoom).toBeCalledWith(2, { animate: false }); expect(panzoom.pan).toBeCalledWith(115.62, 63.6525, { - animate: false, + animate: true, + duration: 100, }); }); @@ -573,11 +598,12 @@ describe('ZoomController', () => { setElementToDefaultCardSize(element); const controller = createAndRegisterZoom(element); - controller.setConfig({ zoom: 2, pan: { x: 3, y: 4 } }); + controller.setSettings({ zoom: 2, pan: { x: 3, y: 4 } }); expect(panzoom.zoom).toHaveBeenNthCalledWith(1, 2, { animate: false }); expect(panzoom.pan).toHaveBeenNthCalledWith(1, 115.62, 63.6525, { - animate: false, + animate: true, + duration: 100, }); vi.mocked(panzoom.getScale).mockReturnValue(2); @@ -588,7 +614,8 @@ describe('ZoomController', () => { expect(panzoom.zoom).toHaveBeenNthCalledWith(2, 2, { animate: false }); expect(panzoom.pan).toHaveBeenNthCalledWith(2, 57.81, 31.82625, { - animate: false, + animate: true, + duration: 100, }); }); diff --git a/tests/components-lib/zoom/zoom-view-context.test.ts b/tests/components-lib/zoom/zoom-view-context.test.ts index 818cc569..25508b5a 100644 --- a/tests/components-lib/zoom/zoom-view-context.test.ts +++ b/tests/components-lib/zoom/zoom-view-context.test.ts @@ -1,14 +1,39 @@ import { describe, expect, it, vi } from 'vitest'; import { - generateViewContextForZoomChange, - handleZoomDefaultEvent, + generateViewContextForZoom, + handleZoomSettingsObservedEvent, } from '../../../src/components-lib/zoom/zoom-view-context'; -describe('generateViewContextForZoomChangeRequest', () => { - it('with config', () => { +describe('generateViewContextForZoom', () => { + it('with observed', () => { expect( - generateViewContextForZoomChange('target', { - zoom: { + generateViewContextForZoom('target', { + observed: { + pan: { x: 1, y: 2 }, + zoom: 3, + isDefault: true, + unzoomed: true, + }, + }), + ).toEqual({ + zoom: { + target: { + observed: { + pan: { x: 1, y: 2 }, + zoom: 3, + isDefault: true, + unzoomed: true, + }, + requested: null, + }, + }, + }); + }); + + it('with requested', () => { + expect( + generateViewContextForZoom('target', { + requested: { pan: { x: 1, y: 2 }, zoom: 3, }, @@ -16,7 +41,7 @@ describe('generateViewContextForZoomChangeRequest', () => { ).toEqual({ zoom: { target: { - zoom: { + requested: { pan: { x: 1, y: 2 }, zoom: 3, }, @@ -24,50 +49,23 @@ describe('generateViewContextForZoomChangeRequest', () => { }, }); }); - - it('without config', () => { - expect(generateViewContextForZoomChange('target')).toEqual({ - zoom: { - target: { - zoom: null, - }, - }, - }); - }); -}); - -describe('generateViewContextForZoomDefault', () => { - it('default', () => { - expect(generateViewContextForZoomChange('target', { isDefault: true })).toEqual({ - zoom: { - target: { - isDefault: true, - zoom: null, - }, - }, - }); - }); - - it('not default', () => { - expect(generateViewContextForZoomChange('target', { isDefault: false })).toEqual({ - zoom: { - target: { - isDefault: false, - zoom: null, - }, - }, - }); - }); }); // @vitest-environment jsdom -it('handleZoomDefaultEvent', () => { +it('handleZoomSettingsObservedEvent', () => { const element = document.createElement('div'); const callback = vi.fn(); element.addEventListener('frigate-card:view:change-context', callback); - handleZoomDefaultEvent( + handleZoomSettingsObservedEvent( element, - new CustomEvent('frigate-card:zoom:default', { detail: { isDefault: true } }), + new CustomEvent('frigate-card:zoom:change', { + detail: { + pan: { x: 1, y: 2 }, + zoom: 3, + isDefault: true, + unzoomed: true, + }, + }), 'target', ); expect(callback).toBeCalledWith( @@ -75,8 +73,8 @@ it('handleZoomDefaultEvent', () => { detail: { zoom: { target: { - zoom: null, - isDefault: true, + observed: { pan: { x: 1, y: 2 }, zoom: 3, isDefault: true, unzoomed: true }, + requested: null, }, }, }, diff --git a/tests/config/management.test.ts b/tests/config/management.test.ts index 9bfb248e..0b5df517 100644 --- a/tests/config/management.test.ts +++ b/tests/config/management.test.ts @@ -1,3 +1,4 @@ +import { CallServiceActionConfig } from '@dermotduffy/custom-card-helpers'; import { describe, expect, it } from 'vitest'; import { copyConfig, @@ -17,7 +18,13 @@ import { upgradeObjectRecursively, upgradeWithOverrides, } from '../../src/config/management'; -import { RawFrigateCardConfig } from '../../src/config/types'; +import { PTZControlAction } from '../../src/config/ptz'; +import { + Actions, + RawFrigateCardConfig, + frigateCardConfigSchema, +} from '../../src/config/types'; +import { getParseErrorPaths } from '../../src/utils/zod'; describe('general functions', () => { it('should set value', () => { @@ -354,6 +361,24 @@ describe('upgrade functions', () => { }); describe('should handle version specific upgrades', () => { + const postUpgradeChecks = (config: RawFrigateCardConfig): void => { + // Should be no additional upgrades. + expect(upgradeConfig(config)).toBeFalsy(); + + // Result should be parseable. + const result = frigateCardConfigSchema.safeParse(config); + if (!result.success) { + expect( + result.success, + 'Post-upgrade parse error.\n\n' + + 'Problem paths: ' + + [...getParseErrorPaths(result.error)] + + '\n\n' + + JSON.stringify(config, null, 2), + ).toBeTruthy(); + } + }; + describe('v4.1.0', () => { describe('should rename mediaLoaded to media_loaded', () => { it('elements', () => { @@ -362,11 +387,13 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { + type: 'custom:random', conditions: { mediaLoaded: true, }, }, { + type: 'custom:random2', conditions: 'not an object', }, ], @@ -377,6 +404,7 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { + type: 'custom:random', conditions: [ { condition: 'media_loaded' as const, @@ -385,10 +413,12 @@ describe('should handle version specific upgrades', () => { ], }, { + type: 'custom:random2', conditions: 'not an object', }, ], }); + postUpgradeChecks(config); }); it('overrides', () => { @@ -428,6 +458,7 @@ describe('should handle version specific upgrades', () => { }, ], }); + postUpgradeChecks(config); }); }); @@ -447,6 +478,7 @@ describe('should handle version specific upgrades', () => { foo: 'bar', }, }); + postUpgradeChecks(config); }); it('should rename menu.buttons.frigate_ui to menu.buttons.camera_ui', () => { @@ -462,7 +494,12 @@ describe('should handle version specific upgrades', () => { }, overrides: [ { - conditions: {}, + conditions: [ + { + condition: 'view', + views: ['clips'], + }, + ], overrides: { menu: { buttons: { @@ -488,7 +525,12 @@ describe('should handle version specific upgrades', () => { }, overrides: [ { - conditions: {}, + conditions: [ + { + condition: 'view', + views: ['clips'], + }, + ], merge: { menu: { buttons: { @@ -501,6 +543,7 @@ describe('should handle version specific upgrades', () => { }, ], }); + postUpgradeChecks(config); }); it('should rename frigate ui actions', () => { @@ -549,6 +592,7 @@ describe('should handle version specific upgrades', () => { }, }, }); + postUpgradeChecks(config); }); describe('should rename frigate-jsmpeg provider to jsmpeg', () => { @@ -562,6 +606,7 @@ describe('should handle version specific upgrades', () => { type: 'custom:frigate-card', cameras: [{ live_provider: 'ha' }, { live_provider: 'jsmpeg' }], }); + postUpgradeChecks(config); }); }); @@ -571,6 +616,7 @@ describe('should handle version specific upgrades', () => { (objName: string) => { const config = { type: 'custom:frigate-card', + cameras: [{}], live: { [objName]: { foo: 'bar', @@ -580,6 +626,7 @@ describe('should handle version specific upgrades', () => { expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ type: 'custom:frigate-card', + cameras: [{}], cameras_global: { [objName]: { foo: 'bar', @@ -587,6 +634,7 @@ describe('should handle version specific upgrades', () => { }, live: {}, }); + postUpgradeChecks(config); }, ); }); @@ -608,6 +656,7 @@ describe('should handle version specific upgrades', () => { { live_provider: 'jsmpeg' }, ], }); + postUpgradeChecks(config); }); }); @@ -627,6 +676,7 @@ describe('should handle version specific upgrades', () => { { live_provider: 'jsmpeg' }, ], }); + postUpgradeChecks(config); }); }); @@ -732,6 +782,7 @@ describe('should handle version specific upgrades', () => { }, }, }); + postUpgradeChecks(config); }); it('negative case', () => { const config = { @@ -749,6 +800,7 @@ describe('should handle version specific upgrades', () => { default: 'live', }, }); + postUpgradeChecks(config); }); }); @@ -781,18 +833,20 @@ describe('should handle version specific upgrades', () => { expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ cameras: [{ camera_entity: 'camera.office' }], + cameras_global: { + ptz: { + actions_up: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + }, live: { controls: { ptz: { - actions_up: { - tap_action: { - action: 'call-service', - data: { - message: 'Hello 1', - }, - service: 'notify.persistent_notification', - }, - }, orientation: 'vertical', style: { color: 'white', @@ -804,6 +858,7 @@ describe('should handle version specific upgrades', () => { }, type: 'custom:frigate-card', }); + postUpgradeChecks(config); }); it('case with >1 element', () => { @@ -842,6 +897,17 @@ describe('should handle version specific upgrades', () => { expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ cameras: [{ camera_entity: 'camera.office' }], + cameras_global: { + ptz: { + actions_up: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + }, elements: [ { service: 'service', @@ -855,15 +921,6 @@ describe('should handle version specific upgrades', () => { live: { controls: { ptz: { - actions_up: { - tap_action: { - action: 'call-service', - data: { - message: 'Hello 1', - }, - service: 'notify.persistent_notification', - }, - }, orientation: 'vertical', style: { color: 'white', @@ -875,6 +932,7 @@ describe('should handle version specific upgrades', () => { }, type: 'custom:frigate-card', }); + postUpgradeChecks(config); }); it('case with custom conditional element with 2 PTZ but nothing else', () => { @@ -932,18 +990,20 @@ describe('should handle version specific upgrades', () => { expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ cameras: [{ camera_entity: 'camera.office' }], + cameras_global: { + ptz: { + actions_up: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + }, live: { controls: { ptz: { - actions_up: { - tap_action: { - action: 'call-service', - data: { - message: 'Hello 1', - }, - service: 'notify.persistent_notification', - }, - }, orientation: 'vertical', style: { color: 'white', @@ -955,6 +1015,7 @@ describe('should handle version specific upgrades', () => { }, type: 'custom:frigate-card', }); + postUpgradeChecks(config); }); it('case with custom conditional element with 1 PTZ and another element', () => { @@ -1002,18 +1063,20 @@ describe('should handle version specific upgrades', () => { expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ cameras: [{ camera_entity: 'camera.office' }], + cameras_global: { + ptz: { + actions_up: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + }, live: { controls: { ptz: { - actions_up: { - tap_action: { - action: 'call-service', - data: { - message: 'Hello 1', - }, - service: 'notify.persistent_notification', - }, - }, orientation: 'vertical', style: { color: 'white', @@ -1050,6 +1113,7 @@ describe('should handle version specific upgrades', () => { ], type: 'custom:frigate-card', }); + postUpgradeChecks(config); }); it('case with stock conditional element with 1 PTZ', () => { @@ -1086,18 +1150,20 @@ describe('should handle version specific upgrades', () => { expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ cameras: [{ camera_entity: 'camera.office' }], + cameras_global: { + ptz: { + actions_up: { + action: 'call-service', + data: { + message: 'Hello 1', + }, + service: 'notify.persistent_notification', + }, + }, + }, live: { controls: { ptz: { - actions_up: { - tap_action: { - action: 'call-service', - data: { - message: 'Hello 1', - }, - service: 'notify.persistent_notification', - }, - }, orientation: 'vertical', style: { color: 'white', @@ -1109,6 +1175,7 @@ describe('should handle version specific upgrades', () => { }, type: 'custom:frigate-card', }); + postUpgradeChecks(config); }); it('case when live.controls.ptz already exists', () => { @@ -1160,18 +1227,20 @@ describe('should handle version specific upgrades', () => { expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ cameras: [{ camera_entity: 'camera.office' }], + cameras_global: { + ptz: { + actions_up: { + action: 'call-service', + data: { + message: 'Original', + }, + service: 'notify.persistent_notification', + }, + }, + }, live: { controls: { ptz: { - actions_up: { - tap_action: { - action: 'call-service', - data: { - message: 'Original', - }, - service: 'notify.persistent_notification', - }, - }, orientation: 'vertical', style: { color: 'white', @@ -1183,6 +1252,7 @@ describe('should handle version specific upgrades', () => { }, type: 'custom:frigate-card', }); + postUpgradeChecks(config); }); }); @@ -1202,6 +1272,7 @@ describe('should handle version specific upgrades', () => { interaction_seconds: 200, }, }); + postUpgradeChecks(config); }); describe('should handle all and never action conditions', () => { @@ -1209,197 +1280,272 @@ describe('should handle version specific upgrades', () => { describe('lazy_unload', () => { it('all', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { lazy_unload: 'all', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: { lazy_unload: ['unselected', 'hidden'], }, }); + postUpgradeChecks(config); }); it('never', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { lazy_unload: 'never', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: {}, }); + postUpgradeChecks(config); }); it('other value', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { lazy_unload: 'unselected', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: { lazy_unload: ['unselected'], }, }); + postUpgradeChecks(config); }); }); describe('auto_play', () => { it('all', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { auto_play: 'all', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: {}, }); + postUpgradeChecks(config); }); it('never', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { auto_play: 'never', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: { auto_play: [], }, }); + postUpgradeChecks(config); }); it('other value', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { auto_play: 'selected', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: { auto_play: ['selected'], }, }); + postUpgradeChecks(config); }); }); describe('auto_pause', () => { it('all', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { auto_pause: 'all', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: { auto_pause: ['unselected', 'hidden'], }, }); + postUpgradeChecks(config); }); it('never', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { auto_pause: 'never', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: {}, }); + postUpgradeChecks(config); }); it('other value', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { auto_pause: 'unselected', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: { auto_pause: ['unselected'], }, }); + postUpgradeChecks(config); }); }); describe('auto_mute', () => { it('all', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { auto_mute: 'all', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: {}, }); + postUpgradeChecks(config); }); it('never', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { auto_mute: 'never', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: { auto_mute: [], }, }); + postUpgradeChecks(config); }); it('other value', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { auto_mute: 'unselected', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: { auto_mute: ['unselected'], }, }); + postUpgradeChecks(config); }); }); describe('auto_unmute', () => { it('all', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { auto_unmute: 'all', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: { auto_unmute: ['selected', 'visible', 'microphone'], }, }); + postUpgradeChecks(config); }); it('never', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { auto_unmute: 'never', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: {}, }); + postUpgradeChecks(config); }); it('other value', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { auto_unmute: 'selected', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: { auto_unmute: ['selected'], }, }); + postUpgradeChecks(config); }); }); }); @@ -1408,157 +1554,217 @@ describe('should handle version specific upgrades', () => { describe('auto_play', () => { it('all', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_play: 'all', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: {}, }); + postUpgradeChecks(config); }); it('never', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_play: 'never', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_play: [], }, }); + postUpgradeChecks(config); }); it('other value', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_play: 'selected', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_play: ['selected'], }, }); + postUpgradeChecks(config); }); }); describe('auto_pause', () => { it('all', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_pause: 'all', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: {}, }); + postUpgradeChecks(config); }); it('never', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_pause: 'never', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_pause: [], }, }); + postUpgradeChecks(config); }); it('other value', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_pause: 'unselected', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_pause: ['unselected'], }, }); + postUpgradeChecks(config); }); }); describe('auto_mute', () => { it('all', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_mute: 'all', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: {}, }); + postUpgradeChecks(config); }); it('never', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_mute: 'never', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_mute: [], }, }); + postUpgradeChecks(config); }); it('other value', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_mute: 'unselected', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_mute: ['unselected'], }, }); + postUpgradeChecks(config); }); }); describe('auto_unmute', () => { it('all', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_unmute: 'all', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_unmute: ['selected', 'visible'], }, }); + postUpgradeChecks(config); }); it('never', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_unmute: 'never', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: {}, }); + postUpgradeChecks(config); }); it('other value', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_unmute: 'selected', }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { auto_unmute: ['selected'], }, }); + postUpgradeChecks(config); }); }); }); @@ -1569,6 +1775,8 @@ describe('should handle version specific upgrades', () => { '%s', (mediaEventType: string) => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { controls: { thumbnails: { @@ -1579,6 +1787,8 @@ describe('should handle version specific upgrades', () => { }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: { controls: { thumbnails: { @@ -1587,6 +1797,7 @@ describe('should handle version specific upgrades', () => { }, }, }); + postUpgradeChecks(config); }, ); }); @@ -1596,16 +1807,21 @@ describe('should handle version specific upgrades', () => { '%s', (mediaEventType: string) => { const config = { + type: 'custom:frigate-card', + cameras: [{}], timeline: { media: mediaEventType, }, }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], timeline: { events_media_type: mediaEventType, }, }); + postUpgradeChecks(config); }, ); }); @@ -1615,6 +1831,8 @@ describe('should handle version specific upgrades', () => { '%s', (mediaEventType: string) => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { controls: { timeline: { @@ -1625,6 +1843,8 @@ describe('should handle version specific upgrades', () => { }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: { controls: { timeline: { @@ -1633,6 +1853,7 @@ describe('should handle version specific upgrades', () => { }, }, }); + postUpgradeChecks(config); }, ); }); @@ -1642,6 +1863,8 @@ describe('should handle version specific upgrades', () => { '%s', (mediaEventType: string) => { const config = { + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { controls: { timeline: { @@ -1652,6 +1875,8 @@ describe('should handle version specific upgrades', () => { }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], media_viewer: { controls: { timeline: { @@ -1660,6 +1885,7 @@ describe('should handle version specific upgrades', () => { }, }, }); + postUpgradeChecks(config); }, ); }); @@ -1688,6 +1914,7 @@ describe('should handle version specific upgrades', () => { }, }, }); + postUpgradeChecks(config); }); it('when false', () => { @@ -1708,12 +1935,15 @@ describe('should handle version specific upgrades', () => { triggers: {}, }, }); + postUpgradeChecks(config); }); }); describe('should rename view.scan.enabled to a trigger action', () => { it('when true', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], view: { scan: { enabled: true, @@ -1722,6 +1952,8 @@ describe('should handle version specific upgrades', () => { }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], view: { triggers: { filter_selected_camera: false, @@ -1731,10 +1963,13 @@ describe('should handle version specific upgrades', () => { }, }, }); + postUpgradeChecks(config); }); it('when false', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], view: { scan: { enabled: false, @@ -1743,10 +1978,13 @@ describe('should handle version specific upgrades', () => { }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], view: { triggers: {}, }, }); + postUpgradeChecks(config); }); }); }); @@ -1754,6 +1992,8 @@ describe('should handle version specific upgrades', () => { describe('should handle media layout changes', () => { it('from live.layout to camera_global.dimensions', () => { const config = { + type: 'custom:frigate-card', + cameras: [{}], live: { layout: { fit: 'cover', @@ -1766,6 +2006,8 @@ describe('should handle version specific upgrades', () => { }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], live: {}, cameras_global: { dimensions: { @@ -1779,6 +2021,7 @@ describe('should handle version specific upgrades', () => { }, }, }); + postUpgradeChecks(config); }); describe('from delete old media layouts', () => { @@ -1786,6 +2029,8 @@ describe('should handle version specific upgrades', () => { '%s', (section: string) => { const config = { + type: 'custom:frigate-card', + cameras: [{}], [section]: { layout: { fit: 'cover', @@ -1798,8 +2043,11 @@ describe('should handle version specific upgrades', () => { }; expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], [section]: {}, }); + postUpgradeChecks(config); }, ); }); @@ -1813,11 +2061,13 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { + type: 'custom:random', conditions: { view: ['clips', 'snapshots'], }, }, { + type: 'custom:random2', conditions: 'not an object', }, ], @@ -1828,6 +2078,7 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { + type: 'custom:random', conditions: [ { condition: 'view' as const, @@ -1836,10 +2087,12 @@ describe('should handle version specific upgrades', () => { ], }, { + type: 'custom:random2', conditions: 'not an object', }, ], }); + postUpgradeChecks(config); }); it('overrides', () => { @@ -1880,6 +2133,7 @@ describe('should handle version specific upgrades', () => { }, ], }); + postUpgradeChecks(config); }); it('automations', () => { @@ -1891,10 +2145,12 @@ describe('should handle version specific upgrades', () => { conditions: { view: ['clips', 'snapshots'], }, - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, + actions: [ + { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + ], }, ], }; @@ -1911,13 +2167,16 @@ describe('should handle version specific upgrades', () => { views: ['clips', 'snapshots'], }, ], - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, + actions: [ + { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + ], }, ], }); + postUpgradeChecks(config); }); }); @@ -1928,11 +2187,13 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { + type: 'custom:random', conditions: { camera: ['camera_1', 'camera_2'], }, }, { + type: 'custom:random2', conditions: 'not an object', }, ], @@ -1943,6 +2204,7 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { + type: 'custom:random', conditions: [ { condition: 'camera' as const, @@ -1951,10 +2213,12 @@ describe('should handle version specific upgrades', () => { ], }, { + type: 'custom:random2', conditions: 'not an object', }, ], }); + postUpgradeChecks(config); }); it('overrides', () => { @@ -1995,6 +2259,7 @@ describe('should handle version specific upgrades', () => { }, ], }); + postUpgradeChecks(config); }); it('automations', () => { @@ -2006,10 +2271,12 @@ describe('should handle version specific upgrades', () => { conditions: { camera: ['camera_1', 'camera_2'], }, - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, + actions: [ + { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + ], }, ], }; @@ -2026,13 +2293,16 @@ describe('should handle version specific upgrades', () => { cameras: ['camera_1', 'camera_2'], }, ], - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, + actions: [ + { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + ], }, ], }); + postUpgradeChecks(config); }); }); @@ -2048,11 +2318,13 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { + type: 'custom:random', conditions: { [condition]: true, }, }, { + type: 'custom:random2', conditions: 'not an object', }, ], @@ -2063,6 +2335,7 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { + type: 'custom:random', conditions: [ { condition: condition, @@ -2071,10 +2344,12 @@ describe('should handle version specific upgrades', () => { ], }, { + type: 'custom:random2', conditions: 'not an object', }, ], }); + postUpgradeChecks(config); }); it('overrides', () => { @@ -2115,6 +2390,7 @@ describe('should handle version specific upgrades', () => { }, ], }); + postUpgradeChecks(config); }); it('automations', () => { @@ -2126,10 +2402,12 @@ describe('should handle version specific upgrades', () => { conditions: { [condition]: true, }, - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, + actions: [ + { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + ], }, ], }; @@ -2146,13 +2424,16 @@ describe('should handle version specific upgrades', () => { [condition]: true, }, ], - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, + actions: [ + { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + ], }, ], }); + postUpgradeChecks(config); }); }); }); @@ -2164,6 +2445,7 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { + type: 'custom:random', conditions: { state: [ { @@ -2179,6 +2461,7 @@ describe('should handle version specific upgrades', () => { }, }, { + type: 'custom:random2', conditions: 'not an object', }, ], @@ -2189,6 +2472,7 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { + type: 'custom:random', conditions: [ { condition: 'state' as const, @@ -2203,10 +2487,12 @@ describe('should handle version specific upgrades', () => { ], }, { + type: 'custom:random2', conditions: 'not an object', }, ], }); + postUpgradeChecks(config); }); it('overrides', () => { @@ -2263,6 +2549,7 @@ describe('should handle version specific upgrades', () => { }, ], }); + postUpgradeChecks(config); }); it('automations', () => { @@ -2284,11 +2571,12 @@ describe('should handle version specific upgrades', () => { {}, ], }, - - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, + actions: [ + { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + ], }, ], }; @@ -2311,13 +2599,16 @@ describe('should handle version specific upgrades', () => { state_not: 'off', }, ], - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, + actions: [ + { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + ], }, ], }); + postUpgradeChecks(config); }); }); @@ -2328,11 +2619,13 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { + type: 'custom:random', conditions: { media_query: 'query', }, }, { + type: 'custom:random2', conditions: 'not an object', }, ], @@ -2343,6 +2636,7 @@ describe('should handle version specific upgrades', () => { cameras: [{ camera_entity: 'camera.office' }], elements: [ { + type: 'custom:random', conditions: [ { condition: 'screen' as const, @@ -2351,10 +2645,12 @@ describe('should handle version specific upgrades', () => { ], }, { + type: 'custom:random2', conditions: 'not an object', }, ], }); + postUpgradeChecks(config); }); it('overrides', () => { @@ -2395,6 +2691,7 @@ describe('should handle version specific upgrades', () => { }, ], }); + postUpgradeChecks(config); }); it('automations', () => { @@ -2406,10 +2703,12 @@ describe('should handle version specific upgrades', () => { conditions: { media_query: 'query', }, - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, + actions: [ + { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + ], }, ], }; @@ -2426,13 +2725,16 @@ describe('should handle version specific upgrades', () => { media_query: 'query', }, ], - actions: { - action: 'custom:frigate-card-action' as const, - frigate_card_action: 'live_substream_on' as const, - }, + actions: [ + { + action: 'custom:frigate-card-action' as const, + frigate_card_action: 'live_substream_on' as const, + }, + ], }, ], }); + postUpgradeChecks(config); }); }); }); @@ -2453,18 +2755,19 @@ describe('should handle version specific upgrades', () => { cameras: [ { camera_entity: 'camera.office', - capabilities: { disable_except: 'substream' }, + capabilities: { disable_except: ['substream'] }, }, { camera_entity: 'camera.sitting_room' }, ], }); + postUpgradeChecks(config); }); describe('from performance profile to generic profile', () => { it('low performance', () => { const config = { type: 'custom:frigate-card', - cameras: [], + cameras: [{}], performance: { profile: 'low', }, @@ -2473,16 +2776,17 @@ describe('should handle version specific upgrades', () => { expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ type: 'custom:frigate-card', - cameras: [], + cameras: [{}], profiles: ['low-performance'], performance: {}, }); + postUpgradeChecks(config); }); it('high performance', () => { const config = { type: 'custom:frigate-card', - cameras: [], + cameras: [{}], performance: { profile: 'high', }, @@ -2491,9 +2795,10 @@ describe('should handle version specific upgrades', () => { expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ type: 'custom:frigate-card', - cameras: [], + cameras: [{}], performance: {}, }); + postUpgradeChecks(config); }); }); }); @@ -2501,13 +2806,13 @@ describe('should handle version specific upgrades', () => { it('from overrides to merge', () => { const config = { type: 'custom:frigate-card', - cameras: [], + cameras: [{}], overrides: [ { conditions: [ { condition: 'view', - view: ['clips'], + views: ['clips'], }, ], overrides: { @@ -2522,13 +2827,13 @@ describe('should handle version specific upgrades', () => { expect(upgradeConfig(config)).toBeTruthy(); expect(config).toEqual({ type: 'custom:frigate-card', - cameras: [], + cameras: [{}], overrides: [ { conditions: [ { condition: 'view', - view: ['clips'], + views: ['clips'], }, ], merge: { @@ -2539,6 +2844,261 @@ describe('should handle version specific upgrades', () => { }, ], }); + postUpgradeChecks(config); + }); + + describe('split live.ptz', () => { + const getAction = (action: PTZControlAction): CallServiceActionConfig => ({ + action: 'call-service', + service: 'service', + data: { + arg: action, + }, + }); + + const getTapAction = (action: PTZControlAction): Actions => ({ + tap_action: getAction(action), + }); + + it('with action_ format', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + live: { + controls: { + ptz: { + actions_up: getTapAction('up'), + actions_down: getTapAction('down'), + actions_left: getTapAction('left'), + actions_right: getTapAction('right'), + actions_zoom_in: getTapAction('zoom_in'), + actions_zoom_out: getTapAction('zoom_out'), + actions_home: { + ...getTapAction('home'), + double_tap_action: getAction('up'), + }, + + mode: 'auto' as const, + position: 'bottom-right' as const, + orientation: 'horizontal' as const, + hide_pan_tilt: false, + hide_zoom: false, + hide_home: false, + style: { + color: 'red', + }, + + something_not_related: 'very_unrelated', + }, + }, + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], + cameras_global: { + ptz: { + actions_left: getAction('left'), + actions_right: getAction('right'), + actions_up: getAction('up'), + actions_down: getAction('down'), + actions_zoom_in: getAction('zoom_in'), + actions_zoom_out: getAction('zoom_out'), + presets: { + home: getAction('home'), + }, + }, + }, + live: { + controls: { + ptz: { + mode: 'auto' as const, + position: 'bottom-right' as const, + orientation: 'horizontal' as const, + hide_pan_tilt: false, + hide_zoom: false, + hide_home: false, + style: { + color: 'red', + }, + }, + }, + }, + }); + postUpgradeChecks(config); + }); + + it('with data_ format', () => { + const getDataAction = (action: PTZControlAction): Actions => ({ + action: { + device: '048123', + cmd: action, + }, + }); + + const config = { + type: 'custom:frigate-card', + cameras: [{}], + live: { + controls: { + ptz: { + service: 'service', + data_up: getDataAction('up'), + data_down: getDataAction('down'), + data_left: getDataAction('left'), + data_right: getDataAction('right'), + data_zoom_in: getDataAction('zoom_in'), + data_zoom_out: getDataAction('zoom_out'), + data_home: getDataAction('home'), + + mode: 'auto' as const, + position: 'bottom-right' as const, + orientation: 'horizontal' as const, + hide_pan_tilt: false, + hide_zoom: false, + hide_home: false, + style: { + color: 'red', + }, + + something_not_related: 'very_unrelated', + }, + }, + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], + cameras_global: { + ptz: { + service: 'service', + data_left: getDataAction('left'), + data_right: getDataAction('right'), + data_up: getDataAction('up'), + data_down: getDataAction('down'), + data_zoom_in: getDataAction('zoom_in'), + data_zoom_out: getDataAction('zoom_out'), + presets: { + service: 'service', + data_home: getDataAction('home'), + }, + }, + }, + live: { + controls: { + ptz: { + mode: 'auto' as const, + position: 'bottom-right' as const, + orientation: 'horizontal' as const, + hide_pan_tilt: false, + hide_zoom: false, + hide_home: false, + style: { + color: 'red', + }, + }, + }, + }, + }); + postUpgradeChecks(config); + }); + + it('with invalid ptz type', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + live: { + controls: { + ptz: 3, // Not an object. + }, + }, + }; + + expect(upgradeConfig(config)).toBeFalsy(); + }); + + it('with nothing to transform', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + live: { + controls: { + ptz: { + mode: 'auto', + }, + }, + }, + }; + + expect(upgradeConfig(config)).toBeFalsy(); + }); + + it('without tap_action', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + live: { + controls: { + ptz: { + actions_up: { + double_tap_action: getAction('up'), + }, + actions_down: getTapAction('down'), + }, + }, + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual( + expect.objectContaining({ + cameras_global: { + ptz: { + actions_down: getAction('down'), + }, + }, + }), + ); + postUpgradeChecks(config); + }); + + it('without pre-existing presets', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + live: { + controls: { + ptz: { + presets: { + home: getAction('left'), + other: getAction('right'), + }, + actions_home: getTapAction('home'), + }, + }, + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual( + expect.objectContaining({ + cameras_global: { + ptz: { + presets: { + other: getAction('right'), + home: getAction('home'), + }, + }, + }, + }), + ); + postUpgradeChecks(config); + }); + }); }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 05342c9d..93b8b56c 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -1,10 +1,10 @@ import { describe, expect, it } from 'vitest'; import { + cameraConfigSchema, conditionalSchema, customSchema, dimensionsConfigSchema, frigateCardCustomActionsBaseSchema, - frigateCardPTZSchema, } from '../../src/config/types'; import { createConfig } from '../test-utils'; @@ -36,6 +36,10 @@ describe('config defaults', () => { file_pattern: '%H-%M-%S', }, }, + ptz: { + c2r_delay_between_calls_seconds: 0.2, + r2c_delay_between_calls_seconds: 0.5, + }, triggers: { events: ['events', 'clips', 'snapshots'], entities: [], @@ -55,7 +59,6 @@ describe('config defaults', () => { image: { mode: 'url', refresh_seconds: 1, - zoomable: true, }, live: { auto_mute: ['unselected', 'hidden', 'microphone'], @@ -72,7 +75,7 @@ describe('config defaults', () => { hide_home: false, hide_pan_tilt: false, hide_zoom: false, - mode: 'on', + mode: 'auto', orientation: 'horizontal', position: 'bottom-right', }, @@ -135,6 +138,14 @@ describe('config defaults', () => { size: 48, style: 'thumbnails', }, + ptz: { + hide_home: false, + hide_pan_tilt: false, + hide_zoom: false, + mode: 'off', + orientation: 'horizontal', + position: 'bottom-right', + }, thumbnails: { mode: 'right', show_details: true, @@ -175,10 +186,6 @@ describe('config defaults', () => { enabled: true, priority: 50, }, - default_zoom: { - enabled: true, - priority: 50, - }, display_mode: { enabled: true, priority: 50, @@ -224,10 +231,14 @@ describe('config defaults', () => { enabled: false, priority: 50, }, - ptz: { + ptz_controls: { enabled: false, priority: 50, }, + ptz_home: { + enabled: true, + priority: 50, + }, recordings: { enabled: false, priority: 50, @@ -285,6 +296,30 @@ describe('config defaults', () => { camera_select: 'current', dark_mode: 'off', default: 'live', + keyboard_shortcuts: { + enabled: true, + ptz_down: { + key: 'ArrowDown', + }, + ptz_home: { + key: 'h', + }, + ptz_left: { + key: 'ArrowLeft', + }, + ptz_right: { + key: 'ArrowRight', + }, + ptz_up: { + key: 'ArrowUp', + }, + ptz_zoom_in: { + key: '+', + }, + ptz_zoom_out: { + key: '-', + }, + }, triggers: { show_trigger_status: false, untrigger_seconds: 0, @@ -336,46 +371,136 @@ it('should transform action', () => { }); describe('should convert webrtc card PTZ to Frigate card PTZ', () => { - it.each([ - ['left' as const], - ['right' as const], - ['up' as const], - ['down' as const], - ['zoom_in' as const], - ['zoom_out' as const], - ['home' as const], - ])('%s', (action: string) => { - expect( - frigateCardPTZSchema.parse({ - type: 'custom:frigate-card-ptz', - service: 'foo', - [`data_${action}`]: { - tap_action: { - action: 'none', + describe('relative actions', () => { + it.each([ + ['left' as const], + ['right' as const], + ['up' as const], + ['down' as const], + ['zoom_in' as const], + ['zoom_out' as const], + ])('%s', (action: string) => { + expect( + cameraConfigSchema.parse({ + ptz: { + service: 'foo', + [`data_${action}`]: { + device: '048123', + cmd: action, + }, }, - }, - }), - ).toEqual({ - [`actions_${action}`]: { - tap_action: { - action: 'call-service', - service: 'foo', - data: { - tap_action: { - action: 'none', + }), + ).toEqual( + expect.objectContaining({ + ptz: expect.objectContaining({ + [`actions_${action}`]: { + action: 'call-service', + service: 'foo', + data: { + device: '048123', + cmd: action, + }, + }, + }), + }), + ); + }); + }); + + describe('continuous actions', () => { + it.each([ + ['left' as const], + ['right' as const], + ['up' as const], + ['down' as const], + ['zoom_in' as const], + ['zoom_out' as const], + ])('%s', (action: string) => { + expect( + cameraConfigSchema.parse({ + ptz: { + service: 'foo', + [`data_${action}_start`]: { + device: '048123', + cmd: action, + phase: 'start', + }, + [`data_${action}_stop`]: { + device: '048123', + cmd: action, + phase: 'stop', + }, + }, + }), + ).toEqual( + expect.objectContaining({ + ptz: expect.objectContaining({ + [`actions_${action}_start`]: { + action: 'call-service', + service: 'foo', + data: { + device: '048123', + cmd: action, + phase: 'start', + }, + }, + [`actions_${action}_stop`]: { + action: 'call-service', + service: 'foo', + data: { + device: '048123', + cmd: action, + phase: 'stop', + }, + }, + }), + }), + ); + }); + }); + + it('presets', () => { + expect( + cameraConfigSchema.parse({ + ptz: { + service: 'service_outer', + presets: { + service: 'service_inner', + data_home: { + device: '048123', + cmd: 'home', + }, + data_another: { + device: '048123', + cmd: 'another', }, }, }, - }, - service: 'foo', - - hide_home: false, - hide_pan_tilt: false, - hide_zoom: false, - mode: 'on', - orientation: 'horizontal', - position: 'bottom-right', - }); + }), + ).toEqual( + expect.objectContaining({ + ptz: expect.objectContaining({ + presets: { + home: { + action: 'call-service', + service: 'service_inner', + data: { + device: '048123', + cmd: 'home', + }, + }, + another: { + action: 'call-service', + service: 'service_inner', + data: { + device: '048123', + cmd: 'another', + }, + }, + }, + }), + }), + ); }); }); diff --git a/tests/test-utils.ts b/tests/test-utils.ts index 3b1cf6e2..6b97f48e 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -14,13 +14,13 @@ import { CameraEventCallback, CameraManagerMediaCapabilities, } from '../src/camera-manager/types'; -import { ActionsManager } from '../src/card-controller/actions-manager'; +import { ActionsManager } from '../src/card-controller/actions/actions-manager'; import { AutoUpdateManager } from '../src/card-controller/auto-update-manager'; import { AutomationsManager } from '../src/card-controller/automations-manager'; import { CameraURLManager } from '../src/card-controller/camera-url-manager'; import { CardElementManager } from '../src/card-controller/card-element-manager'; import { ConditionsManager } from '../src/card-controller/conditions-manager'; -import { ConfigManager } from '../src/card-controller/config-manager'; +import { ConfigManager } from '../src/card-controller/config/config-manager'; import { CardController } from '../src/card-controller/controller'; import { DownloadManager } from '../src/card-controller/download-manager'; import { ExpandManager } from '../src/card-controller/expand-manager'; @@ -40,11 +40,13 @@ import { CameraConfig, FrigateCardCondition, FrigateCardConfig, + FrigateCardCustomAction, PerformanceConfig, RawFrigateCardConfig, cameraConfigSchema, frigateCardConditionSchema, frigateCardConfigSchema, + frigateCardCustomActionSchema, performanceConfigSchema, } from '../src/config/types'; import { CapabilitiesRaw, ExtendedHomeAssistant, MediaLoadedInfo } from '../src/types'; @@ -53,6 +55,17 @@ import { Entity } from '../src/utils/ha/entity-registry/types'; import { ViewMedia, ViewMediaType } from '../src/view/media'; import { MediaQueriesResults } from '../src/view/media-queries-results'; import { View, ViewParameters } from '../src/view/view'; +import { KeyboardStateManager } from '../src/card-controller/keyboard-state-manager'; + +export const createAction = ( + action: Record, +): FrigateCardCustomAction | null => { + const result = frigateCardCustomActionSchema.safeParse({ + action: 'custom:frigate-card-action', + ...action, + }); + return result.success ? result.data : null; +}; export const createCameraConfig = (config?: unknown): CameraConfig => { return cameraConfigSchema.parse(config ?? {}); @@ -209,9 +222,16 @@ export const createStore = ( return store; }; -export const createCameraManager = (): CameraManager => { +export const createCameraManager = (store?: CameraManagerStore): CameraManager => { + const cameraStore = store ?? createStore(); const cameraManager = mock(); - vi.mocked(cameraManager.getStore).mockReturnValue(createStore()); + vi.mocked(cameraManager.getStore).mockReturnValue(cameraStore); + vi.mocked(cameraManager.getCameraCapabilities).mockImplementation( + (cameraID: string): Capabilities | null => { + return cameraStore.getCamera(cameraID)?.getCapabilities() ?? null; + }, + ); + return cameraManager; }; @@ -404,6 +424,7 @@ export const createParent = (options?: { children?: HTMLElement[] }): HTMLElemen export const createLitElement = (): LitElement => { const element = document.createElement('div') as unknown as LitElement; + element.addController = vi.fn(); element.requestUpdate = vi.fn(); return element; }; @@ -426,6 +447,7 @@ export const createCardAPI = (): CardController => { api.getHASSManager.mockReturnValue(mock()); api.getInitializationManager.mockReturnValue(mock()); api.getInteractionManager.mockReturnValue(mock()); + api.getKeyboardStateManager.mockReturnValue(mock()); api.getMediaLoadedInfoManager.mockReturnValue(mock()); api.getMediaPlayerManager.mockReturnValue(mock()); api.getMessageManager.mockReturnValue(mock()); diff --git a/tests/utils/action.test.ts b/tests/utils/action.test.ts index 1591b68b..b0b7eba7 100644 --- a/tests/utils/action.test.ts +++ b/tests/utils/action.test.ts @@ -1,33 +1,33 @@ -import { handleActionConfig, hasAction } from '@dermotduffy/custom-card-helpers'; +import { hasAction } from '@dermotduffy/custom-card-helpers'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { actionSchema } from '../../src/config/types'; import { - convertActionToFrigateCardCustomAction, - createFrigateCardCameraAction, - createFrigateCardChangeZoomAction, - createFrigateCardDisplayModeAction, - createFrigateCardMediaPlayerAction, - createFrigateCardShowPTZAction, - createFrigateCardSimpleAction, - frigateCardHandleAction, - frigateCardHandleActionConfig, + convertActionToCardCustomAction, + createCameraAction, + createDisplayModeAction, + createGeneralAction, + createLogAction, + createMediaPlayerAction, + createPTZDigitalAction, + createPTZMultiAction, + createPTZControlsAction, frigateCardHasAction, getActionConfigGivenAction, stopEventFromActivatingCardWideActions, + createPTZAction, } from '../../src/utils/action'; -import { createHASS } from '../test-utils'; vi.mock('@dermotduffy/custom-card-helpers'); describe('convertActionToFrigateCardCustomAction', () => { it('should skip null action', () => { - expect(convertActionToFrigateCardCustomAction(null)).toBeFalsy(); + expect(convertActionToCardCustomAction(null)).toBeFalsy(); }); it('should parse valid', () => { expect( - convertActionToFrigateCardCustomAction({ + convertActionToCardCustomAction({ action: 'custom:frigate-card-action', frigate_card_action: 'download', }), @@ -38,14 +38,14 @@ describe('convertActionToFrigateCardCustomAction', () => { }); it('should not parse invalid', () => { - expect(convertActionToFrigateCardCustomAction('this is garbage')).toBeNull(); + expect(convertActionToCardCustomAction('this is garbage')).toBeNull(); }); }); -describe('createFrigateCardSimpleAction', () => { +describe('createGeneralAction', () => { it('should create general action', () => { expect( - createFrigateCardSimpleAction('clips', { + createGeneralAction('clips', { cardID: 'card_id', }), ).toEqual({ @@ -56,23 +56,23 @@ describe('createFrigateCardSimpleAction', () => { }); }); -describe('createFrigateCardCameraAction', () => { +describe('createCameraAction', () => { it('should create camera_select', () => { - expect( - createFrigateCardCameraAction('camera_select', 'camera', { cardID: 'card_id' }), - ).toEqual({ - action: 'fire-dom-event', - camera: 'camera', - frigate_card_action: 'camera_select', - card_id: 'card_id', - }); + expect(createCameraAction('camera_select', 'camera', { cardID: 'card_id' })).toEqual( + { + action: 'fire-dom-event', + camera: 'camera', + frigate_card_action: 'camera_select', + card_id: 'card_id', + }, + ); }); }); -describe('createFrigateCardMediaPlayerAction', () => { +describe('createMediaPlayerAction', () => { it('should create media_player', () => { expect( - createFrigateCardMediaPlayerAction('device', 'play', { + createMediaPlayerAction('device', 'play', { cardID: 'card_id', }), ).toEqual({ @@ -85,10 +85,10 @@ describe('createFrigateCardMediaPlayerAction', () => { }); }); -describe('createFrigateCardDisplayModeAction', () => { +describe('createDisplayModeAction', () => { it('should create display mode action', () => { expect( - createFrigateCardDisplayModeAction('grid', { + createDisplayModeAction('grid', { cardID: 'card_id', }), ).toEqual({ @@ -100,49 +100,143 @@ describe('createFrigateCardDisplayModeAction', () => { }); }); -describe('createFrigateCardShowPTZAction', () => { - it('should create show PTZ action', () => { +describe('createPTZControlsAction', () => { + it('should create PTZ controls action', () => { expect( - createFrigateCardShowPTZAction(true, { + createPTZControlsAction(true, { cardID: 'card_id', }), ).toEqual({ action: 'fire-dom-event', - frigate_card_action: 'show_ptz', - show_ptz: true, + frigate_card_action: 'ptz_controls', + enabled: true, card_id: 'card_id', }); }); }); -describe('createFrigateCardChangeZoomAction', () => { - it('should create change zoom default action', () => { +describe('createPTZAction', () => { + it('should create ptz action without parameters', () => { expect( - createFrigateCardChangeZoomAction('target_id', { + createPTZAction({ cardID: 'card_id', }), ).toEqual({ action: 'fire-dom-event', - frigate_card_action: 'change_zoom', + frigate_card_action: 'ptz', card_id: 'card_id', - target_id: 'target_id', }); }); - it('should create change zoom specific action', () => { + it('should create ptz action with parameters', () => { expect( - createFrigateCardChangeZoomAction('target_id', { + createPTZAction({ cardID: 'card_id', - pan: { x: 1, y: 2 }, - zoom: 3, + ptzAction: 'right', + ptzPhase: 'start', + ptzPreset: 'preset', + cameraID: 'camera_id', }), ).toEqual({ action: 'fire-dom-event', - frigate_card_action: 'change_zoom', + frigate_card_action: 'ptz', + card_id: 'card_id', + camera: 'camera_id', + ptz_action: 'right', + ptz_phase: 'start', + ptz_preset: 'preset', + }); + }); +}); + +describe('createPTZDigitalAction', () => { + it('should create ptz digital without parameters', () => { + expect( + createPTZDigitalAction({ + cardID: 'card_id', + }), + ).toEqual({ + action: 'fire-dom-event', + frigate_card_action: 'ptz_digital', + card_id: 'card_id', + }); + }); + + it('should create ptz digital with parameters', () => { + expect( + createPTZDigitalAction({ + cardID: 'card_id', + targetID: 'target_id', + absolute: { + pan: { x: 1, y: 2 }, + zoom: 3, + }, + ptzAction: 'right', + ptzPhase: 'start', + }), + ).toEqual({ + action: 'fire-dom-event', + frigate_card_action: 'ptz_digital', card_id: 'card_id', target_id: 'target_id', - pan: { x: 1, y: 2 }, - zoom: 3, + absolute: { + pan: { x: 1, y: 2 }, + zoom: 3, + }, + ptz_action: 'right', + ptz_phase: 'start', + }); + }); +}); + +describe('createPTZMultiAction', () => { + it('should create ptz multi with parameters', () => { + expect( + createPTZMultiAction({ + cardID: 'card_id', + ptzAction: 'right', + ptzPreset: 'preset', + }), + ).toEqual({ + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + card_id: 'card_id', + ptz_action: 'right', + ptz_preset: 'preset', + }); + }); + + it('should create ptz multi without parameters', () => { + expect( + createPTZMultiAction({ + cardID: 'card_id', + ptzAction: 'right', + ptzPhase: 'start', + targetID: 'target_id', + }), + ).toEqual({ + action: 'fire-dom-event', + frigate_card_action: 'ptz_multi', + card_id: 'card_id', + ptz_action: 'right', + ptz_phase: 'start', + target_id: 'target_id', + }); + }); +}); + +describe('createLogAction', () => { + it('should create log action', () => { + expect( + createLogAction('Hello, world!', { + cardID: 'card_id', + }), + ).toEqual({ + action: 'fire-dom-event', + frigate_card_action: 'log', + message: 'Hello, world!', + card_id: 'card_id', + level: 'info', }); }); }); @@ -190,61 +284,6 @@ describe('getActionConfigGivenAction', () => { }); }); -// @vitest-environment jsdom -describe('frigateCardHandleActionConfig', () => { - const element = document.createElement('div'); - const action = actionSchema.parse({ - action: 'none', - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - it('should not handle missing arguments', () => { - expect( - frigateCardHandleActionConfig(element, createHASS(), {}, 'triple_poke'), - ).toBeFalsy(); - }); - - it('should handle simple case', () => { - const hass = createHASS(); - frigateCardHandleActionConfig(element, hass, {}, 'tap', action); - expect(handleActionConfig).toBeCalled(); - expect(handleActionConfig).toBeCalledWith(element, hass, {}, action); - }); - - it('should handle array case', () => { - const hass = createHASS(); - frigateCardHandleActionConfig(element, hass, {}, 'tap', [action, action, action]); - expect(handleActionConfig).toBeCalledTimes(3); - expect(handleActionConfig).toBeCalledWith(element, hass, {}, action); - }); - - it('should handle null case', () => { - const hass = createHASS(); - frigateCardHandleActionConfig(element, hass, {}, 'tap', null); - expect(handleActionConfig).toBeCalledWith(element, hass, {}, undefined); - }); -}); - -// @vitest-environment jsdom -describe('frigateCardHandleAction', () => { - const element = document.createElement('div'); - const action = actionSchema.parse({ - action: 'none', - }); - - afterEach(() => { - vi.clearAllMocks(); - }); - - it('should call action handler', () => { - frigateCardHandleAction(element, createHASS(), {}, action); - expect(handleActionConfig).toBeCalled(); - }); -}); - describe('frigateCardHasAction', () => { const action = actionSchema.parse({ action: 'toggle', diff --git a/tests/utils/basic.test.ts b/tests/utils/basic.test.ts index 50fc0e60..79188997 100644 --- a/tests/utils/basic.test.ts +++ b/tests/utils/basic.test.ts @@ -22,6 +22,7 @@ import { isTruthy, isValidDate, prettifyTitle, + recursivelyMergeObjectsConcatenatingArraysUniquely, recursivelyMergeObjectsNotArrays, runWhenIdleIfSupported, setify, @@ -345,6 +346,53 @@ describe('recursivelyMergeObjectsNotArrays', () => { }); }); +describe('recursivelyMergeObjectsConcatenatingArraysUniquely', () => { + it('should recursively merge objects but uniquely concat arrays', () => { + expect( + recursivelyMergeObjectsConcatenatingArraysUniquely( + {}, + { + a: { + b: { + c: 3, + d: { + e: 4, + }, + array: [5, 1, 2, 3, 4], + }, + other: { + field: 7, + }, + }, + }, + { + a: { + b: { + array: [4, 4, 5], + d: { + e: 5, + }, + }, + }, + }, + ), + ).toEqual({ + a: { + b: { + c: 3, + array: [5, 1, 2, 3, 4], + d: { + e: 5, + }, + }, + other: { + field: 7, + }, + }, + }); + }); +}); + describe('aspectRatioToStyle', () => { it('default', () => { expect(aspectRatioToStyle()).toEqual({ 'aspect-ratio': 'auto' }); diff --git a/tests/utils/ptz.test.ts b/tests/utils/ptz.test.ts index 272882e5..de085886 100644 --- a/tests/utils/ptz.test.ts +++ b/tests/utils/ptz.test.ts @@ -1,38 +1,154 @@ -import { describe, expect, it } from 'vitest'; -import { FrigateCardPTZConfig, frigateCardPTZSchema } from '../../src/config/types'; -import { hasUsablePTZ } from '../../src/utils/ptz'; -import { createCapabilities } from '../test-utils'; +import { describe, expect, it, vi } from 'vitest'; +import { Capabilities } from '../../src/camera-manager/capabilities'; +import { + getPTZTarget, + hasCameraTruePTZ, + ptzActionToCapabilityKey, +} from '../../src/utils/ptz'; +import { + TestViewMedia, + createCameraManager, + createStore, + createView, +} from '../test-utils'; +import { MediaQueriesResults } from '../../src/view/media-queries-results'; +import { FrigateCardView } from '../../src/config/types'; -const createPTZConfig = ( - config?: Partial, -): FrigateCardPTZConfig => { - return frigateCardPTZSchema.parse(config ?? {}); -}; +describe('getPTZTarget', () => { + describe('in a viewer view', () => { + it('with media', () => { + const media = [new TestViewMedia({ id: 'media-id' })]; + const view = createView({ + view: 'media', + queryResults: new MediaQueriesResults({ results: media, selectedIndex: 0 }), + }); + expect(getPTZTarget(view, { cameraManager: createCameraManager() })).toEqual({ + targetID: 'media-id', + type: 'digital', + }); + }); -describe('hasUsablePTZ', () => { - it('should return true with manual actions', () => { - expect( - hasUsablePTZ( - createCapabilities(), - createPTZConfig({ - actions_left: {}, - }), - ), - ).toBeTruthy(); + it('without media', () => { + const view = createView({ + view: 'media', + }); + expect(getPTZTarget(view, { cameraManager: createCameraManager() })).toBeNull(); + }); + + it('with true PTZ restriction', () => { + const media = [new TestViewMedia({ id: 'media-id' })]; + const view = createView({ + view: 'media', + queryResults: new MediaQueriesResults({ results: media, selectedIndex: 0 }), + }); + expect( + getPTZTarget(view, { type: 'ptz', cameraManager: createCameraManager() }), + ).toBeNull(); + }); }); - it('should return true with capabilities', () => { - expect( - hasUsablePTZ( - createCapabilities({ - ptz: { - panTilt: ['continuous'], - }, + + describe('in live view', () => { + it('without restriction with true PTZ capability', () => { + const view = createView({ + view: 'live', + camera: 'camera-1', + }); + const store = createStore([ + { + cameraID: 'camera-1', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); + + expect(getPTZTarget(view, { cameraManager: createCameraManager(store) })).toEqual({ + targetID: 'camera-1', + type: 'ptz', + }); + }); + + it('without restriction without true PTZ capability', () => { + const view = createView({ + view: 'live', + camera: 'camera-1', + }); + + expect(getPTZTarget(view, { cameraManager: createCameraManager() })).toEqual({ + targetID: 'camera-1', + type: 'digital', + }); + }); + + it('with truePTZ restriction without true PTZ capability', () => { + const view = createView({ + view: 'live', + camera: 'camera-1', + }); + + expect( + getPTZTarget(view, { type: 'ptz', cameraManager: createCameraManager() }), + ).toBeNull(); + }); + + it('with digitalPTZ restriction with true PTZ capability', () => { + const view = createView({ + view: 'live', + camera: 'camera-1', + }); + const store = createStore([ + { + cameraID: 'camera-1', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); + + expect( + getPTZTarget(view, { + type: 'digital', + cameraManager: createCameraManager(store), }), - createPTZConfig(), - ), - ).toBeTruthy(); + ).toEqual({ + targetID: 'camera-1', + type: 'digital', + }); + }); }); - it('should return false with manual actions or capabilities', () => { - expect(hasUsablePTZ(createCapabilities(), createPTZConfig())).toBeFalsy(); + + describe('in non-media views', () => { + it.each([['timeline' as const], ['diagnostics' as const]])( + '%s', + (viewName: FrigateCardView) => { + const view = createView({ + view: viewName, + }); + expect(getPTZTarget(view, { cameraManager: createCameraManager() })).toBeNull(); + }, + ); }); }); + +describe('hasCameraTruePTZ', () => { + it('with true PTZ', () => { + const store = createStore([ + { + cameraID: 'camera-1', + capabilities: new Capabilities({ ptz: { left: ['relative'] } }), + }, + ]); + + expect(hasCameraTruePTZ(createCameraManager(store), 'camera-1')).toBeTruthy(); + }); + + it('without true PTZ', () => { + expect(hasCameraTruePTZ(createCameraManager(createStore()), 'camera-1')).toBeFalsy(); + }); +}); + +it('ptzActionToCapabilityKey', () => { + expect(ptzActionToCapabilityKey('left')).toBe('left'); + expect(ptzActionToCapabilityKey('right')).toBe('right'); + expect(ptzActionToCapabilityKey('up')).toBe('up'); + expect(ptzActionToCapabilityKey('down')).toBe('down'); + expect(ptzActionToCapabilityKey('zoom_in')).toBe('zoomIn'); + expect(ptzActionToCapabilityKey('zoom_out')).toBe('zoomOut'); + expect(ptzActionToCapabilityKey('preset')).toBeNull(); +}); diff --git a/tests/utils/substream.test.ts b/tests/utils/substream.test.ts index 873dfe1b..b36acfe4 100644 --- a/tests/utils/substream.test.ts +++ b/tests/utils/substream.test.ts @@ -37,4 +37,17 @@ describe('hasSubstream/getStreamCameraID', () => { expect(hasSubstream(view)).toBeFalsy(); expect(getStreamCameraID(view)).toBe('camera'); }); + it('should respect cameraID override', () => { + const view = new View({ + view: 'live', + camera: 'camera', + context: { + live: { + overrides: new Map([['camera', 'camera2'], ['camera3', 'camera4']]), + }, + }, + }); + expect(hasSubstream(view)).toBeTruthy(); + expect(getStreamCameraID(view, 'camera3')).toBe('camera4'); + }); }); diff --git a/tsconfig.json b/tsconfig.json index 0b7a905d..9218fb69 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,7 @@ "moduleResolution": "node", "lib": ["es2021", "dom", "dom.iterable"], "noEmit": true, + "noErrorTruncation": true, "noUnusedParameters": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, @@ -22,12 +23,13 @@ // These tags are provided by the HA frontend and [almost all] cannot be // imported by a custom card directly. "globalTags": [ - "ha-card", - "ha-combo-box", - "ha-icon", - "ha-icon-button", "ha-button-menu", + "ha-button", + "ha-card", "ha-circular-progress", + "ha-combo-box", + "ha-icon-button", + "ha-icon", "ha-selector", "ha-svg-icon", "mwc-button", diff --git a/vite.config.ts b/vite.config.ts index 25a3f0be..74dd7e43 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -11,13 +11,14 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'camera-manager/generic/*.ts', 'camera-manager/motioneye/icon.ts', 'camera-manager/utils/*.ts', - 'card-controller/*.ts', + 'card-controller/**/*.ts', 'components-lib/cached-value-controller.ts', + 'components-lib/key-assigner-controller.ts', 'components-lib/live/live-controller.ts', 'components-lib/media-filter-controller.ts', 'components-lib/menu-button-controller.ts', 'components-lib/menu-controller.ts', - 'components-lib/ptz-controller.ts', + 'components-lib/ptz/*.ts', 'components-lib/zoom/*.ts', 'config/**/*.ts', 'const.ts', diff --git a/yarn.lock b/yarn.lock index 2be981ac..e6cd31e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1477,9 +1477,9 @@ __metadata: languageName: node linkType: hard -"@vitest/coverage-istanbul@npm:^1.5.0": - version: 1.5.0 - resolution: "@vitest/coverage-istanbul@npm:1.5.0" +"@vitest/coverage-istanbul@npm:^1.6.0": + version: 1.6.0 + resolution: "@vitest/coverage-istanbul@npm:1.6.0" dependencies: debug: "npm:^4.3.4" istanbul-lib-coverage: "npm:^3.2.2" @@ -1491,8 +1491,8 @@ __metadata: picocolors: "npm:^1.0.0" test-exclude: "npm:^6.0.0" peerDependencies: - vitest: 1.5.0 - checksum: 10c0/12abbaf8925c797e1fafef05c8b7d554c9fc61d13eb70c3f8532ade72db305a3cb1fec9bb7642763de27471e3f3da3d684d6533aa954756c5edf2707d2fc25cd + vitest: 1.6.0 + checksum: 10c0/42524de58d24101b50da048214b8e760c46f32760e371c700704a67ace2828d9d12b6d87720139c8a7e17fbce40dfcaf47296605c85533cc78b9c9f73c50e3d2 languageName: node linkType: hard @@ -3843,7 +3843,7 @@ __metadata: "@types/masonry-layout": "npm:^4.2.5" "@typescript-eslint/eslint-plugin": "npm:^7.12.0" "@typescript-eslint/parser": "npm:^7.12.0" - "@vitest/coverage-istanbul": "npm:^1.5.0" + "@vitest/coverage-istanbul": "npm:^1.6.0" component-emitter: "npm:^1.3.0" crypto: "npm:^1.0.1" date-fns: "npm:^3.6.0" @@ -3879,6 +3879,7 @@ __metadata: side-drawer: "npm:^3.1.0" ts-prune: "npm:^0.10.3" typescript: "npm:^5.4.5" + type-fest: "npm:^4.18.0" uuid: "npm:^8.3.2" vis-data: "npm:^7.1.9" vis-timeline: "npm:^7.7.3" @@ -8178,6 +8179,13 @@ __metadata: languageName: node linkType: hard +"type-fest@npm:^4.18.0": + version: 4.18.0 + resolution: "type-fest@npm:4.18.0" + checksum: 10c0/d16d9be71ceeb5341cfa7e21d9081e843e74791fb60b5e2555caa26c259c9bcbffd965e1a1c8e571856efddb317b4b1802f73938723f399f1070e9db5b182f4e + languageName: node + linkType: hard + "typed-array-buffer@npm:^1.0.2": version: 1.0.2 resolution: "typed-array-buffer@npm:1.0.2" From 71c8a3ca37f5665fd10f8791ec6faf4ac523319a Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 5 Jun 2024 22:00:58 -0700 Subject: [PATCH 139/189] Fix package order. --- package.json | 2 +- yarn.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index fb25a6bf..c2f6cf4c 100644 --- a/package.json +++ b/package.json @@ -81,8 +81,8 @@ "rollup-plugin-visualizer": "^5.8.2", "sass": "^1.54.9", "ts-prune": "^0.10.3", - "typescript": "^5.4.5", "type-fest": "^4.18.0", + "typescript": "^5.4.5", "vitest": "^1.5.0", "vitest-mock-extended": "^1.3.1" }, diff --git a/yarn.lock b/yarn.lock index e6cd31e8..3c4d113b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3878,8 +3878,8 @@ __metadata: screenfull: "npm:^6.0.2" side-drawer: "npm:^3.1.0" ts-prune: "npm:^0.10.3" - typescript: "npm:^5.4.5" type-fest: "npm:^4.18.0" + typescript: "npm:^5.4.5" uuid: "npm:^8.3.2" vis-data: "npm:^7.1.9" vis-timeline: "npm:^7.7.3" From 08ba2ee0b16126803b76323be683b7c46f73b8dd Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Wed, 5 Jun 2024 22:12:42 -0700 Subject: [PATCH 140/189] Hide the ptz_home button. Likely not important enough for most users. --- src/config/types.ts | 4 ++-- tests/components-lib/menu-button-controller.test.ts | 4 ++-- tests/config/types.test.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/config/types.ts b/src/config/types.ts index fdf7b372..3f924f5e 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -1499,7 +1499,7 @@ const menuConfigDefault = { camera_ui: visibleButtonDefault, cameras: visibleButtonDefault, clips: visibleButtonDefault, - ptz_home: visibleButtonDefault, + ptz_home: hiddenButtonDefault, display_mode: visibleButtonDefault, download: visibleButtonDefault, expand: hiddenButtonDefault, @@ -1545,7 +1545,7 @@ export const menuConfigSchema = z camera_ui: visibleButtonSchema.default(menuConfigDefault.buttons.camera_ui), cameras: visibleButtonSchema.default(menuConfigDefault.buttons.cameras), clips: visibleButtonSchema.default(menuConfigDefault.buttons.clips), - ptz_home: visibleButtonSchema.default( + ptz_home: hiddenButtonSchema.default( menuConfigDefault.buttons.ptz_home, ), display_mode: visibleButtonSchema.default( diff --git a/tests/components-lib/menu-button-controller.test.ts b/tests/components-lib/menu-button-controller.test.ts index ed9821b7..c55b9c0c 100644 --- a/tests/components-lib/menu-button-controller.test.ts +++ b/tests/components-lib/menu-button-controller.test.ts @@ -1550,7 +1550,7 @@ describe('MenuButtonController', () => { if (expectedResult) { expect(buttons).toContainEqual({ - enabled: true, + enabled: false, icon: 'mdi:home', priority: 50, tap_action: { @@ -1563,7 +1563,7 @@ describe('MenuButtonController', () => { }); } else { expect(buttons).not.toContainEqual( - expect.objectContaining({ title: 'Digital zoom to default' }), + expect.objectContaining({ title: 'PTZ Home' }), ); } }, diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 93b8b56c..6e90f23c 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -236,7 +236,7 @@ describe('config defaults', () => { priority: 50, }, ptz_home: { - enabled: true, + enabled: false, priority: 50, }, recordings: { From 7069cfc06f85fa067c7771a8d40ab246d8db6133 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 07:47:05 +0000 Subject: [PATCH 141/189] Bump svenstaro/upload-release-action from 2.7.0 to 2.9.0 Bumps [svenstaro/upload-release-action](https://github.com/svenstaro/upload-release-action) from 2.7.0 to 2.9.0. - [Release notes](https://github.com/svenstaro/upload-release-action/releases) - [Changelog](https://github.com/svenstaro/upload-release-action/blob/master/CHANGELOG.md) - [Commits](https://github.com/svenstaro/upload-release-action/compare/2.7.0...2.9.0) --- updated-dependencies: - dependency-name: svenstaro/upload-release-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 429b8e0f..bdd0e897 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -31,7 +31,7 @@ jobs: filename: frigate-hass-card.zip - name: Upload JS files to release - uses: svenstaro/upload-release-action@2.7.0 + uses: svenstaro/upload-release-action@2.9.0 with: repo_token: ${{ secrets.GITHUB_TOKEN }} @@ -41,7 +41,7 @@ jobs: overwrite: true - name: Upload Zip file to release - uses: svenstaro/upload-release-action@2.7.0 + uses: svenstaro/upload-release-action@2.9.0 with: repo_token: ${{ secrets.GITHUB_TOKEN }} From 623b23da39936a1244adc4e9ae630ef5f2d08c66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 07:47:07 +0000 Subject: [PATCH 142/189] Bump thedoctor0/zip-release from 0.7.1 to 0.7.6 Bumps [thedoctor0/zip-release](https://github.com/thedoctor0/zip-release) from 0.7.1 to 0.7.6. - [Release notes](https://github.com/thedoctor0/zip-release/releases) - [Commits](https://github.com/thedoctor0/zip-release/compare/0.7.1...0.7.6) --- updated-dependencies: - dependency-name: thedoctor0/zip-release dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 429b8e0f..f5fbe641 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -24,7 +24,7 @@ jobs: run: yarn run build - name: Zip the files - uses: thedoctor0/zip-release@0.7.1 + uses: thedoctor0/zip-release@0.7.6 with: type: zip path: dist From 78838a22143fc6877599d26da1ddb88c17040811 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 07:47:11 +0000 Subject: [PATCH 143/189] Bump actions/upload-artifact from 3 to 4 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3c5d5634..2de9aaa8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,7 +44,7 @@ jobs: run: yarn run docs-check-links - name: Upload javascript - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: frigate-hass-card path: dist/*.js @@ -52,7 +52,7 @@ jobs: # When this issue is fixed, it would be useful to upload visualizations: # https://github.com/actions/upload-artifact/issues/14 # - name: Upload visualizations - # uses: actions/upload-artifact@v3 + # uses: actions/upload-artifact@v4 # with: # name: frigate-hass-card # path: visualizations/*.html From 6c1f64427593b64cfc3927ab25959911e1bb7404 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Jun 2024 07:47:14 +0000 Subject: [PATCH 144/189] Bump release-drafter/release-drafter from 5.24.0 to 6.0.0 Bumps [release-drafter/release-drafter](https://github.com/release-drafter/release-drafter) from 5.24.0 to 6.0.0. - [Release notes](https://github.com/release-drafter/release-drafter/releases) - [Commits](https://github.com/release-drafter/release-drafter/compare/v5.24.0...v6.0.0) --- updated-dependencies: - dependency-name: release-drafter/release-drafter dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/release-drafter.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index f70c434f..0b7b26f7 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -11,6 +11,6 @@ jobs: runs-on: ubuntu-latest steps: - name: Run release-drafter - uses: release-drafter/release-drafter@v5.24.0 + uses: release-drafter/release-drafter@v6.0.0 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From fca040c13d6edb3bbd9e154241f46b4c71a879e0 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Thu, 6 Jun 2024 20:53:44 -0700 Subject: [PATCH 145/189] Convert docs dependencies to be locally served. --- docs/css/theme-simple-dark.css | 3 + docs/css/theme-simple.css | 3 + docs/index.html | 20 +- docs/js/docsify-copy-code.min.js | 9 + docs/js/docsify-sidebar-collapse.min.js | 1 + docs/js/docsify-themeable.min.js | 9 + docs/js/docsify.min.js | 8 + docs/js/gtag.min.js | 8 + docs/js/prism-yaml.min.js | 1 + docs/js/search.js | 540 ++++++++++++++++++ docs/js/zoom-image.min.js | 1 + package.json | 3 +- scripts/docs-update-dependencies.sh | 29 + ...update-images.sh => docs-update-images.sh} | 18 +- 14 files changed, 637 insertions(+), 16 deletions(-) create mode 100644 docs/css/theme-simple-dark.css create mode 100644 docs/css/theme-simple.css create mode 100644 docs/js/docsify-copy-code.min.js create mode 100644 docs/js/docsify-sidebar-collapse.min.js create mode 100644 docs/js/docsify-themeable.min.js create mode 100644 docs/js/docsify.min.js create mode 100644 docs/js/gtag.min.js create mode 100644 docs/js/prism-yaml.min.js create mode 100644 docs/js/search.js create mode 100644 docs/js/zoom-image.min.js create mode 100755 scripts/docs-update-dependencies.sh rename scripts/{update-images.sh => docs-update-images.sh} (66%) diff --git a/docs/css/theme-simple-dark.css b/docs/css/theme-simple-dark.css new file mode 100644 index 00000000..1aca008c --- /dev/null +++ b/docs/css/theme-simple-dark.css @@ -0,0 +1,3 @@ +.github-corner{position:absolute;z-index:40;top:0;right:0;border-bottom:0;text-decoration:none}.github-corner svg{height:70px;width:70px;fill:var(--theme-color);color:var(--base-background-color)}.github-corner:hover .octo-arm{-webkit-animation:octocat-wave 560ms ease-in-out;animation:octocat-wave 560ms ease-in-out}@-webkit-keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}.progress{position:fixed;z-index:2147483647;top:0;left:0;right:0;height:3px;width:0;background-color:var(--theme-color);transition:width var(--duration-fast),opacity calc(var(--duration-fast)*2)}body.ready-transition:after,body.ready-transition>*:not(.progress){opacity:0;transition:opacity var(--spinner-transition-duration)}body.ready-transition:after{content:"";position:absolute;z-index:1000;top:calc(50% - var(--spinner-size)/2);left:calc(50% - var(--spinner-size)/2);height:var(--spinner-size);width:var(--spinner-size);border:var(--spinner-track-width, 0) solid var(--spinner-track-color);border-left-color:var(--theme-color);border-left-color:var(--theme-color);border-radius:50%;-webkit-animation:spinner var(--duration-slow) infinite linear;animation:spinner var(--duration-slow) infinite linear}body.ready-transition.ready-spinner:after{opacity:1}body.ready-transition.ready-fix:after{opacity:0}body.ready-transition.ready-fix>*:not(.progress){opacity:1;transition-delay:var(--spinner-transition-duration)}@-webkit-keyframes spinner{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@keyframes spinner{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}*,*:before,*:after{box-sizing:inherit;font-size:inherit;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none}:root{box-sizing:border-box;background-color:var(--base-background-color);font-size:var(--base-font-size);font-weight:var(--base-font-weight);line-height:var(--base-line-height);letter-spacing:var(--base-letter-spacing);color:var(--base-color);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased}html,button,input,optgroup,select,textarea{font-family:var(--base-font-family)}button,input,optgroup,select,textarea{font-size:100%;margin:0}a{text-decoration:none;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}body{margin:0}hr{height:0;margin:2em 0;border:none;border-bottom:var(--hr-border, 0)}img{max-width:100%;border:0}main{display:block}main.hidden{display:none}mark{background:var(--mark-background);color:var(--mark-color)}pre{font-family:var(--pre-font-family);font-size:var(--pre-font-size);font-weight:var(--pre-font-weight);line-height:var(--pre-line-height)}small{display:inline-block;font-size:var(--small-font-size)}strong{font-weight:var(--strong-font-weight);color:var(--strong-color, currentColor)}sub,sup{font-size:var(--subsup-font-size);line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}body:not([data-platform^=Mac]) *{scrollbar-color:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3) hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1);scrollbar-width:thin}body:not([data-platform^=Mac]) * ::-webkit-scrollbar{width:5px;height:5px}body:not([data-platform^=Mac]) * ::-webkit-scrollbar-thumb{background:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3)}body:not([data-platform^=Mac]) * ::-webkit-scrollbar-track{background:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1)}::-moz-selection{background:var(--selection-color)}::selection{background:var(--selection-color)}.emoji{height:var(--emoji-size);vertical-align:middle}.task-list-item{list-style:none}.task-list-item input{margin-right:.5em;margin-left:0;vertical-align:.075em}.markdown-section code[class*=lang-],.markdown-section pre[data-lang]{font-family:var(--code-font-family);font-size:var(--code-font-size);font-weight:var(--code-font-weight);letter-spacing:normal;line-height:var(--code-block-line-height);-moz-tab-size:var(--code-tab-size);-o-tab-size:var(--code-tab-size);tab-size:var(--code-tab-size);text-align:left;white-space:pre;word-spacing:normal;word-wrap:normal;word-break:normal;-webkit-hyphens:none;hyphens:none}.markdown-section pre[data-lang]{position:relative;overflow:hidden;margin:var(--code-block-margin);padding:0;border-radius:var(--code-block-border-radius)}.markdown-section pre[data-lang]::after{content:attr(data-lang);position:absolute;top:.75em;right:.75em;opacity:.6;color:inherit;font-size:var(--font-size-s);line-height:1}.markdown-section pre[data-lang] code{display:block;overflow:auto;padding:var(--code-block-padding)}code[class*=lang-],pre[data-lang]{color:var(--code-theme-text)}pre[data-lang]::-moz-selection,pre[data-lang] ::-moz-selection,code[class*=lang-]::-moz-selection,code[class*=lang-] ::-moz-selection{background:var(--code-theme-selection, var(--selection-color))}pre[data-lang]::-moz-selection, pre[data-lang] ::-moz-selection, code[class*=lang-]::-moz-selection, code[class*=lang-] ::-moz-selection{background:var(--code-theme-selection, var(--selection-color))}pre[data-lang]::selection,pre[data-lang] ::selection,code[class*=lang-]::selection,code[class*=lang-] ::selection{background:var(--code-theme-selection, var(--selection-color))}:not(pre)>code[class*=lang-],pre[data-lang]{background:var(--code-theme-background)}.namespace{opacity:.7}.token.comment,.token.prolog,.token.doctype,.token.cdata{color:var(--code-theme-comment)}.token.punctuation{color:var(--code-theme-punctuation)}.token.property,.token.tag,.token.boolean,.token.number,.token.constant,.token.symbol,.token.deleted{color:var(--code-theme-tag)}.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.inserted{color:var(--code-theme-selector)}.token.operator,.token.entity,.token.url,.language-css .token.string,.style .token.string{color:var(--code-theme-operator)}.token.atrule,.token.attr-value,.token.keyword{color:var(--code-theme-keyword)}.token.function{color:var(--code-theme-function)}.token.regex,.token.important,.token.variable{color:var(--code-theme-variable)}.token.important,.token.bold{font-weight:bold}.token.italic{font-style:italic}.token.entity{cursor:help}.markdown-section{position:relative;max-width:var(--content-max-width);margin:0 auto;padding:2rem 45px}.app-nav:not(:empty)~main .markdown-section{padding-top:3.5rem}.markdown-section figure,.markdown-section p,.markdown-section ol,.markdown-section ul{margin:1em 0}.markdown-section ol,.markdown-section ul{padding-left:1.5rem}.markdown-section ol ol,.markdown-section ol ul,.markdown-section ul ol,.markdown-section ul ul{margin-top:.15rem;margin-bottom:.15rem}.markdown-section a{border-bottom:var(--link-border-bottom);color:var(--link-color);-webkit-text-decoration:var(--link-text-decoration);text-decoration:var(--link-text-decoration);-webkit-text-decoration-color:var(--link-text-decoration-color);text-decoration-color:var(--link-text-decoration-color)}.markdown-section a:hover{border-bottom:var(--link-border-bottom--hover, var(--link-border-bottom, 0));color:var(--link-color--hover, var(--link-color));-webkit-text-decoration:var(--link-text-decoration--hover, var(--link-text-decoration));text-decoration:var(--link-text-decoration--hover, var(--link-text-decoration));-webkit-text-decoration-color:var(--link-text-decoration-color--hover, var(--link-text-decoration-color));text-decoration-color:var(--link-text-decoration-color--hover, var(--link-text-decoration-color))}.markdown-section a.anchor{border-bottom:0;color:inherit;text-decoration:none}.markdown-section a.anchor:hover{text-decoration:underline}.markdown-section blockquote{overflow:visible;margin:2em 0;padding:var(--blockquote-padding);border-width:var(--blockquote-border-width, 0);border-style:var(--blockquote-border-style);border-color:var(--blockquote-border-color);border-radius:var(--blockquote-border-radius);background:var(--blockquote-background);color:var(--blockquote-color);font-family:var(--blockquote-font-family);font-size:var(--blockquote-font-size);font-style:var(--blockquote-font-style);font-weight:var(--blockquote-font-weight);quotes:"“" "”" "‘" "’"}.markdown-section blockquote em{font-family:var(--blockquote-em-font-family);font-size:var(--blockquote-em-font-size);font-style:var(--blockquote-em-font-style);font-weight:var(--blockquote-em-font-weight)}.markdown-section blockquote p:first-child{margin-top:0}.markdown-section blockquote p:first-child:before,.markdown-section blockquote p:first-child:after{color:var(--blockquote-quotes-color);font-family:var(--blockquote-quotes-font-family);font-size:var(--blockquote-quotes-font-size);line-height:0}.markdown-section blockquote p:first-child:before{content:var(--blockquote-quotes-open);margin-right:.15em;vertical-align:-0.45em}.markdown-section blockquote p:first-child:after{content:var(--blockquote-quotes-close);margin-left:.15em;vertical-align:-0.55em}.markdown-section blockquote p:last-child{margin-bottom:0}.markdown-section code{font-family:var(--code-font-family);font-size:var(--code-font-size);font-weight:var(--code-font-weight);line-height:inherit}.markdown-section code:not([class*=lang-]):not([class*=language-]){margin:var(--code-inline-margin);padding:var(--code-inline-padding);border-radius:var(--code-inline-border-radius);background:var(--code-inline-background);color:var(--code-inline-color, currentColor);white-space:nowrap}.markdown-section h1:first-child,.markdown-section h2:first-child,.markdown-section h3:first-child,.markdown-section h4:first-child,.markdown-section h5:first-child,.markdown-section h6:first-child{margin-top:0}.markdown-section h1 a[data-id],.markdown-section h2 a[data-id],.markdown-section h3 a[data-id],.markdown-section h4 a[data-id],.markdown-section h5 a[data-id],.markdown-section h6 a[data-id]{display:inline-block}.markdown-section h1 code,.markdown-section h2 code,.markdown-section h3 code,.markdown-section h4 code,.markdown-section h5 code,.markdown-section h6 code{font-size:.875em}.markdown-section h1+h2,.markdown-section h1+h3,.markdown-section h1+h4,.markdown-section h1+h5,.markdown-section h1+h6,.markdown-section h2+h3,.markdown-section h2+h4,.markdown-section h2+h5,.markdown-section h2+h6,.markdown-section h3+h4,.markdown-section h3+h5,.markdown-section h3+h6,.markdown-section h4+h5,.markdown-section h4+h6,.markdown-section h5+h6{margin-top:1rem}.markdown-section h1{margin:var(--heading-h1-margin, var(--heading-margin));padding:var(--heading-h1-padding, var(--heading-padding));border-width:var(--heading-h1-border-width, 0);border-style:var(--heading-h1-border-style);border-color:var(--heading-h1-border-color);font-family:var(--heading-h1-font-family, var(--heading-font-family));font-size:var(--heading-h1-font-size);font-weight:var(--heading-h1-font-weight, var(--heading-font-weight));line-height:var(--base-line-height);color:var(--heading-h1-color, var(--heading-color))}.markdown-section h2{margin:var(--heading-h2-margin, var(--heading-margin));padding:var(--heading-h2-padding, var(--heading-padding));border-width:var(--heading-h2-border-width, 0);border-style:var(--heading-h2-border-style);border-color:var(--heading-h2-border-color);font-family:var(--heading-h2-font-family, var(--heading-font-family));font-size:var(--heading-h2-font-size);font-weight:var(--heading-h2-font-weight, var(--heading-font-weight));line-height:var(--base-line-height);color:var(--heading-h2-color, var(--heading-color))}.markdown-section h3{margin:var(--heading-h3-margin, var(--heading-margin));padding:var(--heading-h3-padding, var(--heading-padding));border-width:var(--heading-h3-border-width, 0);border-style:var(--heading-h3-border-style);border-color:var(--heading-h3-border-color);font-family:var(--heading-h3-font-family, var(--heading-font-family));font-size:var(--heading-h3-font-size);font-weight:var(--heading-h3-font-weight, var(--heading-font-weight));color:var(--heading-h3-color, var(--heading-color))}.markdown-section h4{margin:var(--heading-h4-margin, var(--heading-margin));padding:var(--heading-h4-padding, var(--heading-padding));border-width:var(--heading-h4-border-width, 0);border-style:var(--heading-h4-border-style);border-color:var(--heading-h4-border-color);font-family:var(--heading-h4-font-family, var(--heading-font-family));font-size:var(--heading-h4-font-size);font-weight:var(--heading-h4-font-weight, var(--heading-font-weight));color:var(--heading-h4-color, var(--heading-color))}.markdown-section h5{margin:var(--heading-h5-margin, var(--heading-margin));padding:var(--heading-h5-padding, var(--heading-padding));border-width:var(--heading-h5-border-width, 0);border-style:var(--heading-h5-border-style);border-color:var(--heading-h5-border-color);font-family:var(--heading-h5-font-family, var(--heading-font-family));font-size:var(--heading-h5-font-size);font-weight:var(--heading-h5-font-weight, var(--heading-font-weight));color:var(--heading-h5-color, var(--heading-color))}.markdown-section h6{margin:var(--heading-h6-margin, var(--heading-margin));padding:var(--heading-h6-padding, var(--heading-padding));border-width:var(--heading-h6-border-width, 0);border-style:var(--heading-h6-border-style);border-color:var(--heading-h6-border-color);font-family:var(--heading-h6-font-family, var(--heading-font-family));font-size:var(--heading-h6-font-size);font-weight:var(--heading-h6-font-weight, var(--heading-font-weight));color:var(--heading-h6-color, var(--heading-color))}.markdown-section iframe{margin:1em 0}.markdown-section img{max-width:100%}.markdown-section kbd{display:inline-block;min-width:var(--kbd-min-width);margin:var(--kbd-margin);padding:var(--kbd-padding);border:var(--kbd-border);border-radius:var(--kbd-border-radius);background:var(--kbd-background);font-family:inherit;font-size:var(--kbd-font-size);text-align:center;letter-spacing:0;line-height:1;color:var(--kbd-color)}.markdown-section kbd+kbd{margin-left:-0.15em}.markdown-section table{display:block;overflow:auto;margin:1rem 0;border-spacing:0;border-collapse:collapse}.markdown-section th,.markdown-section td{padding:var(--table-cell-padding)}.markdown-section th:not([align]){text-align:left}.markdown-section thead{border-color:var(--table-head-border-color);border-style:solid;border-width:var(--table-head-border-width, 0);background:var(--table-head-background)}.markdown-section th{font-weight:var(--table-head-font-weight);color:var(--strong-color)}.markdown-section td{border-color:var(--table-cell-border-color);border-style:solid;border-width:var(--table-cell-border-width, 0)}.markdown-section tbody{border-color:var(--table-body-border-color);border-style:solid;border-width:var(--table-body-border-width, 0)}.markdown-section tbody tr:nth-child(odd){background:var(--table-row-odd-background)}.markdown-section tbody tr:nth-child(even){background:var(--table-row-even-background)}.markdown-section>ul .task-list-item{margin-left:-1.25em}.markdown-section>ul .task-list-item .task-list-item{margin-left:0}.markdown-section .table-wrapper{overflow-x:auto}.markdown-section .table-wrapper table{display:table;width:100%}.markdown-section .table-wrapper td::before{display:none}@media(max-width: 30em){.markdown-section .table-wrapper tbody,.markdown-section .table-wrapper tr,.markdown-section .table-wrapper td{display:block}.markdown-section .table-wrapper th,.markdown-section .table-wrapper td{border:none}.markdown-section .table-wrapper thead{display:none}.markdown-section .table-wrapper tr{border-color:var(--table-cell-border-color);border-style:solid;border-width:var(--table-cell-border-width, 0);padding:var(--table-cell-padding)}.markdown-section .table-wrapper tr:not(:last-child){border-bottom:0}.markdown-section .table-wrapper td{padding:.15em 0 .15em 8em}.markdown-section .table-wrapper td::before{display:inline-block;float:left;width:8em;margin-left:-8em;font-weight:bold;text-align:left}}.markdown-section .tip,.markdown-section .warn{position:relative;margin:2em 0;padding:var(--notice-padding);border-width:var(--notice-border-width, 0);border-style:var(--notice-border-style);border-color:var(--notice-border-color);border-radius:var(--notice-border-radius);background:var(--notice-background);font-family:var(--notice-font-family);font-weight:var(--notice-font-weight);color:var(--notice-color)}.markdown-section .tip:before,.markdown-section .warn:before{display:inline-block;position:var(--notice-before-position, relative);top:var(--notice-before-top);left:var(--notice-before-left);height:var(--notice-before-height);width:var(--notice-before-width);margin:var(--notice-before-margin);padding:var(--notice-before-padding);border-radius:var(--notice-before-border-radius);line-height:var(--notice-before-line-height);font-family:var(--notice-before-font-family);font-size:var(--notice-before-font-size);font-weight:var(--notice-before-font-weight);text-align:center}.markdown-section .tip{border-width:var(--notice-important-border-width, var(--notice-border-width, 0));border-style:var(--notice-important-border-style, var(--notice-border-style));border-color:var(--notice-important-border-color, var(--notice-border-color));background:var(--notice-important-background, var(--notice-background));color:var(--notice-important-color, var(--notice-color))}.markdown-section .tip:before{content:var(--notice-important-before-content, var(--notice-before-content));background:var(--notice-important-before-background, var(--notice-before-background));color:var(--notice-important-before-color, var(--notice-before-color))}.markdown-section .warn{border-width:var(--notice-tip-border-width, var(--notice-border-width, 0));border-style:var(--notice-tip-border-style, var(--notice-border-style));border-color:var(--notice-tip-border-color, var(--notice-border-color));background:var(--notice-tip-background, var(--notice-background));color:var(--notice-tip-color, var(--notice-color))}.markdown-section .warn:before{content:var(--notice-tip-before-content, var(--notice-before-content));background:var(--notice-tip-before-background, var(--notice-before-background));color:var(--notice-tip-before-color, var(--notice-before-color))}.cover{display:none;position:relative;z-index:20;min-height:100vh;flex-direction:column;align-items:center;justify-content:center;padding:calc(var(--cover-border-inset, 0px) + var(--cover-border-width, 0px));color:var(--cover-color);text-align:var(--cover-text-align)}@media screen and (-ms-high-contrast: active),screen and (-ms-high-contrast: none){.cover{height:100vh}}.cover:before,.cover:after{content:"";position:absolute}.cover:before{top:0;bottom:0;left:0;right:0;background-blend-mode:var(--cover-background-blend-mode);background-color:var(--cover-background-color);background-image:var(--cover-background-image);background-position:var(--cover-background-position);background-repeat:var(--cover-background-repeat);background-size:var(--cover-background-size)}.cover:after{top:var(--cover-border-inset, 0);bottom:var(--cover-border-inset, 0);left:var(--cover-border-inset, 0);right:var(--cover-border-inset, 0);border-width:var(--cover-border-width, 0);border-style:solid;border-color:var(--cover-border-color)}.cover a{border-bottom:var(--cover-link-border-bottom);color:var(--cover-link-color);-webkit-text-decoration:var(--cover-link-text-decoration);text-decoration:var(--cover-link-text-decoration);-webkit-text-decoration-color:var(--cover-link-text-decoration-color);text-decoration-color:var(--cover-link-text-decoration-color)}.cover a:hover{border-bottom:var(--cover-link-border-bottom--hover, var(--cover-link-border-bottom));color:var(--cover-link-color--hover, var(--cover-link-color));-webkit-text-decoration:var(--cover-link-text-decoration--hover, var(--cover-link-text-decoration));text-decoration:var(--cover-link-text-decoration--hover, var(--cover-link-text-decoration));-webkit-text-decoration-color:var(--cover-link-text-decoration-color--hover, var(--cover-link-text-decoration-color));text-decoration-color:var(--cover-link-text-decoration-color--hover, var(--cover-link-text-decoration-color))}.cover h1{color:var(--cover-heading-color);position:relative;margin:0;font-size:var(--cover-heading-font-size);font-weight:var(--cover-heading-font-weight);line-height:1.2}.cover h1 a,.cover h1 a:hover{display:block;border-bottom:none;color:inherit;text-decoration:none}.cover h1 small{position:absolute;bottom:0;margin-left:.5em}.cover h1 span{font-size:calc(var(--cover-heading-font-size-min)*1px)}@media(min-width: 26em){.cover h1 span{font-size:calc(var(--cover-heading-font-size-min)*1px + (var(--cover-heading-font-size-max) - var(--cover-heading-font-size-min))*(100vw - 420px)/604)}}@media(min-width: 64em){.cover h1 span{font-size:calc(var(--cover-heading-font-size-max)*1px)}}.cover blockquote{margin:0;color:var(--cover-blockquote-color);font-size:var(--cover-blockquote-font-size)}.cover blockquote a{color:inherit}.cover ul{padding:0;list-style-type:none}.cover .cover-main{position:relative;z-index:1;max-width:var(--cover-max-width);margin:var(--cover-margin);padding:0 45px}.cover .cover-main>p:last-child{margin:1.25em -0.25em}.cover .cover-main>p:last-child a{display:block;margin:.375em .25em;padding:var(--cover-button-padding);border:var(--cover-button-border);border-radius:var(--cover-button-border-radius);box-shadow:var(--cover-button-box-shadow);background:var(--cover-button-background);text-align:center;-webkit-text-decoration:var(--cover-button-text-decoration);text-decoration:var(--cover-button-text-decoration);-webkit-text-decoration-color:var(--cover-button-text-decoration-color);text-decoration-color:var(--cover-button-text-decoration-color);color:var(--cover-button-color);white-space:nowrap;transition:var(--cover-button-transition)}.cover .cover-main>p:last-child a:hover{border:var(--cover-button-border--hover, var(--cover-button-border));box-shadow:var(--cover-button-box-shadow--hover, var(--cover-button-box-shadow));background:var(--cover-button-background--hover, var(--cover-button-background));-webkit-text-decoration:var(--cover-button-text-decoration--hover, var(--cover-button-text-decoration));text-decoration:var(--cover-button-text-decoration--hover, var(--cover-button-text-decoration));-webkit-text-decoration-color:var(--cover-button-text-decoration-color--hover, var(--cover-button-text-decoration-color));text-decoration-color:var(--cover-button-text-decoration-color--hover, var(--cover-button-text-decoration-color));color:var(--cover-button-color--hover, var(--cover-button-color))}.cover .cover-main>p:last-child a:first-child{border:var(--cover-button-primary-border, var(--cover-button-border));box-shadow:var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow));background:var(--cover-button-primary-background, var(--cover-button-background));-webkit-text-decoration:var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration));text-decoration:var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration));-webkit-text-decoration-color:var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color));text-decoration-color:var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color));color:var(--cover-button-primary-color, var(--cover-button-color))}.cover .cover-main>p:last-child a:first-child:hover{border:var(--cover-button-primary-border--hover, var(--cover-button-border--hover, var(--cover-button-primary-border, var(--cover-button-border))));box-shadow:var(--cover-button-primary-box-shadow--hover, var(--cover-button-box-shadow--hover, var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow))));background:var(--cover-button-primary-background--hover, var(--cover-button-background--hover, var(--cover-button-primary-background, var(--cover-button-background))));-webkit-text-decoration:var(--cover-button-primary-text-decoration--hover, var(--cover-button-text-decoration--hover, var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration))));text-decoration:var(--cover-button-primary-text-decoration--hover, var(--cover-button-text-decoration--hover, var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration))));-webkit-text-decoration-color:var(--cover-button-primary-text-decoration-color--hover, var(--cover-button-text-decoration-color--hover, var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color))));text-decoration-color:var(--cover-button-primary-text-decoration-color--hover, var(--cover-button-text-decoration-color--hover, var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color))));color:var(--cover-button-primary-color--hover, var(--cover-button-color--hover, var(--cover-button-primary-color, var(--cover-button-color))))}@media(min-width: 30.01em){.cover .cover-main>p:last-child a{display:inline-block}}.cover .mask{visibility:var(--cover-background-mask-visibility, hidden);position:absolute;top:0;bottom:0;left:0;right:0;background-color:var(--cover-background-mask-color);opacity:var(--cover-background-mask-opacity)}.cover.has-mask .mask{visibility:visible}.cover.show{display:flex}.app-nav{position:absolute;z-index:30;top:calc(35px - .5em*var(--base-line-height));left:45px;right:80px;text-align:right}.app-nav.no-badge{right:45px}.app-nav li>img,.app-nav li>a>img{margin-top:-0.25em;vertical-align:middle}.app-nav li>img:first-child,.app-nav li>a>img:first-child{margin-right:.5em}.app-nav ul,.app-nav li{margin:0;padding:0;list-style:none}.app-nav li{position:relative}.app-nav li a{display:block;line-height:1;transition:var(--navbar-root-transition)}.app-nav>ul>li{display:inline-block;margin:var(--navbar-root-margin)}.app-nav>ul>li:first-child{margin-left:0}.app-nav>ul>li:last-child{margin-right:0}.app-nav>ul>li>a,.app-nav>ul>li>span{padding:var(--navbar-root-padding);border-width:var(--navbar-root-border-width, 0);border-style:var(--navbar-root-border-style);border-color:var(--navbar-root-border-color);border-radius:var(--navbar-root-border-radius);background:var(--navbar-root-background);color:var(--navbar-root-color);-webkit-text-decoration:var(--navbar-root-text-decoration);text-decoration:var(--navbar-root-text-decoration);-webkit-text-decoration-color:var(--navbar-root-text-decoration-color);text-decoration-color:var(--navbar-root-text-decoration-color)}.app-nav>ul>li>a:hover,.app-nav>ul>li>span:hover{background:var(--navbar-root-background--hover, var(--navbar-root-background));border-style:var(--navbar-root-border-style--hover, var(--navbar-root-border-style));border-color:var(--navbar-root-border-color--hover, var(--navbar-root-border-color));color:var(--navbar-root-color--hover, var(--navbar-root-color));-webkit-text-decoration:var(--navbar-root-text-decoration--hover, var(--navbar-root-text-decoration));text-decoration:var(--navbar-root-text-decoration--hover, var(--navbar-root-text-decoration));-webkit-text-decoration-color:var(--navbar-root-text-decoration-color--hover, var(--navbar-root-text-decoration-color));text-decoration-color:var(--navbar-root-text-decoration-color--hover, var(--navbar-root-text-decoration-color))}.app-nav>ul>li>a:not(:last-child),.app-nav>ul>li>span:not(:last-child){padding:var(--navbar-menu-root-padding, var(--navbar-root-padding));background:var(--navbar-menu-root-background, var(--navbar-root-background))}.app-nav>ul>li>a:not(:last-child):hover,.app-nav>ul>li>span:not(:last-child):hover{background:var(--navbar-menu-root-background--hover, var(--navbar-menu-root-background, var(--navbar-root-background--hover, var(--navbar-root-background))))}.app-nav>ul>li>a.active{background:var(--navbar-root-background--active, var(--navbar-root-background));border-style:var(--navbar-root-border-style--active, var(--navbar-root-border-style));border-color:var(--navbar-root-border-color--active, var(--navbar-root-border-color));color:var(--navbar-root-color--active, var(--navbar-root-color));-webkit-text-decoration:var(--navbar-root-text-decoration--active, var(--navbar-root-text-decoration));text-decoration:var(--navbar-root-text-decoration--active, var(--navbar-root-text-decoration));-webkit-text-decoration-color:var(--navbar-root-text-decoration-color--active, var(--navbar-root-text-decoration-color));text-decoration-color:var(--navbar-root-text-decoration-color--active, var(--navbar-root-text-decoration-color))}.app-nav>ul>li>a.active:not(:last-child):hover{background:var(--navbar-menu-root-background--active, var(--navbar-menu-root-background, var(--navbar-root-background--active, var(--navbar-root-background))))}.app-nav>ul>li ul{visibility:hidden;position:absolute;top:100%;right:50%;overflow-y:auto;box-sizing:border-box;max-height:50vh;padding:var(--navbar-menu-padding);border-width:var(--navbar-menu-border-width, 0);border-style:solid;border-color:var(--navbar-menu-border-color);border-radius:var(--navbar-menu-border-radius);background:var(--navbar-menu-background);box-shadow:var(--navbar-menu-box-shadow);text-align:left;white-space:nowrap;opacity:0;transform:translate(50%, -0.35em);transition:var(--navbar-menu-transition)}.app-nav>ul>li ul li{white-space:nowrap}.app-nav>ul>li ul a{margin:var(--navbar-menu-link-margin);padding:var(--navbar-menu-link-padding);border-width:var(--navbar-menu-link-border-width, 0);border-style:var(--navbar-menu-link-border-style);border-color:var(--navbar-menu-link-border-color);border-radius:var(--navbar-menu-link-border-radius);background:var(--navbar-menu-link-background);color:var(--navbar-menu-link-color);-webkit-text-decoration:var(--navbar-menu-link-text-decoration);text-decoration:var(--navbar-menu-link-text-decoration);-webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color);text-decoration-color:var(--navbar-menu-link-text-decoration-color)}.app-nav>ul>li ul a:hover{background:var(--navbar-menu-link-background--hover, var(--navbar-menu-link-background));border-style:var(--navbar-menu-link-border-style--hover, var(--navbar-menu-link-border-style));border-color:var(--navbar-menu-link-border-color--hover, var(--navbar-menu-link-border-color));color:var(--navbar-menu-link-color--hover, var(--navbar-menu-link-color));-webkit-text-decoration:var(--navbar-menu-link-text-decoration--hover, var(--navbar-menu-link-text-decoration));text-decoration:var(--navbar-menu-link-text-decoration--hover, var(--navbar-menu-link-text-decoration));-webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color--hover, var(--navbar-menu-link-text-decoration-color));text-decoration-color:var(--navbar-menu-link-text-decoration-color--hover, var(--navbar-menu-link-text-decoration-color))}.app-nav>ul>li ul a.active{background:var(--navbar-menu-link-background--active, var(--navbar-menu-link-background));border-style:var(--navbar-menu-link-border-style--active, var(--navbar-menu-link-border-style));border-color:var(--navbar-menu-link-border-color--active, var(--navbar-menu-link-border-color));color:var(--navbar-menu-link-color--active, var(--navbar-menu-link-color));-webkit-text-decoration:var(--navbar-menu-link-text-decoration--active, var(--navbar-menu-link-text-decoration));text-decoration:var(--navbar-menu-link-text-decoration--active, var(--navbar-menu-link-text-decoration));-webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color--active, var(--navbar-menu-link-text-decoration-color));text-decoration-color:var(--navbar-menu-link-text-decoration-color--active, var(--navbar-menu-link-text-decoration-color))}.app-nav>ul>li:hover ul,.app-nav>ul>li:focus ul,.app-nav>ul>li.focus-within ul{visibility:visible;opacity:1;transform:translate(50%, 0)}@media(min-width: 48em){nav.app-nav{margin-left:var(--sidebar-width)}}main{position:relative;overflow-x:hidden;min-height:100vh}.sidebar,.sidebar-toggle,.sidebar+.content{transition:all var(--sidebar-transition-duration) ease-out}@media(min-width: 48em){.sidebar+.content{margin-left:var(--sidebar-width)}}.sidebar{display:flex;flex-direction:column;position:fixed;z-index:10;top:0;right:100%;overflow-x:hidden;overflow-y:auto;height:100vh;width:var(--sidebar-width);padding:var(--sidebar-padding);border-width:var(--sidebar-border-width);border-style:solid;border-color:var(--sidebar-border-color);background:var(--sidebar-background)}.sidebar>h1{margin:0;margin:var(--sidebar-name-margin);padding:var(--sidebar-name-padding);background:var(--sidebar-name-background);color:var(--sidebar-name-color);font-family:var(--sidebar-name-font-family);font-size:var(--sidebar-name-font-size);font-weight:var(--sidebar-name-font-weight);text-align:var(--sidebar-name-text-align)}.sidebar>h1 img{max-width:100%}.sidebar>h1 .app-name-link{color:var(--sidebar-name-color)}body:not([data-platform^=Mac]) .sidebar::-webkit-scrollbar{width:5px}body:not([data-platform^=Mac]) .sidebar::-webkit-scrollbar-thumb{border-radius:50vw}@media(min-width: 48em){.sidebar{position:absolute;transform:translateX(var(--sidebar-width))}}@media print{.sidebar{display:none}}.sidebar-nav,.sidebar nav{order:1;margin:var(--sidebar-nav-margin);padding:var(--sidebar-nav-padding);background:var(--sidebar-nav-background)}.sidebar-nav ul,.sidebar nav ul{margin:0;padding:0;list-style:none}.sidebar-nav ul ul,.sidebar nav ul ul{margin-left:var(--sidebar-nav-indent)}.sidebar-nav a,.sidebar nav a{display:block;overflow:hidden;margin:var(--sidebar-nav-link-margin);padding:var(--sidebar-nav-link-padding);border-width:var(--sidebar-nav-link-border-width, 0);border-style:var(--sidebar-nav-link-border-style);border-color:var(--sidebar-nav-link-border-color);border-radius:var(--sidebar-nav-link-border-radius);background:var(--sidebar-nav-link-background);color:var(--sidebar-nav-link-color);font-weight:var(--sidebar-nav-link-font-weight);white-space:nowrap;-webkit-text-decoration:var(--sidebar-nav-link-text-decoration);text-decoration:var(--sidebar-nav-link-text-decoration);-webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-overflow:ellipsis;transition:var(--sidebar-nav-link-transition)}.sidebar-nav a img,.sidebar nav a img{margin-top:-0.25em;vertical-align:middle}.sidebar-nav a img:first-child,.sidebar nav a img:first-child{margin-right:.5em}.sidebar-nav a:hover,.sidebar nav a:hover{border-width:var(--sidebar-nav-link-border-width--hover, var(--sidebar-nav-link-border-width, 0));border-style:var(--sidebar-nav-link-border-style--hover, var(--sidebar-nav-link-border-style));border-color:var(--sidebar-nav-link-border-color--hover, var(--sidebar-nav-link-border-color));background:var(--sidebar-nav-link-background--hover, var(--sidebar-nav-link-background));color:var(--sidebar-nav-link-color--hover, var(--sidebar-nav-link-color));font-weight:var(--sidebar-nav-link-font-weight--hover, var(--sidebar-nav-link-font-weight));-webkit-text-decoration:var(--sidebar-nav-link-text-decoration--hover, var(--sidebar-nav-link-text-decoration));text-decoration:var(--sidebar-nav-link-text-decoration--hover, var(--sidebar-nav-link-text-decoration));-webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-decoration-color:var(--sidebar-nav-link-text-decoration-color)}.sidebar-nav ul>li>span,.sidebar-nav ul>li>strong,.sidebar nav ul>li>span,.sidebar nav ul>li>strong{display:block;margin:var(--sidebar-nav-strong-margin);padding:var(--sidebar-nav-strong-padding);border-width:var(--sidebar-nav-strong-border-width, 0);border-style:solid;border-color:var(--sidebar-nav-strong-border-color);color:var(--sidebar-nav-strong-color);font-size:var(--sidebar-nav-strong-font-size);font-weight:var(--sidebar-nav-strong-font-weight);text-transform:var(--sidebar-nav-strong-text-transform)}.sidebar-nav ul>li>span+ul,.sidebar-nav ul>li>strong+ul,.sidebar nav ul>li>span+ul,.sidebar nav ul>li>strong+ul{margin-left:0}.sidebar-nav ul>li:first-child>span,.sidebar-nav ul>li:first-child>strong,.sidebar nav ul>li:first-child>span,.sidebar nav ul>li:first-child>strong{margin-top:0}.sidebar-nav::-webkit-scrollbar,.sidebar nav::-webkit-scrollbar{width:0}@supports(width: env(safe-area-inset)){@media only screen and (orientation: landscape){.sidebar-nav,.sidebar nav{margin-left:calc(env(safe-area-inset-left)/2)}}}.sidebar-nav li>a:before,.sidebar-nav li>strong:before{display:inline-block}.sidebar-nav li>a{background-repeat:var(--sidebar-nav-pagelink-background-repeat);background-size:var(--sidebar-nav-pagelink-background-size)}.sidebar-nav li>a[href^="/"]:not([href*="?id="]),.sidebar-nav li>a[href^="#/"]:not([href*="?id="]){transition:var(--sidebar-nav-pagelink-transition)}.sidebar-nav li>a[href^="/"]:not([href*="?id="]),.sidebar-nav li>a[href^="/"]:not([href*="?id="])~ul a,.sidebar-nav li>a[href^="#/"]:not([href*="?id="]),.sidebar-nav li>a[href^="#/"]:not([href*="?id="])~ul a{padding:var(--sidebar-nav-pagelink-padding, var(--sidebar-nav-link-padding))}.sidebar-nav li>a[href^="/"]:not([href*="?id="]):only-child,.sidebar-nav li>a[href^="#/"]:not([href*="?id="]):only-child{background:var(--sidebar-nav-pagelink-background)}.sidebar-nav li>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li>a[href^="#/"]:not([href*="?id="]):not(:only-child){background:var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background))}.sidebar-nav li.active>a,.sidebar-nav li.collapse>a{border-width:var(--sidebar-nav-link-border-width--active, var(--sidebar-nav-link-border-width));border-style:var(--sidebar-nav-link-border-style--active, var(--sidebar-nav-link-border-style));border-color:var(--sidebar-nav-link-border-color--active, var(--sidebar-nav-link-border-color));background:var(--sidebar-nav-link-background--active, var(--sidebar-nav-link-background));color:var(--sidebar-nav-link-color--active, var(--sidebar-nav-link-color));font-weight:var(--sidebar-nav-link-font-weight--active, var(--sidebar-nav-link-font-weight));-webkit-text-decoration:var(--sidebar-nav-link-text-decoration--active, var(--sidebar-nav-link-text-decoration));text-decoration:var(--sidebar-nav-link-text-decoration--active, var(--sidebar-nav-link-text-decoration));-webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-decoration-color:var(--sidebar-nav-link-text-decoration-color)}.sidebar-nav li.active>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li.active>a[href^="#/"]:not([href*="?id="]):not(:only-child){background:var(--sidebar-nav-pagelink-background--active, var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background)))}.sidebar-nav li.collapse>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li.collapse>a[href^="#/"]:not([href*="?id="]):not(:only-child){background:var(--sidebar-nav-pagelink-background--collapse, var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background)))}.sidebar-nav li.collapse .app-sub-sidebar{display:none}.sidebar-nav>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l1, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l1, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l1--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l1, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l1--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color))))}.sidebar-nav>ul>li>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l2, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l2, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l2--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l2, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l2--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color))))}.sidebar-nav>ul>li>ul>li>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l3, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l3, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li>ul>li>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l3--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l3, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l3--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color))))}.sidebar-nav>ul>li>ul>li>ul>li>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l4, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l4, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li>ul>li>ul>li>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l4--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l4, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l4--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color))))}.sidebar-nav>:last-child{margin-bottom:2rem}.sidebar-toggle,.sidebar-toggle-button{width:var(--sidebar-toggle-width);outline:none}.sidebar-toggle{position:fixed;z-index:11;top:0;bottom:0;left:0;max-width:40px;margin:0;padding:0;border:0;background:rgba(0,0,0,0);-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer}.sidebar-toggle .sidebar-toggle-button{position:absolute;top:var(--sidebar-toggle-offset-top);left:var(--sidebar-toggle-offset-left);height:var(--sidebar-toggle-height);border-radius:var(--sidebar-toggle-border-radius);border-width:var(--sidebar-toggle-border-width);border-style:var(--sidebar-toggle-border-style);border-color:var(--sidebar-toggle-border-color);background:var(--sidebar-toggle-background, transparent);color:var(--sidebar-toggle-icon-color)}.sidebar-toggle span{position:absolute;top:calc(50% - var(--sidebar-toggle-icon-stroke-width)/2);left:calc(50% - var(--sidebar-toggle-icon-width)/2);height:var(--sidebar-toggle-icon-stroke-width);width:var(--sidebar-toggle-icon-width);background-color:currentColor}.sidebar-toggle span:nth-child(1){margin-top:calc(0px - var(--sidebar-toggle-icon-height)/2)}.sidebar-toggle span:nth-child(3){margin-top:calc(var(--sidebar-toggle-icon-height)/2)}@media(min-width: 48em){.sidebar-toggle{position:absolute;overflow:visible;top:var(--sidebar-toggle-offset-top);bottom:auto;left:0;height:var(--sidebar-toggle-height);transform:translateX(var(--sidebar-width))}.sidebar-toggle .sidebar-toggle-button{top:0}}@media print{.sidebar-toggle{display:none}}@media(max-width: 47.99em){body.close .sidebar,body.close .sidebar-toggle,body.close .sidebar+.content{transform:translateX(var(--sidebar-width))}}@media(min-width: 48em){body.close .sidebar+.content{transform:translateX(0)}}@media(max-width: 47.99em){body.close nav.app-nav,body.close .github-corner{display:none}}@media(min-width: 48em){body.close .sidebar,body.close .sidebar-toggle{transform:translateX(0)}}@media(min-width: 48em){body.close nav.app-nav{margin-left:0}}@media(max-width: 47.99em){body.close .sidebar-toggle{width:100%;max-width:none}body.close .sidebar-toggle span{margin-top:0}body.close .sidebar-toggle span:nth-child(1){transform:rotate(45deg)}body.close .sidebar-toggle span:nth-child(2){display:none}body.close .sidebar-toggle span:nth-child(3){transform:rotate(-45deg)}}@media(min-width: 48em){body.close .sidebar+.content{margin-left:0}}@media(min-width: 48em){body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}}body .docsify-copy-code-button,body .docsify-copy-code-button:after{border-radius:var(--border-radius-m, 0);border-top-left-radius:0;border-bottom-right-radius:0;background:var(--copycode-background);color:var(--copycode-color)}body .docsify-copy-code-button span{border-radius:var(--border-radius-s, 0)}body .docsify-pagination-container{border-top:var(--pagination-border-top);color:var(--pagination-color)}body .pagination-item-label{font-size:var(--pagination-label-font-size)}body .pagination-item-label svg{color:var(--pagination-label-color);height:var(--pagination-chevron-height);stroke:var(--pagination-chevron-stroke);stroke-linecap:var(--pagination-chevron-stroke-linecap);stroke-linejoin:var(--pagination-chevron-stroke-linecap);stroke-width:var(--pagination-chevron-stroke-width)}body .pagination-item-title{color:var(--pagination-title-color);font-size:var(--pagination-title-font-size)}body .app-name.hide{display:block}body .sidebar{padding:var(--sidebar-padding)}.sidebar .search{margin:0;padding:0;border:0}.sidebar .search input{padding:0;line-height:1;font-size:inherit}.sidebar .search .clear-button{width:auto}.sidebar .search .clear-button svg{transform:scale(1)}.sidebar .search .matching-post{border:none}.sidebar .search p{font-size:inherit}.sidebar .search{order:var(--search-flex-order);margin:var(--search-margin);padding:var(--search-padding);background:var(--search-background)}.sidebar .search a{color:inherit}.sidebar .search h2{margin:var(--search-result-heading-margin);font-size:var(--search-result-heading-font-size);font-weight:var(--search-result-heading-font-weight);color:var(--search-result-heading-color)}.sidebar .search .input-wrap{align-items:stretch;margin:var(--search-input-margin);background-color:var(--search-input-background-color);border-width:var(--search-input-border-width, 0);border-style:solid;border-color:var(--search-input-border-color);border-radius:var(--search-input-border-radius)}.sidebar .search input[type=search]{min-width:0;padding:var(--search-input-padding);border:none;background-color:rgba(0,0,0,0);background-image:var(--search-input-background-image);background-position:var(--search-input-background-position);background-repeat:var(--search-input-background-repeat);background-size:var(--search-input-background-size);font-size:var(--search-input-font-size);color:var(--search-input-color);transition:var(--search-input-transition)}.sidebar .search input[type=search]::-ms-clear{display:none}.sidebar .search input[type=search]::-moz-placeholder{color:var(--search-input-placeholder-color, #808080)}.sidebar .search input[type=search]::placeholder{color:var(--search-input-placeholder-color, #808080)}.sidebar .search input[type=search]::-webkit-input-placeholder{line-height:normal}.sidebar .search input[type=search]:focus{background-color:var(--search-input-background-color--focus, var(--search-input-background-color));background-image:var(--search-input-background-image--focus, var(--search-input-background-image));background-position:var(--search-input-background-position--focus, var(--search-input-background-position));background-size:var(--search-input-background-size--focus, var(--search-input-background-size))}@supports(width: env(safe-area-inset)){@media only screen and (orientation: landscape){.sidebar .search input[type=search]{margin-left:calc(env(safe-area-inset-left)/2)}}}.sidebar .search p{overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical;-webkit-line-clamp:2}.sidebar .search p:empty{text-align:center}.sidebar .search .clear-button{margin:0;padding:0 10px;border:none;line-height:1;background:rgba(0,0,0,0);cursor:pointer}.sidebar .search .clear-button svg circle{fill:var(--search-clear-icon-color1, #808080)}.sidebar .search .clear-button svg path{stroke:var(--search-clear-icon-color2, #fff)}.sidebar .search.show~*:not(h1){display:none}.sidebar .search .results-panel{display:none;color:var(--search-result-item-color);font-size:var(--search-result-item-font-size);font-weight:var(--search-result-item-font-weight)}.sidebar .search .results-panel.show{display:block}.sidebar .search .matching-post{margin:var(--search-result-item-margin);padding:var(--search-result-item-padding)}.sidebar .search .matching-post,.sidebar .search .matching-post:last-child{border-width:var(--search-result-item-border-width, 0) !important;border-style:var(--search-result-item-border-style);border-color:var(--search-result-item-border-color)}.sidebar .search .matching-post p{margin:0}.sidebar .search .search-keyword{margin:var(--search-result-keyword-margin);padding:var(--search-result-keyword-padding);border-radius:var(--search-result-keyword-border-radius);background-color:var(--search-result-keyword-background);color:var(--search-result-keyword-color, currentColor);font-style:normal;font-weight:var(--search-result-keyword-font-weight)}.medium-zoom-overlay,.medium-zoom-image--open,.medium-zoom-image--opened{z-index:2147483646 !important}.medium-zoom-overlay{background:var(--zoomimage-overlay-background) !important}:root{--mono-hue: 113;--mono-saturation: 0%;--mono-shade3: hsl(var(--mono-hue), var(--mono-saturation), 20%);--mono-shade2: hsl(var(--mono-hue), var(--mono-saturation), 30%);--mono-shade1: hsl(var(--mono-hue), var(--mono-saturation), 40%);--mono-base: hsl(var(--mono-hue), var(--mono-saturation), 50%);--mono-tint1: hsl(var(--mono-hue), var(--mono-saturation), 70%);--mono-tint2: hsl(var(--mono-hue), var(--mono-saturation), 89%);--mono-tint3: hsl(var(--mono-hue), var(--mono-saturation), 97%);--theme-hue: 204;--theme-saturation: 90%;--theme-lightness: 45%;--theme-color: hsl(var(--theme-hue), var(--theme-saturation), var(--theme-lightness));--modular-scale: 1.333;--modular-scale--2: calc(var(--modular-scale--1) / var(--modular-scale));--modular-scale--1: calc(var(--modular-scale-1) / var(--modular-scale));--modular-scale-1: 1rem;--modular-scale-2: calc(var(--modular-scale-1) * var(--modular-scale));--modular-scale-3: calc(var(--modular-scale-2) * var(--modular-scale));--modular-scale-4: calc(var(--modular-scale-3) * var(--modular-scale));--modular-scale-5: calc(var(--modular-scale-4) * var(--modular-scale));--font-size-xxxl: var(--modular-scale-5);--font-size-xxl: var(--modular-scale-4);--font-size-xl: var(--modular-scale-3);--font-size-l: var(--modular-scale-2);--font-size-m: var(--modular-scale-1);--font-size-s: var(--modular-scale--1);--font-size-xs: var(--modular-scale--2);--duration-slow: 1s;--duration-medium: 0.5s;--duration-fast: 0.25s;--spinner-size: 60px;--spinner-track-width: 4px;--spinner-track-color: rgba(0, 0, 0, 0.15);--spinner-transition-duration: var(--duration-medium)}:root{--base-background-color: #fff;--base-color: var(--mono-shade2);--base-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--base-font-size: 16px;--base-font-weight: normal;--base-line-height: 1.7;--emoji-size: calc(var(--base-line-height) * 1em);--hr-border: 1px solid var(--mono-tint2);--mark-background: #ffecb3;--pre-font-family: var(--code-font-family);--pre-font-size: var(--code-font-size);--pre-font-weight: normal;--selection-color: #b4d5fe;--small-font-size: var(--font-size-s);--strong-color: var(--heading-color);--strong-font-weight: 600;--subsup-font-size: var(--font-size-s)}:root{--content-max-width: 55em;--blockquote-background: var(--mono-tint3);--blockquote-border-style: solid;--blockquote-border-radius: var(--border-radius-m);--blockquote-em-font-weight: normal;--blockquote-font-weight: normal;--blockquote-padding: 1.5em;--code-font-family: Inconsolata, Consolas, Menlo, Monaco, "Andale Mono WT", "Andale Mono", "Lucida Console", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;--code-font-size: calc(var(--font-size-m) * 0.95);--code-font-weight: normal;--code-tab-size: 4;--code-block-border-radius: var(--border-radius-m);--code-block-line-height: var(--base-line-height);--code-block-margin: 1em 0;--code-block-padding: 1.75em 1.5em 1.5em 1.5em;--code-inline-background: var(--code-theme-background);--code-inline-border-radius: var(--border-radius-s);--code-inline-color: var(--code-theme-text);--code-inline-margin: 0 0.15em;--code-inline-padding: 0.125em 0.4em;--code-theme-background: var(--mono-tint3);--heading-color: var(--mono-shade3);--heading-margin: 2.5rem 0 0;--heading-h1-border-style: solid;--heading-h1-font-size: var(--font-size-xxl);--heading-h2-border-style: solid;--heading-h2-font-size: var(--font-size-xl);--heading-h3-border-style: solid;--heading-h3-font-size: var(--font-size-l);--heading-h4-border-style: solid;--heading-h4-font-size: var(--font-size-m);--heading-h5-border-style: solid;--heading-h5-font-size: var(--font-size-s);--heading-h6-border-style: solid;--heading-h6-font-size: var(--font-size-xs);--kbd-background: var(--mono-tint3);--kbd-border-radius: var(--border-radius-m);--kbd-margin: 0 0.3em;--kbd-min-width: 2.5em;--kbd-padding: 0.65em 0.5em;--link-text-decoration: underline;--notice-background: var(--mono-tint3);--notice-border-radius: var(--border-radius-m);--notice-border-style: solid;--notice-font-weight: normal;--notice-padding: 1em 1.5em;--notice-before-font-weight: normal;--table-cell-padding: 0.75em 0.5em;--table-head-border-color: var(--table-cell-border-color);--table-head-font-weight: var(--strong-font-weight);--table-row-odd-background: var(--mono-tint3)}:root{--cover-margin: 0 auto;--cover-max-width: 40em;--cover-text-align: center;--cover-background-color: var(--base-background-color);--cover-background-mask-color: var(--base-background-color);--cover-background-mask-opacity: 0.8;--cover-background-position: center center;--cover-background-repeat: no-repeat;--cover-background-size: cover;--cover-blockquote-font-size: var(--font-size-l);--cover-border-color: var(--theme-color);--cover-button-border: 1px solid var(--theme-color);--cover-button-border-radius: var(--border-radius-m);--cover-button-color: var(--theme-color);--cover-button-padding: 0.5em 2rem;--cover-button-text-decoration: none;--cover-button-transition: all var(--duration-fast) ease-in-out;--cover-button-primary-background: var(--theme-color);--cover-button-primary-border: 1px solid var(--theme-color);--cover-button-primary-color: #fff;--cover-heading-color: var(--theme-color);--cover-heading-font-size: var(--font-size-xxl);--cover-heading-font-weight: normal;--cover-link-text-decoration: underline}:root{--navbar-root-border-style: solid;--navbar-root-margin: 0 0 0 1.5em;--navbar-root-transition: all var(--duration-fast);--navbar-menu-background: var(--base-background-color);--navbar-menu-border-radius: var(--border-radius-m);--navbar-menu-box-shadow: rgba(45,45,45,0.05) 0px 0px 1px, rgba(49,49,49,0.05) 0px 1px 2px, rgba(42,42,42,0.05) 0px 2px 4px, rgba(32,32,32,0.05) 0px 4px 8px, rgba(49,49,49,0.05) 0px 8px 16px, rgba(35,35,35,0.05) 0px 16px 32px;--navbar-menu-padding: 0.5em;--navbar-menu-transition: all var(--duration-fast);--navbar-menu-link-border-style: solid;--navbar-menu-link-margin: 0.75em 0.5em;--navbar-menu-link-padding: 0.2em 0}:root{--copycode-background: #808080;--copycode-color: #fff}:root{--docsifytabs-border-color: var(--mono-tint2);--docsifytabs-border-radius-px: var(--border-radius-s);--docsifytabs-tab-background: var(--mono-tint3);--docsifytabs-tab-color: var(--mono-tint1)}:root{--pagination-border-top: 1px solid var(--mono-tint2);--pagination-chevron-height: 0.8em;--pagination-chevron-stroke: currentColor;--pagination-chevron-stroke-linecap: round;--pagination-chevron-stroke-width: 1px;--pagination-label-font-size: var(--font-size-s);--pagination-title-font-size: var(--font-size-l)}:root{--search-margin: 1.5rem 0 0;--search-input-background-repeat: no-repeat;--search-input-border-color: var(--mono-tint1);--search-input-border-width: 1px;--search-input-padding: 0.5em;--search-flex-order: 1;--search-result-heading-color: var(--heading-color);--search-result-heading-font-size: var(--base-font-size);--search-result-heading-font-weight: normal;--search-result-heading-margin: 0 0 0.25em;--search-result-item-border-color: var(--mono-tint2);--search-result-item-border-style: solid;--search-result-item-border-width: 0 0 1px 0;--search-result-item-font-weight: normal;--search-result-item-padding: 1em 0;--search-result-keyword-background: var(--mark-background);--search-result-keyword-border-radius: var(--border-radius-s);--search-result-keyword-color: var(--mark-color);--search-result-keyword-font-weight: normal;--search-result-keyword-margin: 0 0.1em;--search-result-keyword-padding: 0.2em 0}:root{--zoomimage-overlay-background: rgba(0, 0, 0, 0.875)}:root{--sidebar-background: var(--base-background-color);--sidebar-border-width: 0;--sidebar-padding: 0 25px;--sidebar-transition-duration: var(--duration-fast);--sidebar-width: 17rem;--sidebar-name-font-size: var(--font-size-l);--sidebar-name-font-weight: normal;--sidebar-name-margin: 1.5rem 0 0;--sidebar-name-text-align: center;--sidebar-nav-strong-border-color: var(--sidebar-border-color);--sidebar-nav-strong-color: var(--heading-color);--sidebar-nav-strong-font-weight: var(--strong-font-weight);--sidebar-nav-strong-margin: 1.5em 0 0.5em;--sidebar-nav-strong-padding: 0.25em 0;--sidebar-nav-indent: 1em;--sidebar-nav-margin: 1.5rem 0 0;--sidebar-nav-link-border-style: solid;--sidebar-nav-link-border-width: 0;--sidebar-nav-link-color: var(--base-color);--sidebar-nav-link-font-weight: normal;--sidebar-nav-link-padding: 0.25em 0;--sidebar-nav-link-text-decoration--active: underline;--sidebar-nav-link-text-decoration--hover: underline;--sidebar-nav-link-before-margin: 0 0.35em 0 0;--sidebar-nav-pagelink-transition: var(--sidebar-nav-link-transition);--sidebar-toggle-border-radius: var(--border-radius-s);--sidebar-toggle-border-style: solid;--sidebar-toggle-border-width: 0;--sidebar-toggle-height: 36px;--sidebar-toggle-icon-color: var(--base-color);--sidebar-toggle-icon-height: 10px;--sidebar-toggle-icon-stroke-width: 1px;--sidebar-toggle-icon-width: 16px;--sidebar-toggle-offset-left: 0;--sidebar-toggle-offset-top: calc(35px - (var(--sidebar-toggle-height) / 2));--sidebar-toggle-width: 44px}:root{--code-theme-background: #f3f3f3;--code-theme-comment: #6e8090;--code-theme-function: #dd4a68;--code-theme-keyword: #07a;--code-theme-operator: #a67f59;--code-theme-punctuation: #999;--code-theme-selector: #690;--code-theme-tag: #905;--code-theme-text: #333;--code-theme-variable: #e90}:root{--border-radius-s: 2px;--border-radius-m: 4px;--border-radius-l: 8px;--strong-font-weight: 600;--blockquote-border-color: var(--theme-color);--blockquote-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0;--blockquote-border-width: 0 0 0 4px;--code-inline-background: var(--mono-tint2);--code-theme-background: var(--mono-tint3);--heading-font-weight: var(--strong-font-weight);--heading-h1-font-weight: 400;--heading-h2-font-weight: 400;--heading-h2-border-color: var(--mono-tint2);--heading-h2-border-width: 0 0 1px 0;--heading-h2-margin: 2.5rem 0 1.5rem;--heading-h2-padding: 0 0 1rem 0;--kbd-border: 1px solid var(--mono-tint2);--notice-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0;--notice-border-width: 0 0 0 4px;--notice-padding: 1em 1.5em 1em 3em;--notice-before-border-radius: 100%;--notice-before-font-weight: bold;--notice-before-height: 1.5em;--notice-before-left: 0.75em;--notice-before-line-height: 1.5;--notice-before-margin: 0 0.25em 0 0;--notice-before-position: absolute;--notice-before-width: var(--notice-before-height);--notice-important-background: hsl(340, 60%, 96%);--notice-important-border-color: hsl(340, 90%, 45%);--notice-important-before-background: var(--notice-important-border-color) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3E%3Cpath d='M10 14C10 15.1 9.1 16 8 16 6.9 16 6 15.1 6 14 6 12.9 6.9 12 8 12 9.1 12 10 12.9 10 14Z'/%3E%3Cpath d='M10 1.6C10 1.2 9.8 0.9 9.6 0.7 9.2 0.3 8.6 0 8 0 7.4 0 6.8 0.2 6.5 0.6 6.2 0.9 6 1.2 6 1.6 6 1.7 6 1.8 6 1.9L6.8 9.6C6.9 9.9 7 10.1 7.2 10.2 7.4 10.4 7.7 10.5 8 10.5 8.3 10.5 8.6 10.4 8.8 10.3 9 10.1 9.1 9.9 9.2 9.6L10 1.9C10 1.8 10 1.7 10 1.6Z'/%3E%3C/svg%3E") center / 0.875em no-repeat;--notice-important-before-color: #fff;--notice-important-before-content: "";--notice-tip-background: hsl(204, 60%, 96%);--notice-tip-border-color: hsl(204, 90%, 45%);--notice-tip-before-background: var(--notice-tip-border-color) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3E%3Cpath d='M9.1 0C10.2 0 10.7 0.7 10.7 1.6 10.7 2.6 9.8 3.6 8.6 3.6 7.6 3.6 7 3 7 2 7 1.1 7.7 0 9.1 0Z'/%3E%3Cpath d='M5.8 16C5 16 4.4 15.5 5 13.2L5.9 9.1C6.1 8.5 6.1 8.2 5.9 8.2 5.7 8.2 4.6 8.6 3.9 9.1L3.5 8.4C5.6 6.6 7.9 5.6 8.9 5.6 9.8 5.6 9.9 6.6 9.5 8.2L8.4 12.5C8.2 13.2 8.3 13.5 8.5 13.5 8.7 13.5 9.6 13.2 10.4 12.5L10.9 13.2C8.9 15.2 6.7 16 5.8 16Z'/%3E%3C/svg%3E") center / 0.875em no-repeat;--notice-tip-before-color: #fff;--notice-tip-before-content: "";--table-cell-border-color: var(--mono-tint2);--table-cell-border-width: 1px 0;--cover-background-color: hsl(var(--theme-hue), 25%, 60%);--cover-background-image: radial-gradient(ellipse at center 115%, rgba(255, 255, 255, 0.9), transparent);--cover-blockquote-color: var(--strong-color);--cover-heading-color: #fff;--cover-heading-font-size-max: 56;--cover-heading-font-size-min: 34;--cover-heading-font-weight: 200;--navbar-root-color--active: var(--theme-color);--navbar-menu-border-radius: var(--border-radius-m);--navbar-menu-root-background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9.6' height='6' viewBox='0 0 9.6 6'%3E%3Cpath d='M1.5 1.5l3.3 3 3.3-3' stroke-width='1.5' stroke='rgb%28179, 179, 179%29' fill='none' stroke-linecap='square' stroke-linejoin='miter' vector-effect='non-scaling-stroke'/%3E%3C/svg%3E") right no-repeat;--navbar-menu-root-padding: 0 18px 0 0;--search-input-background-color: #fff;--search-input-background-image: url("data:image/svg+xml,%3Csvg height='20px' width='20px' viewBox='0 0 24 24' fill='none' stroke='rgba(0, 0, 0, 0.3)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10.5' cy='10.5' r='7.5' vector-effect='non-scaling-stroke'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='15.8' y2='15.8' vector-effect='non-scaling-stroke'%3E%3C/line%3E%3C/svg%3E");--search-input-background-position: 21px center;--search-input-border-color: var(--sidebar-border-color);--search-input-border-width: 1px 0;--search-input-margin: 0 -25px;--search-input-padding: 0.65em 1em 0.65em 50px;--search-input-placeholder-color: rgba(0, 0, 0, 0.4);--search-clear-icon-color1: rgba(0, 0, 0, 0.3);--search-result-heading-font-weight: var(--strong-font-weight);--search-result-item-border-color: var(--sidebar-border-color);--search-result-keyword-border-radius: var(--border-radius-s);--sidebar-background: var(--mono-tint3);--sidebar-border-color: var(--mono-tint2);--sidebar-border-width: 0 1px 0 0;--sidebar-name-color: var(--theme-color);--sidebar-name-font-weight: 300;--sidebar-nav-strong-border-width: 0 0 1px 0;--sidebar-nav-strong-font-size: smaller;--sidebar-nav-strong-margin: 2em -25px 0.75em 0;--sidebar-nav-strong-padding: 0.25em 0 0.75em 0;--sidebar-nav-strong-text-transform: uppercase;--sidebar-nav-link-border-color: transparent;--sidebar-nav-link-border-color--active: var(--theme-color);--sidebar-nav-link-border-width: 0 4px 0 0;--sidebar-nav-link-color--active: var(--theme-color);--sidebar-nav-link-margin: 0 -25px 0 0;--sidebar-nav-link-text-decoration: none;--sidebar-nav-link-text-decoration--active: none;--sidebar-nav-link-text-decoration--hover: underline;--sidebar-nav-pagelink-background: no-repeat 2px calc(50% - 2.5px) / 6px 5px linear-gradient(45deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4px), no-repeat 2px calc(50% + 2.5px) / 6px 5px linear-gradient(135deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4px);--sidebar-nav-pagelink-background--active: no-repeat 0px center / 5px 6px linear-gradient(225deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4.25px), no-repeat 5px center / 5px 6px linear-gradient(135deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4.25px);--sidebar-nav-pagelink-background--collapse: no-repeat 2px calc(50% - 2.5px) / 6px 5px linear-gradient(45deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4px), no-repeat 2px calc(50% + 2.5px) / 6px 5px linear-gradient(135deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4px);--sidebar-nav-pagelink-background--loaded: no-repeat 0px center / 5px 6px linear-gradient(225deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4.25px), no-repeat 5px center / 5px 6px linear-gradient(135deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4.25px);--sidebar-nav-pagelink-padding: 0.25em 0 0.25em 20px;--sidebar-nav-pagelink-transition: none;--sidebar-toggle-background: var(--sidebar-border-color);--sidebar-toggle-border-radius: 0 var(--border-radius-s) var(--border-radius-s) 0;--sidebar-toggle-width: 32px}:root{--code-theme-background: #222;--code-theme-comment: #516e7a;--code-theme-function: #f07178;--code-theme-keyword: #c2e78c;--code-theme-operator: #ffcb6b;--code-theme-punctuation: #89ddff;--code-theme-selector: #ffcb6b;--code-theme-tag: #f07178;--code-theme-text: #f3f3f3;--code-theme-variable: #ffcb6b}:root{--mono-hue: 201;--mono-saturation: 18%;--mono-shade3: hsl(var(--mono-hue), var(--mono-saturation), 13%);--mono-shade2: hsl(var(--mono-hue), var(--mono-saturation), 15%);--mono-shade1: hsl(var(--mono-hue), var(--mono-saturation), 17%);--mono-base: hsl(var(--mono-hue), var(--mono-saturation), 19%);--mono-tint1: hsl(var(--mono-hue), var(--mono-saturation), 25%);--mono-tint2: hsl(var(--mono-hue), var(--mono-saturation), 35%);--mono-tint3: hsl(var(--mono-hue), var(--mono-saturation), 43%);--spinner-track-color: rgba(255, 255, 255, 0.15);--base-background-color: var(--mono-base);--base-color: #d3d3d3;--hr-border: 1px solid var(--mono-tint2);--mark-background: #ffcb6b;--mark-color: var(--base-background-color);--selection-color: rgba(94, 131, 175, 0.75);--blockquote-background: var(--mono-shade2);--code-inline-background: var(--mono-tint1);--code-theme-background: var(--mono-shade2);--heading-color: #fff;--heading-h2-border-color: var(--mono-tint2);--kbd-background: var(--mono-shade2);--kbd-border: none;--kbd-color: var(--strong-color);--notice-important-background: var(--mono-shade2);--notice-tip-background: var(--mono-shade2);--table-cell-border-color: var(--mono-tint1);--table-row-odd-background: var(--mono-shade2);--cover-background-color: var(--base-background-color);--cover-background-image: radial-gradient(ellipse at center bottom, var(--mono-tint3), transparent);--cover-blockquote-color: var(--mark-background);--cover-button-border: 1px solid var(--mono-tint3);--cover-button-color: #fff;--navbar-menu-background: var(--mono-tint1);--navbar-menu-box-shadow: rgba(0,0,0,0.05) 0px 0px 1px, rgba(0,0,0,0.05) 0px 1px 2px, rgba(0,0,0,0.05) 0px 2px 4px, rgba(0,0,0,0.05) 0px 4px 8px, rgba(0,0,0,0.05) 0px 8px 16px, rgba(0,0,0,0.05) 0px 16px 32px;--copycode-background: var(--mono-tint1);--copycode-color: #fff;--docsifytabs-border-color: var(--mono-tint2);--docsifytabs-tab-background: var(--mono-shade1);--docsifytabs-tab-color: var(--mono-tint2);--pagination-border-top: 1px solid var(--mono-tint2);--pagination-title-color: #fff;--search-input-background-color: var(--mono-shade2);--search-input-background-image: url("data:image/svg+xml,%3Csvg height='20px' width='20px' viewBox='0 0 24 24' fill='none' stroke='rgba(255, 255, 255, 0.3)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10.5' cy='10.5' r='7.5' vector-effect='non-scaling-stroke'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='15.8' y2='15.8' vector-effect='non-scaling-stroke'%3E%3C/line%3E%3C/svg%3E");--search-input-border-color: var(--mono-tint1);--search-input-placeholder-color: rgba(255, 255, 255, 0.4);--search-clear-icon-color1: rgba(255, 255, 255, 0.3);--sidebar-background: var(--mono-shade1);--sidebar-border-color: var(--mono-tint1);--sidebar-nav-pagelink-background: no-repeat 2px calc(50% - 2.5px) / 6px 5px linear-gradient(45deg, transparent 2.75px, var(--mono-tint2) 2.75px 4.25px, transparent 4px), no-repeat 2px calc(50% + 2.5px) / 6px 5px linear-gradient(135deg, transparent 2.75px, var(--mono-tint2) 2.75px 4.25px, transparent 4px);--sidebar-nav-pagelink-background--loaded: no-repeat 0px center / 5px 6px linear-gradient(225deg, transparent 2.75px, var(--mono-tint2) 2.75px 4.25px, transparent 4.25px), no-repeat 5px center / 5px 6px linear-gradient(135deg, transparent 2.75px, var(--mono-tint2) 2.75px 4.25px, transparent 4.25px)} + +/*# sourceMappingURL=theme-simple-dark.css.map */ \ No newline at end of file diff --git a/docs/css/theme-simple.css b/docs/css/theme-simple.css new file mode 100644 index 00000000..608d017e --- /dev/null +++ b/docs/css/theme-simple.css @@ -0,0 +1,3 @@ +.github-corner{position:absolute;z-index:40;top:0;right:0;border-bottom:0;text-decoration:none}.github-corner svg{height:70px;width:70px;fill:var(--theme-color);color:var(--base-background-color)}.github-corner:hover .octo-arm{-webkit-animation:octocat-wave 560ms ease-in-out;animation:octocat-wave 560ms ease-in-out}@-webkit-keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}.progress{position:fixed;z-index:2147483647;top:0;left:0;right:0;height:3px;width:0;background-color:var(--theme-color);transition:width var(--duration-fast),opacity calc(var(--duration-fast)*2)}body.ready-transition:after,body.ready-transition>*:not(.progress){opacity:0;transition:opacity var(--spinner-transition-duration)}body.ready-transition:after{content:"";position:absolute;z-index:1000;top:calc(50% - var(--spinner-size)/2);left:calc(50% - var(--spinner-size)/2);height:var(--spinner-size);width:var(--spinner-size);border:var(--spinner-track-width, 0) solid var(--spinner-track-color);border-left-color:var(--theme-color);border-left-color:var(--theme-color);border-radius:50%;-webkit-animation:spinner var(--duration-slow) infinite linear;animation:spinner var(--duration-slow) infinite linear}body.ready-transition.ready-spinner:after{opacity:1}body.ready-transition.ready-fix:after{opacity:0}body.ready-transition.ready-fix>*:not(.progress){opacity:1;transition-delay:var(--spinner-transition-duration)}@-webkit-keyframes spinner{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@keyframes spinner{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}*,*:before,*:after{box-sizing:inherit;font-size:inherit;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none}:root{box-sizing:border-box;background-color:var(--base-background-color);font-size:var(--base-font-size);font-weight:var(--base-font-weight);line-height:var(--base-line-height);letter-spacing:var(--base-letter-spacing);color:var(--base-color);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased}html,button,input,optgroup,select,textarea{font-family:var(--base-font-family)}button,input,optgroup,select,textarea{font-size:100%;margin:0}a{text-decoration:none;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}body{margin:0}hr{height:0;margin:2em 0;border:none;border-bottom:var(--hr-border, 0)}img{max-width:100%;border:0}main{display:block}main.hidden{display:none}mark{background:var(--mark-background);color:var(--mark-color)}pre{font-family:var(--pre-font-family);font-size:var(--pre-font-size);font-weight:var(--pre-font-weight);line-height:var(--pre-line-height)}small{display:inline-block;font-size:var(--small-font-size)}strong{font-weight:var(--strong-font-weight);color:var(--strong-color, currentColor)}sub,sup{font-size:var(--subsup-font-size);line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}body:not([data-platform^=Mac]) *{scrollbar-color:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3) hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1);scrollbar-width:thin}body:not([data-platform^=Mac]) * ::-webkit-scrollbar{width:5px;height:5px}body:not([data-platform^=Mac]) * ::-webkit-scrollbar-thumb{background:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3)}body:not([data-platform^=Mac]) * ::-webkit-scrollbar-track{background:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1)}::-moz-selection{background:var(--selection-color)}::selection{background:var(--selection-color)}.emoji{height:var(--emoji-size);vertical-align:middle}.task-list-item{list-style:none}.task-list-item input{margin-right:.5em;margin-left:0;vertical-align:.075em}.markdown-section code[class*=lang-],.markdown-section pre[data-lang]{font-family:var(--code-font-family);font-size:var(--code-font-size);font-weight:var(--code-font-weight);letter-spacing:normal;line-height:var(--code-block-line-height);-moz-tab-size:var(--code-tab-size);-o-tab-size:var(--code-tab-size);tab-size:var(--code-tab-size);text-align:left;white-space:pre;word-spacing:normal;word-wrap:normal;word-break:normal;-webkit-hyphens:none;hyphens:none}.markdown-section pre[data-lang]{position:relative;overflow:hidden;margin:var(--code-block-margin);padding:0;border-radius:var(--code-block-border-radius)}.markdown-section pre[data-lang]::after{content:attr(data-lang);position:absolute;top:.75em;right:.75em;opacity:.6;color:inherit;font-size:var(--font-size-s);line-height:1}.markdown-section pre[data-lang] code{display:block;overflow:auto;padding:var(--code-block-padding)}code[class*=lang-],pre[data-lang]{color:var(--code-theme-text)}pre[data-lang]::-moz-selection,pre[data-lang] ::-moz-selection,code[class*=lang-]::-moz-selection,code[class*=lang-] ::-moz-selection{background:var(--code-theme-selection, var(--selection-color))}pre[data-lang]::-moz-selection, pre[data-lang] ::-moz-selection, code[class*=lang-]::-moz-selection, code[class*=lang-] ::-moz-selection{background:var(--code-theme-selection, var(--selection-color))}pre[data-lang]::selection,pre[data-lang] ::selection,code[class*=lang-]::selection,code[class*=lang-] ::selection{background:var(--code-theme-selection, var(--selection-color))}:not(pre)>code[class*=lang-],pre[data-lang]{background:var(--code-theme-background)}.namespace{opacity:.7}.token.comment,.token.prolog,.token.doctype,.token.cdata{color:var(--code-theme-comment)}.token.punctuation{color:var(--code-theme-punctuation)}.token.property,.token.tag,.token.boolean,.token.number,.token.constant,.token.symbol,.token.deleted{color:var(--code-theme-tag)}.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.inserted{color:var(--code-theme-selector)}.token.operator,.token.entity,.token.url,.language-css .token.string,.style .token.string{color:var(--code-theme-operator)}.token.atrule,.token.attr-value,.token.keyword{color:var(--code-theme-keyword)}.token.function{color:var(--code-theme-function)}.token.regex,.token.important,.token.variable{color:var(--code-theme-variable)}.token.important,.token.bold{font-weight:bold}.token.italic{font-style:italic}.token.entity{cursor:help}.markdown-section{position:relative;max-width:var(--content-max-width);margin:0 auto;padding:2rem 45px}.app-nav:not(:empty)~main .markdown-section{padding-top:3.5rem}.markdown-section figure,.markdown-section p,.markdown-section ol,.markdown-section ul{margin:1em 0}.markdown-section ol,.markdown-section ul{padding-left:1.5rem}.markdown-section ol ol,.markdown-section ol ul,.markdown-section ul ol,.markdown-section ul ul{margin-top:.15rem;margin-bottom:.15rem}.markdown-section a{border-bottom:var(--link-border-bottom);color:var(--link-color);-webkit-text-decoration:var(--link-text-decoration);text-decoration:var(--link-text-decoration);-webkit-text-decoration-color:var(--link-text-decoration-color);text-decoration-color:var(--link-text-decoration-color)}.markdown-section a:hover{border-bottom:var(--link-border-bottom--hover, var(--link-border-bottom, 0));color:var(--link-color--hover, var(--link-color));-webkit-text-decoration:var(--link-text-decoration--hover, var(--link-text-decoration));text-decoration:var(--link-text-decoration--hover, var(--link-text-decoration));-webkit-text-decoration-color:var(--link-text-decoration-color--hover, var(--link-text-decoration-color));text-decoration-color:var(--link-text-decoration-color--hover, var(--link-text-decoration-color))}.markdown-section a.anchor{border-bottom:0;color:inherit;text-decoration:none}.markdown-section a.anchor:hover{text-decoration:underline}.markdown-section blockquote{overflow:visible;margin:2em 0;padding:var(--blockquote-padding);border-width:var(--blockquote-border-width, 0);border-style:var(--blockquote-border-style);border-color:var(--blockquote-border-color);border-radius:var(--blockquote-border-radius);background:var(--blockquote-background);color:var(--blockquote-color);font-family:var(--blockquote-font-family);font-size:var(--blockquote-font-size);font-style:var(--blockquote-font-style);font-weight:var(--blockquote-font-weight);quotes:"“" "”" "‘" "’"}.markdown-section blockquote em{font-family:var(--blockquote-em-font-family);font-size:var(--blockquote-em-font-size);font-style:var(--blockquote-em-font-style);font-weight:var(--blockquote-em-font-weight)}.markdown-section blockquote p:first-child{margin-top:0}.markdown-section blockquote p:first-child:before,.markdown-section blockquote p:first-child:after{color:var(--blockquote-quotes-color);font-family:var(--blockquote-quotes-font-family);font-size:var(--blockquote-quotes-font-size);line-height:0}.markdown-section blockquote p:first-child:before{content:var(--blockquote-quotes-open);margin-right:.15em;vertical-align:-0.45em}.markdown-section blockquote p:first-child:after{content:var(--blockquote-quotes-close);margin-left:.15em;vertical-align:-0.55em}.markdown-section blockquote p:last-child{margin-bottom:0}.markdown-section code{font-family:var(--code-font-family);font-size:var(--code-font-size);font-weight:var(--code-font-weight);line-height:inherit}.markdown-section code:not([class*=lang-]):not([class*=language-]){margin:var(--code-inline-margin);padding:var(--code-inline-padding);border-radius:var(--code-inline-border-radius);background:var(--code-inline-background);color:var(--code-inline-color, currentColor);white-space:nowrap}.markdown-section h1:first-child,.markdown-section h2:first-child,.markdown-section h3:first-child,.markdown-section h4:first-child,.markdown-section h5:first-child,.markdown-section h6:first-child{margin-top:0}.markdown-section h1 a[data-id],.markdown-section h2 a[data-id],.markdown-section h3 a[data-id],.markdown-section h4 a[data-id],.markdown-section h5 a[data-id],.markdown-section h6 a[data-id]{display:inline-block}.markdown-section h1 code,.markdown-section h2 code,.markdown-section h3 code,.markdown-section h4 code,.markdown-section h5 code,.markdown-section h6 code{font-size:.875em}.markdown-section h1+h2,.markdown-section h1+h3,.markdown-section h1+h4,.markdown-section h1+h5,.markdown-section h1+h6,.markdown-section h2+h3,.markdown-section h2+h4,.markdown-section h2+h5,.markdown-section h2+h6,.markdown-section h3+h4,.markdown-section h3+h5,.markdown-section h3+h6,.markdown-section h4+h5,.markdown-section h4+h6,.markdown-section h5+h6{margin-top:1rem}.markdown-section h1{margin:var(--heading-h1-margin, var(--heading-margin));padding:var(--heading-h1-padding, var(--heading-padding));border-width:var(--heading-h1-border-width, 0);border-style:var(--heading-h1-border-style);border-color:var(--heading-h1-border-color);font-family:var(--heading-h1-font-family, var(--heading-font-family));font-size:var(--heading-h1-font-size);font-weight:var(--heading-h1-font-weight, var(--heading-font-weight));line-height:var(--base-line-height);color:var(--heading-h1-color, var(--heading-color))}.markdown-section h2{margin:var(--heading-h2-margin, var(--heading-margin));padding:var(--heading-h2-padding, var(--heading-padding));border-width:var(--heading-h2-border-width, 0);border-style:var(--heading-h2-border-style);border-color:var(--heading-h2-border-color);font-family:var(--heading-h2-font-family, var(--heading-font-family));font-size:var(--heading-h2-font-size);font-weight:var(--heading-h2-font-weight, var(--heading-font-weight));line-height:var(--base-line-height);color:var(--heading-h2-color, var(--heading-color))}.markdown-section h3{margin:var(--heading-h3-margin, var(--heading-margin));padding:var(--heading-h3-padding, var(--heading-padding));border-width:var(--heading-h3-border-width, 0);border-style:var(--heading-h3-border-style);border-color:var(--heading-h3-border-color);font-family:var(--heading-h3-font-family, var(--heading-font-family));font-size:var(--heading-h3-font-size);font-weight:var(--heading-h3-font-weight, var(--heading-font-weight));color:var(--heading-h3-color, var(--heading-color))}.markdown-section h4{margin:var(--heading-h4-margin, var(--heading-margin));padding:var(--heading-h4-padding, var(--heading-padding));border-width:var(--heading-h4-border-width, 0);border-style:var(--heading-h4-border-style);border-color:var(--heading-h4-border-color);font-family:var(--heading-h4-font-family, var(--heading-font-family));font-size:var(--heading-h4-font-size);font-weight:var(--heading-h4-font-weight, var(--heading-font-weight));color:var(--heading-h4-color, var(--heading-color))}.markdown-section h5{margin:var(--heading-h5-margin, var(--heading-margin));padding:var(--heading-h5-padding, var(--heading-padding));border-width:var(--heading-h5-border-width, 0);border-style:var(--heading-h5-border-style);border-color:var(--heading-h5-border-color);font-family:var(--heading-h5-font-family, var(--heading-font-family));font-size:var(--heading-h5-font-size);font-weight:var(--heading-h5-font-weight, var(--heading-font-weight));color:var(--heading-h5-color, var(--heading-color))}.markdown-section h6{margin:var(--heading-h6-margin, var(--heading-margin));padding:var(--heading-h6-padding, var(--heading-padding));border-width:var(--heading-h6-border-width, 0);border-style:var(--heading-h6-border-style);border-color:var(--heading-h6-border-color);font-family:var(--heading-h6-font-family, var(--heading-font-family));font-size:var(--heading-h6-font-size);font-weight:var(--heading-h6-font-weight, var(--heading-font-weight));color:var(--heading-h6-color, var(--heading-color))}.markdown-section iframe{margin:1em 0}.markdown-section img{max-width:100%}.markdown-section kbd{display:inline-block;min-width:var(--kbd-min-width);margin:var(--kbd-margin);padding:var(--kbd-padding);border:var(--kbd-border);border-radius:var(--kbd-border-radius);background:var(--kbd-background);font-family:inherit;font-size:var(--kbd-font-size);text-align:center;letter-spacing:0;line-height:1;color:var(--kbd-color)}.markdown-section kbd+kbd{margin-left:-0.15em}.markdown-section table{display:block;overflow:auto;margin:1rem 0;border-spacing:0;border-collapse:collapse}.markdown-section th,.markdown-section td{padding:var(--table-cell-padding)}.markdown-section th:not([align]){text-align:left}.markdown-section thead{border-color:var(--table-head-border-color);border-style:solid;border-width:var(--table-head-border-width, 0);background:var(--table-head-background)}.markdown-section th{font-weight:var(--table-head-font-weight);color:var(--strong-color)}.markdown-section td{border-color:var(--table-cell-border-color);border-style:solid;border-width:var(--table-cell-border-width, 0)}.markdown-section tbody{border-color:var(--table-body-border-color);border-style:solid;border-width:var(--table-body-border-width, 0)}.markdown-section tbody tr:nth-child(odd){background:var(--table-row-odd-background)}.markdown-section tbody tr:nth-child(even){background:var(--table-row-even-background)}.markdown-section>ul .task-list-item{margin-left:-1.25em}.markdown-section>ul .task-list-item .task-list-item{margin-left:0}.markdown-section .table-wrapper{overflow-x:auto}.markdown-section .table-wrapper table{display:table;width:100%}.markdown-section .table-wrapper td::before{display:none}@media(max-width: 30em){.markdown-section .table-wrapper tbody,.markdown-section .table-wrapper tr,.markdown-section .table-wrapper td{display:block}.markdown-section .table-wrapper th,.markdown-section .table-wrapper td{border:none}.markdown-section .table-wrapper thead{display:none}.markdown-section .table-wrapper tr{border-color:var(--table-cell-border-color);border-style:solid;border-width:var(--table-cell-border-width, 0);padding:var(--table-cell-padding)}.markdown-section .table-wrapper tr:not(:last-child){border-bottom:0}.markdown-section .table-wrapper td{padding:.15em 0 .15em 8em}.markdown-section .table-wrapper td::before{display:inline-block;float:left;width:8em;margin-left:-8em;font-weight:bold;text-align:left}}.markdown-section .tip,.markdown-section .warn{position:relative;margin:2em 0;padding:var(--notice-padding);border-width:var(--notice-border-width, 0);border-style:var(--notice-border-style);border-color:var(--notice-border-color);border-radius:var(--notice-border-radius);background:var(--notice-background);font-family:var(--notice-font-family);font-weight:var(--notice-font-weight);color:var(--notice-color)}.markdown-section .tip:before,.markdown-section .warn:before{display:inline-block;position:var(--notice-before-position, relative);top:var(--notice-before-top);left:var(--notice-before-left);height:var(--notice-before-height);width:var(--notice-before-width);margin:var(--notice-before-margin);padding:var(--notice-before-padding);border-radius:var(--notice-before-border-radius);line-height:var(--notice-before-line-height);font-family:var(--notice-before-font-family);font-size:var(--notice-before-font-size);font-weight:var(--notice-before-font-weight);text-align:center}.markdown-section .tip{border-width:var(--notice-important-border-width, var(--notice-border-width, 0));border-style:var(--notice-important-border-style, var(--notice-border-style));border-color:var(--notice-important-border-color, var(--notice-border-color));background:var(--notice-important-background, var(--notice-background));color:var(--notice-important-color, var(--notice-color))}.markdown-section .tip:before{content:var(--notice-important-before-content, var(--notice-before-content));background:var(--notice-important-before-background, var(--notice-before-background));color:var(--notice-important-before-color, var(--notice-before-color))}.markdown-section .warn{border-width:var(--notice-tip-border-width, var(--notice-border-width, 0));border-style:var(--notice-tip-border-style, var(--notice-border-style));border-color:var(--notice-tip-border-color, var(--notice-border-color));background:var(--notice-tip-background, var(--notice-background));color:var(--notice-tip-color, var(--notice-color))}.markdown-section .warn:before{content:var(--notice-tip-before-content, var(--notice-before-content));background:var(--notice-tip-before-background, var(--notice-before-background));color:var(--notice-tip-before-color, var(--notice-before-color))}.cover{display:none;position:relative;z-index:20;min-height:100vh;flex-direction:column;align-items:center;justify-content:center;padding:calc(var(--cover-border-inset, 0px) + var(--cover-border-width, 0px));color:var(--cover-color);text-align:var(--cover-text-align)}@media screen and (-ms-high-contrast: active),screen and (-ms-high-contrast: none){.cover{height:100vh}}.cover:before,.cover:after{content:"";position:absolute}.cover:before{top:0;bottom:0;left:0;right:0;background-blend-mode:var(--cover-background-blend-mode);background-color:var(--cover-background-color);background-image:var(--cover-background-image);background-position:var(--cover-background-position);background-repeat:var(--cover-background-repeat);background-size:var(--cover-background-size)}.cover:after{top:var(--cover-border-inset, 0);bottom:var(--cover-border-inset, 0);left:var(--cover-border-inset, 0);right:var(--cover-border-inset, 0);border-width:var(--cover-border-width, 0);border-style:solid;border-color:var(--cover-border-color)}.cover a{border-bottom:var(--cover-link-border-bottom);color:var(--cover-link-color);-webkit-text-decoration:var(--cover-link-text-decoration);text-decoration:var(--cover-link-text-decoration);-webkit-text-decoration-color:var(--cover-link-text-decoration-color);text-decoration-color:var(--cover-link-text-decoration-color)}.cover a:hover{border-bottom:var(--cover-link-border-bottom--hover, var(--cover-link-border-bottom));color:var(--cover-link-color--hover, var(--cover-link-color));-webkit-text-decoration:var(--cover-link-text-decoration--hover, var(--cover-link-text-decoration));text-decoration:var(--cover-link-text-decoration--hover, var(--cover-link-text-decoration));-webkit-text-decoration-color:var(--cover-link-text-decoration-color--hover, var(--cover-link-text-decoration-color));text-decoration-color:var(--cover-link-text-decoration-color--hover, var(--cover-link-text-decoration-color))}.cover h1{color:var(--cover-heading-color);position:relative;margin:0;font-size:var(--cover-heading-font-size);font-weight:var(--cover-heading-font-weight);line-height:1.2}.cover h1 a,.cover h1 a:hover{display:block;border-bottom:none;color:inherit;text-decoration:none}.cover h1 small{position:absolute;bottom:0;margin-left:.5em}.cover h1 span{font-size:calc(var(--cover-heading-font-size-min)*1px)}@media(min-width: 26em){.cover h1 span{font-size:calc(var(--cover-heading-font-size-min)*1px + (var(--cover-heading-font-size-max) - var(--cover-heading-font-size-min))*(100vw - 420px)/604)}}@media(min-width: 64em){.cover h1 span{font-size:calc(var(--cover-heading-font-size-max)*1px)}}.cover blockquote{margin:0;color:var(--cover-blockquote-color);font-size:var(--cover-blockquote-font-size)}.cover blockquote a{color:inherit}.cover ul{padding:0;list-style-type:none}.cover .cover-main{position:relative;z-index:1;max-width:var(--cover-max-width);margin:var(--cover-margin);padding:0 45px}.cover .cover-main>p:last-child{margin:1.25em -0.25em}.cover .cover-main>p:last-child a{display:block;margin:.375em .25em;padding:var(--cover-button-padding);border:var(--cover-button-border);border-radius:var(--cover-button-border-radius);box-shadow:var(--cover-button-box-shadow);background:var(--cover-button-background);text-align:center;-webkit-text-decoration:var(--cover-button-text-decoration);text-decoration:var(--cover-button-text-decoration);-webkit-text-decoration-color:var(--cover-button-text-decoration-color);text-decoration-color:var(--cover-button-text-decoration-color);color:var(--cover-button-color);white-space:nowrap;transition:var(--cover-button-transition)}.cover .cover-main>p:last-child a:hover{border:var(--cover-button-border--hover, var(--cover-button-border));box-shadow:var(--cover-button-box-shadow--hover, var(--cover-button-box-shadow));background:var(--cover-button-background--hover, var(--cover-button-background));-webkit-text-decoration:var(--cover-button-text-decoration--hover, var(--cover-button-text-decoration));text-decoration:var(--cover-button-text-decoration--hover, var(--cover-button-text-decoration));-webkit-text-decoration-color:var(--cover-button-text-decoration-color--hover, var(--cover-button-text-decoration-color));text-decoration-color:var(--cover-button-text-decoration-color--hover, var(--cover-button-text-decoration-color));color:var(--cover-button-color--hover, var(--cover-button-color))}.cover .cover-main>p:last-child a:first-child{border:var(--cover-button-primary-border, var(--cover-button-border));box-shadow:var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow));background:var(--cover-button-primary-background, var(--cover-button-background));-webkit-text-decoration:var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration));text-decoration:var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration));-webkit-text-decoration-color:var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color));text-decoration-color:var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color));color:var(--cover-button-primary-color, var(--cover-button-color))}.cover .cover-main>p:last-child a:first-child:hover{border:var(--cover-button-primary-border--hover, var(--cover-button-border--hover, var(--cover-button-primary-border, var(--cover-button-border))));box-shadow:var(--cover-button-primary-box-shadow--hover, var(--cover-button-box-shadow--hover, var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow))));background:var(--cover-button-primary-background--hover, var(--cover-button-background--hover, var(--cover-button-primary-background, var(--cover-button-background))));-webkit-text-decoration:var(--cover-button-primary-text-decoration--hover, var(--cover-button-text-decoration--hover, var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration))));text-decoration:var(--cover-button-primary-text-decoration--hover, var(--cover-button-text-decoration--hover, var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration))));-webkit-text-decoration-color:var(--cover-button-primary-text-decoration-color--hover, var(--cover-button-text-decoration-color--hover, var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color))));text-decoration-color:var(--cover-button-primary-text-decoration-color--hover, var(--cover-button-text-decoration-color--hover, var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color))));color:var(--cover-button-primary-color--hover, var(--cover-button-color--hover, var(--cover-button-primary-color, var(--cover-button-color))))}@media(min-width: 30.01em){.cover .cover-main>p:last-child a{display:inline-block}}.cover .mask{visibility:var(--cover-background-mask-visibility, hidden);position:absolute;top:0;bottom:0;left:0;right:0;background-color:var(--cover-background-mask-color);opacity:var(--cover-background-mask-opacity)}.cover.has-mask .mask{visibility:visible}.cover.show{display:flex}.app-nav{position:absolute;z-index:30;top:calc(35px - .5em*var(--base-line-height));left:45px;right:80px;text-align:right}.app-nav.no-badge{right:45px}.app-nav li>img,.app-nav li>a>img{margin-top:-0.25em;vertical-align:middle}.app-nav li>img:first-child,.app-nav li>a>img:first-child{margin-right:.5em}.app-nav ul,.app-nav li{margin:0;padding:0;list-style:none}.app-nav li{position:relative}.app-nav li a{display:block;line-height:1;transition:var(--navbar-root-transition)}.app-nav>ul>li{display:inline-block;margin:var(--navbar-root-margin)}.app-nav>ul>li:first-child{margin-left:0}.app-nav>ul>li:last-child{margin-right:0}.app-nav>ul>li>a,.app-nav>ul>li>span{padding:var(--navbar-root-padding);border-width:var(--navbar-root-border-width, 0);border-style:var(--navbar-root-border-style);border-color:var(--navbar-root-border-color);border-radius:var(--navbar-root-border-radius);background:var(--navbar-root-background);color:var(--navbar-root-color);-webkit-text-decoration:var(--navbar-root-text-decoration);text-decoration:var(--navbar-root-text-decoration);-webkit-text-decoration-color:var(--navbar-root-text-decoration-color);text-decoration-color:var(--navbar-root-text-decoration-color)}.app-nav>ul>li>a:hover,.app-nav>ul>li>span:hover{background:var(--navbar-root-background--hover, var(--navbar-root-background));border-style:var(--navbar-root-border-style--hover, var(--navbar-root-border-style));border-color:var(--navbar-root-border-color--hover, var(--navbar-root-border-color));color:var(--navbar-root-color--hover, var(--navbar-root-color));-webkit-text-decoration:var(--navbar-root-text-decoration--hover, var(--navbar-root-text-decoration));text-decoration:var(--navbar-root-text-decoration--hover, var(--navbar-root-text-decoration));-webkit-text-decoration-color:var(--navbar-root-text-decoration-color--hover, var(--navbar-root-text-decoration-color));text-decoration-color:var(--navbar-root-text-decoration-color--hover, var(--navbar-root-text-decoration-color))}.app-nav>ul>li>a:not(:last-child),.app-nav>ul>li>span:not(:last-child){padding:var(--navbar-menu-root-padding, var(--navbar-root-padding));background:var(--navbar-menu-root-background, var(--navbar-root-background))}.app-nav>ul>li>a:not(:last-child):hover,.app-nav>ul>li>span:not(:last-child):hover{background:var(--navbar-menu-root-background--hover, var(--navbar-menu-root-background, var(--navbar-root-background--hover, var(--navbar-root-background))))}.app-nav>ul>li>a.active{background:var(--navbar-root-background--active, var(--navbar-root-background));border-style:var(--navbar-root-border-style--active, var(--navbar-root-border-style));border-color:var(--navbar-root-border-color--active, var(--navbar-root-border-color));color:var(--navbar-root-color--active, var(--navbar-root-color));-webkit-text-decoration:var(--navbar-root-text-decoration--active, var(--navbar-root-text-decoration));text-decoration:var(--navbar-root-text-decoration--active, var(--navbar-root-text-decoration));-webkit-text-decoration-color:var(--navbar-root-text-decoration-color--active, var(--navbar-root-text-decoration-color));text-decoration-color:var(--navbar-root-text-decoration-color--active, var(--navbar-root-text-decoration-color))}.app-nav>ul>li>a.active:not(:last-child):hover{background:var(--navbar-menu-root-background--active, var(--navbar-menu-root-background, var(--navbar-root-background--active, var(--navbar-root-background))))}.app-nav>ul>li ul{visibility:hidden;position:absolute;top:100%;right:50%;overflow-y:auto;box-sizing:border-box;max-height:50vh;padding:var(--navbar-menu-padding);border-width:var(--navbar-menu-border-width, 0);border-style:solid;border-color:var(--navbar-menu-border-color);border-radius:var(--navbar-menu-border-radius);background:var(--navbar-menu-background);box-shadow:var(--navbar-menu-box-shadow);text-align:left;white-space:nowrap;opacity:0;transform:translate(50%, -0.35em);transition:var(--navbar-menu-transition)}.app-nav>ul>li ul li{white-space:nowrap}.app-nav>ul>li ul a{margin:var(--navbar-menu-link-margin);padding:var(--navbar-menu-link-padding);border-width:var(--navbar-menu-link-border-width, 0);border-style:var(--navbar-menu-link-border-style);border-color:var(--navbar-menu-link-border-color);border-radius:var(--navbar-menu-link-border-radius);background:var(--navbar-menu-link-background);color:var(--navbar-menu-link-color);-webkit-text-decoration:var(--navbar-menu-link-text-decoration);text-decoration:var(--navbar-menu-link-text-decoration);-webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color);text-decoration-color:var(--navbar-menu-link-text-decoration-color)}.app-nav>ul>li ul a:hover{background:var(--navbar-menu-link-background--hover, var(--navbar-menu-link-background));border-style:var(--navbar-menu-link-border-style--hover, var(--navbar-menu-link-border-style));border-color:var(--navbar-menu-link-border-color--hover, var(--navbar-menu-link-border-color));color:var(--navbar-menu-link-color--hover, var(--navbar-menu-link-color));-webkit-text-decoration:var(--navbar-menu-link-text-decoration--hover, var(--navbar-menu-link-text-decoration));text-decoration:var(--navbar-menu-link-text-decoration--hover, var(--navbar-menu-link-text-decoration));-webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color--hover, var(--navbar-menu-link-text-decoration-color));text-decoration-color:var(--navbar-menu-link-text-decoration-color--hover, var(--navbar-menu-link-text-decoration-color))}.app-nav>ul>li ul a.active{background:var(--navbar-menu-link-background--active, var(--navbar-menu-link-background));border-style:var(--navbar-menu-link-border-style--active, var(--navbar-menu-link-border-style));border-color:var(--navbar-menu-link-border-color--active, var(--navbar-menu-link-border-color));color:var(--navbar-menu-link-color--active, var(--navbar-menu-link-color));-webkit-text-decoration:var(--navbar-menu-link-text-decoration--active, var(--navbar-menu-link-text-decoration));text-decoration:var(--navbar-menu-link-text-decoration--active, var(--navbar-menu-link-text-decoration));-webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color--active, var(--navbar-menu-link-text-decoration-color));text-decoration-color:var(--navbar-menu-link-text-decoration-color--active, var(--navbar-menu-link-text-decoration-color))}.app-nav>ul>li:hover ul,.app-nav>ul>li:focus ul,.app-nav>ul>li.focus-within ul{visibility:visible;opacity:1;transform:translate(50%, 0)}@media(min-width: 48em){nav.app-nav{margin-left:var(--sidebar-width)}}main{position:relative;overflow-x:hidden;min-height:100vh}.sidebar,.sidebar-toggle,.sidebar+.content{transition:all var(--sidebar-transition-duration) ease-out}@media(min-width: 48em){.sidebar+.content{margin-left:var(--sidebar-width)}}.sidebar{display:flex;flex-direction:column;position:fixed;z-index:10;top:0;right:100%;overflow-x:hidden;overflow-y:auto;height:100vh;width:var(--sidebar-width);padding:var(--sidebar-padding);border-width:var(--sidebar-border-width);border-style:solid;border-color:var(--sidebar-border-color);background:var(--sidebar-background)}.sidebar>h1{margin:0;margin:var(--sidebar-name-margin);padding:var(--sidebar-name-padding);background:var(--sidebar-name-background);color:var(--sidebar-name-color);font-family:var(--sidebar-name-font-family);font-size:var(--sidebar-name-font-size);font-weight:var(--sidebar-name-font-weight);text-align:var(--sidebar-name-text-align)}.sidebar>h1 img{max-width:100%}.sidebar>h1 .app-name-link{color:var(--sidebar-name-color)}body:not([data-platform^=Mac]) .sidebar::-webkit-scrollbar{width:5px}body:not([data-platform^=Mac]) .sidebar::-webkit-scrollbar-thumb{border-radius:50vw}@media(min-width: 48em){.sidebar{position:absolute;transform:translateX(var(--sidebar-width))}}@media print{.sidebar{display:none}}.sidebar-nav,.sidebar nav{order:1;margin:var(--sidebar-nav-margin);padding:var(--sidebar-nav-padding);background:var(--sidebar-nav-background)}.sidebar-nav ul,.sidebar nav ul{margin:0;padding:0;list-style:none}.sidebar-nav ul ul,.sidebar nav ul ul{margin-left:var(--sidebar-nav-indent)}.sidebar-nav a,.sidebar nav a{display:block;overflow:hidden;margin:var(--sidebar-nav-link-margin);padding:var(--sidebar-nav-link-padding);border-width:var(--sidebar-nav-link-border-width, 0);border-style:var(--sidebar-nav-link-border-style);border-color:var(--sidebar-nav-link-border-color);border-radius:var(--sidebar-nav-link-border-radius);background:var(--sidebar-nav-link-background);color:var(--sidebar-nav-link-color);font-weight:var(--sidebar-nav-link-font-weight);white-space:nowrap;-webkit-text-decoration:var(--sidebar-nav-link-text-decoration);text-decoration:var(--sidebar-nav-link-text-decoration);-webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-overflow:ellipsis;transition:var(--sidebar-nav-link-transition)}.sidebar-nav a img,.sidebar nav a img{margin-top:-0.25em;vertical-align:middle}.sidebar-nav a img:first-child,.sidebar nav a img:first-child{margin-right:.5em}.sidebar-nav a:hover,.sidebar nav a:hover{border-width:var(--sidebar-nav-link-border-width--hover, var(--sidebar-nav-link-border-width, 0));border-style:var(--sidebar-nav-link-border-style--hover, var(--sidebar-nav-link-border-style));border-color:var(--sidebar-nav-link-border-color--hover, var(--sidebar-nav-link-border-color));background:var(--sidebar-nav-link-background--hover, var(--sidebar-nav-link-background));color:var(--sidebar-nav-link-color--hover, var(--sidebar-nav-link-color));font-weight:var(--sidebar-nav-link-font-weight--hover, var(--sidebar-nav-link-font-weight));-webkit-text-decoration:var(--sidebar-nav-link-text-decoration--hover, var(--sidebar-nav-link-text-decoration));text-decoration:var(--sidebar-nav-link-text-decoration--hover, var(--sidebar-nav-link-text-decoration));-webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-decoration-color:var(--sidebar-nav-link-text-decoration-color)}.sidebar-nav ul>li>span,.sidebar-nav ul>li>strong,.sidebar nav ul>li>span,.sidebar nav ul>li>strong{display:block;margin:var(--sidebar-nav-strong-margin);padding:var(--sidebar-nav-strong-padding);border-width:var(--sidebar-nav-strong-border-width, 0);border-style:solid;border-color:var(--sidebar-nav-strong-border-color);color:var(--sidebar-nav-strong-color);font-size:var(--sidebar-nav-strong-font-size);font-weight:var(--sidebar-nav-strong-font-weight);text-transform:var(--sidebar-nav-strong-text-transform)}.sidebar-nav ul>li>span+ul,.sidebar-nav ul>li>strong+ul,.sidebar nav ul>li>span+ul,.sidebar nav ul>li>strong+ul{margin-left:0}.sidebar-nav ul>li:first-child>span,.sidebar-nav ul>li:first-child>strong,.sidebar nav ul>li:first-child>span,.sidebar nav ul>li:first-child>strong{margin-top:0}.sidebar-nav::-webkit-scrollbar,.sidebar nav::-webkit-scrollbar{width:0}@supports(width: env(safe-area-inset)){@media only screen and (orientation: landscape){.sidebar-nav,.sidebar nav{margin-left:calc(env(safe-area-inset-left)/2)}}}.sidebar-nav li>a:before,.sidebar-nav li>strong:before{display:inline-block}.sidebar-nav li>a{background-repeat:var(--sidebar-nav-pagelink-background-repeat);background-size:var(--sidebar-nav-pagelink-background-size)}.sidebar-nav li>a[href^="/"]:not([href*="?id="]),.sidebar-nav li>a[href^="#/"]:not([href*="?id="]){transition:var(--sidebar-nav-pagelink-transition)}.sidebar-nav li>a[href^="/"]:not([href*="?id="]),.sidebar-nav li>a[href^="/"]:not([href*="?id="])~ul a,.sidebar-nav li>a[href^="#/"]:not([href*="?id="]),.sidebar-nav li>a[href^="#/"]:not([href*="?id="])~ul a{padding:var(--sidebar-nav-pagelink-padding, var(--sidebar-nav-link-padding))}.sidebar-nav li>a[href^="/"]:not([href*="?id="]):only-child,.sidebar-nav li>a[href^="#/"]:not([href*="?id="]):only-child{background:var(--sidebar-nav-pagelink-background)}.sidebar-nav li>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li>a[href^="#/"]:not([href*="?id="]):not(:only-child){background:var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background))}.sidebar-nav li.active>a,.sidebar-nav li.collapse>a{border-width:var(--sidebar-nav-link-border-width--active, var(--sidebar-nav-link-border-width));border-style:var(--sidebar-nav-link-border-style--active, var(--sidebar-nav-link-border-style));border-color:var(--sidebar-nav-link-border-color--active, var(--sidebar-nav-link-border-color));background:var(--sidebar-nav-link-background--active, var(--sidebar-nav-link-background));color:var(--sidebar-nav-link-color--active, var(--sidebar-nav-link-color));font-weight:var(--sidebar-nav-link-font-weight--active, var(--sidebar-nav-link-font-weight));-webkit-text-decoration:var(--sidebar-nav-link-text-decoration--active, var(--sidebar-nav-link-text-decoration));text-decoration:var(--sidebar-nav-link-text-decoration--active, var(--sidebar-nav-link-text-decoration));-webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-decoration-color:var(--sidebar-nav-link-text-decoration-color)}.sidebar-nav li.active>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li.active>a[href^="#/"]:not([href*="?id="]):not(:only-child){background:var(--sidebar-nav-pagelink-background--active, var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background)))}.sidebar-nav li.collapse>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li.collapse>a[href^="#/"]:not([href*="?id="]):not(:only-child){background:var(--sidebar-nav-pagelink-background--collapse, var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background)))}.sidebar-nav li.collapse .app-sub-sidebar{display:none}.sidebar-nav>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l1, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l1, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l1--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l1, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l1--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color))))}.sidebar-nav>ul>li>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l2, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l2, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l2--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l2, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l2--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color))))}.sidebar-nav>ul>li>ul>li>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l3, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l3, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li>ul>li>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l3--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l3, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l3--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color))))}.sidebar-nav>ul>li>ul>li>ul>li>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l4, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l4, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li>ul>li>ul>li>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l4--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l4, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l4--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color))))}.sidebar-nav>:last-child{margin-bottom:2rem}.sidebar-toggle,.sidebar-toggle-button{width:var(--sidebar-toggle-width);outline:none}.sidebar-toggle{position:fixed;z-index:11;top:0;bottom:0;left:0;max-width:40px;margin:0;padding:0;border:0;background:rgba(0,0,0,0);-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer}.sidebar-toggle .sidebar-toggle-button{position:absolute;top:var(--sidebar-toggle-offset-top);left:var(--sidebar-toggle-offset-left);height:var(--sidebar-toggle-height);border-radius:var(--sidebar-toggle-border-radius);border-width:var(--sidebar-toggle-border-width);border-style:var(--sidebar-toggle-border-style);border-color:var(--sidebar-toggle-border-color);background:var(--sidebar-toggle-background, transparent);color:var(--sidebar-toggle-icon-color)}.sidebar-toggle span{position:absolute;top:calc(50% - var(--sidebar-toggle-icon-stroke-width)/2);left:calc(50% - var(--sidebar-toggle-icon-width)/2);height:var(--sidebar-toggle-icon-stroke-width);width:var(--sidebar-toggle-icon-width);background-color:currentColor}.sidebar-toggle span:nth-child(1){margin-top:calc(0px - var(--sidebar-toggle-icon-height)/2)}.sidebar-toggle span:nth-child(3){margin-top:calc(var(--sidebar-toggle-icon-height)/2)}@media(min-width: 48em){.sidebar-toggle{position:absolute;overflow:visible;top:var(--sidebar-toggle-offset-top);bottom:auto;left:0;height:var(--sidebar-toggle-height);transform:translateX(var(--sidebar-width))}.sidebar-toggle .sidebar-toggle-button{top:0}}@media print{.sidebar-toggle{display:none}}@media(max-width: 47.99em){body.close .sidebar,body.close .sidebar-toggle,body.close .sidebar+.content{transform:translateX(var(--sidebar-width))}}@media(min-width: 48em){body.close .sidebar+.content{transform:translateX(0)}}@media(max-width: 47.99em){body.close nav.app-nav,body.close .github-corner{display:none}}@media(min-width: 48em){body.close .sidebar,body.close .sidebar-toggle{transform:translateX(0)}}@media(min-width: 48em){body.close nav.app-nav{margin-left:0}}@media(max-width: 47.99em){body.close .sidebar-toggle{width:100%;max-width:none}body.close .sidebar-toggle span{margin-top:0}body.close .sidebar-toggle span:nth-child(1){transform:rotate(45deg)}body.close .sidebar-toggle span:nth-child(2){display:none}body.close .sidebar-toggle span:nth-child(3){transform:rotate(-45deg)}}@media(min-width: 48em){body.close .sidebar+.content{margin-left:0}}@media(min-width: 48em){body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}}body .docsify-copy-code-button,body .docsify-copy-code-button:after{border-radius:var(--border-radius-m, 0);border-top-left-radius:0;border-bottom-right-radius:0;background:var(--copycode-background);color:var(--copycode-color)}body .docsify-copy-code-button span{border-radius:var(--border-radius-s, 0)}body .docsify-pagination-container{border-top:var(--pagination-border-top);color:var(--pagination-color)}body .pagination-item-label{font-size:var(--pagination-label-font-size)}body .pagination-item-label svg{color:var(--pagination-label-color);height:var(--pagination-chevron-height);stroke:var(--pagination-chevron-stroke);stroke-linecap:var(--pagination-chevron-stroke-linecap);stroke-linejoin:var(--pagination-chevron-stroke-linecap);stroke-width:var(--pagination-chevron-stroke-width)}body .pagination-item-title{color:var(--pagination-title-color);font-size:var(--pagination-title-font-size)}body .app-name.hide{display:block}body .sidebar{padding:var(--sidebar-padding)}.sidebar .search{margin:0;padding:0;border:0}.sidebar .search input{padding:0;line-height:1;font-size:inherit}.sidebar .search .clear-button{width:auto}.sidebar .search .clear-button svg{transform:scale(1)}.sidebar .search .matching-post{border:none}.sidebar .search p{font-size:inherit}.sidebar .search{order:var(--search-flex-order);margin:var(--search-margin);padding:var(--search-padding);background:var(--search-background)}.sidebar .search a{color:inherit}.sidebar .search h2{margin:var(--search-result-heading-margin);font-size:var(--search-result-heading-font-size);font-weight:var(--search-result-heading-font-weight);color:var(--search-result-heading-color)}.sidebar .search .input-wrap{align-items:stretch;margin:var(--search-input-margin);background-color:var(--search-input-background-color);border-width:var(--search-input-border-width, 0);border-style:solid;border-color:var(--search-input-border-color);border-radius:var(--search-input-border-radius)}.sidebar .search input[type=search]{min-width:0;padding:var(--search-input-padding);border:none;background-color:rgba(0,0,0,0);background-image:var(--search-input-background-image);background-position:var(--search-input-background-position);background-repeat:var(--search-input-background-repeat);background-size:var(--search-input-background-size);font-size:var(--search-input-font-size);color:var(--search-input-color);transition:var(--search-input-transition)}.sidebar .search input[type=search]::-ms-clear{display:none}.sidebar .search input[type=search]::-moz-placeholder{color:var(--search-input-placeholder-color, #808080)}.sidebar .search input[type=search]::placeholder{color:var(--search-input-placeholder-color, #808080)}.sidebar .search input[type=search]::-webkit-input-placeholder{line-height:normal}.sidebar .search input[type=search]:focus{background-color:var(--search-input-background-color--focus, var(--search-input-background-color));background-image:var(--search-input-background-image--focus, var(--search-input-background-image));background-position:var(--search-input-background-position--focus, var(--search-input-background-position));background-size:var(--search-input-background-size--focus, var(--search-input-background-size))}@supports(width: env(safe-area-inset)){@media only screen and (orientation: landscape){.sidebar .search input[type=search]{margin-left:calc(env(safe-area-inset-left)/2)}}}.sidebar .search p{overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical;-webkit-line-clamp:2}.sidebar .search p:empty{text-align:center}.sidebar .search .clear-button{margin:0;padding:0 10px;border:none;line-height:1;background:rgba(0,0,0,0);cursor:pointer}.sidebar .search .clear-button svg circle{fill:var(--search-clear-icon-color1, #808080)}.sidebar .search .clear-button svg path{stroke:var(--search-clear-icon-color2, #fff)}.sidebar .search.show~*:not(h1){display:none}.sidebar .search .results-panel{display:none;color:var(--search-result-item-color);font-size:var(--search-result-item-font-size);font-weight:var(--search-result-item-font-weight)}.sidebar .search .results-panel.show{display:block}.sidebar .search .matching-post{margin:var(--search-result-item-margin);padding:var(--search-result-item-padding)}.sidebar .search .matching-post,.sidebar .search .matching-post:last-child{border-width:var(--search-result-item-border-width, 0) !important;border-style:var(--search-result-item-border-style);border-color:var(--search-result-item-border-color)}.sidebar .search .matching-post p{margin:0}.sidebar .search .search-keyword{margin:var(--search-result-keyword-margin);padding:var(--search-result-keyword-padding);border-radius:var(--search-result-keyword-border-radius);background-color:var(--search-result-keyword-background);color:var(--search-result-keyword-color, currentColor);font-style:normal;font-weight:var(--search-result-keyword-font-weight)}.medium-zoom-overlay,.medium-zoom-image--open,.medium-zoom-image--opened{z-index:2147483646 !important}.medium-zoom-overlay{background:var(--zoomimage-overlay-background) !important}:root{--mono-hue: 113;--mono-saturation: 0%;--mono-shade3: hsl(var(--mono-hue), var(--mono-saturation), 20%);--mono-shade2: hsl(var(--mono-hue), var(--mono-saturation), 30%);--mono-shade1: hsl(var(--mono-hue), var(--mono-saturation), 40%);--mono-base: hsl(var(--mono-hue), var(--mono-saturation), 50%);--mono-tint1: hsl(var(--mono-hue), var(--mono-saturation), 70%);--mono-tint2: hsl(var(--mono-hue), var(--mono-saturation), 89%);--mono-tint3: hsl(var(--mono-hue), var(--mono-saturation), 97%);--theme-hue: 204;--theme-saturation: 90%;--theme-lightness: 45%;--theme-color: hsl(var(--theme-hue), var(--theme-saturation), var(--theme-lightness));--modular-scale: 1.333;--modular-scale--2: calc(var(--modular-scale--1) / var(--modular-scale));--modular-scale--1: calc(var(--modular-scale-1) / var(--modular-scale));--modular-scale-1: 1rem;--modular-scale-2: calc(var(--modular-scale-1) * var(--modular-scale));--modular-scale-3: calc(var(--modular-scale-2) * var(--modular-scale));--modular-scale-4: calc(var(--modular-scale-3) * var(--modular-scale));--modular-scale-5: calc(var(--modular-scale-4) * var(--modular-scale));--font-size-xxxl: var(--modular-scale-5);--font-size-xxl: var(--modular-scale-4);--font-size-xl: var(--modular-scale-3);--font-size-l: var(--modular-scale-2);--font-size-m: var(--modular-scale-1);--font-size-s: var(--modular-scale--1);--font-size-xs: var(--modular-scale--2);--duration-slow: 1s;--duration-medium: 0.5s;--duration-fast: 0.25s;--spinner-size: 60px;--spinner-track-width: 4px;--spinner-track-color: rgba(0, 0, 0, 0.15);--spinner-transition-duration: var(--duration-medium)}:root{--base-background-color: #fff;--base-color: var(--mono-shade2);--base-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--base-font-size: 16px;--base-font-weight: normal;--base-line-height: 1.7;--emoji-size: calc(var(--base-line-height) * 1em);--hr-border: 1px solid var(--mono-tint2);--mark-background: #ffecb3;--pre-font-family: var(--code-font-family);--pre-font-size: var(--code-font-size);--pre-font-weight: normal;--selection-color: #b4d5fe;--small-font-size: var(--font-size-s);--strong-color: var(--heading-color);--strong-font-weight: 600;--subsup-font-size: var(--font-size-s)}:root{--content-max-width: 55em;--blockquote-background: var(--mono-tint3);--blockquote-border-style: solid;--blockquote-border-radius: var(--border-radius-m);--blockquote-em-font-weight: normal;--blockquote-font-weight: normal;--blockquote-padding: 1.5em;--code-font-family: Inconsolata, Consolas, Menlo, Monaco, "Andale Mono WT", "Andale Mono", "Lucida Console", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;--code-font-size: calc(var(--font-size-m) * 0.95);--code-font-weight: normal;--code-tab-size: 4;--code-block-border-radius: var(--border-radius-m);--code-block-line-height: var(--base-line-height);--code-block-margin: 1em 0;--code-block-padding: 1.75em 1.5em 1.5em 1.5em;--code-inline-background: var(--code-theme-background);--code-inline-border-radius: var(--border-radius-s);--code-inline-color: var(--code-theme-text);--code-inline-margin: 0 0.15em;--code-inline-padding: 0.125em 0.4em;--code-theme-background: var(--mono-tint3);--heading-color: var(--mono-shade3);--heading-margin: 2.5rem 0 0;--heading-h1-border-style: solid;--heading-h1-font-size: var(--font-size-xxl);--heading-h2-border-style: solid;--heading-h2-font-size: var(--font-size-xl);--heading-h3-border-style: solid;--heading-h3-font-size: var(--font-size-l);--heading-h4-border-style: solid;--heading-h4-font-size: var(--font-size-m);--heading-h5-border-style: solid;--heading-h5-font-size: var(--font-size-s);--heading-h6-border-style: solid;--heading-h6-font-size: var(--font-size-xs);--kbd-background: var(--mono-tint3);--kbd-border-radius: var(--border-radius-m);--kbd-margin: 0 0.3em;--kbd-min-width: 2.5em;--kbd-padding: 0.65em 0.5em;--link-text-decoration: underline;--notice-background: var(--mono-tint3);--notice-border-radius: var(--border-radius-m);--notice-border-style: solid;--notice-font-weight: normal;--notice-padding: 1em 1.5em;--notice-before-font-weight: normal;--table-cell-padding: 0.75em 0.5em;--table-head-border-color: var(--table-cell-border-color);--table-head-font-weight: var(--strong-font-weight);--table-row-odd-background: var(--mono-tint3)}:root{--cover-margin: 0 auto;--cover-max-width: 40em;--cover-text-align: center;--cover-background-color: var(--base-background-color);--cover-background-mask-color: var(--base-background-color);--cover-background-mask-opacity: 0.8;--cover-background-position: center center;--cover-background-repeat: no-repeat;--cover-background-size: cover;--cover-blockquote-font-size: var(--font-size-l);--cover-border-color: var(--theme-color);--cover-button-border: 1px solid var(--theme-color);--cover-button-border-radius: var(--border-radius-m);--cover-button-color: var(--theme-color);--cover-button-padding: 0.5em 2rem;--cover-button-text-decoration: none;--cover-button-transition: all var(--duration-fast) ease-in-out;--cover-button-primary-background: var(--theme-color);--cover-button-primary-border: 1px solid var(--theme-color);--cover-button-primary-color: #fff;--cover-heading-color: var(--theme-color);--cover-heading-font-size: var(--font-size-xxl);--cover-heading-font-weight: normal;--cover-link-text-decoration: underline}:root{--navbar-root-border-style: solid;--navbar-root-margin: 0 0 0 1.5em;--navbar-root-transition: all var(--duration-fast);--navbar-menu-background: var(--base-background-color);--navbar-menu-border-radius: var(--border-radius-m);--navbar-menu-box-shadow: rgba(45,45,45,0.05) 0px 0px 1px, rgba(49,49,49,0.05) 0px 1px 2px, rgba(42,42,42,0.05) 0px 2px 4px, rgba(32,32,32,0.05) 0px 4px 8px, rgba(49,49,49,0.05) 0px 8px 16px, rgba(35,35,35,0.05) 0px 16px 32px;--navbar-menu-padding: 0.5em;--navbar-menu-transition: all var(--duration-fast);--navbar-menu-link-border-style: solid;--navbar-menu-link-margin: 0.75em 0.5em;--navbar-menu-link-padding: 0.2em 0}:root{--copycode-background: #808080;--copycode-color: #fff}:root{--docsifytabs-border-color: var(--mono-tint2);--docsifytabs-border-radius-px: var(--border-radius-s);--docsifytabs-tab-background: var(--mono-tint3);--docsifytabs-tab-color: var(--mono-tint1)}:root{--pagination-border-top: 1px solid var(--mono-tint2);--pagination-chevron-height: 0.8em;--pagination-chevron-stroke: currentColor;--pagination-chevron-stroke-linecap: round;--pagination-chevron-stroke-width: 1px;--pagination-label-font-size: var(--font-size-s);--pagination-title-font-size: var(--font-size-l)}:root{--search-margin: 1.5rem 0 0;--search-input-background-repeat: no-repeat;--search-input-border-color: var(--mono-tint1);--search-input-border-width: 1px;--search-input-padding: 0.5em;--search-flex-order: 1;--search-result-heading-color: var(--heading-color);--search-result-heading-font-size: var(--base-font-size);--search-result-heading-font-weight: normal;--search-result-heading-margin: 0 0 0.25em;--search-result-item-border-color: var(--mono-tint2);--search-result-item-border-style: solid;--search-result-item-border-width: 0 0 1px 0;--search-result-item-font-weight: normal;--search-result-item-padding: 1em 0;--search-result-keyword-background: var(--mark-background);--search-result-keyword-border-radius: var(--border-radius-s);--search-result-keyword-color: var(--mark-color);--search-result-keyword-font-weight: normal;--search-result-keyword-margin: 0 0.1em;--search-result-keyword-padding: 0.2em 0}:root{--zoomimage-overlay-background: rgba(0, 0, 0, 0.875)}:root{--sidebar-background: var(--base-background-color);--sidebar-border-width: 0;--sidebar-padding: 0 25px;--sidebar-transition-duration: var(--duration-fast);--sidebar-width: 17rem;--sidebar-name-font-size: var(--font-size-l);--sidebar-name-font-weight: normal;--sidebar-name-margin: 1.5rem 0 0;--sidebar-name-text-align: center;--sidebar-nav-strong-border-color: var(--sidebar-border-color);--sidebar-nav-strong-color: var(--heading-color);--sidebar-nav-strong-font-weight: var(--strong-font-weight);--sidebar-nav-strong-margin: 1.5em 0 0.5em;--sidebar-nav-strong-padding: 0.25em 0;--sidebar-nav-indent: 1em;--sidebar-nav-margin: 1.5rem 0 0;--sidebar-nav-link-border-style: solid;--sidebar-nav-link-border-width: 0;--sidebar-nav-link-color: var(--base-color);--sidebar-nav-link-font-weight: normal;--sidebar-nav-link-padding: 0.25em 0;--sidebar-nav-link-text-decoration--active: underline;--sidebar-nav-link-text-decoration--hover: underline;--sidebar-nav-link-before-margin: 0 0.35em 0 0;--sidebar-nav-pagelink-transition: var(--sidebar-nav-link-transition);--sidebar-toggle-border-radius: var(--border-radius-s);--sidebar-toggle-border-style: solid;--sidebar-toggle-border-width: 0;--sidebar-toggle-height: 36px;--sidebar-toggle-icon-color: var(--base-color);--sidebar-toggle-icon-height: 10px;--sidebar-toggle-icon-stroke-width: 1px;--sidebar-toggle-icon-width: 16px;--sidebar-toggle-offset-left: 0;--sidebar-toggle-offset-top: calc(35px - (var(--sidebar-toggle-height) / 2));--sidebar-toggle-width: 44px}:root{--code-theme-background: #f3f3f3;--code-theme-comment: #6e8090;--code-theme-function: #dd4a68;--code-theme-keyword: #07a;--code-theme-operator: #a67f59;--code-theme-punctuation: #999;--code-theme-selector: #690;--code-theme-tag: #905;--code-theme-text: #333;--code-theme-variable: #e90}:root{--border-radius-s: 2px;--border-radius-m: 4px;--border-radius-l: 8px;--strong-font-weight: 600;--blockquote-border-color: var(--theme-color);--blockquote-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0;--blockquote-border-width: 0 0 0 4px;--code-inline-background: var(--mono-tint2);--code-theme-background: var(--mono-tint3);--heading-font-weight: var(--strong-font-weight);--heading-h1-font-weight: 400;--heading-h2-font-weight: 400;--heading-h2-border-color: var(--mono-tint2);--heading-h2-border-width: 0 0 1px 0;--heading-h2-margin: 2.5rem 0 1.5rem;--heading-h2-padding: 0 0 1rem 0;--kbd-border: 1px solid var(--mono-tint2);--notice-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0;--notice-border-width: 0 0 0 4px;--notice-padding: 1em 1.5em 1em 3em;--notice-before-border-radius: 100%;--notice-before-font-weight: bold;--notice-before-height: 1.5em;--notice-before-left: 0.75em;--notice-before-line-height: 1.5;--notice-before-margin: 0 0.25em 0 0;--notice-before-position: absolute;--notice-before-width: var(--notice-before-height);--notice-important-background: hsl(340, 60%, 96%);--notice-important-border-color: hsl(340, 90%, 45%);--notice-important-before-background: var(--notice-important-border-color) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3E%3Cpath d='M10 14C10 15.1 9.1 16 8 16 6.9 16 6 15.1 6 14 6 12.9 6.9 12 8 12 9.1 12 10 12.9 10 14Z'/%3E%3Cpath d='M10 1.6C10 1.2 9.8 0.9 9.6 0.7 9.2 0.3 8.6 0 8 0 7.4 0 6.8 0.2 6.5 0.6 6.2 0.9 6 1.2 6 1.6 6 1.7 6 1.8 6 1.9L6.8 9.6C6.9 9.9 7 10.1 7.2 10.2 7.4 10.4 7.7 10.5 8 10.5 8.3 10.5 8.6 10.4 8.8 10.3 9 10.1 9.1 9.9 9.2 9.6L10 1.9C10 1.8 10 1.7 10 1.6Z'/%3E%3C/svg%3E") center / 0.875em no-repeat;--notice-important-before-color: #fff;--notice-important-before-content: "";--notice-tip-background: hsl(204, 60%, 96%);--notice-tip-border-color: hsl(204, 90%, 45%);--notice-tip-before-background: var(--notice-tip-border-color) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3E%3Cpath d='M9.1 0C10.2 0 10.7 0.7 10.7 1.6 10.7 2.6 9.8 3.6 8.6 3.6 7.6 3.6 7 3 7 2 7 1.1 7.7 0 9.1 0Z'/%3E%3Cpath d='M5.8 16C5 16 4.4 15.5 5 13.2L5.9 9.1C6.1 8.5 6.1 8.2 5.9 8.2 5.7 8.2 4.6 8.6 3.9 9.1L3.5 8.4C5.6 6.6 7.9 5.6 8.9 5.6 9.8 5.6 9.9 6.6 9.5 8.2L8.4 12.5C8.2 13.2 8.3 13.5 8.5 13.5 8.7 13.5 9.6 13.2 10.4 12.5L10.9 13.2C8.9 15.2 6.7 16 5.8 16Z'/%3E%3C/svg%3E") center / 0.875em no-repeat;--notice-tip-before-color: #fff;--notice-tip-before-content: "";--table-cell-border-color: var(--mono-tint2);--table-cell-border-width: 1px 0;--cover-background-color: hsl(var(--theme-hue), 25%, 60%);--cover-background-image: radial-gradient(ellipse at center 115%, rgba(255, 255, 255, 0.9), transparent);--cover-blockquote-color: var(--strong-color);--cover-heading-color: #fff;--cover-heading-font-size-max: 56;--cover-heading-font-size-min: 34;--cover-heading-font-weight: 200;--navbar-root-color--active: var(--theme-color);--navbar-menu-border-radius: var(--border-radius-m);--navbar-menu-root-background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9.6' height='6' viewBox='0 0 9.6 6'%3E%3Cpath d='M1.5 1.5l3.3 3 3.3-3' stroke-width='1.5' stroke='rgb%28179, 179, 179%29' fill='none' stroke-linecap='square' stroke-linejoin='miter' vector-effect='non-scaling-stroke'/%3E%3C/svg%3E") right no-repeat;--navbar-menu-root-padding: 0 18px 0 0;--search-input-background-color: #fff;--search-input-background-image: url("data:image/svg+xml,%3Csvg height='20px' width='20px' viewBox='0 0 24 24' fill='none' stroke='rgba(0, 0, 0, 0.3)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10.5' cy='10.5' r='7.5' vector-effect='non-scaling-stroke'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='15.8' y2='15.8' vector-effect='non-scaling-stroke'%3E%3C/line%3E%3C/svg%3E");--search-input-background-position: 21px center;--search-input-border-color: var(--sidebar-border-color);--search-input-border-width: 1px 0;--search-input-margin: 0 -25px;--search-input-padding: 0.65em 1em 0.65em 50px;--search-input-placeholder-color: rgba(0, 0, 0, 0.4);--search-clear-icon-color1: rgba(0, 0, 0, 0.3);--search-result-heading-font-weight: var(--strong-font-weight);--search-result-item-border-color: var(--sidebar-border-color);--search-result-keyword-border-radius: var(--border-radius-s);--sidebar-background: var(--mono-tint3);--sidebar-border-color: var(--mono-tint2);--sidebar-border-width: 0 1px 0 0;--sidebar-name-color: var(--theme-color);--sidebar-name-font-weight: 300;--sidebar-nav-strong-border-width: 0 0 1px 0;--sidebar-nav-strong-font-size: smaller;--sidebar-nav-strong-margin: 2em -25px 0.75em 0;--sidebar-nav-strong-padding: 0.25em 0 0.75em 0;--sidebar-nav-strong-text-transform: uppercase;--sidebar-nav-link-border-color: transparent;--sidebar-nav-link-border-color--active: var(--theme-color);--sidebar-nav-link-border-width: 0 4px 0 0;--sidebar-nav-link-color--active: var(--theme-color);--sidebar-nav-link-margin: 0 -25px 0 0;--sidebar-nav-link-text-decoration: none;--sidebar-nav-link-text-decoration--active: none;--sidebar-nav-link-text-decoration--hover: underline;--sidebar-nav-pagelink-background: no-repeat 2px calc(50% - 2.5px) / 6px 5px linear-gradient(45deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4px), no-repeat 2px calc(50% + 2.5px) / 6px 5px linear-gradient(135deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4px);--sidebar-nav-pagelink-background--active: no-repeat 0px center / 5px 6px linear-gradient(225deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4.25px), no-repeat 5px center / 5px 6px linear-gradient(135deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4.25px);--sidebar-nav-pagelink-background--collapse: no-repeat 2px calc(50% - 2.5px) / 6px 5px linear-gradient(45deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4px), no-repeat 2px calc(50% + 2.5px) / 6px 5px linear-gradient(135deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4px);--sidebar-nav-pagelink-background--loaded: no-repeat 0px center / 5px 6px linear-gradient(225deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4.25px), no-repeat 5px center / 5px 6px linear-gradient(135deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4.25px);--sidebar-nav-pagelink-padding: 0.25em 0 0.25em 20px;--sidebar-nav-pagelink-transition: none;--sidebar-toggle-background: var(--sidebar-border-color);--sidebar-toggle-border-radius: 0 var(--border-radius-s) var(--border-radius-s) 0;--sidebar-toggle-width: 32px} + +/*# sourceMappingURL=theme-simple.css.map */ \ No newline at end of file diff --git a/docs/index.html b/docs/index.html index 9cb3ae05..ee971549 100644 --- a/docs/index.html +++ b/docs/index.html @@ -14,12 +14,12 @@ `)).firstElementChild),this._updateRender(),m(d,"ready")}}}function On(e){return class extends e{routes(){return this.config.routes||{}}matchVirtualRoute(e){const n=this.routes(),i=Object.keys(n);let t=()=>null;function o(){const a=i.shift();if(!a)return t(null);const c=function(e){const n=e.startsWith("^")?e:`^${e}`;return n.endsWith("$")?n:`${n}$`}(a),r=e.match(c);if(!r)return o();const s=n[a];if("string"==typeof s){return t(s)}if("function"==typeof s){const n=s,[i,a]=function(){let e=()=>null;return[function(n){e(n)},function(n){e=n}]}();if(a((e=>"string"==typeof e?t(e):!1===e?t(null):o())),n.length<=2){return i(n(e,r))}return n(e,r,i)}return o()}return{then(e){t=e,o()}}}}}const qn=document.currentScript;class Pn extends(function(e){return class extends e{#g(e,n,i,t,o,a){e=a?e:e.replace(/\/$/,""),(e=E(e))&&Ln(o.router.getFile(e+i)+n,!1,o.config.requestHeaders).then(t,(a=>this.#g(e,n,i,t,o)))}#p;#l=()=>this.#p&&this.#p.abort&&this.#p.abort();#v=(e,n)=>(this.#l(),this.#p=Ln(e,!0,n),this.#p);#h=(e,n)=>{const{notFoundPage:i,ext:t}=n,o="_404"+(t||".md");let a,c;switch(typeof i){case"boolean":c=o;break;case"string":c=i;break;case"object":a=Object.keys(i).sort(((e,n)=>n.length-e.length)).filter((n=>e.match(new RegExp("^"+n))))[0],c=a&&i[a]||o}return c};_loadSideAndNav(e,n,i,t){return()=>{if(!i)return t();this.#g(e,n,i,(e=>{this._renderSidebar(e),t()}),this,!0)}}_fetch(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:t;const{query:n}=this.route,{path:i}=this.route;if(a(i))history.replaceState(null,"","#"),this.router.normalize();else{const t=$(n,["id"]),{loadNavbar:o,requestHeaders:c,loadSidebar:r}=this.config,s=this.router.getFile(i);this.isRemoteUrl=a(s),this.isHTML=/\.html$/g.test(s);const u=(n,o,a)=>{this.route.response=a,this._renderMain(n,o,this._loadSideAndNav(i,t,r,e))},d=(n,o)=>{this.route.response=o,this._fetchFallbackPage(i,t,e)||this._fetch404(s,t,e)};this.isRemoteUrl?this.#v(s+t,c).then(u,d):this.matchVirtualRoute(i).then((e=>{"string"==typeof e?u(e):this.#v(s+t,c).then(u,d)})),o&&this.#g(i,t,o,(e=>this._renderNav(e)),this,!0)}}_fetchCover(){const{coverpage:e,requestHeaders:n}=this.config,i=this.route.query,t=E(this.route.path);if(e){let o=null;const a=this.route.path;if("string"==typeof e)"/"===a&&(o=e);else if(Array.isArray(e))o=e.indexOf(a)>-1&&"_coverpage";else{const n=e[a];o=!0===n?"_coverpage":n}const c=Boolean(o)&&this.config.onlyCover;return o?(o=this.router.getFile(t+o),this.coverIsHTML=/\.html$/g.test(o),Ln(o+$(i,["id"]),!1,n).then((e=>this._renderCover(e,c)))):this._renderCover(null,c),c}}$fetch(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:t,n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.onNavigate.bind(this);const i=()=>{this.callHook("doneEach"),e()};this._fetchCover()?i():this._fetch((()=>{n(),i()}))}_fetchFallbackPage(e,n){let i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t;const{requestHeaders:o,fallbackLanguages:a,loadSidebar:c}=this.config;if(!a)return!1;const r=e.split("/")[1];if(-1===a.indexOf(r))return!1;const s=this.router.getFile(e.replace(new RegExp(`^/${r}`),""));return this.#v(s+n,o).then(((t,o)=>this._renderMain(t,o,this._loadSideAndNav(e,n,c,i))),(t=>this._fetch404(e,n,i))),!0}_fetch404(e,n){let i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t;const{loadSidebar:o,requestHeaders:a,notFoundPage:c}=this.config,r=this._loadSideAndNav(e,n,o,i);if(c){const n=this.#h(e,this.config);return this.#v(this.router.getFile(n),a).then(((e,n)=>this._renderMain(e,n,r)),(e=>this._renderMain(null,{},r))),!0}return this._renderMain(null,{},r),!1}initFetch(){this.config,this.$fetch((e=>this.callHook("ready")))}}}(function(e){return class extends e{#_;#m;#b=u.title;initEvent(){const{topMargin:e}=this.config;e&&document.documentElement.style.setProperty("scroll-padding-top",`${e}px`),this.#k(),this.#w("#skip-to-content"),this.#y(".sidebar"),this.#x("button.sidebar-toggle"),this.#$()}#k(){const e=g("section.cover");if(!e)return void m(d,"add","sticky");new IntersectionObserver((e=>{const n=e[0].isIntersecting;m(d,n?"remove":"add","sticky")})).observe(e)}#A(){const e=p("#main :where(h1, h2, h3, h4, h5)"),n=new Set;this.#_?.disconnect(),this.#_=new IntersectionObserver((e=>{if(this.#m)return;for(const i of e){const e=i.isIntersecting?"add":"delete";n[e](i.target)}const i=n.size>1?Array.from(n).sort(((e,n)=>e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING?-1:1))[0]:n.values().next().value;if(i){const e=i.getAttribute("id"),n=this.router.toURL(this.router.getCurrentPath(),{id:e}),t=this.#S(n);t?.scrollIntoView({behavior:"instant",block:"nearest",inline:"nearest"})}}),{rootMargin:"0% 0% -50% 0%"}),e.forEach((e=>{this.#_.observe(e)}))}#$(){const{keyBindings:e}=this.config,n=["alt","ctrl","meta","shift"];e&&e.constructor===Object&&(Object.values(e||[]).forEach((e=>{const{bindings:i}=e;i&&(e.bindings=Array.isArray(i)?i:[i],e.bindings=e.bindings.map((e=>{const i=[[],[]];return"string"==typeof e&&(e=e.split("+")),e.forEach((e=>{const t=n.includes(e),o=i[t?0:1],a=e.trim().toLowerCase();o.push(a)})),i.forEach((e=>e.sort())),i.flat()})))})),_("keydown",(i=>{if(document.activeElement.matches("input, select, textarea"))return;Object.values(e||[]).filter((e=>{let{bindings:t}=e;return t&&t.some((e=>e.every((e=>n.includes(e)&&i[e+"Key"]||i.key===e||i.code.toLowerCase()===e||i.code.toLowerCase()===`key${e}`))))})).forEach((e=>{let{callback:n}=e;i.preventDefault(),n(i)}))})))}#y(e){(e="string"==typeof e?document.querySelector(e):e)&&_(e,"click",(e=>{let{target:n}=e;"A"===n.nodeName&&n.nextSibling&&n.nextSibling.classList&&n.nextSibling.classList.contains("app-sub-sidebar")&&m(n.parentNode,"collapse")}))}#x(e){if(!(e="string"==typeof e?document.querySelector(e):e))return;const n=()=>{d.classList.toggle("close");const n=c?d.classList.contains("close"):!d.classList.contains("close");e.setAttribute("aria-expanded",n)};_(e,"click",(e=>{e.stopPropagation(),n()})),c&&_(d,"click",(()=>d.classList.contains("close")&&n()))}#w(e){(e="string"==typeof e?document.querySelector(e):e)&&e.addEventListener("click",(e=>{e.preventDefault(),g("main")?.scrollIntoView({behavior:"smooth"}),this.#E()}))}onRender(){const e=this.router.toURL(this.router.getCurrentPath()),n=g(`.sidebar a[href='${e}']`)?.innerText;u.title=n||this.#b,this.#z(),this.#T(),this.#A()}onNavigate(e){const{auto2top:n,topMargin:i}=this.config,{query:t}=this.route;if(this.#S(),"history"!==e)if(t.id){const e=g(`.markdown-section :where(h1, h2, h3, h4, h5)[id="${t.id}"]`);e&&(this.#R(),e.scrollIntoView({behavior:"smooth",block:"start"}))}else"navigate"===e&&n&&(document.scrollingElement.scrollTop=i??0);(t.id||"navigate"===e)&&this.#E()}#E(){const e={preventScroll:!0,...arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}},{query:n}=this.route,i=n.id?g(`#${n.id}`):g("#main :where(h1, h2, h3, h4, h5, h6)")||g("#main");i?.focus(e)}#z(){const e=decodeURIComponent(this.router.toURL(this.route.path)),n=g("nav.app-nav");if(!n)return;const i=p(n,"a").sort(((e,n)=>n.href.length-e.href.length)).find((n=>e.includes(n.getAttribute("href"))||e.includes(decodeURI(n.getAttribute("href"))))),t=g(n,"li.active");return i&&i!==t&&(t?.classList.remove("active"),i.classList.add("active")),i}#S(e){e??=this.router.toURL(this.router.getCurrentPath());const n=g(".sidebar");if(!n)return;const i=g(n,"li.active"),t=g(n,`a[href="${e}"], a[href="${decodeURIComponent(e)}"]`)?.closest("li");return t&&t!==i&&(i?.classList.remove("active"),t.classList.add("active")),t}#T(e){e??=this.router.toURL(this.route.path);const n=g(".sidebar");if(!n)return;const i=e?.split("?")[0],t=g(n,"li[aria-current]"),o=g(n,`a[href="${i}"], a[href="${decodeURIComponent(i)}"]`)?.closest("li");return o&&o!==t&&(t?.removeAttribute("aria-current"),o.setAttribute("aria-current","page")),o}#R(){document.addEventListener("scroll",(()=>{if(this.#m=!0,"onscrollend"in window)document.addEventListener("scrollend",(()=>this.#m=!1),{once:!0});else{const e=()=>{clearTimeout(n),n=setTimeout((()=>{document.removeEventListener("scroll",e),this.#m=!1}),100)};let n;document.addEventListener("scroll",e,!1)}}),{once:!0})}}}(jn(On(function(e){return class extends e{route={};updateRender(){this.router.normalize(),this.route=this.router.parse(),d.setAttribute("data-page",this.route.file)}initRouter(){const e=this.config;let n;n="history"===(e.routerMode||"hash")?new q(e):new O(e),this.router=n,this.updateRender(),P=this.route,n.onchange((e=>{this.updateRender(),this._updateRender(),P.path!==this.route.path?(this.$fetch(t,this.onNavigate.bind(this,e.source)),P=this.route):this.onNavigate(e.source)}))}}}(function(e){return class extends e{_hooks={};_lifecycle={};initLifecycle(){["init","mounted","beforeEach","afterEach","doneEach","ready"].forEach((e=>{const n=this._hooks[e]=[];this._lifecycle[e]=e=>n.push(e)}))}callHook(e,n){let i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:t;const o=this._hooks[e],a=this.config.catchPluginErrors,c=function(e){const t=o[e];if(e>=o.length)i(n);else if("function"==typeof t){const i="Docsify plugin error";if(2===t.length)try{t(n,(i=>{n=i,c(e+1)}))}catch(n){if(!a)throw n;console.error(i,n),c(e+1)}else try{const i=t(n);n=void 0===i?n:i,c(e+1)}catch(n){if(!a)throw n;console.error(i,n),c(e+1)}}else c(e+1)};c(0)}}}(Object))))))){config=function(e){const t=Object.assign({auto2top:!1,autoHeader:!1,basePath:"",catchPluginErrors:!0,cornerExternalLinkTarget:"_blank",coverpage:"",el:"#app",executeScript:null,ext:".md",externalLinkRel:"noopener",externalLinkTarget:"_blank",formatUpdated:"",ga:"",homepage:"README.md",loadNavbar:null,loadSidebar:null,maxLevel:6,mergeNavbar:!1,name:"",nameLink:window.location.pathname,nativeEmoji:!1,noCompileLinks:[],noEmoji:!1,notFoundPage:!1,plugins:[],relativePath:!1,repo:"",routes:{},routerMode:"hash",subMaxLevel:0,topMargin:0,__themeColor:"",get themeColor(){return this.__themeColor},set themeColor(e){e&&(this.__themeColor=e,console.warn(Sn("\n $docsify.themeColor is deprecated. Use a --theme-color property in your style sheet. Example:\n \n ").trim()))}},"function"==typeof window.$docsify?window.$docsify(e):window.$docsify);!1!==t.keyBindings&&(t.keyBindings=Object.assign({toggleSidebar:{bindings:["\\"],callback(e){const n=document.querySelector(".sidebar-toggle");n&&(n.click(),n.focus())}}},t.keyBindings));const o=qn||Array.from(document.getElementsByTagName("script")).filter((e=>/docsify\./.test(e.src)))[0];if(o)for(const e of Object.keys(t)){const a=o.getAttribute("data-"+n(e));i(a)&&(t[e]=""===a||a)}return!0===t.loadSidebar&&(t.loadSidebar="_sidebar"+t.ext),!0===t.loadNavbar&&(t.loadNavbar="_navbar"+t.ext),!0===t.coverpage&&(t.coverpage="_coverpage"+t.ext),!0===t.repo&&(t.repo=""),!0===t.name&&(t.name=""),window.$docsify=t,t}(this);constructor(){super(),this.initLifecycle(),this.initPlugin(),this.callHook("init"),this.initRouter(),this.initRender(),this.initEvent(),this.initFetch(),this.callHook("mounted")}initPlugin(){this.config.plugins.forEach((e=>{try{o(e)&&e(this._lifecycle,this)}catch(e){if(!this.config.catchPluginErrors)throw e;{const n="Docsify plugin error";console.error(n,e)}}}))}}var Mn=Object.freeze({__proto__:null,cached:e,cleanPath:z,getParentPath:E,getPath:L,hyphenate:n,inBrowser:!0,isAbsolutePath:A,isExternal:a,isFn:o,isMobile:c,isPrimitive:i,noop:t,parseQuery:x,removeParams:S,replaceSlug:F,resolvePath:T,stringifyQuery:$});window.Docsify={util:Mn,dom:k,get:Ln,slugify:nn,version:"4.13.0"},window.DocsifyCompiler=gn,window.marked=We,window.Prism=un,b((()=>new Pn))}(); +//# sourceMappingURL=docsify.min.js.map diff --git a/docs/js/gtag.min.js b/docs/js/gtag.min.js new file mode 100644 index 00000000..f66d1cac --- /dev/null +++ b/docs/js/gtag.min.js @@ -0,0 +1,8 @@ +/*! + * Docsify Plugin: gtag v4.13.0 + * https://docsify.js.org + * (c) 2017-2024 + * MIT license + */ +!function(){"use strict";function o(o){!function(o){const n=document.createElement("script");n.async=!0,n.src="https://www.googletagmanager.com/gtag/js?id="+o,document.body.appendChild(n)}(o),window.dataLayer=window.dataLayer||[],window.gtag=window.gtag||function(){window.dataLayer.push(arguments)},window.gtag("js",new Date),window.gtag("config",o)}function n(n){Array.isArray(n)?(o(n[0]),n.forEach(((o,n)=>{n>0&&function(o){window.gtag("config",o)}(o)}))):o(n)}function t(){window.gtag||n($docsify.gtag),window.gtag("event","page_view",{page_title:document.title,page_location:location.href,page_path:location.pathname})}window.$docsify=window.$docsify||{},$docsify.plugins=[function(o){$docsify.gtag?o.beforeEach(t):console.error("[Docsify] gtag is required.")},...$docsify.plugins||[]]}(); +//# sourceMappingURL=gtag.min.js.map diff --git a/docs/js/prism-yaml.min.js b/docs/js/prism-yaml.min.js new file mode 100644 index 00000000..5cd16d3d --- /dev/null +++ b/docs/js/prism-yaml.min.js @@ -0,0 +1 @@ +!function(e){var n=/[*&][^\s[\]{},]+/,r=/!(?:<[\w\-%#;/?:@&=+$,.!~*'()[\]]+>|(?:[a-zA-Z\d-]*!)?[\w\-%#;/?:@&=+$.~*'()]+)?/,t="(?:"+r.source+"(?:[ \t]+"+n.source+")?|"+n.source+"(?:[ \t]+"+r.source+")?)",a="(?:[^\\s\\x00-\\x08\\x0e-\\x1f!\"#%&'*,\\-:>?@[\\]`{|}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]|[?:-])(?:[ \t]*(?:(?![#:])|:))*".replace(//g,(function(){return"[^\\s\\x00-\\x08\\x0e-\\x1f,[\\]{}\\x7f-\\x84\\x86-\\x9f\\ud800-\\udfff\\ufffe\\uffff]"})),d="\"(?:[^\"\\\\\r\n]|\\\\.)*\"|'(?:[^'\\\\\r\n]|\\\\.)*'";function o(e,n){n=(n||"").replace(/m/g,"")+"m";var r="([:\\-,[{]\\s*(?:\\s<>[ \t]+)?)(?:<>)(?=[ \t]*(?:$|,|\\]|\\}|(?:[\r\n]\\s*)?#))".replace(/<>/g,(function(){return t})).replace(/<>/g,(function(){return e}));return RegExp(r,n)}e.languages.yaml={scalar:{pattern:RegExp("([\\-:]\\s*(?:\\s<>[ \t]+)?[|>])[ \t]*(?:((?:\r?\n|\r)[ \t]+)\\S[^\r\n]*(?:\\2[^\r\n]+)*)".replace(/<>/g,(function(){return t}))),lookbehind:!0,alias:"string"},comment:/#.*/,key:{pattern:RegExp("((?:^|[:\\-,[{\r\n?])[ \t]*(?:<>[ \t]+)?)<>(?=\\s*:\\s)".replace(/<>/g,(function(){return t})).replace(/<>/g,(function(){return"(?:"+a+"|"+d+")"}))),lookbehind:!0,greedy:!0,alias:"atrule"},directive:{pattern:/(^[ \t]*)%.+/m,lookbehind:!0,alias:"important"},datetime:{pattern:o("\\d{4}-\\d\\d?-\\d\\d?(?:[tT]|[ \t]+)\\d\\d?:\\d{2}:\\d{2}(?:\\.\\d*)?(?:[ \t]*(?:Z|[-+]\\d\\d?(?::\\d{2})?))?|\\d{4}-\\d{2}-\\d{2}|\\d\\d?:\\d{2}(?::\\d{2}(?:\\.\\d*)?)?"),lookbehind:!0,alias:"number"},boolean:{pattern:o("false|true","i"),lookbehind:!0,alias:"important"},null:{pattern:o("null|~","i"),lookbehind:!0,alias:"important"},string:{pattern:o(d),lookbehind:!0,greedy:!0},number:{pattern:o("[+-]?(?:0x[\\da-f]+|0o[0-7]+|(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?|\\.inf|\\.nan)","i"),lookbehind:!0},tag:r,important:n,punctuation:/---|[:[\]{}\-,|>?]|\.\.\./},e.languages.yml=e.languages.yaml}(Prism); \ No newline at end of file diff --git a/docs/js/search.js b/docs/js/search.js new file mode 100644 index 00000000..003bc4c3 --- /dev/null +++ b/docs/js/search.js @@ -0,0 +1,540 @@ +(function () { + /** + * Converts a colon formatted string to a object with properties. + * + * This is process a provided string and look for any tokens in the format + * of `:name[=value]` and then convert it to a object and return. + * An example of this is ':include :type=code :fragment=demo' is taken and + * then converted to: + * + * ``` + * { + * include: '', + * type: 'code', + * fragment: 'demo' + * } + * ``` + * + * @param {string} str The string to parse. + * + * @return {object} The original string and parsed object, { str, config }. + */ + function getAndRemoveConfig(str) { + if ( str === void 0 ) str = ''; + + var config = {}; + + if (str) { + str = str + .replace(/^('|")/, '') + .replace(/('|")$/, '') + .replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g, function (m, key, value) { + if (key.indexOf(':') === -1) { + config[key] = (value && value.replace(/"/g, '')) || true; + return ''; + } + + return m; + }) + .trim(); + } + + return { str: str, config: config }; + } + + function removeDocsifyIgnoreTag(str) { + return str + .replace(//, '') + .replace(/{docsify-ignore}/, '') + .replace(//, '') + .replace(/{docsify-ignore-all}/, '') + .trim(); + } + + /* eslint-disable no-unused-vars */ + + var INDEXS = {}; + + var LOCAL_STORAGE = { + EXPIRE_KEY: 'docsify.search.expires', + INDEX_KEY: 'docsify.search.index', + }; + + function resolveExpireKey(namespace) { + return namespace + ? ((LOCAL_STORAGE.EXPIRE_KEY) + "/" + namespace) + : LOCAL_STORAGE.EXPIRE_KEY; + } + + function resolveIndexKey(namespace) { + return namespace + ? ((LOCAL_STORAGE.INDEX_KEY) + "/" + namespace) + : LOCAL_STORAGE.INDEX_KEY; + } + + function escapeHtml(string) { + var entityMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''', + }; + + return String(string).replace(/[&<>"']/g, function (s) { return entityMap[s]; }); + } + + function getAllPaths(router) { + var paths = []; + + Docsify.dom + .findAll('.sidebar-nav a:not(.section-link):not([data-nosearch])') + .forEach(function (node) { + var href = node.href; + var originHref = node.getAttribute('href'); + var path = router.parse(href).path; + + if ( + path && + paths.indexOf(path) === -1 && + !Docsify.util.isAbsolutePath(originHref) + ) { + paths.push(path); + } + }); + + return paths; + } + + function getTableData(token) { + if (!token.text && token.type === 'table') { + token.cells.unshift(token.header); + token.text = token.cells + .map(function (rows) { + return rows.join(' | '); + }) + .join(' |\n '); + } + return token.text; + } + + function getListData(token) { + if (!token.text && token.type === 'list') { + token.text = token.raw; + } + return token.text; + } + + function saveData(maxAge, expireKey, indexKey) { + localStorage.setItem(expireKey, Date.now() + maxAge); + localStorage.setItem(indexKey, JSON.stringify(INDEXS)); + } + + function genIndex(path, content, router, depth) { + if ( content === void 0 ) content = ''; + + var tokens = window.marked.lexer(content); + var slugify = window.Docsify.slugify; + var index = {}; + var slug; + var title = ''; + + tokens.forEach(function (token, tokenIndex) { + if (token.type === 'heading' && token.depth <= depth) { + var ref = getAndRemoveConfig(token.text); + var str = ref.str; + var config = ref.config; + + var text = removeDocsifyIgnoreTag(token.text); + + if (config.id) { + slug = router.toURL(path, { id: slugify(config.id) }); + } else { + slug = router.toURL(path, { id: slugify(escapeHtml(text)) }); + } + + if (str) { + title = removeDocsifyIgnoreTag(str); + } + + index[slug] = { slug: slug, title: title, body: '' }; + } else { + if (tokenIndex === 0) { + slug = router.toURL(path); + index[slug] = { + slug: slug, + title: path !== '/' ? path.slice(1) : 'Home Page', + body: token.text || '', + }; + } + + if (!slug) { + return; + } + + if (!index[slug]) { + index[slug] = { slug: slug, title: '', body: '' }; + } else if (index[slug].body) { + token.text = getTableData(token); + token.text = getListData(token); + + index[slug].body += '\n' + (token.text || ''); + } else { + token.text = getTableData(token); + token.text = getListData(token); + + index[slug].body = token.text || ''; + } + } + }); + slugify.clear(); + return index; + } + + function ignoreDiacriticalMarks(keyword) { + if (keyword && keyword.normalize) { + return keyword.normalize('NFD').replace(/[\u0300-\u036f]/g, ''); + } + return keyword; + } + + /** + * @param {String} query Search query + * @returns {Array} Array of results + */ + function search(query) { + var matchingResults = []; + var data = []; + Object.keys(INDEXS).forEach(function (key) { + data = data.concat(Object.keys(INDEXS[key]).map(function (page) { return INDEXS[key][page]; })); + }); + + query = query.trim(); + var keywords = query.split(/[\s\-,\\/]+/); + if (keywords.length !== 1) { + keywords = [].concat(query, keywords); + } + + var loop = function ( i ) { + var post = data[i]; + var matchesScore = 0; + var resultStr = ''; + var handlePostTitle = ''; + var handlePostContent = ''; + var postTitle = post.title && post.title.trim(); + var postContent = post.body && post.body.trim(); + var postUrl = post.slug || ''; + + if (postTitle) { + keywords.forEach(function (keyword) { + // From https://github.com/sindresorhus/escape-string-regexp + var regEx = new RegExp( + escapeHtml(ignoreDiacriticalMarks(keyword)).replace( + /[|\\{}()[\]^$+*?.]/g, + '\\$&' + ), + 'gi' + ); + var indexTitle = -1; + var indexContent = -1; + handlePostTitle = postTitle + ? escapeHtml(ignoreDiacriticalMarks(postTitle)) + : postTitle; + handlePostContent = postContent + ? escapeHtml(ignoreDiacriticalMarks(postContent)) + : postContent; + + indexTitle = postTitle ? handlePostTitle.search(regEx) : -1; + indexContent = postContent ? handlePostContent.search(regEx) : -1; + + if (indexTitle >= 0 || indexContent >= 0) { + matchesScore += indexTitle >= 0 ? 3 : indexContent >= 0 ? 2 : 0; + if (indexContent < 0) { + indexContent = 0; + } + + var start = 0; + var end = 0; + + start = indexContent < 11 ? 0 : indexContent - 10; + end = start === 0 ? 70 : indexContent + keyword.length + 60; + + if (postContent && end > postContent.length) { + end = postContent.length; + } + + var matchContent = + handlePostContent && + '...' + + handlePostContent + .substring(start, end) + .replace( + regEx, + function (word) { return ("" + word + ""); } + ) + + '...'; + + resultStr += matchContent; + } + }); + + if (matchesScore > 0) { + var matchingPost = { + title: handlePostTitle, + content: postContent ? resultStr : '', + url: postUrl, + score: matchesScore, + }; + + matchingResults.push(matchingPost); + } + } + }; + + for (var i = 0; i < data.length; i++) loop( i ); + + return matchingResults.sort(function (r1, r2) { return r2.score - r1.score; }); + } + + function init(config, vm) { + var isAuto = config.paths === 'auto'; + var paths = isAuto ? getAllPaths(vm.router) : config.paths; + + var namespaceSuffix = ''; + + // only in auto mode + if (paths.length && isAuto && config.pathNamespaces) { + var path = paths[0]; + + if (Array.isArray(config.pathNamespaces)) { + namespaceSuffix = + config.pathNamespaces.filter( + function (prefix) { return path.slice(0, prefix.length) === prefix; } + )[0] || namespaceSuffix; + } else if (config.pathNamespaces instanceof RegExp) { + var matches = path.match(config.pathNamespaces); + + if (matches) { + namespaceSuffix = matches[0]; + } + } + var isExistHome = paths.indexOf(namespaceSuffix + '/') === -1; + var isExistReadme = paths.indexOf(namespaceSuffix + '/README') === -1; + if (isExistHome && isExistReadme) { + paths.unshift(namespaceSuffix + '/'); + } + } else if (paths.indexOf('/') === -1 && paths.indexOf('/README') === -1) { + paths.unshift('/'); + } + + var expireKey = resolveExpireKey(config.namespace) + namespaceSuffix; + var indexKey = resolveIndexKey(config.namespace) + namespaceSuffix; + + var isExpired = localStorage.getItem(expireKey) < Date.now(); + + INDEXS = JSON.parse(localStorage.getItem(indexKey)); + + if (isExpired) { + INDEXS = {}; + } else if (!isAuto) { + return; + } + + var len = paths.length; + var count = 0; + + paths.forEach(function (path) { + if (INDEXS[path]) { + return count++; + } + + Docsify.get(vm.router.getFile(path), false, vm.config.requestHeaders).then( + function (result) { + INDEXS[path] = genIndex(path, result, vm.router, config.depth); + len === ++count && saveData(config.maxAge, expireKey, indexKey); + } + ); + }); + } + + /* eslint-disable no-unused-vars */ + + var NO_DATA_TEXT = ''; + var options; + + function style() { + var code = "\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0.6em 7px;\n font-size: inherit;\n border: 1px solid transparent;\n}\n\n.search input:focus {\n box-shadow: 0 0 5px var(--theme-color, #42b983);\n border: 1px solid var(--theme-color, #42b983);\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.search input::-ms-clear {\n display: none;\n height: 0;\n width: 0;\n}\n\n.search .clear-button {\n cursor: pointer;\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}"; + + Docsify.dom.style(code); + } + + function tpl(defaultValue) { + if ( defaultValue === void 0 ) defaultValue = ''; + + var html = "
      \n \n
      \n \n \n \n \n \n
      \n
      \n
      \n "; + var el = Docsify.dom.create('div', html); + var aside = Docsify.dom.find('aside'); + + Docsify.dom.toggleClass(el, 'search'); + Docsify.dom.before(aside, el); + } + + function doSearch(value) { + var $search = Docsify.dom.find('div.search'); + var $panel = Docsify.dom.find($search, '.results-panel'); + var $clearBtn = Docsify.dom.find($search, '.clear-button'); + var $sidebarNav = Docsify.dom.find('.sidebar-nav'); + var $appName = Docsify.dom.find('.app-name'); + + if (!value) { + $panel.classList.remove('show'); + $clearBtn.classList.remove('show'); + $panel.innerHTML = ''; + + if (options.hideOtherSidebarContent) { + $sidebarNav && $sidebarNav.classList.remove('hide'); + $appName && $appName.classList.remove('hide'); + } + + return; + } + + var matchs = search(value); + + var html = ''; + matchs.forEach(function (post) { + html += "
      "; + }); + + $panel.classList.add('show'); + $clearBtn.classList.add('show'); + $panel.innerHTML = html || ("

      " + NO_DATA_TEXT + "

      "); + if (options.hideOtherSidebarContent) { + $sidebarNav && $sidebarNav.classList.add('hide'); + $appName && $appName.classList.add('hide'); + } + } + + function bindEvents() { + var $search = Docsify.dom.find('div.search'); + var $input = Docsify.dom.find($search, 'input'); + var $inputWrap = Docsify.dom.find($search, '.input-wrap'); + + var timeId; + + /** + Prevent to Fold sidebar. + + When searching on the mobile end, + the sidebar is collapsed when you click the INPUT box, + making it impossible to search. + */ + Docsify.dom.on( + $search, + 'click', + function (e) { return ['A', 'H2', 'P', 'EM'].indexOf(e.target.tagName) === -1 && + e.stopPropagation(); } + ); + Docsify.dom.on($input, 'input', function (e) { + clearTimeout(timeId); + timeId = setTimeout(function (_) { return doSearch(e.target.value.trim()); }, 100); + }); + Docsify.dom.on($inputWrap, 'click', function (e) { + // Click input outside + if (e.target.tagName !== 'INPUT') { + $input.value = ''; + doSearch(); + } + }); + } + + function updatePlaceholder(text, path) { + var $input = Docsify.dom.getNode('.search input[type="search"]'); + + if (!$input) { + return; + } + + if (typeof text === 'string') { + $input.placeholder = text; + } else { + var match = Object.keys(text).filter(function (key) { return path.indexOf(key) > -1; })[0]; + $input.placeholder = text[match]; + } + } + + function updateNoData(text, path) { + if (typeof text === 'string') { + NO_DATA_TEXT = text; + } else { + var match = Object.keys(text).filter(function (key) { return path.indexOf(key) > -1; })[0]; + NO_DATA_TEXT = text[match]; + } + } + + function updateOptions(opts) { + options = opts; + } + + function init$1(opts, vm) { + var keywords = vm.router.parse().query.s; + + updateOptions(opts); + style(); + tpl(keywords); + bindEvents(); + keywords && setTimeout(function (_) { return doSearch(keywords); }, 500); + } + + function update(opts, vm) { + updateOptions(opts); + updatePlaceholder(opts.placeholder, vm.route.path); + updateNoData(opts.noData, vm.route.path); + } + + /* eslint-disable no-unused-vars */ + + var CONFIG = { + placeholder: 'Type to search', + noData: 'No Results!', + paths: 'auto', + depth: 2, + maxAge: 86400000, // 1 day + hideOtherSidebarContent: false, + namespace: undefined, + pathNamespaces: undefined, + }; + + var install = function (hook, vm) { + var util = Docsify.util; + var opts = vm.config.search || CONFIG; + + if (Array.isArray(opts)) { + CONFIG.paths = opts; + } else if (typeof opts === 'object') { + CONFIG.paths = Array.isArray(opts.paths) ? opts.paths : 'auto'; + CONFIG.maxAge = util.isPrimitive(opts.maxAge) ? opts.maxAge : CONFIG.maxAge; + CONFIG.placeholder = opts.placeholder || CONFIG.placeholder; + CONFIG.noData = opts.noData || CONFIG.noData; + CONFIG.depth = opts.depth || CONFIG.depth; + CONFIG.hideOtherSidebarContent = + opts.hideOtherSidebarContent || CONFIG.hideOtherSidebarContent; + CONFIG.namespace = opts.namespace || CONFIG.namespace; + CONFIG.pathNamespaces = opts.pathNamespaces || CONFIG.pathNamespaces; + } + + var isAuto = CONFIG.paths === 'auto'; + + hook.mounted(function (_) { + init$1(CONFIG, vm); + !isAuto && init(CONFIG, vm); + }); + hook.doneEach(function (_) { + update(CONFIG, vm); + isAuto && init(CONFIG, vm); + }); + }; + + $docsify.plugins = [].concat(install, $docsify.plugins); + +}()); diff --git a/docs/js/zoom-image.min.js b/docs/js/zoom-image.min.js new file mode 100644 index 00000000..63153aef --- /dev/null +++ b/docs/js/zoom-image.min.js @@ -0,0 +1 @@ +!function(){function t(e){return"IMG"===e.tagName}function d(e){function t(){for(var e=arguments,t=arguments.length,o=Array(t),n=0;nu.scrollOffset&&setTimeout(a,150))}),window.addEventListener("resize",a);var f={open:i,close:a,toggle:o,update:function(){var e=0 Date: Mon, 10 Jun 2024 00:29:50 -0300 Subject: [PATCH 146/189] Bump prettier to v3 and format all files --- .eslintrc.cjs | 27 +- .github/dependabot.yml | 16 +- .github/release-drafter.yml | 46 +- .github/workflows/build.yml | 6 + .prettierignore | 1 + .prettierrc.cjs | 8 - .vscode/i18n-ally-custom-framework.yml | 2 - README.md | 28 +- docs/README.md | 10 +- docs/_sidebar.md | 14 +- docs/advanced-installation.md | 2 +- docs/configuration/README.md | 44 +- docs/configuration/_sidebar.md | 46 +- docs/configuration/actions/README.md | 12 +- docs/configuration/actions/_sidebar.md | 48 +- docs/configuration/actions/custom/README.md | 184 +- docs/configuration/actions/custom/_sidebar.md | 48 +- docs/configuration/actions/stock/_sidebar.md | 48 +- docs/configuration/automations.md | 10 +- docs/configuration/cameras/README.md | 217 +- docs/configuration/cameras/_sidebar.md | 48 +- docs/configuration/cameras/engine.md | 74 +- docs/configuration/cameras/live-provider.md | 80 +- docs/configuration/common/expanded-warning.md | 2 +- .../common/timeline-seek-info.md | 2 +- docs/configuration/conditions.md | 80 +- docs/configuration/dimensions.md | 29 +- docs/configuration/elements.md | 70 +- docs/configuration/image.md | 15 +- docs/configuration/live.md | 166 +- docs/configuration/media-gallery.md | 35 +- docs/configuration/media-viewer.md | 142 +- docs/configuration/menu.md | 88 +- docs/configuration/overrides.md | 89 +- docs/configuration/performance.md | 35 +- docs/configuration/profiles.md | 12 +- docs/configuration/timeline-pan-mode.md | 12 +- docs/configuration/timeline.md | 55 +- docs/configuration/view.md | 106 +- docs/css/theme-simple-dark.css | 2474 ++++++++++++++++- docs/css/theme-simple.css | 2376 +++++++++++++++- docs/developing.md | 13 +- docs/examples.md | 17 +- docs/images/README.md | 9 +- docs/index.html | 7 +- docs/screenshots.md | 64 +- docs/troubleshooting.md | 12 +- docs/usage/2-way-audio.md | 40 +- docs/usage/_sidebar.md | 22 +- docs/usage/casting.md | 16 +- docs/usage/keyboard-shortcuts.md | 22 +- docs/usage/url-actions.md | 68 +- hacs.json | 8 +- markdown-link-check.json | 2 +- package.json | 7 +- prettier.config.js | 16 + project.inlang/settings.json | 31 +- .../browse-media/engine-browse-media.ts | 4 +- src/camera-manager/frigate/engine-frigate.ts | 16 +- src/camera-manager/types.ts | 20 +- .../actions/actions/ptz-digital.ts | 12 +- src/card-controller/actions/actions/ptz.ts | 5 +- .../actions/actions/substream-off.ts | 2 +- src/card-controller/actions/types.ts | 4 +- src/card-controller/auto-update-manager.ts | 3 +- src/card-controller/card-element-manager.ts | 7 +- src/card-controller/hass-manager.ts | 2 +- src/card-controller/message-manager.ts | 7 +- src/card-controller/types.ts | 4 +- src/card.ts | 184 +- src/components-lib/media-filter-controller.ts | 8 +- src/components-lib/menu-button-controller.ts | 8 +- src/components-lib/ptz/ptz-controller.ts | 8 +- src/components/date-picker.ts | 2 +- src/components/gallery.ts | 8 +- src/components/live/live.ts | 72 +- src/components/message.ts | 10 +- src/components/thumbnail-carousel.ts | 52 +- src/components/thumbnail.ts | 26 +- src/components/timeline-core.ts | 24 +- src/components/views.ts | 12 +- src/config/keyboard-shortcuts.ts | 1 - src/config/management.ts | 4 +- src/config/profiles/index.ts | 8 +- src/config/types.ts | 20 +- src/editor.ts | 17 +- src/images/README.md | 8 +- src/localize/languages/ca.json | 2 +- src/localize/languages/en.json | 2 +- src/localize/languages/fr.json | 2 +- src/localize/languages/it.json | 2 +- src/localize/languages/pt-BR.json | 2 +- src/localize/languages/pt-PT.json | 2 +- src/patches/ha-camera-stream.ts | 2 +- src/patches/ha-hls-player.ts | 6 +- src/patches/ha-web-rtc-player.ts | 4 +- src/scss/button.scss | 74 +- src/scss/const.scss | 2 +- src/scss/drawer.scss | 9 +- src/scss/elements.scss | 2 +- src/scss/image.scss | 2 +- src/scss/key-assigner.scss | 2 +- src/scss/live-ha-components.scss | 7 +- src/scss/live-ha.scss | 2 +- src/scss/media-filter.scss | 2 +- src/scss/menu.scss | 2 +- src/scss/submenu.scss | 2 +- src/scss/thumbnail-feature-event.scss | 7 +- src/scss/thumbnail-feature-recording.scss | 5 +- src/scss/thumbnail.scss | 16 +- src/scss/timeline-core.scss | 4 +- src/scss/viewer-provider.scss | 2 +- src/scss/viewer.scss | 2 +- src/utils/get-state-obj.ts | 10 +- src/utils/ha/device-registry.ts | 2 +- src/utils/ha/update.ts | 6 +- src/utils/icons/README.md | 2 +- src/utils/icons/domain-icon.ts | 7 +- src/utils/icons/sensor-icon.ts | 5 +- src/utils/media-to-view.ts | 4 +- src/view/media-queries-classifier.ts | 4 +- src/view/media-queries-results.ts | 4 +- src/view/view-to-cameras.ts | 8 +- src/view/view.ts | 6 +- tests/camera-manager/manager.test.ts | 2 +- tests/camera-manager/utils/ptz.test.ts | 2 +- .../actions/actions-manager.test.ts | 12 +- .../actions/actions/default.test.ts | 17 +- .../actions/display-mode-select.test.ts | 19 +- .../actions/actions/ptz.test.ts | 40 +- .../actions/actions/sleep.test.ts | 2 +- .../camera-url-manager.test.ts | 8 +- .../fullscreen-manager.test.ts | 6 +- tests/config/management.test.ts | 1 - tests/utils/embla/test-utils.ts | 10 +- tests/utils/substream.test.ts | 5 +- tests/view/media.test.ts | 2 +- yarn.lock | 54 +- 138 files changed, 6445 insertions(+), 1678 deletions(-) create mode 100644 .prettierignore delete mode 100644 .prettierrc.cjs create mode 100644 prettier.config.js diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 15db0d4c..1f0d97d8 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -1,14 +1,15 @@ module.exports = { - parser: "@typescript-eslint/parser", // Specifies the ESLint parser - parserOptions: { - ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features - sourceType: "module" // Allows for the use of imports - }, - extends: [ - "plugin:@typescript-eslint/recommended" // Uses the recommended rules from the @typescript-eslint/eslint-plugin - ], - rules: { - // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs - // e.g. "@typescript-eslint/explicit-function-return-type": "off", - } -}; \ No newline at end of file + parser: '@typescript-eslint/parser', // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports + }, + extends: [ + 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin + 'prettier', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier + ], + rules: { + // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs + // e.g. "@typescript-eslint/explicit-function-return-type": "off", + }, +}; diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 8489abf2..738cdc55 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,8 +1,8 @@ -version: 2 - -updates: - - package-ecosystem: github-actions - directory: / - schedule: - interval: daily - target-branch: "dev" +version: 2 + +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: daily + target-branch: 'dev' diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index 85a42152..283421a0 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -1,29 +1,29 @@ --- categories: - - title: ":boom: Breaking Changes" - label: "breaking" - - title: ":rocket: Features" - label: "enhancement" - - title: ":fire: Removals and Deprecations" - label: "removal" - - title: ":bug: Fixes" - label: "bug" - - title: ":racehorse: Performance" - label: "performance" - - title: ":rotating_light: Testing" - label: "testing" - - title: ":construction_worker: Continuous Integration" - label: "ci" - - title: ":books: Documentation" - label: "documentation" - - title: ":hammer: Refactoring" - label: "refactoring" - - title: ":lipstick: Style" - label: "style" - - title: ":package: Dependencies" + - title: ':boom: Breaking Changes' + label: 'breaking' + - title: ':rocket: Features' + label: 'enhancement' + - title: ':fire: Removals and Deprecations' + label: 'removal' + - title: ':bug: Fixes' + label: 'bug' + - title: ':racehorse: Performance' + label: 'performance' + - title: ':rotating_light: Testing' + label: 'testing' + - title: ':construction_worker: Continuous Integration' + label: 'ci' + - title: ':books: Documentation' + label: 'documentation' + - title: ':hammer: Refactoring' + label: 'refactoring' + - title: ':lipstick: Style' + label: 'style' + - title: ':package: Dependencies' labels: - - "dependencies" - - "build" + - 'dependencies' + - 'build' template: | ## Changes diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2de9aaa8..7577876b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -25,6 +25,12 @@ jobs: - name: Install dependencies run: yarn install --immutable + - name: Lint + run: yarn run lint + + - name: Check formatting + run: yarn run format-check + - name: Test & Coverage run: yarn run coverage diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..b51ecd95 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +docs/js/ diff --git a/.prettierrc.cjs b/.prettierrc.cjs deleted file mode 100644 index 933e929f..00000000 --- a/.prettierrc.cjs +++ /dev/null @@ -1,8 +0,0 @@ -module.exports = { - semi: true, - trailingComma: 'all', - singleQuote: true, - printWidth: 89, - tabWidth: 2, - embeddedLanguageFormatting: 'auto', -}; diff --git a/.vscode/i18n-ally-custom-framework.yml b/.vscode/i18n-ally-custom-framework.yml index d7a1d8e3..4c691479 100644 --- a/.vscode/i18n-ally-custom-framework.yml +++ b/.vscode/i18n-ally-custom-framework.yml @@ -12,7 +12,6 @@ usageMatchRegex: # you can ignore it and use your own matching rules as well - "[^\\w\\d]localize\\(['\"`]({key})['\"`]" - # An array of strings containing refactor templates. # The "$1" will be replaced by the keypath specified. # Optional: uncomment the following two lines to use @@ -20,6 +19,5 @@ usageMatchRegex: # refactorTemplates: # - i18n.get("$1") - # If set to true, only enables this custom framework (will disable all built-in frameworks) monopoly: true diff --git a/README.md b/README.md index c4fab493..4e2060c6 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,8 @@ [![GitHub Release](https://img.shields.io/github/release/dermotduffy/frigate-hass-card.svg?style=flat-square)](https://github.com/dermotduffy/frigate-hass-card/releases) [![Build Status](https://img.shields.io/github/actions/workflow/status/dermotduffy/frigate-hass-card/build.yml?style=flat-square)](https://github.com/dermotduffy/frigate-hass-card/actions/workflows/build.yml) [![License](https://img.shields.io/github/license/dermotduffy/frigate-hass-card.svg?style=flat-square)](LICENSE) -[![HACS](https://img.shields.io/badge/HACS-default-orange.svg?style=flat-square)](https://hacs.xyz) -[![Sponsor](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86&style=flat-square)](https://github.com/sponsors/dermotduffy) +[![HACS](https://img.shields.io/badge/HACS-default-orange.svg?style=flat-square)](https://hacs.xyz) +[![Sponsor](https://img.shields.io/static/v1?label=Sponsor&message=%E2%9D%A4&logo=GitHub&color=%23fe8e86&style=flat-square)](https://github.com/sponsors/dermotduffy) Frigate Card @@ -19,16 +19,16 @@ A comprehensive camera card for Home Assistant. -* Live viewing of multiple cameras. -* Clips and snapshot browsing via mini-gallery. -* Automatic updating to continually show latest clip / snapshot. -* Support for filtering events by zone and label. -* Arbitrary entity access via menu (e.g. motion sensor access). -* Fullscreen mode. -* Grid or carousel/swipeable media, thumbnails and cameras. -* Direct media downloads. -* Lovelace visual editing. -* Full [Picture Elements](https://www.home-assistant.io/lovelace/picture-elements/) support. -* Theme friendly. +- Live viewing of multiple cameras. +- Clips and snapshot browsing via mini-gallery. +- Automatic updating to continually show latest clip / snapshot. +- Support for filtering events by zone and label. +- Arbitrary entity access via menu (e.g. motion sensor access). +- Fullscreen mode. +- Grid or carousel/swipeable media, thumbnails and cameras. +- Direct media downloads. +- Lovelace visual editing. +- Full [Picture Elements](https://www.home-assistant.io/lovelace/picture-elements/) support. +- Theme friendly. -See [full documentation](https://dermotduffy.github.io/frigate-hass-card). \ No newline at end of file +See [full documentation](https://dermotduffy.github.io/frigate-hass-card). diff --git a/docs/README.md b/docs/README.md index a6dc8d47..8fb8678d 100644 --- a/docs/README.md +++ b/docs/README.md @@ -18,12 +18,14 @@ See [Advanced Installation](advanced-installation.md) for other installation res ## Adding your card - - On a Home Assistant dashboard, choose: +- On a Home Assistant dashboard, choose: + ``` [Three dots menu] > Edit dashboard ``` - - Click `+ Add Card` shown on the bottom of the screen - - Choose `Custom: Frigate card` from the list + +- Click `+ Add Card` shown on the bottom of the screen +- Choose `Custom: Frigate card` from the list ## Initial configuration @@ -57,4 +59,4 @@ live: mode: grid ``` -See [Configuration](configuration/README.md) for full details on supported configuration options. \ No newline at end of file +See [Configuration](configuration/README.md) for full details on supported configuration options. diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 658fb3d9..d55acfdd 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -1,10 +1,10 @@ -* [Getting Started](README.md) -* [Configuration](configuration/README.md) -* [Examples](examples.md) -* [Screenshots](screenshots.md) -* [Troubleshooting](troubleshooting.md) -* [Usage](usage/README.md) +- [Getting Started](README.md) +- [Configuration](configuration/README.md) +- [Examples](examples.md) +- [Screenshots](screenshots.md) +- [Troubleshooting](troubleshooting.md) +- [Usage](usage/README.md) --- -* [Developing](developing.md) \ No newline at end of file +- [Developing](developing.md) diff --git a/docs/advanced-installation.md b/docs/advanced-installation.md index d9451941..d1946899 100644 --- a/docs/advanced-installation.md +++ b/docs/advanced-installation.md @@ -48,4 +48,4 @@ lovelace: ### Unreleased versions -You can install any unreleased version of the card by leveraging the GitHub Actions artifacts that are generated on every revision. See a [video walkthrough](https://user-images.githubusercontent.com/29582865/228320074-6a2607f5-c637-48d5-b833-a553f8df8f4f.mp4) installing the latest revision of the `release-4.1.0` branch. \ No newline at end of file +You can install any unreleased version of the card by leveraging the GitHub Actions artifacts that are generated on every revision. See a [video walkthrough](https://user-images.githubusercontent.com/29582865/228320074-6a2607f5-c637-48d5-b833-a553f8df8f4f.mp4) installing the latest revision of the `release-4.1.0` branch. diff --git a/docs/configuration/README.md b/docs/configuration/README.md index 5cc275de..b7ac589d 100644 --- a/docs/configuration/README.md +++ b/docs/configuration/README.md @@ -16,28 +16,28 @@ cameras: Only the `cameras` option is required, all other parameters are optional. -| Option | Description | -| - | - | -| [`automations`](automations.md) | Take action when conditions are met. | -| [`cameras`](cameras/README.md) | Configures the cameras to be used in the card. At least one camera must be specified. | -| [`cameras_global`](cameras/README.md) | Global defaults that apply to all cameras from the `cameras` section. | -| `card_id` | An optional ID to uniquely identify this card. For use when actions are being sent to card(s) via [URL actions](../usage/url-actions.md). Must exclusively consist of these characters: `[a-zA-Z0-9_]`.| -| [`dimensions`](dimensions.md) | Configures the overall card dimensions. | -| [`elements`](elements.md) | Add custom elements to the card. | -| [`image`](image.md) | Configures the `image` view. | -| [`live`](live.md) | Configures the `live` view. | -| [`media_gallery`](media-gallery.md) | Configures the media gallery. | -| [`media_viewer`](media-viewer.md) | Configures the media viewer. | -| [`menu`](menu.md) | Configures the card menu. | -| [`overrides`](overrides.md) | Override card configuration when conditions are met. | -| [`performance`](performance.md) | Configures the card performance. | -| [`profiles`](profiles.md) | Apply pre-configured sets of defaults to ease card configuration. | -| [`timeline`](timeline.md) | Configures the `timeline` view. | -| [`view`](view.md) | Configures the default view and behavior of the card. | +| Option | Description | +| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| [`automations`](automations.md) | Take action when conditions are met. | +| [`cameras`](cameras/README.md) | Configures the cameras to be used in the card. At least one camera must be specified. | +| [`cameras_global`](cameras/README.md) | Global defaults that apply to all cameras from the `cameras` section. | +| `card_id` | An optional ID to uniquely identify this card. For use when actions are being sent to card(s) via [URL actions](../usage/url-actions.md). Must exclusively consist of these characters: `[a-zA-Z0-9_]`. | +| [`dimensions`](dimensions.md) | Configures the overall card dimensions. | +| [`elements`](elements.md) | Add custom elements to the card. | +| [`image`](image.md) | Configures the `image` view. | +| [`live`](live.md) | Configures the `live` view. | +| [`media_gallery`](media-gallery.md) | Configures the media gallery. | +| [`media_viewer`](media-viewer.md) | Configures the media viewer. | +| [`menu`](menu.md) | Configures the card menu. | +| [`overrides`](overrides.md) | Override card configuration when conditions are met. | +| [`performance`](performance.md) | Configures the card performance. | +| [`profiles`](profiles.md) | Apply pre-configured sets of defaults to ease card configuration. | +| [`timeline`](timeline.md) | Configures the `timeline` view. | +| [`view`](view.md) | Configures the default view and behavior of the card. | #### Common configuration blocks -| Option | Description | -| - | - | -| [`actions`](actions/README.md) | Configure actions. | -| [`conditions`](conditions.md) | Configure conditions. | +| Option | Description | +| ------------------------------ | --------------------- | +| [`actions`](actions/README.md) | Configure actions. | +| [`conditions`](conditions.md) | Configure conditions. | diff --git a/docs/configuration/_sidebar.md b/docs/configuration/_sidebar.md index 8bbd9965..0bc10e8c 100644 --- a/docs/configuration/_sidebar.md +++ b/docs/configuration/_sidebar.md @@ -1,26 +1,26 @@ -* [Getting Started](../README.md) -* [Configuration](README.md) - * [`actions`](actions/README.md) - * [`automations`](automations.md) - * [`cameras`](cameras/README.md) - * [`conditions`](conditions.md) - * [`dimensions`](dimensions.md) - * [`elements`](elements.md) - * [`image`](image.md) - * [`live`](live.md) - * [`media_gallery`](media-gallery.md) - * [`media_viewer`](media-viewer.md) - * [`menu`](menu.md) - * [`overrides`](overrides.md) - * [`performance`](performance.md) - * [`profiles`](profiles.md) - * [`timeline`](timeline.md) - * [`view`](view.md) -* [Examples](../examples.md) -* [Screenshots](../screenshots.md) -* [Troubleshooting](../troubleshooting.md) -* [Usage](../usage/README.md) +- [Getting Started](../README.md) +- [Configuration](README.md) + - [`actions`](actions/README.md) + - [`automations`](automations.md) + - [`cameras`](cameras/README.md) + - [`conditions`](conditions.md) + - [`dimensions`](dimensions.md) + - [`elements`](elements.md) + - [`image`](image.md) + - [`live`](live.md) + - [`media_gallery`](media-gallery.md) + - [`media_viewer`](media-viewer.md) + - [`menu`](menu.md) + - [`overrides`](overrides.md) + - [`performance`](performance.md) + - [`profiles`](profiles.md) + - [`timeline`](timeline.md) + - [`view`](view.md) +- [Examples](../examples.md) +- [Screenshots](../screenshots.md) +- [Troubleshooting](../troubleshooting.md) +- [Usage](../usage/README.md) --- -* [Developing](../developing.md) \ No newline at end of file +- [Developing](../developing.md) diff --git a/docs/configuration/actions/README.md b/docs/configuration/actions/README.md index 1853b004..0990d952 100644 --- a/docs/configuration/actions/README.md +++ b/docs/configuration/actions/README.md @@ -43,12 +43,12 @@ experiences a `tap`, `double_tap`, `hold`, `start_tap` or `end_tap` event. Alternatively they can be configured on a per group-of-views basis, e.g. only when `live` view is tapped. -| Configuration path | Views to which it refers | -| ----------------------- | ---------------------------------- | -| `image.actions` | `image` | -| `live.actions` | `live` | -| `media_gallery.actions` | `clips`, `snapshots`, `recordings` | -| `media_viewer.actions` | `clip`, `snapshot`, `recording` | +| Configuration path | Views to which it refers | +| ----------------------- | -------------------------------------- | +| `image.actions` | `image` | +| `live.actions` | `live` | +| `media_gallery.actions` | `clips`, `snapshots`, `recordings` | +| `media_viewer.actions` | `clip`, `snapshot`, `recording` | | `view.actions` | All except `timeline` and `diagnostic` | If an action is configured for both the whole card (`view.actions`) and a more diff --git a/docs/configuration/actions/_sidebar.md b/docs/configuration/actions/_sidebar.md index 04802078..b9258a61 100644 --- a/docs/configuration/actions/_sidebar.md +++ b/docs/configuration/actions/_sidebar.md @@ -1,27 +1,27 @@ -* [Getting Started](../../README.md) -* [Configuration](../README.md) - * [`actions`](README.md) - * [Custom Actions](./custom/README.md) - * [Stock Actions](./stock/README.md) - * [`automations`](../automations.md) - * [`cameras`](../cameras/README.md) - * [`conditions`](../conditions.md) - * [`dimensions`](../dimensions.md) - * [`elements`](../elements.md) - * [`image`](../image.md) - * [`live`](../live.md) - * [`media_gallery`](../media-gallery.md) - * [`media_viewer`](../media-viewer.md) - * [`menu`](../menu.md) - * [`overrides`](../overrides.md) - * [`performance`](../performance.md) - * [`profiles`](../profiles.md) - * [`timeline`](../timeline.md) - * [`view`](../view.md) -* [Screenshots](../../screenshots.md) -* [Troubleshooting](../../troubleshooting.md) -* [Usage](../../usage/README.md) +- [Getting Started](../../README.md) +- [Configuration](../README.md) + - [`actions`](README.md) + - [Custom Actions](./custom/README.md) + - [Stock Actions](./stock/README.md) + - [`automations`](../automations.md) + - [`cameras`](../cameras/README.md) + - [`conditions`](../conditions.md) + - [`dimensions`](../dimensions.md) + - [`elements`](../elements.md) + - [`image`](../image.md) + - [`live`](../live.md) + - [`media_gallery`](../media-gallery.md) + - [`media_viewer`](../media-viewer.md) + - [`menu`](../menu.md) + - [`overrides`](../overrides.md) + - [`performance`](../performance.md) + - [`profiles`](../profiles.md) + - [`timeline`](../timeline.md) + - [`view`](../view.md) +- [Screenshots](../../screenshots.md) +- [Troubleshooting](../../troubleshooting.md) +- [Usage](../../usage/README.md) --- -* [Developing](../../developing.md) \ No newline at end of file +- [Developing](../../developing.md) diff --git a/docs/configuration/actions/custom/README.md b/docs/configuration/actions/custom/README.md index 66f53159..ba8a7c86 100644 --- a/docs/configuration/actions/custom/README.md +++ b/docs/configuration/actions/custom/README.md @@ -7,9 +7,9 @@ action: custom:frigate-card-action [...] ``` -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | +| Parameter | Description | +| --------------------- | ------------------------------------------- | +| `action` | Must be `custom:frigate-card-action`. | | `frigate_card_action` | A supported Frigate Card action. See below. | ## `camera_select` @@ -22,15 +22,15 @@ frigate_card_action: camera_select [...] ``` -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `camera_select`. | -| `camera` | The [camera ID](../../cameras/README.md?id=cameras) of the camera to select. | -| `triggered` | If `true` instead of `camera` being specified then a triggered camera (if any) is selected instead. | +| Parameter | Description | +| --------------------- | --------------------------------------------------------------------------------------------------- | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `camera_select`. | +| `camera` | The [camera ID](../../cameras/README.md?id=cameras) of the camera to select. | +| `triggered` | If `true` instead of `camera` being specified then a triggered camera (if any) is selected instead. | This action will respect the value of the `view.camera_select` to choose the appropriate view on the new camera. See [`view` configuration](../../view.md). - + ## `camera_ui` Download the displayed media. @@ -52,13 +52,13 @@ frigate_card_action: change_zoom [...] ``` -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `change_zoom`. | -| `target_id` | The [camera ID](../../cameras/README.md?id=cameras) or a media ID (e.g. `frigate` event ID) to change zoom/pam settings for. | -| `zoom` | Optional parameter that controls how much to zoom-in. See the [camera zoom parameter](../../cameras/README.md?id=layout-configuration). | -| `pan` | Optional parameter that controls how much to pan-x/y. See the [camera pan parameter](../../cameras/README.md?id=layout-configuration). | +| Parameter | Description | +| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `change_zoom`. | +| `target_id` | The [camera ID](../../cameras/README.md?id=cameras) or a media ID (e.g. `frigate` event ID) to change zoom/pam settings for. | +| `zoom` | Optional parameter that controls how much to zoom-in. See the [camera zoom parameter](../../cameras/README.md?id=layout-configuration). | +| `pan` | Optional parameter that controls how much to pan-x/y. See the [camera pan parameter](../../cameras/README.md?id=layout-configuration). | ?> If neither `zoom` nor `pan` are specified the camera will return to its default zoom and pan settings. @@ -110,11 +110,11 @@ frigate_card_action: display_mode_select [...] ``` -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `display_mode_select`. | -| `display_mode` | `single` to show a single camera at a time in a carousel, or `grid` to show a grid of cameras. | +| Parameter | Description | +| --------------------- | ---------------------------------------------------------------------------------------------- | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `display_mode_select`. | +| `display_mode` | `single` to show a single camera at a time in a carousel, or `grid` to show a grid of cameras. | ## `download` @@ -170,10 +170,10 @@ action: custom:frigate-card-action frigate_card_action: live_substream_on ``` -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `live_substream_on`. | +| Parameter | Description | +| --------------------- | ------------------------------------- | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `live_substream_on`. | ## `live_substream_on` @@ -184,12 +184,10 @@ action: custom:frigate-card-action frigate_card_action: live_substream_on ``` -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `live_substream_on`. | - - +| Parameter | Description | +| --------------------- | ------------------------------------- | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `live_substream_on`. | ## `live_substream_select` @@ -201,11 +199,11 @@ frigate_card_action: live_substream_select [...] ``` -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `live_substream_select`. | -| `camera` | The [camera ID](../../cameras/README.md?id=cameras) of the substream to select. | +| Parameter | Description | +| --------------------- | ------------------------------------------------------------------------------- | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `live_substream_select`. | +| `camera` | The [camera ID](../../cameras/README.md?id=cameras) of the substream to select. | ## `log` @@ -217,16 +215,16 @@ frigate_card_action: log [...] ``` -| Parameter | Default | Description | -| - | - | - | -| `action` | | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | | Must be `log`. | -| `message` | | The message to log. | -| `level` | `info` | The console logging level to use. One of `['debug', 'info', 'warn', 'error']`. | +| Parameter | Default | Description | +| --------------------- | ------- | ------------------------------------------------------------------------------ | +| `action` | | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | | Must be `log`. | +| `message` | | The message to log. | +| `level` | `info` | The console logging level to use. One of `['debug', 'info', 'warn', 'error']`. | ## `media_player` -Perform a media player action. +Perform a media player action. ```yaml action: custom:frigate-card-action @@ -234,12 +232,12 @@ frigate_card_action: media_player [...] ``` -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `media_player`. | -| `media_player` | The entity ID of the media_player on which to perform the action. | -| `media_player_action` | Either `play` or `stop` to play or stop the media in question. | +| Parameter | Description | +| --------------------- | ----------------------------------------------------------------- | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `media_player`. | +| `media_player` | The entity ID of the media_player on which to perform the action. | +| `media_player_action` | Either `play` or `stop` to play or stop the media in question. | ## `menu_toggle` @@ -305,14 +303,14 @@ frigate_card_action: ptz [...] ``` -| Parameter | | Description | -| - | - | - | -| `action` | | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | | Must be `ptz`. | -| `camera` | Currently selected camera | An optional camera ID to execute the action on. | -| `ptz_action` | | Optional action that is of `left`, `right`, `up`, `down`, `zoom_in`, `zoom_out` or `preset`. | -| `ptz_phase` | | Optional parameter that is one of `start` or `stop` to start or stop the movement separately. | -| `ptz_preset` | | Optional preset to execute when the `ptz_action` is `preset`. | +| Parameter | | Description | +| --------------------- | ------------------------- | --------------------------------------------------------------------------------------------- | +| `action` | | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | | Must be `ptz`. | +| `camera` | Currently selected camera | An optional camera ID to execute the action on. | +| `ptz_action` | | Optional action that is of `left`, `right`, `up`, `down`, `zoom_in`, `zoom_out` or `preset`. | +| `ptz_phase` | | Optional parameter that is one of `start` or `stop` to start or stop the movement separately. | +| `ptz_preset` | | Optional preset to execute when the `ptz_action` is `preset`. | ?> If no `ptz_action` is specified, the camera returns to its "home" position. For a real PTZ camera, the "home" position is the first available preset. If there are no presets, there is no home position. @@ -326,11 +324,11 @@ frigate_card_action: ptz_controls [...] ``` -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `ptz_controls`. | -| `show` | If `true` shows the PTZ controls, if `false` hides them. | +| Parameter | Description | +| --------------------- | -------------------------------------------------------- | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `ptz_controls`. | +| `show` | If `true` shows the PTZ controls, if `false` hides them. | ## `ptz_digital` @@ -342,14 +340,14 @@ frigate_card_action: ptz-digital [...] ``` -| Parameter | Default | Description | -| - | - | - | -| `action` | | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | | Must be `ptz-digital`. | -| `target_id` | The currently selected camera or media | The target (camera or media) to execute a digital PTZ action on. Can be a camera ID, or another media ID (e.g. for Frigate, can specify a media/event ID). | -| `ptz_action` | Optional action that is one of `left`, `right`, `up`, `down`, `zoom_in` or `zoom_out`. | -| `ptz_phase` | Optional parameter that is one of `start` or `stop` to start or stop the movement separately. | -| `absolute` | Optional parameter to specify exact absolute pan and zoom settings. See below. | +| Parameter | Default | Description | +| --------------------- | --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `action` | | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | | Must be `ptz-digital`. | +| `target_id` | The currently selected camera or media | The target (camera or media) to execute a digital PTZ action on. Can be a camera ID, or another media ID (e.g. for Frigate, can specify a media/event ID). | +| `ptz_action` | Optional action that is one of `left`, `right`, `up`, `down`, `zoom_in` or `zoom_out`. | +| `ptz_phase` | Optional parameter that is one of `start` or `stop` to start or stop the movement separately. | +| `absolute` | Optional parameter to specify exact absolute pan and zoom settings. See below. | ?> If no `ptz_action` is specified and no `absolute` value is specified, the camera returns to its "home" position. See [Camera layout configuration](../../cameras/README.md?id=layout-configuration) to configure the default "home" position for digital PTZ. @@ -357,10 +355,10 @@ frigate_card_action: ptz-digital Set exact digital PTZ pan and zoom parameters. -| Parameter | Description | -| - | - | -| `pan` | Control camera digital pan. See the `pan` parameter in [Camera layout configuration](../../cameras/README.md?id=layout-configuration). | -| `zoom` | Control camera digital zoom. See the `zoom` parameter in [Camera layout configuration](../../cameras/README.md?id=layout-configuration). | +| Parameter | Description | +| --------- | ---------------------------------------------------------------------------------------------------------------------------------------- | +| `pan` | Control camera digital pan. See the `pan` parameter in [Camera layout configuration](../../cameras/README.md?id=layout-configuration). | +| `zoom` | Control camera digital zoom. See the `zoom` parameter in [Camera layout configuration](../../cameras/README.md?id=layout-configuration). | ## `ptz_multi` @@ -378,13 +376,13 @@ frigate_card_action: ptz-multi [...] ``` -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `ptz-digital`. | -| `ptz_action` | Optional action that is one of `left`, `right`, `up`, `down`, `zoom_in` or `zoom_out`. | -| `ptz_phase` | Optional parameter that is one of `start` or `stop` to start or stop the movement separately. | -| `ptz_preset` | Optional preset to execute when the `ptz_action` is `preset`. | +| Parameter | Description | +| --------------------- | --------------------------------------------------------------------------------------------- | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `ptz-digital`. | +| `ptz_action` | Optional action that is one of `left`, `right`, `up`, `down`, `zoom_in` or `zoom_out`. | +| `ptz_phase` | Optional parameter that is one of `start` or `stop` to start or stop the movement separately. | +| `ptz_preset` | Optional preset to execute when the `ptz_action` is `preset`. | ?> If no `ptz_action` is specified, the camera returns to its "home" position. @@ -424,22 +422,22 @@ action: custom:frigate-card-action frigate_card_action: sleep ``` -| Parameter | Description | -| - | - | -| `action` | Must be `custom:frigate-card-action`. | -| `frigate_card_action` | Must be `sleep`. | -| `duration` | A duration object. See below. | +| Parameter | Description | +| --------------------- | ------------------------------------- | +| `action` | Must be `custom:frigate-card-action`. | +| `frigate_card_action` | Must be `sleep`. | +| `duration` | A duration object. See below. | ### `duration` The `duration` block configures how long the `sleep` should last. -| Parameter | Description | -| - | - | -| `h` | Hours to sleep for. | -| `m` | Minutes to sleep for. | -| `s` | Seconds to sleep for. | -| `ms` | Milliseconds to sleep for. | +| Parameter | Description | +| --------- | -------------------------- | +| `h` | Hours to sleep for. | +| `m` | Minutes to sleep for. | +| `s` | Seconds to sleep for. | +| `ms` | Milliseconds to sleep for. | ?> Multiple values can be combined, e.g. `{ m: 2, s: 30}` will sleep for `2.5` minutes. diff --git a/docs/configuration/actions/custom/_sidebar.md b/docs/configuration/actions/custom/_sidebar.md index e2d1629d..b565bf98 100644 --- a/docs/configuration/actions/custom/_sidebar.md +++ b/docs/configuration/actions/custom/_sidebar.md @@ -1,27 +1,27 @@ -* [Getting Started](../../../README.md) -* [Configuration](../../README.md) - * [`actions`](../README.md) - * [Custom Actions](README.md) - * [Stock Actions](../stock/README.md) - * [`automations`](../../automations.md) - * [`cameras`](../../cameras/README.md) - * [`conditions`](../../conditions.md) - * [`dimensions`](../../dimensions.md) - * [`elements`](../../elements.md) - * [`image`](../../image.md) - * [`live`](../../live.md) - * [`media_gallery`](../../media-gallery.md) - * [`media_viewer`](../../media-viewer.md) - * [`menu`](../../menu.md) - * [`overrides`](../../overrides.md) - * [`performance`](../../performance.md) - * [`profiles`](../../profiles.md) - * [`timeline`](../../timeline.md) - * [`view`](../../view.md) -* [Screenshots](../../../screenshots.md) -* [Troubleshooting](../../../troubleshooting.md) -* [Usage](../../../usage/README.md) +- [Getting Started](../../../README.md) +- [Configuration](../../README.md) + - [`actions`](../README.md) + - [Custom Actions](README.md) + - [Stock Actions](../stock/README.md) + - [`automations`](../../automations.md) + - [`cameras`](../../cameras/README.md) + - [`conditions`](../../conditions.md) + - [`dimensions`](../../dimensions.md) + - [`elements`](../../elements.md) + - [`image`](../../image.md) + - [`live`](../../live.md) + - [`media_gallery`](../../media-gallery.md) + - [`media_viewer`](../../media-viewer.md) + - [`menu`](../../menu.md) + - [`overrides`](../../overrides.md) + - [`performance`](../../performance.md) + - [`profiles`](../../profiles.md) + - [`timeline`](../../timeline.md) + - [`view`](../../view.md) +- [Screenshots](../../../screenshots.md) +- [Troubleshooting](../../../troubleshooting.md) +- [Usage](../../../usage/README.md) --- -* [Developing](../../../developing.md) \ No newline at end of file +- [Developing](../../../developing.md) diff --git a/docs/configuration/actions/stock/_sidebar.md b/docs/configuration/actions/stock/_sidebar.md index 3858987a..f933ffe7 100644 --- a/docs/configuration/actions/stock/_sidebar.md +++ b/docs/configuration/actions/stock/_sidebar.md @@ -1,27 +1,27 @@ -* [Getting Started](../../../README.md) -* [Configuration](../../README.md) - * [`actions`](../README.md) - * [Custom Actions](../custom/README.md) - * [Stock Actions](README.md) - * [`automations`](../../automations.md) - * [`cameras`](../../cameras/README.md) - * [`conditions`](../../conditions.md) - * [`dimensions`](../../dimensions.md) - * [`elements`](../../elements.md) - * [`image`](../../image.md) - * [`live`](../../live.md) - * [`media_gallery`](../../media-gallery.md) - * [`media_viewer`](../../media-viewer.md) - * [`menu`](../../menu.md) - * [`overrides`](../../overrides.md) - * [`performance`](../../performance.md) - * [`profiles`](../../profiles.md) - * [`timeline`](../../timeline.md) - * [`view`](../../view.md) -* [Screenshots](../../../screenshots.md) -* [Troubleshooting](../../../troubleshooting.md) -* [Usage](../../../usage/README.md) +- [Getting Started](../../../README.md) +- [Configuration](../../README.md) + - [`actions`](../README.md) + - [Custom Actions](../custom/README.md) + - [Stock Actions](README.md) + - [`automations`](../../automations.md) + - [`cameras`](../../cameras/README.md) + - [`conditions`](../../conditions.md) + - [`dimensions`](../../dimensions.md) + - [`elements`](../../elements.md) + - [`image`](../../image.md) + - [`live`](../../live.md) + - [`media_gallery`](../../media-gallery.md) + - [`media_viewer`](../../media-viewer.md) + - [`menu`](../../menu.md) + - [`overrides`](../../overrides.md) + - [`performance`](../../performance.md) + - [`profiles`](../../profiles.md) + - [`timeline`](../../timeline.md) + - [`view`](../../view.md) +- [Screenshots](../../../screenshots.md) +- [Troubleshooting](../../../troubleshooting.md) +- [Usage](../../../usage/README.md) --- -* [Developing](../../../developing.md) \ No newline at end of file +- [Developing](../../../developing.md) diff --git a/docs/configuration/automations.md b/docs/configuration/automations.md index 37a1dc39..49697bb6 100644 --- a/docs/configuration/automations.md +++ b/docs/configuration/automations.md @@ -14,11 +14,11 @@ automations: - [action] ``` -| Option | Default | Description | -| - | - | - | -| `conditions` | | A list of [conditions](conditions.md) that must evaluate to `true` in order to trigger the automation. | -| `actions` | | An optional list of [actions](actions/README.md) that will be run when the [conditions](conditions.md) evaluate `true`. | -| `actions_not` | | An optional list of [actions](actions/README.md) that will be run when the [conditions](conditions.md) evaluate `false`. | +| Option | Default | Description | +| ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------ | +| `conditions` | | A list of [conditions](conditions.md) that must evaluate to `true` in order to trigger the automation. | +| `actions` | | An optional list of [actions](actions/README.md) that will be run when the [conditions](conditions.md) evaluate `true`. | +| `actions_not` | | An optional list of [actions](actions/README.md) that will be run when the [conditions](conditions.md) evaluate `false`. | # Fully expanded reference diff --git a/docs/configuration/cameras/README.md b/docs/configuration/cameras/README.md index 12f8cd92..51ced51e 100644 --- a/docs/configuration/cameras/README.md +++ b/docs/configuration/cameras/README.md @@ -12,25 +12,24 @@ cameras: The `cameras_global` block can be used to set defaults across multiple cameras. ```yaml -cameras_global: - [...] +cameras_global: [...] ``` -| Option | Default | Description | -| - | - | - | -| `camera_entity` | | The Home Assistant camera entity to use with the `frigate` live provider view. Also used to automatically detect the name of the underlying Frigate camera, and the title/icon of the camera. | -| `capabilities` | | Allows selective disabling of camera capabilities. See below. | -| `cast` | | Configuration that controls how this camera is "casted" / sent to media players. See below. | -| `dependencies` | | Other cameras that this camera should depend upon. See below. | -| `dimensions` | | Controls the dimensions and layout for media from this camera. See below. | -| `engine` | `auto` | The camera engine to use. If `auto` the card will attempt to choose the correct engine from the specified options. See [Engine](engine.md). | -| `frigate` | | Options for Frigate cameras. See [Frigate camera engine configuration](engine.md?id=frigate). | -| `icon` | Autodetected from `camera_entity` if that is specified. | The icon to use for this camera in the camera menu and in the next & previous controls when using the `icon` style. | -| `id` | `camera_entity`, `webrtc_card.entity` or `frigate.camera_name` if set (in that preference order). | An optional identifier to use throughout the card configuration to refer unambiguously to this camera. This `id` may be used in [conditions](../conditions.md), dependencies or custom [actions](../actions/README.md) to refer to a given camera unambiguously. | -| `live_provider` | `auto` | The choice of live stream provider. See [Live Provider](live-provider.md).| -| `title` | Autodetected from `camera_entity` if that is specified. | A friendly name for this camera to use in the card. | -| `triggers` | | Define what should cause this camera to update/trigger. See below. | -| `webrtc_card` | | The WebRTC entity/URL to use for this camera with the `webrtc-card` live provider. See below. | +| Option | Default | Description | +| --------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `camera_entity` | | The Home Assistant camera entity to use with the `frigate` live provider view. Also used to automatically detect the name of the underlying Frigate camera, and the title/icon of the camera. | +| `capabilities` | | Allows selective disabling of camera capabilities. See below. | +| `cast` | | Configuration that controls how this camera is "casted" / sent to media players. See below. | +| `dependencies` | | Other cameras that this camera should depend upon. See below. | +| `dimensions` | | Controls the dimensions and layout for media from this camera. See below. | +| `engine` | `auto` | The camera engine to use. If `auto` the card will attempt to choose the correct engine from the specified options. See [Engine](engine.md). | +| `frigate` | | Options for Frigate cameras. See [Frigate camera engine configuration](engine.md?id=frigate). | +| `icon` | Autodetected from `camera_entity` if that is specified. | The icon to use for this camera in the camera menu and in the next & previous controls when using the `icon` style. | +| `id` | `camera_entity`, `webrtc_card.entity` or `frigate.camera_name` if set (in that preference order). | An optional identifier to use throughout the card configuration to refer unambiguously to this camera. This `id` may be used in [conditions](../conditions.md), dependencies or custom [actions](../actions/README.md) to refer to a given camera unambiguously. | +| `live_provider` | `auto` | The choice of live stream provider. See [Live Provider](live-provider.md). | +| `title` | Autodetected from `camera_entity` if that is specified. | A friendly name for this camera to use in the card. | +| `triggers` | | Define what should cause this camera to update/trigger. See below. | +| `webrtc_card` | | The WebRTC entity/URL to use for this camera with the `webrtc-card` live provider. See below. | ## `capabilities` @@ -38,30 +37,29 @@ The `capabilities` block allows selected disabling of auto-detected camera capab ```yaml cameras: - - camera_entity: camera.office - capabilities: - [...] + - camera_entity: camera.office + capabilities: [...] ``` -| Option | Default | Description | -| - | - | - | -| `disable` | | A list of camera capabilities to disable. By default all capabilities supported by the camera are enabled. | -| `disable_except` | | A list of camera capabilities to leave enabled if supported. Everything else will be disabled. | +| Option | Default | Description | +| ---------------- | ------- | ---------------------------------------------------------------------------------------------------------- | +| `disable` | | A list of camera capabilities to disable. By default all capabilities supported by the camera are enabled. | +| `disable_except` | | A list of camera capabilities to leave enabled if supported. Everything else will be disabled. | ### Capabilities -| Capability | Purpose | -| - | - | -| `clips` | Clips can be fetched from the camera. | -| `favorite-events` | Events can be favorited. | -| `favorite-recordings` | Recordings can be favorited. | -| `live` | Live video can be received from the camera. | -| `menu` | The camera should show up in the card camera menu. | -| `ptz` | The camera can be PTZ controlled. | -| `recordings` | Recordings can be fetched from the camera. | -| `seek` | Clips can be seeked / scrubbed by the timeline. | -| `snapshots` | Snapshots can be fetched from the camera. | -| `substream` | The camera can be used as a substream on another camera. | +| Capability | Purpose | +| --------------------- | -------------------------------------------------------- | +| `clips` | Clips can be fetched from the camera. | +| `favorite-events` | Events can be favorited. | +| `favorite-recordings` | Recordings can be favorited. | +| `live` | Live video can be received from the camera. | +| `menu` | The camera should show up in the card camera menu. | +| `ptz` | The camera can be PTZ controlled. | +| `recordings` | Recordings can be fetched from the camera. | +| `seek` | Clips can be seeked / scrubbed by the timeline. | +| `snapshots` | Snapshots can be fetched from the camera. | +| `substream` | The camera can be used as a substream on another camera. | ## `cast` @@ -69,15 +67,14 @@ The `cast` block configures how a camera is cast / sent to media players. ```yaml cameras: - - camera_entity: camera.office - cast: - [...] + - camera_entity: camera.office + cast: [...] ``` -| Option | Default | Description | -| - | - | - | -| `dashboard` | | Configuration for the dashboard to cast. See below. | -| `method` | `standard` | Whether to use `standard` media casting to send the live view to your media player, or to instead cast a `dashboard` you have manually setup. Casting a dashboard supports a much wider variety of video media, including low latency video providers (e.g. `go2rtc`). This setting has no effect on casting non-live media. | +| Option | Default | Description | +| ----------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `dashboard` | | Configuration for the dashboard to cast. See below. | +| `method` | `standard` | Whether to use `standard` media casting to send the live view to your media player, or to instead cast a `dashboard` you have manually setup. Casting a dashboard supports a much wider variety of video media, including low latency video providers (e.g. `go2rtc`). This setting has no effect on casting non-live media. | See the [dashboard method cast example](../../examples.md?id=cast-a-dashboard). @@ -85,16 +82,15 @@ See the [dashboard method cast example](../../examples.md?id=cast-a-dashboard). ```yaml cameras: - - camera_entity: camera.office - cast: - dashboard: - [...] + - camera_entity: camera.office + cast: + dashboard: [...] ``` -| Option | Default | Description | -| - | - | - | -| `dashboard_path` | | A required field that specifies the name of the dashboard to cast. You can see this name in your HA URL when you visit the dashboard. | -| `view_path` | | A required field that specifies view/"tab" on that dashboard to cast. This is the value you have specified in the `url` field of the view configuration on the dashboard. | +| Option | Default | Description | +| ---------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `dashboard_path` | | A required field that specifies the name of the dashboard to cast. You can see this name in your HA URL when you visit the dashboard. | +| `view_path` | | A required field that specifies view/"tab" on that dashboard to cast. This is the value you have specified in the `url` field of the view configuration on the dashboard. | ## `dependencies` @@ -102,32 +98,29 @@ The `dependencies` block configures other cameras as dependents of this camera. ```yaml cameras: - - camera_entity: camera.office - dependencies: - [...] + - camera_entity: camera.office + dependencies: [...] ``` -| Option | Default | Description | -| - | - | - | -| `all_cameras` | `false` | Shortcut to specify all other cameras as dependent cameras. | -| `cameras` | | An optional list of other camera identifiers (see `id` parameter). If specified the card will fetch media for this camera and *also* recursively for the named cameras by default. Live views for the involved cameras will be available as 'substreams' of the main (depended upon) camera. All dependent cameras must themselves be a configured camera in the card. This can be useful to group events for cameras that are close together, to show multiple related live views, to always have clips/snapshots show fully merged events across all cameras or to show events for the `birdseye` camera that otherwise would not have events itself. | +| Option | Default | Description | +| ------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `all_cameras` | `false` | Shortcut to specify all other cameras as dependent cameras. | +| `cameras` | | An optional list of other camera identifiers (see `id` parameter). If specified the card will fetch media for this camera and _also_ recursively for the named cameras by default. Live views for the involved cameras will be available as 'substreams' of the main (depended upon) camera. All dependent cameras must themselves be a configured camera in the card. This can be useful to group events for cameras that are close together, to show multiple related live views, to always have clips/snapshots show fully merged events across all cameras or to show events for the `birdseye` camera that otherwise would not have events itself. | ## `dimensions` The `dimensions` block configures the dimensions and layout of media of a given camera (see [Card Dimensions](../dimensions.md) to set the dimensions of the whole card and not just a single camera). - ```yaml cameras: - - camera_entity: camera.office - dimensions: - [...] + - camera_entity: camera.office + dimensions: [...] ``` -| Option | Default | Description | -| - | - | - | -| `aspect_ratio` | | An optional aspect ratio for media from this camera which will be used in `live` or media viewer related views (e.g. `clip`, `snapshot` and `recording`). Format is the same as the parameter of the same name under the [dimensions block](../dimensions.md) (which controls dimensions for the whole card), e.g. `16 / 9`. | -| `layout` | | How the media should be laid out *within* the camera dimensions. See below. | +| Option | Default | Description | +| -------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `aspect_ratio` | | An optional aspect ratio for media from this camera which will be used in `live` or media viewer related views (e.g. `clip`, `snapshot` and `recording`). Format is the same as the parameter of the same name under the [dimensions block](../dimensions.md) (which controls dimensions for the whole card), e.g. `16 / 9`. | +| `layout` | | How the media should be laid out _within_ the camera dimensions. See below. | ### Layout Configuration @@ -135,19 +128,18 @@ The `layout` block configures the fit and position of the media _within_ the cam ```yaml cameras: - - camera_entity: camera.office - dimensions: - layout: - [...] + - camera_entity: camera.office + dimensions: + layout: [...] ``` -| Option | Default | Description | -| - | - | - | -| `fit` | `contain` | If `contain`, the media is contained within the card and letterboxed if necessary. If `cover`, the media is expanded proportionally (i.e. maintaining the media aspect ratio) until the camera/card dimensions are fully covered. If `fill`, the media is stretched to fill the camera/card dimensions (i.e. ignoring the media aspect ratio). See [CSS object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) for technical details and a visualization. | -| `pan` | | A dictionary that may contain an `x` and `y` percentage (`0` - `100`) to control the position of the media when "digitally zoomed in" (see `zoom` parameter). This can be effectively used to "pan"/cut the media shown. A value of `0` means maximally to the left or top of the media, a value of `100` means maximally to the right or bottom of the media. See visualizations below. | -| `position` | | A dictionary that may contain an `x` and `y` percentage (`0` - `100`) to control the position of the media when the fit is `cover` (for other values of `fit` this option has no effect). This can be effectively used to "pan"/cut the media shown. At any given time, only one of `x` and `y` will have an effect, depending on whether media width is larger than the camera/card dimensions (in which case `x` controls the position) or the media height is larger than the camera/card dimensions (in which case `y` controls the position). A value of `0` means maximally to the left or top of the media, a value of `100` means maximally to the right or bottom of the media. See [CSS object-position](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) for technicals. See visualizations below. | -| `view_box` | | A dictionary that may contain a `top`, `bottom`, `left` and `right` percentage (`0` - `100`) to precisely crop what part of the media to show by specifying a % inset value from each side. Browsers apply this cropping after `position` and `fit` have been applied. Unlike `zoom`, the user cannot dynamically zoom back out -- however the builtin media controls will work as normal. See visualizations below. Limited [browser support](https://caniuse.com/mdn-css_properties_object-view-box): ![](../../images/browsers/chrome_16x16.png "Google Chrome :no-zoom") ![](../../images/browsers/chromium_16x16.png "Chromium :no-zoom") ![](../../images/browsers/edge_16x16.png "Microsoft Edge :no-zoom") | -| `zoom` | `1.0` | A value between `1.0` and `10.0` inclusive that defines how much additional "digital zoom" to apply to this camera by default. Unlike with `view_box` the user can easily "zoom back out". Often used in conjuction with `pan`. When zoomed in the [builtin browser media controls](../live.md?id=controls) will automatically be disabled (as otherwise they would be enlarged also). | +| Option | Default | Description | +| ---------- | --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `fit` | `contain` | If `contain`, the media is contained within the card and letterboxed if necessary. If `cover`, the media is expanded proportionally (i.e. maintaining the media aspect ratio) until the camera/card dimensions are fully covered. If `fill`, the media is stretched to fill the camera/card dimensions (i.e. ignoring the media aspect ratio). See [CSS object-fit](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) for technical details and a visualization. | +| `pan` | | A dictionary that may contain an `x` and `y` percentage (`0` - `100`) to control the position of the media when "digitally zoomed in" (see `zoom` parameter). This can be effectively used to "pan"/cut the media shown. A value of `0` means maximally to the left or top of the media, a value of `100` means maximally to the right or bottom of the media. See visualizations below. | +| `position` | | A dictionary that may contain an `x` and `y` percentage (`0` - `100`) to control the position of the media when the fit is `cover` (for other values of `fit` this option has no effect). This can be effectively used to "pan"/cut the media shown. At any given time, only one of `x` and `y` will have an effect, depending on whether media width is larger than the camera/card dimensions (in which case `x` controls the position) or the media height is larger than the camera/card dimensions (in which case `y` controls the position). A value of `0` means maximally to the left or top of the media, a value of `100` means maximally to the right or bottom of the media. See [CSS object-position](https://developer.mozilla.org/en-US/docs/Web/CSS/object-position) for technicals. See visualizations below. | +| `view_box` | | A dictionary that may contain a `top`, `bottom`, `left` and `right` percentage (`0` - `100`) to precisely crop what part of the media to show by specifying a % inset value from each side. Browsers apply this cropping after `position` and `fit` have been applied. Unlike `zoom`, the user cannot dynamically zoom back out -- however the builtin media controls will work as normal. See visualizations below. Limited [browser support](https://caniuse.com/mdn-css_properties_object-view-box): ![](../../images/browsers/chrome_16x16.png 'Google Chrome :no-zoom') ![](../../images/browsers/chromium_16x16.png 'Chromium :no-zoom') ![](../../images/browsers/edge_16x16.png 'Microsoft Edge :no-zoom') | +| `zoom` | `1.0` | A value between `1.0` and `10.0` inclusive that defines how much additional "digital zoom" to apply to this camera by default. Unlike with `view_box` the user can easily "zoom back out". Often used in conjuction with `pan`. When zoomed in the [builtin browser media controls](../live.md?id=controls) will automatically be disabled (as otherwise they would be enlarged also). | ?> Layout operations are effectively applied in this order: `fit`, `position`, `view_box`, `zoom` then `pan`. @@ -157,24 +149,23 @@ See [media layout examples](../../examples.md?id=media-layout). ##### `fit` -![](../../images/media_layout/fit.png "Media Layout Fit :size=400") +![](../../images/media_layout/fit.png 'Media Layout Fit :size=400') ##### `position`: When media is shorter than dimensions height -![](../../images/media_layout/position-shorter-than-height.png "Media Layout Position: Wider than taller :size=400") +![](../../images/media_layout/position-shorter-than-height.png 'Media Layout Position: Wider than taller :size=400') ##### `position`: When media is thinner than dimensions width -![](../../images/media_layout/position-thinner-than-width.png "Media Layout Position: Taller than wider :size=400") +![](../../images/media_layout/position-thinner-than-width.png 'Media Layout Position: Taller than wider :size=400') #### `view_box`: Precise media cropping -![](../../images/media_layout/view-box.png "Media Layout Position: Taller than wider :size=400") +![](../../images/media_layout/view-box.png 'Media Layout Position: Taller than wider :size=400') #### `pan` and `zoom`: Predefined panning and zooming -![](../../images/media_layout/pan-zoom.png "Panning and zooming :size=400") - +![](../../images/media_layout/pan-zoom.png 'Panning and zooming :size=400') ## `ptz` @@ -182,17 +173,16 @@ Configure the PTZ actions taken for a camera (not to be confused with configurat ```yaml cameras: - - camera_entity: camera.office - ptz: - [...] + - camera_entity: camera.office + ptz: [...] ``` ### Movement types Generally PTZ cameras/integrations may support two kinds of PTZ actions: -* `relative`: Single relative steps, e.g. "Pan to the left one step". -* `continuous`: Separate start and stop, e.g. "Start panning to the left", following by a later command "Stop panning". +- `relative`: Single relative steps, e.g. "Pan to the left one step". +- `continuous`: Separate start and stop, e.g. "Start panning to the left", following by a later command "Stop panning". The card supports both, and with the help of the `r2c_delay_between_calls_seconds` and `c2r_delay_between_calls_seconds` can @@ -206,20 +196,20 @@ to allow for precise/smooth controls, and if unavailable will translate multiple [actions](../actions/README.md) may be configured to call either variety. ?> Frigate auto-detected PTZ actions will always be `continuous` as this is what -the integration currently offers. +the integration currently offers. ### Parameters -| Option | Default | Description | -| - | - | - | -| `actions_left`, `actions_right`, `actions_up`, `actions_down`, `actions_zoom_in`, `actions_zoom_out`, `actions_home` | Set by camera [engine](./engine.md) of the selected camera | The [call-service](../actions/stock/README.md?id=call-service) action that will be called for each PTZ action for relative movements. | -| `actions_left_start`, `actions_left_stop`, `actions_right_start`, `actions_right_stop`,`actions_up_start`, `actions_up_stop`,`actions_down_start`, `actions_down_stop`,`actions_zoom_in_start`, `actions_zoom_in_stop`,`actions_zoom_out_start`, `actions_zoom_out_stop` | Set by camera [engine](./engine.md) of the selected camera | The [call-service](../actions/stock/README.md?id=call-service) action that will be called for each PTZ action for continous movements. Both a `_start` and `_stop` variety must be provided for an action to be usable. | -| `c2r_delay_between_calls_seconds` | `0.2` | When the camera is configured with continuous actions only (e.g. `left_start` and `left_stop`, but not `left`), if something requests a relative action (e.g. a manually configured [action](../actions/README.md)), then `start` will be called, followed by a delay of this number of seconds and finally `stop` will be called. Cameras / integrations that are slower to respond to continuous steps may need to increase this value to avoid the continuous motion being too small. Cameras / integrations that are rapid to respond may need to decrease this value to avoid the "relative step" being too large. | -| `data_left`, `data_right`, `data_up`, `data_down`, `data_zoom_in`, `data_zoom_out`, `data_home` | | Shorthand for relative actions that call the service defined by the `service` parameter, with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[action]`. If both `actions_X` and `data_X` are specified, `actions_X` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). | -| `data_left_start`, `data_left_stop`, `data_right_start`, `data_right_stop`, `data_up_start`, `data_up_stop`, `data_down_start`, `data_down_stop`, `data_zoom_in_start`, `data_zoom_in_stop`, `data_zoom_out_start`, `data_zoom_out_stop` | | Shorthand for continuous actions that call the service defined by the `service` parameter, with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[action]_start` and `actions_[action]_stop`. If both `actions_X_*` and `data_X_*` are specified, `actions_X_*` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). Both a `_start` and `_stop` variety must be provided for an action to be usable. | -| `presets` | | PTZ preset actions. See below. | -| `r2c_delay_between_calls_seconds` | `0.5` | When the camera is configured with relative actions only (e.g. `left` but not `left_start` and `left_stop`), if something requests a continuous action (e.g. the card PTZ controls have a button held down), then a delay of this number of seconds will be inserted between each call of the relative action. Cameras / integrations that are slower to respond to relative steps may need to increase this value to avoid multiple simultaneous actions being sent. Cameras / integrations that are rapid to respond may need to decrease this value to increase the appearance of one single continuous motion. | -| `service` | | An optional Home Assistant service to call when the `data_` parameters are used. | +| Option | Default | Description | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `actions_left`, `actions_right`, `actions_up`, `actions_down`, `actions_zoom_in`, `actions_zoom_out`, `actions_home` | Set by camera [engine](./engine.md) of the selected camera | The [call-service](../actions/stock/README.md?id=call-service) action that will be called for each PTZ action for relative movements. | +| `actions_left_start`, `actions_left_stop`, `actions_right_start`, `actions_right_stop`,`actions_up_start`, `actions_up_stop`,`actions_down_start`, `actions_down_stop`,`actions_zoom_in_start`, `actions_zoom_in_stop`,`actions_zoom_out_start`, `actions_zoom_out_stop` | Set by camera [engine](./engine.md) of the selected camera | The [call-service](../actions/stock/README.md?id=call-service) action that will be called for each PTZ action for continous movements. Both a `_start` and `_stop` variety must be provided for an action to be usable. | +| `c2r_delay_between_calls_seconds` | `0.2` | When the camera is configured with continuous actions only (e.g. `left_start` and `left_stop`, but not `left`), if something requests a relative action (e.g. a manually configured [action](../actions/README.md)), then `start` will be called, followed by a delay of this number of seconds and finally `stop` will be called. Cameras / integrations that are slower to respond to continuous steps may need to increase this value to avoid the continuous motion being too small. Cameras / integrations that are rapid to respond may need to decrease this value to avoid the "relative step" being too large. | +| `data_left`, `data_right`, `data_up`, `data_down`, `data_zoom_in`, `data_zoom_out`, `data_home` | | Shorthand for relative actions that call the service defined by the `service` parameter, with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[action]`. If both `actions_X` and `data_X` are specified, `actions_X` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). | +| `data_left_start`, `data_left_stop`, `data_right_start`, `data_right_stop`, `data_up_start`, `data_up_stop`, `data_down_start`, `data_down_stop`, `data_zoom_in_start`, `data_zoom_in_stop`, `data_zoom_out_start`, `data_zoom_out_stop` | | Shorthand for continuous actions that call the service defined by the `service` parameter, with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[action]_start` and `actions_[action]_stop`. If both `actions_X_*` and `data_X_*` are specified, `actions_X_*` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). Both a `_start` and `_stop` variety must be provided for an action to be usable. | +| `presets` | | PTZ preset actions. See below. | +| `r2c_delay_between_calls_seconds` | `0.5` | When the camera is configured with relative actions only (e.g. `left` but not `left_start` and `left_stop`), if something requests a continuous action (e.g. the card PTZ controls have a button held down), then a delay of this number of seconds will be inserted between each call of the relative action. Cameras / integrations that are slower to respond to relative steps may need to increase this value to avoid multiple simultaneous actions being sent. Cameras / integrations that are rapid to respond may need to decrease this value to increase the appearance of one single continuous motion. | +| `service` | | An optional Home Assistant service to call when the `data_` parameters are used. | ### `presets` @@ -227,11 +217,11 @@ Configures named PTZ presets. If a preset of this name is auto-detected, these c ```yaml cameras: - - camera_entity: camera.office - ptz: - presets: - [preset_name]: - [action]: + - camera_entity: camera.office + ptz: + presets: + [preset_name]: + ? [action] ``` `[action]` is any [call-service](../actions/stock/README.md?id=call-service) action. @@ -245,17 +235,16 @@ camera is triggered. ```yaml cameras: - - camera_entity: camera.office - triggers: - [...] + - camera_entity: camera.office + triggers: [...] ``` -| Option | Default | Description | -| - | - | - | -| `entities` | | Whether to not to trigger the camera when the state of any Home Assistant entity becomes active (i.e. state becomes `on` or `open`). This works for Frigate or non-Frigate cameras.| -| `events` | `[events, clips, snapshots]` | Whether to trigger the camera when `events` occur (whether or not media is available) or whenever updated `clips` or `snapshots` are detected. Detection support varies by camera [engine](engine.md). | -| `motion` | `false` | Whether to not to trigger the camera by automatically detecting and using the motion `binary_sensor` for this camera. This autodetection only works for Frigate cameras, and only when the motion `binary_sensor` entity has been enabled in Home Assistant.| -| `occupancy` | `false` | Whether to not to trigger the camera by automatically detecting and using the occupancy `binary_sensor` for this camera and its configured zones and labels. This autodetection only works for Frigate cameras, and only when the occupancy `binary_sensor` entity has been enabled in Home Assistant. If this camera has configured zones, only occupancy sensors for those zones are used -- if the overall _camera_ occupancy sensor is also required, it can be manually added to `entities`. If this camera has configured labels, only occupancy sensors for those labels are used. | +| Option | Default | Description | +| ----------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `entities` | | Whether to not to trigger the camera when the state of any Home Assistant entity becomes active (i.e. state becomes `on` or `open`). This works for Frigate or non-Frigate cameras. | +| `events` | `[events, clips, snapshots]` | Whether to trigger the camera when `events` occur (whether or not media is available) or whenever updated `clips` or `snapshots` are detected. Detection support varies by camera [engine](engine.md). | +| `motion` | `false` | Whether to not to trigger the camera by automatically detecting and using the motion `binary_sensor` for this camera. This autodetection only works for Frigate cameras, and only when the motion `binary_sensor` entity has been enabled in Home Assistant. | +| `occupancy` | `false` | Whether to not to trigger the camera by automatically detecting and using the occupancy `binary_sensor` for this camera and its configured zones and labels. This autodetection only works for Frigate cameras, and only when the occupancy `binary_sensor` entity has been enabled in Home Assistant. If this camera has configured zones, only occupancy sensors for those zones are used -- if the overall _camera_ occupancy sensor is also required, it can be manually added to `entities`. If this camera has configured labels, only occupancy sensors for those labels are used. | ## Fully expanded reference @@ -384,7 +373,7 @@ cameras: service: service.of_your_choice data: device: '048123' - cmd: left + cmd: left # Continuous action (only `right` shown) actions_right_start: action: call-service diff --git a/docs/configuration/cameras/_sidebar.md b/docs/configuration/cameras/_sidebar.md index 6ab6e00b..050ab8bf 100644 --- a/docs/configuration/cameras/_sidebar.md +++ b/docs/configuration/cameras/_sidebar.md @@ -1,27 +1,27 @@ -* [Getting Started](../../README.md) -* [Configuration](../README.md) - * [`actions`](../actions/README.md) - * [`automations`](../automations.md) - * [`cameras`](README.md) - * [`live_provider`](live-provider.md) - * [`engine`](engine.md) - * [`conditions`](../conditions.md) - * [`dimensions`](../dimensions.md) - * [`elements`](../elements.md) - * [`image`](../image.md) - * [`live`](../live.md) - * [`media_gallery`](../media-gallery.md) - * [`media_viewer`](../media-viewer.md) - * [`menu`](../menu.md) - * [`overrides`](../overrides.md) - * [`performance`](../performance.md) - * [`profiles`](../profiles.md) - * [`timeline`](../timeline.md) - * [`view`](../view.md) -* [Screenshots](../../screenshots.md) -* [Troubleshooting](../../troubleshooting.md) -* [Usage](../../usage/README.md) +- [Getting Started](../../README.md) +- [Configuration](../README.md) + - [`actions`](../actions/README.md) + - [`automations`](../automations.md) + - [`cameras`](README.md) + - [`live_provider`](live-provider.md) + - [`engine`](engine.md) + - [`conditions`](../conditions.md) + - [`dimensions`](../dimensions.md) + - [`elements`](../elements.md) + - [`image`](../image.md) + - [`live`](../live.md) + - [`media_gallery`](../media-gallery.md) + - [`media_viewer`](../media-viewer.md) + - [`menu`](../menu.md) + - [`overrides`](../overrides.md) + - [`performance`](../performance.md) + - [`profiles`](../profiles.md) + - [`timeline`](../timeline.md) + - [`view`](../view.md) +- [Screenshots](../../screenshots.md) +- [Troubleshooting](../../troubleshooting.md) +- [Usage](../../usage/README.md) --- -* [Developing](../../developing.md) \ No newline at end of file +- [Developing](../../developing.md) diff --git a/docs/configuration/cameras/engine.md b/docs/configuration/cameras/engine.md index b5fb173e..dab970e1 100644 --- a/docs/configuration/cameras/engine.md +++ b/docs/configuration/cameras/engine.md @@ -4,19 +4,19 @@ A "Camera Engine" defines what "type" of camera is being configured (e.g. `frigate`), each engine offers different capabilities: -|Engine|Live|Supports clips|Supports Snapshots|Supports Recordings|Supports Timeline|Supports PTZ out of the box|Supports manually configured PTZ|Favorite events|Favorite recordings|Detect new events|Detect new snapshots|Detect new clips| -| - | - | - | - | - | - | - | - | - | - | - | - | - | -|`frigate`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -|`generic`| :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | -|`motioneye`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | +| Engine | Live | Supports clips | Supports Snapshots | Supports Recordings | Supports Timeline | Supports PTZ out of the box | Supports manually configured PTZ | Favorite events | Favorite recordings | Detect new events | Detect new snapshots | Detect new clips | +| ----------- | ------------------ | ------------------------ | ------------------------ | ------------------------ | ------------------------ | --------------------------- | -------------------------------- | ------------------------ | ------------------------ | ------------------------ | ------------------------ | ------------------------ | +| `frigate` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| `generic` | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | +| `motioneye` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | :heavy_multiplication_x: | #### Live providers supported per Engine -|Engine / Live Provider|`ha`|`image`|`jsmpeg`|`go2rtc`|`webrtc-card`| -| - | - | - | - | - | - | -|`frigate`| :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | -|`generic`| :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :white_check_mark: | -|`motioneye`| :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | +| Engine / Live Provider | `ha` | `image` | `jsmpeg` | `go2rtc` | `webrtc-card` | +| ---------------------- | ------------------ | ------------------ | ------------------------ | ------------------ | ------------------------ | +| `frigate` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | +| `generic` | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :white_check_mark: | +| `motioneye` | :white_check_mark: | :white_check_mark: | :heavy_multiplication_x: | :white_check_mark: | :heavy_multiplication_x: | See [Live Provider Configuration](live-provider.md) for more details on live providers. @@ -26,18 +26,17 @@ The `frigate` block configures options for a Frigate camera. ```yaml cameras: - - camera_entity: camera.office - frigate: - [...] + - camera_entity: camera.office + frigate: [...] ``` -| Option | Default | Description | -| - | - | - | -| `camera_name` | Autodetected from `camera_entity` if that is specified. | The Frigate camera name to use when communicating with the Frigate server, e.g. for viewing clips/snapshots or the JSMPEG live view.| -| `client_id` | `frigate` | The Frigate client id to use. If this Home Assistant server has multiple Frigate server backends configured, this selects which server should be used. It should be set to the MQTT client id configured for this server, see [Frigate Integration Multiple Instance Support](https://docs.frigate.video/integrations/home-assistant/#multiple-instance-support).| -| `labels` | | A list of Frigate labels used to filter events (clips & snapshots), e.g. [`person`, `car`].| -| `url` | | The URL of the frigate server. If set, this value will be (exclusively) used for a `Camera UI` menu button. All other communication with Frigate goes via Home Assistant. | -| `zones` | | A list of Frigates zones used to filter events (clips & snapshots), e.g. [`front_door`, `front_steps`].| +| Option | Default | Description | +| ------------- | ------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `camera_name` | Autodetected from `camera_entity` if that is specified. | The Frigate camera name to use when communicating with the Frigate server, e.g. for viewing clips/snapshots or the JSMPEG live view. | +| `client_id` | `frigate` | The Frigate client id to use. If this Home Assistant server has multiple Frigate server backends configured, this selects which server should be used. It should be set to the MQTT client id configured for this server, see [Frigate Integration Multiple Instance Support](https://docs.frigate.video/integrations/home-assistant/#multiple-instance-support). | +| `labels` | | A list of Frigate labels used to filter events (clips & snapshots), e.g. [`person`, `car`]. | +| `url` | | The URL of the frigate server. If set, this value will be (exclusively) used for a `Camera UI` menu button. All other communication with Frigate goes via Home Assistant. | +| `zones` | | A list of Frigates zones used to filter events (clips & snapshots), e.g. [`front_door`, `front_steps`]. | ## `motioneye` @@ -45,16 +44,15 @@ The `motioneye` block configures options for a MotionEye camera. ```yaml cameras: - - camera_entity: camera.office - motioneye: - [...] + - camera_entity: camera.office + motioneye: [...] ``` -| Option | Default | Description | -| - | - | - | -| `images` | | Configure how MotionEye images are consumed. See below. | -| `movies` | | Configure how MotionEye movies are consumed. See below. | -| `url` | | The URL of the MotionEye server. If set, this value will be (exclusively) used for a `Camera UI` menu button. | +| Option | Default | Description | +| -------- | ------- | ------------------------------------------------------------------------------------------------------------- | +| `images` | | Configure how MotionEye images are consumed. See below. | +| `movies` | | Configure how MotionEye movies are consumed. See below. | +| `url` | | The URL of the MotionEye server. If set, this value will be (exclusively) used for a `Camera UI` menu button. | ### `images` / `movies` @@ -62,21 +60,19 @@ The `images` and `movies` block configures how images and movies respectively ar ```yaml cameras: - - camera_entity: camera.office - motioneye: - images: - [...] + - camera_entity: camera.office + motioneye: + images: [...] ``` ```yaml cameras: - - camera_entity: camera.office - motioneye: - movies: - [...] + - camera_entity: camera.office + motioneye: + movies: [...] ``` -| Option | Default | Description | -| - | - | - | +| Option | Default | Description | +| ------------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `directory_pattern` | `%Y-%m-%d` | The directory that motionEye is configured to store media into. May contain multiple sub-directories separated by `/`. Path must encode the date of the media using MotionEye patterns such as `%Y`, `%m`, `%d`, `%H`, `%M`, `%S` (at least one pattern is required). Consult MotionEye help text for information on these substitutions. | -| `file_pattern` | `%H-%M-%S` | Within a directory (as matched by `directory_pattern`) the media items must exist and match this pattern. `file_pattern` must encode the time of the media using MotionEye patterns such as `%Y`, `%m`, `%d`, `%H`, `%M`, `%S` (at least one pattern is required). Consult MotionEye help text for information on these substitutions. | +| `file_pattern` | `%H-%M-%S` | Within a directory (as matched by `directory_pattern`) the media items must exist and match this pattern. `file_pattern` must encode the time of the media using MotionEye patterns such as `%Y`, `%m`, `%d`, `%H`, `%M`, `%S` (at least one pattern is required). Consult MotionEye help text for information on these substitutions. | diff --git a/docs/configuration/cameras/live-provider.md b/docs/configuration/cameras/live-provider.md index b775e3b6..03604627 100644 --- a/docs/configuration/cameras/live-provider.md +++ b/docs/configuration/cameras/live-provider.md @@ -4,15 +4,15 @@ The `live_provider` parameter determines what provides the live stream for a camera. Each provider offers different capabilities: -|Live Provider|Latency|Frame Rate|Loading Time|Installation|Description| -| -- | -- | -- | -- | -- | -- | -|`go2rtc`|Best|High|Better|Builtin|Uses [go2rtc](https://github.com/AlexxIT/go2rtc) to stream live feeds. This is supported by Frigate >= `0.12`. | -|`ha` (default HA configuration)|Poor|High|Better|Builtin|Use the built-in Home Assistant camera stream. The camera doesn't even need to be a Frigate camera! | -|`ha` (Native WebRTC)|Best|High|Better|Builtin|Use the built-in Home Assistant camera streams -- can be configured to use [native WebRTC](https://www.home-assistant.io/integrations/rtsp_to_webrtc/) offering a very low-latency feed direct to your browser. | -|`ha` (when configured with LL-HLS)|Better|High|Better|Builtin|Use the built-in Home Assistant camera streams -- can be configured to use an [LL-HLS](https://www.home-assistant.io/integrations/stream/#ll-hls) feed for lower latency. | -|`image`|Poor|Poor|Best|Builtin|Use refreshing snapshots of the built-in Home Assistant camera streams.| -|`jsmpeg`|Better|Low|Poor|Builtin|Use a the JSMPEG stream. | -|`webrtc-card`|Best|High|Better|Separate installation required|Embed's [AlexxIT's WebRTC Card](https://github.com/AlexxIT/WebRTC) to stream live feed, requires manual extra setup. See below. Not to be confused with native Home Assistant WebRTC (use the `ha` provider). | +| Live Provider | Latency | Frame Rate | Loading Time | Installation | Description | +| ---------------------------------- | ------- | ---------- | ------------ | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `go2rtc` | Best | High | Better | Builtin | Uses [go2rtc](https://github.com/AlexxIT/go2rtc) to stream live feeds. This is supported by Frigate >= `0.12`. | +| `ha` (default HA configuration) | Poor | High | Better | Builtin | Use the built-in Home Assistant camera stream. The camera doesn't even need to be a Frigate camera! | +| `ha` (Native WebRTC) | Best | High | Better | Builtin | Use the built-in Home Assistant camera streams -- can be configured to use [native WebRTC](https://www.home-assistant.io/integrations/rtsp_to_webrtc/) offering a very low-latency feed direct to your browser. | +| `ha` (when configured with LL-HLS) | Better | High | Better | Builtin | Use the built-in Home Assistant camera streams -- can be configured to use an [LL-HLS](https://www.home-assistant.io/integrations/stream/#ll-hls) feed for lower latency. | +| `image` | Poor | Poor | Best | Builtin | Use refreshing snapshots of the built-in Home Assistant camera streams. | +| `jsmpeg` | Better | Low | Poor | Builtin | Use a the JSMPEG stream. | +| `webrtc-card` | Best | High | Better | Separate installation required | Embed's [AlexxIT's WebRTC Card](https://github.com/AlexxIT/WebRTC) to stream live feed, requires manual extra setup. See below. Not to be confused with native Home Assistant WebRTC (use the `ha` provider). | ## `go2rtc` @@ -20,17 +20,16 @@ The `go2rtc` block configures use of the `go2rtc` live provider. This configurat ```yaml cameras: - - camera_entity: camera.office - live_provider: go2rtc - go2rtc: - [...] + - camera_entity: camera.office + live_provider: go2rtc + go2rtc: [...] ``` -| Option | Default | Description | -| - | - | - | -| `modes` | `[webrtc, mse, mp4, mjpeg]` | An ordered list of `go2rtc` modes to use. Valid values are `webrtc`, `mse`, `mp4` or `mjpeg` values. | -| `stream` | Determined by camera engine (e.g. `frigate` camera name). | A valid `go2rtc` stream name. | -| `url` | Determined by camera engine (e.g. the `frigate` engine will automatically generate a URL for the go2rtc backend that runs in the Frigate container). | The root `go2rtc` URL the card should stream the video from. This is only needed for non-Frigate usecases, or advanced Frigate usecases. Example: `http://my-custom-go2rtc:1984` | +| Option | Default | Description | +| -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `modes` | `[webrtc, mse, mp4, mjpeg]` | An ordered list of `go2rtc` modes to use. Valid values are `webrtc`, `mse`, `mp4` or `mjpeg` values. | +| `stream` | Determined by camera engine (e.g. `frigate` camera name). | A valid `go2rtc` stream name. | +| `url` | Determined by camera engine (e.g. the `frigate` engine will automatically generate a URL for the go2rtc backend that runs in the Frigate container). | The root `go2rtc` URL the card should stream the video from. This is only needed for non-Frigate usecases, or advanced Frigate usecases. Example: `http://my-custom-go2rtc:1984` | ## `image` @@ -38,16 +37,15 @@ All configuration is under: ```yaml cameras: - - camera_entity: camera.office - live_provider: image - image: - [...] + - camera_entity: camera.office + live_provider: image + image: [...] ``` -| Option | Default | Description | -| - | - | - | -| `refresh_seconds` | 1 | The image will be refreshed at least every `refresh_seconds`. `0` implies no refreshing. | -| `url` | | **Advanced**: A static image URL to be fetched in lieu of the Home Assistant image for the given camera. This may be useful for advanced configurations where the camera image is being provided by some non-Home Assistant system. This will also set the temporary loading image used when `show_image_during_load` is set to true under the `live` configuration. | +| Option | Default | Description | +| ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `refresh_seconds` | 1 | The image will be refreshed at least every `refresh_seconds`. `0` implies no refreshing. | +| `url` | | **Advanced**: A static image URL to be fetched in lieu of the Home Assistant image for the given camera. This may be useful for advanced configurations where the camera image is being provided by some non-Home Assistant system. This will also set the temporary loading image used when `show_image_during_load` is set to true under the `live` configuration. | ## `jsmpeg` @@ -55,15 +53,14 @@ All configuration is under: ```yaml cameras: - - camera_entity: camera.office - live_provider: jsmpeg - jsmpeg: - [...] + - camera_entity: camera.office + live_provider: jsmpeg + jsmpeg: [...] ``` -| Option | Default | Description | -| - | - | - | -| `options` | | **Advanced users only**: Control the underlying [JSMPEG library options](https://github.com/phoboslab/jsmpeg#usage). Supports setting these JSMPEG options `{audio, video, pauseWhenHidden, disableGl, disableWebAssembly, preserveDrawingBuffer, progressive, throttled, chunkSize, maxAudioLag, videoBufferSize, audioBufferSize}`. This is not necessary for the vast majority of users: only set these flags if you know what you're doing, as you may entirely break video rendering in the card.| +| Option | Default | Description | +| --------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `options` | | **Advanced users only**: Control the underlying [JSMPEG library options](https://github.com/phoboslab/jsmpeg#usage). Supports setting these JSMPEG options `{audio, video, pauseWhenHidden, disableGl, disableWebAssembly, preserveDrawingBuffer, progressive, throttled, chunkSize, maxAudioLag, videoBufferSize, audioBufferSize}`. This is not necessary for the vast majority of users: only set these flags if you know what you're doing, as you may entirely break video rendering in the card. | ## `webrtc_card` @@ -73,14 +70,13 @@ events/snapshots/UI. AlexxIT's WebRTC Integration/Card must be installed and con ```yaml cameras: - - camera_entity: camera.office - live_provider: webrtc-card - webrtc_card: - [...] + - camera_entity: camera.office + live_provider: webrtc-card + webrtc_card: [...] ``` -| Option | Default | Description | -| - | - | - | -| `entity` | | The RTSP camera entity to pass to the WebRTC Card for this camera. | -| `url` | Depends on the camera engine (e.g. Frigate cameras will automatically use the camera name since this is the [recommended setup](https://deploy-preview-4055--frigate-docs.netlify.app/guides/configuring_go2rtc/)). | The RTSP url to pass to the WebRTC Card, e.g. `rtsp://USERNAME:PASSWORD@CAMERA:554/RTSP_PATH` | -| `*`| | Any options specified in the `webrtc_card:` YAML dictionary are silently passed through to the AlexxIT's WebRTC Card. See [WebRTC Configuration](https://github.com/AlexxIT/WebRTC#configuration) for full details this external card provides, e.g. `ui: true` will enable the WebRTC Card UI. | +| Option | Default | Description | +| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `entity` | | The RTSP camera entity to pass to the WebRTC Card for this camera. | +| `url` | Depends on the camera engine (e.g. Frigate cameras will automatically use the camera name since this is the [recommended setup](https://deploy-preview-4055--frigate-docs.netlify.app/guides/configuring_go2rtc/)). | The RTSP url to pass to the WebRTC Card, e.g. `rtsp://USERNAME:PASSWORD@CAMERA:554/RTSP_PATH` | +| `*` | | Any options specified in the `webrtc_card:` YAML dictionary are silently passed through to the AlexxIT's WebRTC Card. See [WebRTC Configuration](https://github.com/AlexxIT/WebRTC#configuration) for full details this external card provides, e.g. `ui: true` will enable the WebRTC Card UI. | diff --git a/docs/configuration/common/expanded-warning.md b/docs/configuration/common/expanded-warning.md index ba915b1c..5c80c96d 100644 --- a/docs/configuration/common/expanded-warning.md +++ b/docs/configuration/common/expanded-warning.md @@ -1 +1 @@ -!> Just copying this full reference into your configuration will cause you a significant maintenance burden. Don't do it! Only specify what you need, everything shown here are either default or illustrative values. \ No newline at end of file +!> Just copying this full reference into your configuration will cause you a significant maintenance burden. Don't do it! Only specify what you need, everything shown here are either default or illustrative values. diff --git a/docs/configuration/common/timeline-seek-info.md b/docs/configuration/common/timeline-seek-info.md index f184386b..476d93b2 100644 --- a/docs/configuration/common/timeline-seek-info.md +++ b/docs/configuration/common/timeline-seek-info.md @@ -1,4 +1,4 @@ ?> For optimal UX, keep the settings for the mini-timeline in the `live` and `media_viewer` identical. Dragging the timeline may cause the card to change between the `live` view and `media_viewer` based views as the user pans between -the past and present -- if the settings are different the timeline must "reset". \ No newline at end of file +the past and present -- if the settings are different the timeline must "reset". diff --git a/docs/configuration/conditions.md b/docs/configuration/conditions.md index 3a26792b..8555e1f3 100644 --- a/docs/configuration/conditions.md +++ b/docs/configuration/conditions.md @@ -22,10 +22,10 @@ conditions: [...] ``` -| Parameter | Description | -| - | - | -| `condition` | Must be `camera`. | -| `cameras` | A list of camera IDs in which this condition is satisfied. See the camera [id](cameras/README.md) parameter. | +| Parameter | Description | +| ----------- | ------------------------------------------------------------------------------------------------------------ | +| `condition` | Must be `camera`. | +| `cameras` | A list of camera IDs in which this condition is satisfied. See the camera [id](cameras/README.md) parameter. | ## `expand` @@ -35,10 +35,10 @@ conditions: [...] ``` -| Parameter | Description | -| - | - | -| `condition` | Must be `expand`. | -| `expand` | If `true` the condition is satisfied if the card is in expanded mode (in a dialog/popup). If `false` the condition is satisfied if the card is **NOT** in expanded mode (in a dialog/popup). | +| Parameter | Description | +| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `condition` | Must be `expand`. | +| `expand` | If `true` the condition is satisfied if the card is in expanded mode (in a dialog/popup). If `false` the condition is satisfied if the card is **NOT** in expanded mode (in a dialog/popup). | ## `fullscreen` @@ -48,9 +48,9 @@ conditions: [...] ``` -| Parameter | Description | -| - | - | -| `condition` | Must be `fullscreen`. | +| Parameter | Description | +| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `condition` | Must be `fullscreen`. | | `fullscreen` | If `true` the condition is satisfied if the card is in fullscreen mode. If `false` the condition is satisfied if the card is **NOT** in fullscreen mode. | ## `interaction` @@ -61,9 +61,9 @@ conditions: [...] ``` -| Parameter | Description | -| - | - | -| `condition` | Must be `interaction`. | +| Parameter | Description | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `condition` | Must be `interaction`. | | `interaction` | If `true` the condition is satisfied if the card has had human interaction within `view.interaction_seconds` elapsed seconds. If `false` the condition is satisfied if the card has **NOT** had human interaction in that time. | ## `key` @@ -74,15 +74,15 @@ conditions: [...] ``` -| Parameter | Default | Description | -| - | - | - | -| `condition` | - | Must be `key`. | -| `alt` | `false` | An optional value to match whether the `alt` key is being held. | -| `ctrl` | `false` | An optional value to match whether the `ctrl` key is being held. | -| `key` | | Any [keyboard key value](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values), e.g. `ArrowLeft`. | -| `meta` | `false` | An optional value to match whether the `meta` key is being held. | -| `shift` | `false` | An optional value to match whether the `shift` key is being held. | -| `state` | `down` | An optional value to match the state of the. Must be one of `down` or `up`. | +| Parameter | Default | Description | +| ----------- | ------- | --------------------------------------------------------------------------------------------------------------------------------- | +| `condition` | - | Must be `key`. | +| `alt` | `false` | An optional value to match whether the `alt` key is being held. | +| `ctrl` | `false` | An optional value to match whether the `ctrl` key is being held. | +| `key` | | Any [keyboard key value](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values), e.g. `ArrowLeft`. | +| `meta` | `false` | An optional value to match whether the `meta` key is being held. | +| `shift` | `false` | An optional value to match whether the `shift` key is being held. | +| `state` | `down` | An optional value to match the state of the. Must be one of `down` or `up`. | ## `media_loaded` @@ -92,9 +92,9 @@ conditions: [...] ``` -| Parameter | Description | -| - | - | -| `condition` | Must be `media_loaded`. | +| Parameter | Description | +| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `condition` | Must be `media_loaded`. | | `media_loaded` | If `true` the condition is satisfied if there is media load**ED** (not load**ING**) in the card (e.g. a clip, snapshot or live view). This may be used to hide controls during media loading or when a message (not media) is being displayed. | ## `microphone` @@ -105,11 +105,11 @@ conditions: [...] ``` -| Parameter | Description | -| - | - | -| `condition` | Must be `microphone`. | +| Parameter | Description | +| ----------- | ---------------------------------------------------------------------------------------------------------------------- | +| `condition` | Must be `microphone`. | | `connected` | Optional: If `true` or `false` the condition is satisfied if the microphone is connected or disconnected respectively. | -| `muted` | Optional: If `true` or `false` the condition is satisfied if the microphone is muted or unmuted respectively. | +| `muted` | Optional: If `true` or `false` the condition is satisfied if the microphone is muted or unmuted respectively. | ## `numeric_state` @@ -129,9 +129,9 @@ conditions: [...] ``` -| Parameter | Description | -| - | - | -| `condition` | Must be `screen`. | +| Parameter | Description | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `condition` | Must be `screen`. | | `media_query` | Any valid [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/Media_Queries/Using_media_queries) string. Media queries must start and end with parentheses. This may be used to alter card configuration based on device/media properties (e.g. viewport width, orientation). Please note that `width` and `height` refer to the entire viewport not just the card. | See the [screen conditions examples](../examples.md?id=screen-conditions). @@ -154,9 +154,9 @@ conditions: [...] ``` -| Parameter | Description | -| - | - | -| `condition` | Must be `triggered`. | +| Parameter | Description | +| ----------- | ------------------------------------------------------------------------------------------------- | +| `condition` | Must be `triggered`. | | `triggered` | A list of camera IDs which, if [triggered](cameras/README.md?id=triggers), satisfy the condition. | ## `user` @@ -177,10 +177,10 @@ conditions: [...] ``` -| Parameter | Description | -| - | - | -| `condition` | Must be `view`. | -| `views` | A list of [views](view.md?id=supported-views) in which this condition is satified (e.g. `clips`). | +| Parameter | Description | +| ----------- | ------------------------------------------------------------------------------------------------- | +| `condition` | Must be `view`. | +| `views` | A list of [views](view.md?id=supported-views) in which this condition is satified (e.g. `clips`). | ?> Internally, views associated with the media viewer (e.g. `clip`, `snapshot`, `recording`) are translated to a special view called `media` after the relevant diff --git a/docs/configuration/dimensions.md b/docs/configuration/dimensions.md index 45338087..3a74d5c3 100644 --- a/docs/configuration/dimensions.md +++ b/docs/configuration/dimensions.md @@ -9,30 +9,29 @@ expanded (popup/dialog mode) the aspect ratio is chosen dynamically to maximize the amount of content shown. ```yaml -dimensions: - [...] +dimensions: [...] ``` -| Option | Default | Description | -| - | - | - | -| `aspect_ratio_mode` | `dynamic` | The aspect ratio mode to use. Acceptable values: `dynamic`, `static`, `unconstrained`. See below. | -| `aspect_ratio` | `16:9` | The aspect ratio to use. Acceptable values: `[W]:[H]` or `[W]/[H]`. See below. | -| `max_height` | `100vh` | The maximum allowable height for the card. Specified in [CSS units](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units). Generally users should not need to change this setting unless they have set an `unconstrained` aspect ratio. | -| `min_height` | `100px` | The minimum allowable height for the card. Specified in [CSS units](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units). Generally users should not need to change this setting. | +| Option | Default | Description | +| ------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `aspect_ratio_mode` | `dynamic` | The aspect ratio mode to use. Acceptable values: `dynamic`, `static`, `unconstrained`. See below. | +| `aspect_ratio` | `16:9` | The aspect ratio to use. Acceptable values: `[W]:[H]` or `[W]/[H]`. See below. | +| `max_height` | `100vh` | The maximum allowable height for the card. Specified in [CSS units](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units). Generally users should not need to change this setting unless they have set an `unconstrained` aspect ratio. | +| `min_height` | `100px` | The minimum allowable height for the card. Specified in [CSS units](https://developer.mozilla.org/en-US/docs/Learn/CSS/Building_blocks/Values_and_units). Generally users should not need to change this setting. | ### `aspect_ratio_mode` -| Option | Description | -| - | - | -| `dynamic` | The aspect-ratio of the entire card will match the aspect-ratio of the last selected media item. | -| `static` | A fixed aspect-ratio (as defined by `aspect_ratio`) will be applied to the card. | +| Option | Description | +| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `dynamic` | The aspect-ratio of the entire card will match the aspect-ratio of the last selected media item. | +| `static` | A fixed aspect-ratio (as defined by `aspect_ratio`) will be applied to the card. | | `unconstrained` | No aspect ratio is enforced in any view, the card will expand with the content. This may be especially useful for a panel-mode dashboard, or in views that have no intrinsic aspect-ratio (e.g. the media gallery). | ### `aspect_ratio` -* `16 / 9` or `16:9`: Default widescreen ratio. -* `4 / 3` or `4:3`: Default fullscreen ratio. -* `[W]/[H]` or `[W]:[H]`: Any arbitrary aspect-ratio. +- `16 / 9` or `16:9`: Default widescreen ratio. +- `4 / 3` or `4:3`: Default fullscreen ratio. +- `[W]/[H]` or `[W]:[H]`: Any arbitrary aspect-ratio. ## Fully expanded reference diff --git a/docs/configuration/elements.md b/docs/configuration/elements.md index 992a89e7..87606c68 100644 --- a/docs/configuration/elements.md +++ b/docs/configuration/elements.md @@ -6,8 +6,8 @@ allow the user to add custom elements to the card. ```yaml elements: - - [element_1] - - [element_2] + - [element_1] + - [element_2] ``` ?> The Frigate Card allows either a single [action](actions/README.md) (as in stock Home @@ -66,27 +66,27 @@ elements: Parameters for this element are identical to the parameters of the [stock Home Assistant Icon Element](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) with the exception of these parameters which differ: -| Parameter | Description | -| - | - | -| `type` | Must be `custom:frigate-card-menu-submenu`. | -| `items` | A list of menu items, as described below. | +| Parameter | Description | +| --------- | ------------------------------------------- | +| `type` | Must be `custom:frigate-card-menu-submenu`. | +| `items` | A list of menu items, as described below. | ### Submenu items -| Parameter | Default | Description | -| - | - | - | -| `enabled` | `true` | Whether or not to show this item as enabled / selectable. | -| `entity` | | An optional Home Assistant entity from which title, icon and style can be automatically computed. | -| `icon` | | An optional item icon to display, e.g. `mdi:car` | -| `selected` | `false` | Whether or not to show this item as selected. | -| `state_color` | `true` | Whether or not the title and icon should be stylized based on state. | -| `style` | | Position and style the element using CSS. | -| `tap_action`, `double_tap_action`, `hold_action`, `start_tap`, `end_tap` | | The [actions](actions/README.md) to take when this item is interacted with. | -| `title` | | An optional title to display. | +| Parameter | Default | Description | +| ------------------------------------------------------------------------ | ------- | ------------------------------------------------------------------------------------------------- | +| `enabled` | `true` | Whether or not to show this item as enabled / selectable. | +| `entity` | | An optional Home Assistant entity from which title, icon and style can be automatically computed. | +| `icon` | | An optional item icon to display, e.g. `mdi:car` | +| `selected` | `false` | Whether or not to show this item as selected. | +| `state_color` | `true` | Whether or not the title and icon should be stylized based on state. | +| `style` | | Position and style the element using CSS. | +| `tap_action`, `double_tap_action`, `hold_action`, `start_tap`, `end_tap` | | The [actions](actions/README.md) to take when this item is interacted with. | +| `title` | | An optional title to display. | ## `custom:frigate-card-menu-submenu-select` -Add a submenu based on a `select` or `input_select`. This element allows you to convert a [Home Assistant Select Entity](https://www.home-assistant.io/integrations/select/) or [Home Assistant Input Select Entity](https://www.home-assistant.io/integrations/input_select/) (an entity either starting with `select` or `input_select`) into an overridable submenu. This *could* be done by hand using a regular submenu (above) -- this element is a convenience. +Add a submenu based on a `select` or `input_select`. This element allows you to convert a [Home Assistant Select Entity](https://www.home-assistant.io/integrations/select/) or [Home Assistant Input Select Entity](https://www.home-assistant.io/integrations/input_select/) (an entity either starting with `select` or `input_select`) into an overridable submenu. This _could_ be done by hand using a regular submenu (above) -- this element is a convenience. ```yaml elements: @@ -96,9 +96,9 @@ elements: Parameters for the `custom:frigate-card-menu-submenu-select` element are identical to the parameters of the [stock Home Assistant State Icon Element](https://www.home-assistant.io/dashboards/picture-elements/#state-icon) with the exception of these parameters which differ: -| Parameter | Description | -| - | - | -| `type` | Must be `custom:frigate-card-menu-submenu-select`. | +| Parameter | Description | +| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `type` | Must be `custom:frigate-card-menu-submenu-select`. | | `options` | An optional dictionary of overrides keyed by the option name that the given select entity supports. These options can be used to set or override submenu item parameters on a per-option basis. The format is as described in [Submenu Items](elements.md?id=submenu-items) above. | See the `select` [submenu example](../examples.md?id=select-submenu). @@ -115,11 +115,11 @@ elements: Parameters for the `custom:frigate-card-conditional` element: -| Parameter | Description | -| - | - | -| `type` | Must be `custom:frigate-card-conditional`. | +| Parameter | Description | +| ------------ | ---------------------------------------------------------------------------------------------------------- | +| `type` | Must be `custom:frigate-card-conditional`. | | `conditions` | A list of [conditions](conditions.md) that must evaluate to true in order for the elements to be rendered. | -| `elements` | The elements to render. Can be any supported element. | +| `elements` | The elements to render. Can be any supported element. | See the [conditional elements example](../examples.md?id=conditional-elements). @@ -200,7 +200,7 @@ elements: style: left: 100px top: 50px - title: "Temperature" + title: 'Temperature' - type: state-icon entity: light.office_main_lights icon: mdi:lamp @@ -243,11 +243,11 @@ elements: entity: light.office_main_lights title: Image state_image: - on: "https://picsum.photos/id/1003/1181/1772" - off: "https://picsum.photos/id/102/4320/3240" + on: 'https://picsum.photos/id/1003/1181/1772' + off: 'https://picsum.photos/id/102/4320/3240' state_filter: - "on": brightness(110%) saturate(1.2) - "off": brightness(50%) hue-rotate(45deg) + 'on': brightness(110%) saturate(1.2) + 'off': brightness(50%) hue-rotate(45deg) style: left: 100px top: 350px @@ -267,12 +267,12 @@ elements: users: - 581fca7fdc014b8b894519cc531f9a04 elements: - - type: icon - icon: mdi:dog - title: Woof - style: - left: 100px - top: 400px + - type: icon + icon: mdi:dog + title: Woof + style: + left: 100px + top: 400px ``` ### Frigate Card elements diff --git a/docs/configuration/image.md b/docs/configuration/image.md index 2f56f6fa..273bd767 100644 --- a/docs/configuration/image.md +++ b/docs/configuration/image.md @@ -3,16 +3,15 @@ Configure the `image` view. ```yaml -image: - [...] +image: [...] ``` -| Option | Default | Description | -| - | - | - | -| `actions` | | [Actions](actions/README.md) to use for the `image` view.| -| `mode` | `url` | Mode of the the `image` view. Value must be one of `url` (to fetch an arbitrary image URL), `camera` (to show a still of the currently selected camera using either `camera_entity` or `webrtc_card.entity` in that order of precedence), or `screensaver` (to show an [embedded stock Frigate card logo](https://github.com/dermotduffy/frigate-hass-card/blob/main/src/images/frigate-bird-in-sky.jpg)). In either `url` or `camera` mode, the `screensaver` content is used as a fallback if a URL is not specified or cannot be derived. | -| `refresh_seconds` | 0 | The image will be refreshed at least every `refresh_seconds` (it may refresh more frequently, e.g. whenever Home Assistant updates its camera security token). `0` implies no refreshing. | -| `url` | | A static image URL to be used when the `mode` is set to `url` or when a temporary image is required (e.g. may appear momentarily prior to load of a camera snapshot in the `camera` mode). Note that a `_t=[timestsamp]` query parameter will be automatically added to all URLs such that the image will not be cached by the browser. | +| Option | Default | Description | +| ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `actions` | | [Actions](actions/README.md) to use for the `image` view. | +| `mode` | `url` | Mode of the the `image` view. Value must be one of `url` (to fetch an arbitrary image URL), `camera` (to show a still of the currently selected camera using either `camera_entity` or `webrtc_card.entity` in that order of precedence), or `screensaver` (to show an [embedded stock Frigate card logo](https://github.com/dermotduffy/frigate-hass-card/blob/main/src/images/frigate-bird-in-sky.jpg)). In either `url` or `camera` mode, the `screensaver` content is used as a fallback if a URL is not specified or cannot be derived. | +| `refresh_seconds` | 0 | The image will be refreshed at least every `refresh_seconds` (it may refresh more frequently, e.g. whenever Home Assistant updates its camera security token). `0` implies no refreshing. | +| `url` | | A static image URL to be used when the `mode` is set to `url` or when a temporary image is required (e.g. may appear momentarily prior to load of a camera snapshot in the `camera` mode). Note that a `_t=[timestsamp]` query parameter will be automatically added to all URLs such that the image will not be cached by the browser. | ?> When `mode` is set to `camera` this is effectively providing the same image as the `image` [live provider](cameras/live-provider.md) would show in the live camera carousel. diff --git a/docs/configuration/live.md b/docs/configuration/live.md index 51b144cc..777c6753 100644 --- a/docs/configuration/live.md +++ b/docs/configuration/live.md @@ -2,28 +2,27 @@ Configures the behavior of the `live` view. - ```yaml -live: - [...] +```yaml +live: [...] ``` -| Option | Default | Description | -| - | - | - | -| `actions` | | [Actions](actions/README.md) to use for the `live` view. | -| `auto_mute` | `[unselected, hidden, microphone]` | A list of conditions in which live camera feeds are muted. `unselected` will automatically mute when a camera is unselected in the carousel, `hidden` will automatically mute when the browser/tab becomes hidden or `microphone` will automatically mute after the microphone is muted as long as the camera stays selected (see the `live.microphone.mute_after_microphone_mute_seconds` to control how long after). Use an empty list (`[]`) to never automatically mute. Note that if `auto_play` is enabled, the stream may mute itself automatically in order to honor the `auto_play` setting, as some browsers will not auto play media that is unmuted -- that is to say, where necessary, the `auto_play` parameter will take priority over the `auto_mute` parameter.| -| `auto_pause` | `[]` | A list of conditions in which live camera feeds are automatically paused. `unselected` will automatically pause when a camera is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause. **Caution**: Some live providers (e.g. `jsmpeg`) may not offer human-accessible means to resume play if it is paused, unless the `auto_play` option is used.| -| `auto_play` | `[selected, visible]` | A list of conditions in which live camera feeds are automatically played.`selected` will automatically play when a camera is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play. Some live providers (e.g. `webrtc-card`, `jsmpeg`) do not support the prevention of automatic play on initial load, but should still respect the value of this flag on play-after-pause.| -| `auto_unmute` | `[microphone]` | A list of conditions in which live camera feeds are unmuted. `selected` will automatically unmute when a camera is unselected in the carousel, `visible` will automatically unmute when the browser/tab becomes visible or `microphone` will automatically unmute after the microphone is unmuted. Use an empty list (`[]`) to never automatically unmute.| -| `controls` | | Configuration for the `live` view controls. See below. | -| `display` | | Controls whether to show a single or grid `live` view. See below. | -| `draggable` | `true` | Whether or not the live carousel can be dragged left or right, via touch/swipe and mouse dragging. | -| `lazy_load` | `true` | Whether or not to lazily load cameras in the camera carousel. Setting this will `false` will cause all cameras to load simultaneously when the `live` carousel is opened (or cause all cameras to load continually if both `lazy_load` and `preload` are `true`). This will result in a smoother carousel experience at a cost of (potentially) a substantial amount of continually streamed data. | -| `lazy_unload` | `[]` | A list of conditions in which live camera feeds are unloaded. `unselected` will lazy-unload a camera when it is unselected in the carousel and `hidden` will lazy-unload all cameras when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically unload. This will cause a reloading delay on revisiting that camera in the carousel but will save the streaming network resources that are otherwise consumed. This option has no effect if `lazy_load` is false. Some live providers (e.g. `webrtc-card`) implement their own lazy unloading independently which may occur regardless of the value of this setting.| -| `microphone` | | See below. | -| `preload` | `false` | Whether or not to preload the live view. Preloading causes the live view to render in the background regardless of what view is actually shown, so it's instantly available when requested. This consumes additional network/CPU resources continually. | -| `show_image_during_load` | `true` | If `true`, during the initial stream load, the `image` live provider will be shown instead of the loading video stream. This still image will auto-refresh and is replaced with the live stream once loaded. | -| `transition_effect` | `slide` | Effect to apply as a transition between live cameras. Accepted values: `slide` or `none`. | -| `zoomable` | `true` | Whether or not the live carousel can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | +| Option | Default | Description | +| ------------------------ | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `actions` | | [Actions](actions/README.md) to use for the `live` view. | +| `auto_mute` | `[unselected, hidden, microphone]` | A list of conditions in which live camera feeds are muted. `unselected` will automatically mute when a camera is unselected in the carousel, `hidden` will automatically mute when the browser/tab becomes hidden or `microphone` will automatically mute after the microphone is muted as long as the camera stays selected (see the `live.microphone.mute_after_microphone_mute_seconds` to control how long after). Use an empty list (`[]`) to never automatically mute. Note that if `auto_play` is enabled, the stream may mute itself automatically in order to honor the `auto_play` setting, as some browsers will not auto play media that is unmuted -- that is to say, where necessary, the `auto_play` parameter will take priority over the `auto_mute` parameter. | +| `auto_pause` | `[]` | A list of conditions in which live camera feeds are automatically paused. `unselected` will automatically pause when a camera is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause. **Caution**: Some live providers (e.g. `jsmpeg`) may not offer human-accessible means to resume play if it is paused, unless the `auto_play` option is used. | +| `auto_play` | `[selected, visible]` | A list of conditions in which live camera feeds are automatically played.`selected` will automatically play when a camera is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play. Some live providers (e.g. `webrtc-card`, `jsmpeg`) do not support the prevention of automatic play on initial load, but should still respect the value of this flag on play-after-pause. | +| `auto_unmute` | `[microphone]` | A list of conditions in which live camera feeds are unmuted. `selected` will automatically unmute when a camera is unselected in the carousel, `visible` will automatically unmute when the browser/tab becomes visible or `microphone` will automatically unmute after the microphone is unmuted. Use an empty list (`[]`) to never automatically unmute. | +| `controls` | | Configuration for the `live` view controls. See below. | +| `display` | | Controls whether to show a single or grid `live` view. See below. | +| `draggable` | `true` | Whether or not the live carousel can be dragged left or right, via touch/swipe and mouse dragging. | +| `lazy_load` | `true` | Whether or not to lazily load cameras in the camera carousel. Setting this will `false` will cause all cameras to load simultaneously when the `live` carousel is opened (or cause all cameras to load continually if both `lazy_load` and `preload` are `true`). This will result in a smoother carousel experience at a cost of (potentially) a substantial amount of continually streamed data. | +| `lazy_unload` | `[]` | A list of conditions in which live camera feeds are unloaded. `unselected` will lazy-unload a camera when it is unselected in the carousel and `hidden` will lazy-unload all cameras when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically unload. This will cause a reloading delay on revisiting that camera in the carousel but will save the streaming network resources that are otherwise consumed. This option has no effect if `lazy_load` is false. Some live providers (e.g. `webrtc-card`) implement their own lazy unloading independently which may occur regardless of the value of this setting. | +| `microphone` | | See below. | +| `preload` | `false` | Whether or not to preload the live view. Preloading causes the live view to render in the background regardless of what view is actually shown, so it's instantly available when requested. This consumes additional network/CPU resources continually. | +| `show_image_during_load` | `true` | If `true`, during the initial stream load, the `image` live provider will be shown instead of the loading video stream. This still image will auto-refresh and is replaced with the live stream once loaded. | +| `transition_effect` | `slide` | Effect to apply as a transition between live cameras. Accepted values: `slide` or `none`. | +| `zoomable` | `true` | Whether or not the live carousel can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | ## `controls` @@ -31,17 +30,16 @@ Configure the controls for the `live` view. ```yaml live: - controls: - [...] + controls: [...] ``` -| Option | Default | Description | -| - | - | - | -| `builtin` | `true` | Whether to show the built in (browser) video controls on live video. | -| `next_previous` | | Configures how the "Next & Previous" controls are shown on the `live` view. See below. | -| `thumbnails` | | Configures how thumbnails are shown on the `live` view. See below. | -| `timeline` | | Configures how the mini-timeline is shown on the `live` view. See below. | -| `title` | | Configures how the camera title is shown on the `live` view. See below. | +| Option | Default | Description | +| --------------- | ------- | -------------------------------------------------------------------------------------- | +| `builtin` | `true` | Whether to show the built in (browser) video controls on live video. | +| `next_previous` | | Configures how the "Next & Previous" controls are shown on the `live` view. See below. | +| `thumbnails` | | Configures how thumbnails are shown on the `live` view. See below. | +| `timeline` | | Configures how the mini-timeline is shown on the `live` view. See below. | +| `title` | | Configures how the camera title is shown on the `live` view. See below. | ### `next_previous` @@ -50,13 +48,12 @@ Configures how the "Next & Previous" controls are shown on the live view. ```yaml live: controls: - next_previous: - [...] + next_previous: [...] ``` -| Option | Default | Description | -| - | - | - | -| `size` | `48` | The size of the next/previous controls in pixels. Must be >= `20`. | +| Option | Default | Description | +| ------- | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | +| `size` | `48` | The size of the next/previous controls in pixels. Must be >= `20`. | | `style` | `chevrons` | When viewing live cameras, what kind of controls to show to move to the previous/next camera. Acceptable values: `chevrons`, `icons`, `none` . | ### `ptz` @@ -66,19 +63,18 @@ Configures the PTZ (Pan Tilt Zoom) controls. ```yaml live: controls: - ptz: - [...] + ptz: [...] ``` -| Option | Default | Description | -| - | - | - | -| `hide_home` | `false` | When `true` the Home button of the control is hidden | -| `hide_pan_tilt` | `false` | When `true` the Pan & Tilt buttons of the control is hidden | -| `hide_zoom` | `false` | When `true` the Zoom button of the control is hidden | -| `mode` | `auto` | If `on` or `off` will always or never show PTZ controls respectively, if `auto` will show PTZ controls only if the camera supports real PTZ. | -| `orientation` | `horizontal` | Whether to show a `vertical` or `horizontal` PTZ control. | -| `position` | `bottom-right` | Whether to position the control on the `top-left`, `top-right`, `bottom-left` or `bottom-right`. This may be overridden by using the `style` parameter to precisely control placement. | -| `style` | | Optionally position and style the element using CSS. Similar to [Picture Element styling](https://www.home-assistant.io/dashboards/picture-elements/#how-to-use-the-style-object), except without any default, e.g. `left: 42%` | +| Option | Default | Description | +| --------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `hide_home` | `false` | When `true` the Home button of the control is hidden | +| `hide_pan_tilt` | `false` | When `true` the Pan & Tilt buttons of the control is hidden | +| `hide_zoom` | `false` | When `true` the Zoom button of the control is hidden | +| `mode` | `auto` | If `on` or `off` will always or never show PTZ controls respectively, if `auto` will show PTZ controls only if the camera supports real PTZ. | +| `orientation` | `horizontal` | Whether to show a `vertical` or `horizontal` PTZ control. | +| `position` | `bottom-right` | Whether to position the control on the `top-left`, `top-right`, `bottom-left` or `bottom-right`. This may be overridden by using the `style` parameter to precisely control placement. | +| `style` | | Optionally position and style the element using CSS. Similar to [Picture Element styling](https://www.home-assistant.io/dashboards/picture-elements/#how-to-use-the-style-object), except without any default, e.g. `left: 42%` | To configure the PTZ _actions_ taken for a particular camera, see [Camera PTZ Settings](./cameras/README.md?id=ptz). @@ -89,20 +85,19 @@ Configures how thumbnails are shown on the live view. ```yaml live: controls: - thumbnails: - [...] + thumbnails: [...] ``` -| Option | Default | Description | -| - | - | - | -| `events_media_type` | `all` | Whether to show `clips`, `snapshots` or `all` in the thumbnail carousel in the `live` view. This setting is only relevant when the `media_type` parameter is set to `events`.| -| `media_type` | `events` | Whether to load `events` or `recordings` media.| -| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| -| `show_details` | `false` | Whether to show event details (e.g. duration, start time, object detected, etc) alongside the thumbnail.| -| `show_download_control` | `true` | Whether to show the download control on each thumbnail.| -| `show_favorite_control` | `true` | Whether to show the favorite ('star') control on each thumbnail.| -| `show_timeline_control` | `true` | Whether to show the timeline ('target') control on each thumbnail.| -| `size` | `100` | The size of the thumbnails in the thumbnail carousel in pixels. Must be >= `75` and <= `175`. | +| Option | Default | Description | +| ----------------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `events_media_type` | `all` | Whether to show `clips`, `snapshots` or `all` in the thumbnail carousel in the `live` view. This setting is only relevant when the `media_type` parameter is set to `events`. | +| `media_type` | `events` | Whether to load `events` or `recordings` media. | +| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`). | +| `show_details` | `false` | Whether to show event details (e.g. duration, start time, object detected, etc) alongside the thumbnail. | +| `show_download_control` | `true` | Whether to show the download control on each thumbnail. | +| `show_favorite_control` | `true` | Whether to show the favorite ('star') control on each thumbnail. | +| `show_timeline_control` | `true` | Whether to show the timeline ('target') control on each thumbnail. | +| `size` | `100` | The size of the thumbnails in the thumbnail carousel in pixels. Must be >= `75` and <= `175`. | ### `timeline` @@ -111,19 +106,18 @@ Configures how the mini-timeline is shown on the live view. ```yaml live: controls: - timeline: - [...] + timeline: [...] ``` -| Option | Default | Description | -| - | - | - | -| `clustering_threshold` | `3` | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | -| `events_media_type` | `all` | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot.| -| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| -| `pan_mode` | `pan`| See [timeline pan mode](timeline-pan-mode.md). | -| `show_recordings` | `true` | Whether to show recordings on the timeline (specifically: which hours have any recorded content).| -| `style` | `ribbon` | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold`. | -| `window_seconds` | `3600` | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | +| Option | Default | Description | +| ---------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `clustering_threshold` | `3` | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | +| `events_media_type` | `all` | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot. | +| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`). | +| `pan_mode` | `pan` | See [timeline pan mode](timeline-pan-mode.md). | +| `show_recordings` | `true` | Whether to show recordings on the timeline (specifically: which hours have any recorded content). | +| `style` | `ribbon` | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold`. | +| `window_seconds` | `3600` | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | [](common/timeline-seek-info.md ':include') @@ -134,14 +128,13 @@ Configures how the camera title is shown on the live view. ```yaml live: controls: - title: - [...] + title: [...] ``` -| Option | Default | Description | -| - | - | - | -| `duration_seconds` | `2` | The number of seconds to display the title popup. `0` implies forever.| -| `mode` | `popup-bottom-right` | How to display the live camera title. Acceptable values: `none`, `popup-top-left`, `popup-top-right`, `popup-bottom-left`, `popup-bottom-right` . | +| Option | Default | Description | +| ------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | +| `duration_seconds` | `2` | The number of seconds to display the title popup. `0` implies forever. | +| `mode` | `popup-bottom-right` | How to display the live camera title. Acceptable values: `none`, `popup-top-left`, `popup-top-right`, `popup-bottom-left`, `popup-bottom-right` . | ## `display` @@ -149,16 +142,15 @@ Controls whether to show a single or grid `live` view. ```yaml live: - display: - [...] + display: [...] ``` -| Option | Default | Description | -| - | - | - | -| `grid_columns` | | If specified the grid will always have exactly this number of columns.| -| `grid_max_columns` | `4` | If specified, and `grid_columns` is not specified, the grid will not render more than this number of columns. The precise number will be calculated based on the [grid layout algorithm](grid-layout-algorithm.md). | -| `grid_selected_width_factor` | `2` | How much to scale up the selected media item in a grid. A value of `1` will not scale the selected item at all, the default value of `2` will scale the media item width to twice what it would otherwise be, etc. | -| `mode` | `single` | Whether to display a `single` live camera in a carousel, or all cameras in a `grid` configuration.| +| Option | Default | Description | +| ---------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `grid_columns` | | If specified the grid will always have exactly this number of columns. | +| `grid_max_columns` | `4` | If specified, and `grid_columns` is not specified, the grid will not render more than this number of columns. The precise number will be calculated based on the [grid layout algorithm](grid-layout-algorithm.md). | +| `grid_selected_width_factor` | `2` | How much to scale up the selected media item in a grid. A value of `1` will not scale the selected item at all, the default value of `2` will scale the media item width to twice what it would otherwise be, etc. | +| `mode` | `single` | Whether to display a `single` live camera in a carousel, or all cameras in a `grid` configuration. | ## `microphone` @@ -169,11 +161,11 @@ live: microphone: ``` -| Option | Default | Description | -| - | - | - | -| `always_connected` | `false` | Whether or not to keep the microphone stream continually connected while the card is running, or only when microphone is used (default). In the latter case there'll be a connection reset when the microphone is first used -- using this option can avoid that reset.| -| `disconnect_seconds` | `90` | The number of seconds after microphone usage to disconnect the microphone from the stream. `0` implies never. Not relevant if `always_connected` is `true`.| -| `mute_after_microphone_mute_seconds` | `60` | The number of seconds after the microphone mutes to automatically mute the inbound audio when `live.auto_mute` includes `microphone`.| +| Option | Default | Description | +| ------------------------------------ | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `always_connected` | `false` | Whether or not to keep the microphone stream continually connected while the card is running, or only when microphone is used (default). In the latter case there'll be a connection reset when the microphone is first used -- using this option can avoid that reset. | +| `disconnect_seconds` | `90` | The number of seconds after microphone usage to disconnect the microphone from the stream. `0` implies never. Not relevant if `always_connected` is `true`. | +| `mute_after_microphone_mute_seconds` | `60` | The number of seconds after the microphone mutes to automatically mute the inbound audio when `live.auto_mute` includes `microphone`. | See [Using 2-way audio](../usage/2-way-audio.md) for more information about the very particular requirements that must be followed for 2-way audio to work. diff --git a/docs/configuration/media-gallery.md b/docs/configuration/media-gallery.md index bd7a611b..34a6d4af 100644 --- a/docs/configuration/media-gallery.md +++ b/docs/configuration/media-gallery.md @@ -3,14 +3,13 @@ The `media_gallery` is used for providing an overview of all `clips`, `snapshots` and `recordings` in a thumbnail gallery. ```yaml -media_gallery: - [...] +media_gallery: [...] ``` -| Option | Default | Description | -| - | - | - | -| `actions` | | [Actions](actions/README.md) to use for all views that use the `media_gallery` (e.g. `clips`, `snapshots`, `recordings`). | -| `controls` | | Configuration for the Media viewer controls. See below. | +| Option | Default | Description | +| ---------- | ------- | ------------------------------------------------------------------------------------------------------------------------- | +| `actions` | | [Actions](actions/README.md) to use for all views that use the `media_gallery` (e.g. `clips`, `snapshots`, `recordings`). | +| `controls` | | Configuration for the Media viewer controls. See below. | ## `controls` @@ -21,12 +20,11 @@ Configure the media gallery filter. ```yaml media_gallery: controls: - filter: - [...] + filter: [...] ``` -| Option | Default | Description | -| - | - | - | +| Option | Default | Description | +| ------ | ------- | ----------------------------------------------------------------------------------------------------- | | `mode` | `right` | Whether to show the gallery media filter to the `left`, to the `right` or `none` for no media filter. | ### `thumbnails` @@ -36,17 +34,16 @@ Configure the media gallery thumbnails. ```yaml media_gallery: controls: - thumbnails: - [...] + thumbnails: [...] ``` -| Option | Default | Description | -| - | - | - | -| `show_details` | `false` | Whether to show media details (e.g. duration, start time, object detected, etc) alongside the thumbnail.| -| `show_download_control` | `true` | Whether to show the download control on each thumbnail.| -| `show_favorite_control` | `true` | Whether to show the favorite ('star') control on each thumbnail.| -| `show_timeline_control` | `true` | Whether to show the timeline ('target') control on each thumbnail.| -| `size` | `100` | The size of the thumbnails in the gallery. Must be >= `75` and <= `175`.| +| Option | Default | Description | +| ----------------------- | ------- | -------------------------------------------------------------------------------------------------------- | +| `show_details` | `false` | Whether to show media details (e.g. duration, start time, object detected, etc) alongside the thumbnail. | +| `show_download_control` | `true` | Whether to show the download control on each thumbnail. | +| `show_favorite_control` | `true` | Whether to show the favorite ('star') control on each thumbnail. | +| `show_timeline_control` | `true` | Whether to show the timeline ('target') control on each thumbnail. | +| `size` | `100` | The size of the thumbnails in the gallery. Must be >= `75` and <= `175`. | ## Fully expanded reference diff --git a/docs/configuration/media-viewer.md b/docs/configuration/media-viewer.md index 751efaba..beb3e800 100644 --- a/docs/configuration/media-viewer.md +++ b/docs/configuration/media-viewer.md @@ -3,23 +3,22 @@ The `media_player` section configures viewing all `clip`, `snapshot` or `recording` media, in either a media carousel or grid. ```yaml -media_viewer: - [...] +media_viewer: [...] ``` -| Option | Default | Description | -| - | - | - | -| `actions` | | [Actions](actions/README.md) to use for all views that use the `media_viewer` (e.g. `clip`, `snapshot`). | -| `auto_mute` | `[unselected, hidden]` | A list of conditions in which media items are muted. `unselected` will automatically mute when a media item is unselected in the carousel and `hidden` will automatically mute when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically mute.| -| `auto_pause` | `[unselected, hidden]` | A list of conditions in which media items are automatically paused. `unselected` will automatically pause when a media item is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause.| -| `auto_play` | `[selected, visible]` | A list of conditions in which media items are automatically played.`selected` will automatically play when a media item is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play.| -| `auto_unmute` | `[]` | A list of conditions in which media items are unmuted. `selected` will automatically unmute when a media item is unselected in the carousel and `visible` will automatically unmute when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically unmute. Note that some browsers will not allow automated unmute until the user has interacted with the page in some way -- if the user has not then the browser may pause the media instead.| -| `controls` | | Configuration for the Media viewer controls. See below. | -| `draggable` | `true` | Whether or not the Media viewer carousel can be dragged left or right, via touch/swipe and mouse dragging. | -| `lazy_load` | `true` | Whether or not to lazily load media in the Media viewer carousel. Setting this will false will fetch all media immediately which may make the carousel experience smoother at a cost of (potentially) a substantial number of simultaneous media fetches on load. | -| `snapshot_click_plays_clip` | `true` | Whether clicking on a snapshot in the media viewer should play a related clip. | -| `transition_effect` | `slide` | Effect to apply as a transition between event media. Accepted values: `slide` or `none`. | -| `zoomable` | `true` | Whether or not the Media Viewer can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | +| Option | Default | Description | +| --------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `actions` | | [Actions](actions/README.md) to use for all views that use the `media_viewer` (e.g. `clip`, `snapshot`). | +| `auto_mute` | `[unselected, hidden]` | A list of conditions in which media items are muted. `unselected` will automatically mute when a media item is unselected in the carousel and `hidden` will automatically mute when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically mute. | +| `auto_pause` | `[unselected, hidden]` | A list of conditions in which media items are automatically paused. `unselected` will automatically pause when a media item is unselected in the carousel and `hidden` will automatically pause when the browser/tab becomes hidden. Use an empty list (`[]`) to never automatically pause. | +| `auto_play` | `[selected, visible]` | A list of conditions in which media items are automatically played.`selected` will automatically play when a media item is selected in the carousel and `visible` will automatically play when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically play. | +| `auto_unmute` | `[]` | A list of conditions in which media items are unmuted. `selected` will automatically unmute when a media item is unselected in the carousel and `visible` will automatically unmute when the browser/tab becomes visible. Use an empty list (`[]`) to never automatically unmute. Note that some browsers will not allow automated unmute until the user has interacted with the page in some way -- if the user has not then the browser may pause the media instead. | +| `controls` | | Configuration for the Media viewer controls. See below. | +| `draggable` | `true` | Whether or not the Media viewer carousel can be dragged left or right, via touch/swipe and mouse dragging. | +| `lazy_load` | `true` | Whether or not to lazily load media in the Media viewer carousel. Setting this will false will fetch all media immediately which may make the carousel experience smoother at a cost of (potentially) a substantial number of simultaneous media fetches on load. | +| `snapshot_click_plays_clip` | `true` | Whether clicking on a snapshot in the media viewer should play a related clip. | +| `transition_effect` | `slide` | Effect to apply as a transition between event media. Accepted values: `slide` or `none`. | +| `zoomable` | `true` | Whether or not the Media Viewer can be zoomed and panned, via touch/pinch and mouse scroll wheel with `ctrl` held. | ## `controls` @@ -27,17 +26,16 @@ Configure the controls for the media player views. ```yaml media_viewer: - controls: - [...] + controls: [...] ``` -| Option | Default | Description | -| - | - | - | -| `builtin` | `true` | Whether to show the built in (browser) video controls on media viewer videos. | -| `next_previous` | | Configures how the "Next & Previous" controls are shown on the media viewer. See below. | -| `thumbnails` | | Configures how thumbnails are shown on the media viewer. See below. | -| `timeline` | | Configures how the mini-timeline is shown on the media viewer. See below. | -| `title` | | Configures how the media title is shown on the media viewer. See below. | +| Option | Default | Description | +| --------------- | ------- | --------------------------------------------------------------------------------------- | +| `builtin` | `true` | Whether to show the built in (browser) video controls on media viewer videos. | +| `next_previous` | | Configures how the "Next & Previous" controls are shown on the media viewer. See below. | +| `thumbnails` | | Configures how thumbnails are shown on the media viewer. See below. | +| `timeline` | | Configures how the mini-timeline is shown on the media viewer. See below. | +| `title` | | Configures how the media title is shown on the media viewer. See below. | ### `next_previous` @@ -46,13 +44,12 @@ Configures how the "Next & Previous" controls are shown on the media viewer. ```yaml media_viewer: controls: - next_previous: - [...] + next_previous: [...] ``` -| Option | Default | Description | -| - | - | - | -| `size` | `48` | The size of the next/previous controls in pixels. Must be >= `20`.| +| Option | Default | Description | +| ------- | ------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| `size` | `48` | The size of the next/previous controls in pixels. Must be >= `20`. | | `style` | `thumbnails` | When viewing media, what kind of controls to show to move to the previous/next media item. Acceptable values: `thumbnails`, `chevrons`, `none` . | ### `ptz` @@ -64,19 +61,18 @@ real) panning and zooming. ```yaml media_viewer: controls: - ptz: - [...] + ptz: [...] ``` -| Option | Default | Description | -| - | - | - | -| `hide_home` | `false` | When `true` the Home button of the control is hidden | -| `hide_pan_tilt` | `false` | When `true` the Pan & Tilt buttons of the control is hidden | -| `hide_zoom` | `false` | When `true` the Zoom button of the control is hidden | -| `mode` | `off` | If `on` or `off` will always or never show PTZ controls respectively. | -| `orientation` | `horizontal` | Whether to show a `vertical` or `horizontal` PTZ control. | -| `position` | `bottom-right` | Whether to position the control on the `top-left`, `top-right`, `bottom-left` or `bottom-right`. This may be overridden by using the `style` parameter to precisely control placement. | -| `style` | | Optionally position and style the element using CSS. Similar to [Picture Element styling](https://www.home-assistant.io/dashboards/picture-elements/#how-to-use-the-style-object), except without any default, e.g. `left: 42%` | +| Option | Default | Description | +| --------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `hide_home` | `false` | When `true` the Home button of the control is hidden | +| `hide_pan_tilt` | `false` | When `true` the Pan & Tilt buttons of the control is hidden | +| `hide_zoom` | `false` | When `true` the Zoom button of the control is hidden | +| `mode` | `off` | If `on` or `off` will always or never show PTZ controls respectively. | +| `orientation` | `horizontal` | Whether to show a `vertical` or `horizontal` PTZ control. | +| `position` | `bottom-right` | Whether to position the control on the `top-left`, `top-right`, `bottom-left` or `bottom-right`. This may be overridden by using the `style` parameter to precisely control placement. | +| `style` | | Optionally position and style the element using CSS. Similar to [Picture Element styling](https://www.home-assistant.io/dashboards/picture-elements/#how-to-use-the-style-object), except without any default, e.g. `left: 42%` | ### `thumbnails` @@ -85,18 +81,17 @@ Configures how thumbnails are shown on the media viewer. ```yaml media_viewer: controls: - thumbnails: - [...] + thumbnails: [...] ``` -| Option | Default | Description | -| - | - | - | -| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| -| `show_details` | `false` | Whether to show event details (e.g. duration, start time, object detected, etc) alongside the thumbnail.| -| `show_download_control` | `true` | Whether to show the download control on each thumbnail.| -| `show_favorite_control` | `true` | Whether to show the favorite ('star') control on each thumbnail.| -| `show_timeline_control` | `true` | Whether to show the timeline ('target') control on each thumbnail.| -| `size` | `100` | The size of the thumbnails in the thumbnail carousel pixels. Must be >= `75` and <= `175`.| +| Option | Default | Description | +| ----------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`). | +| `show_details` | `false` | Whether to show event details (e.g. duration, start time, object detected, etc) alongside the thumbnail. | +| `show_download_control` | `true` | Whether to show the download control on each thumbnail. | +| `show_favorite_control` | `true` | Whether to show the favorite ('star') control on each thumbnail. | +| `show_timeline_control` | `true` | Whether to show the timeline ('target') control on each thumbnail. | +| `size` | `100` | The size of the thumbnails in the thumbnail carousel pixels. Must be >= `75` and <= `175`. | ### `timeline` @@ -105,19 +100,18 @@ Configures how the mini-timeline is shown on the media viewer. ```yaml media_viewer: controls: - timeline: - [...] + timeline: [...] ``` -| Option | Default | Description | -| - | - | - | -| `clustering_threshold` | `3` | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | -| `events_media_type` | `all` | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot. | -| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| -| `pan_mode` | `pan`| See [timeline pan mode](timeline-pan-mode.md). | -| `show_recordings` | `true` | Whether to show recordings on the timeline (specifically: which hours have any recorded content).| -| `style` | `ribbon` | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold`. | -| `window_seconds` | `3600` | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | +| Option | Default | Description | +| ---------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `clustering_threshold` | `3` | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | +| `events_media_type` | `all` | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot. | +| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`). | +| `pan_mode` | `pan` | See [timeline pan mode](timeline-pan-mode.md). | +| `show_recordings` | `true` | Whether to show recordings on the timeline (specifically: which hours have any recorded content). | +| `style` | `ribbon` | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold`. | +| `window_seconds` | `3600` | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | [](common/timeline-seek-info.md ':include') @@ -128,14 +122,13 @@ Configures how the media title is shown on the media viewer. ```yaml media_viewer: controls: - title: - [...] + title: [...] ``` -| Option | Default | Description | -| - | - | - | -| `duration_seconds` | `2` | The number of seconds to display the title popup. `0` implies forever.| -| `mode` | `popup-bottom-right` | How to display the Media viewer media title. Acceptable values: `none`, `popup-top-left`, `popup-top-right`, `popup-bottom-left`, `popup-bottom-right` . | +| Option | Default | Description | +| ------------------ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `duration_seconds` | `2` | The number of seconds to display the title popup. `0` implies forever. | +| `mode` | `popup-bottom-right` | How to display the Media viewer media title. Acceptable values: `none`, `popup-top-left`, `popup-top-right`, `popup-bottom-left`, `popup-bottom-right` . | ## `display` @@ -143,16 +136,15 @@ Controls whether to show a single media item or grid in the media viewer. ```yaml media_viewer: - display: - [...] + display: [...] ``` -| Option | Default | Description | -| - | - | - | -| `grid_columns` | | If specified the grid will always have exactly this number of columns.| -| `grid_max_columns` | `4` | If specified, and `grid_columns` is not specified, the grid will not render more than this number of columns. The precise number will be calculated based on the [grid layout algorithm](grid-layout-algorithm.md). | -| `grid_selected_width_factor` | `2` | How much to scale up the selected media item in a grid. A value of `1` will not scale the selected item at all, the default value of `2` will scale the media item width to twice what it would otherwise be, etc. | -| `mode` | `single` | Whether to display a `single` media item at a time, or a media item for all cameras in a `grid` configuration.| +| Option | Default | Description | +| ---------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `grid_columns` | | If specified the grid will always have exactly this number of columns. | +| `grid_max_columns` | `4` | If specified, and `grid_columns` is not specified, the grid will not render more than this number of columns. The precise number will be calculated based on the [grid layout algorithm](grid-layout-algorithm.md). | +| `grid_selected_width_factor` | `2` | How much to scale up the selected media item in a grid. A value of `1` will not scale the selected item at all, the default value of `2` will scale the media item width to twice what it would otherwise be, etc. | +| `mode` | `single` | Whether to display a `single` media item at a time, or a media item for all cameras in a `grid` configuration. | ## Fully expanded reference diff --git a/docs/configuration/menu.md b/docs/configuration/menu.md index 7c956cb2..c332f13d 100644 --- a/docs/configuration/menu.md +++ b/docs/configuration/menu.md @@ -2,18 +2,17 @@ Configures how the card menu behaves. - ```yaml -menu: - [...] +```yaml +menu: [...] ``` -| Option | Default | Description | -| - | - | - | -| `alignment` | `left` | Whether to align the menu buttons to the `left`, `right`, `top` or `bottom` of the menu. Some selections may have no effect depending on the value of `position` (e.g. it doesn't make sense to `left` align icons on a menu with `position` to the `left`).| -| `button_size` | `40` | The size of the menu buttons in pixels. Must be >= `20`.| -| `buttons` | | Whether to show or hide built-in buttons. See below. | -| `position` | `top` | Whether to show the menu on the `left`, `right`, `top` or `bottom` side of the card. Note that for the `outside` style only the `top` and `bottom` positions have an effect.| -| `style` | `hidden` | The menu style to show by default, one of `none`, `hidden`, `hover`, `hover-card`, `overlay`, or `outside`. See below. | +| Option | Default | Description | +| ------------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `alignment` | `left` | Whether to align the menu buttons to the `left`, `right`, `top` or `bottom` of the menu. Some selections may have no effect depending on the value of `position` (e.g. it doesn't make sense to `left` align icons on a menu with `position` to the `left`). | +| `button_size` | `40` | The size of the menu buttons in pixels. Must be >= `20`. | +| `buttons` | | Whether to show or hide built-in buttons. See below. | +| `position` | `top` | Whether to show the menu on the `left`, `right`, `top` or `bottom` side of the card. Note that for the `outside` style only the `top` and `bottom` positions have an effect. | +| `style` | `hidden` | The menu style to show by default, one of `none`, `hidden`, `hover`, `hover-card`, `overlay`, or `outside`. See below. | ## `buttons` @@ -22,54 +21,53 @@ All configuration is under: ```yaml menu: buttons: - [button]: - [...] + [button]: [...] ``` ### Available Buttons -| Button name | Description | -| - | - | -| `camera_ui` | The `camera_ui` menu button: brings the user to a context-appropriate page on the UI of their camera engine (e.g. the Frigate camera homepage). Will only appear if the camera engine supports a camera UI (e.g. if `frigate.url` option is set for `frigate` engine users).| -| `cameras` | The camera selection submenu. Will only appear if multiple cameras are configured. | -| `clips` | The `clips` view menu button: brings the user to the `clips` view on tap and the most-recent `clip` view on hold. | -| `display_mode` | The `display_mode` button allows changing between single and grid views. | -| `download` | The `download` menu button: allow direct download of the media being displayed.| -| `expand` | The `expand` menu button: expand the card into a popup/dialog. | -| `frigate` | The `Frigate` menu button: brings the user to the default configured view (`view.default`), or collapses/expands the menu if the `menu.style` is `hidden` . | -| `fullscreen` | The `fullscreen` menu button: expand the card to consume the fullscreen. | -| `image` | The `image` view menu button: brings the user to the static `image` view. | -| `live` | The `live` view menu button: brings the user to the `live` view. | +| Button name | Description | +| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `camera_ui` | The `camera_ui` menu button: brings the user to a context-appropriate page on the UI of their camera engine (e.g. the Frigate camera homepage). Will only appear if the camera engine supports a camera UI (e.g. if `frigate.url` option is set for `frigate` engine users). | +| `cameras` | The camera selection submenu. Will only appear if multiple cameras are configured. | +| `clips` | The `clips` view menu button: brings the user to the `clips` view on tap and the most-recent `clip` view on hold. | +| `display_mode` | The `display_mode` button allows changing between single and grid views. | +| `download` | The `download` menu button: allow direct download of the media being displayed. | +| `expand` | The `expand` menu button: expand the card into a popup/dialog. | +| `frigate` | The `Frigate` menu button: brings the user to the default configured view (`view.default`), or collapses/expands the menu if the `menu.style` is `hidden` . | +| `fullscreen` | The `fullscreen` menu button: expand the card to consume the fullscreen. | +| `image` | The `image` view menu button: brings the user to the static `image` view. | +| `live` | The `live` view menu button: brings the user to the `live` view. | | `media_player` | The `media_player` menu button: sends the visible media to a remote media player. Supports Frigate clips, snapshots and live camera (only for cameras that specify a `camera_entity` and only using the default HA stream (equivalent to the `ha` live provider)). `jsmpeg` or `webrtc-card` are not supported, although live can still be played as long as `camera_entity` is specified. In the player list, a `tap` will send the media to the player, a `hold` will stop the media on the player. | -| `microphone` | The `microphone` button allows usage of 2-way audio in certain configurations. See [Using 2-way audio](../usage/2-way-audio.md). | -| `ptz_controls` | The `ptz_controls` button shows or hides the PTZ controls. | -| `ptz_home` | The `ptz_home` button allows easily returning the camera to default home position. | -| `recordings` | The `recordings` view menu button: brings the user to the `recordings` view on tap and the most-recent `recording` view on hold. | -| `screenshot` | The `screenshot` menu button: take a screenshot of the loaded media (e.g. a still from a video). | -| `snapshots` | The `snapshots` view menu button: brings the user to the `clips` view on tap and the most-recent `snapshot` view on hold. | -| `timeline` | The `timeline` menu button: show the event timeline. | +| `microphone` | The `microphone` button allows usage of 2-way audio in certain configurations. See [Using 2-way audio](../usage/2-way-audio.md). | +| `ptz_controls` | The `ptz_controls` button shows or hides the PTZ controls. | +| `ptz_home` | The `ptz_home` button allows easily returning the camera to default home position. | +| `recordings` | The `recordings` view menu button: brings the user to the `recordings` view on tap and the most-recent `recording` view on hold. | +| `screenshot` | The `screenshot` menu button: take a screenshot of the loaded media (e.g. a still from a video). | +| `snapshots` | The `snapshots` view menu button: brings the user to the `clips` view on tap and the most-recent `snapshot` view on hold. | +| `timeline` | The `timeline` menu button: show the event timeline. | ### Options for each button -| Option | Default | Description | -| - | - | - | -| `alignment` | `matching` | Whether this button should have an alignment that is `matching` the menu alignment or `opposing` the menu. Can be used to create two separate groups of buttons on the menu. `priority` orders buttons within a given `alignment`. | -| `enabled` | `true` for `frigate`, `cameras`, `substreams`, `live`, `clips`, `snapshots`, `timeline`, `download`, `camera_ui`, `fullscreen`, `media_player`, `display_mode` and `ptz_home`. `false` for `image`, `expand`, `microphone`, `mute`, `play`, `recordings`, `screenshot`, `ptz_controls` | Whether or not to show the button. | -| `icon` | | An icon to overriding the default for that button, e.g. `mdi:camera-front`. | -| `priority` | `50` | The button priority. Higher priority buttons are ordered closer to the start of the menu alignment (i.e. a button with priority `70` will order further to the left than a button with priority `60`, when the menu alignment is `left`). Minimum `0`, maximum `100`.| +| Option | Default | Description | +| ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `alignment` | `matching` | Whether this button should have an alignment that is `matching` the menu alignment or `opposing` the menu. Can be used to create two separate groups of buttons on the menu. `priority` orders buttons within a given `alignment`. | +| `enabled` | `true` for `frigate`, `cameras`, `substreams`, `live`, `clips`, `snapshots`, `timeline`, `download`, `camera_ui`, `fullscreen`, `media_player`, `display_mode` and `ptz_home`. `false` for `image`, `expand`, `microphone`, `mute`, `play`, `recordings`, `screenshot`, `ptz_controls` | Whether or not to show the button. | +| `icon` | | An icon to overriding the default for that button, e.g. `mdi:camera-front`. | +| `priority` | `50` | The button priority. Higher priority buttons are ordered closer to the start of the menu alignment (i.e. a button with priority `70` will order further to the left than a button with priority `60`, when the menu alignment is `left`). Minimum `0`, maximum `100`. | ## `style` This card supports several menu styles. -| Key | Description | Screenshot | -| - | - | - | -|`hidden`| Hide the menu by default, expandable upon clicking the Frigate button. | ![](../images/menu-mode-hidden.png "Menu hidden :size=400") | -|`hover-card`| Overlay the menu over the card contents when the mouse is over the **card**, otherwise it is not shown. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png "Menu hover-card :size=400") | -|`hover`| Overlay the menu over the card contents when the mouse is over the **menu**, otherwise it is not shown. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png "Menu hover :size=400") | -|`none`| No menu is shown. | ![](../images/menu-mode-none.png "No menu :size=400") | -|`outside`| Render the menu outside the card (i.e. above it if `position` is `top`, or below it if `position` is `bottom`). The Frigate button shows the default view. | ![](../images/menu-mode-above.png "Menu outside :size=400") | -|`overlay`| Overlay the menu over the card contents. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png "Menu hidden :size=400") | +| Key | Description | Screenshot | +| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- | +| `hidden` | Hide the menu by default, expandable upon clicking the Frigate button. | ![](../images/menu-mode-hidden.png 'Menu hidden :size=400') | +| `hover-card` | Overlay the menu over the card contents when the mouse is over the **card**, otherwise it is not shown. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png 'Menu hover-card :size=400') | +| `hover` | Overlay the menu over the card contents when the mouse is over the **menu**, otherwise it is not shown. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png 'Menu hover :size=400') | +| `none` | No menu is shown. | ![](../images/menu-mode-none.png 'No menu :size=400') | +| `outside` | Render the menu outside the card (i.e. above it if `position` is `top`, or below it if `position` is `bottom`). The Frigate button shows the default view. | ![](../images/menu-mode-above.png 'Menu outside :size=400') | +| `overlay` | Overlay the menu over the card contents. The Frigate button shows the default view. | ![](../images/menu-mode-overlay.png 'Menu hidden :size=400') | ## Fully expanded reference diff --git a/docs/configuration/overrides.md b/docs/configuration/overrides.md index d0c70375..ace180ad 100644 --- a/docs/configuration/overrides.md +++ b/docs/configuration/overrides.md @@ -15,12 +15,12 @@ overrides: The top-level `overrides` configuration block expects a list, with each list item containing `conditions` and at least one of `merge`, `delete` or `set` specified. -| Option | Default | Description | -| - | - | - | -| `conditions` | | A list of [conditions](conditions.md) that must evaluate to `true` in order for the overrides to be applied. | -| `delete` | | An array of configuration paths to delete. See below. | -| `merge` | | A dictionary of configuration paths to merge. See below. | -| `set` | | A dictionary of configuration paths to set. See below. | +| Option | Default | Description | +| ------------ | ------- | ------------------------------------------------------------------------------------------------------------ | +| `conditions` | | A list of [conditions](conditions.md) that must evaluate to `true` in order for the overrides to be applied. | +| `delete` | | An array of configuration paths to delete. See below. | +| `merge` | | A dictionary of configuration paths to merge. See below. | +| `set` | | A dictionary of configuration paths to set. See below. | ## Configuration Paths @@ -42,11 +42,10 @@ An array of configuration paths to delete. ```yaml overrides: - - conditions: - [condition] + - conditions: [condition] delete: - - [path_1] - - [path_2] + - [path_1] + - [path_2] ``` ### Examples @@ -55,29 +54,25 @@ Delete the 2nd camera: ```yaml overrides: - - conditions: - [condition] - delete: - 'cameras[2]' + - conditions: [condition] + delete: 'cameras[2]' ``` Delete the menu style parameter, thus falling back to the default: ```yaml overrides: - - conditions: - [condition] - delete: - 'menu.style' + - conditions: [condition] + delete: 'menu.style' ``` ## `merge` -Specifies an object to recursively merge into existing configuration. +Specifies an object to recursively merge into existing configuration. -| Option | Default | Description | -| - | - | - | -| [configuration path] | | Arbitrary configuration object to merge. Must be an object (i.e. not a literal value). | +| Option | Default | Description | +| -------------------- | ------- | -------------------------------------------------------------------------------------- | +| [configuration path] | | Arbitrary configuration object to merge. Must be an object (i.e. not a literal value). | ### Examples @@ -85,49 +80,36 @@ Hide the menu when a given condition is met: ```yaml overrides: - - conditions: - [condition] + - conditions: [condition] merge: - menu: { - style: 'hidden' - } + menu: { style: 'hidden' } ``` Enable thumbnails below the `live` feed: ```yaml overrides: - - conditions: - [condition] + - conditions: [condition] merge: - 'live.controls.thumbnails': { - mode: 'below' - } + 'live.controls.thumbnails': { mode: 'below' } ``` Also enables thumbnails below the `live` feed, but without using the dot-separated notation: ```yaml overrides: - - conditions: - [condition] + - conditions: [condition] merge: - live: { - controls: { - thumbnails: { - mode: 'below' - } - } - } + live: { controls: { thumbnails: { mode: 'below' } } } ``` ## `set` Specifies a value to set in the configuration. This differs from `merge` in that the existing value is entirely replaced. -| Option | Default | Description | -| - | - | - | -| [configuration path] | | Arbitrary configuration value / object / list to set. | +| Option | Default | Description | +| -------------------- | ------- | ----------------------------------------------------- | +| [configuration path] | | Arbitrary configuration value / object / list to set. | ### Examples @@ -135,20 +117,16 @@ Set the entire menu configuration to defaults with the exception of the `style` ```yaml overrides: - - conditions: - [condition] + - conditions: [condition] set: - menu: { - style: 'overlay' - } + menu: { style: 'overlay' } ``` Set the menu style but without touching the other `menu` parameters: ```yaml overrides: - - conditions: - [condition] + - conditions: [condition] set: 'menu.style': 'overlay' ``` @@ -157,10 +135,7 @@ That is equivalent to merging the following: ```yaml overrides: - - conditions: - [condition] + - conditions: [condition] merge: - menu: { - style: 'overlay' - } -``` \ No newline at end of file + menu: { style: 'overlay' } +``` diff --git a/docs/configuration/performance.md b/docs/configuration/performance.md index a83b922a..f7ec210d 100644 --- a/docs/configuration/performance.md +++ b/docs/configuration/performance.md @@ -3,14 +3,13 @@ Configure the card performance settings to enable the card to run (more) smoothly on lower end devices. ```yaml -performance: - [...] +performance: [...] ``` -| Option | Default | Description | -| - | - | - | -| `features` | | Configure feature settings that impact performance. | -| `style` | | Configure style settings that impact performance. | +| Option | Default | Description | +| ---------- | ------- | --------------------------------------------------- | +| `features` | | Configure feature settings that impact performance. | +| `style` | | Configure style settings that impact performance. | ### `features` @@ -18,14 +17,13 @@ Controls card-wide functionality that may impact performance. ```yaml performance: - features: - [...] + features: [...] ``` -| Option | Default | Description | -| - | - | - | -| `animated_progress_indicator` | `true` | Will show the animated progress indicator 'spinner' when `true` or a simple loading icon when `false`.| -| `media_chunk_size` | `50` | How many media items to fetch and render at a time (e.g. thumbnails under a live view, or number of snapshots to load in the media viewer). This may only make partial sense in some contexts (e.g. the 'infinite gallery' is still infinite, it just loads thumbnails this many items at a time) or not at all (e.g. the timeline will show the number of events dictated by the time span the user navigates to).| +| Option | Default | Description | +| ----------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `animated_progress_indicator` | `true` | Will show the animated progress indicator 'spinner' when `true` or a simple loading icon when `false`. | +| `media_chunk_size` | `50` | How many media items to fetch and render at a time (e.g. thumbnails under a live view, or number of snapshots to load in the media viewer). This may only make partial sense in some contexts (e.g. the 'infinite gallery' is still infinite, it just loads thumbnails this many items at a time) or not at all (e.g. the timeline will show the number of events dictated by the time span the user navigates to). | ### `style` @@ -37,14 +35,13 @@ shadows on timeline items, or curves in the media gallery items). ```yaml performance: - style: - [...] + style: [...] ``` -| Option | Default | Description | -| - | - | - | -| `border_radius` | `true` | If `false` minimizes the usage of rounded corners.| -| `box_shadow` | `true` | If `false` minimizes the usage of shadows.| +| Option | Default | Description | +| --------------- | ------- | -------------------------------------------------- | +| `border_radius` | `true` | If `false` minimizes the usage of rounded corners. | +| `box_shadow` | `true` | If `false` minimizes the usage of shadows. | ### The `low-performance` profile @@ -62,4 +59,4 @@ performance: style: border_radius: true box_shadow: true -``` \ No newline at end of file +``` diff --git a/docs/configuration/profiles.md b/docs/configuration/profiles.md index 00aac819..287e7e07 100644 --- a/docs/configuration/profiles.md +++ b/docs/configuration/profiles.md @@ -14,10 +14,10 @@ the user. ?> Profiles are applied top to bottom. If multiple profiles change a configuration default, then the last one "wins" -| Profile name | Purpose | -| - | - | +| Profile name | Purpose | +| ----------------- | -------------------------- | | `low-performance` | Increase card performance. | -| `scrubbing` | Allow media "scrubbing". | +| `scrubbing` | Allow media "scrubbing". | ## `low-performance` @@ -25,8 +25,8 @@ For low end devices, the `low-performance` profile will adjust card defaults to Principles used in the selection of options set by `low-profile` profile mode: -* Get 'out of the box' performance similar to the basic "Home Assistant Picture Glance" card. -* Do not break the visual aesthetic of the card. +- Get 'out of the box' performance similar to the basic "Home Assistant Picture Glance" card. +- Do not break the visual aesthetic of the card. See the [source code](https://github.com/dermotduffy/frigate-hass-card/blob/dev/src/config/profiles/low-performance.ts) for an exhaustive list of options set by this profile. @@ -44,4 +44,4 @@ See the [source code](https://github.com/dermotduffy/frigate-hass-card/blob/dev/ profiles: - low-performance - scrubbing -``` \ No newline at end of file +``` diff --git a/docs/configuration/timeline-pan-mode.md b/docs/configuration/timeline-pan-mode.md index 160e1cba..be7fbd86 100644 --- a/docs/configuration/timeline-pan-mode.md +++ b/docs/configuration/timeline-pan-mode.md @@ -2,9 +2,9 @@ The behavior of the timeline during seeking/dragging can be controlled by means of the icon on the bottom-right of the timeline, or by using the `pan_mode` configuration variable for the relevant timeline controls (e.g. `live.controls.timeline.pan_mode`). -| Configuration name | UI Icon | Behavior | -| - | - | - | -| `pan`| pan-horizontal | Dragging the timeline will pan only without selected or seeking any media. | -| `seek-in-camera` | camera-lock | Dragging the timeline will seek / select across all available media from the selected camera only, selecting the media item with the longest duration. | -| `seek-in-media` | play-box-lock | Dragging the timeline will seek within the selected media item only. | -| `seek` | filmstrip-box-multiple | Dragging the timeline will seek / select across all available media from all cameras, selecting the media item with the longest duration whilst favoring (but not limited to) the currently selected camera. | +| Configuration name | UI Icon | Behavior | +| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `pan` | pan-horizontal | Dragging the timeline will pan only without selected or seeking any media. | +| `seek-in-camera` | camera-lock | Dragging the timeline will seek / select across all available media from the selected camera only, selecting the media item with the longest duration. | +| `seek-in-media` | play-box-lock | Dragging the timeline will seek within the selected media item only. | +| `seek` | filmstrip-box-multiple | Dragging the timeline will seek / select across all available media from all cameras, selecting the media item with the longest duration whilst favoring (but not limited to) the currently selected camera. | diff --git a/docs/configuration/timeline.md b/docs/configuration/timeline.md index 3edea8d7..cb9b0ea8 100644 --- a/docs/configuration/timeline.md +++ b/docs/configuration/timeline.md @@ -4,24 +4,23 @@ Configures a `timeline` view used to show the timing sequence of events and recordings across multiple cameras. ```yaml -timeline: - [...] +timeline: [...] ``` You can interact with the timeline in a number of ways: -* Clicking on an event will take you to the media viewer for that event. -* Clicking on the "background", or a camera title, will take you to the recordings for that camera (seeking to the clicked time). -* Clicking on the time axis will take you to recordings for all cameras (seeking to the clicked time). +- Clicking on an event will take you to the media viewer for that event. +- Clicking on the "background", or a camera title, will take you to the recordings for that camera (seeking to the clicked time). +- Clicking on the time axis will take you to recordings for all cameras (seeking to the clicked time). -| Option | Default | Description | -| - | - | - | -| `clustering_threshold` | `3` | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | -| `controls` | | Configuration for the timeline controls. See below. | -| `events_media_type` | `all` | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot.| -| `show_recordings` | `true` | Whether to show recordings on the timeline (specifically: which hours have any recorded content).| -| `style` | `stack` | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold`. | -| `window_seconds` | `3600` | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | +| Option | Default | Description | +| ---------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `clustering_threshold` | `3` | The minimum number of overlapping events to allow prior to clustering/grouping them. Higher numbers cause clustering to happen less frequently. Depending on the timescale/zoom of the timeline, the underlying timeline library may still allow overlaps for low values of this parameter -- for a fully "flat" timeline use the `ribbon` style. `0` disables clustering entirely. Only used in the `stack` style of timeline. | +| `controls` | | Configuration for the timeline controls. See below. | +| `events_media_type` | `all` | Whether to show only events with `clips`, events with `snapshots` or `all` events. When `all` is used, `clips` are favored for events that have both a clip and a snapshot. | +| `show_recordings` | `true` | Whether to show recordings on the timeline (specifically: which hours have any recorded content). | +| `style` | `stack` | Whether the timeline should show events as a single flat `ribbon` or a `stack` of events that are clustered using the `clustering_threshold`. | +| `window_seconds` | `3600` | The length of the default timeline in seconds. By default, 1 hour (`3600` seconds) is shown in the timeline. | ## `controls` @@ -29,13 +28,12 @@ Configure the controls for the `timeline` view. ```yaml timeline: - controls: - [...] + controls: [...] ``` -| Option | Default | Description | -| - | - | - | -| `thumbnails` | | Configures how thumbnails are shown on the `timeline` view. See below. | +| Option | Default | Description | +| ------------ | ------- | ---------------------------------------------------------------------- | +| `thumbnails` | | Configures how thumbnails are shown on the `timeline` view. See below. | ### `thumbnails` @@ -44,18 +42,17 @@ Configures how thumbnails are shown on the timeline. ```yaml timeline: controls: - thumbnails: - [...] + thumbnails: [...] ``` -| Option | Default | Description | -| - | - | - | -| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`).| -| `show_details` | `false` | Whether to show event details (e.g. duration, start time, object detected, etc) alongside the thumbnail.| -| `show_download_control` | `true` | Whether to show the download control on each thumbnail.| -| `show_favorite_control` | `true` | Whether to show the favorite ('star') control on each thumbnail.| -| `show_timeline_control` | `true` | Whether to show the timeline ('target') control on each thumbnail.| -| `size` | `100` | The size of the thumbnails in the thumbnail carousel in pixels. Must be >= `75` and <= `175`.| +| Option | Default | Description | +| ----------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `mode` | `none` | Whether to show the thumbnail carousel `below` the media, `above` the media, in a drawer to the `left` or `right` of the media or to hide it entirely (`none`). | +| `show_details` | `false` | Whether to show event details (e.g. duration, start time, object detected, etc) alongside the thumbnail. | +| `show_download_control` | `true` | Whether to show the download control on each thumbnail. | +| `show_favorite_control` | `true` | Whether to show the favorite ('star') control on each thumbnail. | +| `show_timeline_control` | `true` | Whether to show the timeline ('target') control on each thumbnail. | +| `size` | `100` | The size of the thumbnails in the thumbnail carousel in pixels. Must be >= `75` and <= `175`. | ## Fully expanded reference @@ -76,4 +73,4 @@ timeline: show_download_control: true show_favorite_control: true show_timeline_control: true -``` \ No newline at end of file +``` diff --git a/docs/configuration/view.md b/docs/configuration/view.md index 2315cc91..18971513 100644 --- a/docs/configuration/view.md +++ b/docs/configuration/view.md @@ -2,45 +2,44 @@ The `view` configuration options control how the default view of the card behaves. - ```yaml -view: - [...] +```yaml +view: [...] ``` -| Option | Default | Description | -| - | - | - | -| `actions` | | [Actions](actions/README.md) to use for all views, individual actions may be overriden by view-specific actions. | -| `camera_select` | `current` | The [view](view.md?id=supported-views) to show when a new camera is selected (e.g. in the camera menu). If `current` the view is unchanged when a new camera is selected. | -| `dark_mode` | `off` | Whether or not to turn dark mode `on`, `off` or `auto` to automatically turn on if the card `interaction_seconds` has expired (i.e. card has been left unattended for that period of time) or if dark mode is enabled in the HA profile theme setting. Dark mode dims the brightness by `25%`.| -| `default` | `live` | The view to show in the card by default. The default camera is the first one listed. See [Supported Views](view.md?id=supported-views) below. | -| `interaction_seconds` | `300` | After a mouse/touch interaction with the card, it will be considered "interacted with" until this number of seconds elapses without further interaction. May be used as part of an [interaction condition](conditions.md?id=interaction) or with `reset_after_interaction` to reset the view after the interaction is complete. `0` means no interactions are reported / acted upon. | -| `keyboard_shortcuts` | See [usage](../usage/keyboard-shortcuts.md) for defaults. | Configure keyboard shortcuts. See below. | -| `render_entities` | | **YAML only**: A list of entity ids that should cause the card to re-render 'in-place'. The view/camera is not changed. `update_*` flags do not pertain/relate to the behavior of this flag. This should **very** rarely be needed, but could be useful if the card is both setting and changing HA state of the same object as could be the case for some complex `card_mod` scenarios ([example](https://github.com/dermotduffy/frigate-hass-card/issues/343)). | -| `reset_after_interaction` | `true` | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | -| `triggers` | | How to react when a camera is [triggered](cameras/README.md?id=triggers). | -| `update_cycle_camera` | `false` | When set to `true` the selected camera is cycled on each default view change. | -| `update_entities` | | **YAML only**: A card-wide list of entities that should cause the view to reset to the default (if the entity only pertains to a particular camera use [`triggers`](cameras/README.md?id=triggers) for the selected camera instead. | -| `update_force` | `false` | Whether automated card updates should ignore user interaction. | -| `update_seconds` | `0` | A number of seconds after which to automatically update/refresh the default view. If the default view occurs sooner (e.g. manually) the timer will start over. `0` disables this functionality.| +| Option | Default | Description | +| ------------------------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `actions` | | [Actions](actions/README.md) to use for all views, individual actions may be overriden by view-specific actions. | +| `camera_select` | `current` | The [view](view.md?id=supported-views) to show when a new camera is selected (e.g. in the camera menu). If `current` the view is unchanged when a new camera is selected. | +| `dark_mode` | `off` | Whether or not to turn dark mode `on`, `off` or `auto` to automatically turn on if the card `interaction_seconds` has expired (i.e. card has been left unattended for that period of time) or if dark mode is enabled in the HA profile theme setting. Dark mode dims the brightness by `25%`. | +| `default` | `live` | The view to show in the card by default. The default camera is the first one listed. See [Supported Views](view.md?id=supported-views) below. | +| `interaction_seconds` | `300` | After a mouse/touch interaction with the card, it will be considered "interacted with" until this number of seconds elapses without further interaction. May be used as part of an [interaction condition](conditions.md?id=interaction) or with `reset_after_interaction` to reset the view after the interaction is complete. `0` means no interactions are reported / acted upon. | +| `keyboard_shortcuts` | See [usage](../usage/keyboard-shortcuts.md) for defaults. | Configure keyboard shortcuts. See below. | +| `render_entities` | | **YAML only**: A list of entity ids that should cause the card to re-render 'in-place'. The view/camera is not changed. `update_*` flags do not pertain/relate to the behavior of this flag. This should **very** rarely be needed, but could be useful if the card is both setting and changing HA state of the same object as could be the case for some complex `card_mod` scenarios ([example](https://github.com/dermotduffy/frigate-hass-card/issues/343)). | +| `reset_after_interaction` | `true` | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | +| `triggers` | | How to react when a camera is [triggered](cameras/README.md?id=triggers). | +| `update_cycle_camera` | `false` | When set to `true` the selected camera is cycled on each default view change. | +| `update_entities` | | **YAML only**: A card-wide list of entities that should cause the view to reset to the default (if the entity only pertains to a particular camera use [`triggers`](cameras/README.md?id=triggers) for the selected camera instead. | +| `update_force` | `false` | Whether automated card updates should ignore user interaction. | +| `update_seconds` | `0` | A number of seconds after which to automatically update/refresh the default view. If the default view occurs sooner (e.g. manually) the timer will start over. `0` disables this functionality. | ## `keyboard_shortcuts` Configure the key-bindings for the builtin keyboard shortcuts. See [usage](../usage/keyboard-shortcuts.md) information for defaults on keyboard shortcuts. -| Option | Default | Description | -| - | - | - | -| `enabled` | `true` | If `true`, keyboard shortcuts are enabled. If `false`, they are disabled. | +| Option | Default | Description | +| ---------------------------------------------------------------------------------------- | --------------------------------------------------------- | --------------------------------------------------------------------------------------- | +| `enabled` | `true` | If `true`, keyboard shortcuts are enabled. If `false`, they are disabled. | | `ptz_left`, `ptz_right`, `ptz_up`, `ptz_down`, `ptz_zoom_in`, `ptz_zoom_out`, `ptz_home` | See [usage](../usage/keyboard-shortcuts.md) for defaults. | An object that configures the key binding for a given pre-configured action. See below. | ### Keyboard Shortcut Configuration -| Option | Default | Description | -| - | - | - | -| key | | Any [keyboard key value](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values), e.g. `ArrowLeft` | -| ctrl | `false` | If `true` requires the `ctrl` key to be held. | -| shift | `false` | If `true` requires the `shift` key to be held. | -| alt | `false` | If `true` requires the `alt` key to be held. | -| meta | `false` | If `true` requires the `meta` key to be held. | +| Option | Default | Description | +| ------ | ------- | -------------------------------------------------------------------------------------------------------------------------------- | +| key | | Any [keyboard key value](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values), e.g. `ArrowLeft` | +| ctrl | `false` | If `true` requires the `ctrl` key to be held. | +| shift | `false` | If `true` requires the `shift` key to be held. | +| alt | `false` | If `true` requires the `alt` key to be held. | +| meta | `false` | If `true` requires the `meta` key to be held. | ## `triggers` @@ -50,8 +49,7 @@ All configuration is under: ```yaml view: - triggers: - [...] + triggers: [...] ``` When a camera untriggers (e.g. an entity state returning to something other than @@ -60,40 +58,40 @@ to wait prior to the acting (see `untrigger_seconds`). By default, triggering is only allowed when there is no ongoing human interaction with the card. This behavior can be controlled by the `interaction_mode` parameter. -Triggers based on Home Assistant entities require state *changes* -- when the +Triggers based on Home Assistant entities require state _changes_ -- when the card is first started, it takes an active change in state to trigger (i.e. an already occupied room will not trigger, but a newly occupied room will). -| Option | Default | Description | -| - | - | - | -| `actions` | | The actions to take when a camera is triggered. See below. | -| `filter_selected_camera` | `false` | If set to `true` will only trigger on the currently selected camera.| -| `show_trigger_status` | `false` | Whether or not the `live` view should show a visual indication that it is triggered (a pulsing border around the camera edge). | -| `untrigger_seconds` | `0` | The number of seconds to wait after a camera untriggers before considering the card untriggered and taking the `untrigger` action. | +| Option | Default | Description | +| ------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------- | +| `actions` | | The actions to take when a camera is triggered. See below. | +| `filter_selected_camera` | `false` | If set to `true` will only trigger on the currently selected camera. | +| `show_trigger_status` | `false` | Whether or not the `live` view should show a visual indication that it is triggered (a pulsing border around the camera edge). | +| `untrigger_seconds` | `0` | The number of seconds to wait after a camera untriggers before considering the card untriggered and taking the `untrigger` action. | ### Trigger action configuration -| Option | Default | Description | -| - | - | - | -| `interaction_mode` | `inactive` | Whether actions should be taken when the card is being interacted with. If `all`, actions will always left be taken regardless. If `inactive` actions will only be taken if the card has *not* had human interaction recently (as defined by `view.interaction_seconds`). If `active` actions will only be taken if the card *has* had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed. | -| `trigger` | `default` | If set to `default` the default view of the card will be reloaded. If set to `live` the triggered camera will be selected in `live` view. If set to `media` the appropriate media view (e.g. `clip` or `snapshot`) will be chosen to match a newly available media item (please note that only some [camera engines](cameras/engine.md) support new media detection, e.g. `frigate`). If set to `none` no action is taken. | -| `untrigger` | `none` | If set to `default` the the default view of the card will be reloaded. If set to `none` no action will be taken. | +| Option | Default | Description | +| ------------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `interaction_mode` | `inactive` | Whether actions should be taken when the card is being interacted with. If `all`, actions will always left be taken regardless. If `inactive` actions will only be taken if the card has _not_ had human interaction recently (as defined by `view.interaction_seconds`). If `active` actions will only be taken if the card _has_ had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed. | +| `trigger` | `default` | If set to `default` the default view of the card will be reloaded. If set to `live` the triggered camera will be selected in `live` view. If set to `media` the appropriate media view (e.g. `clip` or `snapshot`) will be chosen to match a newly available media item (please note that only some [camera engines](cameras/engine.md) support new media detection, e.g. `frigate`). If set to `none` no action is taken. | +| `untrigger` | `none` | If set to `default` the the default view of the card will be reloaded. If set to `none` no action will be taken. | ## Supported views This card supports several different views. -| Key | Description | -| - | - | -|`clip`|Shows a viewer for the most recent clip for this camera. Can also be accessed by holding down the `clips` menu icon.| -|`clips`|Shows a gallery of clips for this camera.| -|`image`|Shows a static image specified by the `image` parameter, can be used as a discrete default view or a screensaver (via `view.interaction_seconds`).| -|`live`| Shows the live camera view with the configured [live provider]().| -|`recording`|Shows a viewer for the most recent recording for this camera. Can also be accessed by holding down the `recordings` menu icon.| -|`recordings`|Shows a gallery of recent (last day) recordings for this camera and its dependents.| -|`snapshot`|Shows a viewer for the most recent snapshot for this camera. Can also be accessed by holding down the `snapshots` menu icon.| -|`snapshots`|Shows a gallery of snapshots for this camera.| -|`timeline`|Shows an event timeline.| +| Key | Description | +| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| `clip` | Shows a viewer for the most recent clip for this camera. Can also be accessed by holding down the `clips` menu icon. | +| `clips` | Shows a gallery of clips for this camera. | +| `image` | Shows a static image specified by the `image` parameter, can be used as a discrete default view or a screensaver (via `view.interaction_seconds`). | +| `live` | Shows the live camera view with the configured [live provider](). | +| `recording` | Shows a viewer for the most recent recording for this camera. Can also be accessed by holding down the `recordings` menu icon. | +| `recordings` | Shows a gallery of recent (last day) recordings for this camera and its dependents. | +| `snapshot` | Shows a viewer for the most recent snapshot for this camera. Can also be accessed by holding down the `snapshots` menu icon. | +| `snapshots` | Shows a gallery of snapshots for this camera. | +| `timeline` | Shows an event timeline. | The default view is `live`, but can be configured by the `view.default` parameter. @@ -136,7 +134,7 @@ view: key: '+' ptz_zoom_out: key: '-' - ptz_home: + ptz_home: key: 'h' actions: entity: light.office_main_lights diff --git a/docs/css/theme-simple-dark.css b/docs/css/theme-simple-dark.css index 1aca008c..09824915 100644 --- a/docs/css/theme-simple-dark.css +++ b/docs/css/theme-simple-dark.css @@ -1,3 +1,2473 @@ -.github-corner{position:absolute;z-index:40;top:0;right:0;border-bottom:0;text-decoration:none}.github-corner svg{height:70px;width:70px;fill:var(--theme-color);color:var(--base-background-color)}.github-corner:hover .octo-arm{-webkit-animation:octocat-wave 560ms ease-in-out;animation:octocat-wave 560ms ease-in-out}@-webkit-keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}.progress{position:fixed;z-index:2147483647;top:0;left:0;right:0;height:3px;width:0;background-color:var(--theme-color);transition:width var(--duration-fast),opacity calc(var(--duration-fast)*2)}body.ready-transition:after,body.ready-transition>*:not(.progress){opacity:0;transition:opacity var(--spinner-transition-duration)}body.ready-transition:after{content:"";position:absolute;z-index:1000;top:calc(50% - var(--spinner-size)/2);left:calc(50% - var(--spinner-size)/2);height:var(--spinner-size);width:var(--spinner-size);border:var(--spinner-track-width, 0) solid var(--spinner-track-color);border-left-color:var(--theme-color);border-left-color:var(--theme-color);border-radius:50%;-webkit-animation:spinner var(--duration-slow) infinite linear;animation:spinner var(--duration-slow) infinite linear}body.ready-transition.ready-spinner:after{opacity:1}body.ready-transition.ready-fix:after{opacity:0}body.ready-transition.ready-fix>*:not(.progress){opacity:1;transition-delay:var(--spinner-transition-duration)}@-webkit-keyframes spinner{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@keyframes spinner{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}*,*:before,*:after{box-sizing:inherit;font-size:inherit;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none}:root{box-sizing:border-box;background-color:var(--base-background-color);font-size:var(--base-font-size);font-weight:var(--base-font-weight);line-height:var(--base-line-height);letter-spacing:var(--base-letter-spacing);color:var(--base-color);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased}html,button,input,optgroup,select,textarea{font-family:var(--base-font-family)}button,input,optgroup,select,textarea{font-size:100%;margin:0}a{text-decoration:none;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}body{margin:0}hr{height:0;margin:2em 0;border:none;border-bottom:var(--hr-border, 0)}img{max-width:100%;border:0}main{display:block}main.hidden{display:none}mark{background:var(--mark-background);color:var(--mark-color)}pre{font-family:var(--pre-font-family);font-size:var(--pre-font-size);font-weight:var(--pre-font-weight);line-height:var(--pre-line-height)}small{display:inline-block;font-size:var(--small-font-size)}strong{font-weight:var(--strong-font-weight);color:var(--strong-color, currentColor)}sub,sup{font-size:var(--subsup-font-size);line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}body:not([data-platform^=Mac]) *{scrollbar-color:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3) hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1);scrollbar-width:thin}body:not([data-platform^=Mac]) * ::-webkit-scrollbar{width:5px;height:5px}body:not([data-platform^=Mac]) * ::-webkit-scrollbar-thumb{background:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3)}body:not([data-platform^=Mac]) * ::-webkit-scrollbar-track{background:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1)}::-moz-selection{background:var(--selection-color)}::selection{background:var(--selection-color)}.emoji{height:var(--emoji-size);vertical-align:middle}.task-list-item{list-style:none}.task-list-item input{margin-right:.5em;margin-left:0;vertical-align:.075em}.markdown-section code[class*=lang-],.markdown-section pre[data-lang]{font-family:var(--code-font-family);font-size:var(--code-font-size);font-weight:var(--code-font-weight);letter-spacing:normal;line-height:var(--code-block-line-height);-moz-tab-size:var(--code-tab-size);-o-tab-size:var(--code-tab-size);tab-size:var(--code-tab-size);text-align:left;white-space:pre;word-spacing:normal;word-wrap:normal;word-break:normal;-webkit-hyphens:none;hyphens:none}.markdown-section pre[data-lang]{position:relative;overflow:hidden;margin:var(--code-block-margin);padding:0;border-radius:var(--code-block-border-radius)}.markdown-section pre[data-lang]::after{content:attr(data-lang);position:absolute;top:.75em;right:.75em;opacity:.6;color:inherit;font-size:var(--font-size-s);line-height:1}.markdown-section pre[data-lang] code{display:block;overflow:auto;padding:var(--code-block-padding)}code[class*=lang-],pre[data-lang]{color:var(--code-theme-text)}pre[data-lang]::-moz-selection,pre[data-lang] ::-moz-selection,code[class*=lang-]::-moz-selection,code[class*=lang-] ::-moz-selection{background:var(--code-theme-selection, var(--selection-color))}pre[data-lang]::-moz-selection, pre[data-lang] ::-moz-selection, code[class*=lang-]::-moz-selection, code[class*=lang-] ::-moz-selection{background:var(--code-theme-selection, var(--selection-color))}pre[data-lang]::selection,pre[data-lang] ::selection,code[class*=lang-]::selection,code[class*=lang-] ::selection{background:var(--code-theme-selection, var(--selection-color))}:not(pre)>code[class*=lang-],pre[data-lang]{background:var(--code-theme-background)}.namespace{opacity:.7}.token.comment,.token.prolog,.token.doctype,.token.cdata{color:var(--code-theme-comment)}.token.punctuation{color:var(--code-theme-punctuation)}.token.property,.token.tag,.token.boolean,.token.number,.token.constant,.token.symbol,.token.deleted{color:var(--code-theme-tag)}.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.inserted{color:var(--code-theme-selector)}.token.operator,.token.entity,.token.url,.language-css .token.string,.style .token.string{color:var(--code-theme-operator)}.token.atrule,.token.attr-value,.token.keyword{color:var(--code-theme-keyword)}.token.function{color:var(--code-theme-function)}.token.regex,.token.important,.token.variable{color:var(--code-theme-variable)}.token.important,.token.bold{font-weight:bold}.token.italic{font-style:italic}.token.entity{cursor:help}.markdown-section{position:relative;max-width:var(--content-max-width);margin:0 auto;padding:2rem 45px}.app-nav:not(:empty)~main .markdown-section{padding-top:3.5rem}.markdown-section figure,.markdown-section p,.markdown-section ol,.markdown-section ul{margin:1em 0}.markdown-section ol,.markdown-section ul{padding-left:1.5rem}.markdown-section ol ol,.markdown-section ol ul,.markdown-section ul ol,.markdown-section ul ul{margin-top:.15rem;margin-bottom:.15rem}.markdown-section a{border-bottom:var(--link-border-bottom);color:var(--link-color);-webkit-text-decoration:var(--link-text-decoration);text-decoration:var(--link-text-decoration);-webkit-text-decoration-color:var(--link-text-decoration-color);text-decoration-color:var(--link-text-decoration-color)}.markdown-section a:hover{border-bottom:var(--link-border-bottom--hover, var(--link-border-bottom, 0));color:var(--link-color--hover, var(--link-color));-webkit-text-decoration:var(--link-text-decoration--hover, var(--link-text-decoration));text-decoration:var(--link-text-decoration--hover, var(--link-text-decoration));-webkit-text-decoration-color:var(--link-text-decoration-color--hover, var(--link-text-decoration-color));text-decoration-color:var(--link-text-decoration-color--hover, var(--link-text-decoration-color))}.markdown-section a.anchor{border-bottom:0;color:inherit;text-decoration:none}.markdown-section a.anchor:hover{text-decoration:underline}.markdown-section blockquote{overflow:visible;margin:2em 0;padding:var(--blockquote-padding);border-width:var(--blockquote-border-width, 0);border-style:var(--blockquote-border-style);border-color:var(--blockquote-border-color);border-radius:var(--blockquote-border-radius);background:var(--blockquote-background);color:var(--blockquote-color);font-family:var(--blockquote-font-family);font-size:var(--blockquote-font-size);font-style:var(--blockquote-font-style);font-weight:var(--blockquote-font-weight);quotes:"“" "”" "‘" "’"}.markdown-section blockquote em{font-family:var(--blockquote-em-font-family);font-size:var(--blockquote-em-font-size);font-style:var(--blockquote-em-font-style);font-weight:var(--blockquote-em-font-weight)}.markdown-section blockquote p:first-child{margin-top:0}.markdown-section blockquote p:first-child:before,.markdown-section blockquote p:first-child:after{color:var(--blockquote-quotes-color);font-family:var(--blockquote-quotes-font-family);font-size:var(--blockquote-quotes-font-size);line-height:0}.markdown-section blockquote p:first-child:before{content:var(--blockquote-quotes-open);margin-right:.15em;vertical-align:-0.45em}.markdown-section blockquote p:first-child:after{content:var(--blockquote-quotes-close);margin-left:.15em;vertical-align:-0.55em}.markdown-section blockquote p:last-child{margin-bottom:0}.markdown-section code{font-family:var(--code-font-family);font-size:var(--code-font-size);font-weight:var(--code-font-weight);line-height:inherit}.markdown-section code:not([class*=lang-]):not([class*=language-]){margin:var(--code-inline-margin);padding:var(--code-inline-padding);border-radius:var(--code-inline-border-radius);background:var(--code-inline-background);color:var(--code-inline-color, currentColor);white-space:nowrap}.markdown-section h1:first-child,.markdown-section h2:first-child,.markdown-section h3:first-child,.markdown-section h4:first-child,.markdown-section h5:first-child,.markdown-section h6:first-child{margin-top:0}.markdown-section h1 a[data-id],.markdown-section h2 a[data-id],.markdown-section h3 a[data-id],.markdown-section h4 a[data-id],.markdown-section h5 a[data-id],.markdown-section h6 a[data-id]{display:inline-block}.markdown-section h1 code,.markdown-section h2 code,.markdown-section h3 code,.markdown-section h4 code,.markdown-section h5 code,.markdown-section h6 code{font-size:.875em}.markdown-section h1+h2,.markdown-section h1+h3,.markdown-section h1+h4,.markdown-section h1+h5,.markdown-section h1+h6,.markdown-section h2+h3,.markdown-section h2+h4,.markdown-section h2+h5,.markdown-section h2+h6,.markdown-section h3+h4,.markdown-section h3+h5,.markdown-section h3+h6,.markdown-section h4+h5,.markdown-section h4+h6,.markdown-section h5+h6{margin-top:1rem}.markdown-section h1{margin:var(--heading-h1-margin, var(--heading-margin));padding:var(--heading-h1-padding, var(--heading-padding));border-width:var(--heading-h1-border-width, 0);border-style:var(--heading-h1-border-style);border-color:var(--heading-h1-border-color);font-family:var(--heading-h1-font-family, var(--heading-font-family));font-size:var(--heading-h1-font-size);font-weight:var(--heading-h1-font-weight, var(--heading-font-weight));line-height:var(--base-line-height);color:var(--heading-h1-color, var(--heading-color))}.markdown-section h2{margin:var(--heading-h2-margin, var(--heading-margin));padding:var(--heading-h2-padding, var(--heading-padding));border-width:var(--heading-h2-border-width, 0);border-style:var(--heading-h2-border-style);border-color:var(--heading-h2-border-color);font-family:var(--heading-h2-font-family, var(--heading-font-family));font-size:var(--heading-h2-font-size);font-weight:var(--heading-h2-font-weight, var(--heading-font-weight));line-height:var(--base-line-height);color:var(--heading-h2-color, var(--heading-color))}.markdown-section h3{margin:var(--heading-h3-margin, var(--heading-margin));padding:var(--heading-h3-padding, var(--heading-padding));border-width:var(--heading-h3-border-width, 0);border-style:var(--heading-h3-border-style);border-color:var(--heading-h3-border-color);font-family:var(--heading-h3-font-family, var(--heading-font-family));font-size:var(--heading-h3-font-size);font-weight:var(--heading-h3-font-weight, var(--heading-font-weight));color:var(--heading-h3-color, var(--heading-color))}.markdown-section h4{margin:var(--heading-h4-margin, var(--heading-margin));padding:var(--heading-h4-padding, var(--heading-padding));border-width:var(--heading-h4-border-width, 0);border-style:var(--heading-h4-border-style);border-color:var(--heading-h4-border-color);font-family:var(--heading-h4-font-family, var(--heading-font-family));font-size:var(--heading-h4-font-size);font-weight:var(--heading-h4-font-weight, var(--heading-font-weight));color:var(--heading-h4-color, var(--heading-color))}.markdown-section h5{margin:var(--heading-h5-margin, var(--heading-margin));padding:var(--heading-h5-padding, var(--heading-padding));border-width:var(--heading-h5-border-width, 0);border-style:var(--heading-h5-border-style);border-color:var(--heading-h5-border-color);font-family:var(--heading-h5-font-family, var(--heading-font-family));font-size:var(--heading-h5-font-size);font-weight:var(--heading-h5-font-weight, var(--heading-font-weight));color:var(--heading-h5-color, var(--heading-color))}.markdown-section h6{margin:var(--heading-h6-margin, var(--heading-margin));padding:var(--heading-h6-padding, var(--heading-padding));border-width:var(--heading-h6-border-width, 0);border-style:var(--heading-h6-border-style);border-color:var(--heading-h6-border-color);font-family:var(--heading-h6-font-family, var(--heading-font-family));font-size:var(--heading-h6-font-size);font-weight:var(--heading-h6-font-weight, var(--heading-font-weight));color:var(--heading-h6-color, var(--heading-color))}.markdown-section iframe{margin:1em 0}.markdown-section img{max-width:100%}.markdown-section kbd{display:inline-block;min-width:var(--kbd-min-width);margin:var(--kbd-margin);padding:var(--kbd-padding);border:var(--kbd-border);border-radius:var(--kbd-border-radius);background:var(--kbd-background);font-family:inherit;font-size:var(--kbd-font-size);text-align:center;letter-spacing:0;line-height:1;color:var(--kbd-color)}.markdown-section kbd+kbd{margin-left:-0.15em}.markdown-section table{display:block;overflow:auto;margin:1rem 0;border-spacing:0;border-collapse:collapse}.markdown-section th,.markdown-section td{padding:var(--table-cell-padding)}.markdown-section th:not([align]){text-align:left}.markdown-section thead{border-color:var(--table-head-border-color);border-style:solid;border-width:var(--table-head-border-width, 0);background:var(--table-head-background)}.markdown-section th{font-weight:var(--table-head-font-weight);color:var(--strong-color)}.markdown-section td{border-color:var(--table-cell-border-color);border-style:solid;border-width:var(--table-cell-border-width, 0)}.markdown-section tbody{border-color:var(--table-body-border-color);border-style:solid;border-width:var(--table-body-border-width, 0)}.markdown-section tbody tr:nth-child(odd){background:var(--table-row-odd-background)}.markdown-section tbody tr:nth-child(even){background:var(--table-row-even-background)}.markdown-section>ul .task-list-item{margin-left:-1.25em}.markdown-section>ul .task-list-item .task-list-item{margin-left:0}.markdown-section .table-wrapper{overflow-x:auto}.markdown-section .table-wrapper table{display:table;width:100%}.markdown-section .table-wrapper td::before{display:none}@media(max-width: 30em){.markdown-section .table-wrapper tbody,.markdown-section .table-wrapper tr,.markdown-section .table-wrapper td{display:block}.markdown-section .table-wrapper th,.markdown-section .table-wrapper td{border:none}.markdown-section .table-wrapper thead{display:none}.markdown-section .table-wrapper tr{border-color:var(--table-cell-border-color);border-style:solid;border-width:var(--table-cell-border-width, 0);padding:var(--table-cell-padding)}.markdown-section .table-wrapper tr:not(:last-child){border-bottom:0}.markdown-section .table-wrapper td{padding:.15em 0 .15em 8em}.markdown-section .table-wrapper td::before{display:inline-block;float:left;width:8em;margin-left:-8em;font-weight:bold;text-align:left}}.markdown-section .tip,.markdown-section .warn{position:relative;margin:2em 0;padding:var(--notice-padding);border-width:var(--notice-border-width, 0);border-style:var(--notice-border-style);border-color:var(--notice-border-color);border-radius:var(--notice-border-radius);background:var(--notice-background);font-family:var(--notice-font-family);font-weight:var(--notice-font-weight);color:var(--notice-color)}.markdown-section .tip:before,.markdown-section .warn:before{display:inline-block;position:var(--notice-before-position, relative);top:var(--notice-before-top);left:var(--notice-before-left);height:var(--notice-before-height);width:var(--notice-before-width);margin:var(--notice-before-margin);padding:var(--notice-before-padding);border-radius:var(--notice-before-border-radius);line-height:var(--notice-before-line-height);font-family:var(--notice-before-font-family);font-size:var(--notice-before-font-size);font-weight:var(--notice-before-font-weight);text-align:center}.markdown-section .tip{border-width:var(--notice-important-border-width, var(--notice-border-width, 0));border-style:var(--notice-important-border-style, var(--notice-border-style));border-color:var(--notice-important-border-color, var(--notice-border-color));background:var(--notice-important-background, var(--notice-background));color:var(--notice-important-color, var(--notice-color))}.markdown-section .tip:before{content:var(--notice-important-before-content, var(--notice-before-content));background:var(--notice-important-before-background, var(--notice-before-background));color:var(--notice-important-before-color, var(--notice-before-color))}.markdown-section .warn{border-width:var(--notice-tip-border-width, var(--notice-border-width, 0));border-style:var(--notice-tip-border-style, var(--notice-border-style));border-color:var(--notice-tip-border-color, var(--notice-border-color));background:var(--notice-tip-background, var(--notice-background));color:var(--notice-tip-color, var(--notice-color))}.markdown-section .warn:before{content:var(--notice-tip-before-content, var(--notice-before-content));background:var(--notice-tip-before-background, var(--notice-before-background));color:var(--notice-tip-before-color, var(--notice-before-color))}.cover{display:none;position:relative;z-index:20;min-height:100vh;flex-direction:column;align-items:center;justify-content:center;padding:calc(var(--cover-border-inset, 0px) + var(--cover-border-width, 0px));color:var(--cover-color);text-align:var(--cover-text-align)}@media screen and (-ms-high-contrast: active),screen and (-ms-high-contrast: none){.cover{height:100vh}}.cover:before,.cover:after{content:"";position:absolute}.cover:before{top:0;bottom:0;left:0;right:0;background-blend-mode:var(--cover-background-blend-mode);background-color:var(--cover-background-color);background-image:var(--cover-background-image);background-position:var(--cover-background-position);background-repeat:var(--cover-background-repeat);background-size:var(--cover-background-size)}.cover:after{top:var(--cover-border-inset, 0);bottom:var(--cover-border-inset, 0);left:var(--cover-border-inset, 0);right:var(--cover-border-inset, 0);border-width:var(--cover-border-width, 0);border-style:solid;border-color:var(--cover-border-color)}.cover a{border-bottom:var(--cover-link-border-bottom);color:var(--cover-link-color);-webkit-text-decoration:var(--cover-link-text-decoration);text-decoration:var(--cover-link-text-decoration);-webkit-text-decoration-color:var(--cover-link-text-decoration-color);text-decoration-color:var(--cover-link-text-decoration-color)}.cover a:hover{border-bottom:var(--cover-link-border-bottom--hover, var(--cover-link-border-bottom));color:var(--cover-link-color--hover, var(--cover-link-color));-webkit-text-decoration:var(--cover-link-text-decoration--hover, var(--cover-link-text-decoration));text-decoration:var(--cover-link-text-decoration--hover, var(--cover-link-text-decoration));-webkit-text-decoration-color:var(--cover-link-text-decoration-color--hover, var(--cover-link-text-decoration-color));text-decoration-color:var(--cover-link-text-decoration-color--hover, var(--cover-link-text-decoration-color))}.cover h1{color:var(--cover-heading-color);position:relative;margin:0;font-size:var(--cover-heading-font-size);font-weight:var(--cover-heading-font-weight);line-height:1.2}.cover h1 a,.cover h1 a:hover{display:block;border-bottom:none;color:inherit;text-decoration:none}.cover h1 small{position:absolute;bottom:0;margin-left:.5em}.cover h1 span{font-size:calc(var(--cover-heading-font-size-min)*1px)}@media(min-width: 26em){.cover h1 span{font-size:calc(var(--cover-heading-font-size-min)*1px + (var(--cover-heading-font-size-max) - var(--cover-heading-font-size-min))*(100vw - 420px)/604)}}@media(min-width: 64em){.cover h1 span{font-size:calc(var(--cover-heading-font-size-max)*1px)}}.cover blockquote{margin:0;color:var(--cover-blockquote-color);font-size:var(--cover-blockquote-font-size)}.cover blockquote a{color:inherit}.cover ul{padding:0;list-style-type:none}.cover .cover-main{position:relative;z-index:1;max-width:var(--cover-max-width);margin:var(--cover-margin);padding:0 45px}.cover .cover-main>p:last-child{margin:1.25em -0.25em}.cover .cover-main>p:last-child a{display:block;margin:.375em .25em;padding:var(--cover-button-padding);border:var(--cover-button-border);border-radius:var(--cover-button-border-radius);box-shadow:var(--cover-button-box-shadow);background:var(--cover-button-background);text-align:center;-webkit-text-decoration:var(--cover-button-text-decoration);text-decoration:var(--cover-button-text-decoration);-webkit-text-decoration-color:var(--cover-button-text-decoration-color);text-decoration-color:var(--cover-button-text-decoration-color);color:var(--cover-button-color);white-space:nowrap;transition:var(--cover-button-transition)}.cover .cover-main>p:last-child a:hover{border:var(--cover-button-border--hover, var(--cover-button-border));box-shadow:var(--cover-button-box-shadow--hover, var(--cover-button-box-shadow));background:var(--cover-button-background--hover, var(--cover-button-background));-webkit-text-decoration:var(--cover-button-text-decoration--hover, var(--cover-button-text-decoration));text-decoration:var(--cover-button-text-decoration--hover, var(--cover-button-text-decoration));-webkit-text-decoration-color:var(--cover-button-text-decoration-color--hover, var(--cover-button-text-decoration-color));text-decoration-color:var(--cover-button-text-decoration-color--hover, var(--cover-button-text-decoration-color));color:var(--cover-button-color--hover, var(--cover-button-color))}.cover .cover-main>p:last-child a:first-child{border:var(--cover-button-primary-border, var(--cover-button-border));box-shadow:var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow));background:var(--cover-button-primary-background, var(--cover-button-background));-webkit-text-decoration:var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration));text-decoration:var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration));-webkit-text-decoration-color:var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color));text-decoration-color:var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color));color:var(--cover-button-primary-color, var(--cover-button-color))}.cover .cover-main>p:last-child a:first-child:hover{border:var(--cover-button-primary-border--hover, var(--cover-button-border--hover, var(--cover-button-primary-border, var(--cover-button-border))));box-shadow:var(--cover-button-primary-box-shadow--hover, var(--cover-button-box-shadow--hover, var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow))));background:var(--cover-button-primary-background--hover, var(--cover-button-background--hover, var(--cover-button-primary-background, var(--cover-button-background))));-webkit-text-decoration:var(--cover-button-primary-text-decoration--hover, var(--cover-button-text-decoration--hover, var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration))));text-decoration:var(--cover-button-primary-text-decoration--hover, var(--cover-button-text-decoration--hover, var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration))));-webkit-text-decoration-color:var(--cover-button-primary-text-decoration-color--hover, var(--cover-button-text-decoration-color--hover, var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color))));text-decoration-color:var(--cover-button-primary-text-decoration-color--hover, var(--cover-button-text-decoration-color--hover, var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color))));color:var(--cover-button-primary-color--hover, var(--cover-button-color--hover, var(--cover-button-primary-color, var(--cover-button-color))))}@media(min-width: 30.01em){.cover .cover-main>p:last-child a{display:inline-block}}.cover .mask{visibility:var(--cover-background-mask-visibility, hidden);position:absolute;top:0;bottom:0;left:0;right:0;background-color:var(--cover-background-mask-color);opacity:var(--cover-background-mask-opacity)}.cover.has-mask .mask{visibility:visible}.cover.show{display:flex}.app-nav{position:absolute;z-index:30;top:calc(35px - .5em*var(--base-line-height));left:45px;right:80px;text-align:right}.app-nav.no-badge{right:45px}.app-nav li>img,.app-nav li>a>img{margin-top:-0.25em;vertical-align:middle}.app-nav li>img:first-child,.app-nav li>a>img:first-child{margin-right:.5em}.app-nav ul,.app-nav li{margin:0;padding:0;list-style:none}.app-nav li{position:relative}.app-nav li a{display:block;line-height:1;transition:var(--navbar-root-transition)}.app-nav>ul>li{display:inline-block;margin:var(--navbar-root-margin)}.app-nav>ul>li:first-child{margin-left:0}.app-nav>ul>li:last-child{margin-right:0}.app-nav>ul>li>a,.app-nav>ul>li>span{padding:var(--navbar-root-padding);border-width:var(--navbar-root-border-width, 0);border-style:var(--navbar-root-border-style);border-color:var(--navbar-root-border-color);border-radius:var(--navbar-root-border-radius);background:var(--navbar-root-background);color:var(--navbar-root-color);-webkit-text-decoration:var(--navbar-root-text-decoration);text-decoration:var(--navbar-root-text-decoration);-webkit-text-decoration-color:var(--navbar-root-text-decoration-color);text-decoration-color:var(--navbar-root-text-decoration-color)}.app-nav>ul>li>a:hover,.app-nav>ul>li>span:hover{background:var(--navbar-root-background--hover, var(--navbar-root-background));border-style:var(--navbar-root-border-style--hover, var(--navbar-root-border-style));border-color:var(--navbar-root-border-color--hover, var(--navbar-root-border-color));color:var(--navbar-root-color--hover, var(--navbar-root-color));-webkit-text-decoration:var(--navbar-root-text-decoration--hover, var(--navbar-root-text-decoration));text-decoration:var(--navbar-root-text-decoration--hover, var(--navbar-root-text-decoration));-webkit-text-decoration-color:var(--navbar-root-text-decoration-color--hover, var(--navbar-root-text-decoration-color));text-decoration-color:var(--navbar-root-text-decoration-color--hover, var(--navbar-root-text-decoration-color))}.app-nav>ul>li>a:not(:last-child),.app-nav>ul>li>span:not(:last-child){padding:var(--navbar-menu-root-padding, var(--navbar-root-padding));background:var(--navbar-menu-root-background, var(--navbar-root-background))}.app-nav>ul>li>a:not(:last-child):hover,.app-nav>ul>li>span:not(:last-child):hover{background:var(--navbar-menu-root-background--hover, var(--navbar-menu-root-background, var(--navbar-root-background--hover, var(--navbar-root-background))))}.app-nav>ul>li>a.active{background:var(--navbar-root-background--active, var(--navbar-root-background));border-style:var(--navbar-root-border-style--active, var(--navbar-root-border-style));border-color:var(--navbar-root-border-color--active, var(--navbar-root-border-color));color:var(--navbar-root-color--active, var(--navbar-root-color));-webkit-text-decoration:var(--navbar-root-text-decoration--active, var(--navbar-root-text-decoration));text-decoration:var(--navbar-root-text-decoration--active, var(--navbar-root-text-decoration));-webkit-text-decoration-color:var(--navbar-root-text-decoration-color--active, var(--navbar-root-text-decoration-color));text-decoration-color:var(--navbar-root-text-decoration-color--active, var(--navbar-root-text-decoration-color))}.app-nav>ul>li>a.active:not(:last-child):hover{background:var(--navbar-menu-root-background--active, var(--navbar-menu-root-background, var(--navbar-root-background--active, var(--navbar-root-background))))}.app-nav>ul>li ul{visibility:hidden;position:absolute;top:100%;right:50%;overflow-y:auto;box-sizing:border-box;max-height:50vh;padding:var(--navbar-menu-padding);border-width:var(--navbar-menu-border-width, 0);border-style:solid;border-color:var(--navbar-menu-border-color);border-radius:var(--navbar-menu-border-radius);background:var(--navbar-menu-background);box-shadow:var(--navbar-menu-box-shadow);text-align:left;white-space:nowrap;opacity:0;transform:translate(50%, -0.35em);transition:var(--navbar-menu-transition)}.app-nav>ul>li ul li{white-space:nowrap}.app-nav>ul>li ul a{margin:var(--navbar-menu-link-margin);padding:var(--navbar-menu-link-padding);border-width:var(--navbar-menu-link-border-width, 0);border-style:var(--navbar-menu-link-border-style);border-color:var(--navbar-menu-link-border-color);border-radius:var(--navbar-menu-link-border-radius);background:var(--navbar-menu-link-background);color:var(--navbar-menu-link-color);-webkit-text-decoration:var(--navbar-menu-link-text-decoration);text-decoration:var(--navbar-menu-link-text-decoration);-webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color);text-decoration-color:var(--navbar-menu-link-text-decoration-color)}.app-nav>ul>li ul a:hover{background:var(--navbar-menu-link-background--hover, var(--navbar-menu-link-background));border-style:var(--navbar-menu-link-border-style--hover, var(--navbar-menu-link-border-style));border-color:var(--navbar-menu-link-border-color--hover, var(--navbar-menu-link-border-color));color:var(--navbar-menu-link-color--hover, var(--navbar-menu-link-color));-webkit-text-decoration:var(--navbar-menu-link-text-decoration--hover, var(--navbar-menu-link-text-decoration));text-decoration:var(--navbar-menu-link-text-decoration--hover, var(--navbar-menu-link-text-decoration));-webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color--hover, var(--navbar-menu-link-text-decoration-color));text-decoration-color:var(--navbar-menu-link-text-decoration-color--hover, var(--navbar-menu-link-text-decoration-color))}.app-nav>ul>li ul a.active{background:var(--navbar-menu-link-background--active, var(--navbar-menu-link-background));border-style:var(--navbar-menu-link-border-style--active, var(--navbar-menu-link-border-style));border-color:var(--navbar-menu-link-border-color--active, var(--navbar-menu-link-border-color));color:var(--navbar-menu-link-color--active, var(--navbar-menu-link-color));-webkit-text-decoration:var(--navbar-menu-link-text-decoration--active, var(--navbar-menu-link-text-decoration));text-decoration:var(--navbar-menu-link-text-decoration--active, var(--navbar-menu-link-text-decoration));-webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color--active, var(--navbar-menu-link-text-decoration-color));text-decoration-color:var(--navbar-menu-link-text-decoration-color--active, var(--navbar-menu-link-text-decoration-color))}.app-nav>ul>li:hover ul,.app-nav>ul>li:focus ul,.app-nav>ul>li.focus-within ul{visibility:visible;opacity:1;transform:translate(50%, 0)}@media(min-width: 48em){nav.app-nav{margin-left:var(--sidebar-width)}}main{position:relative;overflow-x:hidden;min-height:100vh}.sidebar,.sidebar-toggle,.sidebar+.content{transition:all var(--sidebar-transition-duration) ease-out}@media(min-width: 48em){.sidebar+.content{margin-left:var(--sidebar-width)}}.sidebar{display:flex;flex-direction:column;position:fixed;z-index:10;top:0;right:100%;overflow-x:hidden;overflow-y:auto;height:100vh;width:var(--sidebar-width);padding:var(--sidebar-padding);border-width:var(--sidebar-border-width);border-style:solid;border-color:var(--sidebar-border-color);background:var(--sidebar-background)}.sidebar>h1{margin:0;margin:var(--sidebar-name-margin);padding:var(--sidebar-name-padding);background:var(--sidebar-name-background);color:var(--sidebar-name-color);font-family:var(--sidebar-name-font-family);font-size:var(--sidebar-name-font-size);font-weight:var(--sidebar-name-font-weight);text-align:var(--sidebar-name-text-align)}.sidebar>h1 img{max-width:100%}.sidebar>h1 .app-name-link{color:var(--sidebar-name-color)}body:not([data-platform^=Mac]) .sidebar::-webkit-scrollbar{width:5px}body:not([data-platform^=Mac]) .sidebar::-webkit-scrollbar-thumb{border-radius:50vw}@media(min-width: 48em){.sidebar{position:absolute;transform:translateX(var(--sidebar-width))}}@media print{.sidebar{display:none}}.sidebar-nav,.sidebar nav{order:1;margin:var(--sidebar-nav-margin);padding:var(--sidebar-nav-padding);background:var(--sidebar-nav-background)}.sidebar-nav ul,.sidebar nav ul{margin:0;padding:0;list-style:none}.sidebar-nav ul ul,.sidebar nav ul ul{margin-left:var(--sidebar-nav-indent)}.sidebar-nav a,.sidebar nav a{display:block;overflow:hidden;margin:var(--sidebar-nav-link-margin);padding:var(--sidebar-nav-link-padding);border-width:var(--sidebar-nav-link-border-width, 0);border-style:var(--sidebar-nav-link-border-style);border-color:var(--sidebar-nav-link-border-color);border-radius:var(--sidebar-nav-link-border-radius);background:var(--sidebar-nav-link-background);color:var(--sidebar-nav-link-color);font-weight:var(--sidebar-nav-link-font-weight);white-space:nowrap;-webkit-text-decoration:var(--sidebar-nav-link-text-decoration);text-decoration:var(--sidebar-nav-link-text-decoration);-webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-overflow:ellipsis;transition:var(--sidebar-nav-link-transition)}.sidebar-nav a img,.sidebar nav a img{margin-top:-0.25em;vertical-align:middle}.sidebar-nav a img:first-child,.sidebar nav a img:first-child{margin-right:.5em}.sidebar-nav a:hover,.sidebar nav a:hover{border-width:var(--sidebar-nav-link-border-width--hover, var(--sidebar-nav-link-border-width, 0));border-style:var(--sidebar-nav-link-border-style--hover, var(--sidebar-nav-link-border-style));border-color:var(--sidebar-nav-link-border-color--hover, var(--sidebar-nav-link-border-color));background:var(--sidebar-nav-link-background--hover, var(--sidebar-nav-link-background));color:var(--sidebar-nav-link-color--hover, var(--sidebar-nav-link-color));font-weight:var(--sidebar-nav-link-font-weight--hover, var(--sidebar-nav-link-font-weight));-webkit-text-decoration:var(--sidebar-nav-link-text-decoration--hover, var(--sidebar-nav-link-text-decoration));text-decoration:var(--sidebar-nav-link-text-decoration--hover, var(--sidebar-nav-link-text-decoration));-webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-decoration-color:var(--sidebar-nav-link-text-decoration-color)}.sidebar-nav ul>li>span,.sidebar-nav ul>li>strong,.sidebar nav ul>li>span,.sidebar nav ul>li>strong{display:block;margin:var(--sidebar-nav-strong-margin);padding:var(--sidebar-nav-strong-padding);border-width:var(--sidebar-nav-strong-border-width, 0);border-style:solid;border-color:var(--sidebar-nav-strong-border-color);color:var(--sidebar-nav-strong-color);font-size:var(--sidebar-nav-strong-font-size);font-weight:var(--sidebar-nav-strong-font-weight);text-transform:var(--sidebar-nav-strong-text-transform)}.sidebar-nav ul>li>span+ul,.sidebar-nav ul>li>strong+ul,.sidebar nav ul>li>span+ul,.sidebar nav ul>li>strong+ul{margin-left:0}.sidebar-nav ul>li:first-child>span,.sidebar-nav ul>li:first-child>strong,.sidebar nav ul>li:first-child>span,.sidebar nav ul>li:first-child>strong{margin-top:0}.sidebar-nav::-webkit-scrollbar,.sidebar nav::-webkit-scrollbar{width:0}@supports(width: env(safe-area-inset)){@media only screen and (orientation: landscape){.sidebar-nav,.sidebar nav{margin-left:calc(env(safe-area-inset-left)/2)}}}.sidebar-nav li>a:before,.sidebar-nav li>strong:before{display:inline-block}.sidebar-nav li>a{background-repeat:var(--sidebar-nav-pagelink-background-repeat);background-size:var(--sidebar-nav-pagelink-background-size)}.sidebar-nav li>a[href^="/"]:not([href*="?id="]),.sidebar-nav li>a[href^="#/"]:not([href*="?id="]){transition:var(--sidebar-nav-pagelink-transition)}.sidebar-nav li>a[href^="/"]:not([href*="?id="]),.sidebar-nav li>a[href^="/"]:not([href*="?id="])~ul a,.sidebar-nav li>a[href^="#/"]:not([href*="?id="]),.sidebar-nav li>a[href^="#/"]:not([href*="?id="])~ul a{padding:var(--sidebar-nav-pagelink-padding, var(--sidebar-nav-link-padding))}.sidebar-nav li>a[href^="/"]:not([href*="?id="]):only-child,.sidebar-nav li>a[href^="#/"]:not([href*="?id="]):only-child{background:var(--sidebar-nav-pagelink-background)}.sidebar-nav li>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li>a[href^="#/"]:not([href*="?id="]):not(:only-child){background:var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background))}.sidebar-nav li.active>a,.sidebar-nav li.collapse>a{border-width:var(--sidebar-nav-link-border-width--active, var(--sidebar-nav-link-border-width));border-style:var(--sidebar-nav-link-border-style--active, var(--sidebar-nav-link-border-style));border-color:var(--sidebar-nav-link-border-color--active, var(--sidebar-nav-link-border-color));background:var(--sidebar-nav-link-background--active, var(--sidebar-nav-link-background));color:var(--sidebar-nav-link-color--active, var(--sidebar-nav-link-color));font-weight:var(--sidebar-nav-link-font-weight--active, var(--sidebar-nav-link-font-weight));-webkit-text-decoration:var(--sidebar-nav-link-text-decoration--active, var(--sidebar-nav-link-text-decoration));text-decoration:var(--sidebar-nav-link-text-decoration--active, var(--sidebar-nav-link-text-decoration));-webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-decoration-color:var(--sidebar-nav-link-text-decoration-color)}.sidebar-nav li.active>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li.active>a[href^="#/"]:not([href*="?id="]):not(:only-child){background:var(--sidebar-nav-pagelink-background--active, var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background)))}.sidebar-nav li.collapse>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li.collapse>a[href^="#/"]:not([href*="?id="]):not(:only-child){background:var(--sidebar-nav-pagelink-background--collapse, var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background)))}.sidebar-nav li.collapse .app-sub-sidebar{display:none}.sidebar-nav>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l1, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l1, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l1--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l1, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l1--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color))))}.sidebar-nav>ul>li>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l2, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l2, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l2--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l2, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l2--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color))))}.sidebar-nav>ul>li>ul>li>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l3, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l3, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li>ul>li>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l3--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l3, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l3--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color))))}.sidebar-nav>ul>li>ul>li>ul>li>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l4, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l4, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li>ul>li>ul>li>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l4--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l4, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l4--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color))))}.sidebar-nav>:last-child{margin-bottom:2rem}.sidebar-toggle,.sidebar-toggle-button{width:var(--sidebar-toggle-width);outline:none}.sidebar-toggle{position:fixed;z-index:11;top:0;bottom:0;left:0;max-width:40px;margin:0;padding:0;border:0;background:rgba(0,0,0,0);-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer}.sidebar-toggle .sidebar-toggle-button{position:absolute;top:var(--sidebar-toggle-offset-top);left:var(--sidebar-toggle-offset-left);height:var(--sidebar-toggle-height);border-radius:var(--sidebar-toggle-border-radius);border-width:var(--sidebar-toggle-border-width);border-style:var(--sidebar-toggle-border-style);border-color:var(--sidebar-toggle-border-color);background:var(--sidebar-toggle-background, transparent);color:var(--sidebar-toggle-icon-color)}.sidebar-toggle span{position:absolute;top:calc(50% - var(--sidebar-toggle-icon-stroke-width)/2);left:calc(50% - var(--sidebar-toggle-icon-width)/2);height:var(--sidebar-toggle-icon-stroke-width);width:var(--sidebar-toggle-icon-width);background-color:currentColor}.sidebar-toggle span:nth-child(1){margin-top:calc(0px - var(--sidebar-toggle-icon-height)/2)}.sidebar-toggle span:nth-child(3){margin-top:calc(var(--sidebar-toggle-icon-height)/2)}@media(min-width: 48em){.sidebar-toggle{position:absolute;overflow:visible;top:var(--sidebar-toggle-offset-top);bottom:auto;left:0;height:var(--sidebar-toggle-height);transform:translateX(var(--sidebar-width))}.sidebar-toggle .sidebar-toggle-button{top:0}}@media print{.sidebar-toggle{display:none}}@media(max-width: 47.99em){body.close .sidebar,body.close .sidebar-toggle,body.close .sidebar+.content{transform:translateX(var(--sidebar-width))}}@media(min-width: 48em){body.close .sidebar+.content{transform:translateX(0)}}@media(max-width: 47.99em){body.close nav.app-nav,body.close .github-corner{display:none}}@media(min-width: 48em){body.close .sidebar,body.close .sidebar-toggle{transform:translateX(0)}}@media(min-width: 48em){body.close nav.app-nav{margin-left:0}}@media(max-width: 47.99em){body.close .sidebar-toggle{width:100%;max-width:none}body.close .sidebar-toggle span{margin-top:0}body.close .sidebar-toggle span:nth-child(1){transform:rotate(45deg)}body.close .sidebar-toggle span:nth-child(2){display:none}body.close .sidebar-toggle span:nth-child(3){transform:rotate(-45deg)}}@media(min-width: 48em){body.close .sidebar+.content{margin-left:0}}@media(min-width: 48em){body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}}body .docsify-copy-code-button,body .docsify-copy-code-button:after{border-radius:var(--border-radius-m, 0);border-top-left-radius:0;border-bottom-right-radius:0;background:var(--copycode-background);color:var(--copycode-color)}body .docsify-copy-code-button span{border-radius:var(--border-radius-s, 0)}body .docsify-pagination-container{border-top:var(--pagination-border-top);color:var(--pagination-color)}body .pagination-item-label{font-size:var(--pagination-label-font-size)}body .pagination-item-label svg{color:var(--pagination-label-color);height:var(--pagination-chevron-height);stroke:var(--pagination-chevron-stroke);stroke-linecap:var(--pagination-chevron-stroke-linecap);stroke-linejoin:var(--pagination-chevron-stroke-linecap);stroke-width:var(--pagination-chevron-stroke-width)}body .pagination-item-title{color:var(--pagination-title-color);font-size:var(--pagination-title-font-size)}body .app-name.hide{display:block}body .sidebar{padding:var(--sidebar-padding)}.sidebar .search{margin:0;padding:0;border:0}.sidebar .search input{padding:0;line-height:1;font-size:inherit}.sidebar .search .clear-button{width:auto}.sidebar .search .clear-button svg{transform:scale(1)}.sidebar .search .matching-post{border:none}.sidebar .search p{font-size:inherit}.sidebar .search{order:var(--search-flex-order);margin:var(--search-margin);padding:var(--search-padding);background:var(--search-background)}.sidebar .search a{color:inherit}.sidebar .search h2{margin:var(--search-result-heading-margin);font-size:var(--search-result-heading-font-size);font-weight:var(--search-result-heading-font-weight);color:var(--search-result-heading-color)}.sidebar .search .input-wrap{align-items:stretch;margin:var(--search-input-margin);background-color:var(--search-input-background-color);border-width:var(--search-input-border-width, 0);border-style:solid;border-color:var(--search-input-border-color);border-radius:var(--search-input-border-radius)}.sidebar .search input[type=search]{min-width:0;padding:var(--search-input-padding);border:none;background-color:rgba(0,0,0,0);background-image:var(--search-input-background-image);background-position:var(--search-input-background-position);background-repeat:var(--search-input-background-repeat);background-size:var(--search-input-background-size);font-size:var(--search-input-font-size);color:var(--search-input-color);transition:var(--search-input-transition)}.sidebar .search input[type=search]::-ms-clear{display:none}.sidebar .search input[type=search]::-moz-placeholder{color:var(--search-input-placeholder-color, #808080)}.sidebar .search input[type=search]::placeholder{color:var(--search-input-placeholder-color, #808080)}.sidebar .search input[type=search]::-webkit-input-placeholder{line-height:normal}.sidebar .search input[type=search]:focus{background-color:var(--search-input-background-color--focus, var(--search-input-background-color));background-image:var(--search-input-background-image--focus, var(--search-input-background-image));background-position:var(--search-input-background-position--focus, var(--search-input-background-position));background-size:var(--search-input-background-size--focus, var(--search-input-background-size))}@supports(width: env(safe-area-inset)){@media only screen and (orientation: landscape){.sidebar .search input[type=search]{margin-left:calc(env(safe-area-inset-left)/2)}}}.sidebar .search p{overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical;-webkit-line-clamp:2}.sidebar .search p:empty{text-align:center}.sidebar .search .clear-button{margin:0;padding:0 10px;border:none;line-height:1;background:rgba(0,0,0,0);cursor:pointer}.sidebar .search .clear-button svg circle{fill:var(--search-clear-icon-color1, #808080)}.sidebar .search .clear-button svg path{stroke:var(--search-clear-icon-color2, #fff)}.sidebar .search.show~*:not(h1){display:none}.sidebar .search .results-panel{display:none;color:var(--search-result-item-color);font-size:var(--search-result-item-font-size);font-weight:var(--search-result-item-font-weight)}.sidebar .search .results-panel.show{display:block}.sidebar .search .matching-post{margin:var(--search-result-item-margin);padding:var(--search-result-item-padding)}.sidebar .search .matching-post,.sidebar .search .matching-post:last-child{border-width:var(--search-result-item-border-width, 0) !important;border-style:var(--search-result-item-border-style);border-color:var(--search-result-item-border-color)}.sidebar .search .matching-post p{margin:0}.sidebar .search .search-keyword{margin:var(--search-result-keyword-margin);padding:var(--search-result-keyword-padding);border-radius:var(--search-result-keyword-border-radius);background-color:var(--search-result-keyword-background);color:var(--search-result-keyword-color, currentColor);font-style:normal;font-weight:var(--search-result-keyword-font-weight)}.medium-zoom-overlay,.medium-zoom-image--open,.medium-zoom-image--opened{z-index:2147483646 !important}.medium-zoom-overlay{background:var(--zoomimage-overlay-background) !important}:root{--mono-hue: 113;--mono-saturation: 0%;--mono-shade3: hsl(var(--mono-hue), var(--mono-saturation), 20%);--mono-shade2: hsl(var(--mono-hue), var(--mono-saturation), 30%);--mono-shade1: hsl(var(--mono-hue), var(--mono-saturation), 40%);--mono-base: hsl(var(--mono-hue), var(--mono-saturation), 50%);--mono-tint1: hsl(var(--mono-hue), var(--mono-saturation), 70%);--mono-tint2: hsl(var(--mono-hue), var(--mono-saturation), 89%);--mono-tint3: hsl(var(--mono-hue), var(--mono-saturation), 97%);--theme-hue: 204;--theme-saturation: 90%;--theme-lightness: 45%;--theme-color: hsl(var(--theme-hue), var(--theme-saturation), var(--theme-lightness));--modular-scale: 1.333;--modular-scale--2: calc(var(--modular-scale--1) / var(--modular-scale));--modular-scale--1: calc(var(--modular-scale-1) / var(--modular-scale));--modular-scale-1: 1rem;--modular-scale-2: calc(var(--modular-scale-1) * var(--modular-scale));--modular-scale-3: calc(var(--modular-scale-2) * var(--modular-scale));--modular-scale-4: calc(var(--modular-scale-3) * var(--modular-scale));--modular-scale-5: calc(var(--modular-scale-4) * var(--modular-scale));--font-size-xxxl: var(--modular-scale-5);--font-size-xxl: var(--modular-scale-4);--font-size-xl: var(--modular-scale-3);--font-size-l: var(--modular-scale-2);--font-size-m: var(--modular-scale-1);--font-size-s: var(--modular-scale--1);--font-size-xs: var(--modular-scale--2);--duration-slow: 1s;--duration-medium: 0.5s;--duration-fast: 0.25s;--spinner-size: 60px;--spinner-track-width: 4px;--spinner-track-color: rgba(0, 0, 0, 0.15);--spinner-transition-duration: var(--duration-medium)}:root{--base-background-color: #fff;--base-color: var(--mono-shade2);--base-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--base-font-size: 16px;--base-font-weight: normal;--base-line-height: 1.7;--emoji-size: calc(var(--base-line-height) * 1em);--hr-border: 1px solid var(--mono-tint2);--mark-background: #ffecb3;--pre-font-family: var(--code-font-family);--pre-font-size: var(--code-font-size);--pre-font-weight: normal;--selection-color: #b4d5fe;--small-font-size: var(--font-size-s);--strong-color: var(--heading-color);--strong-font-weight: 600;--subsup-font-size: var(--font-size-s)}:root{--content-max-width: 55em;--blockquote-background: var(--mono-tint3);--blockquote-border-style: solid;--blockquote-border-radius: var(--border-radius-m);--blockquote-em-font-weight: normal;--blockquote-font-weight: normal;--blockquote-padding: 1.5em;--code-font-family: Inconsolata, Consolas, Menlo, Monaco, "Andale Mono WT", "Andale Mono", "Lucida Console", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;--code-font-size: calc(var(--font-size-m) * 0.95);--code-font-weight: normal;--code-tab-size: 4;--code-block-border-radius: var(--border-radius-m);--code-block-line-height: var(--base-line-height);--code-block-margin: 1em 0;--code-block-padding: 1.75em 1.5em 1.5em 1.5em;--code-inline-background: var(--code-theme-background);--code-inline-border-radius: var(--border-radius-s);--code-inline-color: var(--code-theme-text);--code-inline-margin: 0 0.15em;--code-inline-padding: 0.125em 0.4em;--code-theme-background: var(--mono-tint3);--heading-color: var(--mono-shade3);--heading-margin: 2.5rem 0 0;--heading-h1-border-style: solid;--heading-h1-font-size: var(--font-size-xxl);--heading-h2-border-style: solid;--heading-h2-font-size: var(--font-size-xl);--heading-h3-border-style: solid;--heading-h3-font-size: var(--font-size-l);--heading-h4-border-style: solid;--heading-h4-font-size: var(--font-size-m);--heading-h5-border-style: solid;--heading-h5-font-size: var(--font-size-s);--heading-h6-border-style: solid;--heading-h6-font-size: var(--font-size-xs);--kbd-background: var(--mono-tint3);--kbd-border-radius: var(--border-radius-m);--kbd-margin: 0 0.3em;--kbd-min-width: 2.5em;--kbd-padding: 0.65em 0.5em;--link-text-decoration: underline;--notice-background: var(--mono-tint3);--notice-border-radius: var(--border-radius-m);--notice-border-style: solid;--notice-font-weight: normal;--notice-padding: 1em 1.5em;--notice-before-font-weight: normal;--table-cell-padding: 0.75em 0.5em;--table-head-border-color: var(--table-cell-border-color);--table-head-font-weight: var(--strong-font-weight);--table-row-odd-background: var(--mono-tint3)}:root{--cover-margin: 0 auto;--cover-max-width: 40em;--cover-text-align: center;--cover-background-color: var(--base-background-color);--cover-background-mask-color: var(--base-background-color);--cover-background-mask-opacity: 0.8;--cover-background-position: center center;--cover-background-repeat: no-repeat;--cover-background-size: cover;--cover-blockquote-font-size: var(--font-size-l);--cover-border-color: var(--theme-color);--cover-button-border: 1px solid var(--theme-color);--cover-button-border-radius: var(--border-radius-m);--cover-button-color: var(--theme-color);--cover-button-padding: 0.5em 2rem;--cover-button-text-decoration: none;--cover-button-transition: all var(--duration-fast) ease-in-out;--cover-button-primary-background: var(--theme-color);--cover-button-primary-border: 1px solid var(--theme-color);--cover-button-primary-color: #fff;--cover-heading-color: var(--theme-color);--cover-heading-font-size: var(--font-size-xxl);--cover-heading-font-weight: normal;--cover-link-text-decoration: underline}:root{--navbar-root-border-style: solid;--navbar-root-margin: 0 0 0 1.5em;--navbar-root-transition: all var(--duration-fast);--navbar-menu-background: var(--base-background-color);--navbar-menu-border-radius: var(--border-radius-m);--navbar-menu-box-shadow: rgba(45,45,45,0.05) 0px 0px 1px, rgba(49,49,49,0.05) 0px 1px 2px, rgba(42,42,42,0.05) 0px 2px 4px, rgba(32,32,32,0.05) 0px 4px 8px, rgba(49,49,49,0.05) 0px 8px 16px, rgba(35,35,35,0.05) 0px 16px 32px;--navbar-menu-padding: 0.5em;--navbar-menu-transition: all var(--duration-fast);--navbar-menu-link-border-style: solid;--navbar-menu-link-margin: 0.75em 0.5em;--navbar-menu-link-padding: 0.2em 0}:root{--copycode-background: #808080;--copycode-color: #fff}:root{--docsifytabs-border-color: var(--mono-tint2);--docsifytabs-border-radius-px: var(--border-radius-s);--docsifytabs-tab-background: var(--mono-tint3);--docsifytabs-tab-color: var(--mono-tint1)}:root{--pagination-border-top: 1px solid var(--mono-tint2);--pagination-chevron-height: 0.8em;--pagination-chevron-stroke: currentColor;--pagination-chevron-stroke-linecap: round;--pagination-chevron-stroke-width: 1px;--pagination-label-font-size: var(--font-size-s);--pagination-title-font-size: var(--font-size-l)}:root{--search-margin: 1.5rem 0 0;--search-input-background-repeat: no-repeat;--search-input-border-color: var(--mono-tint1);--search-input-border-width: 1px;--search-input-padding: 0.5em;--search-flex-order: 1;--search-result-heading-color: var(--heading-color);--search-result-heading-font-size: var(--base-font-size);--search-result-heading-font-weight: normal;--search-result-heading-margin: 0 0 0.25em;--search-result-item-border-color: var(--mono-tint2);--search-result-item-border-style: solid;--search-result-item-border-width: 0 0 1px 0;--search-result-item-font-weight: normal;--search-result-item-padding: 1em 0;--search-result-keyword-background: var(--mark-background);--search-result-keyword-border-radius: var(--border-radius-s);--search-result-keyword-color: var(--mark-color);--search-result-keyword-font-weight: normal;--search-result-keyword-margin: 0 0.1em;--search-result-keyword-padding: 0.2em 0}:root{--zoomimage-overlay-background: rgba(0, 0, 0, 0.875)}:root{--sidebar-background: var(--base-background-color);--sidebar-border-width: 0;--sidebar-padding: 0 25px;--sidebar-transition-duration: var(--duration-fast);--sidebar-width: 17rem;--sidebar-name-font-size: var(--font-size-l);--sidebar-name-font-weight: normal;--sidebar-name-margin: 1.5rem 0 0;--sidebar-name-text-align: center;--sidebar-nav-strong-border-color: var(--sidebar-border-color);--sidebar-nav-strong-color: var(--heading-color);--sidebar-nav-strong-font-weight: var(--strong-font-weight);--sidebar-nav-strong-margin: 1.5em 0 0.5em;--sidebar-nav-strong-padding: 0.25em 0;--sidebar-nav-indent: 1em;--sidebar-nav-margin: 1.5rem 0 0;--sidebar-nav-link-border-style: solid;--sidebar-nav-link-border-width: 0;--sidebar-nav-link-color: var(--base-color);--sidebar-nav-link-font-weight: normal;--sidebar-nav-link-padding: 0.25em 0;--sidebar-nav-link-text-decoration--active: underline;--sidebar-nav-link-text-decoration--hover: underline;--sidebar-nav-link-before-margin: 0 0.35em 0 0;--sidebar-nav-pagelink-transition: var(--sidebar-nav-link-transition);--sidebar-toggle-border-radius: var(--border-radius-s);--sidebar-toggle-border-style: solid;--sidebar-toggle-border-width: 0;--sidebar-toggle-height: 36px;--sidebar-toggle-icon-color: var(--base-color);--sidebar-toggle-icon-height: 10px;--sidebar-toggle-icon-stroke-width: 1px;--sidebar-toggle-icon-width: 16px;--sidebar-toggle-offset-left: 0;--sidebar-toggle-offset-top: calc(35px - (var(--sidebar-toggle-height) / 2));--sidebar-toggle-width: 44px}:root{--code-theme-background: #f3f3f3;--code-theme-comment: #6e8090;--code-theme-function: #dd4a68;--code-theme-keyword: #07a;--code-theme-operator: #a67f59;--code-theme-punctuation: #999;--code-theme-selector: #690;--code-theme-tag: #905;--code-theme-text: #333;--code-theme-variable: #e90}:root{--border-radius-s: 2px;--border-radius-m: 4px;--border-radius-l: 8px;--strong-font-weight: 600;--blockquote-border-color: var(--theme-color);--blockquote-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0;--blockquote-border-width: 0 0 0 4px;--code-inline-background: var(--mono-tint2);--code-theme-background: var(--mono-tint3);--heading-font-weight: var(--strong-font-weight);--heading-h1-font-weight: 400;--heading-h2-font-weight: 400;--heading-h2-border-color: var(--mono-tint2);--heading-h2-border-width: 0 0 1px 0;--heading-h2-margin: 2.5rem 0 1.5rem;--heading-h2-padding: 0 0 1rem 0;--kbd-border: 1px solid var(--mono-tint2);--notice-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0;--notice-border-width: 0 0 0 4px;--notice-padding: 1em 1.5em 1em 3em;--notice-before-border-radius: 100%;--notice-before-font-weight: bold;--notice-before-height: 1.5em;--notice-before-left: 0.75em;--notice-before-line-height: 1.5;--notice-before-margin: 0 0.25em 0 0;--notice-before-position: absolute;--notice-before-width: var(--notice-before-height);--notice-important-background: hsl(340, 60%, 96%);--notice-important-border-color: hsl(340, 90%, 45%);--notice-important-before-background: var(--notice-important-border-color) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3E%3Cpath d='M10 14C10 15.1 9.1 16 8 16 6.9 16 6 15.1 6 14 6 12.9 6.9 12 8 12 9.1 12 10 12.9 10 14Z'/%3E%3Cpath d='M10 1.6C10 1.2 9.8 0.9 9.6 0.7 9.2 0.3 8.6 0 8 0 7.4 0 6.8 0.2 6.5 0.6 6.2 0.9 6 1.2 6 1.6 6 1.7 6 1.8 6 1.9L6.8 9.6C6.9 9.9 7 10.1 7.2 10.2 7.4 10.4 7.7 10.5 8 10.5 8.3 10.5 8.6 10.4 8.8 10.3 9 10.1 9.1 9.9 9.2 9.6L10 1.9C10 1.8 10 1.7 10 1.6Z'/%3E%3C/svg%3E") center / 0.875em no-repeat;--notice-important-before-color: #fff;--notice-important-before-content: "";--notice-tip-background: hsl(204, 60%, 96%);--notice-tip-border-color: hsl(204, 90%, 45%);--notice-tip-before-background: var(--notice-tip-border-color) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3E%3Cpath d='M9.1 0C10.2 0 10.7 0.7 10.7 1.6 10.7 2.6 9.8 3.6 8.6 3.6 7.6 3.6 7 3 7 2 7 1.1 7.7 0 9.1 0Z'/%3E%3Cpath d='M5.8 16C5 16 4.4 15.5 5 13.2L5.9 9.1C6.1 8.5 6.1 8.2 5.9 8.2 5.7 8.2 4.6 8.6 3.9 9.1L3.5 8.4C5.6 6.6 7.9 5.6 8.9 5.6 9.8 5.6 9.9 6.6 9.5 8.2L8.4 12.5C8.2 13.2 8.3 13.5 8.5 13.5 8.7 13.5 9.6 13.2 10.4 12.5L10.9 13.2C8.9 15.2 6.7 16 5.8 16Z'/%3E%3C/svg%3E") center / 0.875em no-repeat;--notice-tip-before-color: #fff;--notice-tip-before-content: "";--table-cell-border-color: var(--mono-tint2);--table-cell-border-width: 1px 0;--cover-background-color: hsl(var(--theme-hue), 25%, 60%);--cover-background-image: radial-gradient(ellipse at center 115%, rgba(255, 255, 255, 0.9), transparent);--cover-blockquote-color: var(--strong-color);--cover-heading-color: #fff;--cover-heading-font-size-max: 56;--cover-heading-font-size-min: 34;--cover-heading-font-weight: 200;--navbar-root-color--active: var(--theme-color);--navbar-menu-border-radius: var(--border-radius-m);--navbar-menu-root-background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9.6' height='6' viewBox='0 0 9.6 6'%3E%3Cpath d='M1.5 1.5l3.3 3 3.3-3' stroke-width='1.5' stroke='rgb%28179, 179, 179%29' fill='none' stroke-linecap='square' stroke-linejoin='miter' vector-effect='non-scaling-stroke'/%3E%3C/svg%3E") right no-repeat;--navbar-menu-root-padding: 0 18px 0 0;--search-input-background-color: #fff;--search-input-background-image: url("data:image/svg+xml,%3Csvg height='20px' width='20px' viewBox='0 0 24 24' fill='none' stroke='rgba(0, 0, 0, 0.3)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10.5' cy='10.5' r='7.5' vector-effect='non-scaling-stroke'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='15.8' y2='15.8' vector-effect='non-scaling-stroke'%3E%3C/line%3E%3C/svg%3E");--search-input-background-position: 21px center;--search-input-border-color: var(--sidebar-border-color);--search-input-border-width: 1px 0;--search-input-margin: 0 -25px;--search-input-padding: 0.65em 1em 0.65em 50px;--search-input-placeholder-color: rgba(0, 0, 0, 0.4);--search-clear-icon-color1: rgba(0, 0, 0, 0.3);--search-result-heading-font-weight: var(--strong-font-weight);--search-result-item-border-color: var(--sidebar-border-color);--search-result-keyword-border-radius: var(--border-radius-s);--sidebar-background: var(--mono-tint3);--sidebar-border-color: var(--mono-tint2);--sidebar-border-width: 0 1px 0 0;--sidebar-name-color: var(--theme-color);--sidebar-name-font-weight: 300;--sidebar-nav-strong-border-width: 0 0 1px 0;--sidebar-nav-strong-font-size: smaller;--sidebar-nav-strong-margin: 2em -25px 0.75em 0;--sidebar-nav-strong-padding: 0.25em 0 0.75em 0;--sidebar-nav-strong-text-transform: uppercase;--sidebar-nav-link-border-color: transparent;--sidebar-nav-link-border-color--active: var(--theme-color);--sidebar-nav-link-border-width: 0 4px 0 0;--sidebar-nav-link-color--active: var(--theme-color);--sidebar-nav-link-margin: 0 -25px 0 0;--sidebar-nav-link-text-decoration: none;--sidebar-nav-link-text-decoration--active: none;--sidebar-nav-link-text-decoration--hover: underline;--sidebar-nav-pagelink-background: no-repeat 2px calc(50% - 2.5px) / 6px 5px linear-gradient(45deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4px), no-repeat 2px calc(50% + 2.5px) / 6px 5px linear-gradient(135deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4px);--sidebar-nav-pagelink-background--active: no-repeat 0px center / 5px 6px linear-gradient(225deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4.25px), no-repeat 5px center / 5px 6px linear-gradient(135deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4.25px);--sidebar-nav-pagelink-background--collapse: no-repeat 2px calc(50% - 2.5px) / 6px 5px linear-gradient(45deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4px), no-repeat 2px calc(50% + 2.5px) / 6px 5px linear-gradient(135deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4px);--sidebar-nav-pagelink-background--loaded: no-repeat 0px center / 5px 6px linear-gradient(225deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4.25px), no-repeat 5px center / 5px 6px linear-gradient(135deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4.25px);--sidebar-nav-pagelink-padding: 0.25em 0 0.25em 20px;--sidebar-nav-pagelink-transition: none;--sidebar-toggle-background: var(--sidebar-border-color);--sidebar-toggle-border-radius: 0 var(--border-radius-s) var(--border-radius-s) 0;--sidebar-toggle-width: 32px}:root{--code-theme-background: #222;--code-theme-comment: #516e7a;--code-theme-function: #f07178;--code-theme-keyword: #c2e78c;--code-theme-operator: #ffcb6b;--code-theme-punctuation: #89ddff;--code-theme-selector: #ffcb6b;--code-theme-tag: #f07178;--code-theme-text: #f3f3f3;--code-theme-variable: #ffcb6b}:root{--mono-hue: 201;--mono-saturation: 18%;--mono-shade3: hsl(var(--mono-hue), var(--mono-saturation), 13%);--mono-shade2: hsl(var(--mono-hue), var(--mono-saturation), 15%);--mono-shade1: hsl(var(--mono-hue), var(--mono-saturation), 17%);--mono-base: hsl(var(--mono-hue), var(--mono-saturation), 19%);--mono-tint1: hsl(var(--mono-hue), var(--mono-saturation), 25%);--mono-tint2: hsl(var(--mono-hue), var(--mono-saturation), 35%);--mono-tint3: hsl(var(--mono-hue), var(--mono-saturation), 43%);--spinner-track-color: rgba(255, 255, 255, 0.15);--base-background-color: var(--mono-base);--base-color: #d3d3d3;--hr-border: 1px solid var(--mono-tint2);--mark-background: #ffcb6b;--mark-color: var(--base-background-color);--selection-color: rgba(94, 131, 175, 0.75);--blockquote-background: var(--mono-shade2);--code-inline-background: var(--mono-tint1);--code-theme-background: var(--mono-shade2);--heading-color: #fff;--heading-h2-border-color: var(--mono-tint2);--kbd-background: var(--mono-shade2);--kbd-border: none;--kbd-color: var(--strong-color);--notice-important-background: var(--mono-shade2);--notice-tip-background: var(--mono-shade2);--table-cell-border-color: var(--mono-tint1);--table-row-odd-background: var(--mono-shade2);--cover-background-color: var(--base-background-color);--cover-background-image: radial-gradient(ellipse at center bottom, var(--mono-tint3), transparent);--cover-blockquote-color: var(--mark-background);--cover-button-border: 1px solid var(--mono-tint3);--cover-button-color: #fff;--navbar-menu-background: var(--mono-tint1);--navbar-menu-box-shadow: rgba(0,0,0,0.05) 0px 0px 1px, rgba(0,0,0,0.05) 0px 1px 2px, rgba(0,0,0,0.05) 0px 2px 4px, rgba(0,0,0,0.05) 0px 4px 8px, rgba(0,0,0,0.05) 0px 8px 16px, rgba(0,0,0,0.05) 0px 16px 32px;--copycode-background: var(--mono-tint1);--copycode-color: #fff;--docsifytabs-border-color: var(--mono-tint2);--docsifytabs-tab-background: var(--mono-shade1);--docsifytabs-tab-color: var(--mono-tint2);--pagination-border-top: 1px solid var(--mono-tint2);--pagination-title-color: #fff;--search-input-background-color: var(--mono-shade2);--search-input-background-image: url("data:image/svg+xml,%3Csvg height='20px' width='20px' viewBox='0 0 24 24' fill='none' stroke='rgba(255, 255, 255, 0.3)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10.5' cy='10.5' r='7.5' vector-effect='non-scaling-stroke'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='15.8' y2='15.8' vector-effect='non-scaling-stroke'%3E%3C/line%3E%3C/svg%3E");--search-input-border-color: var(--mono-tint1);--search-input-placeholder-color: rgba(255, 255, 255, 0.4);--search-clear-icon-color1: rgba(255, 255, 255, 0.3);--sidebar-background: var(--mono-shade1);--sidebar-border-color: var(--mono-tint1);--sidebar-nav-pagelink-background: no-repeat 2px calc(50% - 2.5px) / 6px 5px linear-gradient(45deg, transparent 2.75px, var(--mono-tint2) 2.75px 4.25px, transparent 4px), no-repeat 2px calc(50% + 2.5px) / 6px 5px linear-gradient(135deg, transparent 2.75px, var(--mono-tint2) 2.75px 4.25px, transparent 4px);--sidebar-nav-pagelink-background--loaded: no-repeat 0px center / 5px 6px linear-gradient(225deg, transparent 2.75px, var(--mono-tint2) 2.75px 4.25px, transparent 4.25px), no-repeat 5px center / 5px 6px linear-gradient(135deg, transparent 2.75px, var(--mono-tint2) 2.75px 4.25px, transparent 4.25px)} +.github-corner { + position: absolute; + z-index: 40; + top: 0; + right: 0; + border-bottom: 0; + text-decoration: none; +} +.github-corner svg { + height: 70px; + width: 70px; + fill: var(--theme-color); + color: var(--base-background-color); +} +.github-corner:hover .octo-arm { + -webkit-animation: octocat-wave 560ms ease-in-out; + animation: octocat-wave 560ms ease-in-out; +} +@-webkit-keyframes octocat-wave { + 0%, + 100% { + transform: rotate(0); + } + 20%, + 60% { + transform: rotate(-25deg); + } + 40%, + 80% { + transform: rotate(10deg); + } +} +@keyframes octocat-wave { + 0%, + 100% { + transform: rotate(0); + } + 20%, + 60% { + transform: rotate(-25deg); + } + 40%, + 80% { + transform: rotate(10deg); + } +} +.progress { + position: fixed; + z-index: 2147483647; + top: 0; + left: 0; + right: 0; + height: 3px; + width: 0; + background-color: var(--theme-color); + transition: + width var(--duration-fast), + opacity calc(var(--duration-fast) * 2); +} +body.ready-transition:after, +body.ready-transition > *:not(.progress) { + opacity: 0; + transition: opacity var(--spinner-transition-duration); +} +body.ready-transition:after { + content: ''; + position: absolute; + z-index: 1000; + top: calc(50% - var(--spinner-size) / 2); + left: calc(50% - var(--spinner-size) / 2); + height: var(--spinner-size); + width: var(--spinner-size); + border: var(--spinner-track-width, 0) solid var(--spinner-track-color); + border-left-color: var(--theme-color); + border-left-color: var(--theme-color); + border-radius: 50%; + -webkit-animation: spinner var(--duration-slow) infinite linear; + animation: spinner var(--duration-slow) infinite linear; +} +body.ready-transition.ready-spinner:after { + opacity: 1; +} +body.ready-transition.ready-fix:after { + opacity: 0; +} +body.ready-transition.ready-fix > *:not(.progress) { + opacity: 1; + transition-delay: var(--spinner-transition-duration); +} +@-webkit-keyframes spinner { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +@keyframes spinner { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +*, +*:before, +*:after { + box-sizing: inherit; + font-size: inherit; + -webkit-overflow-scrolling: touch; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-text-size-adjust: none; + -webkit-touch-callout: none; +} +:root { + box-sizing: border-box; + background-color: var(--base-background-color); + font-size: var(--base-font-size); + font-weight: var(--base-font-weight); + line-height: var(--base-line-height); + letter-spacing: var(--base-letter-spacing); + color: var(--base-color); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-smoothing: antialiased; +} +html, +button, +input, +optgroup, +select, +textarea { + font-family: var(--base-font-family); +} +button, +input, +optgroup, +select, +textarea { + font-size: 100%; + margin: 0; +} +a { + text-decoration: none; + -webkit-text-decoration-skip: ink; + text-decoration-skip-ink: auto; +} +body { + margin: 0; +} +hr { + height: 0; + margin: 2em 0; + border: none; + border-bottom: var(--hr-border, 0); +} +img { + max-width: 100%; + border: 0; +} +main { + display: block; +} +main.hidden { + display: none; +} +mark { + background: var(--mark-background); + color: var(--mark-color); +} +pre { + font-family: var(--pre-font-family); + font-size: var(--pre-font-size); + font-weight: var(--pre-font-weight); + line-height: var(--pre-line-height); +} +small { + display: inline-block; + font-size: var(--small-font-size); +} +strong { + font-weight: var(--strong-font-weight); + color: var(--strong-color, currentColor); +} +sub, +sup { + font-size: var(--subsup-font-size); + line-height: 0; + position: relative; + vertical-align: baseline; +} +sub { + bottom: -0.25em; +} +sup { + top: -0.5em; +} +body:not([data-platform^='Mac']) * { + scrollbar-color: hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3) + hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1); + scrollbar-width: thin; +} +body:not([data-platform^='Mac']) * ::-webkit-scrollbar { + width: 5px; + height: 5px; +} +body:not([data-platform^='Mac']) * ::-webkit-scrollbar-thumb { + background: hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3); +} +body:not([data-platform^='Mac']) * ::-webkit-scrollbar-track { + background: hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1); +} +::-moz-selection { + background: var(--selection-color); +} +::selection { + background: var(--selection-color); +} +.emoji { + height: var(--emoji-size); + vertical-align: middle; +} +.task-list-item { + list-style: none; +} +.task-list-item input { + margin-right: 0.5em; + margin-left: 0; + vertical-align: 0.075em; +} +.markdown-section code[class*='lang-'], +.markdown-section pre[data-lang] { + font-family: var(--code-font-family); + font-size: var(--code-font-size); + font-weight: var(--code-font-weight); + letter-spacing: normal; + line-height: var(--code-block-line-height); + -moz-tab-size: var(--code-tab-size); + -o-tab-size: var(--code-tab-size); + tab-size: var(--code-tab-size); + text-align: left; + white-space: pre; + word-spacing: normal; + word-wrap: normal; + word-break: normal; + -webkit-hyphens: none; + hyphens: none; +} +.markdown-section pre[data-lang] { + position: relative; + overflow: hidden; + margin: var(--code-block-margin); + padding: 0; + border-radius: var(--code-block-border-radius); +} +.markdown-section pre[data-lang]::after { + content: attr(data-lang); + position: absolute; + top: 0.75em; + right: 0.75em; + opacity: 0.6; + color: inherit; + font-size: var(--font-size-s); + line-height: 1; +} +.markdown-section pre[data-lang] code { + display: block; + overflow: auto; + padding: var(--code-block-padding); +} +code[class*='lang-'], +pre[data-lang] { + color: var(--code-theme-text); +} +pre[data-lang]::-moz-selection, +pre[data-lang] ::-moz-selection, +code[class*='lang-']::-moz-selection, +code[class*='lang-'] ::-moz-selection { + background: var(--code-theme-selection, var(--selection-color)); +} +pre[data-lang]::-moz-selection, +pre[data-lang] ::-moz-selection, +code[class*='lang-']::-moz-selection, +code[class*='lang-'] ::-moz-selection { + background: var(--code-theme-selection, var(--selection-color)); +} +pre[data-lang]::selection, +pre[data-lang] ::selection, +code[class*='lang-']::selection, +code[class*='lang-'] ::selection { + background: var(--code-theme-selection, var(--selection-color)); +} +:not(pre) > code[class*='lang-'], +pre[data-lang] { + background: var(--code-theme-background); +} +.namespace { + opacity: 0.7; +} +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: var(--code-theme-comment); +} +.token.punctuation { + color: var(--code-theme-punctuation); +} +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: var(--code-theme-tag); +} +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: var(--code-theme-selector); +} +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: var(--code-theme-operator); +} +.token.atrule, +.token.attr-value, +.token.keyword { + color: var(--code-theme-keyword); +} +.token.function { + color: var(--code-theme-function); +} +.token.regex, +.token.important, +.token.variable { + color: var(--code-theme-variable); +} +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} +.token.entity { + cursor: help; +} +.markdown-section { + position: relative; + max-width: var(--content-max-width); + margin: 0 auto; + padding: 2rem 45px; +} +.app-nav:not(:empty) ~ main .markdown-section { + padding-top: 3.5rem; +} +.markdown-section figure, +.markdown-section p, +.markdown-section ol, +.markdown-section ul { + margin: 1em 0; +} +.markdown-section ol, +.markdown-section ul { + padding-left: 1.5rem; +} +.markdown-section ol ol, +.markdown-section ol ul, +.markdown-section ul ol, +.markdown-section ul ul { + margin-top: 0.15rem; + margin-bottom: 0.15rem; +} +.markdown-section a { + border-bottom: var(--link-border-bottom); + color: var(--link-color); + -webkit-text-decoration: var(--link-text-decoration); + text-decoration: var(--link-text-decoration); + -webkit-text-decoration-color: var(--link-text-decoration-color); + text-decoration-color: var(--link-text-decoration-color); +} +.markdown-section a:hover { + border-bottom: var(--link-border-bottom--hover, var(--link-border-bottom, 0)); + color: var(--link-color--hover, var(--link-color)); + -webkit-text-decoration: var( + --link-text-decoration--hover, + var(--link-text-decoration) + ); + text-decoration: var(--link-text-decoration--hover, var(--link-text-decoration)); + -webkit-text-decoration-color: var( + --link-text-decoration-color--hover, + var(--link-text-decoration-color) + ); + text-decoration-color: var( + --link-text-decoration-color--hover, + var(--link-text-decoration-color) + ); +} +.markdown-section a.anchor { + border-bottom: 0; + color: inherit; + text-decoration: none; +} +.markdown-section a.anchor:hover { + text-decoration: underline; +} +.markdown-section blockquote { + overflow: visible; + margin: 2em 0; + padding: var(--blockquote-padding); + border-width: var(--blockquote-border-width, 0); + border-style: var(--blockquote-border-style); + border-color: var(--blockquote-border-color); + border-radius: var(--blockquote-border-radius); + background: var(--blockquote-background); + color: var(--blockquote-color); + font-family: var(--blockquote-font-family); + font-size: var(--blockquote-font-size); + font-style: var(--blockquote-font-style); + font-weight: var(--blockquote-font-weight); + quotes: '“' '”' '‘' '’'; +} +.markdown-section blockquote em { + font-family: var(--blockquote-em-font-family); + font-size: var(--blockquote-em-font-size); + font-style: var(--blockquote-em-font-style); + font-weight: var(--blockquote-em-font-weight); +} +.markdown-section blockquote p:first-child { + margin-top: 0; +} +.markdown-section blockquote p:first-child:before, +.markdown-section blockquote p:first-child:after { + color: var(--blockquote-quotes-color); + font-family: var(--blockquote-quotes-font-family); + font-size: var(--blockquote-quotes-font-size); + line-height: 0; +} +.markdown-section blockquote p:first-child:before { + content: var(--blockquote-quotes-open); + margin-right: 0.15em; + vertical-align: -0.45em; +} +.markdown-section blockquote p:first-child:after { + content: var(--blockquote-quotes-close); + margin-left: 0.15em; + vertical-align: -0.55em; +} +.markdown-section blockquote p:last-child { + margin-bottom: 0; +} +.markdown-section code { + font-family: var(--code-font-family); + font-size: var(--code-font-size); + font-weight: var(--code-font-weight); + line-height: inherit; +} +.markdown-section code:not([class*='lang-']):not([class*='language-']) { + margin: var(--code-inline-margin); + padding: var(--code-inline-padding); + border-radius: var(--code-inline-border-radius); + background: var(--code-inline-background); + color: var(--code-inline-color, currentColor); + white-space: nowrap; +} +.markdown-section h1:first-child, +.markdown-section h2:first-child, +.markdown-section h3:first-child, +.markdown-section h4:first-child, +.markdown-section h5:first-child, +.markdown-section h6:first-child { + margin-top: 0; +} +.markdown-section h1 a[data-id], +.markdown-section h2 a[data-id], +.markdown-section h3 a[data-id], +.markdown-section h4 a[data-id], +.markdown-section h5 a[data-id], +.markdown-section h6 a[data-id] { + display: inline-block; +} +.markdown-section h1 code, +.markdown-section h2 code, +.markdown-section h3 code, +.markdown-section h4 code, +.markdown-section h5 code, +.markdown-section h6 code { + font-size: 0.875em; +} +.markdown-section h1 + h2, +.markdown-section h1 + h3, +.markdown-section h1 + h4, +.markdown-section h1 + h5, +.markdown-section h1 + h6, +.markdown-section h2 + h3, +.markdown-section h2 + h4, +.markdown-section h2 + h5, +.markdown-section h2 + h6, +.markdown-section h3 + h4, +.markdown-section h3 + h5, +.markdown-section h3 + h6, +.markdown-section h4 + h5, +.markdown-section h4 + h6, +.markdown-section h5 + h6 { + margin-top: 1rem; +} +.markdown-section h1 { + margin: var(--heading-h1-margin, var(--heading-margin)); + padding: var(--heading-h1-padding, var(--heading-padding)); + border-width: var(--heading-h1-border-width, 0); + border-style: var(--heading-h1-border-style); + border-color: var(--heading-h1-border-color); + font-family: var(--heading-h1-font-family, var(--heading-font-family)); + font-size: var(--heading-h1-font-size); + font-weight: var(--heading-h1-font-weight, var(--heading-font-weight)); + line-height: var(--base-line-height); + color: var(--heading-h1-color, var(--heading-color)); +} +.markdown-section h2 { + margin: var(--heading-h2-margin, var(--heading-margin)); + padding: var(--heading-h2-padding, var(--heading-padding)); + border-width: var(--heading-h2-border-width, 0); + border-style: var(--heading-h2-border-style); + border-color: var(--heading-h2-border-color); + font-family: var(--heading-h2-font-family, var(--heading-font-family)); + font-size: var(--heading-h2-font-size); + font-weight: var(--heading-h2-font-weight, var(--heading-font-weight)); + line-height: var(--base-line-height); + color: var(--heading-h2-color, var(--heading-color)); +} +.markdown-section h3 { + margin: var(--heading-h3-margin, var(--heading-margin)); + padding: var(--heading-h3-padding, var(--heading-padding)); + border-width: var(--heading-h3-border-width, 0); + border-style: var(--heading-h3-border-style); + border-color: var(--heading-h3-border-color); + font-family: var(--heading-h3-font-family, var(--heading-font-family)); + font-size: var(--heading-h3-font-size); + font-weight: var(--heading-h3-font-weight, var(--heading-font-weight)); + color: var(--heading-h3-color, var(--heading-color)); +} +.markdown-section h4 { + margin: var(--heading-h4-margin, var(--heading-margin)); + padding: var(--heading-h4-padding, var(--heading-padding)); + border-width: var(--heading-h4-border-width, 0); + border-style: var(--heading-h4-border-style); + border-color: var(--heading-h4-border-color); + font-family: var(--heading-h4-font-family, var(--heading-font-family)); + font-size: var(--heading-h4-font-size); + font-weight: var(--heading-h4-font-weight, var(--heading-font-weight)); + color: var(--heading-h4-color, var(--heading-color)); +} +.markdown-section h5 { + margin: var(--heading-h5-margin, var(--heading-margin)); + padding: var(--heading-h5-padding, var(--heading-padding)); + border-width: var(--heading-h5-border-width, 0); + border-style: var(--heading-h5-border-style); + border-color: var(--heading-h5-border-color); + font-family: var(--heading-h5-font-family, var(--heading-font-family)); + font-size: var(--heading-h5-font-size); + font-weight: var(--heading-h5-font-weight, var(--heading-font-weight)); + color: var(--heading-h5-color, var(--heading-color)); +} +.markdown-section h6 { + margin: var(--heading-h6-margin, var(--heading-margin)); + padding: var(--heading-h6-padding, var(--heading-padding)); + border-width: var(--heading-h6-border-width, 0); + border-style: var(--heading-h6-border-style); + border-color: var(--heading-h6-border-color); + font-family: var(--heading-h6-font-family, var(--heading-font-family)); + font-size: var(--heading-h6-font-size); + font-weight: var(--heading-h6-font-weight, var(--heading-font-weight)); + color: var(--heading-h6-color, var(--heading-color)); +} +.markdown-section iframe { + margin: 1em 0; +} +.markdown-section img { + max-width: 100%; +} +.markdown-section kbd { + display: inline-block; + min-width: var(--kbd-min-width); + margin: var(--kbd-margin); + padding: var(--kbd-padding); + border: var(--kbd-border); + border-radius: var(--kbd-border-radius); + background: var(--kbd-background); + font-family: inherit; + font-size: var(--kbd-font-size); + text-align: center; + letter-spacing: 0; + line-height: 1; + color: var(--kbd-color); +} +.markdown-section kbd + kbd { + margin-left: -0.15em; +} +.markdown-section table { + display: block; + overflow: auto; + margin: 1rem 0; + border-spacing: 0; + border-collapse: collapse; +} +.markdown-section th, +.markdown-section td { + padding: var(--table-cell-padding); +} +.markdown-section th:not([align]) { + text-align: left; +} +.markdown-section thead { + border-color: var(--table-head-border-color); + border-style: solid; + border-width: var(--table-head-border-width, 0); + background: var(--table-head-background); +} +.markdown-section th { + font-weight: var(--table-head-font-weight); + color: var(--strong-color); +} +.markdown-section td { + border-color: var(--table-cell-border-color); + border-style: solid; + border-width: var(--table-cell-border-width, 0); +} +.markdown-section tbody { + border-color: var(--table-body-border-color); + border-style: solid; + border-width: var(--table-body-border-width, 0); +} +.markdown-section tbody tr:nth-child(odd) { + background: var(--table-row-odd-background); +} +.markdown-section tbody tr:nth-child(even) { + background: var(--table-row-even-background); +} +.markdown-section > ul .task-list-item { + margin-left: -1.25em; +} +.markdown-section > ul .task-list-item .task-list-item { + margin-left: 0; +} +.markdown-section .table-wrapper { + overflow-x: auto; +} +.markdown-section .table-wrapper table { + display: table; + width: 100%; +} +.markdown-section .table-wrapper td::before { + display: none; +} +@media (max-width: 30em) { + .markdown-section .table-wrapper tbody, + .markdown-section .table-wrapper tr, + .markdown-section .table-wrapper td { + display: block; + } + .markdown-section .table-wrapper th, + .markdown-section .table-wrapper td { + border: none; + } + .markdown-section .table-wrapper thead { + display: none; + } + .markdown-section .table-wrapper tr { + border-color: var(--table-cell-border-color); + border-style: solid; + border-width: var(--table-cell-border-width, 0); + padding: var(--table-cell-padding); + } + .markdown-section .table-wrapper tr:not(:last-child) { + border-bottom: 0; + } + .markdown-section .table-wrapper td { + padding: 0.15em 0 0.15em 8em; + } + .markdown-section .table-wrapper td::before { + display: inline-block; + float: left; + width: 8em; + margin-left: -8em; + font-weight: bold; + text-align: left; + } +} +.markdown-section .tip, +.markdown-section .warn { + position: relative; + margin: 2em 0; + padding: var(--notice-padding); + border-width: var(--notice-border-width, 0); + border-style: var(--notice-border-style); + border-color: var(--notice-border-color); + border-radius: var(--notice-border-radius); + background: var(--notice-background); + font-family: var(--notice-font-family); + font-weight: var(--notice-font-weight); + color: var(--notice-color); +} +.markdown-section .tip:before, +.markdown-section .warn:before { + display: inline-block; + position: var(--notice-before-position, relative); + top: var(--notice-before-top); + left: var(--notice-before-left); + height: var(--notice-before-height); + width: var(--notice-before-width); + margin: var(--notice-before-margin); + padding: var(--notice-before-padding); + border-radius: var(--notice-before-border-radius); + line-height: var(--notice-before-line-height); + font-family: var(--notice-before-font-family); + font-size: var(--notice-before-font-size); + font-weight: var(--notice-before-font-weight); + text-align: center; +} +.markdown-section .tip { + border-width: var(--notice-important-border-width, var(--notice-border-width, 0)); + border-style: var(--notice-important-border-style, var(--notice-border-style)); + border-color: var(--notice-important-border-color, var(--notice-border-color)); + background: var(--notice-important-background, var(--notice-background)); + color: var(--notice-important-color, var(--notice-color)); +} +.markdown-section .tip:before { + content: var(--notice-important-before-content, var(--notice-before-content)); + background: var(--notice-important-before-background, var(--notice-before-background)); + color: var(--notice-important-before-color, var(--notice-before-color)); +} +.markdown-section .warn { + border-width: var(--notice-tip-border-width, var(--notice-border-width, 0)); + border-style: var(--notice-tip-border-style, var(--notice-border-style)); + border-color: var(--notice-tip-border-color, var(--notice-border-color)); + background: var(--notice-tip-background, var(--notice-background)); + color: var(--notice-tip-color, var(--notice-color)); +} +.markdown-section .warn:before { + content: var(--notice-tip-before-content, var(--notice-before-content)); + background: var(--notice-tip-before-background, var(--notice-before-background)); + color: var(--notice-tip-before-color, var(--notice-before-color)); +} +.cover { + display: none; + position: relative; + z-index: 20; + min-height: 100vh; + flex-direction: column; + align-items: center; + justify-content: center; + padding: calc(var(--cover-border-inset, 0px) + var(--cover-border-width, 0px)); + color: var(--cover-color); + text-align: var(--cover-text-align); +} +@media screen and (-ms-high-contrast: active), screen and (-ms-high-contrast: none) { + .cover { + height: 100vh; + } +} +.cover:before, +.cover:after { + content: ''; + position: absolute; +} +.cover:before { + top: 0; + bottom: 0; + left: 0; + right: 0; + background-blend-mode: var(--cover-background-blend-mode); + background-color: var(--cover-background-color); + background-image: var(--cover-background-image); + background-position: var(--cover-background-position); + background-repeat: var(--cover-background-repeat); + background-size: var(--cover-background-size); +} +.cover:after { + top: var(--cover-border-inset, 0); + bottom: var(--cover-border-inset, 0); + left: var(--cover-border-inset, 0); + right: var(--cover-border-inset, 0); + border-width: var(--cover-border-width, 0); + border-style: solid; + border-color: var(--cover-border-color); +} +.cover a { + border-bottom: var(--cover-link-border-bottom); + color: var(--cover-link-color); + -webkit-text-decoration: var(--cover-link-text-decoration); + text-decoration: var(--cover-link-text-decoration); + -webkit-text-decoration-color: var(--cover-link-text-decoration-color); + text-decoration-color: var(--cover-link-text-decoration-color); +} +.cover a:hover { + border-bottom: var(--cover-link-border-bottom--hover, var(--cover-link-border-bottom)); + color: var(--cover-link-color--hover, var(--cover-link-color)); + -webkit-text-decoration: var( + --cover-link-text-decoration--hover, + var(--cover-link-text-decoration) + ); + text-decoration: var( + --cover-link-text-decoration--hover, + var(--cover-link-text-decoration) + ); + -webkit-text-decoration-color: var( + --cover-link-text-decoration-color--hover, + var(--cover-link-text-decoration-color) + ); + text-decoration-color: var( + --cover-link-text-decoration-color--hover, + var(--cover-link-text-decoration-color) + ); +} +.cover h1 { + color: var(--cover-heading-color); + position: relative; + margin: 0; + font-size: var(--cover-heading-font-size); + font-weight: var(--cover-heading-font-weight); + line-height: 1.2; +} +.cover h1 a, +.cover h1 a:hover { + display: block; + border-bottom: none; + color: inherit; + text-decoration: none; +} +.cover h1 small { + position: absolute; + bottom: 0; + margin-left: 0.5em; +} +.cover h1 span { + font-size: calc(var(--cover-heading-font-size-min) * 1px); +} +@media (min-width: 26em) { + .cover h1 span { + font-size: calc( + var(--cover-heading-font-size-min) * 1px + + (var(--cover-heading-font-size-max) - var(--cover-heading-font-size-min)) * + (100vw - 420px) / 604 + ); + } +} +@media (min-width: 64em) { + .cover h1 span { + font-size: calc(var(--cover-heading-font-size-max) * 1px); + } +} +.cover blockquote { + margin: 0; + color: var(--cover-blockquote-color); + font-size: var(--cover-blockquote-font-size); +} +.cover blockquote a { + color: inherit; +} +.cover ul { + padding: 0; + list-style-type: none; +} +.cover .cover-main { + position: relative; + z-index: 1; + max-width: var(--cover-max-width); + margin: var(--cover-margin); + padding: 0 45px; +} +.cover .cover-main > p:last-child { + margin: 1.25em -0.25em; +} +.cover .cover-main > p:last-child a { + display: block; + margin: 0.375em 0.25em; + padding: var(--cover-button-padding); + border: var(--cover-button-border); + border-radius: var(--cover-button-border-radius); + box-shadow: var(--cover-button-box-shadow); + background: var(--cover-button-background); + text-align: center; + -webkit-text-decoration: var(--cover-button-text-decoration); + text-decoration: var(--cover-button-text-decoration); + -webkit-text-decoration-color: var(--cover-button-text-decoration-color); + text-decoration-color: var(--cover-button-text-decoration-color); + color: var(--cover-button-color); + white-space: nowrap; + transition: var(--cover-button-transition); +} +.cover .cover-main > p:last-child a:hover { + border: var(--cover-button-border--hover, var(--cover-button-border)); + box-shadow: var(--cover-button-box-shadow--hover, var(--cover-button-box-shadow)); + background: var(--cover-button-background--hover, var(--cover-button-background)); + -webkit-text-decoration: var( + --cover-button-text-decoration--hover, + var(--cover-button-text-decoration) + ); + text-decoration: var( + --cover-button-text-decoration--hover, + var(--cover-button-text-decoration) + ); + -webkit-text-decoration-color: var( + --cover-button-text-decoration-color--hover, + var(--cover-button-text-decoration-color) + ); + text-decoration-color: var( + --cover-button-text-decoration-color--hover, + var(--cover-button-text-decoration-color) + ); + color: var(--cover-button-color--hover, var(--cover-button-color)); +} +.cover .cover-main > p:last-child a:first-child { + border: var(--cover-button-primary-border, var(--cover-button-border)); + box-shadow: var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow)); + background: var(--cover-button-primary-background, var(--cover-button-background)); + -webkit-text-decoration: var( + --cover-button-primary-text-decoration, + var(--cover-button-text-decoration) + ); + text-decoration: var( + --cover-button-primary-text-decoration, + var(--cover-button-text-decoration) + ); + -webkit-text-decoration-color: var( + --cover-button-primary-text-decoration-color, + var(--cover-button-text-decoration-color) + ); + text-decoration-color: var( + --cover-button-primary-text-decoration-color, + var(--cover-button-text-decoration-color) + ); + color: var(--cover-button-primary-color, var(--cover-button-color)); +} +.cover .cover-main > p:last-child a:first-child:hover { + border: var( + --cover-button-primary-border--hover, + var( + --cover-button-border--hover, + var(--cover-button-primary-border, var(--cover-button-border)) + ) + ); + box-shadow: var( + --cover-button-primary-box-shadow--hover, + var( + --cover-button-box-shadow--hover, + var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow)) + ) + ); + background: var( + --cover-button-primary-background--hover, + var( + --cover-button-background--hover, + var(--cover-button-primary-background, var(--cover-button-background)) + ) + ); + -webkit-text-decoration: var( + --cover-button-primary-text-decoration--hover, + var( + --cover-button-text-decoration--hover, + var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration)) + ) + ); + text-decoration: var( + --cover-button-primary-text-decoration--hover, + var( + --cover-button-text-decoration--hover, + var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration)) + ) + ); + -webkit-text-decoration-color: var( + --cover-button-primary-text-decoration-color--hover, + var( + --cover-button-text-decoration-color--hover, + var( + --cover-button-primary-text-decoration-color, + var(--cover-button-text-decoration-color) + ) + ) + ); + text-decoration-color: var( + --cover-button-primary-text-decoration-color--hover, + var( + --cover-button-text-decoration-color--hover, + var( + --cover-button-primary-text-decoration-color, + var(--cover-button-text-decoration-color) + ) + ) + ); + color: var( + --cover-button-primary-color--hover, + var( + --cover-button-color--hover, + var(--cover-button-primary-color, var(--cover-button-color)) + ) + ); +} +@media (min-width: 30.01em) { + .cover .cover-main > p:last-child a { + display: inline-block; + } +} +.cover .mask { + visibility: var(--cover-background-mask-visibility, hidden); + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: var(--cover-background-mask-color); + opacity: var(--cover-background-mask-opacity); +} +.cover.has-mask .mask { + visibility: visible; +} +.cover.show { + display: flex; +} +.app-nav { + position: absolute; + z-index: 30; + top: calc(35px - 0.5em * var(--base-line-height)); + left: 45px; + right: 80px; + text-align: right; +} +.app-nav.no-badge { + right: 45px; +} +.app-nav li > img, +.app-nav li > a > img { + margin-top: -0.25em; + vertical-align: middle; +} +.app-nav li > img:first-child, +.app-nav li > a > img:first-child { + margin-right: 0.5em; +} +.app-nav ul, +.app-nav li { + margin: 0; + padding: 0; + list-style: none; +} +.app-nav li { + position: relative; +} +.app-nav li a { + display: block; + line-height: 1; + transition: var(--navbar-root-transition); +} +.app-nav > ul > li { + display: inline-block; + margin: var(--navbar-root-margin); +} +.app-nav > ul > li:first-child { + margin-left: 0; +} +.app-nav > ul > li:last-child { + margin-right: 0; +} +.app-nav > ul > li > a, +.app-nav > ul > li > span { + padding: var(--navbar-root-padding); + border-width: var(--navbar-root-border-width, 0); + border-style: var(--navbar-root-border-style); + border-color: var(--navbar-root-border-color); + border-radius: var(--navbar-root-border-radius); + background: var(--navbar-root-background); + color: var(--navbar-root-color); + -webkit-text-decoration: var(--navbar-root-text-decoration); + text-decoration: var(--navbar-root-text-decoration); + -webkit-text-decoration-color: var(--navbar-root-text-decoration-color); + text-decoration-color: var(--navbar-root-text-decoration-color); +} +.app-nav > ul > li > a:hover, +.app-nav > ul > li > span:hover { + background: var(--navbar-root-background--hover, var(--navbar-root-background)); + border-style: var(--navbar-root-border-style--hover, var(--navbar-root-border-style)); + border-color: var(--navbar-root-border-color--hover, var(--navbar-root-border-color)); + color: var(--navbar-root-color--hover, var(--navbar-root-color)); + -webkit-text-decoration: var( + --navbar-root-text-decoration--hover, + var(--navbar-root-text-decoration) + ); + text-decoration: var( + --navbar-root-text-decoration--hover, + var(--navbar-root-text-decoration) + ); + -webkit-text-decoration-color: var( + --navbar-root-text-decoration-color--hover, + var(--navbar-root-text-decoration-color) + ); + text-decoration-color: var( + --navbar-root-text-decoration-color--hover, + var(--navbar-root-text-decoration-color) + ); +} +.app-nav > ul > li > a:not(:last-child), +.app-nav > ul > li > span:not(:last-child) { + padding: var(--navbar-menu-root-padding, var(--navbar-root-padding)); + background: var(--navbar-menu-root-background, var(--navbar-root-background)); +} +.app-nav > ul > li > a:not(:last-child):hover, +.app-nav > ul > li > span:not(:last-child):hover { + background: var( + --navbar-menu-root-background--hover, + var( + --navbar-menu-root-background, + var(--navbar-root-background--hover, var(--navbar-root-background)) + ) + ); +} +.app-nav > ul > li > a.active { + background: var(--navbar-root-background--active, var(--navbar-root-background)); + border-style: var(--navbar-root-border-style--active, var(--navbar-root-border-style)); + border-color: var(--navbar-root-border-color--active, var(--navbar-root-border-color)); + color: var(--navbar-root-color--active, var(--navbar-root-color)); + -webkit-text-decoration: var( + --navbar-root-text-decoration--active, + var(--navbar-root-text-decoration) + ); + text-decoration: var( + --navbar-root-text-decoration--active, + var(--navbar-root-text-decoration) + ); + -webkit-text-decoration-color: var( + --navbar-root-text-decoration-color--active, + var(--navbar-root-text-decoration-color) + ); + text-decoration-color: var( + --navbar-root-text-decoration-color--active, + var(--navbar-root-text-decoration-color) + ); +} +.app-nav > ul > li > a.active:not(:last-child):hover { + background: var( + --navbar-menu-root-background--active, + var( + --navbar-menu-root-background, + var(--navbar-root-background--active, var(--navbar-root-background)) + ) + ); +} +.app-nav > ul > li ul { + visibility: hidden; + position: absolute; + top: 100%; + right: 50%; + overflow-y: auto; + box-sizing: border-box; + max-height: 50vh; + padding: var(--navbar-menu-padding); + border-width: var(--navbar-menu-border-width, 0); + border-style: solid; + border-color: var(--navbar-menu-border-color); + border-radius: var(--navbar-menu-border-radius); + background: var(--navbar-menu-background); + box-shadow: var(--navbar-menu-box-shadow); + text-align: left; + white-space: nowrap; + opacity: 0; + transform: translate(50%, -0.35em); + transition: var(--navbar-menu-transition); +} +.app-nav > ul > li ul li { + white-space: nowrap; +} +.app-nav > ul > li ul a { + margin: var(--navbar-menu-link-margin); + padding: var(--navbar-menu-link-padding); + border-width: var(--navbar-menu-link-border-width, 0); + border-style: var(--navbar-menu-link-border-style); + border-color: var(--navbar-menu-link-border-color); + border-radius: var(--navbar-menu-link-border-radius); + background: var(--navbar-menu-link-background); + color: var(--navbar-menu-link-color); + -webkit-text-decoration: var(--navbar-menu-link-text-decoration); + text-decoration: var(--navbar-menu-link-text-decoration); + -webkit-text-decoration-color: var(--navbar-menu-link-text-decoration-color); + text-decoration-color: var(--navbar-menu-link-text-decoration-color); +} +.app-nav > ul > li ul a:hover { + background: var( + --navbar-menu-link-background--hover, + var(--navbar-menu-link-background) + ); + border-style: var( + --navbar-menu-link-border-style--hover, + var(--navbar-menu-link-border-style) + ); + border-color: var( + --navbar-menu-link-border-color--hover, + var(--navbar-menu-link-border-color) + ); + color: var(--navbar-menu-link-color--hover, var(--navbar-menu-link-color)); + -webkit-text-decoration: var( + --navbar-menu-link-text-decoration--hover, + var(--navbar-menu-link-text-decoration) + ); + text-decoration: var( + --navbar-menu-link-text-decoration--hover, + var(--navbar-menu-link-text-decoration) + ); + -webkit-text-decoration-color: var( + --navbar-menu-link-text-decoration-color--hover, + var(--navbar-menu-link-text-decoration-color) + ); + text-decoration-color: var( + --navbar-menu-link-text-decoration-color--hover, + var(--navbar-menu-link-text-decoration-color) + ); +} +.app-nav > ul > li ul a.active { + background: var( + --navbar-menu-link-background--active, + var(--navbar-menu-link-background) + ); + border-style: var( + --navbar-menu-link-border-style--active, + var(--navbar-menu-link-border-style) + ); + border-color: var( + --navbar-menu-link-border-color--active, + var(--navbar-menu-link-border-color) + ); + color: var(--navbar-menu-link-color--active, var(--navbar-menu-link-color)); + -webkit-text-decoration: var( + --navbar-menu-link-text-decoration--active, + var(--navbar-menu-link-text-decoration) + ); + text-decoration: var( + --navbar-menu-link-text-decoration--active, + var(--navbar-menu-link-text-decoration) + ); + -webkit-text-decoration-color: var( + --navbar-menu-link-text-decoration-color--active, + var(--navbar-menu-link-text-decoration-color) + ); + text-decoration-color: var( + --navbar-menu-link-text-decoration-color--active, + var(--navbar-menu-link-text-decoration-color) + ); +} +.app-nav > ul > li:hover ul, +.app-nav > ul > li:focus ul, +.app-nav > ul > li.focus-within ul { + visibility: visible; + opacity: 1; + transform: translate(50%, 0); +} +@media (min-width: 48em) { + nav.app-nav { + margin-left: var(--sidebar-width); + } +} +main { + position: relative; + overflow-x: hidden; + min-height: 100vh; +} +.sidebar, +.sidebar-toggle, +.sidebar + .content { + transition: all var(--sidebar-transition-duration) ease-out; +} +@media (min-width: 48em) { + .sidebar + .content { + margin-left: var(--sidebar-width); + } +} +.sidebar { + display: flex; + flex-direction: column; + position: fixed; + z-index: 10; + top: 0; + right: 100%; + overflow-x: hidden; + overflow-y: auto; + height: 100vh; + width: var(--sidebar-width); + padding: var(--sidebar-padding); + border-width: var(--sidebar-border-width); + border-style: solid; + border-color: var(--sidebar-border-color); + background: var(--sidebar-background); +} +.sidebar > h1 { + margin: 0; + margin: var(--sidebar-name-margin); + padding: var(--sidebar-name-padding); + background: var(--sidebar-name-background); + color: var(--sidebar-name-color); + font-family: var(--sidebar-name-font-family); + font-size: var(--sidebar-name-font-size); + font-weight: var(--sidebar-name-font-weight); + text-align: var(--sidebar-name-text-align); +} +.sidebar > h1 img { + max-width: 100%; +} +.sidebar > h1 .app-name-link { + color: var(--sidebar-name-color); +} +body:not([data-platform^='Mac']) .sidebar::-webkit-scrollbar { + width: 5px; +} +body:not([data-platform^='Mac']) .sidebar::-webkit-scrollbar-thumb { + border-radius: 50vw; +} +@media (min-width: 48em) { + .sidebar { + position: absolute; + transform: translateX(var(--sidebar-width)); + } +} +@media print { + .sidebar { + display: none; + } +} +.sidebar-nav, +.sidebar nav { + order: 1; + margin: var(--sidebar-nav-margin); + padding: var(--sidebar-nav-padding); + background: var(--sidebar-nav-background); +} +.sidebar-nav ul, +.sidebar nav ul { + margin: 0; + padding: 0; + list-style: none; +} +.sidebar-nav ul ul, +.sidebar nav ul ul { + margin-left: var(--sidebar-nav-indent); +} +.sidebar-nav a, +.sidebar nav a { + display: block; + overflow: hidden; + margin: var(--sidebar-nav-link-margin); + padding: var(--sidebar-nav-link-padding); + border-width: var(--sidebar-nav-link-border-width, 0); + border-style: var(--sidebar-nav-link-border-style); + border-color: var(--sidebar-nav-link-border-color); + border-radius: var(--sidebar-nav-link-border-radius); + background: var(--sidebar-nav-link-background); + color: var(--sidebar-nav-link-color); + font-weight: var(--sidebar-nav-link-font-weight); + white-space: nowrap; + -webkit-text-decoration: var(--sidebar-nav-link-text-decoration); + text-decoration: var(--sidebar-nav-link-text-decoration); + -webkit-text-decoration-color: var(--sidebar-nav-link-text-decoration-color); + text-decoration-color: var(--sidebar-nav-link-text-decoration-color); + text-overflow: ellipsis; + transition: var(--sidebar-nav-link-transition); +} +.sidebar-nav a img, +.sidebar nav a img { + margin-top: -0.25em; + vertical-align: middle; +} +.sidebar-nav a img:first-child, +.sidebar nav a img:first-child { + margin-right: 0.5em; +} +.sidebar-nav a:hover, +.sidebar nav a:hover { + border-width: var( + --sidebar-nav-link-border-width--hover, + var(--sidebar-nav-link-border-width, 0) + ); + border-style: var( + --sidebar-nav-link-border-style--hover, + var(--sidebar-nav-link-border-style) + ); + border-color: var( + --sidebar-nav-link-border-color--hover, + var(--sidebar-nav-link-border-color) + ); + background: var( + --sidebar-nav-link-background--hover, + var(--sidebar-nav-link-background) + ); + color: var(--sidebar-nav-link-color--hover, var(--sidebar-nav-link-color)); + font-weight: var( + --sidebar-nav-link-font-weight--hover, + var(--sidebar-nav-link-font-weight) + ); + -webkit-text-decoration: var( + --sidebar-nav-link-text-decoration--hover, + var(--sidebar-nav-link-text-decoration) + ); + text-decoration: var( + --sidebar-nav-link-text-decoration--hover, + var(--sidebar-nav-link-text-decoration) + ); + -webkit-text-decoration-color: var(--sidebar-nav-link-text-decoration-color); + text-decoration-color: var(--sidebar-nav-link-text-decoration-color); +} +.sidebar-nav ul > li > span, +.sidebar-nav ul > li > strong, +.sidebar nav ul > li > span, +.sidebar nav ul > li > strong { + display: block; + margin: var(--sidebar-nav-strong-margin); + padding: var(--sidebar-nav-strong-padding); + border-width: var(--sidebar-nav-strong-border-width, 0); + border-style: solid; + border-color: var(--sidebar-nav-strong-border-color); + color: var(--sidebar-nav-strong-color); + font-size: var(--sidebar-nav-strong-font-size); + font-weight: var(--sidebar-nav-strong-font-weight); + text-transform: var(--sidebar-nav-strong-text-transform); +} +.sidebar-nav ul > li > span + ul, +.sidebar-nav ul > li > strong + ul, +.sidebar nav ul > li > span + ul, +.sidebar nav ul > li > strong + ul { + margin-left: 0; +} +.sidebar-nav ul > li:first-child > span, +.sidebar-nav ul > li:first-child > strong, +.sidebar nav ul > li:first-child > span, +.sidebar nav ul > li:first-child > strong { + margin-top: 0; +} +.sidebar-nav::-webkit-scrollbar, +.sidebar nav::-webkit-scrollbar { + width: 0; +} +@supports (width: env(safe-area-inset)) { + @media only screen and (orientation: landscape) { + .sidebar-nav, + .sidebar nav { + margin-left: calc(env(safe-area-inset-left) / 2); + } + } +} +.sidebar-nav li > a:before, +.sidebar-nav li > strong:before { + display: inline-block; +} +.sidebar-nav li > a { + background-repeat: var(--sidebar-nav-pagelink-background-repeat); + background-size: var(--sidebar-nav-pagelink-background-size); +} +.sidebar-nav li > a[href^='/']:not([href*='?id=']), +.sidebar-nav li > a[href^='#/']:not([href*='?id=']) { + transition: var(--sidebar-nav-pagelink-transition); +} +.sidebar-nav li > a[href^='/']:not([href*='?id=']), +.sidebar-nav li > a[href^='/']:not([href*='?id=']) ~ ul a, +.sidebar-nav li > a[href^='#/']:not([href*='?id=']), +.sidebar-nav li > a[href^='#/']:not([href*='?id=']) ~ ul a { + padding: var(--sidebar-nav-pagelink-padding, var(--sidebar-nav-link-padding)); +} +.sidebar-nav li > a[href^='/']:not([href*='?id=']):only-child, +.sidebar-nav li > a[href^='#/']:not([href*='?id=']):only-child { + background: var(--sidebar-nav-pagelink-background); +} +.sidebar-nav li > a[href^='/']:not([href*='?id=']):not(:only-child), +.sidebar-nav li > a[href^='#/']:not([href*='?id=']):not(:only-child) { + background: var( + --sidebar-nav-pagelink-background--loaded, + var(--sidebar-nav-pagelink-background) + ); +} +.sidebar-nav li.active > a, +.sidebar-nav li.collapse > a { + border-width: var( + --sidebar-nav-link-border-width--active, + var(--sidebar-nav-link-border-width) + ); + border-style: var( + --sidebar-nav-link-border-style--active, + var(--sidebar-nav-link-border-style) + ); + border-color: var( + --sidebar-nav-link-border-color--active, + var(--sidebar-nav-link-border-color) + ); + background: var( + --sidebar-nav-link-background--active, + var(--sidebar-nav-link-background) + ); + color: var(--sidebar-nav-link-color--active, var(--sidebar-nav-link-color)); + font-weight: var( + --sidebar-nav-link-font-weight--active, + var(--sidebar-nav-link-font-weight) + ); + -webkit-text-decoration: var( + --sidebar-nav-link-text-decoration--active, + var(--sidebar-nav-link-text-decoration) + ); + text-decoration: var( + --sidebar-nav-link-text-decoration--active, + var(--sidebar-nav-link-text-decoration) + ); + -webkit-text-decoration-color: var(--sidebar-nav-link-text-decoration-color); + text-decoration-color: var(--sidebar-nav-link-text-decoration-color); +} +.sidebar-nav li.active > a[href^='/']:not([href*='?id=']):not(:only-child), +.sidebar-nav li.active > a[href^='#/']:not([href*='?id=']):not(:only-child) { + background: var( + --sidebar-nav-pagelink-background--active, + var( + --sidebar-nav-pagelink-background--loaded, + var(--sidebar-nav-pagelink-background) + ) + ); +} +.sidebar-nav li.collapse > a[href^='/']:not([href*='?id=']):not(:only-child), +.sidebar-nav li.collapse > a[href^='#/']:not([href*='?id=']):not(:only-child) { + background: var( + --sidebar-nav-pagelink-background--collapse, + var( + --sidebar-nav-pagelink-background--loaded, + var(--sidebar-nav-pagelink-background) + ) + ); +} +.sidebar-nav li.collapse .app-sub-sidebar { + display: none; +} +.sidebar-nav > ul > li > a:before { + content: var( + --sidebar-nav-link-before-content-l1, + var(--sidebar-nav-link-before-content) + ); + margin: var( + --sidebar-nav-link-before-margin-l1, + var(--sidebar-nav-link-before-margin) + ); + color: var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color)); +} +.sidebar-nav > ul > li.active > a:before { + content: var( + --sidebar-nav-link-before-content-l1--active, + var( + --sidebar-nav-link-before-content--active, + var(--sidebar-nav-link-before-content-l1, var(--sidebar-nav-link-before-content)) + ) + ); + color: var( + --sidebar-nav-link-before-color-l1--active, + var( + --sidebar-nav-link-before-color--active, + var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color)) + ) + ); +} +.sidebar-nav > ul > li > ul > li > a:before { + content: var( + --sidebar-nav-link-before-content-l2, + var(--sidebar-nav-link-before-content) + ); + margin: var( + --sidebar-nav-link-before-margin-l2, + var(--sidebar-nav-link-before-margin) + ); + color: var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color)); +} +.sidebar-nav > ul > li > ul > li.active > a:before { + content: var( + --sidebar-nav-link-before-content-l2--active, + var( + --sidebar-nav-link-before-content--active, + var(--sidebar-nav-link-before-content-l2, var(--sidebar-nav-link-before-content)) + ) + ); + color: var( + --sidebar-nav-link-before-color-l2--active, + var( + --sidebar-nav-link-before-color--active, + var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color)) + ) + ); +} +.sidebar-nav > ul > li > ul > li > ul > li > a:before { + content: var( + --sidebar-nav-link-before-content-l3, + var(--sidebar-nav-link-before-content) + ); + margin: var( + --sidebar-nav-link-before-margin-l3, + var(--sidebar-nav-link-before-margin) + ); + color: var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color)); +} +.sidebar-nav > ul > li > ul > li > ul > li.active > a:before { + content: var( + --sidebar-nav-link-before-content-l3--active, + var( + --sidebar-nav-link-before-content--active, + var(--sidebar-nav-link-before-content-l3, var(--sidebar-nav-link-before-content)) + ) + ); + color: var( + --sidebar-nav-link-before-color-l3--active, + var( + --sidebar-nav-link-before-color--active, + var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color)) + ) + ); +} +.sidebar-nav > ul > li > ul > li > ul > li > ul > li > a:before { + content: var( + --sidebar-nav-link-before-content-l4, + var(--sidebar-nav-link-before-content) + ); + margin: var( + --sidebar-nav-link-before-margin-l4, + var(--sidebar-nav-link-before-margin) + ); + color: var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color)); +} +.sidebar-nav > ul > li > ul > li > ul > li > ul > li.active > a:before { + content: var( + --sidebar-nav-link-before-content-l4--active, + var( + --sidebar-nav-link-before-content--active, + var(--sidebar-nav-link-before-content-l4, var(--sidebar-nav-link-before-content)) + ) + ); + color: var( + --sidebar-nav-link-before-color-l4--active, + var( + --sidebar-nav-link-before-color--active, + var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color)) + ) + ); +} +.sidebar-nav > :last-child { + margin-bottom: 2rem; +} +.sidebar-toggle, +.sidebar-toggle-button { + width: var(--sidebar-toggle-width); + outline: none; +} +.sidebar-toggle { + position: fixed; + z-index: 11; + top: 0; + bottom: 0; + left: 0; + max-width: 40px; + margin: 0; + padding: 0; + border: 0; + background: rgba(0, 0, 0, 0); + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + cursor: pointer; +} +.sidebar-toggle .sidebar-toggle-button { + position: absolute; + top: var(--sidebar-toggle-offset-top); + left: var(--sidebar-toggle-offset-left); + height: var(--sidebar-toggle-height); + border-radius: var(--sidebar-toggle-border-radius); + border-width: var(--sidebar-toggle-border-width); + border-style: var(--sidebar-toggle-border-style); + border-color: var(--sidebar-toggle-border-color); + background: var(--sidebar-toggle-background, transparent); + color: var(--sidebar-toggle-icon-color); +} +.sidebar-toggle span { + position: absolute; + top: calc(50% - var(--sidebar-toggle-icon-stroke-width) / 2); + left: calc(50% - var(--sidebar-toggle-icon-width) / 2); + height: var(--sidebar-toggle-icon-stroke-width); + width: var(--sidebar-toggle-icon-width); + background-color: currentColor; +} +.sidebar-toggle span:nth-child(1) { + margin-top: calc(0px - var(--sidebar-toggle-icon-height) / 2); +} +.sidebar-toggle span:nth-child(3) { + margin-top: calc(var(--sidebar-toggle-icon-height) / 2); +} +@media (min-width: 48em) { + .sidebar-toggle { + position: absolute; + overflow: visible; + top: var(--sidebar-toggle-offset-top); + bottom: auto; + left: 0; + height: var(--sidebar-toggle-height); + transform: translateX(var(--sidebar-width)); + } + .sidebar-toggle .sidebar-toggle-button { + top: 0; + } +} +@media print { + .sidebar-toggle { + display: none; + } +} +@media (max-width: 47.99em) { + body.close .sidebar, + body.close .sidebar-toggle, + body.close .sidebar + .content { + transform: translateX(var(--sidebar-width)); + } +} +@media (min-width: 48em) { + body.close .sidebar + .content { + transform: translateX(0); + } +} +@media (max-width: 47.99em) { + body.close nav.app-nav, + body.close .github-corner { + display: none; + } +} +@media (min-width: 48em) { + body.close .sidebar, + body.close .sidebar-toggle { + transform: translateX(0); + } +} +@media (min-width: 48em) { + body.close nav.app-nav { + margin-left: 0; + } +} +@media (max-width: 47.99em) { + body.close .sidebar-toggle { + width: 100%; + max-width: none; + } + body.close .sidebar-toggle span { + margin-top: 0; + } + body.close .sidebar-toggle span:nth-child(1) { + transform: rotate(45deg); + } + body.close .sidebar-toggle span:nth-child(2) { + display: none; + } + body.close .sidebar-toggle span:nth-child(3) { + transform: rotate(-45deg); + } +} +@media (min-width: 48em) { + body.close .sidebar + .content { + margin-left: 0; + } +} +@media (min-width: 48em) { + body.sticky .sidebar, + body.sticky .sidebar-toggle { + position: fixed; + } +} +body .docsify-copy-code-button, +body .docsify-copy-code-button:after { + border-radius: var(--border-radius-m, 0); + border-top-left-radius: 0; + border-bottom-right-radius: 0; + background: var(--copycode-background); + color: var(--copycode-color); +} +body .docsify-copy-code-button span { + border-radius: var(--border-radius-s, 0); +} +body .docsify-pagination-container { + border-top: var(--pagination-border-top); + color: var(--pagination-color); +} +body .pagination-item-label { + font-size: var(--pagination-label-font-size); +} +body .pagination-item-label svg { + color: var(--pagination-label-color); + height: var(--pagination-chevron-height); + stroke: var(--pagination-chevron-stroke); + stroke-linecap: var(--pagination-chevron-stroke-linecap); + stroke-linejoin: var(--pagination-chevron-stroke-linecap); + stroke-width: var(--pagination-chevron-stroke-width); +} +body .pagination-item-title { + color: var(--pagination-title-color); + font-size: var(--pagination-title-font-size); +} +body .app-name.hide { + display: block; +} +body .sidebar { + padding: var(--sidebar-padding); +} +.sidebar .search { + margin: 0; + padding: 0; + border: 0; +} +.sidebar .search input { + padding: 0; + line-height: 1; + font-size: inherit; +} +.sidebar .search .clear-button { + width: auto; +} +.sidebar .search .clear-button svg { + transform: scale(1); +} +.sidebar .search .matching-post { + border: none; +} +.sidebar .search p { + font-size: inherit; +} +.sidebar .search { + order: var(--search-flex-order); + margin: var(--search-margin); + padding: var(--search-padding); + background: var(--search-background); +} +.sidebar .search a { + color: inherit; +} +.sidebar .search h2 { + margin: var(--search-result-heading-margin); + font-size: var(--search-result-heading-font-size); + font-weight: var(--search-result-heading-font-weight); + color: var(--search-result-heading-color); +} +.sidebar .search .input-wrap { + align-items: stretch; + margin: var(--search-input-margin); + background-color: var(--search-input-background-color); + border-width: var(--search-input-border-width, 0); + border-style: solid; + border-color: var(--search-input-border-color); + border-radius: var(--search-input-border-radius); +} +.sidebar .search input[type='search'] { + min-width: 0; + padding: var(--search-input-padding); + border: none; + background-color: rgba(0, 0, 0, 0); + background-image: var(--search-input-background-image); + background-position: var(--search-input-background-position); + background-repeat: var(--search-input-background-repeat); + background-size: var(--search-input-background-size); + font-size: var(--search-input-font-size); + color: var(--search-input-color); + transition: var(--search-input-transition); +} +.sidebar .search input[type='search']::-ms-clear { + display: none; +} +.sidebar .search input[type='search']::-moz-placeholder { + color: var(--search-input-placeholder-color, #808080); +} +.sidebar .search input[type='search']::placeholder { + color: var(--search-input-placeholder-color, #808080); +} +.sidebar .search input[type='search']::-webkit-input-placeholder { + line-height: normal; +} +.sidebar .search input[type='search']:focus { + background-color: var( + --search-input-background-color--focus, + var(--search-input-background-color) + ); + background-image: var( + --search-input-background-image--focus, + var(--search-input-background-image) + ); + background-position: var( + --search-input-background-position--focus, + var(--search-input-background-position) + ); + background-size: var( + --search-input-background-size--focus, + var(--search-input-background-size) + ); +} +@supports (width: env(safe-area-inset)) { + @media only screen and (orientation: landscape) { + .sidebar .search input[type='search'] { + margin-left: calc(env(safe-area-inset-left) / 2); + } + } +} +.sidebar .search p { + overflow: hidden; + text-overflow: ellipsis; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} +.sidebar .search p:empty { + text-align: center; +} +.sidebar .search .clear-button { + margin: 0; + padding: 0 10px; + border: none; + line-height: 1; + background: rgba(0, 0, 0, 0); + cursor: pointer; +} +.sidebar .search .clear-button svg circle { + fill: var(--search-clear-icon-color1, #808080); +} +.sidebar .search .clear-button svg path { + stroke: var(--search-clear-icon-color2, #fff); +} +.sidebar .search.show ~ *:not(h1) { + display: none; +} +.sidebar .search .results-panel { + display: none; + color: var(--search-result-item-color); + font-size: var(--search-result-item-font-size); + font-weight: var(--search-result-item-font-weight); +} +.sidebar .search .results-panel.show { + display: block; +} +.sidebar .search .matching-post { + margin: var(--search-result-item-margin); + padding: var(--search-result-item-padding); +} +.sidebar .search .matching-post, +.sidebar .search .matching-post:last-child { + border-width: var(--search-result-item-border-width, 0) !important; + border-style: var(--search-result-item-border-style); + border-color: var(--search-result-item-border-color); +} +.sidebar .search .matching-post p { + margin: 0; +} +.sidebar .search .search-keyword { + margin: var(--search-result-keyword-margin); + padding: var(--search-result-keyword-padding); + border-radius: var(--search-result-keyword-border-radius); + background-color: var(--search-result-keyword-background); + color: var(--search-result-keyword-color, currentColor); + font-style: normal; + font-weight: var(--search-result-keyword-font-weight); +} +.medium-zoom-overlay, +.medium-zoom-image--open, +.medium-zoom-image--opened { + z-index: 2147483646 !important; +} +.medium-zoom-overlay { + background: var(--zoomimage-overlay-background) !important; +} +:root { + --mono-hue: 113; + --mono-saturation: 0%; + --mono-shade3: hsl(var(--mono-hue), var(--mono-saturation), 20%); + --mono-shade2: hsl(var(--mono-hue), var(--mono-saturation), 30%); + --mono-shade1: hsl(var(--mono-hue), var(--mono-saturation), 40%); + --mono-base: hsl(var(--mono-hue), var(--mono-saturation), 50%); + --mono-tint1: hsl(var(--mono-hue), var(--mono-saturation), 70%); + --mono-tint2: hsl(var(--mono-hue), var(--mono-saturation), 89%); + --mono-tint3: hsl(var(--mono-hue), var(--mono-saturation), 97%); + --theme-hue: 204; + --theme-saturation: 90%; + --theme-lightness: 45%; + --theme-color: hsl(var(--theme-hue), var(--theme-saturation), var(--theme-lightness)); + --modular-scale: 1.333; + --modular-scale--2: calc(var(--modular-scale--1) / var(--modular-scale)); + --modular-scale--1: calc(var(--modular-scale-1) / var(--modular-scale)); + --modular-scale-1: 1rem; + --modular-scale-2: calc(var(--modular-scale-1) * var(--modular-scale)); + --modular-scale-3: calc(var(--modular-scale-2) * var(--modular-scale)); + --modular-scale-4: calc(var(--modular-scale-3) * var(--modular-scale)); + --modular-scale-5: calc(var(--modular-scale-4) * var(--modular-scale)); + --font-size-xxxl: var(--modular-scale-5); + --font-size-xxl: var(--modular-scale-4); + --font-size-xl: var(--modular-scale-3); + --font-size-l: var(--modular-scale-2); + --font-size-m: var(--modular-scale-1); + --font-size-s: var(--modular-scale--1); + --font-size-xs: var(--modular-scale--2); + --duration-slow: 1s; + --duration-medium: 0.5s; + --duration-fast: 0.25s; + --spinner-size: 60px; + --spinner-track-width: 4px; + --spinner-track-color: rgba(0, 0, 0, 0.15); + --spinner-transition-duration: var(--duration-medium); +} +:root { + --base-background-color: #fff; + --base-color: var(--mono-shade2); + --base-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, + sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + --base-font-size: 16px; + --base-font-weight: normal; + --base-line-height: 1.7; + --emoji-size: calc(var(--base-line-height) * 1em); + --hr-border: 1px solid var(--mono-tint2); + --mark-background: #ffecb3; + --pre-font-family: var(--code-font-family); + --pre-font-size: var(--code-font-size); + --pre-font-weight: normal; + --selection-color: #b4d5fe; + --small-font-size: var(--font-size-s); + --strong-color: var(--heading-color); + --strong-font-weight: 600; + --subsup-font-size: var(--font-size-s); +} +:root { + --content-max-width: 55em; + --blockquote-background: var(--mono-tint3); + --blockquote-border-style: solid; + --blockquote-border-radius: var(--border-radius-m); + --blockquote-em-font-weight: normal; + --blockquote-font-weight: normal; + --blockquote-padding: 1.5em; + --code-font-family: Inconsolata, Consolas, Menlo, Monaco, 'Andale Mono WT', + 'Andale Mono', 'Lucida Console', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', + 'Courier New', Courier, monospace; + --code-font-size: calc(var(--font-size-m) * 0.95); + --code-font-weight: normal; + --code-tab-size: 4; + --code-block-border-radius: var(--border-radius-m); + --code-block-line-height: var(--base-line-height); + --code-block-margin: 1em 0; + --code-block-padding: 1.75em 1.5em 1.5em 1.5em; + --code-inline-background: var(--code-theme-background); + --code-inline-border-radius: var(--border-radius-s); + --code-inline-color: var(--code-theme-text); + --code-inline-margin: 0 0.15em; + --code-inline-padding: 0.125em 0.4em; + --code-theme-background: var(--mono-tint3); + --heading-color: var(--mono-shade3); + --heading-margin: 2.5rem 0 0; + --heading-h1-border-style: solid; + --heading-h1-font-size: var(--font-size-xxl); + --heading-h2-border-style: solid; + --heading-h2-font-size: var(--font-size-xl); + --heading-h3-border-style: solid; + --heading-h3-font-size: var(--font-size-l); + --heading-h4-border-style: solid; + --heading-h4-font-size: var(--font-size-m); + --heading-h5-border-style: solid; + --heading-h5-font-size: var(--font-size-s); + --heading-h6-border-style: solid; + --heading-h6-font-size: var(--font-size-xs); + --kbd-background: var(--mono-tint3); + --kbd-border-radius: var(--border-radius-m); + --kbd-margin: 0 0.3em; + --kbd-min-width: 2.5em; + --kbd-padding: 0.65em 0.5em; + --link-text-decoration: underline; + --notice-background: var(--mono-tint3); + --notice-border-radius: var(--border-radius-m); + --notice-border-style: solid; + --notice-font-weight: normal; + --notice-padding: 1em 1.5em; + --notice-before-font-weight: normal; + --table-cell-padding: 0.75em 0.5em; + --table-head-border-color: var(--table-cell-border-color); + --table-head-font-weight: var(--strong-font-weight); + --table-row-odd-background: var(--mono-tint3); +} +:root { + --cover-margin: 0 auto; + --cover-max-width: 40em; + --cover-text-align: center; + --cover-background-color: var(--base-background-color); + --cover-background-mask-color: var(--base-background-color); + --cover-background-mask-opacity: 0.8; + --cover-background-position: center center; + --cover-background-repeat: no-repeat; + --cover-background-size: cover; + --cover-blockquote-font-size: var(--font-size-l); + --cover-border-color: var(--theme-color); + --cover-button-border: 1px solid var(--theme-color); + --cover-button-border-radius: var(--border-radius-m); + --cover-button-color: var(--theme-color); + --cover-button-padding: 0.5em 2rem; + --cover-button-text-decoration: none; + --cover-button-transition: all var(--duration-fast) ease-in-out; + --cover-button-primary-background: var(--theme-color); + --cover-button-primary-border: 1px solid var(--theme-color); + --cover-button-primary-color: #fff; + --cover-heading-color: var(--theme-color); + --cover-heading-font-size: var(--font-size-xxl); + --cover-heading-font-weight: normal; + --cover-link-text-decoration: underline; +} +:root { + --navbar-root-border-style: solid; + --navbar-root-margin: 0 0 0 1.5em; + --navbar-root-transition: all var(--duration-fast); + --navbar-menu-background: var(--base-background-color); + --navbar-menu-border-radius: var(--border-radius-m); + --navbar-menu-box-shadow: rgba(45, 45, 45, 0.05) 0px 0px 1px, + rgba(49, 49, 49, 0.05) 0px 1px 2px, rgba(42, 42, 42, 0.05) 0px 2px 4px, + rgba(32, 32, 32, 0.05) 0px 4px 8px, rgba(49, 49, 49, 0.05) 0px 8px 16px, + rgba(35, 35, 35, 0.05) 0px 16px 32px; + --navbar-menu-padding: 0.5em; + --navbar-menu-transition: all var(--duration-fast); + --navbar-menu-link-border-style: solid; + --navbar-menu-link-margin: 0.75em 0.5em; + --navbar-menu-link-padding: 0.2em 0; +} +:root { + --copycode-background: #808080; + --copycode-color: #fff; +} +:root { + --docsifytabs-border-color: var(--mono-tint2); + --docsifytabs-border-radius-px: var(--border-radius-s); + --docsifytabs-tab-background: var(--mono-tint3); + --docsifytabs-tab-color: var(--mono-tint1); +} +:root { + --pagination-border-top: 1px solid var(--mono-tint2); + --pagination-chevron-height: 0.8em; + --pagination-chevron-stroke: currentColor; + --pagination-chevron-stroke-linecap: round; + --pagination-chevron-stroke-width: 1px; + --pagination-label-font-size: var(--font-size-s); + --pagination-title-font-size: var(--font-size-l); +} +:root { + --search-margin: 1.5rem 0 0; + --search-input-background-repeat: no-repeat; + --search-input-border-color: var(--mono-tint1); + --search-input-border-width: 1px; + --search-input-padding: 0.5em; + --search-flex-order: 1; + --search-result-heading-color: var(--heading-color); + --search-result-heading-font-size: var(--base-font-size); + --search-result-heading-font-weight: normal; + --search-result-heading-margin: 0 0 0.25em; + --search-result-item-border-color: var(--mono-tint2); + --search-result-item-border-style: solid; + --search-result-item-border-width: 0 0 1px 0; + --search-result-item-font-weight: normal; + --search-result-item-padding: 1em 0; + --search-result-keyword-background: var(--mark-background); + --search-result-keyword-border-radius: var(--border-radius-s); + --search-result-keyword-color: var(--mark-color); + --search-result-keyword-font-weight: normal; + --search-result-keyword-margin: 0 0.1em; + --search-result-keyword-padding: 0.2em 0; +} +:root { + --zoomimage-overlay-background: rgba(0, 0, 0, 0.875); +} +:root { + --sidebar-background: var(--base-background-color); + --sidebar-border-width: 0; + --sidebar-padding: 0 25px; + --sidebar-transition-duration: var(--duration-fast); + --sidebar-width: 17rem; + --sidebar-name-font-size: var(--font-size-l); + --sidebar-name-font-weight: normal; + --sidebar-name-margin: 1.5rem 0 0; + --sidebar-name-text-align: center; + --sidebar-nav-strong-border-color: var(--sidebar-border-color); + --sidebar-nav-strong-color: var(--heading-color); + --sidebar-nav-strong-font-weight: var(--strong-font-weight); + --sidebar-nav-strong-margin: 1.5em 0 0.5em; + --sidebar-nav-strong-padding: 0.25em 0; + --sidebar-nav-indent: 1em; + --sidebar-nav-margin: 1.5rem 0 0; + --sidebar-nav-link-border-style: solid; + --sidebar-nav-link-border-width: 0; + --sidebar-nav-link-color: var(--base-color); + --sidebar-nav-link-font-weight: normal; + --sidebar-nav-link-padding: 0.25em 0; + --sidebar-nav-link-text-decoration--active: underline; + --sidebar-nav-link-text-decoration--hover: underline; + --sidebar-nav-link-before-margin: 0 0.35em 0 0; + --sidebar-nav-pagelink-transition: var(--sidebar-nav-link-transition); + --sidebar-toggle-border-radius: var(--border-radius-s); + --sidebar-toggle-border-style: solid; + --sidebar-toggle-border-width: 0; + --sidebar-toggle-height: 36px; + --sidebar-toggle-icon-color: var(--base-color); + --sidebar-toggle-icon-height: 10px; + --sidebar-toggle-icon-stroke-width: 1px; + --sidebar-toggle-icon-width: 16px; + --sidebar-toggle-offset-left: 0; + --sidebar-toggle-offset-top: calc(35px - (var(--sidebar-toggle-height) / 2)); + --sidebar-toggle-width: 44px; +} +:root { + --code-theme-background: #f3f3f3; + --code-theme-comment: #6e8090; + --code-theme-function: #dd4a68; + --code-theme-keyword: #07a; + --code-theme-operator: #a67f59; + --code-theme-punctuation: #999; + --code-theme-selector: #690; + --code-theme-tag: #905; + --code-theme-text: #333; + --code-theme-variable: #e90; +} +:root { + --border-radius-s: 2px; + --border-radius-m: 4px; + --border-radius-l: 8px; + --strong-font-weight: 600; + --blockquote-border-color: var(--theme-color); + --blockquote-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0; + --blockquote-border-width: 0 0 0 4px; + --code-inline-background: var(--mono-tint2); + --code-theme-background: var(--mono-tint3); + --heading-font-weight: var(--strong-font-weight); + --heading-h1-font-weight: 400; + --heading-h2-font-weight: 400; + --heading-h2-border-color: var(--mono-tint2); + --heading-h2-border-width: 0 0 1px 0; + --heading-h2-margin: 2.5rem 0 1.5rem; + --heading-h2-padding: 0 0 1rem 0; + --kbd-border: 1px solid var(--mono-tint2); + --notice-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0; + --notice-border-width: 0 0 0 4px; + --notice-padding: 1em 1.5em 1em 3em; + --notice-before-border-radius: 100%; + --notice-before-font-weight: bold; + --notice-before-height: 1.5em; + --notice-before-left: 0.75em; + --notice-before-line-height: 1.5; + --notice-before-margin: 0 0.25em 0 0; + --notice-before-position: absolute; + --notice-before-width: var(--notice-before-height); + --notice-important-background: hsl(340, 60%, 96%); + --notice-important-border-color: hsl(340, 90%, 45%); + --notice-important-before-background: var(--notice-important-border-color) + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3E%3Cpath d='M10 14C10 15.1 9.1 16 8 16 6.9 16 6 15.1 6 14 6 12.9 6.9 12 8 12 9.1 12 10 12.9 10 14Z'/%3E%3Cpath d='M10 1.6C10 1.2 9.8 0.9 9.6 0.7 9.2 0.3 8.6 0 8 0 7.4 0 6.8 0.2 6.5 0.6 6.2 0.9 6 1.2 6 1.6 6 1.7 6 1.8 6 1.9L6.8 9.6C6.9 9.9 7 10.1 7.2 10.2 7.4 10.4 7.7 10.5 8 10.5 8.3 10.5 8.6 10.4 8.8 10.3 9 10.1 9.1 9.9 9.2 9.6L10 1.9C10 1.8 10 1.7 10 1.6Z'/%3E%3C/svg%3E") + center / 0.875em no-repeat; + --notice-important-before-color: #fff; + --notice-important-before-content: ''; + --notice-tip-background: hsl(204, 60%, 96%); + --notice-tip-border-color: hsl(204, 90%, 45%); + --notice-tip-before-background: var(--notice-tip-border-color) + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3E%3Cpath d='M9.1 0C10.2 0 10.7 0.7 10.7 1.6 10.7 2.6 9.8 3.6 8.6 3.6 7.6 3.6 7 3 7 2 7 1.1 7.7 0 9.1 0Z'/%3E%3Cpath d='M5.8 16C5 16 4.4 15.5 5 13.2L5.9 9.1C6.1 8.5 6.1 8.2 5.9 8.2 5.7 8.2 4.6 8.6 3.9 9.1L3.5 8.4C5.6 6.6 7.9 5.6 8.9 5.6 9.8 5.6 9.9 6.6 9.5 8.2L8.4 12.5C8.2 13.2 8.3 13.5 8.5 13.5 8.7 13.5 9.6 13.2 10.4 12.5L10.9 13.2C8.9 15.2 6.7 16 5.8 16Z'/%3E%3C/svg%3E") + center / 0.875em no-repeat; + --notice-tip-before-color: #fff; + --notice-tip-before-content: ''; + --table-cell-border-color: var(--mono-tint2); + --table-cell-border-width: 1px 0; + --cover-background-color: hsl(var(--theme-hue), 25%, 60%); + --cover-background-image: radial-gradient( + ellipse at center 115%, + rgba(255, 255, 255, 0.9), + transparent + ); + --cover-blockquote-color: var(--strong-color); + --cover-heading-color: #fff; + --cover-heading-font-size-max: 56; + --cover-heading-font-size-min: 34; + --cover-heading-font-weight: 200; + --navbar-root-color--active: var(--theme-color); + --navbar-menu-border-radius: var(--border-radius-m); + --navbar-menu-root-background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9.6' height='6' viewBox='0 0 9.6 6'%3E%3Cpath d='M1.5 1.5l3.3 3 3.3-3' stroke-width='1.5' stroke='rgb%28179, 179, 179%29' fill='none' stroke-linecap='square' stroke-linejoin='miter' vector-effect='non-scaling-stroke'/%3E%3C/svg%3E") + right no-repeat; + --navbar-menu-root-padding: 0 18px 0 0; + --search-input-background-color: #fff; + --search-input-background-image: url("data:image/svg+xml,%3Csvg height='20px' width='20px' viewBox='0 0 24 24' fill='none' stroke='rgba(0, 0, 0, 0.3)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10.5' cy='10.5' r='7.5' vector-effect='non-scaling-stroke'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='15.8' y2='15.8' vector-effect='non-scaling-stroke'%3E%3C/line%3E%3C/svg%3E"); + --search-input-background-position: 21px center; + --search-input-border-color: var(--sidebar-border-color); + --search-input-border-width: 1px 0; + --search-input-margin: 0 -25px; + --search-input-padding: 0.65em 1em 0.65em 50px; + --search-input-placeholder-color: rgba(0, 0, 0, 0.4); + --search-clear-icon-color1: rgba(0, 0, 0, 0.3); + --search-result-heading-font-weight: var(--strong-font-weight); + --search-result-item-border-color: var(--sidebar-border-color); + --search-result-keyword-border-radius: var(--border-radius-s); + --sidebar-background: var(--mono-tint3); + --sidebar-border-color: var(--mono-tint2); + --sidebar-border-width: 0 1px 0 0; + --sidebar-name-color: var(--theme-color); + --sidebar-name-font-weight: 300; + --sidebar-nav-strong-border-width: 0 0 1px 0; + --sidebar-nav-strong-font-size: smaller; + --sidebar-nav-strong-margin: 2em -25px 0.75em 0; + --sidebar-nav-strong-padding: 0.25em 0 0.75em 0; + --sidebar-nav-strong-text-transform: uppercase; + --sidebar-nav-link-border-color: transparent; + --sidebar-nav-link-border-color--active: var(--theme-color); + --sidebar-nav-link-border-width: 0 4px 0 0; + --sidebar-nav-link-color--active: var(--theme-color); + --sidebar-nav-link-margin: 0 -25px 0 0; + --sidebar-nav-link-text-decoration: none; + --sidebar-nav-link-text-decoration--active: none; + --sidebar-nav-link-text-decoration--hover: underline; + --sidebar-nav-pagelink-background: no-repeat 2px calc(50% - 2.5px) / 6px 5px + linear-gradient( + 45deg, + transparent 2.75px, + var(--mono-tint1) 2.75px 4.25px, + transparent 4px + ), + no-repeat 2px calc(50% + 2.5px) / 6px 5px + linear-gradient( + 135deg, + transparent 2.75px, + var(--mono-tint1) 2.75px 4.25px, + transparent 4px + ); + --sidebar-nav-pagelink-background--active: no-repeat 0px center / 5px 6px + linear-gradient( + 225deg, + transparent 2.75px, + var(--theme-color) 2.75px 4.25px, + transparent 4.25px + ), + no-repeat 5px center / 5px 6px + linear-gradient( + 135deg, + transparent 2.75px, + var(--theme-color) 2.75px 4.25px, + transparent 4.25px + ); + --sidebar-nav-pagelink-background--collapse: no-repeat 2px calc(50% - 2.5px) / 6px 5px + linear-gradient( + 45deg, + transparent 2.75px, + var(--theme-color) 2.75px 4.25px, + transparent 4px + ), + no-repeat 2px calc(50% + 2.5px) / 6px 5px + linear-gradient( + 135deg, + transparent 2.75px, + var(--theme-color) 2.75px 4.25px, + transparent 4px + ); + --sidebar-nav-pagelink-background--loaded: no-repeat 0px center / 5px 6px + linear-gradient( + 225deg, + transparent 2.75px, + var(--mono-tint1) 2.75px 4.25px, + transparent 4.25px + ), + no-repeat 5px center / 5px 6px + linear-gradient( + 135deg, + transparent 2.75px, + var(--mono-tint1) 2.75px 4.25px, + transparent 4.25px + ); + --sidebar-nav-pagelink-padding: 0.25em 0 0.25em 20px; + --sidebar-nav-pagelink-transition: none; + --sidebar-toggle-background: var(--sidebar-border-color); + --sidebar-toggle-border-radius: 0 var(--border-radius-s) var(--border-radius-s) 0; + --sidebar-toggle-width: 32px; +} +:root { + --code-theme-background: #222; + --code-theme-comment: #516e7a; + --code-theme-function: #f07178; + --code-theme-keyword: #c2e78c; + --code-theme-operator: #ffcb6b; + --code-theme-punctuation: #89ddff; + --code-theme-selector: #ffcb6b; + --code-theme-tag: #f07178; + --code-theme-text: #f3f3f3; + --code-theme-variable: #ffcb6b; +} +:root { + --mono-hue: 201; + --mono-saturation: 18%; + --mono-shade3: hsl(var(--mono-hue), var(--mono-saturation), 13%); + --mono-shade2: hsl(var(--mono-hue), var(--mono-saturation), 15%); + --mono-shade1: hsl(var(--mono-hue), var(--mono-saturation), 17%); + --mono-base: hsl(var(--mono-hue), var(--mono-saturation), 19%); + --mono-tint1: hsl(var(--mono-hue), var(--mono-saturation), 25%); + --mono-tint2: hsl(var(--mono-hue), var(--mono-saturation), 35%); + --mono-tint3: hsl(var(--mono-hue), var(--mono-saturation), 43%); + --spinner-track-color: rgba(255, 255, 255, 0.15); + --base-background-color: var(--mono-base); + --base-color: #d3d3d3; + --hr-border: 1px solid var(--mono-tint2); + --mark-background: #ffcb6b; + --mark-color: var(--base-background-color); + --selection-color: rgba(94, 131, 175, 0.75); + --blockquote-background: var(--mono-shade2); + --code-inline-background: var(--mono-tint1); + --code-theme-background: var(--mono-shade2); + --heading-color: #fff; + --heading-h2-border-color: var(--mono-tint2); + --kbd-background: var(--mono-shade2); + --kbd-border: none; + --kbd-color: var(--strong-color); + --notice-important-background: var(--mono-shade2); + --notice-tip-background: var(--mono-shade2); + --table-cell-border-color: var(--mono-tint1); + --table-row-odd-background: var(--mono-shade2); + --cover-background-color: var(--base-background-color); + --cover-background-image: radial-gradient( + ellipse at center bottom, + var(--mono-tint3), + transparent + ); + --cover-blockquote-color: var(--mark-background); + --cover-button-border: 1px solid var(--mono-tint3); + --cover-button-color: #fff; + --navbar-menu-background: var(--mono-tint1); + --navbar-menu-box-shadow: rgba(0, 0, 0, 0.05) 0px 0px 1px, + rgba(0, 0, 0, 0.05) 0px 1px 2px, rgba(0, 0, 0, 0.05) 0px 2px 4px, + rgba(0, 0, 0, 0.05) 0px 4px 8px, rgba(0, 0, 0, 0.05) 0px 8px 16px, + rgba(0, 0, 0, 0.05) 0px 16px 32px; + --copycode-background: var(--mono-tint1); + --copycode-color: #fff; + --docsifytabs-border-color: var(--mono-tint2); + --docsifytabs-tab-background: var(--mono-shade1); + --docsifytabs-tab-color: var(--mono-tint2); + --pagination-border-top: 1px solid var(--mono-tint2); + --pagination-title-color: #fff; + --search-input-background-color: var(--mono-shade2); + --search-input-background-image: url("data:image/svg+xml,%3Csvg height='20px' width='20px' viewBox='0 0 24 24' fill='none' stroke='rgba(255, 255, 255, 0.3)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10.5' cy='10.5' r='7.5' vector-effect='non-scaling-stroke'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='15.8' y2='15.8' vector-effect='non-scaling-stroke'%3E%3C/line%3E%3C/svg%3E"); + --search-input-border-color: var(--mono-tint1); + --search-input-placeholder-color: rgba(255, 255, 255, 0.4); + --search-clear-icon-color1: rgba(255, 255, 255, 0.3); + --sidebar-background: var(--mono-shade1); + --sidebar-border-color: var(--mono-tint1); + --sidebar-nav-pagelink-background: no-repeat 2px calc(50% - 2.5px) / 6px 5px + linear-gradient( + 45deg, + transparent 2.75px, + var(--mono-tint2) 2.75px 4.25px, + transparent 4px + ), + no-repeat 2px calc(50% + 2.5px) / 6px 5px + linear-gradient( + 135deg, + transparent 2.75px, + var(--mono-tint2) 2.75px 4.25px, + transparent 4px + ); + --sidebar-nav-pagelink-background--loaded: no-repeat 0px center / 5px 6px + linear-gradient( + 225deg, + transparent 2.75px, + var(--mono-tint2) 2.75px 4.25px, + transparent 4.25px + ), + no-repeat 5px center / 5px 6px + linear-gradient( + 135deg, + transparent 2.75px, + var(--mono-tint2) 2.75px 4.25px, + transparent 4.25px + ); +} -/*# sourceMappingURL=theme-simple-dark.css.map */ \ No newline at end of file +/*# sourceMappingURL=theme-simple-dark.css.map */ diff --git a/docs/css/theme-simple.css b/docs/css/theme-simple.css index 608d017e..581a3464 100644 --- a/docs/css/theme-simple.css +++ b/docs/css/theme-simple.css @@ -1,3 +1,2375 @@ -.github-corner{position:absolute;z-index:40;top:0;right:0;border-bottom:0;text-decoration:none}.github-corner svg{height:70px;width:70px;fill:var(--theme-color);color:var(--base-background-color)}.github-corner:hover .octo-arm{-webkit-animation:octocat-wave 560ms ease-in-out;animation:octocat-wave 560ms ease-in-out}@-webkit-keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}.progress{position:fixed;z-index:2147483647;top:0;left:0;right:0;height:3px;width:0;background-color:var(--theme-color);transition:width var(--duration-fast),opacity calc(var(--duration-fast)*2)}body.ready-transition:after,body.ready-transition>*:not(.progress){opacity:0;transition:opacity var(--spinner-transition-duration)}body.ready-transition:after{content:"";position:absolute;z-index:1000;top:calc(50% - var(--spinner-size)/2);left:calc(50% - var(--spinner-size)/2);height:var(--spinner-size);width:var(--spinner-size);border:var(--spinner-track-width, 0) solid var(--spinner-track-color);border-left-color:var(--theme-color);border-left-color:var(--theme-color);border-radius:50%;-webkit-animation:spinner var(--duration-slow) infinite linear;animation:spinner var(--duration-slow) infinite linear}body.ready-transition.ready-spinner:after{opacity:1}body.ready-transition.ready-fix:after{opacity:0}body.ready-transition.ready-fix>*:not(.progress){opacity:1;transition-delay:var(--spinner-transition-duration)}@-webkit-keyframes spinner{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}@keyframes spinner{0%{transform:rotate(0deg)}100%{transform:rotate(360deg)}}*,*:before,*:after{box-sizing:inherit;font-size:inherit;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none}:root{box-sizing:border-box;background-color:var(--base-background-color);font-size:var(--base-font-size);font-weight:var(--base-font-weight);line-height:var(--base-line-height);letter-spacing:var(--base-letter-spacing);color:var(--base-color);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;font-smoothing:antialiased}html,button,input,optgroup,select,textarea{font-family:var(--base-font-family)}button,input,optgroup,select,textarea{font-size:100%;margin:0}a{text-decoration:none;-webkit-text-decoration-skip:ink;text-decoration-skip-ink:auto}body{margin:0}hr{height:0;margin:2em 0;border:none;border-bottom:var(--hr-border, 0)}img{max-width:100%;border:0}main{display:block}main.hidden{display:none}mark{background:var(--mark-background);color:var(--mark-color)}pre{font-family:var(--pre-font-family);font-size:var(--pre-font-size);font-weight:var(--pre-font-weight);line-height:var(--pre-line-height)}small{display:inline-block;font-size:var(--small-font-size)}strong{font-weight:var(--strong-font-weight);color:var(--strong-color, currentColor)}sub,sup{font-size:var(--subsup-font-size);line-height:0;position:relative;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}body:not([data-platform^=Mac]) *{scrollbar-color:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3) hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1);scrollbar-width:thin}body:not([data-platform^=Mac]) * ::-webkit-scrollbar{width:5px;height:5px}body:not([data-platform^=Mac]) * ::-webkit-scrollbar-thumb{background:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3)}body:not([data-platform^=Mac]) * ::-webkit-scrollbar-track{background:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1)}::-moz-selection{background:var(--selection-color)}::selection{background:var(--selection-color)}.emoji{height:var(--emoji-size);vertical-align:middle}.task-list-item{list-style:none}.task-list-item input{margin-right:.5em;margin-left:0;vertical-align:.075em}.markdown-section code[class*=lang-],.markdown-section pre[data-lang]{font-family:var(--code-font-family);font-size:var(--code-font-size);font-weight:var(--code-font-weight);letter-spacing:normal;line-height:var(--code-block-line-height);-moz-tab-size:var(--code-tab-size);-o-tab-size:var(--code-tab-size);tab-size:var(--code-tab-size);text-align:left;white-space:pre;word-spacing:normal;word-wrap:normal;word-break:normal;-webkit-hyphens:none;hyphens:none}.markdown-section pre[data-lang]{position:relative;overflow:hidden;margin:var(--code-block-margin);padding:0;border-radius:var(--code-block-border-radius)}.markdown-section pre[data-lang]::after{content:attr(data-lang);position:absolute;top:.75em;right:.75em;opacity:.6;color:inherit;font-size:var(--font-size-s);line-height:1}.markdown-section pre[data-lang] code{display:block;overflow:auto;padding:var(--code-block-padding)}code[class*=lang-],pre[data-lang]{color:var(--code-theme-text)}pre[data-lang]::-moz-selection,pre[data-lang] ::-moz-selection,code[class*=lang-]::-moz-selection,code[class*=lang-] ::-moz-selection{background:var(--code-theme-selection, var(--selection-color))}pre[data-lang]::-moz-selection, pre[data-lang] ::-moz-selection, code[class*=lang-]::-moz-selection, code[class*=lang-] ::-moz-selection{background:var(--code-theme-selection, var(--selection-color))}pre[data-lang]::selection,pre[data-lang] ::selection,code[class*=lang-]::selection,code[class*=lang-] ::selection{background:var(--code-theme-selection, var(--selection-color))}:not(pre)>code[class*=lang-],pre[data-lang]{background:var(--code-theme-background)}.namespace{opacity:.7}.token.comment,.token.prolog,.token.doctype,.token.cdata{color:var(--code-theme-comment)}.token.punctuation{color:var(--code-theme-punctuation)}.token.property,.token.tag,.token.boolean,.token.number,.token.constant,.token.symbol,.token.deleted{color:var(--code-theme-tag)}.token.selector,.token.attr-name,.token.string,.token.char,.token.builtin,.token.inserted{color:var(--code-theme-selector)}.token.operator,.token.entity,.token.url,.language-css .token.string,.style .token.string{color:var(--code-theme-operator)}.token.atrule,.token.attr-value,.token.keyword{color:var(--code-theme-keyword)}.token.function{color:var(--code-theme-function)}.token.regex,.token.important,.token.variable{color:var(--code-theme-variable)}.token.important,.token.bold{font-weight:bold}.token.italic{font-style:italic}.token.entity{cursor:help}.markdown-section{position:relative;max-width:var(--content-max-width);margin:0 auto;padding:2rem 45px}.app-nav:not(:empty)~main .markdown-section{padding-top:3.5rem}.markdown-section figure,.markdown-section p,.markdown-section ol,.markdown-section ul{margin:1em 0}.markdown-section ol,.markdown-section ul{padding-left:1.5rem}.markdown-section ol ol,.markdown-section ol ul,.markdown-section ul ol,.markdown-section ul ul{margin-top:.15rem;margin-bottom:.15rem}.markdown-section a{border-bottom:var(--link-border-bottom);color:var(--link-color);-webkit-text-decoration:var(--link-text-decoration);text-decoration:var(--link-text-decoration);-webkit-text-decoration-color:var(--link-text-decoration-color);text-decoration-color:var(--link-text-decoration-color)}.markdown-section a:hover{border-bottom:var(--link-border-bottom--hover, var(--link-border-bottom, 0));color:var(--link-color--hover, var(--link-color));-webkit-text-decoration:var(--link-text-decoration--hover, var(--link-text-decoration));text-decoration:var(--link-text-decoration--hover, var(--link-text-decoration));-webkit-text-decoration-color:var(--link-text-decoration-color--hover, var(--link-text-decoration-color));text-decoration-color:var(--link-text-decoration-color--hover, var(--link-text-decoration-color))}.markdown-section a.anchor{border-bottom:0;color:inherit;text-decoration:none}.markdown-section a.anchor:hover{text-decoration:underline}.markdown-section blockquote{overflow:visible;margin:2em 0;padding:var(--blockquote-padding);border-width:var(--blockquote-border-width, 0);border-style:var(--blockquote-border-style);border-color:var(--blockquote-border-color);border-radius:var(--blockquote-border-radius);background:var(--blockquote-background);color:var(--blockquote-color);font-family:var(--blockquote-font-family);font-size:var(--blockquote-font-size);font-style:var(--blockquote-font-style);font-weight:var(--blockquote-font-weight);quotes:"“" "”" "‘" "’"}.markdown-section blockquote em{font-family:var(--blockquote-em-font-family);font-size:var(--blockquote-em-font-size);font-style:var(--blockquote-em-font-style);font-weight:var(--blockquote-em-font-weight)}.markdown-section blockquote p:first-child{margin-top:0}.markdown-section blockquote p:first-child:before,.markdown-section blockquote p:first-child:after{color:var(--blockquote-quotes-color);font-family:var(--blockquote-quotes-font-family);font-size:var(--blockquote-quotes-font-size);line-height:0}.markdown-section blockquote p:first-child:before{content:var(--blockquote-quotes-open);margin-right:.15em;vertical-align:-0.45em}.markdown-section blockquote p:first-child:after{content:var(--blockquote-quotes-close);margin-left:.15em;vertical-align:-0.55em}.markdown-section blockquote p:last-child{margin-bottom:0}.markdown-section code{font-family:var(--code-font-family);font-size:var(--code-font-size);font-weight:var(--code-font-weight);line-height:inherit}.markdown-section code:not([class*=lang-]):not([class*=language-]){margin:var(--code-inline-margin);padding:var(--code-inline-padding);border-radius:var(--code-inline-border-radius);background:var(--code-inline-background);color:var(--code-inline-color, currentColor);white-space:nowrap}.markdown-section h1:first-child,.markdown-section h2:first-child,.markdown-section h3:first-child,.markdown-section h4:first-child,.markdown-section h5:first-child,.markdown-section h6:first-child{margin-top:0}.markdown-section h1 a[data-id],.markdown-section h2 a[data-id],.markdown-section h3 a[data-id],.markdown-section h4 a[data-id],.markdown-section h5 a[data-id],.markdown-section h6 a[data-id]{display:inline-block}.markdown-section h1 code,.markdown-section h2 code,.markdown-section h3 code,.markdown-section h4 code,.markdown-section h5 code,.markdown-section h6 code{font-size:.875em}.markdown-section h1+h2,.markdown-section h1+h3,.markdown-section h1+h4,.markdown-section h1+h5,.markdown-section h1+h6,.markdown-section h2+h3,.markdown-section h2+h4,.markdown-section h2+h5,.markdown-section h2+h6,.markdown-section h3+h4,.markdown-section h3+h5,.markdown-section h3+h6,.markdown-section h4+h5,.markdown-section h4+h6,.markdown-section h5+h6{margin-top:1rem}.markdown-section h1{margin:var(--heading-h1-margin, var(--heading-margin));padding:var(--heading-h1-padding, var(--heading-padding));border-width:var(--heading-h1-border-width, 0);border-style:var(--heading-h1-border-style);border-color:var(--heading-h1-border-color);font-family:var(--heading-h1-font-family, var(--heading-font-family));font-size:var(--heading-h1-font-size);font-weight:var(--heading-h1-font-weight, var(--heading-font-weight));line-height:var(--base-line-height);color:var(--heading-h1-color, var(--heading-color))}.markdown-section h2{margin:var(--heading-h2-margin, var(--heading-margin));padding:var(--heading-h2-padding, var(--heading-padding));border-width:var(--heading-h2-border-width, 0);border-style:var(--heading-h2-border-style);border-color:var(--heading-h2-border-color);font-family:var(--heading-h2-font-family, var(--heading-font-family));font-size:var(--heading-h2-font-size);font-weight:var(--heading-h2-font-weight, var(--heading-font-weight));line-height:var(--base-line-height);color:var(--heading-h2-color, var(--heading-color))}.markdown-section h3{margin:var(--heading-h3-margin, var(--heading-margin));padding:var(--heading-h3-padding, var(--heading-padding));border-width:var(--heading-h3-border-width, 0);border-style:var(--heading-h3-border-style);border-color:var(--heading-h3-border-color);font-family:var(--heading-h3-font-family, var(--heading-font-family));font-size:var(--heading-h3-font-size);font-weight:var(--heading-h3-font-weight, var(--heading-font-weight));color:var(--heading-h3-color, var(--heading-color))}.markdown-section h4{margin:var(--heading-h4-margin, var(--heading-margin));padding:var(--heading-h4-padding, var(--heading-padding));border-width:var(--heading-h4-border-width, 0);border-style:var(--heading-h4-border-style);border-color:var(--heading-h4-border-color);font-family:var(--heading-h4-font-family, var(--heading-font-family));font-size:var(--heading-h4-font-size);font-weight:var(--heading-h4-font-weight, var(--heading-font-weight));color:var(--heading-h4-color, var(--heading-color))}.markdown-section h5{margin:var(--heading-h5-margin, var(--heading-margin));padding:var(--heading-h5-padding, var(--heading-padding));border-width:var(--heading-h5-border-width, 0);border-style:var(--heading-h5-border-style);border-color:var(--heading-h5-border-color);font-family:var(--heading-h5-font-family, var(--heading-font-family));font-size:var(--heading-h5-font-size);font-weight:var(--heading-h5-font-weight, var(--heading-font-weight));color:var(--heading-h5-color, var(--heading-color))}.markdown-section h6{margin:var(--heading-h6-margin, var(--heading-margin));padding:var(--heading-h6-padding, var(--heading-padding));border-width:var(--heading-h6-border-width, 0);border-style:var(--heading-h6-border-style);border-color:var(--heading-h6-border-color);font-family:var(--heading-h6-font-family, var(--heading-font-family));font-size:var(--heading-h6-font-size);font-weight:var(--heading-h6-font-weight, var(--heading-font-weight));color:var(--heading-h6-color, var(--heading-color))}.markdown-section iframe{margin:1em 0}.markdown-section img{max-width:100%}.markdown-section kbd{display:inline-block;min-width:var(--kbd-min-width);margin:var(--kbd-margin);padding:var(--kbd-padding);border:var(--kbd-border);border-radius:var(--kbd-border-radius);background:var(--kbd-background);font-family:inherit;font-size:var(--kbd-font-size);text-align:center;letter-spacing:0;line-height:1;color:var(--kbd-color)}.markdown-section kbd+kbd{margin-left:-0.15em}.markdown-section table{display:block;overflow:auto;margin:1rem 0;border-spacing:0;border-collapse:collapse}.markdown-section th,.markdown-section td{padding:var(--table-cell-padding)}.markdown-section th:not([align]){text-align:left}.markdown-section thead{border-color:var(--table-head-border-color);border-style:solid;border-width:var(--table-head-border-width, 0);background:var(--table-head-background)}.markdown-section th{font-weight:var(--table-head-font-weight);color:var(--strong-color)}.markdown-section td{border-color:var(--table-cell-border-color);border-style:solid;border-width:var(--table-cell-border-width, 0)}.markdown-section tbody{border-color:var(--table-body-border-color);border-style:solid;border-width:var(--table-body-border-width, 0)}.markdown-section tbody tr:nth-child(odd){background:var(--table-row-odd-background)}.markdown-section tbody tr:nth-child(even){background:var(--table-row-even-background)}.markdown-section>ul .task-list-item{margin-left:-1.25em}.markdown-section>ul .task-list-item .task-list-item{margin-left:0}.markdown-section .table-wrapper{overflow-x:auto}.markdown-section .table-wrapper table{display:table;width:100%}.markdown-section .table-wrapper td::before{display:none}@media(max-width: 30em){.markdown-section .table-wrapper tbody,.markdown-section .table-wrapper tr,.markdown-section .table-wrapper td{display:block}.markdown-section .table-wrapper th,.markdown-section .table-wrapper td{border:none}.markdown-section .table-wrapper thead{display:none}.markdown-section .table-wrapper tr{border-color:var(--table-cell-border-color);border-style:solid;border-width:var(--table-cell-border-width, 0);padding:var(--table-cell-padding)}.markdown-section .table-wrapper tr:not(:last-child){border-bottom:0}.markdown-section .table-wrapper td{padding:.15em 0 .15em 8em}.markdown-section .table-wrapper td::before{display:inline-block;float:left;width:8em;margin-left:-8em;font-weight:bold;text-align:left}}.markdown-section .tip,.markdown-section .warn{position:relative;margin:2em 0;padding:var(--notice-padding);border-width:var(--notice-border-width, 0);border-style:var(--notice-border-style);border-color:var(--notice-border-color);border-radius:var(--notice-border-radius);background:var(--notice-background);font-family:var(--notice-font-family);font-weight:var(--notice-font-weight);color:var(--notice-color)}.markdown-section .tip:before,.markdown-section .warn:before{display:inline-block;position:var(--notice-before-position, relative);top:var(--notice-before-top);left:var(--notice-before-left);height:var(--notice-before-height);width:var(--notice-before-width);margin:var(--notice-before-margin);padding:var(--notice-before-padding);border-radius:var(--notice-before-border-radius);line-height:var(--notice-before-line-height);font-family:var(--notice-before-font-family);font-size:var(--notice-before-font-size);font-weight:var(--notice-before-font-weight);text-align:center}.markdown-section .tip{border-width:var(--notice-important-border-width, var(--notice-border-width, 0));border-style:var(--notice-important-border-style, var(--notice-border-style));border-color:var(--notice-important-border-color, var(--notice-border-color));background:var(--notice-important-background, var(--notice-background));color:var(--notice-important-color, var(--notice-color))}.markdown-section .tip:before{content:var(--notice-important-before-content, var(--notice-before-content));background:var(--notice-important-before-background, var(--notice-before-background));color:var(--notice-important-before-color, var(--notice-before-color))}.markdown-section .warn{border-width:var(--notice-tip-border-width, var(--notice-border-width, 0));border-style:var(--notice-tip-border-style, var(--notice-border-style));border-color:var(--notice-tip-border-color, var(--notice-border-color));background:var(--notice-tip-background, var(--notice-background));color:var(--notice-tip-color, var(--notice-color))}.markdown-section .warn:before{content:var(--notice-tip-before-content, var(--notice-before-content));background:var(--notice-tip-before-background, var(--notice-before-background));color:var(--notice-tip-before-color, var(--notice-before-color))}.cover{display:none;position:relative;z-index:20;min-height:100vh;flex-direction:column;align-items:center;justify-content:center;padding:calc(var(--cover-border-inset, 0px) + var(--cover-border-width, 0px));color:var(--cover-color);text-align:var(--cover-text-align)}@media screen and (-ms-high-contrast: active),screen and (-ms-high-contrast: none){.cover{height:100vh}}.cover:before,.cover:after{content:"";position:absolute}.cover:before{top:0;bottom:0;left:0;right:0;background-blend-mode:var(--cover-background-blend-mode);background-color:var(--cover-background-color);background-image:var(--cover-background-image);background-position:var(--cover-background-position);background-repeat:var(--cover-background-repeat);background-size:var(--cover-background-size)}.cover:after{top:var(--cover-border-inset, 0);bottom:var(--cover-border-inset, 0);left:var(--cover-border-inset, 0);right:var(--cover-border-inset, 0);border-width:var(--cover-border-width, 0);border-style:solid;border-color:var(--cover-border-color)}.cover a{border-bottom:var(--cover-link-border-bottom);color:var(--cover-link-color);-webkit-text-decoration:var(--cover-link-text-decoration);text-decoration:var(--cover-link-text-decoration);-webkit-text-decoration-color:var(--cover-link-text-decoration-color);text-decoration-color:var(--cover-link-text-decoration-color)}.cover a:hover{border-bottom:var(--cover-link-border-bottom--hover, var(--cover-link-border-bottom));color:var(--cover-link-color--hover, var(--cover-link-color));-webkit-text-decoration:var(--cover-link-text-decoration--hover, var(--cover-link-text-decoration));text-decoration:var(--cover-link-text-decoration--hover, var(--cover-link-text-decoration));-webkit-text-decoration-color:var(--cover-link-text-decoration-color--hover, var(--cover-link-text-decoration-color));text-decoration-color:var(--cover-link-text-decoration-color--hover, var(--cover-link-text-decoration-color))}.cover h1{color:var(--cover-heading-color);position:relative;margin:0;font-size:var(--cover-heading-font-size);font-weight:var(--cover-heading-font-weight);line-height:1.2}.cover h1 a,.cover h1 a:hover{display:block;border-bottom:none;color:inherit;text-decoration:none}.cover h1 small{position:absolute;bottom:0;margin-left:.5em}.cover h1 span{font-size:calc(var(--cover-heading-font-size-min)*1px)}@media(min-width: 26em){.cover h1 span{font-size:calc(var(--cover-heading-font-size-min)*1px + (var(--cover-heading-font-size-max) - var(--cover-heading-font-size-min))*(100vw - 420px)/604)}}@media(min-width: 64em){.cover h1 span{font-size:calc(var(--cover-heading-font-size-max)*1px)}}.cover blockquote{margin:0;color:var(--cover-blockquote-color);font-size:var(--cover-blockquote-font-size)}.cover blockquote a{color:inherit}.cover ul{padding:0;list-style-type:none}.cover .cover-main{position:relative;z-index:1;max-width:var(--cover-max-width);margin:var(--cover-margin);padding:0 45px}.cover .cover-main>p:last-child{margin:1.25em -0.25em}.cover .cover-main>p:last-child a{display:block;margin:.375em .25em;padding:var(--cover-button-padding);border:var(--cover-button-border);border-radius:var(--cover-button-border-radius);box-shadow:var(--cover-button-box-shadow);background:var(--cover-button-background);text-align:center;-webkit-text-decoration:var(--cover-button-text-decoration);text-decoration:var(--cover-button-text-decoration);-webkit-text-decoration-color:var(--cover-button-text-decoration-color);text-decoration-color:var(--cover-button-text-decoration-color);color:var(--cover-button-color);white-space:nowrap;transition:var(--cover-button-transition)}.cover .cover-main>p:last-child a:hover{border:var(--cover-button-border--hover, var(--cover-button-border));box-shadow:var(--cover-button-box-shadow--hover, var(--cover-button-box-shadow));background:var(--cover-button-background--hover, var(--cover-button-background));-webkit-text-decoration:var(--cover-button-text-decoration--hover, var(--cover-button-text-decoration));text-decoration:var(--cover-button-text-decoration--hover, var(--cover-button-text-decoration));-webkit-text-decoration-color:var(--cover-button-text-decoration-color--hover, var(--cover-button-text-decoration-color));text-decoration-color:var(--cover-button-text-decoration-color--hover, var(--cover-button-text-decoration-color));color:var(--cover-button-color--hover, var(--cover-button-color))}.cover .cover-main>p:last-child a:first-child{border:var(--cover-button-primary-border, var(--cover-button-border));box-shadow:var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow));background:var(--cover-button-primary-background, var(--cover-button-background));-webkit-text-decoration:var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration));text-decoration:var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration));-webkit-text-decoration-color:var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color));text-decoration-color:var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color));color:var(--cover-button-primary-color, var(--cover-button-color))}.cover .cover-main>p:last-child a:first-child:hover{border:var(--cover-button-primary-border--hover, var(--cover-button-border--hover, var(--cover-button-primary-border, var(--cover-button-border))));box-shadow:var(--cover-button-primary-box-shadow--hover, var(--cover-button-box-shadow--hover, var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow))));background:var(--cover-button-primary-background--hover, var(--cover-button-background--hover, var(--cover-button-primary-background, var(--cover-button-background))));-webkit-text-decoration:var(--cover-button-primary-text-decoration--hover, var(--cover-button-text-decoration--hover, var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration))));text-decoration:var(--cover-button-primary-text-decoration--hover, var(--cover-button-text-decoration--hover, var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration))));-webkit-text-decoration-color:var(--cover-button-primary-text-decoration-color--hover, var(--cover-button-text-decoration-color--hover, var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color))));text-decoration-color:var(--cover-button-primary-text-decoration-color--hover, var(--cover-button-text-decoration-color--hover, var(--cover-button-primary-text-decoration-color, var(--cover-button-text-decoration-color))));color:var(--cover-button-primary-color--hover, var(--cover-button-color--hover, var(--cover-button-primary-color, var(--cover-button-color))))}@media(min-width: 30.01em){.cover .cover-main>p:last-child a{display:inline-block}}.cover .mask{visibility:var(--cover-background-mask-visibility, hidden);position:absolute;top:0;bottom:0;left:0;right:0;background-color:var(--cover-background-mask-color);opacity:var(--cover-background-mask-opacity)}.cover.has-mask .mask{visibility:visible}.cover.show{display:flex}.app-nav{position:absolute;z-index:30;top:calc(35px - .5em*var(--base-line-height));left:45px;right:80px;text-align:right}.app-nav.no-badge{right:45px}.app-nav li>img,.app-nav li>a>img{margin-top:-0.25em;vertical-align:middle}.app-nav li>img:first-child,.app-nav li>a>img:first-child{margin-right:.5em}.app-nav ul,.app-nav li{margin:0;padding:0;list-style:none}.app-nav li{position:relative}.app-nav li a{display:block;line-height:1;transition:var(--navbar-root-transition)}.app-nav>ul>li{display:inline-block;margin:var(--navbar-root-margin)}.app-nav>ul>li:first-child{margin-left:0}.app-nav>ul>li:last-child{margin-right:0}.app-nav>ul>li>a,.app-nav>ul>li>span{padding:var(--navbar-root-padding);border-width:var(--navbar-root-border-width, 0);border-style:var(--navbar-root-border-style);border-color:var(--navbar-root-border-color);border-radius:var(--navbar-root-border-radius);background:var(--navbar-root-background);color:var(--navbar-root-color);-webkit-text-decoration:var(--navbar-root-text-decoration);text-decoration:var(--navbar-root-text-decoration);-webkit-text-decoration-color:var(--navbar-root-text-decoration-color);text-decoration-color:var(--navbar-root-text-decoration-color)}.app-nav>ul>li>a:hover,.app-nav>ul>li>span:hover{background:var(--navbar-root-background--hover, var(--navbar-root-background));border-style:var(--navbar-root-border-style--hover, var(--navbar-root-border-style));border-color:var(--navbar-root-border-color--hover, var(--navbar-root-border-color));color:var(--navbar-root-color--hover, var(--navbar-root-color));-webkit-text-decoration:var(--navbar-root-text-decoration--hover, var(--navbar-root-text-decoration));text-decoration:var(--navbar-root-text-decoration--hover, var(--navbar-root-text-decoration));-webkit-text-decoration-color:var(--navbar-root-text-decoration-color--hover, var(--navbar-root-text-decoration-color));text-decoration-color:var(--navbar-root-text-decoration-color--hover, var(--navbar-root-text-decoration-color))}.app-nav>ul>li>a:not(:last-child),.app-nav>ul>li>span:not(:last-child){padding:var(--navbar-menu-root-padding, var(--navbar-root-padding));background:var(--navbar-menu-root-background, var(--navbar-root-background))}.app-nav>ul>li>a:not(:last-child):hover,.app-nav>ul>li>span:not(:last-child):hover{background:var(--navbar-menu-root-background--hover, var(--navbar-menu-root-background, var(--navbar-root-background--hover, var(--navbar-root-background))))}.app-nav>ul>li>a.active{background:var(--navbar-root-background--active, var(--navbar-root-background));border-style:var(--navbar-root-border-style--active, var(--navbar-root-border-style));border-color:var(--navbar-root-border-color--active, var(--navbar-root-border-color));color:var(--navbar-root-color--active, var(--navbar-root-color));-webkit-text-decoration:var(--navbar-root-text-decoration--active, var(--navbar-root-text-decoration));text-decoration:var(--navbar-root-text-decoration--active, var(--navbar-root-text-decoration));-webkit-text-decoration-color:var(--navbar-root-text-decoration-color--active, var(--navbar-root-text-decoration-color));text-decoration-color:var(--navbar-root-text-decoration-color--active, var(--navbar-root-text-decoration-color))}.app-nav>ul>li>a.active:not(:last-child):hover{background:var(--navbar-menu-root-background--active, var(--navbar-menu-root-background, var(--navbar-root-background--active, var(--navbar-root-background))))}.app-nav>ul>li ul{visibility:hidden;position:absolute;top:100%;right:50%;overflow-y:auto;box-sizing:border-box;max-height:50vh;padding:var(--navbar-menu-padding);border-width:var(--navbar-menu-border-width, 0);border-style:solid;border-color:var(--navbar-menu-border-color);border-radius:var(--navbar-menu-border-radius);background:var(--navbar-menu-background);box-shadow:var(--navbar-menu-box-shadow);text-align:left;white-space:nowrap;opacity:0;transform:translate(50%, -0.35em);transition:var(--navbar-menu-transition)}.app-nav>ul>li ul li{white-space:nowrap}.app-nav>ul>li ul a{margin:var(--navbar-menu-link-margin);padding:var(--navbar-menu-link-padding);border-width:var(--navbar-menu-link-border-width, 0);border-style:var(--navbar-menu-link-border-style);border-color:var(--navbar-menu-link-border-color);border-radius:var(--navbar-menu-link-border-radius);background:var(--navbar-menu-link-background);color:var(--navbar-menu-link-color);-webkit-text-decoration:var(--navbar-menu-link-text-decoration);text-decoration:var(--navbar-menu-link-text-decoration);-webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color);text-decoration-color:var(--navbar-menu-link-text-decoration-color)}.app-nav>ul>li ul a:hover{background:var(--navbar-menu-link-background--hover, var(--navbar-menu-link-background));border-style:var(--navbar-menu-link-border-style--hover, var(--navbar-menu-link-border-style));border-color:var(--navbar-menu-link-border-color--hover, var(--navbar-menu-link-border-color));color:var(--navbar-menu-link-color--hover, var(--navbar-menu-link-color));-webkit-text-decoration:var(--navbar-menu-link-text-decoration--hover, var(--navbar-menu-link-text-decoration));text-decoration:var(--navbar-menu-link-text-decoration--hover, var(--navbar-menu-link-text-decoration));-webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color--hover, var(--navbar-menu-link-text-decoration-color));text-decoration-color:var(--navbar-menu-link-text-decoration-color--hover, var(--navbar-menu-link-text-decoration-color))}.app-nav>ul>li ul a.active{background:var(--navbar-menu-link-background--active, var(--navbar-menu-link-background));border-style:var(--navbar-menu-link-border-style--active, var(--navbar-menu-link-border-style));border-color:var(--navbar-menu-link-border-color--active, var(--navbar-menu-link-border-color));color:var(--navbar-menu-link-color--active, var(--navbar-menu-link-color));-webkit-text-decoration:var(--navbar-menu-link-text-decoration--active, var(--navbar-menu-link-text-decoration));text-decoration:var(--navbar-menu-link-text-decoration--active, var(--navbar-menu-link-text-decoration));-webkit-text-decoration-color:var(--navbar-menu-link-text-decoration-color--active, var(--navbar-menu-link-text-decoration-color));text-decoration-color:var(--navbar-menu-link-text-decoration-color--active, var(--navbar-menu-link-text-decoration-color))}.app-nav>ul>li:hover ul,.app-nav>ul>li:focus ul,.app-nav>ul>li.focus-within ul{visibility:visible;opacity:1;transform:translate(50%, 0)}@media(min-width: 48em){nav.app-nav{margin-left:var(--sidebar-width)}}main{position:relative;overflow-x:hidden;min-height:100vh}.sidebar,.sidebar-toggle,.sidebar+.content{transition:all var(--sidebar-transition-duration) ease-out}@media(min-width: 48em){.sidebar+.content{margin-left:var(--sidebar-width)}}.sidebar{display:flex;flex-direction:column;position:fixed;z-index:10;top:0;right:100%;overflow-x:hidden;overflow-y:auto;height:100vh;width:var(--sidebar-width);padding:var(--sidebar-padding);border-width:var(--sidebar-border-width);border-style:solid;border-color:var(--sidebar-border-color);background:var(--sidebar-background)}.sidebar>h1{margin:0;margin:var(--sidebar-name-margin);padding:var(--sidebar-name-padding);background:var(--sidebar-name-background);color:var(--sidebar-name-color);font-family:var(--sidebar-name-font-family);font-size:var(--sidebar-name-font-size);font-weight:var(--sidebar-name-font-weight);text-align:var(--sidebar-name-text-align)}.sidebar>h1 img{max-width:100%}.sidebar>h1 .app-name-link{color:var(--sidebar-name-color)}body:not([data-platform^=Mac]) .sidebar::-webkit-scrollbar{width:5px}body:not([data-platform^=Mac]) .sidebar::-webkit-scrollbar-thumb{border-radius:50vw}@media(min-width: 48em){.sidebar{position:absolute;transform:translateX(var(--sidebar-width))}}@media print{.sidebar{display:none}}.sidebar-nav,.sidebar nav{order:1;margin:var(--sidebar-nav-margin);padding:var(--sidebar-nav-padding);background:var(--sidebar-nav-background)}.sidebar-nav ul,.sidebar nav ul{margin:0;padding:0;list-style:none}.sidebar-nav ul ul,.sidebar nav ul ul{margin-left:var(--sidebar-nav-indent)}.sidebar-nav a,.sidebar nav a{display:block;overflow:hidden;margin:var(--sidebar-nav-link-margin);padding:var(--sidebar-nav-link-padding);border-width:var(--sidebar-nav-link-border-width, 0);border-style:var(--sidebar-nav-link-border-style);border-color:var(--sidebar-nav-link-border-color);border-radius:var(--sidebar-nav-link-border-radius);background:var(--sidebar-nav-link-background);color:var(--sidebar-nav-link-color);font-weight:var(--sidebar-nav-link-font-weight);white-space:nowrap;-webkit-text-decoration:var(--sidebar-nav-link-text-decoration);text-decoration:var(--sidebar-nav-link-text-decoration);-webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-overflow:ellipsis;transition:var(--sidebar-nav-link-transition)}.sidebar-nav a img,.sidebar nav a img{margin-top:-0.25em;vertical-align:middle}.sidebar-nav a img:first-child,.sidebar nav a img:first-child{margin-right:.5em}.sidebar-nav a:hover,.sidebar nav a:hover{border-width:var(--sidebar-nav-link-border-width--hover, var(--sidebar-nav-link-border-width, 0));border-style:var(--sidebar-nav-link-border-style--hover, var(--sidebar-nav-link-border-style));border-color:var(--sidebar-nav-link-border-color--hover, var(--sidebar-nav-link-border-color));background:var(--sidebar-nav-link-background--hover, var(--sidebar-nav-link-background));color:var(--sidebar-nav-link-color--hover, var(--sidebar-nav-link-color));font-weight:var(--sidebar-nav-link-font-weight--hover, var(--sidebar-nav-link-font-weight));-webkit-text-decoration:var(--sidebar-nav-link-text-decoration--hover, var(--sidebar-nav-link-text-decoration));text-decoration:var(--sidebar-nav-link-text-decoration--hover, var(--sidebar-nav-link-text-decoration));-webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-decoration-color:var(--sidebar-nav-link-text-decoration-color)}.sidebar-nav ul>li>span,.sidebar-nav ul>li>strong,.sidebar nav ul>li>span,.sidebar nav ul>li>strong{display:block;margin:var(--sidebar-nav-strong-margin);padding:var(--sidebar-nav-strong-padding);border-width:var(--sidebar-nav-strong-border-width, 0);border-style:solid;border-color:var(--sidebar-nav-strong-border-color);color:var(--sidebar-nav-strong-color);font-size:var(--sidebar-nav-strong-font-size);font-weight:var(--sidebar-nav-strong-font-weight);text-transform:var(--sidebar-nav-strong-text-transform)}.sidebar-nav ul>li>span+ul,.sidebar-nav ul>li>strong+ul,.sidebar nav ul>li>span+ul,.sidebar nav ul>li>strong+ul{margin-left:0}.sidebar-nav ul>li:first-child>span,.sidebar-nav ul>li:first-child>strong,.sidebar nav ul>li:first-child>span,.sidebar nav ul>li:first-child>strong{margin-top:0}.sidebar-nav::-webkit-scrollbar,.sidebar nav::-webkit-scrollbar{width:0}@supports(width: env(safe-area-inset)){@media only screen and (orientation: landscape){.sidebar-nav,.sidebar nav{margin-left:calc(env(safe-area-inset-left)/2)}}}.sidebar-nav li>a:before,.sidebar-nav li>strong:before{display:inline-block}.sidebar-nav li>a{background-repeat:var(--sidebar-nav-pagelink-background-repeat);background-size:var(--sidebar-nav-pagelink-background-size)}.sidebar-nav li>a[href^="/"]:not([href*="?id="]),.sidebar-nav li>a[href^="#/"]:not([href*="?id="]){transition:var(--sidebar-nav-pagelink-transition)}.sidebar-nav li>a[href^="/"]:not([href*="?id="]),.sidebar-nav li>a[href^="/"]:not([href*="?id="])~ul a,.sidebar-nav li>a[href^="#/"]:not([href*="?id="]),.sidebar-nav li>a[href^="#/"]:not([href*="?id="])~ul a{padding:var(--sidebar-nav-pagelink-padding, var(--sidebar-nav-link-padding))}.sidebar-nav li>a[href^="/"]:not([href*="?id="]):only-child,.sidebar-nav li>a[href^="#/"]:not([href*="?id="]):only-child{background:var(--sidebar-nav-pagelink-background)}.sidebar-nav li>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li>a[href^="#/"]:not([href*="?id="]):not(:only-child){background:var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background))}.sidebar-nav li.active>a,.sidebar-nav li.collapse>a{border-width:var(--sidebar-nav-link-border-width--active, var(--sidebar-nav-link-border-width));border-style:var(--sidebar-nav-link-border-style--active, var(--sidebar-nav-link-border-style));border-color:var(--sidebar-nav-link-border-color--active, var(--sidebar-nav-link-border-color));background:var(--sidebar-nav-link-background--active, var(--sidebar-nav-link-background));color:var(--sidebar-nav-link-color--active, var(--sidebar-nav-link-color));font-weight:var(--sidebar-nav-link-font-weight--active, var(--sidebar-nav-link-font-weight));-webkit-text-decoration:var(--sidebar-nav-link-text-decoration--active, var(--sidebar-nav-link-text-decoration));text-decoration:var(--sidebar-nav-link-text-decoration--active, var(--sidebar-nav-link-text-decoration));-webkit-text-decoration-color:var(--sidebar-nav-link-text-decoration-color);text-decoration-color:var(--sidebar-nav-link-text-decoration-color)}.sidebar-nav li.active>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li.active>a[href^="#/"]:not([href*="?id="]):not(:only-child){background:var(--sidebar-nav-pagelink-background--active, var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background)))}.sidebar-nav li.collapse>a[href^="/"]:not([href*="?id="]):not(:only-child),.sidebar-nav li.collapse>a[href^="#/"]:not([href*="?id="]):not(:only-child){background:var(--sidebar-nav-pagelink-background--collapse, var(--sidebar-nav-pagelink-background--loaded, var(--sidebar-nav-pagelink-background)))}.sidebar-nav li.collapse .app-sub-sidebar{display:none}.sidebar-nav>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l1, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l1, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l1--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l1, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l1--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color))))}.sidebar-nav>ul>li>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l2, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l2, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l2--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l2, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l2--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color))))}.sidebar-nav>ul>li>ul>li>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l3, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l3, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li>ul>li>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l3--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l3, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l3--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color))))}.sidebar-nav>ul>li>ul>li>ul>li>ul>li>a:before{content:var(--sidebar-nav-link-before-content-l4, var(--sidebar-nav-link-before-content));margin:var(--sidebar-nav-link-before-margin-l4, var(--sidebar-nav-link-before-margin));color:var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color))}.sidebar-nav>ul>li>ul>li>ul>li>ul>li.active>a:before{content:var(--sidebar-nav-link-before-content-l4--active, var(--sidebar-nav-link-before-content--active, var(--sidebar-nav-link-before-content-l4, var(--sidebar-nav-link-before-content))));color:var(--sidebar-nav-link-before-color-l4--active, var(--sidebar-nav-link-before-color--active, var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color))))}.sidebar-nav>:last-child{margin-bottom:2rem}.sidebar-toggle,.sidebar-toggle-button{width:var(--sidebar-toggle-width);outline:none}.sidebar-toggle{position:fixed;z-index:11;top:0;bottom:0;left:0;max-width:40px;margin:0;padding:0;border:0;background:rgba(0,0,0,0);-webkit-appearance:none;-moz-appearance:none;appearance:none;cursor:pointer}.sidebar-toggle .sidebar-toggle-button{position:absolute;top:var(--sidebar-toggle-offset-top);left:var(--sidebar-toggle-offset-left);height:var(--sidebar-toggle-height);border-radius:var(--sidebar-toggle-border-radius);border-width:var(--sidebar-toggle-border-width);border-style:var(--sidebar-toggle-border-style);border-color:var(--sidebar-toggle-border-color);background:var(--sidebar-toggle-background, transparent);color:var(--sidebar-toggle-icon-color)}.sidebar-toggle span{position:absolute;top:calc(50% - var(--sidebar-toggle-icon-stroke-width)/2);left:calc(50% - var(--sidebar-toggle-icon-width)/2);height:var(--sidebar-toggle-icon-stroke-width);width:var(--sidebar-toggle-icon-width);background-color:currentColor}.sidebar-toggle span:nth-child(1){margin-top:calc(0px - var(--sidebar-toggle-icon-height)/2)}.sidebar-toggle span:nth-child(3){margin-top:calc(var(--sidebar-toggle-icon-height)/2)}@media(min-width: 48em){.sidebar-toggle{position:absolute;overflow:visible;top:var(--sidebar-toggle-offset-top);bottom:auto;left:0;height:var(--sidebar-toggle-height);transform:translateX(var(--sidebar-width))}.sidebar-toggle .sidebar-toggle-button{top:0}}@media print{.sidebar-toggle{display:none}}@media(max-width: 47.99em){body.close .sidebar,body.close .sidebar-toggle,body.close .sidebar+.content{transform:translateX(var(--sidebar-width))}}@media(min-width: 48em){body.close .sidebar+.content{transform:translateX(0)}}@media(max-width: 47.99em){body.close nav.app-nav,body.close .github-corner{display:none}}@media(min-width: 48em){body.close .sidebar,body.close .sidebar-toggle{transform:translateX(0)}}@media(min-width: 48em){body.close nav.app-nav{margin-left:0}}@media(max-width: 47.99em){body.close .sidebar-toggle{width:100%;max-width:none}body.close .sidebar-toggle span{margin-top:0}body.close .sidebar-toggle span:nth-child(1){transform:rotate(45deg)}body.close .sidebar-toggle span:nth-child(2){display:none}body.close .sidebar-toggle span:nth-child(3){transform:rotate(-45deg)}}@media(min-width: 48em){body.close .sidebar+.content{margin-left:0}}@media(min-width: 48em){body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}}body .docsify-copy-code-button,body .docsify-copy-code-button:after{border-radius:var(--border-radius-m, 0);border-top-left-radius:0;border-bottom-right-radius:0;background:var(--copycode-background);color:var(--copycode-color)}body .docsify-copy-code-button span{border-radius:var(--border-radius-s, 0)}body .docsify-pagination-container{border-top:var(--pagination-border-top);color:var(--pagination-color)}body .pagination-item-label{font-size:var(--pagination-label-font-size)}body .pagination-item-label svg{color:var(--pagination-label-color);height:var(--pagination-chevron-height);stroke:var(--pagination-chevron-stroke);stroke-linecap:var(--pagination-chevron-stroke-linecap);stroke-linejoin:var(--pagination-chevron-stroke-linecap);stroke-width:var(--pagination-chevron-stroke-width)}body .pagination-item-title{color:var(--pagination-title-color);font-size:var(--pagination-title-font-size)}body .app-name.hide{display:block}body .sidebar{padding:var(--sidebar-padding)}.sidebar .search{margin:0;padding:0;border:0}.sidebar .search input{padding:0;line-height:1;font-size:inherit}.sidebar .search .clear-button{width:auto}.sidebar .search .clear-button svg{transform:scale(1)}.sidebar .search .matching-post{border:none}.sidebar .search p{font-size:inherit}.sidebar .search{order:var(--search-flex-order);margin:var(--search-margin);padding:var(--search-padding);background:var(--search-background)}.sidebar .search a{color:inherit}.sidebar .search h2{margin:var(--search-result-heading-margin);font-size:var(--search-result-heading-font-size);font-weight:var(--search-result-heading-font-weight);color:var(--search-result-heading-color)}.sidebar .search .input-wrap{align-items:stretch;margin:var(--search-input-margin);background-color:var(--search-input-background-color);border-width:var(--search-input-border-width, 0);border-style:solid;border-color:var(--search-input-border-color);border-radius:var(--search-input-border-radius)}.sidebar .search input[type=search]{min-width:0;padding:var(--search-input-padding);border:none;background-color:rgba(0,0,0,0);background-image:var(--search-input-background-image);background-position:var(--search-input-background-position);background-repeat:var(--search-input-background-repeat);background-size:var(--search-input-background-size);font-size:var(--search-input-font-size);color:var(--search-input-color);transition:var(--search-input-transition)}.sidebar .search input[type=search]::-ms-clear{display:none}.sidebar .search input[type=search]::-moz-placeholder{color:var(--search-input-placeholder-color, #808080)}.sidebar .search input[type=search]::placeholder{color:var(--search-input-placeholder-color, #808080)}.sidebar .search input[type=search]::-webkit-input-placeholder{line-height:normal}.sidebar .search input[type=search]:focus{background-color:var(--search-input-background-color--focus, var(--search-input-background-color));background-image:var(--search-input-background-image--focus, var(--search-input-background-image));background-position:var(--search-input-background-position--focus, var(--search-input-background-position));background-size:var(--search-input-background-size--focus, var(--search-input-background-size))}@supports(width: env(safe-area-inset)){@media only screen and (orientation: landscape){.sidebar .search input[type=search]{margin-left:calc(env(safe-area-inset-left)/2)}}}.sidebar .search p{overflow:hidden;text-overflow:ellipsis;-webkit-box-orient:vertical;-webkit-line-clamp:2}.sidebar .search p:empty{text-align:center}.sidebar .search .clear-button{margin:0;padding:0 10px;border:none;line-height:1;background:rgba(0,0,0,0);cursor:pointer}.sidebar .search .clear-button svg circle{fill:var(--search-clear-icon-color1, #808080)}.sidebar .search .clear-button svg path{stroke:var(--search-clear-icon-color2, #fff)}.sidebar .search.show~*:not(h1){display:none}.sidebar .search .results-panel{display:none;color:var(--search-result-item-color);font-size:var(--search-result-item-font-size);font-weight:var(--search-result-item-font-weight)}.sidebar .search .results-panel.show{display:block}.sidebar .search .matching-post{margin:var(--search-result-item-margin);padding:var(--search-result-item-padding)}.sidebar .search .matching-post,.sidebar .search .matching-post:last-child{border-width:var(--search-result-item-border-width, 0) !important;border-style:var(--search-result-item-border-style);border-color:var(--search-result-item-border-color)}.sidebar .search .matching-post p{margin:0}.sidebar .search .search-keyword{margin:var(--search-result-keyword-margin);padding:var(--search-result-keyword-padding);border-radius:var(--search-result-keyword-border-radius);background-color:var(--search-result-keyword-background);color:var(--search-result-keyword-color, currentColor);font-style:normal;font-weight:var(--search-result-keyword-font-weight)}.medium-zoom-overlay,.medium-zoom-image--open,.medium-zoom-image--opened{z-index:2147483646 !important}.medium-zoom-overlay{background:var(--zoomimage-overlay-background) !important}:root{--mono-hue: 113;--mono-saturation: 0%;--mono-shade3: hsl(var(--mono-hue), var(--mono-saturation), 20%);--mono-shade2: hsl(var(--mono-hue), var(--mono-saturation), 30%);--mono-shade1: hsl(var(--mono-hue), var(--mono-saturation), 40%);--mono-base: hsl(var(--mono-hue), var(--mono-saturation), 50%);--mono-tint1: hsl(var(--mono-hue), var(--mono-saturation), 70%);--mono-tint2: hsl(var(--mono-hue), var(--mono-saturation), 89%);--mono-tint3: hsl(var(--mono-hue), var(--mono-saturation), 97%);--theme-hue: 204;--theme-saturation: 90%;--theme-lightness: 45%;--theme-color: hsl(var(--theme-hue), var(--theme-saturation), var(--theme-lightness));--modular-scale: 1.333;--modular-scale--2: calc(var(--modular-scale--1) / var(--modular-scale));--modular-scale--1: calc(var(--modular-scale-1) / var(--modular-scale));--modular-scale-1: 1rem;--modular-scale-2: calc(var(--modular-scale-1) * var(--modular-scale));--modular-scale-3: calc(var(--modular-scale-2) * var(--modular-scale));--modular-scale-4: calc(var(--modular-scale-3) * var(--modular-scale));--modular-scale-5: calc(var(--modular-scale-4) * var(--modular-scale));--font-size-xxxl: var(--modular-scale-5);--font-size-xxl: var(--modular-scale-4);--font-size-xl: var(--modular-scale-3);--font-size-l: var(--modular-scale-2);--font-size-m: var(--modular-scale-1);--font-size-s: var(--modular-scale--1);--font-size-xs: var(--modular-scale--2);--duration-slow: 1s;--duration-medium: 0.5s;--duration-fast: 0.25s;--spinner-size: 60px;--spinner-track-width: 4px;--spinner-track-color: rgba(0, 0, 0, 0.15);--spinner-transition-duration: var(--duration-medium)}:root{--base-background-color: #fff;--base-color: var(--mono-shade2);--base-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--base-font-size: 16px;--base-font-weight: normal;--base-line-height: 1.7;--emoji-size: calc(var(--base-line-height) * 1em);--hr-border: 1px solid var(--mono-tint2);--mark-background: #ffecb3;--pre-font-family: var(--code-font-family);--pre-font-size: var(--code-font-size);--pre-font-weight: normal;--selection-color: #b4d5fe;--small-font-size: var(--font-size-s);--strong-color: var(--heading-color);--strong-font-weight: 600;--subsup-font-size: var(--font-size-s)}:root{--content-max-width: 55em;--blockquote-background: var(--mono-tint3);--blockquote-border-style: solid;--blockquote-border-radius: var(--border-radius-m);--blockquote-em-font-weight: normal;--blockquote-font-weight: normal;--blockquote-padding: 1.5em;--code-font-family: Inconsolata, Consolas, Menlo, Monaco, "Andale Mono WT", "Andale Mono", "Lucida Console", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace;--code-font-size: calc(var(--font-size-m) * 0.95);--code-font-weight: normal;--code-tab-size: 4;--code-block-border-radius: var(--border-radius-m);--code-block-line-height: var(--base-line-height);--code-block-margin: 1em 0;--code-block-padding: 1.75em 1.5em 1.5em 1.5em;--code-inline-background: var(--code-theme-background);--code-inline-border-radius: var(--border-radius-s);--code-inline-color: var(--code-theme-text);--code-inline-margin: 0 0.15em;--code-inline-padding: 0.125em 0.4em;--code-theme-background: var(--mono-tint3);--heading-color: var(--mono-shade3);--heading-margin: 2.5rem 0 0;--heading-h1-border-style: solid;--heading-h1-font-size: var(--font-size-xxl);--heading-h2-border-style: solid;--heading-h2-font-size: var(--font-size-xl);--heading-h3-border-style: solid;--heading-h3-font-size: var(--font-size-l);--heading-h4-border-style: solid;--heading-h4-font-size: var(--font-size-m);--heading-h5-border-style: solid;--heading-h5-font-size: var(--font-size-s);--heading-h6-border-style: solid;--heading-h6-font-size: var(--font-size-xs);--kbd-background: var(--mono-tint3);--kbd-border-radius: var(--border-radius-m);--kbd-margin: 0 0.3em;--kbd-min-width: 2.5em;--kbd-padding: 0.65em 0.5em;--link-text-decoration: underline;--notice-background: var(--mono-tint3);--notice-border-radius: var(--border-radius-m);--notice-border-style: solid;--notice-font-weight: normal;--notice-padding: 1em 1.5em;--notice-before-font-weight: normal;--table-cell-padding: 0.75em 0.5em;--table-head-border-color: var(--table-cell-border-color);--table-head-font-weight: var(--strong-font-weight);--table-row-odd-background: var(--mono-tint3)}:root{--cover-margin: 0 auto;--cover-max-width: 40em;--cover-text-align: center;--cover-background-color: var(--base-background-color);--cover-background-mask-color: var(--base-background-color);--cover-background-mask-opacity: 0.8;--cover-background-position: center center;--cover-background-repeat: no-repeat;--cover-background-size: cover;--cover-blockquote-font-size: var(--font-size-l);--cover-border-color: var(--theme-color);--cover-button-border: 1px solid var(--theme-color);--cover-button-border-radius: var(--border-radius-m);--cover-button-color: var(--theme-color);--cover-button-padding: 0.5em 2rem;--cover-button-text-decoration: none;--cover-button-transition: all var(--duration-fast) ease-in-out;--cover-button-primary-background: var(--theme-color);--cover-button-primary-border: 1px solid var(--theme-color);--cover-button-primary-color: #fff;--cover-heading-color: var(--theme-color);--cover-heading-font-size: var(--font-size-xxl);--cover-heading-font-weight: normal;--cover-link-text-decoration: underline}:root{--navbar-root-border-style: solid;--navbar-root-margin: 0 0 0 1.5em;--navbar-root-transition: all var(--duration-fast);--navbar-menu-background: var(--base-background-color);--navbar-menu-border-radius: var(--border-radius-m);--navbar-menu-box-shadow: rgba(45,45,45,0.05) 0px 0px 1px, rgba(49,49,49,0.05) 0px 1px 2px, rgba(42,42,42,0.05) 0px 2px 4px, rgba(32,32,32,0.05) 0px 4px 8px, rgba(49,49,49,0.05) 0px 8px 16px, rgba(35,35,35,0.05) 0px 16px 32px;--navbar-menu-padding: 0.5em;--navbar-menu-transition: all var(--duration-fast);--navbar-menu-link-border-style: solid;--navbar-menu-link-margin: 0.75em 0.5em;--navbar-menu-link-padding: 0.2em 0}:root{--copycode-background: #808080;--copycode-color: #fff}:root{--docsifytabs-border-color: var(--mono-tint2);--docsifytabs-border-radius-px: var(--border-radius-s);--docsifytabs-tab-background: var(--mono-tint3);--docsifytabs-tab-color: var(--mono-tint1)}:root{--pagination-border-top: 1px solid var(--mono-tint2);--pagination-chevron-height: 0.8em;--pagination-chevron-stroke: currentColor;--pagination-chevron-stroke-linecap: round;--pagination-chevron-stroke-width: 1px;--pagination-label-font-size: var(--font-size-s);--pagination-title-font-size: var(--font-size-l)}:root{--search-margin: 1.5rem 0 0;--search-input-background-repeat: no-repeat;--search-input-border-color: var(--mono-tint1);--search-input-border-width: 1px;--search-input-padding: 0.5em;--search-flex-order: 1;--search-result-heading-color: var(--heading-color);--search-result-heading-font-size: var(--base-font-size);--search-result-heading-font-weight: normal;--search-result-heading-margin: 0 0 0.25em;--search-result-item-border-color: var(--mono-tint2);--search-result-item-border-style: solid;--search-result-item-border-width: 0 0 1px 0;--search-result-item-font-weight: normal;--search-result-item-padding: 1em 0;--search-result-keyword-background: var(--mark-background);--search-result-keyword-border-radius: var(--border-radius-s);--search-result-keyword-color: var(--mark-color);--search-result-keyword-font-weight: normal;--search-result-keyword-margin: 0 0.1em;--search-result-keyword-padding: 0.2em 0}:root{--zoomimage-overlay-background: rgba(0, 0, 0, 0.875)}:root{--sidebar-background: var(--base-background-color);--sidebar-border-width: 0;--sidebar-padding: 0 25px;--sidebar-transition-duration: var(--duration-fast);--sidebar-width: 17rem;--sidebar-name-font-size: var(--font-size-l);--sidebar-name-font-weight: normal;--sidebar-name-margin: 1.5rem 0 0;--sidebar-name-text-align: center;--sidebar-nav-strong-border-color: var(--sidebar-border-color);--sidebar-nav-strong-color: var(--heading-color);--sidebar-nav-strong-font-weight: var(--strong-font-weight);--sidebar-nav-strong-margin: 1.5em 0 0.5em;--sidebar-nav-strong-padding: 0.25em 0;--sidebar-nav-indent: 1em;--sidebar-nav-margin: 1.5rem 0 0;--sidebar-nav-link-border-style: solid;--sidebar-nav-link-border-width: 0;--sidebar-nav-link-color: var(--base-color);--sidebar-nav-link-font-weight: normal;--sidebar-nav-link-padding: 0.25em 0;--sidebar-nav-link-text-decoration--active: underline;--sidebar-nav-link-text-decoration--hover: underline;--sidebar-nav-link-before-margin: 0 0.35em 0 0;--sidebar-nav-pagelink-transition: var(--sidebar-nav-link-transition);--sidebar-toggle-border-radius: var(--border-radius-s);--sidebar-toggle-border-style: solid;--sidebar-toggle-border-width: 0;--sidebar-toggle-height: 36px;--sidebar-toggle-icon-color: var(--base-color);--sidebar-toggle-icon-height: 10px;--sidebar-toggle-icon-stroke-width: 1px;--sidebar-toggle-icon-width: 16px;--sidebar-toggle-offset-left: 0;--sidebar-toggle-offset-top: calc(35px - (var(--sidebar-toggle-height) / 2));--sidebar-toggle-width: 44px}:root{--code-theme-background: #f3f3f3;--code-theme-comment: #6e8090;--code-theme-function: #dd4a68;--code-theme-keyword: #07a;--code-theme-operator: #a67f59;--code-theme-punctuation: #999;--code-theme-selector: #690;--code-theme-tag: #905;--code-theme-text: #333;--code-theme-variable: #e90}:root{--border-radius-s: 2px;--border-radius-m: 4px;--border-radius-l: 8px;--strong-font-weight: 600;--blockquote-border-color: var(--theme-color);--blockquote-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0;--blockquote-border-width: 0 0 0 4px;--code-inline-background: var(--mono-tint2);--code-theme-background: var(--mono-tint3);--heading-font-weight: var(--strong-font-weight);--heading-h1-font-weight: 400;--heading-h2-font-weight: 400;--heading-h2-border-color: var(--mono-tint2);--heading-h2-border-width: 0 0 1px 0;--heading-h2-margin: 2.5rem 0 1.5rem;--heading-h2-padding: 0 0 1rem 0;--kbd-border: 1px solid var(--mono-tint2);--notice-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0;--notice-border-width: 0 0 0 4px;--notice-padding: 1em 1.5em 1em 3em;--notice-before-border-radius: 100%;--notice-before-font-weight: bold;--notice-before-height: 1.5em;--notice-before-left: 0.75em;--notice-before-line-height: 1.5;--notice-before-margin: 0 0.25em 0 0;--notice-before-position: absolute;--notice-before-width: var(--notice-before-height);--notice-important-background: hsl(340, 60%, 96%);--notice-important-border-color: hsl(340, 90%, 45%);--notice-important-before-background: var(--notice-important-border-color) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3E%3Cpath d='M10 14C10 15.1 9.1 16 8 16 6.9 16 6 15.1 6 14 6 12.9 6.9 12 8 12 9.1 12 10 12.9 10 14Z'/%3E%3Cpath d='M10 1.6C10 1.2 9.8 0.9 9.6 0.7 9.2 0.3 8.6 0 8 0 7.4 0 6.8 0.2 6.5 0.6 6.2 0.9 6 1.2 6 1.6 6 1.7 6 1.8 6 1.9L6.8 9.6C6.9 9.9 7 10.1 7.2 10.2 7.4 10.4 7.7 10.5 8 10.5 8.3 10.5 8.6 10.4 8.8 10.3 9 10.1 9.1 9.9 9.2 9.6L10 1.9C10 1.8 10 1.7 10 1.6Z'/%3E%3C/svg%3E") center / 0.875em no-repeat;--notice-important-before-color: #fff;--notice-important-before-content: "";--notice-tip-background: hsl(204, 60%, 96%);--notice-tip-border-color: hsl(204, 90%, 45%);--notice-tip-before-background: var(--notice-tip-border-color) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3E%3Cpath d='M9.1 0C10.2 0 10.7 0.7 10.7 1.6 10.7 2.6 9.8 3.6 8.6 3.6 7.6 3.6 7 3 7 2 7 1.1 7.7 0 9.1 0Z'/%3E%3Cpath d='M5.8 16C5 16 4.4 15.5 5 13.2L5.9 9.1C6.1 8.5 6.1 8.2 5.9 8.2 5.7 8.2 4.6 8.6 3.9 9.1L3.5 8.4C5.6 6.6 7.9 5.6 8.9 5.6 9.8 5.6 9.9 6.6 9.5 8.2L8.4 12.5C8.2 13.2 8.3 13.5 8.5 13.5 8.7 13.5 9.6 13.2 10.4 12.5L10.9 13.2C8.9 15.2 6.7 16 5.8 16Z'/%3E%3C/svg%3E") center / 0.875em no-repeat;--notice-tip-before-color: #fff;--notice-tip-before-content: "";--table-cell-border-color: var(--mono-tint2);--table-cell-border-width: 1px 0;--cover-background-color: hsl(var(--theme-hue), 25%, 60%);--cover-background-image: radial-gradient(ellipse at center 115%, rgba(255, 255, 255, 0.9), transparent);--cover-blockquote-color: var(--strong-color);--cover-heading-color: #fff;--cover-heading-font-size-max: 56;--cover-heading-font-size-min: 34;--cover-heading-font-weight: 200;--navbar-root-color--active: var(--theme-color);--navbar-menu-border-radius: var(--border-radius-m);--navbar-menu-root-background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9.6' height='6' viewBox='0 0 9.6 6'%3E%3Cpath d='M1.5 1.5l3.3 3 3.3-3' stroke-width='1.5' stroke='rgb%28179, 179, 179%29' fill='none' stroke-linecap='square' stroke-linejoin='miter' vector-effect='non-scaling-stroke'/%3E%3C/svg%3E") right no-repeat;--navbar-menu-root-padding: 0 18px 0 0;--search-input-background-color: #fff;--search-input-background-image: url("data:image/svg+xml,%3Csvg height='20px' width='20px' viewBox='0 0 24 24' fill='none' stroke='rgba(0, 0, 0, 0.3)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10.5' cy='10.5' r='7.5' vector-effect='non-scaling-stroke'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='15.8' y2='15.8' vector-effect='non-scaling-stroke'%3E%3C/line%3E%3C/svg%3E");--search-input-background-position: 21px center;--search-input-border-color: var(--sidebar-border-color);--search-input-border-width: 1px 0;--search-input-margin: 0 -25px;--search-input-padding: 0.65em 1em 0.65em 50px;--search-input-placeholder-color: rgba(0, 0, 0, 0.4);--search-clear-icon-color1: rgba(0, 0, 0, 0.3);--search-result-heading-font-weight: var(--strong-font-weight);--search-result-item-border-color: var(--sidebar-border-color);--search-result-keyword-border-radius: var(--border-radius-s);--sidebar-background: var(--mono-tint3);--sidebar-border-color: var(--mono-tint2);--sidebar-border-width: 0 1px 0 0;--sidebar-name-color: var(--theme-color);--sidebar-name-font-weight: 300;--sidebar-nav-strong-border-width: 0 0 1px 0;--sidebar-nav-strong-font-size: smaller;--sidebar-nav-strong-margin: 2em -25px 0.75em 0;--sidebar-nav-strong-padding: 0.25em 0 0.75em 0;--sidebar-nav-strong-text-transform: uppercase;--sidebar-nav-link-border-color: transparent;--sidebar-nav-link-border-color--active: var(--theme-color);--sidebar-nav-link-border-width: 0 4px 0 0;--sidebar-nav-link-color--active: var(--theme-color);--sidebar-nav-link-margin: 0 -25px 0 0;--sidebar-nav-link-text-decoration: none;--sidebar-nav-link-text-decoration--active: none;--sidebar-nav-link-text-decoration--hover: underline;--sidebar-nav-pagelink-background: no-repeat 2px calc(50% - 2.5px) / 6px 5px linear-gradient(45deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4px), no-repeat 2px calc(50% + 2.5px) / 6px 5px linear-gradient(135deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4px);--sidebar-nav-pagelink-background--active: no-repeat 0px center / 5px 6px linear-gradient(225deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4.25px), no-repeat 5px center / 5px 6px linear-gradient(135deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4.25px);--sidebar-nav-pagelink-background--collapse: no-repeat 2px calc(50% - 2.5px) / 6px 5px linear-gradient(45deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4px), no-repeat 2px calc(50% + 2.5px) / 6px 5px linear-gradient(135deg, transparent 2.75px, var(--theme-color) 2.75px 4.25px, transparent 4px);--sidebar-nav-pagelink-background--loaded: no-repeat 0px center / 5px 6px linear-gradient(225deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4.25px), no-repeat 5px center / 5px 6px linear-gradient(135deg, transparent 2.75px, var(--mono-tint1) 2.75px 4.25px, transparent 4.25px);--sidebar-nav-pagelink-padding: 0.25em 0 0.25em 20px;--sidebar-nav-pagelink-transition: none;--sidebar-toggle-background: var(--sidebar-border-color);--sidebar-toggle-border-radius: 0 var(--border-radius-s) var(--border-radius-s) 0;--sidebar-toggle-width: 32px} +.github-corner { + position: absolute; + z-index: 40; + top: 0; + right: 0; + border-bottom: 0; + text-decoration: none; +} +.github-corner svg { + height: 70px; + width: 70px; + fill: var(--theme-color); + color: var(--base-background-color); +} +.github-corner:hover .octo-arm { + -webkit-animation: octocat-wave 560ms ease-in-out; + animation: octocat-wave 560ms ease-in-out; +} +@-webkit-keyframes octocat-wave { + 0%, + 100% { + transform: rotate(0); + } + 20%, + 60% { + transform: rotate(-25deg); + } + 40%, + 80% { + transform: rotate(10deg); + } +} +@keyframes octocat-wave { + 0%, + 100% { + transform: rotate(0); + } + 20%, + 60% { + transform: rotate(-25deg); + } + 40%, + 80% { + transform: rotate(10deg); + } +} +.progress { + position: fixed; + z-index: 2147483647; + top: 0; + left: 0; + right: 0; + height: 3px; + width: 0; + background-color: var(--theme-color); + transition: + width var(--duration-fast), + opacity calc(var(--duration-fast) * 2); +} +body.ready-transition:after, +body.ready-transition > *:not(.progress) { + opacity: 0; + transition: opacity var(--spinner-transition-duration); +} +body.ready-transition:after { + content: ''; + position: absolute; + z-index: 1000; + top: calc(50% - var(--spinner-size) / 2); + left: calc(50% - var(--spinner-size) / 2); + height: var(--spinner-size); + width: var(--spinner-size); + border: var(--spinner-track-width, 0) solid var(--spinner-track-color); + border-left-color: var(--theme-color); + border-left-color: var(--theme-color); + border-radius: 50%; + -webkit-animation: spinner var(--duration-slow) infinite linear; + animation: spinner var(--duration-slow) infinite linear; +} +body.ready-transition.ready-spinner:after { + opacity: 1; +} +body.ready-transition.ready-fix:after { + opacity: 0; +} +body.ready-transition.ready-fix > *:not(.progress) { + opacity: 1; + transition-delay: var(--spinner-transition-duration); +} +@-webkit-keyframes spinner { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +@keyframes spinner { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} +*, +*:before, +*:after { + box-sizing: inherit; + font-size: inherit; + -webkit-overflow-scrolling: touch; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); + -webkit-text-size-adjust: none; + -webkit-touch-callout: none; +} +:root { + box-sizing: border-box; + background-color: var(--base-background-color); + font-size: var(--base-font-size); + font-weight: var(--base-font-weight); + line-height: var(--base-line-height); + letter-spacing: var(--base-letter-spacing); + color: var(--base-color); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-smoothing: antialiased; +} +html, +button, +input, +optgroup, +select, +textarea { + font-family: var(--base-font-family); +} +button, +input, +optgroup, +select, +textarea { + font-size: 100%; + margin: 0; +} +a { + text-decoration: none; + -webkit-text-decoration-skip: ink; + text-decoration-skip-ink: auto; +} +body { + margin: 0; +} +hr { + height: 0; + margin: 2em 0; + border: none; + border-bottom: var(--hr-border, 0); +} +img { + max-width: 100%; + border: 0; +} +main { + display: block; +} +main.hidden { + display: none; +} +mark { + background: var(--mark-background); + color: var(--mark-color); +} +pre { + font-family: var(--pre-font-family); + font-size: var(--pre-font-size); + font-weight: var(--pre-font-weight); + line-height: var(--pre-line-height); +} +small { + display: inline-block; + font-size: var(--small-font-size); +} +strong { + font-weight: var(--strong-font-weight); + color: var(--strong-color, currentColor); +} +sub, +sup { + font-size: var(--subsup-font-size); + line-height: 0; + position: relative; + vertical-align: baseline; +} +sub { + bottom: -0.25em; +} +sup { + top: -0.5em; +} +body:not([data-platform^='Mac']) * { + scrollbar-color: hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3) + hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1); + scrollbar-width: thin; +} +body:not([data-platform^='Mac']) * ::-webkit-scrollbar { + width: 5px; + height: 5px; +} +body:not([data-platform^='Mac']) * ::-webkit-scrollbar-thumb { + background: hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.3); +} +body:not([data-platform^='Mac']) * ::-webkit-scrollbar-track { + background: hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1); +} +::-moz-selection { + background: var(--selection-color); +} +::selection { + background: var(--selection-color); +} +.emoji { + height: var(--emoji-size); + vertical-align: middle; +} +.task-list-item { + list-style: none; +} +.task-list-item input { + margin-right: 0.5em; + margin-left: 0; + vertical-align: 0.075em; +} +.markdown-section code[class*='lang-'], +.markdown-section pre[data-lang] { + font-family: var(--code-font-family); + font-size: var(--code-font-size); + font-weight: var(--code-font-weight); + letter-spacing: normal; + line-height: var(--code-block-line-height); + -moz-tab-size: var(--code-tab-size); + -o-tab-size: var(--code-tab-size); + tab-size: var(--code-tab-size); + text-align: left; + white-space: pre; + word-spacing: normal; + word-wrap: normal; + word-break: normal; + -webkit-hyphens: none; + hyphens: none; +} +.markdown-section pre[data-lang] { + position: relative; + overflow: hidden; + margin: var(--code-block-margin); + padding: 0; + border-radius: var(--code-block-border-radius); +} +.markdown-section pre[data-lang]::after { + content: attr(data-lang); + position: absolute; + top: 0.75em; + right: 0.75em; + opacity: 0.6; + color: inherit; + font-size: var(--font-size-s); + line-height: 1; +} +.markdown-section pre[data-lang] code { + display: block; + overflow: auto; + padding: var(--code-block-padding); +} +code[class*='lang-'], +pre[data-lang] { + color: var(--code-theme-text); +} +pre[data-lang]::-moz-selection, +pre[data-lang] ::-moz-selection, +code[class*='lang-']::-moz-selection, +code[class*='lang-'] ::-moz-selection { + background: var(--code-theme-selection, var(--selection-color)); +} +pre[data-lang]::-moz-selection, +pre[data-lang] ::-moz-selection, +code[class*='lang-']::-moz-selection, +code[class*='lang-'] ::-moz-selection { + background: var(--code-theme-selection, var(--selection-color)); +} +pre[data-lang]::selection, +pre[data-lang] ::selection, +code[class*='lang-']::selection, +code[class*='lang-'] ::selection { + background: var(--code-theme-selection, var(--selection-color)); +} +:not(pre) > code[class*='lang-'], +pre[data-lang] { + background: var(--code-theme-background); +} +.namespace { + opacity: 0.7; +} +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: var(--code-theme-comment); +} +.token.punctuation { + color: var(--code-theme-punctuation); +} +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: var(--code-theme-tag); +} +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: var(--code-theme-selector); +} +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: var(--code-theme-operator); +} +.token.atrule, +.token.attr-value, +.token.keyword { + color: var(--code-theme-keyword); +} +.token.function { + color: var(--code-theme-function); +} +.token.regex, +.token.important, +.token.variable { + color: var(--code-theme-variable); +} +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} +.token.entity { + cursor: help; +} +.markdown-section { + position: relative; + max-width: var(--content-max-width); + margin: 0 auto; + padding: 2rem 45px; +} +.app-nav:not(:empty) ~ main .markdown-section { + padding-top: 3.5rem; +} +.markdown-section figure, +.markdown-section p, +.markdown-section ol, +.markdown-section ul { + margin: 1em 0; +} +.markdown-section ol, +.markdown-section ul { + padding-left: 1.5rem; +} +.markdown-section ol ol, +.markdown-section ol ul, +.markdown-section ul ol, +.markdown-section ul ul { + margin-top: 0.15rem; + margin-bottom: 0.15rem; +} +.markdown-section a { + border-bottom: var(--link-border-bottom); + color: var(--link-color); + -webkit-text-decoration: var(--link-text-decoration); + text-decoration: var(--link-text-decoration); + -webkit-text-decoration-color: var(--link-text-decoration-color); + text-decoration-color: var(--link-text-decoration-color); +} +.markdown-section a:hover { + border-bottom: var(--link-border-bottom--hover, var(--link-border-bottom, 0)); + color: var(--link-color--hover, var(--link-color)); + -webkit-text-decoration: var( + --link-text-decoration--hover, + var(--link-text-decoration) + ); + text-decoration: var(--link-text-decoration--hover, var(--link-text-decoration)); + -webkit-text-decoration-color: var( + --link-text-decoration-color--hover, + var(--link-text-decoration-color) + ); + text-decoration-color: var( + --link-text-decoration-color--hover, + var(--link-text-decoration-color) + ); +} +.markdown-section a.anchor { + border-bottom: 0; + color: inherit; + text-decoration: none; +} +.markdown-section a.anchor:hover { + text-decoration: underline; +} +.markdown-section blockquote { + overflow: visible; + margin: 2em 0; + padding: var(--blockquote-padding); + border-width: var(--blockquote-border-width, 0); + border-style: var(--blockquote-border-style); + border-color: var(--blockquote-border-color); + border-radius: var(--blockquote-border-radius); + background: var(--blockquote-background); + color: var(--blockquote-color); + font-family: var(--blockquote-font-family); + font-size: var(--blockquote-font-size); + font-style: var(--blockquote-font-style); + font-weight: var(--blockquote-font-weight); + quotes: '“' '”' '‘' '’'; +} +.markdown-section blockquote em { + font-family: var(--blockquote-em-font-family); + font-size: var(--blockquote-em-font-size); + font-style: var(--blockquote-em-font-style); + font-weight: var(--blockquote-em-font-weight); +} +.markdown-section blockquote p:first-child { + margin-top: 0; +} +.markdown-section blockquote p:first-child:before, +.markdown-section blockquote p:first-child:after { + color: var(--blockquote-quotes-color); + font-family: var(--blockquote-quotes-font-family); + font-size: var(--blockquote-quotes-font-size); + line-height: 0; +} +.markdown-section blockquote p:first-child:before { + content: var(--blockquote-quotes-open); + margin-right: 0.15em; + vertical-align: -0.45em; +} +.markdown-section blockquote p:first-child:after { + content: var(--blockquote-quotes-close); + margin-left: 0.15em; + vertical-align: -0.55em; +} +.markdown-section blockquote p:last-child { + margin-bottom: 0; +} +.markdown-section code { + font-family: var(--code-font-family); + font-size: var(--code-font-size); + font-weight: var(--code-font-weight); + line-height: inherit; +} +.markdown-section code:not([class*='lang-']):not([class*='language-']) { + margin: var(--code-inline-margin); + padding: var(--code-inline-padding); + border-radius: var(--code-inline-border-radius); + background: var(--code-inline-background); + color: var(--code-inline-color, currentColor); + white-space: nowrap; +} +.markdown-section h1:first-child, +.markdown-section h2:first-child, +.markdown-section h3:first-child, +.markdown-section h4:first-child, +.markdown-section h5:first-child, +.markdown-section h6:first-child { + margin-top: 0; +} +.markdown-section h1 a[data-id], +.markdown-section h2 a[data-id], +.markdown-section h3 a[data-id], +.markdown-section h4 a[data-id], +.markdown-section h5 a[data-id], +.markdown-section h6 a[data-id] { + display: inline-block; +} +.markdown-section h1 code, +.markdown-section h2 code, +.markdown-section h3 code, +.markdown-section h4 code, +.markdown-section h5 code, +.markdown-section h6 code { + font-size: 0.875em; +} +.markdown-section h1 + h2, +.markdown-section h1 + h3, +.markdown-section h1 + h4, +.markdown-section h1 + h5, +.markdown-section h1 + h6, +.markdown-section h2 + h3, +.markdown-section h2 + h4, +.markdown-section h2 + h5, +.markdown-section h2 + h6, +.markdown-section h3 + h4, +.markdown-section h3 + h5, +.markdown-section h3 + h6, +.markdown-section h4 + h5, +.markdown-section h4 + h6, +.markdown-section h5 + h6 { + margin-top: 1rem; +} +.markdown-section h1 { + margin: var(--heading-h1-margin, var(--heading-margin)); + padding: var(--heading-h1-padding, var(--heading-padding)); + border-width: var(--heading-h1-border-width, 0); + border-style: var(--heading-h1-border-style); + border-color: var(--heading-h1-border-color); + font-family: var(--heading-h1-font-family, var(--heading-font-family)); + font-size: var(--heading-h1-font-size); + font-weight: var(--heading-h1-font-weight, var(--heading-font-weight)); + line-height: var(--base-line-height); + color: var(--heading-h1-color, var(--heading-color)); +} +.markdown-section h2 { + margin: var(--heading-h2-margin, var(--heading-margin)); + padding: var(--heading-h2-padding, var(--heading-padding)); + border-width: var(--heading-h2-border-width, 0); + border-style: var(--heading-h2-border-style); + border-color: var(--heading-h2-border-color); + font-family: var(--heading-h2-font-family, var(--heading-font-family)); + font-size: var(--heading-h2-font-size); + font-weight: var(--heading-h2-font-weight, var(--heading-font-weight)); + line-height: var(--base-line-height); + color: var(--heading-h2-color, var(--heading-color)); +} +.markdown-section h3 { + margin: var(--heading-h3-margin, var(--heading-margin)); + padding: var(--heading-h3-padding, var(--heading-padding)); + border-width: var(--heading-h3-border-width, 0); + border-style: var(--heading-h3-border-style); + border-color: var(--heading-h3-border-color); + font-family: var(--heading-h3-font-family, var(--heading-font-family)); + font-size: var(--heading-h3-font-size); + font-weight: var(--heading-h3-font-weight, var(--heading-font-weight)); + color: var(--heading-h3-color, var(--heading-color)); +} +.markdown-section h4 { + margin: var(--heading-h4-margin, var(--heading-margin)); + padding: var(--heading-h4-padding, var(--heading-padding)); + border-width: var(--heading-h4-border-width, 0); + border-style: var(--heading-h4-border-style); + border-color: var(--heading-h4-border-color); + font-family: var(--heading-h4-font-family, var(--heading-font-family)); + font-size: var(--heading-h4-font-size); + font-weight: var(--heading-h4-font-weight, var(--heading-font-weight)); + color: var(--heading-h4-color, var(--heading-color)); +} +.markdown-section h5 { + margin: var(--heading-h5-margin, var(--heading-margin)); + padding: var(--heading-h5-padding, var(--heading-padding)); + border-width: var(--heading-h5-border-width, 0); + border-style: var(--heading-h5-border-style); + border-color: var(--heading-h5-border-color); + font-family: var(--heading-h5-font-family, var(--heading-font-family)); + font-size: var(--heading-h5-font-size); + font-weight: var(--heading-h5-font-weight, var(--heading-font-weight)); + color: var(--heading-h5-color, var(--heading-color)); +} +.markdown-section h6 { + margin: var(--heading-h6-margin, var(--heading-margin)); + padding: var(--heading-h6-padding, var(--heading-padding)); + border-width: var(--heading-h6-border-width, 0); + border-style: var(--heading-h6-border-style); + border-color: var(--heading-h6-border-color); + font-family: var(--heading-h6-font-family, var(--heading-font-family)); + font-size: var(--heading-h6-font-size); + font-weight: var(--heading-h6-font-weight, var(--heading-font-weight)); + color: var(--heading-h6-color, var(--heading-color)); +} +.markdown-section iframe { + margin: 1em 0; +} +.markdown-section img { + max-width: 100%; +} +.markdown-section kbd { + display: inline-block; + min-width: var(--kbd-min-width); + margin: var(--kbd-margin); + padding: var(--kbd-padding); + border: var(--kbd-border); + border-radius: var(--kbd-border-radius); + background: var(--kbd-background); + font-family: inherit; + font-size: var(--kbd-font-size); + text-align: center; + letter-spacing: 0; + line-height: 1; + color: var(--kbd-color); +} +.markdown-section kbd + kbd { + margin-left: -0.15em; +} +.markdown-section table { + display: block; + overflow: auto; + margin: 1rem 0; + border-spacing: 0; + border-collapse: collapse; +} +.markdown-section th, +.markdown-section td { + padding: var(--table-cell-padding); +} +.markdown-section th:not([align]) { + text-align: left; +} +.markdown-section thead { + border-color: var(--table-head-border-color); + border-style: solid; + border-width: var(--table-head-border-width, 0); + background: var(--table-head-background); +} +.markdown-section th { + font-weight: var(--table-head-font-weight); + color: var(--strong-color); +} +.markdown-section td { + border-color: var(--table-cell-border-color); + border-style: solid; + border-width: var(--table-cell-border-width, 0); +} +.markdown-section tbody { + border-color: var(--table-body-border-color); + border-style: solid; + border-width: var(--table-body-border-width, 0); +} +.markdown-section tbody tr:nth-child(odd) { + background: var(--table-row-odd-background); +} +.markdown-section tbody tr:nth-child(even) { + background: var(--table-row-even-background); +} +.markdown-section > ul .task-list-item { + margin-left: -1.25em; +} +.markdown-section > ul .task-list-item .task-list-item { + margin-left: 0; +} +.markdown-section .table-wrapper { + overflow-x: auto; +} +.markdown-section .table-wrapper table { + display: table; + width: 100%; +} +.markdown-section .table-wrapper td::before { + display: none; +} +@media (max-width: 30em) { + .markdown-section .table-wrapper tbody, + .markdown-section .table-wrapper tr, + .markdown-section .table-wrapper td { + display: block; + } + .markdown-section .table-wrapper th, + .markdown-section .table-wrapper td { + border: none; + } + .markdown-section .table-wrapper thead { + display: none; + } + .markdown-section .table-wrapper tr { + border-color: var(--table-cell-border-color); + border-style: solid; + border-width: var(--table-cell-border-width, 0); + padding: var(--table-cell-padding); + } + .markdown-section .table-wrapper tr:not(:last-child) { + border-bottom: 0; + } + .markdown-section .table-wrapper td { + padding: 0.15em 0 0.15em 8em; + } + .markdown-section .table-wrapper td::before { + display: inline-block; + float: left; + width: 8em; + margin-left: -8em; + font-weight: bold; + text-align: left; + } +} +.markdown-section .tip, +.markdown-section .warn { + position: relative; + margin: 2em 0; + padding: var(--notice-padding); + border-width: var(--notice-border-width, 0); + border-style: var(--notice-border-style); + border-color: var(--notice-border-color); + border-radius: var(--notice-border-radius); + background: var(--notice-background); + font-family: var(--notice-font-family); + font-weight: var(--notice-font-weight); + color: var(--notice-color); +} +.markdown-section .tip:before, +.markdown-section .warn:before { + display: inline-block; + position: var(--notice-before-position, relative); + top: var(--notice-before-top); + left: var(--notice-before-left); + height: var(--notice-before-height); + width: var(--notice-before-width); + margin: var(--notice-before-margin); + padding: var(--notice-before-padding); + border-radius: var(--notice-before-border-radius); + line-height: var(--notice-before-line-height); + font-family: var(--notice-before-font-family); + font-size: var(--notice-before-font-size); + font-weight: var(--notice-before-font-weight); + text-align: center; +} +.markdown-section .tip { + border-width: var(--notice-important-border-width, var(--notice-border-width, 0)); + border-style: var(--notice-important-border-style, var(--notice-border-style)); + border-color: var(--notice-important-border-color, var(--notice-border-color)); + background: var(--notice-important-background, var(--notice-background)); + color: var(--notice-important-color, var(--notice-color)); +} +.markdown-section .tip:before { + content: var(--notice-important-before-content, var(--notice-before-content)); + background: var(--notice-important-before-background, var(--notice-before-background)); + color: var(--notice-important-before-color, var(--notice-before-color)); +} +.markdown-section .warn { + border-width: var(--notice-tip-border-width, var(--notice-border-width, 0)); + border-style: var(--notice-tip-border-style, var(--notice-border-style)); + border-color: var(--notice-tip-border-color, var(--notice-border-color)); + background: var(--notice-tip-background, var(--notice-background)); + color: var(--notice-tip-color, var(--notice-color)); +} +.markdown-section .warn:before { + content: var(--notice-tip-before-content, var(--notice-before-content)); + background: var(--notice-tip-before-background, var(--notice-before-background)); + color: var(--notice-tip-before-color, var(--notice-before-color)); +} +.cover { + display: none; + position: relative; + z-index: 20; + min-height: 100vh; + flex-direction: column; + align-items: center; + justify-content: center; + padding: calc(var(--cover-border-inset, 0px) + var(--cover-border-width, 0px)); + color: var(--cover-color); + text-align: var(--cover-text-align); +} +@media screen and (-ms-high-contrast: active), screen and (-ms-high-contrast: none) { + .cover { + height: 100vh; + } +} +.cover:before, +.cover:after { + content: ''; + position: absolute; +} +.cover:before { + top: 0; + bottom: 0; + left: 0; + right: 0; + background-blend-mode: var(--cover-background-blend-mode); + background-color: var(--cover-background-color); + background-image: var(--cover-background-image); + background-position: var(--cover-background-position); + background-repeat: var(--cover-background-repeat); + background-size: var(--cover-background-size); +} +.cover:after { + top: var(--cover-border-inset, 0); + bottom: var(--cover-border-inset, 0); + left: var(--cover-border-inset, 0); + right: var(--cover-border-inset, 0); + border-width: var(--cover-border-width, 0); + border-style: solid; + border-color: var(--cover-border-color); +} +.cover a { + border-bottom: var(--cover-link-border-bottom); + color: var(--cover-link-color); + -webkit-text-decoration: var(--cover-link-text-decoration); + text-decoration: var(--cover-link-text-decoration); + -webkit-text-decoration-color: var(--cover-link-text-decoration-color); + text-decoration-color: var(--cover-link-text-decoration-color); +} +.cover a:hover { + border-bottom: var(--cover-link-border-bottom--hover, var(--cover-link-border-bottom)); + color: var(--cover-link-color--hover, var(--cover-link-color)); + -webkit-text-decoration: var( + --cover-link-text-decoration--hover, + var(--cover-link-text-decoration) + ); + text-decoration: var( + --cover-link-text-decoration--hover, + var(--cover-link-text-decoration) + ); + -webkit-text-decoration-color: var( + --cover-link-text-decoration-color--hover, + var(--cover-link-text-decoration-color) + ); + text-decoration-color: var( + --cover-link-text-decoration-color--hover, + var(--cover-link-text-decoration-color) + ); +} +.cover h1 { + color: var(--cover-heading-color); + position: relative; + margin: 0; + font-size: var(--cover-heading-font-size); + font-weight: var(--cover-heading-font-weight); + line-height: 1.2; +} +.cover h1 a, +.cover h1 a:hover { + display: block; + border-bottom: none; + color: inherit; + text-decoration: none; +} +.cover h1 small { + position: absolute; + bottom: 0; + margin-left: 0.5em; +} +.cover h1 span { + font-size: calc(var(--cover-heading-font-size-min) * 1px); +} +@media (min-width: 26em) { + .cover h1 span { + font-size: calc( + var(--cover-heading-font-size-min) * 1px + + (var(--cover-heading-font-size-max) - var(--cover-heading-font-size-min)) * + (100vw - 420px) / 604 + ); + } +} +@media (min-width: 64em) { + .cover h1 span { + font-size: calc(var(--cover-heading-font-size-max) * 1px); + } +} +.cover blockquote { + margin: 0; + color: var(--cover-blockquote-color); + font-size: var(--cover-blockquote-font-size); +} +.cover blockquote a { + color: inherit; +} +.cover ul { + padding: 0; + list-style-type: none; +} +.cover .cover-main { + position: relative; + z-index: 1; + max-width: var(--cover-max-width); + margin: var(--cover-margin); + padding: 0 45px; +} +.cover .cover-main > p:last-child { + margin: 1.25em -0.25em; +} +.cover .cover-main > p:last-child a { + display: block; + margin: 0.375em 0.25em; + padding: var(--cover-button-padding); + border: var(--cover-button-border); + border-radius: var(--cover-button-border-radius); + box-shadow: var(--cover-button-box-shadow); + background: var(--cover-button-background); + text-align: center; + -webkit-text-decoration: var(--cover-button-text-decoration); + text-decoration: var(--cover-button-text-decoration); + -webkit-text-decoration-color: var(--cover-button-text-decoration-color); + text-decoration-color: var(--cover-button-text-decoration-color); + color: var(--cover-button-color); + white-space: nowrap; + transition: var(--cover-button-transition); +} +.cover .cover-main > p:last-child a:hover { + border: var(--cover-button-border--hover, var(--cover-button-border)); + box-shadow: var(--cover-button-box-shadow--hover, var(--cover-button-box-shadow)); + background: var(--cover-button-background--hover, var(--cover-button-background)); + -webkit-text-decoration: var( + --cover-button-text-decoration--hover, + var(--cover-button-text-decoration) + ); + text-decoration: var( + --cover-button-text-decoration--hover, + var(--cover-button-text-decoration) + ); + -webkit-text-decoration-color: var( + --cover-button-text-decoration-color--hover, + var(--cover-button-text-decoration-color) + ); + text-decoration-color: var( + --cover-button-text-decoration-color--hover, + var(--cover-button-text-decoration-color) + ); + color: var(--cover-button-color--hover, var(--cover-button-color)); +} +.cover .cover-main > p:last-child a:first-child { + border: var(--cover-button-primary-border, var(--cover-button-border)); + box-shadow: var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow)); + background: var(--cover-button-primary-background, var(--cover-button-background)); + -webkit-text-decoration: var( + --cover-button-primary-text-decoration, + var(--cover-button-text-decoration) + ); + text-decoration: var( + --cover-button-primary-text-decoration, + var(--cover-button-text-decoration) + ); + -webkit-text-decoration-color: var( + --cover-button-primary-text-decoration-color, + var(--cover-button-text-decoration-color) + ); + text-decoration-color: var( + --cover-button-primary-text-decoration-color, + var(--cover-button-text-decoration-color) + ); + color: var(--cover-button-primary-color, var(--cover-button-color)); +} +.cover .cover-main > p:last-child a:first-child:hover { + border: var( + --cover-button-primary-border--hover, + var( + --cover-button-border--hover, + var(--cover-button-primary-border, var(--cover-button-border)) + ) + ); + box-shadow: var( + --cover-button-primary-box-shadow--hover, + var( + --cover-button-box-shadow--hover, + var(--cover-button-primary-box-shadow, var(--cover-button-box-shadow)) + ) + ); + background: var( + --cover-button-primary-background--hover, + var( + --cover-button-background--hover, + var(--cover-button-primary-background, var(--cover-button-background)) + ) + ); + -webkit-text-decoration: var( + --cover-button-primary-text-decoration--hover, + var( + --cover-button-text-decoration--hover, + var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration)) + ) + ); + text-decoration: var( + --cover-button-primary-text-decoration--hover, + var( + --cover-button-text-decoration--hover, + var(--cover-button-primary-text-decoration, var(--cover-button-text-decoration)) + ) + ); + -webkit-text-decoration-color: var( + --cover-button-primary-text-decoration-color--hover, + var( + --cover-button-text-decoration-color--hover, + var( + --cover-button-primary-text-decoration-color, + var(--cover-button-text-decoration-color) + ) + ) + ); + text-decoration-color: var( + --cover-button-primary-text-decoration-color--hover, + var( + --cover-button-text-decoration-color--hover, + var( + --cover-button-primary-text-decoration-color, + var(--cover-button-text-decoration-color) + ) + ) + ); + color: var( + --cover-button-primary-color--hover, + var( + --cover-button-color--hover, + var(--cover-button-primary-color, var(--cover-button-color)) + ) + ); +} +@media (min-width: 30.01em) { + .cover .cover-main > p:last-child a { + display: inline-block; + } +} +.cover .mask { + visibility: var(--cover-background-mask-visibility, hidden); + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + background-color: var(--cover-background-mask-color); + opacity: var(--cover-background-mask-opacity); +} +.cover.has-mask .mask { + visibility: visible; +} +.cover.show { + display: flex; +} +.app-nav { + position: absolute; + z-index: 30; + top: calc(35px - 0.5em * var(--base-line-height)); + left: 45px; + right: 80px; + text-align: right; +} +.app-nav.no-badge { + right: 45px; +} +.app-nav li > img, +.app-nav li > a > img { + margin-top: -0.25em; + vertical-align: middle; +} +.app-nav li > img:first-child, +.app-nav li > a > img:first-child { + margin-right: 0.5em; +} +.app-nav ul, +.app-nav li { + margin: 0; + padding: 0; + list-style: none; +} +.app-nav li { + position: relative; +} +.app-nav li a { + display: block; + line-height: 1; + transition: var(--navbar-root-transition); +} +.app-nav > ul > li { + display: inline-block; + margin: var(--navbar-root-margin); +} +.app-nav > ul > li:first-child { + margin-left: 0; +} +.app-nav > ul > li:last-child { + margin-right: 0; +} +.app-nav > ul > li > a, +.app-nav > ul > li > span { + padding: var(--navbar-root-padding); + border-width: var(--navbar-root-border-width, 0); + border-style: var(--navbar-root-border-style); + border-color: var(--navbar-root-border-color); + border-radius: var(--navbar-root-border-radius); + background: var(--navbar-root-background); + color: var(--navbar-root-color); + -webkit-text-decoration: var(--navbar-root-text-decoration); + text-decoration: var(--navbar-root-text-decoration); + -webkit-text-decoration-color: var(--navbar-root-text-decoration-color); + text-decoration-color: var(--navbar-root-text-decoration-color); +} +.app-nav > ul > li > a:hover, +.app-nav > ul > li > span:hover { + background: var(--navbar-root-background--hover, var(--navbar-root-background)); + border-style: var(--navbar-root-border-style--hover, var(--navbar-root-border-style)); + border-color: var(--navbar-root-border-color--hover, var(--navbar-root-border-color)); + color: var(--navbar-root-color--hover, var(--navbar-root-color)); + -webkit-text-decoration: var( + --navbar-root-text-decoration--hover, + var(--navbar-root-text-decoration) + ); + text-decoration: var( + --navbar-root-text-decoration--hover, + var(--navbar-root-text-decoration) + ); + -webkit-text-decoration-color: var( + --navbar-root-text-decoration-color--hover, + var(--navbar-root-text-decoration-color) + ); + text-decoration-color: var( + --navbar-root-text-decoration-color--hover, + var(--navbar-root-text-decoration-color) + ); +} +.app-nav > ul > li > a:not(:last-child), +.app-nav > ul > li > span:not(:last-child) { + padding: var(--navbar-menu-root-padding, var(--navbar-root-padding)); + background: var(--navbar-menu-root-background, var(--navbar-root-background)); +} +.app-nav > ul > li > a:not(:last-child):hover, +.app-nav > ul > li > span:not(:last-child):hover { + background: var( + --navbar-menu-root-background--hover, + var( + --navbar-menu-root-background, + var(--navbar-root-background--hover, var(--navbar-root-background)) + ) + ); +} +.app-nav > ul > li > a.active { + background: var(--navbar-root-background--active, var(--navbar-root-background)); + border-style: var(--navbar-root-border-style--active, var(--navbar-root-border-style)); + border-color: var(--navbar-root-border-color--active, var(--navbar-root-border-color)); + color: var(--navbar-root-color--active, var(--navbar-root-color)); + -webkit-text-decoration: var( + --navbar-root-text-decoration--active, + var(--navbar-root-text-decoration) + ); + text-decoration: var( + --navbar-root-text-decoration--active, + var(--navbar-root-text-decoration) + ); + -webkit-text-decoration-color: var( + --navbar-root-text-decoration-color--active, + var(--navbar-root-text-decoration-color) + ); + text-decoration-color: var( + --navbar-root-text-decoration-color--active, + var(--navbar-root-text-decoration-color) + ); +} +.app-nav > ul > li > a.active:not(:last-child):hover { + background: var( + --navbar-menu-root-background--active, + var( + --navbar-menu-root-background, + var(--navbar-root-background--active, var(--navbar-root-background)) + ) + ); +} +.app-nav > ul > li ul { + visibility: hidden; + position: absolute; + top: 100%; + right: 50%; + overflow-y: auto; + box-sizing: border-box; + max-height: 50vh; + padding: var(--navbar-menu-padding); + border-width: var(--navbar-menu-border-width, 0); + border-style: solid; + border-color: var(--navbar-menu-border-color); + border-radius: var(--navbar-menu-border-radius); + background: var(--navbar-menu-background); + box-shadow: var(--navbar-menu-box-shadow); + text-align: left; + white-space: nowrap; + opacity: 0; + transform: translate(50%, -0.35em); + transition: var(--navbar-menu-transition); +} +.app-nav > ul > li ul li { + white-space: nowrap; +} +.app-nav > ul > li ul a { + margin: var(--navbar-menu-link-margin); + padding: var(--navbar-menu-link-padding); + border-width: var(--navbar-menu-link-border-width, 0); + border-style: var(--navbar-menu-link-border-style); + border-color: var(--navbar-menu-link-border-color); + border-radius: var(--navbar-menu-link-border-radius); + background: var(--navbar-menu-link-background); + color: var(--navbar-menu-link-color); + -webkit-text-decoration: var(--navbar-menu-link-text-decoration); + text-decoration: var(--navbar-menu-link-text-decoration); + -webkit-text-decoration-color: var(--navbar-menu-link-text-decoration-color); + text-decoration-color: var(--navbar-menu-link-text-decoration-color); +} +.app-nav > ul > li ul a:hover { + background: var( + --navbar-menu-link-background--hover, + var(--navbar-menu-link-background) + ); + border-style: var( + --navbar-menu-link-border-style--hover, + var(--navbar-menu-link-border-style) + ); + border-color: var( + --navbar-menu-link-border-color--hover, + var(--navbar-menu-link-border-color) + ); + color: var(--navbar-menu-link-color--hover, var(--navbar-menu-link-color)); + -webkit-text-decoration: var( + --navbar-menu-link-text-decoration--hover, + var(--navbar-menu-link-text-decoration) + ); + text-decoration: var( + --navbar-menu-link-text-decoration--hover, + var(--navbar-menu-link-text-decoration) + ); + -webkit-text-decoration-color: var( + --navbar-menu-link-text-decoration-color--hover, + var(--navbar-menu-link-text-decoration-color) + ); + text-decoration-color: var( + --navbar-menu-link-text-decoration-color--hover, + var(--navbar-menu-link-text-decoration-color) + ); +} +.app-nav > ul > li ul a.active { + background: var( + --navbar-menu-link-background--active, + var(--navbar-menu-link-background) + ); + border-style: var( + --navbar-menu-link-border-style--active, + var(--navbar-menu-link-border-style) + ); + border-color: var( + --navbar-menu-link-border-color--active, + var(--navbar-menu-link-border-color) + ); + color: var(--navbar-menu-link-color--active, var(--navbar-menu-link-color)); + -webkit-text-decoration: var( + --navbar-menu-link-text-decoration--active, + var(--navbar-menu-link-text-decoration) + ); + text-decoration: var( + --navbar-menu-link-text-decoration--active, + var(--navbar-menu-link-text-decoration) + ); + -webkit-text-decoration-color: var( + --navbar-menu-link-text-decoration-color--active, + var(--navbar-menu-link-text-decoration-color) + ); + text-decoration-color: var( + --navbar-menu-link-text-decoration-color--active, + var(--navbar-menu-link-text-decoration-color) + ); +} +.app-nav > ul > li:hover ul, +.app-nav > ul > li:focus ul, +.app-nav > ul > li.focus-within ul { + visibility: visible; + opacity: 1; + transform: translate(50%, 0); +} +@media (min-width: 48em) { + nav.app-nav { + margin-left: var(--sidebar-width); + } +} +main { + position: relative; + overflow-x: hidden; + min-height: 100vh; +} +.sidebar, +.sidebar-toggle, +.sidebar + .content { + transition: all var(--sidebar-transition-duration) ease-out; +} +@media (min-width: 48em) { + .sidebar + .content { + margin-left: var(--sidebar-width); + } +} +.sidebar { + display: flex; + flex-direction: column; + position: fixed; + z-index: 10; + top: 0; + right: 100%; + overflow-x: hidden; + overflow-y: auto; + height: 100vh; + width: var(--sidebar-width); + padding: var(--sidebar-padding); + border-width: var(--sidebar-border-width); + border-style: solid; + border-color: var(--sidebar-border-color); + background: var(--sidebar-background); +} +.sidebar > h1 { + margin: 0; + margin: var(--sidebar-name-margin); + padding: var(--sidebar-name-padding); + background: var(--sidebar-name-background); + color: var(--sidebar-name-color); + font-family: var(--sidebar-name-font-family); + font-size: var(--sidebar-name-font-size); + font-weight: var(--sidebar-name-font-weight); + text-align: var(--sidebar-name-text-align); +} +.sidebar > h1 img { + max-width: 100%; +} +.sidebar > h1 .app-name-link { + color: var(--sidebar-name-color); +} +body:not([data-platform^='Mac']) .sidebar::-webkit-scrollbar { + width: 5px; +} +body:not([data-platform^='Mac']) .sidebar::-webkit-scrollbar-thumb { + border-radius: 50vw; +} +@media (min-width: 48em) { + .sidebar { + position: absolute; + transform: translateX(var(--sidebar-width)); + } +} +@media print { + .sidebar { + display: none; + } +} +.sidebar-nav, +.sidebar nav { + order: 1; + margin: var(--sidebar-nav-margin); + padding: var(--sidebar-nav-padding); + background: var(--sidebar-nav-background); +} +.sidebar-nav ul, +.sidebar nav ul { + margin: 0; + padding: 0; + list-style: none; +} +.sidebar-nav ul ul, +.sidebar nav ul ul { + margin-left: var(--sidebar-nav-indent); +} +.sidebar-nav a, +.sidebar nav a { + display: block; + overflow: hidden; + margin: var(--sidebar-nav-link-margin); + padding: var(--sidebar-nav-link-padding); + border-width: var(--sidebar-nav-link-border-width, 0); + border-style: var(--sidebar-nav-link-border-style); + border-color: var(--sidebar-nav-link-border-color); + border-radius: var(--sidebar-nav-link-border-radius); + background: var(--sidebar-nav-link-background); + color: var(--sidebar-nav-link-color); + font-weight: var(--sidebar-nav-link-font-weight); + white-space: nowrap; + -webkit-text-decoration: var(--sidebar-nav-link-text-decoration); + text-decoration: var(--sidebar-nav-link-text-decoration); + -webkit-text-decoration-color: var(--sidebar-nav-link-text-decoration-color); + text-decoration-color: var(--sidebar-nav-link-text-decoration-color); + text-overflow: ellipsis; + transition: var(--sidebar-nav-link-transition); +} +.sidebar-nav a img, +.sidebar nav a img { + margin-top: -0.25em; + vertical-align: middle; +} +.sidebar-nav a img:first-child, +.sidebar nav a img:first-child { + margin-right: 0.5em; +} +.sidebar-nav a:hover, +.sidebar nav a:hover { + border-width: var( + --sidebar-nav-link-border-width--hover, + var(--sidebar-nav-link-border-width, 0) + ); + border-style: var( + --sidebar-nav-link-border-style--hover, + var(--sidebar-nav-link-border-style) + ); + border-color: var( + --sidebar-nav-link-border-color--hover, + var(--sidebar-nav-link-border-color) + ); + background: var( + --sidebar-nav-link-background--hover, + var(--sidebar-nav-link-background) + ); + color: var(--sidebar-nav-link-color--hover, var(--sidebar-nav-link-color)); + font-weight: var( + --sidebar-nav-link-font-weight--hover, + var(--sidebar-nav-link-font-weight) + ); + -webkit-text-decoration: var( + --sidebar-nav-link-text-decoration--hover, + var(--sidebar-nav-link-text-decoration) + ); + text-decoration: var( + --sidebar-nav-link-text-decoration--hover, + var(--sidebar-nav-link-text-decoration) + ); + -webkit-text-decoration-color: var(--sidebar-nav-link-text-decoration-color); + text-decoration-color: var(--sidebar-nav-link-text-decoration-color); +} +.sidebar-nav ul > li > span, +.sidebar-nav ul > li > strong, +.sidebar nav ul > li > span, +.sidebar nav ul > li > strong { + display: block; + margin: var(--sidebar-nav-strong-margin); + padding: var(--sidebar-nav-strong-padding); + border-width: var(--sidebar-nav-strong-border-width, 0); + border-style: solid; + border-color: var(--sidebar-nav-strong-border-color); + color: var(--sidebar-nav-strong-color); + font-size: var(--sidebar-nav-strong-font-size); + font-weight: var(--sidebar-nav-strong-font-weight); + text-transform: var(--sidebar-nav-strong-text-transform); +} +.sidebar-nav ul > li > span + ul, +.sidebar-nav ul > li > strong + ul, +.sidebar nav ul > li > span + ul, +.sidebar nav ul > li > strong + ul { + margin-left: 0; +} +.sidebar-nav ul > li:first-child > span, +.sidebar-nav ul > li:first-child > strong, +.sidebar nav ul > li:first-child > span, +.sidebar nav ul > li:first-child > strong { + margin-top: 0; +} +.sidebar-nav::-webkit-scrollbar, +.sidebar nav::-webkit-scrollbar { + width: 0; +} +@supports (width: env(safe-area-inset)) { + @media only screen and (orientation: landscape) { + .sidebar-nav, + .sidebar nav { + margin-left: calc(env(safe-area-inset-left) / 2); + } + } +} +.sidebar-nav li > a:before, +.sidebar-nav li > strong:before { + display: inline-block; +} +.sidebar-nav li > a { + background-repeat: var(--sidebar-nav-pagelink-background-repeat); + background-size: var(--sidebar-nav-pagelink-background-size); +} +.sidebar-nav li > a[href^='/']:not([href*='?id=']), +.sidebar-nav li > a[href^='#/']:not([href*='?id=']) { + transition: var(--sidebar-nav-pagelink-transition); +} +.sidebar-nav li > a[href^='/']:not([href*='?id=']), +.sidebar-nav li > a[href^='/']:not([href*='?id=']) ~ ul a, +.sidebar-nav li > a[href^='#/']:not([href*='?id=']), +.sidebar-nav li > a[href^='#/']:not([href*='?id=']) ~ ul a { + padding: var(--sidebar-nav-pagelink-padding, var(--sidebar-nav-link-padding)); +} +.sidebar-nav li > a[href^='/']:not([href*='?id=']):only-child, +.sidebar-nav li > a[href^='#/']:not([href*='?id=']):only-child { + background: var(--sidebar-nav-pagelink-background); +} +.sidebar-nav li > a[href^='/']:not([href*='?id=']):not(:only-child), +.sidebar-nav li > a[href^='#/']:not([href*='?id=']):not(:only-child) { + background: var( + --sidebar-nav-pagelink-background--loaded, + var(--sidebar-nav-pagelink-background) + ); +} +.sidebar-nav li.active > a, +.sidebar-nav li.collapse > a { + border-width: var( + --sidebar-nav-link-border-width--active, + var(--sidebar-nav-link-border-width) + ); + border-style: var( + --sidebar-nav-link-border-style--active, + var(--sidebar-nav-link-border-style) + ); + border-color: var( + --sidebar-nav-link-border-color--active, + var(--sidebar-nav-link-border-color) + ); + background: var( + --sidebar-nav-link-background--active, + var(--sidebar-nav-link-background) + ); + color: var(--sidebar-nav-link-color--active, var(--sidebar-nav-link-color)); + font-weight: var( + --sidebar-nav-link-font-weight--active, + var(--sidebar-nav-link-font-weight) + ); + -webkit-text-decoration: var( + --sidebar-nav-link-text-decoration--active, + var(--sidebar-nav-link-text-decoration) + ); + text-decoration: var( + --sidebar-nav-link-text-decoration--active, + var(--sidebar-nav-link-text-decoration) + ); + -webkit-text-decoration-color: var(--sidebar-nav-link-text-decoration-color); + text-decoration-color: var(--sidebar-nav-link-text-decoration-color); +} +.sidebar-nav li.active > a[href^='/']:not([href*='?id=']):not(:only-child), +.sidebar-nav li.active > a[href^='#/']:not([href*='?id=']):not(:only-child) { + background: var( + --sidebar-nav-pagelink-background--active, + var( + --sidebar-nav-pagelink-background--loaded, + var(--sidebar-nav-pagelink-background) + ) + ); +} +.sidebar-nav li.collapse > a[href^='/']:not([href*='?id=']):not(:only-child), +.sidebar-nav li.collapse > a[href^='#/']:not([href*='?id=']):not(:only-child) { + background: var( + --sidebar-nav-pagelink-background--collapse, + var( + --sidebar-nav-pagelink-background--loaded, + var(--sidebar-nav-pagelink-background) + ) + ); +} +.sidebar-nav li.collapse .app-sub-sidebar { + display: none; +} +.sidebar-nav > ul > li > a:before { + content: var( + --sidebar-nav-link-before-content-l1, + var(--sidebar-nav-link-before-content) + ); + margin: var( + --sidebar-nav-link-before-margin-l1, + var(--sidebar-nav-link-before-margin) + ); + color: var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color)); +} +.sidebar-nav > ul > li.active > a:before { + content: var( + --sidebar-nav-link-before-content-l1--active, + var( + --sidebar-nav-link-before-content--active, + var(--sidebar-nav-link-before-content-l1, var(--sidebar-nav-link-before-content)) + ) + ); + color: var( + --sidebar-nav-link-before-color-l1--active, + var( + --sidebar-nav-link-before-color--active, + var(--sidebar-nav-link-before-color-l1, var(--sidebar-nav-link-before-color)) + ) + ); +} +.sidebar-nav > ul > li > ul > li > a:before { + content: var( + --sidebar-nav-link-before-content-l2, + var(--sidebar-nav-link-before-content) + ); + margin: var( + --sidebar-nav-link-before-margin-l2, + var(--sidebar-nav-link-before-margin) + ); + color: var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color)); +} +.sidebar-nav > ul > li > ul > li.active > a:before { + content: var( + --sidebar-nav-link-before-content-l2--active, + var( + --sidebar-nav-link-before-content--active, + var(--sidebar-nav-link-before-content-l2, var(--sidebar-nav-link-before-content)) + ) + ); + color: var( + --sidebar-nav-link-before-color-l2--active, + var( + --sidebar-nav-link-before-color--active, + var(--sidebar-nav-link-before-color-l2, var(--sidebar-nav-link-before-color)) + ) + ); +} +.sidebar-nav > ul > li > ul > li > ul > li > a:before { + content: var( + --sidebar-nav-link-before-content-l3, + var(--sidebar-nav-link-before-content) + ); + margin: var( + --sidebar-nav-link-before-margin-l3, + var(--sidebar-nav-link-before-margin) + ); + color: var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color)); +} +.sidebar-nav > ul > li > ul > li > ul > li.active > a:before { + content: var( + --sidebar-nav-link-before-content-l3--active, + var( + --sidebar-nav-link-before-content--active, + var(--sidebar-nav-link-before-content-l3, var(--sidebar-nav-link-before-content)) + ) + ); + color: var( + --sidebar-nav-link-before-color-l3--active, + var( + --sidebar-nav-link-before-color--active, + var(--sidebar-nav-link-before-color-l3, var(--sidebar-nav-link-before-color)) + ) + ); +} +.sidebar-nav > ul > li > ul > li > ul > li > ul > li > a:before { + content: var( + --sidebar-nav-link-before-content-l4, + var(--sidebar-nav-link-before-content) + ); + margin: var( + --sidebar-nav-link-before-margin-l4, + var(--sidebar-nav-link-before-margin) + ); + color: var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color)); +} +.sidebar-nav > ul > li > ul > li > ul > li > ul > li.active > a:before { + content: var( + --sidebar-nav-link-before-content-l4--active, + var( + --sidebar-nav-link-before-content--active, + var(--sidebar-nav-link-before-content-l4, var(--sidebar-nav-link-before-content)) + ) + ); + color: var( + --sidebar-nav-link-before-color-l4--active, + var( + --sidebar-nav-link-before-color--active, + var(--sidebar-nav-link-before-color-l4, var(--sidebar-nav-link-before-color)) + ) + ); +} +.sidebar-nav > :last-child { + margin-bottom: 2rem; +} +.sidebar-toggle, +.sidebar-toggle-button { + width: var(--sidebar-toggle-width); + outline: none; +} +.sidebar-toggle { + position: fixed; + z-index: 11; + top: 0; + bottom: 0; + left: 0; + max-width: 40px; + margin: 0; + padding: 0; + border: 0; + background: rgba(0, 0, 0, 0); + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + cursor: pointer; +} +.sidebar-toggle .sidebar-toggle-button { + position: absolute; + top: var(--sidebar-toggle-offset-top); + left: var(--sidebar-toggle-offset-left); + height: var(--sidebar-toggle-height); + border-radius: var(--sidebar-toggle-border-radius); + border-width: var(--sidebar-toggle-border-width); + border-style: var(--sidebar-toggle-border-style); + border-color: var(--sidebar-toggle-border-color); + background: var(--sidebar-toggle-background, transparent); + color: var(--sidebar-toggle-icon-color); +} +.sidebar-toggle span { + position: absolute; + top: calc(50% - var(--sidebar-toggle-icon-stroke-width) / 2); + left: calc(50% - var(--sidebar-toggle-icon-width) / 2); + height: var(--sidebar-toggle-icon-stroke-width); + width: var(--sidebar-toggle-icon-width); + background-color: currentColor; +} +.sidebar-toggle span:nth-child(1) { + margin-top: calc(0px - var(--sidebar-toggle-icon-height) / 2); +} +.sidebar-toggle span:nth-child(3) { + margin-top: calc(var(--sidebar-toggle-icon-height) / 2); +} +@media (min-width: 48em) { + .sidebar-toggle { + position: absolute; + overflow: visible; + top: var(--sidebar-toggle-offset-top); + bottom: auto; + left: 0; + height: var(--sidebar-toggle-height); + transform: translateX(var(--sidebar-width)); + } + .sidebar-toggle .sidebar-toggle-button { + top: 0; + } +} +@media print { + .sidebar-toggle { + display: none; + } +} +@media (max-width: 47.99em) { + body.close .sidebar, + body.close .sidebar-toggle, + body.close .sidebar + .content { + transform: translateX(var(--sidebar-width)); + } +} +@media (min-width: 48em) { + body.close .sidebar + .content { + transform: translateX(0); + } +} +@media (max-width: 47.99em) { + body.close nav.app-nav, + body.close .github-corner { + display: none; + } +} +@media (min-width: 48em) { + body.close .sidebar, + body.close .sidebar-toggle { + transform: translateX(0); + } +} +@media (min-width: 48em) { + body.close nav.app-nav { + margin-left: 0; + } +} +@media (max-width: 47.99em) { + body.close .sidebar-toggle { + width: 100%; + max-width: none; + } + body.close .sidebar-toggle span { + margin-top: 0; + } + body.close .sidebar-toggle span:nth-child(1) { + transform: rotate(45deg); + } + body.close .sidebar-toggle span:nth-child(2) { + display: none; + } + body.close .sidebar-toggle span:nth-child(3) { + transform: rotate(-45deg); + } +} +@media (min-width: 48em) { + body.close .sidebar + .content { + margin-left: 0; + } +} +@media (min-width: 48em) { + body.sticky .sidebar, + body.sticky .sidebar-toggle { + position: fixed; + } +} +body .docsify-copy-code-button, +body .docsify-copy-code-button:after { + border-radius: var(--border-radius-m, 0); + border-top-left-radius: 0; + border-bottom-right-radius: 0; + background: var(--copycode-background); + color: var(--copycode-color); +} +body .docsify-copy-code-button span { + border-radius: var(--border-radius-s, 0); +} +body .docsify-pagination-container { + border-top: var(--pagination-border-top); + color: var(--pagination-color); +} +body .pagination-item-label { + font-size: var(--pagination-label-font-size); +} +body .pagination-item-label svg { + color: var(--pagination-label-color); + height: var(--pagination-chevron-height); + stroke: var(--pagination-chevron-stroke); + stroke-linecap: var(--pagination-chevron-stroke-linecap); + stroke-linejoin: var(--pagination-chevron-stroke-linecap); + stroke-width: var(--pagination-chevron-stroke-width); +} +body .pagination-item-title { + color: var(--pagination-title-color); + font-size: var(--pagination-title-font-size); +} +body .app-name.hide { + display: block; +} +body .sidebar { + padding: var(--sidebar-padding); +} +.sidebar .search { + margin: 0; + padding: 0; + border: 0; +} +.sidebar .search input { + padding: 0; + line-height: 1; + font-size: inherit; +} +.sidebar .search .clear-button { + width: auto; +} +.sidebar .search .clear-button svg { + transform: scale(1); +} +.sidebar .search .matching-post { + border: none; +} +.sidebar .search p { + font-size: inherit; +} +.sidebar .search { + order: var(--search-flex-order); + margin: var(--search-margin); + padding: var(--search-padding); + background: var(--search-background); +} +.sidebar .search a { + color: inherit; +} +.sidebar .search h2 { + margin: var(--search-result-heading-margin); + font-size: var(--search-result-heading-font-size); + font-weight: var(--search-result-heading-font-weight); + color: var(--search-result-heading-color); +} +.sidebar .search .input-wrap { + align-items: stretch; + margin: var(--search-input-margin); + background-color: var(--search-input-background-color); + border-width: var(--search-input-border-width, 0); + border-style: solid; + border-color: var(--search-input-border-color); + border-radius: var(--search-input-border-radius); +} +.sidebar .search input[type='search'] { + min-width: 0; + padding: var(--search-input-padding); + border: none; + background-color: rgba(0, 0, 0, 0); + background-image: var(--search-input-background-image); + background-position: var(--search-input-background-position); + background-repeat: var(--search-input-background-repeat); + background-size: var(--search-input-background-size); + font-size: var(--search-input-font-size); + color: var(--search-input-color); + transition: var(--search-input-transition); +} +.sidebar .search input[type='search']::-ms-clear { + display: none; +} +.sidebar .search input[type='search']::-moz-placeholder { + color: var(--search-input-placeholder-color, #808080); +} +.sidebar .search input[type='search']::placeholder { + color: var(--search-input-placeholder-color, #808080); +} +.sidebar .search input[type='search']::-webkit-input-placeholder { + line-height: normal; +} +.sidebar .search input[type='search']:focus { + background-color: var( + --search-input-background-color--focus, + var(--search-input-background-color) + ); + background-image: var( + --search-input-background-image--focus, + var(--search-input-background-image) + ); + background-position: var( + --search-input-background-position--focus, + var(--search-input-background-position) + ); + background-size: var( + --search-input-background-size--focus, + var(--search-input-background-size) + ); +} +@supports (width: env(safe-area-inset)) { + @media only screen and (orientation: landscape) { + .sidebar .search input[type='search'] { + margin-left: calc(env(safe-area-inset-left) / 2); + } + } +} +.sidebar .search p { + overflow: hidden; + text-overflow: ellipsis; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; +} +.sidebar .search p:empty { + text-align: center; +} +.sidebar .search .clear-button { + margin: 0; + padding: 0 10px; + border: none; + line-height: 1; + background: rgba(0, 0, 0, 0); + cursor: pointer; +} +.sidebar .search .clear-button svg circle { + fill: var(--search-clear-icon-color1, #808080); +} +.sidebar .search .clear-button svg path { + stroke: var(--search-clear-icon-color2, #fff); +} +.sidebar .search.show ~ *:not(h1) { + display: none; +} +.sidebar .search .results-panel { + display: none; + color: var(--search-result-item-color); + font-size: var(--search-result-item-font-size); + font-weight: var(--search-result-item-font-weight); +} +.sidebar .search .results-panel.show { + display: block; +} +.sidebar .search .matching-post { + margin: var(--search-result-item-margin); + padding: var(--search-result-item-padding); +} +.sidebar .search .matching-post, +.sidebar .search .matching-post:last-child { + border-width: var(--search-result-item-border-width, 0) !important; + border-style: var(--search-result-item-border-style); + border-color: var(--search-result-item-border-color); +} +.sidebar .search .matching-post p { + margin: 0; +} +.sidebar .search .search-keyword { + margin: var(--search-result-keyword-margin); + padding: var(--search-result-keyword-padding); + border-radius: var(--search-result-keyword-border-radius); + background-color: var(--search-result-keyword-background); + color: var(--search-result-keyword-color, currentColor); + font-style: normal; + font-weight: var(--search-result-keyword-font-weight); +} +.medium-zoom-overlay, +.medium-zoom-image--open, +.medium-zoom-image--opened { + z-index: 2147483646 !important; +} +.medium-zoom-overlay { + background: var(--zoomimage-overlay-background) !important; +} +:root { + --mono-hue: 113; + --mono-saturation: 0%; + --mono-shade3: hsl(var(--mono-hue), var(--mono-saturation), 20%); + --mono-shade2: hsl(var(--mono-hue), var(--mono-saturation), 30%); + --mono-shade1: hsl(var(--mono-hue), var(--mono-saturation), 40%); + --mono-base: hsl(var(--mono-hue), var(--mono-saturation), 50%); + --mono-tint1: hsl(var(--mono-hue), var(--mono-saturation), 70%); + --mono-tint2: hsl(var(--mono-hue), var(--mono-saturation), 89%); + --mono-tint3: hsl(var(--mono-hue), var(--mono-saturation), 97%); + --theme-hue: 204; + --theme-saturation: 90%; + --theme-lightness: 45%; + --theme-color: hsl(var(--theme-hue), var(--theme-saturation), var(--theme-lightness)); + --modular-scale: 1.333; + --modular-scale--2: calc(var(--modular-scale--1) / var(--modular-scale)); + --modular-scale--1: calc(var(--modular-scale-1) / var(--modular-scale)); + --modular-scale-1: 1rem; + --modular-scale-2: calc(var(--modular-scale-1) * var(--modular-scale)); + --modular-scale-3: calc(var(--modular-scale-2) * var(--modular-scale)); + --modular-scale-4: calc(var(--modular-scale-3) * var(--modular-scale)); + --modular-scale-5: calc(var(--modular-scale-4) * var(--modular-scale)); + --font-size-xxxl: var(--modular-scale-5); + --font-size-xxl: var(--modular-scale-4); + --font-size-xl: var(--modular-scale-3); + --font-size-l: var(--modular-scale-2); + --font-size-m: var(--modular-scale-1); + --font-size-s: var(--modular-scale--1); + --font-size-xs: var(--modular-scale--2); + --duration-slow: 1s; + --duration-medium: 0.5s; + --duration-fast: 0.25s; + --spinner-size: 60px; + --spinner-track-width: 4px; + --spinner-track-color: rgba(0, 0, 0, 0.15); + --spinner-transition-duration: var(--duration-medium); +} +:root { + --base-background-color: #fff; + --base-color: var(--mono-shade2); + --base-font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, + sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + --base-font-size: 16px; + --base-font-weight: normal; + --base-line-height: 1.7; + --emoji-size: calc(var(--base-line-height) * 1em); + --hr-border: 1px solid var(--mono-tint2); + --mark-background: #ffecb3; + --pre-font-family: var(--code-font-family); + --pre-font-size: var(--code-font-size); + --pre-font-weight: normal; + --selection-color: #b4d5fe; + --small-font-size: var(--font-size-s); + --strong-color: var(--heading-color); + --strong-font-weight: 600; + --subsup-font-size: var(--font-size-s); +} +:root { + --content-max-width: 55em; + --blockquote-background: var(--mono-tint3); + --blockquote-border-style: solid; + --blockquote-border-radius: var(--border-radius-m); + --blockquote-em-font-weight: normal; + --blockquote-font-weight: normal; + --blockquote-padding: 1.5em; + --code-font-family: Inconsolata, Consolas, Menlo, Monaco, 'Andale Mono WT', + 'Andale Mono', 'Lucida Console', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', + 'Courier New', Courier, monospace; + --code-font-size: calc(var(--font-size-m) * 0.95); + --code-font-weight: normal; + --code-tab-size: 4; + --code-block-border-radius: var(--border-radius-m); + --code-block-line-height: var(--base-line-height); + --code-block-margin: 1em 0; + --code-block-padding: 1.75em 1.5em 1.5em 1.5em; + --code-inline-background: var(--code-theme-background); + --code-inline-border-radius: var(--border-radius-s); + --code-inline-color: var(--code-theme-text); + --code-inline-margin: 0 0.15em; + --code-inline-padding: 0.125em 0.4em; + --code-theme-background: var(--mono-tint3); + --heading-color: var(--mono-shade3); + --heading-margin: 2.5rem 0 0; + --heading-h1-border-style: solid; + --heading-h1-font-size: var(--font-size-xxl); + --heading-h2-border-style: solid; + --heading-h2-font-size: var(--font-size-xl); + --heading-h3-border-style: solid; + --heading-h3-font-size: var(--font-size-l); + --heading-h4-border-style: solid; + --heading-h4-font-size: var(--font-size-m); + --heading-h5-border-style: solid; + --heading-h5-font-size: var(--font-size-s); + --heading-h6-border-style: solid; + --heading-h6-font-size: var(--font-size-xs); + --kbd-background: var(--mono-tint3); + --kbd-border-radius: var(--border-radius-m); + --kbd-margin: 0 0.3em; + --kbd-min-width: 2.5em; + --kbd-padding: 0.65em 0.5em; + --link-text-decoration: underline; + --notice-background: var(--mono-tint3); + --notice-border-radius: var(--border-radius-m); + --notice-border-style: solid; + --notice-font-weight: normal; + --notice-padding: 1em 1.5em; + --notice-before-font-weight: normal; + --table-cell-padding: 0.75em 0.5em; + --table-head-border-color: var(--table-cell-border-color); + --table-head-font-weight: var(--strong-font-weight); + --table-row-odd-background: var(--mono-tint3); +} +:root { + --cover-margin: 0 auto; + --cover-max-width: 40em; + --cover-text-align: center; + --cover-background-color: var(--base-background-color); + --cover-background-mask-color: var(--base-background-color); + --cover-background-mask-opacity: 0.8; + --cover-background-position: center center; + --cover-background-repeat: no-repeat; + --cover-background-size: cover; + --cover-blockquote-font-size: var(--font-size-l); + --cover-border-color: var(--theme-color); + --cover-button-border: 1px solid var(--theme-color); + --cover-button-border-radius: var(--border-radius-m); + --cover-button-color: var(--theme-color); + --cover-button-padding: 0.5em 2rem; + --cover-button-text-decoration: none; + --cover-button-transition: all var(--duration-fast) ease-in-out; + --cover-button-primary-background: var(--theme-color); + --cover-button-primary-border: 1px solid var(--theme-color); + --cover-button-primary-color: #fff; + --cover-heading-color: var(--theme-color); + --cover-heading-font-size: var(--font-size-xxl); + --cover-heading-font-weight: normal; + --cover-link-text-decoration: underline; +} +:root { + --navbar-root-border-style: solid; + --navbar-root-margin: 0 0 0 1.5em; + --navbar-root-transition: all var(--duration-fast); + --navbar-menu-background: var(--base-background-color); + --navbar-menu-border-radius: var(--border-radius-m); + --navbar-menu-box-shadow: rgba(45, 45, 45, 0.05) 0px 0px 1px, + rgba(49, 49, 49, 0.05) 0px 1px 2px, rgba(42, 42, 42, 0.05) 0px 2px 4px, + rgba(32, 32, 32, 0.05) 0px 4px 8px, rgba(49, 49, 49, 0.05) 0px 8px 16px, + rgba(35, 35, 35, 0.05) 0px 16px 32px; + --navbar-menu-padding: 0.5em; + --navbar-menu-transition: all var(--duration-fast); + --navbar-menu-link-border-style: solid; + --navbar-menu-link-margin: 0.75em 0.5em; + --navbar-menu-link-padding: 0.2em 0; +} +:root { + --copycode-background: #808080; + --copycode-color: #fff; +} +:root { + --docsifytabs-border-color: var(--mono-tint2); + --docsifytabs-border-radius-px: var(--border-radius-s); + --docsifytabs-tab-background: var(--mono-tint3); + --docsifytabs-tab-color: var(--mono-tint1); +} +:root { + --pagination-border-top: 1px solid var(--mono-tint2); + --pagination-chevron-height: 0.8em; + --pagination-chevron-stroke: currentColor; + --pagination-chevron-stroke-linecap: round; + --pagination-chevron-stroke-width: 1px; + --pagination-label-font-size: var(--font-size-s); + --pagination-title-font-size: var(--font-size-l); +} +:root { + --search-margin: 1.5rem 0 0; + --search-input-background-repeat: no-repeat; + --search-input-border-color: var(--mono-tint1); + --search-input-border-width: 1px; + --search-input-padding: 0.5em; + --search-flex-order: 1; + --search-result-heading-color: var(--heading-color); + --search-result-heading-font-size: var(--base-font-size); + --search-result-heading-font-weight: normal; + --search-result-heading-margin: 0 0 0.25em; + --search-result-item-border-color: var(--mono-tint2); + --search-result-item-border-style: solid; + --search-result-item-border-width: 0 0 1px 0; + --search-result-item-font-weight: normal; + --search-result-item-padding: 1em 0; + --search-result-keyword-background: var(--mark-background); + --search-result-keyword-border-radius: var(--border-radius-s); + --search-result-keyword-color: var(--mark-color); + --search-result-keyword-font-weight: normal; + --search-result-keyword-margin: 0 0.1em; + --search-result-keyword-padding: 0.2em 0; +} +:root { + --zoomimage-overlay-background: rgba(0, 0, 0, 0.875); +} +:root { + --sidebar-background: var(--base-background-color); + --sidebar-border-width: 0; + --sidebar-padding: 0 25px; + --sidebar-transition-duration: var(--duration-fast); + --sidebar-width: 17rem; + --sidebar-name-font-size: var(--font-size-l); + --sidebar-name-font-weight: normal; + --sidebar-name-margin: 1.5rem 0 0; + --sidebar-name-text-align: center; + --sidebar-nav-strong-border-color: var(--sidebar-border-color); + --sidebar-nav-strong-color: var(--heading-color); + --sidebar-nav-strong-font-weight: var(--strong-font-weight); + --sidebar-nav-strong-margin: 1.5em 0 0.5em; + --sidebar-nav-strong-padding: 0.25em 0; + --sidebar-nav-indent: 1em; + --sidebar-nav-margin: 1.5rem 0 0; + --sidebar-nav-link-border-style: solid; + --sidebar-nav-link-border-width: 0; + --sidebar-nav-link-color: var(--base-color); + --sidebar-nav-link-font-weight: normal; + --sidebar-nav-link-padding: 0.25em 0; + --sidebar-nav-link-text-decoration--active: underline; + --sidebar-nav-link-text-decoration--hover: underline; + --sidebar-nav-link-before-margin: 0 0.35em 0 0; + --sidebar-nav-pagelink-transition: var(--sidebar-nav-link-transition); + --sidebar-toggle-border-radius: var(--border-radius-s); + --sidebar-toggle-border-style: solid; + --sidebar-toggle-border-width: 0; + --sidebar-toggle-height: 36px; + --sidebar-toggle-icon-color: var(--base-color); + --sidebar-toggle-icon-height: 10px; + --sidebar-toggle-icon-stroke-width: 1px; + --sidebar-toggle-icon-width: 16px; + --sidebar-toggle-offset-left: 0; + --sidebar-toggle-offset-top: calc(35px - (var(--sidebar-toggle-height) / 2)); + --sidebar-toggle-width: 44px; +} +:root { + --code-theme-background: #f3f3f3; + --code-theme-comment: #6e8090; + --code-theme-function: #dd4a68; + --code-theme-keyword: #07a; + --code-theme-operator: #a67f59; + --code-theme-punctuation: #999; + --code-theme-selector: #690; + --code-theme-tag: #905; + --code-theme-text: #333; + --code-theme-variable: #e90; +} +:root { + --border-radius-s: 2px; + --border-radius-m: 4px; + --border-radius-l: 8px; + --strong-font-weight: 600; + --blockquote-border-color: var(--theme-color); + --blockquote-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0; + --blockquote-border-width: 0 0 0 4px; + --code-inline-background: var(--mono-tint2); + --code-theme-background: var(--mono-tint3); + --heading-font-weight: var(--strong-font-weight); + --heading-h1-font-weight: 400; + --heading-h2-font-weight: 400; + --heading-h2-border-color: var(--mono-tint2); + --heading-h2-border-width: 0 0 1px 0; + --heading-h2-margin: 2.5rem 0 1.5rem; + --heading-h2-padding: 0 0 1rem 0; + --kbd-border: 1px solid var(--mono-tint2); + --notice-border-radius: 0 var(--border-radius-m) var(--border-radius-m) 0; + --notice-border-width: 0 0 0 4px; + --notice-padding: 1em 1.5em 1em 3em; + --notice-before-border-radius: 100%; + --notice-before-font-weight: bold; + --notice-before-height: 1.5em; + --notice-before-left: 0.75em; + --notice-before-line-height: 1.5; + --notice-before-margin: 0 0.25em 0 0; + --notice-before-position: absolute; + --notice-before-width: var(--notice-before-height); + --notice-important-background: hsl(340, 60%, 96%); + --notice-important-border-color: hsl(340, 90%, 45%); + --notice-important-before-background: var(--notice-important-border-color) + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3E%3Cpath d='M10 14C10 15.1 9.1 16 8 16 6.9 16 6 15.1 6 14 6 12.9 6.9 12 8 12 9.1 12 10 12.9 10 14Z'/%3E%3Cpath d='M10 1.6C10 1.2 9.8 0.9 9.6 0.7 9.2 0.3 8.6 0 8 0 7.4 0 6.8 0.2 6.5 0.6 6.2 0.9 6 1.2 6 1.6 6 1.7 6 1.8 6 1.9L6.8 9.6C6.9 9.9 7 10.1 7.2 10.2 7.4 10.4 7.7 10.5 8 10.5 8.3 10.5 8.6 10.4 8.8 10.3 9 10.1 9.1 9.9 9.2 9.6L10 1.9C10 1.8 10 1.7 10 1.6Z'/%3E%3C/svg%3E") + center / 0.875em no-repeat; + --notice-important-before-color: #fff; + --notice-important-before-content: ''; + --notice-tip-background: hsl(204, 60%, 96%); + --notice-tip-border-color: hsl(204, 90%, 45%); + --notice-tip-before-background: var(--notice-tip-border-color) + url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3E%3Cpath d='M9.1 0C10.2 0 10.7 0.7 10.7 1.6 10.7 2.6 9.8 3.6 8.6 3.6 7.6 3.6 7 3 7 2 7 1.1 7.7 0 9.1 0Z'/%3E%3Cpath d='M5.8 16C5 16 4.4 15.5 5 13.2L5.9 9.1C6.1 8.5 6.1 8.2 5.9 8.2 5.7 8.2 4.6 8.6 3.9 9.1L3.5 8.4C5.6 6.6 7.9 5.6 8.9 5.6 9.8 5.6 9.9 6.6 9.5 8.2L8.4 12.5C8.2 13.2 8.3 13.5 8.5 13.5 8.7 13.5 9.6 13.2 10.4 12.5L10.9 13.2C8.9 15.2 6.7 16 5.8 16Z'/%3E%3C/svg%3E") + center / 0.875em no-repeat; + --notice-tip-before-color: #fff; + --notice-tip-before-content: ''; + --table-cell-border-color: var(--mono-tint2); + --table-cell-border-width: 1px 0; + --cover-background-color: hsl(var(--theme-hue), 25%, 60%); + --cover-background-image: radial-gradient( + ellipse at center 115%, + rgba(255, 255, 255, 0.9), + transparent + ); + --cover-blockquote-color: var(--strong-color); + --cover-heading-color: #fff; + --cover-heading-font-size-max: 56; + --cover-heading-font-size-min: 34; + --cover-heading-font-weight: 200; + --navbar-root-color--active: var(--theme-color); + --navbar-menu-border-radius: var(--border-radius-m); + --navbar-menu-root-background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='9.6' height='6' viewBox='0 0 9.6 6'%3E%3Cpath d='M1.5 1.5l3.3 3 3.3-3' stroke-width='1.5' stroke='rgb%28179, 179, 179%29' fill='none' stroke-linecap='square' stroke-linejoin='miter' vector-effect='non-scaling-stroke'/%3E%3C/svg%3E") + right no-repeat; + --navbar-menu-root-padding: 0 18px 0 0; + --search-input-background-color: #fff; + --search-input-background-image: url("data:image/svg+xml,%3Csvg height='20px' width='20px' viewBox='0 0 24 24' fill='none' stroke='rgba(0, 0, 0, 0.3)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round' preserveAspectRatio='xMidYMid meet' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='10.5' cy='10.5' r='7.5' vector-effect='non-scaling-stroke'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='15.8' y2='15.8' vector-effect='non-scaling-stroke'%3E%3C/line%3E%3C/svg%3E"); + --search-input-background-position: 21px center; + --search-input-border-color: var(--sidebar-border-color); + --search-input-border-width: 1px 0; + --search-input-margin: 0 -25px; + --search-input-padding: 0.65em 1em 0.65em 50px; + --search-input-placeholder-color: rgba(0, 0, 0, 0.4); + --search-clear-icon-color1: rgba(0, 0, 0, 0.3); + --search-result-heading-font-weight: var(--strong-font-weight); + --search-result-item-border-color: var(--sidebar-border-color); + --search-result-keyword-border-radius: var(--border-radius-s); + --sidebar-background: var(--mono-tint3); + --sidebar-border-color: var(--mono-tint2); + --sidebar-border-width: 0 1px 0 0; + --sidebar-name-color: var(--theme-color); + --sidebar-name-font-weight: 300; + --sidebar-nav-strong-border-width: 0 0 1px 0; + --sidebar-nav-strong-font-size: smaller; + --sidebar-nav-strong-margin: 2em -25px 0.75em 0; + --sidebar-nav-strong-padding: 0.25em 0 0.75em 0; + --sidebar-nav-strong-text-transform: uppercase; + --sidebar-nav-link-border-color: transparent; + --sidebar-nav-link-border-color--active: var(--theme-color); + --sidebar-nav-link-border-width: 0 4px 0 0; + --sidebar-nav-link-color--active: var(--theme-color); + --sidebar-nav-link-margin: 0 -25px 0 0; + --sidebar-nav-link-text-decoration: none; + --sidebar-nav-link-text-decoration--active: none; + --sidebar-nav-link-text-decoration--hover: underline; + --sidebar-nav-pagelink-background: no-repeat 2px calc(50% - 2.5px) / 6px 5px + linear-gradient( + 45deg, + transparent 2.75px, + var(--mono-tint1) 2.75px 4.25px, + transparent 4px + ), + no-repeat 2px calc(50% + 2.5px) / 6px 5px + linear-gradient( + 135deg, + transparent 2.75px, + var(--mono-tint1) 2.75px 4.25px, + transparent 4px + ); + --sidebar-nav-pagelink-background--active: no-repeat 0px center / 5px 6px + linear-gradient( + 225deg, + transparent 2.75px, + var(--theme-color) 2.75px 4.25px, + transparent 4.25px + ), + no-repeat 5px center / 5px 6px + linear-gradient( + 135deg, + transparent 2.75px, + var(--theme-color) 2.75px 4.25px, + transparent 4.25px + ); + --sidebar-nav-pagelink-background--collapse: no-repeat 2px calc(50% - 2.5px) / 6px 5px + linear-gradient( + 45deg, + transparent 2.75px, + var(--theme-color) 2.75px 4.25px, + transparent 4px + ), + no-repeat 2px calc(50% + 2.5px) / 6px 5px + linear-gradient( + 135deg, + transparent 2.75px, + var(--theme-color) 2.75px 4.25px, + transparent 4px + ); + --sidebar-nav-pagelink-background--loaded: no-repeat 0px center / 5px 6px + linear-gradient( + 225deg, + transparent 2.75px, + var(--mono-tint1) 2.75px 4.25px, + transparent 4.25px + ), + no-repeat 5px center / 5px 6px + linear-gradient( + 135deg, + transparent 2.75px, + var(--mono-tint1) 2.75px 4.25px, + transparent 4.25px + ); + --sidebar-nav-pagelink-padding: 0.25em 0 0.25em 20px; + --sidebar-nav-pagelink-transition: none; + --sidebar-toggle-background: var(--sidebar-border-color); + --sidebar-toggle-border-radius: 0 var(--border-radius-s) var(--border-radius-s) 0; + --sidebar-toggle-width: 32px; +} -/*# sourceMappingURL=theme-simple.css.map */ \ No newline at end of file +/*# sourceMappingURL=theme-simple.css.map */ diff --git a/docs/developing.md b/docs/developing.md index a87a603e..3f72f21f 100644 --- a/docs/developing.md +++ b/docs/developing.md @@ -33,6 +33,7 @@ instructions](advanced-installation.md?id=manual-installation). 1. Hit 'Publish release'. ## Translations + [![translation badge](https://badge.inlang.com/?url=github.com/dermotduffy/frigate-hass-card)](https://fink.inlang.com/github.com/dermotduffy/frigate-hass-card?ref=badge) To add translations, you can manually edit the JSON translation files in @@ -53,18 +54,18 @@ speed up the development environment creation. Simply: Everything should just work without any additional configuration. Under the hood, the dev container setup takes care of bringing up: -* Home Assistant (port `8123` or the next available one) -* Frigate (ports `5000` or the next available one) -* MQTT (port `1883` or the next available one) +- Home Assistant (port `8123` or the next available one) +- Frigate (ports `5000` or the next available one) +- MQTT (port `1883` or the next available one) As docker-compose containers. -* The Frigate Home Assistant Integration is registered as a `git submodule` at `.devcontainer/frigate-hass-integration`, and VS Code will initialize/clone it for you before opening the dev container. +- The Frigate Home Assistant Integration is registered as a `git submodule` at `.devcontainer/frigate-hass-integration`, and VS Code will initialize/clone it for you before opening the dev container. Some environment variables are supported in a `.env` file: -* `FRIGATE_VERSION`: The version of Frigate to use. Defaults to the latest stable version. -* `HA_VERSION`: The version of Home Assistant to use. Defaults to the latest stable version. +- `FRIGATE_VERSION`: The version of Frigate to use. Defaults to the latest stable version. +- `HA_VERSION`: The version of Home Assistant to use. Defaults to the latest stable version. ?> When not specifying any version, it's recommended that you `docker-compose pull` the stack from time to time to ensure you have the latest versions of the images. diff --git a/docs/examples.md b/docs/examples.md index bf623e6e..a6608a72 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -287,7 +287,7 @@ cameras: ### Using dependent cameras with birdseye for all cameras -This example shows events for *all* other cameras when `birdseye` is selected. +This example shows events for _all_ other cameras when `birdseye` is selected. This is just a shortcut for naming all other cameras. ```yaml @@ -866,7 +866,7 @@ elements: The card cannot automatically natively trigger fullscreen mode without the user clicking, since Javascript (understandbly) prevents random websites from -triggering fullscreen mode without the user having activated it. +triggering fullscreen mode without the user having activated it. This example uses [hass-browser_mod](https://github.com/thomasloven/hass-browser_mod) with an @@ -877,17 +877,17 @@ automation to trigger a popup. Thanks to alias: >- Doorbell Pressed OR Human Detected - Firefox browser full screen video feed for 15 seconds -description: "" +description: '' trigger: - platform: state - from: "off" - to: "on" + from: 'off' + to: 'on' entity_id: - binary_sensor.frontdoor_person_occupancy - platform: state entity_id: - binary_sensor.front_door_dahua_button_pressed - to: "on" + to: 'on' condition: [] action: - service: browser_mod.popup @@ -988,7 +988,7 @@ https://ha.mydomain.org/lovelace-test/0?frigate-card-action.main.clips ### Choosing the camera from a separate picture elements card -In this example, the card will select a given camera when the user navigates from a *separate* Picture Elements card: +In this example, the card will select a given camera when the user navigates from a _separate_ Picture Elements card: Frigate Card configuration: @@ -1023,8 +1023,7 @@ elements: navigation_path: /lovelace-test/0?frigate-card-action.camera_select=camera.kitchen ``` -![](images/navigate-picture-elements.gif "Taking card actions via the URL :size=400" ) - +![](images/navigate-picture-elements.gif 'Taking card actions via the URL :size=400') ### Selecting a camera in expanded mode via query string diff --git a/docs/images/README.md b/docs/images/README.md index b14e2066..b626d5bd 100644 --- a/docs/images/README.md +++ b/docs/images/README.md @@ -1,7 +1,4 @@ -favicon.ico --- - - https://pictogrammers.com/library/mdi/icon/camera-iris/ - - $ convert camera-iris.png -define icon:auto-resize="256,128,96,64,48,32,16" favicon.ico - - +## favicon.ico +- https://pictogrammers.com/library/mdi/icon/camera-iris/ +- $ convert camera-iris.png -define icon:auto-resize="256,128,96,64,48,32,16" favicon.ico diff --git a/docs/index.html b/docs/index.html index ee971549..5d79de65 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,11 +1,14 @@ - + Frigate Card - + diff --git a/docs/screenshots.md b/docs/screenshots.md index 9feec540..33b9c698 100644 --- a/docs/screenshots.md +++ b/docs/screenshots.md @@ -2,45 +2,45 @@ ## 2-way audio -![](images/microphone.gif "2-way audio support :size=400") +![](images/microphone.gif '2-way audio support :size=400') ## Cast media from card -![](images/cast-your-events.gif "Cast media from the card :size=400") +![](images/cast-your-events.gif 'Cast media from the card :size=400') ## Cast whole card A dashboard with the card can be cast onto a suitable device (such as the Nest Hub shown below). -![](images/card-on-nest-hub.jpg "Card casting :size=400") +![](images/card-on-nest-hub.jpg 'Card casting :size=400') ## Dark mode -![](images/dark-mode.gif "Dark mode :size=400") +![](images/dark-mode.gif 'Dark mode :size=400') ## Editing -![](images/editor.gif "Card editing :size=400") +![](images/editor.gif 'Card editing :size=400') ## Events -![](images/gallery.png "Full Viewing Of Events :size=400") +![](images/gallery.png 'Full Viewing Of Events :size=400') ## Expanded mode -![](images/expanded.gif "Expanded mode :size=400") +![](images/expanded.gif 'Expanded mode :size=400') ## Favoriting events -![](images/star.gif "Card casting :size=400") +![](images/star.gif 'Card casting :size=400') ## Filtering -![](images/media-filtering.gif "Media filtering :size=400") +![](images/media-filtering.gif 'Media filtering :size=400') ## Grid -![](images/grid-small.gif "Interacting with a camera grid :size=400") +![](images/grid-small.gif 'Interacting with a camera grid :size=400') ## Media layout @@ -48,95 +48,95 @@ Pan around a large camera view to only show part of the video feed in the card a ### Before -![](images/media-layout-a.png "Before :size=400") +![](images/media-layout-a.png 'Before :size=400') ### After -![](images/media-layout-b.png "After :size=400") +![](images/media-layout-b.png 'After :size=400') ## Menu hovering -![](images/viewer-with-thumbnail-next-prev.gif "Hover menu / Next & Previous controls :size=400") +![](images/viewer-with-thumbnail-next-prev.gif 'Hover menu / Next & Previous controls :size=400') ## Menu media control -![](images/native-media-control.png "In-menu media / mute control :size=400") +![](images/native-media-control.png 'In-menu media / mute control :size=400') ## Mixed engines -![](images/motioneye.gif "Different camera sources/engines :size=400") +![](images/motioneye.gif 'Different camera sources/engines :size=400') ## Multiple cameras Scroll through your live cameras, or choose from a menu. Seamlessly supports cameras of different dimensions, and custom submenus per camera. -![](images/camera-carousel.gif "Live viewing of multiple cameras :size=400") +![](images/camera-carousel.gif 'Live viewing of multiple cameras :size=400') ## PTZ -![](images/native-ptz.gif "PTZ control :size=400") +![](images/native-ptz.gif 'PTZ control :size=400') ## Recordings ### Recordings single -![](images/recording-seek.gif "Single camera recordings :size=400") +![](images/recording-seek.gif 'Single camera recordings :size=400') ### Recordings multiple -![](images/recording-seek-all-cameras.gif "Multiple camera recordings :size=400") +![](images/recording-seek-all-cameras.gif 'Multiple camera recordings :size=400') ## Scrubbing -![](images/video-scrubbing.gif "Video scrubbing :size=400") +![](images/video-scrubbing.gif 'Video scrubbing :size=400') ## Submenus -![](images/submenu.gif "Configurable submenus :size=400") +![](images/submenu.gif 'Configurable submenus :size=400') ## Submenus with `select` entities -![](images/submenu-select.gif "select entity submenus :size=400") +![](images/submenu-select.gif 'select entity submenus :size=400') ## Substreams -![](images/substream.gif "Substreams :size=400") +![](images/substream.gif 'Substreams :size=400') ## Thumbnail drawers -![](images/thumbnails-in-drawer.gif "Thumbnail drawers :size=400") +![](images/thumbnails-in-drawer.gif 'Thumbnail drawers :size=400') ## Thumbnails in live -![](images/live-thumbnails.gif "Live viewing with thumbnail carousel :size=400") +![](images/live-thumbnails.gif 'Live viewing with thumbnail carousel :size=400') ## Thumbnails in media viewer -![](images/viewer-thumbnails.gif "Clip viewing with thumbnail carousel :size=400") +![](images/viewer-thumbnails.gif 'Clip viewing with thumbnail carousel :size=400') ## Timeline -![](images/timeline.gif "Event timeline :size=400") +![](images/timeline.gif 'Event timeline :size=400') ## Timeline date picking -![](images/date-picker.gif "Timeline date picking :size=400") +![](images/date-picker.gif 'Timeline date picking :size=400') ## Timeline `ribbon` -![](images/ribbon-timeline.png "Ribbon timeline :size=400") +![](images/ribbon-timeline.png 'Ribbon timeline :size=400') ## Triggering Automatically choose the camera with the action! -![](images/triggered.gif "Triggered! :size=400") +![](images/triggered.gif 'Triggered! :size=400') ## URL actions -![](images/navigate-picture-elements.gif "Taking card actions via the URL :size=400") +![](images/navigate-picture-elements.gif 'Taking card actions via the URL :size=400') ## Zoom -![](images/zoom.gif "Zoom support :size=400") +![](images/zoom.gif 'Zoom support :size=400') diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index b6841665..5d51a4ab 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -77,8 +77,8 @@ hardware). In this latter case, you are out of luck. The Android video player swallows `double_tap` interactions in order to rewind or fast-forward. Workarounds: -* Use `hold` instead of `double_tap` for your card-wide action. -* Use a [Frigate Card Element](configuration/elements.md) or menu icon to trigger +- Use `hold` instead of `double_tap` for your card-wide action. +- Use a [Frigate Card Element](configuration/elements.md) or menu icon to trigger the action instead. ### Dragging in carousels broken in Firefox @@ -118,11 +118,11 @@ between clicking the download button and the download starting. ### `Forbidden media source identifier` -* If you are using a custom `client_id` setting in your `frigate.yml` file (the +- If you are using a custom `client_id` setting in your `frigate.yml` file (the configuration file for the Frigate backend itself), you must tell the card about it. See [Frigate engine configuration](configuration/cameras/engine.md?id=frigate). -* You must have the `Enable the media browser` option enabled for the Frigate +- You must have the `Enable the media browser` option enabled for the Frigate integration, in order for media fetches to work for the card. Media fetches are used to fetch events / clips / snapshots, etc. If you just wish to use live streams without media fetches, you can use the following configuration: @@ -144,7 +144,7 @@ for the iPhone is not currently possible. Try resetting the app frontend cache: -* `Configuration -> Companion App -> Debugging -> Reset frontend cache` +- `Configuration -> Companion App -> Debugging -> Reset frontend cache` ### Javascript console errors @@ -168,7 +168,7 @@ must be followed. When upgrading the card it's recommended to reset the frontend cache. Sometimes clearing site data in Chrome settings isn't enough. -* Press F12 to display `Dev Console` in Chrome then right click on the refresh +- Press F12 to display `Dev Console` in Chrome then right click on the refresh icon and select `Empty Cache and Hard Reload` ### Static image URL with credentials doesn't load diff --git a/docs/usage/2-way-audio.md b/docs/usage/2-way-audio.md index 2dbd366c..f0877132 100644 --- a/docs/usage/2-way-audio.md +++ b/docs/usage/2-way-audio.md @@ -9,16 +9,16 @@ challenging. ### Environmental requirements - * Must have a camera that supports audio out (otherwise what's the point!) - * Camera must be supported by `go2rtc` for 2-way audio (see [supported cameras](https://github.com/AlexxIT/go2rtc#two-way-audio)). - * Must be accessing your Home Assistant instance over `https`. The browser will enforce this. +- Must have a camera that supports audio out (otherwise what's the point!) +- Camera must be supported by `go2rtc` for 2-way audio (see [supported cameras](https://github.com/AlexxIT/go2rtc#two-way-audio)). +- Must be accessing your Home Assistant instance over `https`. The browser will enforce this. ### Card requirements - * Only Frigate cameras are supported. - * Only the `go2rtc` live provider is supported. - * Only the `webrtc` mode supports 2-way audio: - * Must have microphone menu button enabled: +- Only Frigate cameras are supported. +- Only the `go2rtc` live provider is supported. +- Only the `webrtc` mode supports 2-way audio: +- Must have microphone menu button enabled: ## Example configuration @@ -38,16 +38,16 @@ menu: ## Usage - * The camera will always load *without* the microphone connected, unless the - [`always_connected`](../configuration/live.md?id=microphone) microphone option is - set to `true`. - * To speak, hold-down the microphone menu button. - * On first press, this will reset the `webrtc` connection to include 2-way - audio unless [`always_connected`](../configuration/live.md?id=microphone) has - been used. - * Thereafter hold the microphone button down to unmute/speak, let go to - mute. - * The video will automatically reset to remove the microphone after the number - of seconds specified by - [`disconnect_seconds`](../configuration/live.md?id=microphone) configuration have - elapsed since the last mute/unmute press. +- The camera will always load _without_ the microphone connected, unless the + [`always_connected`](../configuration/live.md?id=microphone) microphone option is + set to `true`. +- To speak, hold-down the microphone menu button. + - On first press, this will reset the `webrtc` connection to include 2-way + audio unless [`always_connected`](../configuration/live.md?id=microphone) has + been used. + - Thereafter hold the microphone button down to unmute/speak, let go to + mute. +- The video will automatically reset to remove the microphone after the number + of seconds specified by + [`disconnect_seconds`](../configuration/live.md?id=microphone) configuration have + elapsed since the last mute/unmute press. diff --git a/docs/usage/_sidebar.md b/docs/usage/_sidebar.md index d129cda7..4d3913db 100644 --- a/docs/usage/_sidebar.md +++ b/docs/usage/_sidebar.md @@ -1,14 +1,14 @@ -* [Getting Started](../README.md) -* [Configuration](../configuration/README.md) -* [Examples](../examples.md) -* [Screenshots](../screenshots.md) -* [Troubleshooting](../troubleshooting.md) -* [Usage](README.md) - * [2-way audio](2-way-audio.md) - * [Casting](casting.md) - * [Keyboard Shortcuts](keyboard-shortcuts.md) - * [URL Actions](url-actions.md) +- [Getting Started](../README.md) +- [Configuration](../configuration/README.md) +- [Examples](../examples.md) +- [Screenshots](../screenshots.md) +- [Troubleshooting](../troubleshooting.md) +- [Usage](README.md) + - [2-way audio](2-way-audio.md) + - [Casting](casting.md) + - [Keyboard Shortcuts](keyboard-shortcuts.md) + - [URL Actions](url-actions.md) --- -* [Developing](../developing.md) \ No newline at end of file +- [Developing](../developing.md) diff --git a/docs/usage/casting.md b/docs/usage/casting.md index d136944b..3877ebca 100644 --- a/docs/usage/casting.md +++ b/docs/usage/casting.md @@ -6,21 +6,21 @@ Hub](https://store.google.com/us/product/nest_hub_2nd_gen)) through the use of ## Instructions -* Visit [Home Assistant Cast](https://cast.home-assistant.io/) and click `Start Casting` -* Enter your Home Assistant URL, and authorize your account. -* Click `Start Casting` and choose the device to cast to from the browser menu. -* Choose which view/dashboard to display. -* If successful, the view will be cast to the device. +- Visit [Home Assistant Cast](https://cast.home-assistant.io/) and click `Start Casting` +- Enter your Home Assistant URL, and authorize your account. +- Click `Start Casting` and choose the device to cast to from the browser menu. +- Choose which view/dashboard to display. +- If successful, the view will be cast to the device. ## Limitations Casting Home Assistant dashboards comes with a number of caveats: -* Home Assistant Casting does not support the HA `streaming` component +- Home Assistant Casting does not support the HA `streaming` component ([source](https://cast.home-assistant.io/faq.html)). This means clips playing and the `ha` live provider can not work. Other live providers such as `jsmpeg` and `webrtc-card` function correctly. -* The Javascript fullscreen API does not work (so the fullscreen button does not +- The Javascript fullscreen API does not work (so the fullscreen button does not work, but see below for an equivalent). ## Recommended configuration for Nest Hub @@ -42,4 +42,4 @@ dimensions: ### Result -![](../images/card-on-nest-hub.jpg "Casting on a Nest Hub :size=400") +![](../images/card-on-nest-hub.jpg 'Casting on a Nest Hub :size=400') diff --git a/docs/usage/keyboard-shortcuts.md b/docs/usage/keyboard-shortcuts.md index c7c07bd7..81245bf1 100644 --- a/docs/usage/keyboard-shortcuts.md +++ b/docs/usage/keyboard-shortcuts.md @@ -2,17 +2,17 @@ There are two ways to have the card respond to key input: -* As a convenience, the card supports a small number of built in shortcuts with pre-defined default bindings. See below for these built in shortcuts. Use the [`keyboard_shortcuts`](../configuration/view.md?id=keyboard_shortcuts) configuration to change their bindings. -* More generally, _any_ [action](../configuration/actions/README.md) can be configured to run in response to keyboard input as part of an [automation](../configuration/automations.md), even if that action does not have a pre-defined shortcut. See [keyboard automation example](../examples.md?id=responding-to-key-input) to show how to execute any arbitrary action(s) in response to keyboard activity. +- As a convenience, the card supports a small number of built in shortcuts with pre-defined default bindings. See below for these built in shortcuts. Use the [`keyboard_shortcuts`](../configuration/view.md?id=keyboard_shortcuts) configuration to change their bindings. +- More generally, _any_ [action](../configuration/actions/README.md) can be configured to run in response to keyboard input as part of an [automation](../configuration/automations.md), even if that action does not have a pre-defined shortcut. See [keyboard automation example](../examples.md?id=responding-to-key-input) to show how to execute any arbitrary action(s) in response to keyboard activity. ## Built-in shortcuts -| Name | Default key binding | Action | Description | -| - | - | - | - | -| `ptz_down` | `ArrowDown` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ move down. | -| `ptz_home` | `h` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ home / default. | -| `ptz_left` | `ArrowLeft` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ move left. | -| `ptz_right` | `ArrowRight` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ move right. | -| `ptz_up` | `ArrowUp` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ move up. | -| `ptz_zoom_in` | `+` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ zoom in. | -| `ptz_zoom_out` | `-` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ zoom out. | +| Name | Default key binding | Action | Description | +| -------------- | ------------------- | --------------------------------------------------------------------- | ------------------- | +| `ptz_down` | `ArrowDown` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ move down. | +| `ptz_home` | `h` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ home / default. | +| `ptz_left` | `ArrowLeft` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ move left. | +| `ptz_right` | `ArrowRight` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ move right. | +| `ptz_up` | `ArrowUp` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ move up. | +| `ptz_zoom_in` | `+` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ zoom in. | +| `ptz_zoom_out` | `-` | [`ptz_multi`](../configuration/actions/custom/README.md?id=ptz_multi) | PTZ zoom out. | diff --git a/docs/usage/url-actions.md b/docs/usage/url-actions.md index fa026bcd..fa5a5ea0 100644 --- a/docs/usage/url-actions.md +++ b/docs/usage/url-actions.md @@ -8,16 +8,16 @@ camera, open the live view in expanded mode, etc). The Frigate card will execute these actions in the following circumstances: -* On initial card load. -* On 'tab' change in a dashboard. -* When a `navigate` [action](https://www.home-assistant.io/dashboards/actions/) +- On initial card load. +- On 'tab' change in a dashboard. +- When a `navigate` [action](https://www.home-assistant.io/dashboards/actions/) is called on the dashboard (e.g. a button click requests navigation). -* When the user uses the `back` / `forward` browser buttons whilst viewing a +- When the user uses the `back` / `forward` browser buttons whilst viewing a dashboard. ## Instructions -To send an action to *all* Frigate Cards on a dashboard: +To send an action to _all_ Frigate Cards on a dashboard: ``` [PATH_TO_YOUR_HA_DASHBOARD]?frigate-card-action.[ACTION]=[VALUE] @@ -29,11 +29,11 @@ To send an action to a specific named Frigate Card: [PATH_TO_YOUR_HA_DASHBOARD]?frigate-card-action.[CARD_ID].[ACTION]=[VALUE] ``` -| Parameter | Description | -| - | - | -| `ACTION` | One of the supported Frigate Card custom actions. See below. | +| Parameter | Description | +| --------- | ------------------------------------------------------------------------------------------------- | +| `ACTION` | One of the supported Frigate Card custom actions. See below. | | `CARD_ID` | When specified only cards that have a [`card_id`](../configuration/README.md) parameter will act. | -| `VALUE` | An optional value to use with the `camera_select` and `live_substream_select` actions. | +| `VALUE` | An optional value to use with the `camera_select` and `live_substream_select` actions. | ?> Both `.` and `:` may be used as the delimiter. If you use `:` some browsers may require it be escaped to `%3A`. @@ -46,31 +46,31 @@ unless the action is targeted with a `CARD_ID` as shown above. Only a subset of all [actions](../configuration/actions/README.md) are supported in URL form. -| Action | Supported in URL | Explanation | -| - | - | - | -| `camera_select` | :white_check_mark: | | -| `camera_ui`| :white_check_mark: | | -| `clip` | :white_check_mark: | | -| `clips` | :white_check_mark: | | -| `default` | :white_check_mark: | | -| `download`| :heavy_multiplication_x: | Latest media information is not available on initial render. | -| `expand` | :white_check_mark: | | -| `fullscreen` | :heavy_multiplication_x: | Javascript does not support activating fullscreen without direct human interaction. Use `expand` as an alternative. | -| `image` | :white_check_mark: | | -| `live_substream_select` | :white_check_mark: | | -| `live` | :white_check_mark: | | -| `media_player`| :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/frigate-hass-card/issues) if you need this. | -| `menu_toggle` | :white_check_mark: | | -| `microphone_mute`, `microphone_unmute`| :heavy_multiplication_x: | | -| `mute`, `unmute` | :heavy_multiplication_x: | | -| `play`, `pause` | :heavy_multiplication_x: | | -| `ptz` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/frigate-hass-card/issues) if you need this. | -| `recording` | :white_check_mark: | | -| `recordings` | :white_check_mark: | | -| `screenshot`| :heavy_multiplication_x: | Latest media information is not available on initial render. | -| `ptz_controls` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/frigate-hass-card/issues) if you need this. | -| `snapshot` | :white_check_mark: | | -| `snapshots` | :white_check_mark: | | +| Action | Supported in URL | Explanation | +| -------------------------------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------------- | +| `camera_select` | :white_check_mark: | | +| `camera_ui` | :white_check_mark: | | +| `clip` | :white_check_mark: | | +| `clips` | :white_check_mark: | | +| `default` | :white_check_mark: | | +| `download` | :heavy_multiplication_x: | Latest media information is not available on initial render. | +| `expand` | :white_check_mark: | | +| `fullscreen` | :heavy_multiplication_x: | Javascript does not support activating fullscreen without direct human interaction. Use `expand` as an alternative. | +| `image` | :white_check_mark: | | +| `live_substream_select` | :white_check_mark: | | +| `live` | :white_check_mark: | | +| `media_player` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/frigate-hass-card/issues) if you need this. | +| `menu_toggle` | :white_check_mark: | | +| `microphone_mute`, `microphone_unmute` | :heavy_multiplication_x: | | +| `mute`, `unmute` | :heavy_multiplication_x: | | +| `play`, `pause` | :heavy_multiplication_x: | | +| `ptz` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/frigate-hass-card/issues) if you need this. | +| `recording` | :white_check_mark: | | +| `recordings` | :white_check_mark: | | +| `screenshot` | :heavy_multiplication_x: | Latest media information is not available on initial render. | +| `ptz_controls` | :heavy_multiplication_x: | Please [request](https://github.com/dermotduffy/frigate-hass-card/issues) if you need this. | +| `snapshot` | :white_check_mark: | | +| `snapshots` | :white_check_mark: | | ## Examples diff --git a/hacs.json b/hacs.json index daffb222..34428673 100644 --- a/hacs.json +++ b/hacs.json @@ -1,6 +1,6 @@ { - "name": "Frigate Card", - "render_readme": true, - "filename": "frigate-hass-card.js", - "homeassistant": "2022.3.0" + "name": "Frigate Card", + "render_readme": true, + "filename": "frigate-hass-card.js", + "homeassistant": "2022.3.0" } diff --git a/markdown-link-check.json b/markdown-link-check.json index f29f72c4..7fba64e4 100644 --- a/markdown-link-check.json +++ b/markdown-link-check.json @@ -4,4 +4,4 @@ "pattern": "vscode://" } ] -} \ No newline at end of file +} diff --git a/package.json b/package.json index 16933f53..eaabf464 100644 --- a/package.json +++ b/package.json @@ -67,12 +67,11 @@ "docsify-cli": "^4.4.4", "eslint": "^8.57.0", "eslint-config-airbnb-base": "^15.0.0", - "eslint-config-prettier": "^8.5.0", + "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.25.4", - "eslint-plugin-prettier": "^4.2.1", "jsdom": "^21.1.1", "markdown-link-check": "^3.12.1", - "prettier": "^2.6.0", + "prettier": "^3.3.1", "rollup": "^2.79.0", "rollup-plugin-git-info": "^1.0.0", "rollup-plugin-serve": "^2.0.1", @@ -94,6 +93,8 @@ "docs-update-images": "./scripts/docs-update-images.sh", "docs-update-dependencies": "./scripts/docs-update-dependencies.sh", "lint": "eslint 'src/**/*.ts'", + "format": "prettier --write .", + "format-check": "prettier --check .", "rollup": "rollup -c", "prune": "ts-prune", "test": "vitest run", diff --git a/prettier.config.js b/prettier.config.js new file mode 100644 index 00000000..91e19b63 --- /dev/null +++ b/prettier.config.js @@ -0,0 +1,16 @@ +// @ts-check + +/** + * @see https://prettier.io/docs/en/configuration.html + * @type {import('prettier').Options} + * */ +const config = { + semi: true, + trailingComma: 'all', + singleQuote: true, + printWidth: 89, + tabWidth: 2, + embeddedLanguageFormatting: 'auto', +}; + +export default config; diff --git a/project.inlang/settings.json b/project.inlang/settings.json index c6416fe2..2cfd10e9 100644 --- a/project.inlang/settings.json +++ b/project.inlang/settings.json @@ -1,19 +1,16 @@ { - "$schema":"https://inlang.com/schema/project-settings", - "sourceLanguageTag": "en", - "languageTags": ["en", "it", "pt-BR", "pt-PT"], - "modules": [ - "https://cdn.jsdelivr.net/npm/@inlang/plugin-json@latest/dist/index.js", - "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-empty-pattern@latest/dist/index.js", - "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-identical-pattern@latest/dist/index.js", - "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-without-source@latest/dist/index.js", - "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-missing-translation@latest/dist/index.js" - ], - "plugin.inlang.json": { - "pathPattern": "./src/localize/languages/{languageTag}.json", - "variableReferencePattern": [ - "{", - "}" - ] - } + "$schema": "https://inlang.com/schema/project-settings", + "sourceLanguageTag": "en", + "languageTags": ["en", "it", "pt-BR", "pt-PT"], + "modules": [ + "https://cdn.jsdelivr.net/npm/@inlang/plugin-json@latest/dist/index.js", + "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-empty-pattern@latest/dist/index.js", + "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-identical-pattern@latest/dist/index.js", + "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-without-source@latest/dist/index.js", + "https://cdn.jsdelivr.net/npm/@inlang/message-lint-rule-missing-translation@latest/dist/index.js" + ], + "plugin.inlang.json": { + "pathPattern": "./src/localize/languages/{languageTag}.json", + "variableReferencePattern": ["{", "}"] + } } diff --git a/src/camera-manager/browse-media/engine-browse-media.ts b/src/camera-manager/browse-media/engine-browse-media.ts index 6f7e236d..1463d8f9 100644 --- a/src/camera-manager/browse-media/engine-browse-media.ts +++ b/src/camera-manager/browse-media/engine-browse-media.ts @@ -87,8 +87,8 @@ export const getViewMediaFromBrowseMediaArray = ( browseMediaItem.media_class === MEDIA_CLASS_VIDEO ? 'clip' : browseMediaItem.media_class === MEDIA_CLASS_IMAGE - ? 'snapshot' - : null; + ? 'snapshot' + : null; if (!mediaType) { continue; diff --git a/src/camera-manager/frigate/engine-frigate.ts b/src/camera-manager/frigate/engine-frigate.ts index 0f01bae3..bc2a837e 100644 --- a/src/camera-manager/frigate/engine-frigate.ts +++ b/src/camera-manager/frigate/engine-frigate.ts @@ -1034,19 +1034,19 @@ export class FrigateCameraManagerEngine options?.phase === 'stop' ? 'stop' : action === 'zoom_in' || action === 'zoom_out' - ? 'zoom' - : action === 'preset' - ? 'preset' - : 'move', + ? 'zoom' + : action === 'preset' + ? 'preset' + : 'move', ...(options?.phase !== 'stop' && { argument: action === 'zoom_in' ? 'in' : action === 'zoom_out' - ? 'out' - : action === 'preset' - ? options?.preset - : action, + ? 'out' + : action === 'preset' + ? options?.preset + : action, }), }); } diff --git a/src/camera-manager/types.ts b/src/camera-manager/types.ts index 8a26450c..425749ec 100644 --- a/src/camera-manager/types.ts +++ b/src/camera-manager/types.ts @@ -65,19 +65,19 @@ export interface RecordingSegment { export type QueryReturnType = QT extends EventQuery ? EventQueryResults : QT extends RecordingQuery - ? RecordingQueryResults - : QT extends RecordingSegmentsQuery - ? RecordingSegmentsQueryResults - : QT extends MediaMetadataQuery - ? MediaMetadataQueryResults - : never; + ? RecordingQueryResults + : QT extends RecordingSegmentsQuery + ? RecordingSegmentsQueryResults + : QT extends MediaMetadataQuery + ? MediaMetadataQueryResults + : never; export type PartialQueryConcreteType = PQT extends PartialEventQuery ? EventQuery : PQT extends PartialRecordingQuery - ? RecordingQuery - : PQT extends PartialRecordingSegmentsQuery - ? RecordingSegmentsQuery - : never; + ? RecordingQuery + : PQT extends PartialRecordingSegmentsQuery + ? RecordingSegmentsQuery + : never; export type ResultsMap = Map>; export type EventQueryResultsMap = ResultsMap; diff --git a/src/card-controller/actions/actions/ptz-digital.ts b/src/card-controller/actions/actions/ptz-digital.ts index 1f8bec54..a2e1e779 100644 --- a/src/card-controller/actions/actions/ptz-digital.ts +++ b/src/card-controller/actions/actions/ptz-digital.ts @@ -100,20 +100,20 @@ export class PTZDigitalAction extends FrigateCardAction this._action.ptz_action === 'zoom_in' ? STEP_ZOOM : this._action.ptz_action === 'zoom_out' - ? -STEP_ZOOM - : 0; + ? -STEP_ZOOM + : 0; const xDelta = this._action.ptz_action === 'left' ? -STEP_PAN : this._action.ptz_action === 'right' - ? STEP_PAN - : 0; + ? STEP_PAN + : 0; const yDelta = this._action.ptz_action === 'up' ? -STEP_PAN : this._action.ptz_action === 'down' - ? STEP_PAN - : 0; + ? STEP_PAN + : 0; return { zoom: clamp(zoom + zoomDelta, ZOOM_MIN, ZOOM_MAX), diff --git a/src/card-controller/actions/actions/ptz.ts b/src/card-controller/actions/actions/ptz.ts index 17cf7a0b..8e253869 100644 --- a/src/card-controller/actions/actions/ptz.ts +++ b/src/card-controller/actions/actions/ptz.ts @@ -39,10 +39,7 @@ export class PTZAction extends FrigateCardAction { ?.targetID ?? null; const ptzCapabilities = ptzCameraID - ? api - .getCameraManager() - .getCameraCapabilities(ptzCameraID) - ?.getPTZCapabilities() + ? api.getCameraManager().getCameraCapabilities(ptzCameraID)?.getPTZCapabilities() : null; const ptzConfiguration = ptzCameraID ? api.getCameraManager().getStore().getCameraConfig(ptzCameraID)?.ptz diff --git a/src/card-controller/actions/actions/substream-off.ts b/src/card-controller/actions/actions/substream-off.ts index 6e84e04a..8503e4a1 100644 --- a/src/card-controller/actions/actions/substream-off.ts +++ b/src/card-controller/actions/actions/substream-off.ts @@ -4,6 +4,6 @@ import { FrigateCardAction } from './base'; export class SubstreamOffAction extends FrigateCardAction { public async execute(api: CardActionsAPI): Promise { - api.getViewManager().setViewWithoutSubstream(); + api.getViewManager().setViewWithoutSubstream(); } } diff --git a/src/card-controller/actions/types.ts b/src/card-controller/actions/types.ts index 5eeb4f0f..45197585 100644 --- a/src/card-controller/actions/types.ts +++ b/src/card-controller/actions/types.ts @@ -1,5 +1,5 @@ -import { ActionType } from "../../config/types"; -import { CardActionsAPI } from "../types"; +import { ActionType } from '../../config/types'; +import { CardActionsAPI } from '../types'; export interface AuxillaryActionConfig { camera_image?: string; diff --git a/src/card-controller/auto-update-manager.ts b/src/card-controller/auto-update-manager.ts index 96462c97..bad2f5a7 100644 --- a/src/card-controller/auto-update-manager.ts +++ b/src/card-controller/auto-update-manager.ts @@ -15,8 +15,7 @@ export class AutoUpdateManager { */ public startDefaultViewTimer(): void { this._timer.stop(); - const updateSeconds = this._api.getConfigManager().getConfig() - ?.view.update_seconds; + const updateSeconds = this._api.getConfigManager().getConfig()?.view.update_seconds; if (updateSeconds) { this._timer.start(updateSeconds, () => { if (this._isAutomatedUpdateAllowed()) { diff --git a/src/card-controller/card-element-manager.ts b/src/card-controller/card-element-manager.ts index 6cc3a462..5c8b80db 100644 --- a/src/card-controller/card-element-manager.ts +++ b/src/card-controller/card-element-manager.ts @@ -9,7 +9,10 @@ import { ActionExecutionRequestEventTarget } from './actions/utils/execution-req export type ScrollCallback = () => void; export type MenuToggleCallback = () => void; -export type CardHTMLElement = LitElement & ReactiveControllerHost & ActionEventTarget & ActionExecutionRequestEventTarget; +export type CardHTMLElement = LitElement & + ReactiveControllerHost & + ActionEventTarget & + ActionExecutionRequestEventTarget; export class CardElementManager { protected _api: CardElementAPI; @@ -70,7 +73,7 @@ export class CardElementManager { setOrRemoveAttribute(this._element, true, 'tabindex', '0'); this._api.getFullscreenManager().connect(); - + this._element.addEventListener( 'mousemove', this._api.getInteractionManager().reportInteraction, diff --git a/src/card-controller/hass-manager.ts b/src/card-controller/hass-manager.ts index 9c0d3503..2ada031f 100644 --- a/src/card-controller/hass-manager.ts +++ b/src/card-controller/hass-manager.ts @@ -66,7 +66,7 @@ export class HASSManager { } if (this._api.getConditionsManager().hasHAStateConditions()) { - this._api.getConditionsManager().setState({ + this._api.getConditionsManager().setState({ state: this._hass.states, user: this._hass.user, }); diff --git a/src/card-controller/message-manager.ts b/src/card-controller/message-manager.ts index 17933e6c..22afbdf6 100644 --- a/src/card-controller/message-manager.ts +++ b/src/card-controller/message-manager.ts @@ -1,4 +1,9 @@ -import { FrigateCardError, MESSAGE_TYPE_PRIORITIES, Message, MessageType } from '../types'; +import { + FrigateCardError, + MESSAGE_TYPE_PRIORITIES, + Message, + MessageType, +} from '../types'; import { errorToConsole } from '../utils/basic'; import { CardMessageAPI } from './types'; diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index d289f9c5..7eb9ebf7 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -37,7 +37,7 @@ export interface CardActionsAPI { getCameraManager(): CameraManager; getCameraURLManager(): CameraURLManager; getCardElementManager(): CardElementManager; - getConditionsManager(): ConditionsManager; + getConditionsManager(): ConditionsManager; getConfigManager(): ConfigManager; getDownloadManager(): DownloadManager; getExpandManager(): ExpandManager; @@ -256,7 +256,7 @@ export interface KeysState { shift: boolean; alt: boolean; meta: boolean; - } + }; } interface TaggedAutomation extends Automation { tag?: unknown; diff --git a/src/card.ts b/src/card.ts index 350fde22..f36bdbe3 100644 --- a/src/card.ts +++ b/src/card.ts @@ -258,99 +258,105 @@ class FrigateCard extends LitElement { // Caution: Keep the main div and the menu next to one another in order to // ensure the hover menu styling continues to work. - return this._renderInDialogIfNecessary(html` ) => - this._controller.getMessageManager().setMessageIfHigherPriority(ev.detail)} - @frigate-card:view:change=${(ev: CustomEvent) => - this._controller.getViewManager().setView(ev.detail)} - @frigate-card:view:change-context=${(ev: CustomEvent) => - this._controller.getViewManager().setViewWithMergedContext(ev.detail)} - @frigate-card:media:loaded=${(ev: CustomEvent) => - this._controller.getMediaLoadedInfoManager().set(ev.detail)} - @frigate-card:media:unloaded=${() => - this._controller.getMediaLoadedInfoManager().clear()} - @frigate-card:media:volumechange=${ - () => this.requestUpdate() /* Refresh mute menu button */ - } - @frigate-card:media:play=${ - () => this.requestUpdate() /* Refresh play/pause menu button */ - } - @frigate-card:media:pause=${ - () => this.requestUpdate() /* Refresh play/pause menu button */ - } - @frigate-card:focus=${() => this.focus()} - > - ${renderMenuAbove ? this._renderMenu() : ''} -
      - ${!cameraManager.isInitialized() && - !this._controller.getMessageManager().hasMessage() - ? renderProgressIndicator({ - cardWideConfig: this._controller.getConfigManager().getCardWideConfig(), - }) - : // Always want to render even if there's a message, to - // ensure live preload is always present (even if not displayed). - html`) => + this._controller.getMessageManager().setMessageIfHigherPriority(ev.detail)} + @frigate-card:view:change=${(ev: CustomEvent) => + this._controller.getViewManager().setView(ev.detail)} + @frigate-card:view:change-context=${(ev: CustomEvent) => + this._controller.getViewManager().setViewWithMergedContext(ev.detail)} + @frigate-card:media:loaded=${(ev: CustomEvent) => + this._controller.getMediaLoadedInfoManager().set(ev.detail)} + @frigate-card:media:unloaded=${() => + this._controller.getMediaLoadedInfoManager().clear()} + @frigate-card:media:volumechange=${ + () => this.requestUpdate() /* Refresh mute menu button */ + } + @frigate-card:media:play=${ + () => this.requestUpdate() /* Refresh play/pause menu button */ + } + @frigate-card:media:pause=${ + () => this.requestUpdate() /* Refresh play/pause menu button */ + } + @frigate-card:focus=${() => this.focus()} + > + ${renderMenuAbove ? this._renderMenu() : ''} +
      + ${!cameraManager.isInitialized() && + !this._controller.getMessageManager().hasMessage() + ? renderProgressIndicator({ + cardWideConfig: this._controller.getConfigManager().getCardWideConfig(), + }) + : // Always want to render even if there's a message, to + // ensure live preload is always present (even if not displayed). + html``} + ${ + // Keep message rendering to last to show messages that may have been + // generated during the render. + renderMessage(this._controller.getMessageManager().getMessage()) + } +
      + ${!renderMenuAbove ? this._renderMenu() : ''} + ${this._config?.elements + ? // Elements need to render after the main views so it can render 'on + // top'. + html`
      `} - ${ - // Keep message rendering to last to show messages that may have been - // generated during the render. - renderMessage(this._controller.getMessageManager().getMessage()) - } -
      - ${!renderMenuAbove ? this._renderMenu() : ''} - ${this._config?.elements - ? // Elements need to render after the main views so it can render 'on - // top'. - html` ) => { - this._menuButtonController.addDynamicMenuButton(ev.detail); - this.requestUpdate(); - }} - @frigate-card:menu-remove=${(ev: CustomEvent) => { - this._menuButtonController.removeDynamicMenuButton(ev.detail); - this.requestUpdate(); - }} - @frigate-card:conditions:evaluate=${(ev: ConditionsEvaluateRequestEvent) => { - ev.evaluation = this._controller - .getConditionsManager() - ?.evaluateConditions(ev.conditions); - }} - > - ` - : ``} -
      `); + @frigate-card:menu-add=${(ev: CustomEvent) => { + this._menuButtonController.addDynamicMenuButton(ev.detail); + this.requestUpdate(); + }} + @frigate-card:menu-remove=${(ev: CustomEvent) => { + this._menuButtonController.removeDynamicMenuButton(ev.detail); + this.requestUpdate(); + }} + @frigate-card:conditions:evaluate=${( + ev: ConditionsEvaluateRequestEvent, + ) => { + ev.evaluation = this._controller + .getConditionsManager() + ?.evaluateConditions(ev.conditions); + }} + > + ` + : ``} + `, + ); } static get styles(): CSSResultGroup { diff --git a/src/components-lib/media-filter-controller.ts b/src/components-lib/media-filter-controller.ts index d4c6ce99..5a46f6f1 100644 --- a/src/components-lib/media-filter-controller.ts +++ b/src/components-lib/media-filter-controller.ts @@ -343,8 +343,8 @@ export class MediaFilterController { mediaType = !!hasClips[0] ? MediaFilterMediaType.Clips : !!hasSnapshots[0] - ? MediaFilterMediaType.Snapshots - : undefined; + ? MediaFilterMediaType.Snapshots + : undefined; } const whatSets = uniqWith( @@ -460,8 +460,8 @@ export class MediaFilterController { favorites: events ? managerCapabilities?.has('favorite-events') : recordings - ? managerCapabilities?.has('favorite-recordings') - : false, + ? managerCapabilities?.has('favorite-recordings') + : false, }; } diff --git a/src/components-lib/menu-button-controller.ts b/src/components-lib/menu-button-controller.ts index 0c4983c0..160b256f 100644 --- a/src/components-lib/menu-button-controller.ts +++ b/src/components-lib/menu-button-controller.ts @@ -377,8 +377,8 @@ export class MenuButtonController { icon: forbidden ? 'mdi:microphone-message-off' : muted - ? 'mdi:microphone-off' - : 'mdi:microphone', + ? 'mdi:microphone-off' + : 'mdi:microphone', ...config.menu.buttons.microphone, type: 'custom:frigate-card-menu-icon', title: localize('config.menu.buttons.microphone'), @@ -570,8 +570,8 @@ export class MenuButtonController { const ptzConfig = view.is('live') ? config.live.controls.ptz : view.isViewerView() - ? config.media_viewer.controls.ptz - : null; + ? config.media_viewer.controls.ptz + : null; if (!ptzConfig || ptzConfig.mode === 'off') { return null; diff --git a/src/components-lib/ptz/ptz-controller.ts b/src/components-lib/ptz/ptz-controller.ts index 88af5a20..52f1b0bd 100644 --- a/src/components-lib/ptz/ptz-controller.ts +++ b/src/components-lib/ptz/ptz-controller.ts @@ -96,9 +96,11 @@ export class PTZController { return this._forceVisibility !== undefined ? this._forceVisibility : this._config?.mode === 'auto' - ? !!this._cameraID && - !!this._cameraManager?.getCameraCapabilities(this._cameraID)?.hasPTZCapability() - : this._config?.mode === 'on'; + ? !!this._cameraID && + !!this._cameraManager + ?.getCameraCapabilities(this._cameraID) + ?.hasPTZCapability() + : this._config?.mode === 'on'; } public getPTZActions(): PTZActionNameToMultiAction { diff --git a/src/components/date-picker.ts b/src/components/date-picker.ts index bf171ee4..24c7456c 100644 --- a/src/components/date-picker.ts +++ b/src/components/date-picker.ts @@ -30,7 +30,7 @@ export class FrigateCardDatePicker extends LitElement { protected render(): TemplateResult { const changed = () => { const value = this._refInput.value?.value; - + dispatchFrigateCardEvent(this, 'date-picker:change', { date: value ? new Date(value) : null, }); diff --git a/src/components/gallery.ts b/src/components/gallery.ts index b4f0f315..c98608c7 100644 --- a/src/components/gallery.ts +++ b/src/components/gallery.ts @@ -90,8 +90,8 @@ export class FrigateCardGallery extends LitElement { const eventsMediaType = this.view.is('snapshots') ? 'snapshots' : this.view.is('clips') - ? 'clips' - : null; + ? 'clips' + : null; changeViewToRecentEventsForCameraAndDependents( this, this.cameraManager, @@ -358,8 +358,8 @@ export class FrigateCardGalleryCore extends LitElement { const newMediaQueries = MediaQueriesClassifier.areEventQueries(query) ? new EventMediaQueries(extension.queries as EventQuery[]) : MediaQueriesClassifier.areRecordingQueries(query) - ? new RecordingMediaQueries(extension.queries as RecordingQuery[]) - : null; + ? new RecordingMediaQueries(extension.queries as RecordingQuery[]) + : null; if (newMediaQueries) { this.view diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 9a1910b5..c435f88b 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -947,42 +947,42 @@ export class FrigateCardLiveProvider > ` : provider === 'go2rtc' - ? html` - ` - : provider === 'webrtc-card' - ? html` - ` - : provider === 'jsmpeg' - ? html` - ` - : html``} + ? html` + ` + : provider === 'webrtc-card' + ? html` + ` + : provider === 'jsmpeg' + ? html` + ` + : html``} `)} ${showImageDuringLoading && !this._isVideoMediaLoaded ? html`, - ) => void, + listener: (this: FrigateCardMessageEventTarget, ev: CustomEvent) => void, options?: AddEventListenerOptions | boolean, ): void; addEventListener( @@ -217,10 +214,7 @@ export interface FrigateCardMessageEventTarget extends EventTarget { ): void; removeEventListener( event: 'frigate-card:message', - listener: ( - this: FrigateCardMessageEventTarget, - ev: CustomEvent, - ) => void, + listener: (this: FrigateCardMessageEventTarget, ev: CustomEvent) => void, options?: boolean | EventListenerOptions, ): void; removeEventListener( diff --git a/src/components/thumbnail-carousel.ts b/src/components/thumbnail-carousel.ts index 52e81acd..c1280cb8 100644 --- a/src/components/thumbnail-carousel.ts +++ b/src/components/thumbnail-carousel.ts @@ -92,31 +92,33 @@ export class FrigateCardThumbnailCarousel extends LitElement { 'slide-selected': selectedIndex === index, }; - slides.push(html` { - if (this.view && this.view.queryResults) { - dispatchFrigateCardEvent( - this, - 'thumbnail-carousel:tap', - { - queryResults: this.view.queryResults.clone().selectIndex(index), - }, - ); - } - stopEventFromActivatingCardWideActions(ev); - }} - > - `); + slides.push( + html` { + if (this.view && this.view.queryResults) { + dispatchFrigateCardEvent( + this, + 'thumbnail-carousel:tap', + { + queryResults: this.view.queryResults.clone().selectIndex(index), + }, + ); + } + stopEventFromActivatingCardWideActions(ev); + }} + > + `, + ); } return slides; } diff --git a/src/components/thumbnail.ts b/src/components/thumbnail.ts index eca1731c..61f4464f 100644 --- a/src/components/thumbnail.ts +++ b/src/components/thumbnail.ts @@ -418,13 +418,13 @@ export class FrigateCardThumbnail extends LitElement { .thumbnail=${thumbnail ?? undefined} >` : ViewMediaClassifier.isRecording(this.media) - ? html`` - : html``} + ? html`` + : html``} ${shouldShowFavoriteControl ? html` ` : this.details && ViewMediaClassifier.isRecording(this.media) - ? html`` - : html``} + ? html`` + : html``} ${shouldShowTimelineControl ? html`; - const KEYBOARD_SHORTCUT_PTZ_NAMES = [ 'ptz_down', 'ptz_home', diff --git a/src/config/management.ts b/src/config/management.ts index a5a0c39e..031abd2a 100644 --- a/src/config/management.ts +++ b/src/config/management.ts @@ -722,8 +722,8 @@ const UPGRADES = [ data === 'all' ? ['selected', 'visible', 'microphone'] : data === 'never' - ? null - : arrayify(data), + ? null + : arrayify(data), ), upgradeWithOverrides('media_viewer.auto_play', (data) => data === 'all' ? null : data === 'never' ? [] : arrayify(data), diff --git a/src/config/profiles/index.ts b/src/config/profiles/index.ts index 61460daf..3499dab5 100644 --- a/src/config/profiles/index.ts +++ b/src/config/profiles/index.ts @@ -1,16 +1,12 @@ import { getConfigValue, setConfigValue } from '../management.js'; -import { - ProfileType, - RawFrigateCardConfig, - frigateCardConfigSchema, -} from '../types.js'; +import { ProfileType, RawFrigateCardConfig, frigateCardConfigSchema } from '../types.js'; import { deepRemoveDefaults } from '../../utils/zod.js'; import { LOW_PERFORMANCE_PROFILE } from './low-performance.js'; import { SCRUBBING_PROFILE } from './scrubbing.js'; const PROFILES = { 'low-performance': LOW_PERFORMANCE_PROFILE, - 'scrubbing': SCRUBBING_PROFILE, + scrubbing: SCRUBBING_PROFILE, }; /** diff --git a/src/config/types.ts b/src/config/types.ts index 3f924f5e..09d4dab8 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -737,9 +737,7 @@ const ptzCameraConfigDefaults = { // service data as actions for each PTZ action, and it will be preprocessed // into the full form. This also provides compatability with the AlexIT/WebRTC // PTZ configuration. -const dataPTZFormatToFullFormat = function ( - suffix: string, -): (data: unknown) => unknown { +const dataPTZFormatToFullFormat = function (suffix: string): (data: unknown) => unknown { return (data) => { if (!data || typeof data !== 'object' || !data['service']) { return data; @@ -1545,9 +1543,7 @@ export const menuConfigSchema = z camera_ui: visibleButtonSchema.default(menuConfigDefault.buttons.camera_ui), cameras: visibleButtonSchema.default(menuConfigDefault.buttons.cameras), clips: visibleButtonSchema.default(menuConfigDefault.buttons.clips), - ptz_home: hiddenButtonSchema.default( - menuConfigDefault.buttons.ptz_home, - ), + ptz_home: hiddenButtonSchema.default(menuConfigDefault.buttons.ptz_home), display_mode: visibleButtonSchema.default( menuConfigDefault.buttons.display_mode, ), @@ -1608,7 +1604,7 @@ const viewerConfigDefault = { ptz: { ...ptzControlsDefaults, mode: 'off' as const, - } + }, }, }; @@ -1658,10 +1654,12 @@ const viewerConfigSchema = z next_previous: viewerNextPreviousControlConfigSchema.default( viewerConfigDefault.controls.next_previous, ), - ptz: ptzControlsConfigSchema.extend({ - // The media_viewer ptz has no 'auto' mode. - mode: z.enum(['off', 'on']).default(viewerConfigDefault.controls.ptz.mode), - }).default(viewerConfigDefault.controls.ptz), + ptz: ptzControlsConfigSchema + .extend({ + // The media_viewer ptz has no 'auto' mode. + mode: z.enum(['off', 'on']).default(viewerConfigDefault.controls.ptz.mode), + }) + .default(viewerConfigDefault.controls.ptz), thumbnails: thumbnailsControlSchema.default( viewerConfigDefault.controls.thumbnails, ), diff --git a/src/editor.ts b/src/editor.ts index 2c378b42..bbc7ed33 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -1123,10 +1123,15 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ); } - protected _renderKeyAssigner(configPath: string, defaultValue: KeyboardShortcut): TemplateResult { + protected _renderKeyAssigner( + configPath: string, + defaultValue: KeyboardShortcut, + ): TemplateResult { return html` this._valueChangedHandler(configPath, ev)} >`; } @@ -1279,10 +1284,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${icon.name ? html` ` : icon.path - ? html` - - ` - : ``} + ? html` + + ` + : ``} ${localize(labelPath)} ${selected ? html`
      ${template}
      ` : ''} diff --git a/src/images/README.md b/src/images/README.md index 7660ec7b..b65d2855 100644 --- a/src/images/README.md +++ b/src/images/README.md @@ -12,10 +12,10 @@ **Image Formatting Process**: -* Horizontal mirror (to face the opposite direction) -* Cropped for 16:9 -* Scaled down to 492x277 -* Quality @ 85% +- Horizontal mirror (to face the opposite direction) +- Cropped for 16:9 +- Scaled down to 492x277 +- Quality @ 85% ```sh $ convert -extent 2048x1152 -flop -gravity center 47543120431_b285c45ac8_k.jpg frigate-bird-in-sky.jpg diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json index fbbc3de0..01d3b62c 100644 --- a/src/localize/languages/ca.json +++ b/src/localize/languages/ca.json @@ -645,4 +645,4 @@ "timeline": { "select_date": "Escolliu la data" } -} \ No newline at end of file +} diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index b67be927..e7d8d321 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -652,4 +652,4 @@ "timeline": { "select_date": "Choose date" } -} \ No newline at end of file +} diff --git a/src/localize/languages/fr.json b/src/localize/languages/fr.json index 4b72a638..5d435d66 100644 --- a/src/localize/languages/fr.json +++ b/src/localize/languages/fr.json @@ -645,4 +645,4 @@ "timeline": { "select_date": "Choisir une date" } -} \ No newline at end of file +} diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index eab11dcb..08276c1a 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -645,4 +645,4 @@ "timeline": { "select_date": "Scegli la data" } -} \ No newline at end of file +} diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 862c3239..df882da2 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -645,4 +645,4 @@ "timeline": { "select_date": "Escolha a data" } -} \ No newline at end of file +} diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 8800e74a..ad966a0b 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -645,4 +645,4 @@ "timeline": { "select_date": "Selecionar a data" } -} \ No newline at end of file +} diff --git a/src/patches/ha-camera-stream.ts b/src/patches/ha-camera-stream.ts index e1e742a1..5381aec2 100644 --- a/src/patches/ha-camera-stream.ts +++ b/src/patches/ha-camera-stream.ts @@ -80,7 +80,7 @@ customElements.whenDefined('ha-camera-stream').then(() => { public isPaused(): boolean { return this._player?.isPaused() ?? true; } - + public async getScreenshotURL(): Promise { return this._player ? await this._player.getScreenshotURL() : null; } diff --git a/src/patches/ha-hls-player.ts b/src/patches/ha-hls-player.ts index 89c6920f..50bb7080 100644 --- a/src/patches/ha-hls-player.ts +++ b/src/patches/ha-hls-player.ts @@ -21,10 +21,12 @@ import { dispatchMediaLoadedEvent, dispatchMediaPauseEvent, dispatchMediaPlayEvent, - dispatchMediaVolumeChangeEvent + dispatchMediaVolumeChangeEvent, } from '../utils/media-info.js'; import { - hideMediaControlsTemporarily, MEDIA_LOAD_CONTROLS_HIDE_SECONDS, setControlsOnVideo + hideMediaControlsTemporarily, + MEDIA_LOAD_CONTROLS_HIDE_SECONDS, + setControlsOnVideo, } from '../utils/media.js'; import { screenshotMedia } from '../utils/screenshot.js'; diff --git a/src/patches/ha-web-rtc-player.ts b/src/patches/ha-web-rtc-player.ts index c9ceb764..de30478b 100644 --- a/src/patches/ha-web-rtc-player.ts +++ b/src/patches/ha-web-rtc-player.ts @@ -21,12 +21,12 @@ import { dispatchMediaLoadedEvent, dispatchMediaPauseEvent, dispatchMediaPlayEvent, - dispatchMediaVolumeChangeEvent + dispatchMediaVolumeChangeEvent, } from '../utils/media-info.js'; import { hideMediaControlsTemporarily, MEDIA_LOAD_CONTROLS_HIDE_SECONDS, - setControlsOnVideo + setControlsOnVideo, } from '../utils/media.js'; customElements.whenDefined('ha-web-rtc-player').then(() => { diff --git a/src/scss/button.scss b/src/scss/button.scss index c3148296..9ff1fa85 100644 --- a/src/scss/button.scss +++ b/src/scss/button.scss @@ -27,71 +27,71 @@ ha-icon-button.button { } @mixin state-icon($element) { - #{$element}[data-domain="alert"][data-state="on"], - #{$element}[data-domain="automation"][data-state="on"], - #{$element}[data-domain="binary_sensor"][data-state="on"], - #{$element}[data-domain="calendar"][data-state="on"], - #{$element}[data-domain="camera"][data-state="streaming"], - #{$element}[data-domain="cover"][data-state="open"], - #{$element}[data-domain="fan"][data-state="on"], - #{$element}[data-domain="humidifier"][data-state="on"], - #{$element}[data-domain="light"][data-state="on"], - #{$element}[data-domain="input_boolean"][data-state="on"], - #{$element}[data-domain="lock"][data-state="unlocked"], - #{$element}[data-domain="media_player"][data-state="on"], - #{$element}[data-domain="media_player"][data-state="paused"], - #{$element}[data-domain="media_player"][data-state="playing"], - #{$element}[data-domain="script"][data-state="on"], - #{$element}[data-domain="sun"][data-state="above_horizon"], - #{$element}[data-domain="switch"][data-state="on"], - #{$element}[data-domain="timer"][data-state="active"], - #{$element}[data-domain="vacuum"][data-state="cleaning"], - #{$element}[data-domain="group"][data-state="on"], - #{$element}[data-domain="group"][data-state="home"], - #{$element}[data-domain="group"][data-state="open"], - #{$element}[data-domain="group"][data-state="locked"], - #{$element}[data-domain="group"][data-state="problem"] { + #{$element}[data-domain='alert'][data-state='on'], + #{$element}[data-domain='automation'][data-state='on'], + #{$element}[data-domain='binary_sensor'][data-state='on'], + #{$element}[data-domain='calendar'][data-state='on'], + #{$element}[data-domain='camera'][data-state='streaming'], + #{$element}[data-domain='cover'][data-state='open'], + #{$element}[data-domain='fan'][data-state='on'], + #{$element}[data-domain='humidifier'][data-state='on'], + #{$element}[data-domain='light'][data-state='on'], + #{$element}[data-domain='input_boolean'][data-state='on'], + #{$element}[data-domain='lock'][data-state='unlocked'], + #{$element}[data-domain='media_player'][data-state='on'], + #{$element}[data-domain='media_player'][data-state='paused'], + #{$element}[data-domain='media_player'][data-state='playing'], + #{$element}[data-domain='script'][data-state='on'], + #{$element}[data-domain='sun'][data-state='above_horizon'], + #{$element}[data-domain='switch'][data-state='on'], + #{$element}[data-domain='timer'][data-state='active'], + #{$element}[data-domain='vacuum'][data-state='cleaning'], + #{$element}[data-domain='group'][data-state='on'], + #{$element}[data-domain='group'][data-state='home'], + #{$element}[data-domain='group'][data-state='open'], + #{$element}[data-domain='group'][data-state='locked'], + #{$element}[data-domain='group'][data-state='problem'] { color: var(--paper-item-icon-active-color, #fdd835); } - #{$element}[data-domain="climate"][data-state="cooling"] { + #{$element}[data-domain='climate'][data-state='cooling'] { color: var(--cool-color, var(--state-climate-cool-color)); } - #{$element}[data-domain="climate"][data-state="heating"] { + #{$element}[data-domain='climate'][data-state='heating'] { color: var(--heat-color, var(--state-climate-heat-color)); } - #{$element}[data-domain="climate"][data-state="drying"] { + #{$element}[data-domain='climate'][data-state='drying'] { color: var(--dry-color, var(--state-climate-dry-color)); } - #{$element}[data-domain="alarm_control_panel"] { + #{$element}[data-domain='alarm_control_panel'] { color: var(--alarm-color-armed, var(--label-badge-red)); } - #{$element}[data-domain="alarm_control_panel"][data-state="disarmed"] { + #{$element}[data-domain='alarm_control_panel'][data-state='disarmed'] { color: var(--alarm-color-disarmed, var(--label-badge-green)); } - #{$element}[data-domain="alarm_control_panel"][data-state="pending"], - #{$element}[data-domain="alarm_control_panel"][data-state="arming"] { + #{$element}[data-domain='alarm_control_panel'][data-state='pending'], + #{$element}[data-domain='alarm_control_panel'][data-state='arming'] { color: var(--alarm-color-pending, var(--label-badge-yellow)); animation: pulse 1s infinite; } - #{$element}[data-domain="alarm_control_panel"][data-state="triggered"] { + #{$element}[data-domain='alarm_control_panel'][data-state='triggered'] { color: var(--alarm-color-triggered, var(--label-badge-red)); animation: pulse 1s infinite; } - #{$element}[data-domain="plant"][data-state="problem"], - #{$element}[data-domain="zwave"][data-state="dead"] { + #{$element}[data-domain='plant'][data-state='problem'], + #{$element}[data-domain='zwave'][data-state='dead'] { color: var(--state-icon-error-color); } /* Color the icon if unavailable */ - #{$element}[data-state="unavailable"] { + #{$element}[data-state='unavailable'] { color: var(--state-unavailable-color); } } -@include state-icon("ha-icon"); -@include state-icon("ha-icon-button"); \ No newline at end of file +@include state-icon('ha-icon'); +@include state-icon('ha-icon-button'); diff --git a/src/scss/const.scss b/src/scss/const.scss index 4d531702..f2dac2a8 100644 --- a/src/scss/const.scss +++ b/src/scss/const.scss @@ -3,4 +3,4 @@ --frigate-card-thumbnail-details-width: calc( var(--frigate-card-thumbnail-size) + 200px ); -} \ No newline at end of file +} diff --git a/src/scss/drawer.scss b/src/scss/drawer.scss index ebbb47fc..7c100e9a 100644 --- a/src/scss/drawer.scss +++ b/src/scss/drawer.scss @@ -27,10 +27,12 @@ div.control-surround { } right: 100%; } -:host([empty]), :host([empty]) > * { +:host([empty]), +:host([empty]) > * { visibility: hidden; } -:host(:not([empty])), :host(:not([empty])) > * { +:host(:not([empty])), +:host(:not([empty])) > * { visibility: visible; } @@ -47,7 +49,8 @@ ha-icon.control { transition: opacity 0.5s ease; } -:host([open]) ha-icon.control, ha-icon.control:hover { +:host([open]) ha-icon.control, +ha-icon.control:hover { // When the drawer is open or hovered make the button to close it more // prominent. opacity: 1; diff --git a/src/scss/elements.scss b/src/scss/elements.scss index 2621cf83..b8d8d1b5 100644 --- a/src/scss/elements.scss +++ b/src/scss/elements.scss @@ -18,4 +18,4 @@ hui-error-card.element { inset: 0px; transform: unset; -} \ No newline at end of file +} diff --git a/src/scss/image.scss b/src/scss/image.scss index 954b500b..01413a0c 100644 --- a/src/scss/image.scss +++ b/src/scss/image.scss @@ -6,4 +6,4 @@ img { display: block; @include media-layout.media-layout(); -} \ No newline at end of file +} diff --git a/src/scss/key-assigner.scss b/src/scss/key-assigner.scss index 01036432..e2fa20dc 100644 --- a/src/scss/key-assigner.scss +++ b/src/scss/key-assigner.scss @@ -76,4 +76,4 @@ div.key + div.key:before { margin-right: 5px; content: ' + '; -} \ No newline at end of file +} diff --git a/src/scss/live-ha-components.scss b/src/scss/live-ha-components.scss index 2815cb6a..805422df 100644 --- a/src/scss/live-ha-components.scss +++ b/src/scss/live-ha-components.scss @@ -1,5 +1,6 @@ -@use 'media-layout.scss'; +@use 'media-layout.scss'; -img, video { +img, +video { @include media-layout.media-layout(); -} \ No newline at end of file +} diff --git a/src/scss/live-ha.scss b/src/scss/live-ha.scss index f0f64c07..9f92a4e0 100644 --- a/src/scss/live-ha.scss +++ b/src/scss/live-ha.scss @@ -2,4 +2,4 @@ width: 100%; height: 100%; display: block; -} \ No newline at end of file +} diff --git a/src/scss/media-filter.scss b/src/scss/media-filter.scss index e70f5f69..77d1741b 100644 --- a/src/scss/media-filter.scss +++ b/src/scss/media-filter.scss @@ -44,4 +44,4 @@ div.when frigate-card-date-picker.selected { } div.when frigate-card-date-picker.hidden { width: 0px; -} \ No newline at end of file +} diff --git a/src/scss/menu.scss b/src/scss/menu.scss index 45e5e6ba..9f56c136 100644 --- a/src/scss/menu.scss +++ b/src/scss/menu.scss @@ -154,7 +154,7 @@ div.opposing { ********************************************/ :host([data-style='overlay']), -:host([data-style*=hover]), +:host([data-style*='hover']), :host([data-style='hidden']) { position: absolute; overflow: hidden; diff --git a/src/scss/submenu.scss b/src/scss/submenu.scss index fe2042a5..482e4084 100644 --- a/src/scss/submenu.scss +++ b/src/scss/submenu.scss @@ -4,6 +4,6 @@ pointer-events: auto; } -mwc-list-item { +mwc-list-item { z-index: 20; } diff --git a/src/scss/thumbnail-feature-event.scss b/src/scss/thumbnail-feature-event.scss index b10149f5..ea67c4a4 100644 --- a/src/scss/thumbnail-feature-event.scss +++ b/src/scss/thumbnail-feature-event.scss @@ -14,7 +14,7 @@ img { } img, -ha-icon { +ha-icon { // Safari will occasionally not load thumbnails correctly with display block. display: inline-block; @@ -22,7 +22,10 @@ ha-icon { vertical-align: top; margin: 0; - border-radius: var(--frigate-card-css-border-radius, var(--ha-card-border-radius, 4px)); + border-radius: var( + --frigate-card-css-border-radius, + var(--ha-card-border-radius, 4px) + ); max-width: var(--frigate-card-thumbnail-size); max-height: 100%; diff --git a/src/scss/thumbnail-feature-recording.scss b/src/scss/thumbnail-feature-recording.scss index 459e3e22..1ba8675d 100644 --- a/src/scss/thumbnail-feature-recording.scss +++ b/src/scss/thumbnail-feature-recording.scss @@ -12,7 +12,10 @@ border: 1px solid var(--secondary-color); background-color: var(--secondary-background-color); - border-radius: var(--frigate-card-css-border-radius, var(--ha-card-border-radius, 4px)); + border-radius: var( + --frigate-card-css-border-radius, + var(--ha-card-border-radius, 4px) + ); box-sizing: border-box; color: var(--primary-text-color); diff --git a/src/scss/thumbnail.scss b/src/scss/thumbnail.scss index 23c56eff..a585b793 100644 --- a/src/scss/thumbnail.scss +++ b/src/scss/thumbnail.scss @@ -16,7 +16,10 @@ :host([details]) { border: 1px solid var(--primary-color); - border-radius: var(--frigate-card-css-border-radius, var(--ha-card-border-radius, 4px)); + border-radius: var( + --frigate-card-css-border-radius, + var(--ha-card-border-radius, 4px) + ); padding: 2px; // When details are enabled, use a background color so that the details have @@ -36,10 +39,12 @@ ha-icon { cursor: pointer; - transition: opacity 0.2s ease-in-out, color 0.2s ease-in-out; + transition: + opacity 0.2s ease-in-out, + color 0.2s ease-in-out; } ha-icon:hover { - opacity: 1.0; + opacity: 1; } ha-icon.star { @@ -60,6 +65,7 @@ ha-icon.download { bottom: 3px; } -frigate-card-thumbnail-details-event, frigate-card-thumbnail-details-recording { +frigate-card-thumbnail-details-event, +frigate-card-thumbnail-details-recording { flex: 1; -} \ No newline at end of file +} diff --git a/src/scss/timeline-core.scss b/src/scss/timeline-core.scss index e2bc517f..1221a39c 100644 --- a/src/scss/timeline-core.scss +++ b/src/scss/timeline-core.scss @@ -59,7 +59,9 @@ div.timeline { color: var(--primary-text-color); background-color: var(--primary-color); - transition: background-color ease-in-out 1s, border-color ease-in-out 1s, + transition: + background-color ease-in-out 1s, + border-color ease-in-out 1s, box-shadow ease-in-out 1s; } .vis-item.vis-selected { diff --git a/src/scss/viewer-provider.scss b/src/scss/viewer-provider.scss index 6e5f94e6..df186b97 100644 --- a/src/scss/viewer-provider.scss +++ b/src/scss/viewer-provider.scss @@ -19,4 +19,4 @@ frigate-card-ha-hls-player { frigate-card-progress-indicator { padding: 30px; box-sizing: border-box; -} \ No newline at end of file +} diff --git a/src/scss/viewer.scss b/src/scss/viewer.scss index 19bc1a0b..18ec3c39 100644 --- a/src/scss/viewer.scss +++ b/src/scss/viewer.scss @@ -9,4 +9,4 @@ frigate-card-viewer-carousel { flex: 1; min-height: 0; -} \ No newline at end of file +} diff --git a/src/utils/get-state-obj.ts b/src/utils/get-state-obj.ts index 1edd43e9..811ef06b 100644 --- a/src/utils/get-state-obj.ts +++ b/src/utils/get-state-obj.ts @@ -1,8 +1,8 @@ -import { HomeAssistant } from "@dermotduffy/custom-card-helpers"; -import { HassEntity } from "home-assistant-js-websocket"; -import { CameraConfig } from "../config/types.js"; -import { dispatchErrorMessageEvent } from "../components/message.js"; -import { localize } from "../localize/localize.js"; +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { HassEntity } from 'home-assistant-js-websocket'; +import { CameraConfig } from '../config/types.js'; +import { dispatchErrorMessageEvent } from '../components/message.js'; +import { localize } from '../localize/localize.js'; /** * Get the state object or dispatch an error. Used in `ha` and `image` live diff --git a/src/utils/ha/device-registry.ts b/src/utils/ha/device-registry.ts index 43e5b109..0bc1b187 100644 --- a/src/utils/ha/device-registry.ts +++ b/src/utils/ha/device-registry.ts @@ -6,7 +6,7 @@ const deviceSchema = z.object({ model: z.string().nullable(), config_entries: z.string().array(), manufacturer: z.string().nullable(), -}) +}); const deviceListSchema = deviceSchema.array(); export type DeviceList = z.infer; diff --git a/src/utils/ha/update.ts b/src/utils/ha/update.ts index f7af7974..5ede0871 100644 --- a/src/utils/ha/update.ts +++ b/src/utils/ha/update.ts @@ -1,7 +1,7 @@ import { - HassEntity, - HassEntityAttributeBase, - HassEntityBase + HassEntity, + HassEntityAttributeBase, + HassEntityBase, } from 'home-assistant-js-websocket'; const UPDATE_SUPPORT_PROGRESS = 4; diff --git a/src/utils/icons/README.md b/src/utils/icons/README.md index 89ca8032..e1501184 100644 --- a/src/utils/icons/README.md +++ b/src/utils/icons/README.md @@ -4,4 +4,4 @@ These entity icon mappings are copied (with slight tweaks to work with this card), from the [Lovelace Mushroom Card](https://github.com/piitaya/lovelace-mushroom/tree/main/src/utils/icons), which are in turn copied from [the Home Assistant frontend](https://github.com/home-assistant/frontend/tree/dev/src/common/entity) in order to replace the out of date entity icons in -[custom-card-helpers](https://github.com/custom-cards/custom-card-helpers). \ No newline at end of file +[custom-card-helpers](https://github.com/custom-cards/custom-card-helpers). diff --git a/src/utils/icons/domain-icon.ts b/src/utils/icons/domain-icon.ts index b995aa76..64dfab9a 100644 --- a/src/utils/icons/domain-icon.ts +++ b/src/utils/icons/domain-icon.ts @@ -52,7 +52,12 @@ const FIXED_DOMAIN_ICONS = { zone: 'mdi:map-marker-radius', }; -export function domainIcon(domain: string, entity?: HassEntity, state?: string, defaultIcon?: string): string { +export function domainIcon( + domain: string, + entity?: HassEntity, + state?: string, + defaultIcon?: string, +): string { switch (domain) { case 'alarm_control_panel': return alarmPanelIcon(state); diff --git a/src/utils/icons/sensor-icon.ts b/src/utils/icons/sensor-icon.ts index e9000472..efb42df6 100644 --- a/src/utils/icons/sensor-icon.ts +++ b/src/utils/icons/sensor-icon.ts @@ -70,10 +70,7 @@ const batteryStateIcon = ( return batteryIcon(battery, batteryCharging); }; -const batteryIcon = ( - batteryState: number | string, - batteryCharging?: boolean, -) => { +const batteryIcon = (batteryState: number | string, batteryCharging?: boolean) => { const batteryValue = Number(batteryState); if (isNaN(batteryValue)) { if (batteryState === 'off') { diff --git a/src/utils/media-to-view.ts b/src/utils/media-to-view.ts index 6ca25497..718f2646 100644 --- a/src/utils/media-to-view.ts +++ b/src/utils/media-to-view.ts @@ -62,7 +62,7 @@ export const changeViewToRecentEventsForCameraAndDependents = async ( targetView: options?.targetView, select: options?.select, useCache: options?.useCache, - viewContext: options?.viewContext + viewContext: options?.viewContext, }, ) )?.dispatchChangeEvent(element); @@ -201,7 +201,7 @@ export const executeMediaQueryForView = async ( camera: cameraID, }) .mergeInContext(options?.viewContext) - .mergeInContext(viewerContext) + .mergeInContext(viewerContext); }; export const executeMediaQueryForViewWithErrorDispatching = async ( diff --git a/src/view/media-queries-classifier.ts b/src/view/media-queries-classifier.ts index b63210bc..9c35cb23 100644 --- a/src/view/media-queries-classifier.ts +++ b/src/view/media-queries-classifier.ts @@ -18,7 +18,7 @@ export class MediaQueriesClassifier { return this.areEventQueries(queries) ? 'event' : this.areRecordingQueries(queries) - ? 'recording' - : null; + ? 'recording' + : null; } } diff --git a/src/view/media-queries-results.ts b/src/view/media-queries-results.ts index f3d2588d..3115bfac 100644 --- a/src/view/media-queries-results.ts +++ b/src/view/media-queries-results.ts @@ -246,8 +246,8 @@ export class MediaQueriesResults { return criteria?.allCameras ? this.getCameraIDs() : criteria?.cameraID - ? new Set([criteria.cameraID]) - : null; + ? new Set([criteria.cameraID]) + : null; } public selectResultIfFound( diff --git a/src/view/view-to-cameras.ts b/src/view/view-to-cameras.ts index 3f669277..449f13f7 100644 --- a/src/view/view-to-cameras.ts +++ b/src/view/view-to-cameras.ts @@ -26,10 +26,10 @@ export const getCameraIDsForViewName = ( viewName === 'clip' ? 'clips' : viewName === 'snapshot' - ? 'snapshots' - : viewName === 'recording' - ? 'recordings' - : viewName; + ? 'snapshots' + : viewName === 'recording' + ? 'recordings' + : viewName; return cameraID ? cameraManager.getStore().getAllDependentCameras(cameraID, capability) : cameraManager.getStore().getCameraIDsWithCapability(capability); diff --git a/src/view/view.ts b/src/view/view.ts index dd9b0ed8..918ff818 100644 --- a/src/view/view.ts +++ b/src/view/view.ts @@ -64,7 +64,7 @@ export class View { } public static adoptFromViewIfAppropriate(next: View, curr?: View | null): void { - if (!curr) { + if (!curr) { return; } @@ -121,8 +121,8 @@ export class View { currentQueriesView === 'clips' ? 'clip' : currentQueriesView === 'snapshots' - ? 'snapshot' - : 'recording'; + ? 'snapshot' + : 'recording'; } } diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts index ee9b53bc..de95a742 100644 --- a/tests/camera-manager/manager.test.ts +++ b/tests/camera-manager/manager.test.ts @@ -1125,7 +1125,7 @@ describe('CameraManager', async () => { const action = { action: 'call-service' as const, service: 'service', - } + }; const manager = createCameraManager(api, engine, [ { config: createCameraConfig({ diff --git a/tests/camera-manager/utils/ptz.test.ts b/tests/camera-manager/utils/ptz.test.ts index 44788a86..32470596 100644 --- a/tests/camera-manager/utils/ptz.test.ts +++ b/tests/camera-manager/utils/ptz.test.ts @@ -43,7 +43,7 @@ describe('getConfiguredPTZAction', () => { createCameraConfig({ ptz: { presets: { - window: action + window: action, }, }, }), diff --git a/tests/card-controller/actions/actions-manager.test.ts b/tests/card-controller/actions/actions-manager.test.ts index 8da0dde3..32bd5c82 100644 --- a/tests/card-controller/actions/actions-manager.test.ts +++ b/tests/card-controller/actions/actions-manager.test.ts @@ -145,7 +145,7 @@ describe('ActionsManager', () => { createConfig({ view: { actions: { - tap_action: createLogAction("Hello, world!"), + tap_action: createLogAction('Hello, world!'), }, }, }), @@ -174,7 +174,7 @@ describe('ActionsManager', () => { createConfig({ view: { actions: { - tap_action: createLogAction("Hello, world!"), + tap_action: createLogAction('Hello, world!'), }, }, }), @@ -202,7 +202,7 @@ describe('ActionsManager', () => { }); it('should handle event', () => { - const action = createLogAction("Hello, world!"); + const action = createLogAction('Hello, world!'); const event = new CustomEvent('ll-custom', { detail: action, }); @@ -232,7 +232,7 @@ describe('ActionsManager', () => { const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined); await manager.handleActionExecutionRequestEvent( new CustomEvent('frigate-card:action:execution-request', { - detail: { action: createLogAction("Hello, world!") }, + detail: { action: createLogAction('Hello, world!') }, }), ); expect(consoleSpy).toBeCalled(); @@ -245,7 +245,7 @@ describe('ActionsManager', () => { const manager = new ActionsManager(api); const consoleSpy = vi.spyOn(global.console, 'info').mockReturnValue(undefined); - await manager.executeActions(createLogAction("Hello, world!")); + await manager.executeActions(createLogAction('Hello, world!')); expect(consoleSpy).toBeCalled(); }); }); @@ -271,7 +271,7 @@ describe('ActionsManager', () => { m: 1, }, })!, - createLogAction("Hello, world!"), + createLogAction('Hello, world!'), ]); // Stop inflight actions. diff --git a/tests/card-controller/actions/actions/default.test.ts b/tests/card-controller/actions/actions/default.test.ts index ac9692c8..2527aa8a 100644 --- a/tests/card-controller/actions/actions/default.test.ts +++ b/tests/card-controller/actions/actions/default.test.ts @@ -1,13 +1,16 @@ -import { expect, it } from "vitest"; -import { DefaultAction } from "../../../../src/card-controller/actions/actions/default"; -import { createCardAPI } from "../../../test-utils"; +import { expect, it } from 'vitest'; +import { DefaultAction } from '../../../../src/card-controller/actions/actions/default'; +import { createCardAPI } from '../../../test-utils'; it('should handle default action', async () => { const api = createCardAPI(); - const action = new DefaultAction({}, { - action: 'fire-dom-event', - frigate_card_action: 'default', - }); + const action = new DefaultAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'default', + }, + ); await action.execute(api); diff --git a/tests/card-controller/actions/actions/display-mode-select.test.ts b/tests/card-controller/actions/actions/display-mode-select.test.ts index 1e999a8b..57da6936 100644 --- a/tests/card-controller/actions/actions/display-mode-select.test.ts +++ b/tests/card-controller/actions/actions/display-mode-select.test.ts @@ -1,14 +1,17 @@ -import { expect, it } from "vitest"; -import { DisplayModeSelectAction } from "../../../../src/card-controller/actions/actions/display-mode-select"; -import { createCardAPI } from "../../../test-utils"; +import { expect, it } from 'vitest'; +import { DisplayModeSelectAction } from '../../../../src/card-controller/actions/actions/display-mode-select'; +import { createCardAPI } from '../../../test-utils'; it('should handle default action', async () => { const api = createCardAPI(); - const action = new DisplayModeSelectAction({}, { - action: 'fire-dom-event', - frigate_card_action: 'display_mode_select', - display_mode: 'grid', - }); + const action = new DisplayModeSelectAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'display_mode_select', + display_mode: 'grid', + }, + ); await action.execute(api); diff --git a/tests/card-controller/actions/actions/ptz.test.ts b/tests/card-controller/actions/actions/ptz.test.ts index 7217d4d8..4743089d 100644 --- a/tests/card-controller/actions/actions/ptz.test.ts +++ b/tests/card-controller/actions/actions/ptz.test.ts @@ -430,15 +430,12 @@ describe('should handle ptz action', () => { ); const context = {}; - const startAction = new PTZAction( - context, - { - action: 'fire-dom-event', - frigate_card_action: 'ptz', - ptz_action: 'left', - ptz_phase: 'start', - }, - ); + const startAction = new PTZAction(context, { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + ptz_phase: 'start', + }); await startAction.execute(api); expect(api.getCameraManager().executePTZAction).toBeCalledWith( @@ -450,25 +447,22 @@ describe('should handle ptz action', () => { ); expect(api.getCameraManager().executePTZAction).toBeCalledTimes(1); - await vi.runOnlyPendingTimersAsync() + await vi.runOnlyPendingTimersAsync(); expect(api.getCameraManager().executePTZAction).toBeCalledTimes(2); - await vi.runOnlyPendingTimersAsync() + await vi.runOnlyPendingTimersAsync(); expect(api.getCameraManager().executePTZAction).toBeCalledTimes(3); - const stopAction = new PTZAction( - context, - { - action: 'fire-dom-event', - frigate_card_action: 'ptz', - ptz_action: 'left', - ptz_phase: 'stop', - }, - ); + const stopAction = new PTZAction(context, { + action: 'fire-dom-event', + frigate_card_action: 'ptz', + ptz_action: 'left', + ptz_phase: 'stop', + }); await stopAction.execute(api); // There should be no additional calls. - await vi.runOnlyPendingTimersAsync() + await vi.runOnlyPendingTimersAsync(); expect(api.getCameraManager().executePTZAction).toBeCalledTimes(3); }); @@ -500,11 +494,11 @@ describe('should handle ptz action', () => { await action.execute(api); expect(api.getCameraManager().executePTZAction).toBeCalledTimes(1); - await vi.runOnlyPendingTimersAsync() + await vi.runOnlyPendingTimersAsync(); expect(api.getCameraManager().executePTZAction).toBeCalledTimes(2); action.stop(); - await vi.runOnlyPendingTimersAsync() + await vi.runOnlyPendingTimersAsync(); // There should be no additional calls. expect(api.getCameraManager().executePTZAction).toBeCalledTimes(2); diff --git a/tests/card-controller/actions/actions/sleep.test.ts b/tests/card-controller/actions/actions/sleep.test.ts index 0515b45a..b9e3efb7 100644 --- a/tests/card-controller/actions/actions/sleep.test.ts +++ b/tests/card-controller/actions/actions/sleep.test.ts @@ -18,7 +18,7 @@ it('should handle sleep action', async () => { frigate_card_action: 'sleep', duration: { s: 5, - ms: 200 + ms: 200, }, }, ); diff --git a/tests/card-controller/camera-url-manager.test.ts b/tests/card-controller/camera-url-manager.test.ts index 881af96a..ccb95401 100644 --- a/tests/card-controller/camera-url-manager.test.ts +++ b/tests/card-controller/camera-url-manager.test.ts @@ -1,16 +1,12 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { CameraEndpoint } from '../../src/camera-manager/types'; import { CameraURLManager } from '../../src/card-controller/camera-url-manager'; -import { - CardCameraURLAPI -} from '../../src/card-controller/types'; +import { CardCameraURLAPI } from '../../src/card-controller/types'; import { createCardAPI, createViewWithMedia } from '../test-utils'; const createAPIWithMedia = (): CardCameraURLAPI => { const api = createCardAPI(); - vi.mocked(api.getViewManager().getView).mockReturnValue( - createViewWithMedia() - ) + vi.mocked(api.getViewManager().getView).mockReturnValue(createViewWithMedia()); return api; }; diff --git a/tests/card-controller/fullscreen-manager.test.ts b/tests/card-controller/fullscreen-manager.test.ts index ba0d3f6c..7615811e 100644 --- a/tests/card-controller/fullscreen-manager.test.ts +++ b/tests/card-controller/fullscreen-manager.test.ts @@ -53,11 +53,9 @@ describe('FullscreenManager', () => { it('should toggle fullscreen', () => { const toggle = vi.mocked(screenfull.toggle); - const element = document.createElement('div') + const element = document.createElement('div'); const api = createCardAPI(); - vi.mocked(api.getCardElementManager().getElement).mockReturnValue( - element, - ); + vi.mocked(api.getCardElementManager().getElement).mockReturnValue(element); const manager = new FullscreenManager(api); manager.toggleFullscreen(); diff --git a/tests/config/management.test.ts b/tests/config/management.test.ts index 0b5df517..bd9cfbcb 100644 --- a/tests/config/management.test.ts +++ b/tests/config/management.test.ts @@ -3098,7 +3098,6 @@ describe('should handle version specific upgrades', () => { ); postUpgradeChecks(config); }); - }); }); }); diff --git a/tests/utils/embla/test-utils.ts b/tests/utils/embla/test-utils.ts index 66aee8a8..4aad2d0f 100644 --- a/tests/utils/embla/test-utils.ts +++ b/tests/utils/embla/test-utils.ts @@ -81,7 +81,7 @@ export const callResizeHandler = ( height: entry.height, width: entry.width, }, - } as unknown as ResizeObserverEntry), + }) as unknown as ResizeObserverEntry, ), observer, ); @@ -109,10 +109,6 @@ export const createEmblaApiInstance = (options?: { return emblaApi; }; -export const createTestSlideNodes = (options?: { - n?: number; -}): HTMLElement[] => { - return [...Array(options?.n ?? 10).keys()].map((_) => - document.createElement('div'), - ); +export const createTestSlideNodes = (options?: { n?: number }): HTMLElement[] => { + return [...Array(options?.n ?? 10).keys()].map((_) => document.createElement('div')); }; diff --git a/tests/utils/substream.test.ts b/tests/utils/substream.test.ts index b36acfe4..a9d1ea88 100644 --- a/tests/utils/substream.test.ts +++ b/tests/utils/substream.test.ts @@ -43,7 +43,10 @@ describe('hasSubstream/getStreamCameraID', () => { camera: 'camera', context: { live: { - overrides: new Map([['camera', 'camera2'], ['camera3', 'camera4']]), + overrides: new Map([ + ['camera', 'camera2'], + ['camera3', 'camera4'], + ]), }, }, }); diff --git a/tests/view/media.test.ts b/tests/view/media.test.ts index 7aaa8131..397414f1 100644 --- a/tests/view/media.test.ts +++ b/tests/view/media.test.ts @@ -46,7 +46,7 @@ describe('ViewMedia', () => { const fakeNow = new Date('2023-08-08T17:15:00'); vi.setSystemTime(fakeNow); - expect(media.getUsableEndTime()).toEqual(fakeNow) + expect(media.getUsableEndTime()).toEqual(fakeNow); }); }); diff --git a/yarn.lock b/yarn.lock index 3c4d113b..c6260fc8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3365,14 +3365,14 @@ __metadata: languageName: node linkType: hard -"eslint-config-prettier@npm:^8.5.0": - version: 8.10.0 - resolution: "eslint-config-prettier@npm:8.10.0" +"eslint-config-prettier@npm:^9.1.0": + version: 9.1.0 + resolution: "eslint-config-prettier@npm:9.1.0" peerDependencies: eslint: ">=7.0.0" bin: eslint-config-prettier: bin/cli.js - checksum: 10c0/19f8c497d9bdc111a17a61b25ded97217be3755bbc4714477dfe535ed539dddcaf42ef5cf8bb97908b058260cf89a3d7c565cb0be31096cbcd39f4c2fa5fe43c + checksum: 10c0/6d332694b36bc9ac6fdb18d3ca2f6ac42afa2ad61f0493e89226950a7091e38981b66bac2b47ba39d15b73fff2cd32c78b850a9cf9eed9ca9a96bfb2f3a2f10d languageName: node linkType: hard @@ -3426,21 +3426,6 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-prettier@npm:^4.2.1": - version: 4.2.1 - resolution: "eslint-plugin-prettier@npm:4.2.1" - dependencies: - prettier-linter-helpers: "npm:^1.0.0" - peerDependencies: - eslint: ">=7.28.0" - prettier: ">=2.0.0" - peerDependenciesMeta: - eslint-config-prettier: - optional: true - checksum: 10c0/c5e7316baeab9d96ac39c279f16686e837277e5c67a8006c6588bcff317edffdc1532fb580441eb598bc6770f6444006756b68a6575dff1cd85ebe227252d0b7 - languageName: node - linkType: hard - "eslint-scope@npm:^7.2.2": version: 7.2.2 resolution: "eslint-scope@npm:7.2.2" @@ -3641,13 +3626,6 @@ __metadata: languageName: node linkType: hard -"fast-diff@npm:^1.1.2": - version: 1.3.0 - resolution: "fast-diff@npm:1.3.0" - checksum: 10c0/5c19af237edb5d5effda008c891a18a585f74bf12953be57923f17a3a4d0979565fc64dbc73b9e20926b9d895f5b690c618cbb969af0cf022e3222471220ad29 - languageName: node - linkType: hard - "fast-glob@npm:^3.2.7, fast-glob@npm:^3.2.9": version: 3.3.2 resolution: "fast-glob@npm:3.3.2" @@ -3853,9 +3831,8 @@ __metadata: embla-carousel-wheel-gestures: "npm:8.0.0-rc04" eslint: "npm:^8.57.0" eslint-config-airbnb-base: "npm:^15.0.0" - eslint-config-prettier: "npm:^8.5.0" + eslint-config-prettier: "npm:^9.1.0" eslint-plugin-import: "npm:^2.25.4" - eslint-plugin-prettier: "npm:^4.2.1" home-assistant-js-websocket: "npm:^8.0.0" jsdom: "npm:^21.1.1" keycharm: "npm:^0.4.0" @@ -3865,7 +3842,7 @@ __metadata: masonry-layout: "npm:^4.2.2" moment: "npm:^2.29.4" p-queue: "npm:^8.0.1" - prettier: "npm:^2.6.0" + prettier: "npm:^3.3.1" propagating-hammerjs: "npm:^2.0.1" quick-lru: "npm:^6.1.0" rollup: "npm:^2.79.0" @@ -6836,21 +6813,12 @@ __metadata: languageName: node linkType: hard -"prettier-linter-helpers@npm:^1.0.0": - version: 1.0.0 - resolution: "prettier-linter-helpers@npm:1.0.0" - dependencies: - fast-diff: "npm:^1.1.2" - checksum: 10c0/81e0027d731b7b3697ccd2129470ed9913ecb111e4ec175a12f0fcfab0096516373bf0af2fef132af50cafb0a905b74ff57996d615f59512bb9ac7378fcc64ab - languageName: node - linkType: hard - -"prettier@npm:^2.6.0": - version: 2.8.8 - resolution: "prettier@npm:2.8.8" +"prettier@npm:^3.3.1": + version: 3.3.1 + resolution: "prettier@npm:3.3.1" bin: - prettier: bin-prettier.js - checksum: 10c0/463ea8f9a0946cd5b828d8cf27bd8b567345cf02f56562d5ecde198b91f47a76b7ac9eae0facd247ace70e927143af6135e8cf411986b8cb8478784a4d6d724a + prettier: bin/prettier.cjs + checksum: 10c0/c25a709c9f0be670dc6bcb190b622347e1dbeb6c3e7df8b0711724cb64d8647c60b839937a4df4df18e9cfb556c2b08ca9d24d9645eb5488a7fc032a2c4d5cb3 languageName: node linkType: hard From 91b0909614b5a29af04dd6542a4b135e2ae1b5be Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Mon, 10 Jun 2024 00:49:57 -0300 Subject: [PATCH 147/189] Fix some broken formatting in the docs --- docs/configuration/actions/custom/README.md | 22 ++++----- docs/configuration/actions/stock/README.md | 10 ++-- docs/configuration/cameras/README.md | 27 +++++++---- docs/configuration/cameras/engine.md | 12 +++-- docs/configuration/cameras/live-provider.md | 12 +++-- docs/configuration/conditions.md | 26 +++++------ docs/configuration/dimensions.md | 3 +- docs/configuration/elements.md | 52 ++++++++++----------- docs/configuration/image.md | 3 +- docs/configuration/live.md | 24 ++++++---- docs/configuration/media-gallery.md | 9 ++-- docs/configuration/media-viewer.md | 24 ++++++---- docs/configuration/menu.md | 6 ++- docs/configuration/overrides.md | 37 +++++++++------ docs/configuration/performance.md | 9 ++-- docs/configuration/timeline.md | 9 ++-- docs/configuration/view.md | 6 ++- 17 files changed, 175 insertions(+), 116 deletions(-) diff --git a/docs/configuration/actions/custom/README.md b/docs/configuration/actions/custom/README.md index ba8a7c86..15fb42f4 100644 --- a/docs/configuration/actions/custom/README.md +++ b/docs/configuration/actions/custom/README.md @@ -4,7 +4,7 @@ Execute a Frigate Card action. ```yaml action: custom:frigate-card-action -[...] +# [...] ``` | Parameter | Description | @@ -19,7 +19,7 @@ Select a given camera. ```yaml action: custom:frigate-card-action frigate_card_action: camera_select -[...] +# [...] ``` | Parameter | Description | @@ -49,7 +49,7 @@ Zoom in and/or pan for a given camera. ```yaml action: custom:frigate-card-action frigate_card_action: change_zoom -[...] +# [...] ``` | Parameter | Description | @@ -107,7 +107,7 @@ Select a display mode (e.g. view a `single` camera or a `grid` of cameras). ```yaml action: custom:frigate-card-action frigate_card_action: display_mode_select -[...] +# [...] ``` | Parameter | Description | @@ -196,7 +196,7 @@ Select a substream. Use [Camera dependency configuration](../../cameras/README.m ```yaml action: custom:frigate-card-action frigate_card_action: live_substream_select -[...] +# [...] ``` | Parameter | Description | @@ -212,7 +212,7 @@ Log a message to the Javascript console. ```yaml action: custom:frigate-card-action frigate_card_action: log -[...] +# [...] ``` | Parameter | Default | Description | @@ -229,7 +229,7 @@ Perform a media player action. ```yaml action: custom:frigate-card-action frigate_card_action: media_player -[...] +# [...] ``` | Parameter | Description | @@ -300,7 +300,7 @@ Execute a real PTZ action, whether configured manually (see [Camera PTZ configur ```yaml action: custom:frigate-card-action frigate_card_action: ptz -[...] +# [...] ``` | Parameter | | Description | @@ -321,7 +321,7 @@ Show or hide the PTZ controls. ```yaml action: custom:frigate-card-action frigate_card_action: ptz_controls -[...] +# [...] ``` | Parameter | Description | @@ -337,7 +337,7 @@ Execute a digital PTZ action. ```yaml action: custom:frigate-card-action frigate_card_action: ptz-digital -[...] +# [...] ``` | Parameter | Default | Description | @@ -373,7 +373,7 @@ action), otherwise a digital PTZ action will be run (equivalent to using the ```yaml action: custom:frigate-card-action frigate_card_action: ptz-multi -[...] +# [...] ``` | Parameter | Description | diff --git a/docs/configuration/actions/stock/README.md b/docs/configuration/actions/stock/README.md index 6fdcfd03..d8458d03 100644 --- a/docs/configuration/actions/stock/README.md +++ b/docs/configuration/actions/stock/README.md @@ -6,7 +6,7 @@ Call a service. See [Home Assistant actions documentation](https://www.home-assi ```yaml action: call-service -[...] +# [...] ``` ## `more-info` @@ -15,7 +15,7 @@ Open the "more-info" dialog for an entity. See [Home Assistant actions documenta ```yaml action: more-info -[...] +# [...] ``` ## `navigate` @@ -24,7 +24,7 @@ Navigate to a particular dashboard path. See [Home Assistant actions documentati ```yaml action: navigate -[...] +# [...] ``` ## `toggle` @@ -33,7 +33,7 @@ Toggle an entity. See [Home Assistant actions documentation](https://www.home-as ```yaml action: toggle -[...] +# [...] ``` ## `url` @@ -42,7 +42,7 @@ Navigate to an arbitrary URL. See [Home Assistant actions documentation](https:/ ```yaml action: url -[...] +# [...] ``` ## Fully expanded reference diff --git a/docs/configuration/cameras/README.md b/docs/configuration/cameras/README.md index 51ced51e..e1da9a0c 100644 --- a/docs/configuration/cameras/README.md +++ b/docs/configuration/cameras/README.md @@ -12,7 +12,8 @@ cameras: The `cameras_global` block can be used to set defaults across multiple cameras. ```yaml -cameras_global: [...] +cameras_global: + # [...] ``` | Option | Default | Description | @@ -38,7 +39,8 @@ The `capabilities` block allows selected disabling of auto-detected camera capab ```yaml cameras: - camera_entity: camera.office - capabilities: [...] + capabilities: + # [...] ``` | Option | Default | Description | @@ -68,7 +70,8 @@ The `cast` block configures how a camera is cast / sent to media players. ```yaml cameras: - camera_entity: camera.office - cast: [...] + cast: + # [...] ``` | Option | Default | Description | @@ -84,7 +87,8 @@ See the [dashboard method cast example](../../examples.md?id=cast-a-dashboard). cameras: - camera_entity: camera.office cast: - dashboard: [...] + dashboard: + # [...] ``` | Option | Default | Description | @@ -99,7 +103,8 @@ The `dependencies` block configures other cameras as dependents of this camera. ```yaml cameras: - camera_entity: camera.office - dependencies: [...] + dependencies: + # [...] ``` | Option | Default | Description | @@ -114,7 +119,8 @@ The `dimensions` block configures the dimensions and layout of media of a given ```yaml cameras: - camera_entity: camera.office - dimensions: [...] + dimensions: + # [...] ``` | Option | Default | Description | @@ -130,7 +136,8 @@ The `layout` block configures the fit and position of the media _within_ the cam cameras: - camera_entity: camera.office dimensions: - layout: [...] + layout: + # [...] ``` | Option | Default | Description | @@ -174,7 +181,8 @@ Configure the PTZ actions taken for a camera (not to be confused with configurat ```yaml cameras: - camera_entity: camera.office - ptz: [...] + ptz: + # [...] ``` ### Movement types @@ -236,7 +244,8 @@ camera is triggered. ```yaml cameras: - camera_entity: camera.office - triggers: [...] + triggers: + # [...] ``` | Option | Default | Description | diff --git a/docs/configuration/cameras/engine.md b/docs/configuration/cameras/engine.md index dab970e1..dcf80892 100644 --- a/docs/configuration/cameras/engine.md +++ b/docs/configuration/cameras/engine.md @@ -27,7 +27,8 @@ The `frigate` block configures options for a Frigate camera. ```yaml cameras: - camera_entity: camera.office - frigate: [...] + frigate: + # [...] ``` | Option | Default | Description | @@ -45,7 +46,8 @@ The `motioneye` block configures options for a MotionEye camera. ```yaml cameras: - camera_entity: camera.office - motioneye: [...] + motioneye: + # [...] ``` | Option | Default | Description | @@ -62,14 +64,16 @@ The `images` and `movies` block configures how images and movies respectively ar cameras: - camera_entity: camera.office motioneye: - images: [...] + images: + # [...] ``` ```yaml cameras: - camera_entity: camera.office motioneye: - movies: [...] + movies: + # [...] ``` | Option | Default | Description | diff --git a/docs/configuration/cameras/live-provider.md b/docs/configuration/cameras/live-provider.md index 03604627..a9b01412 100644 --- a/docs/configuration/cameras/live-provider.md +++ b/docs/configuration/cameras/live-provider.md @@ -22,7 +22,8 @@ The `go2rtc` block configures use of the `go2rtc` live provider. This configurat cameras: - camera_entity: camera.office live_provider: go2rtc - go2rtc: [...] + go2rtc: + # [...] ``` | Option | Default | Description | @@ -39,7 +40,8 @@ All configuration is under: cameras: - camera_entity: camera.office live_provider: image - image: [...] + image: + # [...] ``` | Option | Default | Description | @@ -55,7 +57,8 @@ All configuration is under: cameras: - camera_entity: camera.office live_provider: jsmpeg - jsmpeg: [...] + jsmpeg: + # [...] ``` | Option | Default | Description | @@ -72,7 +75,8 @@ events/snapshots/UI. AlexxIT's WebRTC Integration/Card must be installed and con cameras: - camera_entity: camera.office live_provider: webrtc-card - webrtc_card: [...] + webrtc_card: + # [...] ``` | Option | Default | Description | diff --git a/docs/configuration/conditions.md b/docs/configuration/conditions.md index 8555e1f3..855695c4 100644 --- a/docs/configuration/conditions.md +++ b/docs/configuration/conditions.md @@ -19,7 +19,7 @@ certain configurations (in `overrides`) or to display "picture elements" (in ```yaml conditions: - condition: camera - [...] + # [...] ``` | Parameter | Description | @@ -32,7 +32,7 @@ conditions: ```yaml conditions: - condition: expand - [...] + # [...] ``` | Parameter | Description | @@ -45,7 +45,7 @@ conditions: ```yaml conditions: - condition: fullscreen - [...] + # [...] ``` | Parameter | Description | @@ -58,7 +58,7 @@ conditions: ```yaml conditions: - condition: interaction - [...] + # [...] ``` | Parameter | Description | @@ -71,7 +71,7 @@ conditions: ```yaml conditions: - condition: key - [...] + # [...] ``` | Parameter | Default | Description | @@ -89,7 +89,7 @@ conditions: ```yaml conditions: - condition: media_loaded - [...] + # [...] ``` | Parameter | Description | @@ -102,7 +102,7 @@ conditions: ```yaml conditions: - condition: microphone - [...] + # [...] ``` | Parameter | Description | @@ -116,7 +116,7 @@ conditions: ```yaml conditions: - condition: numeric_state - [...] + # [...] ``` This stock Home Assistant condition works out of the box. See [Home Assistant conditions documentation](https://www.home-assistant.io/dashboards/conditional/#numeric-state). @@ -126,7 +126,7 @@ This stock Home Assistant condition works out of the box. See [Home Assistant co ```yaml conditions: - condition: screen - [...] + # [...] ``` | Parameter | Description | @@ -141,7 +141,7 @@ See the [screen conditions examples](../examples.md?id=screen-conditions). ```yaml conditions: - condition: state - [...] + # [...] ``` This stock Home Assistant condition works out of the box. See [Home Assistant conditions documentation](https://www.home-assistant.io/dashboards/conditional/#state). @@ -151,7 +151,7 @@ This stock Home Assistant condition works out of the box. See [Home Assistant co ```yaml conditions: - condition: triggered - [...] + # [...] ``` | Parameter | Description | @@ -164,7 +164,7 @@ conditions: ```yaml conditions: - condition: user - [...] + # [...] ``` This stock Home Assistant condition works out of the box. See [Home Assistant conditions documentation](https://www.home-assistant.io/dashboards/conditional/#user). @@ -174,7 +174,7 @@ This stock Home Assistant condition works out of the box. See [Home Assistant co ```yaml conditions: - condition: view - [...] + # [...] ``` | Parameter | Description | diff --git a/docs/configuration/dimensions.md b/docs/configuration/dimensions.md index 3a74d5c3..a499c558 100644 --- a/docs/configuration/dimensions.md +++ b/docs/configuration/dimensions.md @@ -9,7 +9,8 @@ expanded (popup/dialog mode) the aspect ratio is chosen dynamically to maximize the amount of content shown. ```yaml -dimensions: [...] +dimensions: + # [...] ``` | Option | Default | Description | diff --git a/docs/configuration/elements.md b/docs/configuration/elements.md index 87606c68..a3caf508 100644 --- a/docs/configuration/elements.md +++ b/docs/configuration/elements.md @@ -20,8 +20,8 @@ This element will let you show its sub-elements based on entity states. See [Hom ```yaml elements: - - type: conditional - [...] + - type: conditional + # [...] ``` ## `custom` @@ -30,8 +30,8 @@ Custom elements provided by a card. See [Home Assistant elements documentation]( ```yaml elements: - - type: custom - [...] + - type: custom + # [...] ``` ## `custom:frigate-card-menu-icon` @@ -40,8 +40,8 @@ Add an arbitrary icon to the Frigate Card menu. Configuration is ~identical to t ```yaml elements: - - type: custom:frigate-card-menu-icon - [...] + - type: custom:frigate-card-menu-icon + # [...] ``` ## `custom:frigate-card-menu-state-icon` @@ -50,8 +50,8 @@ Add a state icon to the Frigate Card menu that represents the state of a Home As ```yaml elements: - - type: custom:frigate-card-menu-icon - [...] + - type: custom:frigate-card-menu-icon + # [...] ``` ## `custom:frigate-card-menu-submenu` @@ -60,8 +60,8 @@ Add a configurable submenu dropdown. ```yaml elements: - - type: custom:frigate-card-menu-submenu - [...] + - type: custom:frigate-card-menu-submenu + # [...] ``` Parameters for this element are identical to the parameters of the [stock Home Assistant Icon Element](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) with the exception of these parameters which differ: @@ -90,8 +90,8 @@ Add a submenu based on a `select` or `input_select`. This element allows you to ```yaml elements: - - type: custom:frigate-card-menu-submenu-select - [...] + - type: custom:frigate-card-menu-submenu-select + # [...] ``` Parameters for the `custom:frigate-card-menu-submenu-select` element are identical to the parameters of the [stock Home Assistant State Icon Element](https://www.home-assistant.io/dashboards/picture-elements/#state-icon) with the exception of these parameters which differ: @@ -109,8 +109,8 @@ Restrict a set of elements to only render when the card is matches a set of [con ```yaml elements: - - type: custom:frigate-card-conditional - [...] + - type: custom:frigate-card-conditional + # [...] ``` Parameters for the `custom:frigate-card-conditional` element: @@ -129,8 +129,8 @@ This element creates a static icon that is not linked to the state of an entity. ```yaml elements: - - type: icon - [...] + - type: icon + # [...] ``` ## `image` @@ -139,8 +139,8 @@ This creates an image element that overlays the background image. See [Home Assi ```yaml elements: - - type: image - [...] + - type: image + # [...] ``` ## `service-button` @@ -149,8 +149,8 @@ This entity creates a button (with arbitrary text) that can be used to call a se ```yaml elements: - - type: service-button - [...] + - type: service-button + # [...] ``` ## `state-badge` @@ -159,8 +159,8 @@ This element creates a badge representing the state of an entity. See [Home Assi ```yaml elements: - - type: state-badge - [...] + - type: state-badge + # [...] ``` ## `state-icon` @@ -169,8 +169,8 @@ This element represents an entity state using an icon. See [Home Assistant eleme ```yaml elements: - - type: state-icon - [...] + - type: state-icon + # [...] ``` ## `state-label` @@ -179,8 +179,8 @@ This element represents an entity’s state via text. See [Home Assistant elemen ```yaml elements: - - type: state-label - [...] + - type: state-label + # [...] ``` ## Fully expanded reference diff --git a/docs/configuration/image.md b/docs/configuration/image.md index 273bd767..9141db6d 100644 --- a/docs/configuration/image.md +++ b/docs/configuration/image.md @@ -3,7 +3,8 @@ Configure the `image` view. ```yaml -image: [...] +image: + # [...] ``` | Option | Default | Description | diff --git a/docs/configuration/live.md b/docs/configuration/live.md index 777c6753..b22e29c2 100644 --- a/docs/configuration/live.md +++ b/docs/configuration/live.md @@ -3,7 +3,8 @@ Configures the behavior of the `live` view. ```yaml -live: [...] +live: + # [...] ``` | Option | Default | Description | @@ -30,7 +31,8 @@ Configure the controls for the `live` view. ```yaml live: - controls: [...] + controls: + # [...] ``` | Option | Default | Description | @@ -48,7 +50,8 @@ Configures how the "Next & Previous" controls are shown on the live view. ```yaml live: controls: - next_previous: [...] + next_previous: + # [...] ``` | Option | Default | Description | @@ -63,7 +66,8 @@ Configures the PTZ (Pan Tilt Zoom) controls. ```yaml live: controls: - ptz: [...] + ptz: + # [...] ``` | Option | Default | Description | @@ -85,7 +89,8 @@ Configures how thumbnails are shown on the live view. ```yaml live: controls: - thumbnails: [...] + thumbnails: + # [...] ``` | Option | Default | Description | @@ -106,7 +111,8 @@ Configures how the mini-timeline is shown on the live view. ```yaml live: controls: - timeline: [...] + timeline: + # [...] ``` | Option | Default | Description | @@ -128,7 +134,8 @@ Configures how the camera title is shown on the live view. ```yaml live: controls: - title: [...] + title: + # [...] ``` | Option | Default | Description | @@ -142,7 +149,8 @@ Controls whether to show a single or grid `live` view. ```yaml live: - display: [...] + display: + # [...] ``` | Option | Default | Description | diff --git a/docs/configuration/media-gallery.md b/docs/configuration/media-gallery.md index 34a6d4af..d04bb9b8 100644 --- a/docs/configuration/media-gallery.md +++ b/docs/configuration/media-gallery.md @@ -3,7 +3,8 @@ The `media_gallery` is used for providing an overview of all `clips`, `snapshots` and `recordings` in a thumbnail gallery. ```yaml -media_gallery: [...] +media_gallery: + # [...] ``` | Option | Default | Description | @@ -20,7 +21,8 @@ Configure the media gallery filter. ```yaml media_gallery: controls: - filter: [...] + filter: + # [...] ``` | Option | Default | Description | @@ -34,7 +36,8 @@ Configure the media gallery thumbnails. ```yaml media_gallery: controls: - thumbnails: [...] + thumbnails: + # [...] ``` | Option | Default | Description | diff --git a/docs/configuration/media-viewer.md b/docs/configuration/media-viewer.md index beb3e800..049df860 100644 --- a/docs/configuration/media-viewer.md +++ b/docs/configuration/media-viewer.md @@ -3,7 +3,8 @@ The `media_player` section configures viewing all `clip`, `snapshot` or `recording` media, in either a media carousel or grid. ```yaml -media_viewer: [...] +media_viewer: + # [...] ``` | Option | Default | Description | @@ -26,7 +27,8 @@ Configure the controls for the media player views. ```yaml media_viewer: - controls: [...] + controls: + # [...] ``` | Option | Default | Description | @@ -44,7 +46,8 @@ Configures how the "Next & Previous" controls are shown on the media viewer. ```yaml media_viewer: controls: - next_previous: [...] + next_previous: + # [...] ``` | Option | Default | Description | @@ -61,7 +64,8 @@ real) panning and zooming. ```yaml media_viewer: controls: - ptz: [...] + ptz: + # [...] ``` | Option | Default | Description | @@ -81,7 +85,8 @@ Configures how thumbnails are shown on the media viewer. ```yaml media_viewer: controls: - thumbnails: [...] + thumbnails: + # [...] ``` | Option | Default | Description | @@ -100,7 +105,8 @@ Configures how the mini-timeline is shown on the media viewer. ```yaml media_viewer: controls: - timeline: [...] + timeline: + # [...] ``` | Option | Default | Description | @@ -122,7 +128,8 @@ Configures how the media title is shown on the media viewer. ```yaml media_viewer: controls: - title: [...] + title: + # [...] ``` | Option | Default | Description | @@ -136,7 +143,8 @@ Controls whether to show a single media item or grid in the media viewer. ```yaml media_viewer: - display: [...] + display: + # [...] ``` | Option | Default | Description | diff --git a/docs/configuration/menu.md b/docs/configuration/menu.md index c332f13d..e885a32c 100644 --- a/docs/configuration/menu.md +++ b/docs/configuration/menu.md @@ -3,7 +3,8 @@ Configures how the card menu behaves. ```yaml -menu: [...] +menu: + # [...] ``` | Option | Default | Description | @@ -21,7 +22,8 @@ All configuration is under: ```yaml menu: buttons: - [button]: [...] + [button]: + # [...] ``` ### Available Buttons diff --git a/docs/configuration/overrides.md b/docs/configuration/overrides.md index ace180ad..a645bbc9 100644 --- a/docs/configuration/overrides.md +++ b/docs/configuration/overrides.md @@ -6,8 +6,8 @@ hide the menu in fullscreen mode). ```yaml overrides: - conditions: - [condition] - [...] + - [condition] + # [...] ``` !> Whilst all configuration parameters are theoretically overridable, in some instances a configuration variable may only be consulted on startup or changing its value may negatively impact behavior -- override results may vary! @@ -42,7 +42,8 @@ An array of configuration paths to delete. ```yaml overrides: - - conditions: [condition] + - conditions: + - [condition] delete: - [path_1] - [path_2] @@ -54,16 +55,20 @@ Delete the 2nd camera: ```yaml overrides: - - conditions: [condition] - delete: 'cameras[2]' + - conditions: + - [condition] + delete: + - 'cameras[2]' ``` Delete the menu style parameter, thus falling back to the default: ```yaml overrides: - - conditions: [condition] - delete: 'menu.style' + - conditions: + - [condition] + delete: + - 'menu.style' ``` ## `merge` @@ -80,7 +85,8 @@ Hide the menu when a given condition is met: ```yaml overrides: - - conditions: [condition] + - conditions: + - [condition] merge: menu: { style: 'hidden' } ``` @@ -89,7 +95,8 @@ Enable thumbnails below the `live` feed: ```yaml overrides: - - conditions: [condition] + - conditions: + - [condition] merge: 'live.controls.thumbnails': { mode: 'below' } ``` @@ -98,7 +105,8 @@ Also enables thumbnails below the `live` feed, but without using the dot-separat ```yaml overrides: - - conditions: [condition] + - conditions: + - [condition] merge: live: { controls: { thumbnails: { mode: 'below' } } } ``` @@ -117,7 +125,8 @@ Set the entire menu configuration to defaults with the exception of the `style` ```yaml overrides: - - conditions: [condition] + - conditions: + - [condition] set: menu: { style: 'overlay' } ``` @@ -126,7 +135,8 @@ Set the menu style but without touching the other `menu` parameters: ```yaml overrides: - - conditions: [condition] + - conditions: + - [condition] set: 'menu.style': 'overlay' ``` @@ -135,7 +145,8 @@ That is equivalent to merging the following: ```yaml overrides: - - conditions: [condition] + - conditions: + - [condition] merge: menu: { style: 'overlay' } ``` diff --git a/docs/configuration/performance.md b/docs/configuration/performance.md index f7ec210d..9590a07c 100644 --- a/docs/configuration/performance.md +++ b/docs/configuration/performance.md @@ -3,7 +3,8 @@ Configure the card performance settings to enable the card to run (more) smoothly on lower end devices. ```yaml -performance: [...] +performance: + # [...] ``` | Option | Default | Description | @@ -17,7 +18,8 @@ Controls card-wide functionality that may impact performance. ```yaml performance: - features: [...] + features: + # [...] ``` | Option | Default | Description | @@ -35,7 +37,8 @@ shadows on timeline items, or curves in the media gallery items). ```yaml performance: - style: [...] + style: + # [...] ``` | Option | Default | Description | diff --git a/docs/configuration/timeline.md b/docs/configuration/timeline.md index cb9b0ea8..28ebfffc 100644 --- a/docs/configuration/timeline.md +++ b/docs/configuration/timeline.md @@ -4,7 +4,8 @@ Configures a `timeline` view used to show the timing sequence of events and recordings across multiple cameras. ```yaml -timeline: [...] +timeline: + # [...] ``` You can interact with the timeline in a number of ways: @@ -28,7 +29,8 @@ Configure the controls for the `timeline` view. ```yaml timeline: - controls: [...] + controls: + # [...] ``` | Option | Default | Description | @@ -42,7 +44,8 @@ Configures how thumbnails are shown on the timeline. ```yaml timeline: controls: - thumbnails: [...] + thumbnails: + # [...] ``` | Option | Default | Description | diff --git a/docs/configuration/view.md b/docs/configuration/view.md index 18971513..f71ce88f 100644 --- a/docs/configuration/view.md +++ b/docs/configuration/view.md @@ -3,7 +3,8 @@ The `view` configuration options control how the default view of the card behaves. ```yaml -view: [...] +view: + # [...] ``` | Option | Default | Description | @@ -49,7 +50,8 @@ All configuration is under: ```yaml view: - triggers: [...] + triggers: + # [...] ``` When a camera untriggers (e.g. an entity state returning to something other than From 321bb6fd1491d748a9e306ea97ca3a5d1d66165c Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Wed, 5 Jun 2024 23:30:38 -0300 Subject: [PATCH 148/189] Update all non-major dependencies --- package.json | 64 ++--- yarn.lock | 713 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 547 insertions(+), 230 deletions(-) diff --git a/package.json b/package.json index eaabf464..ba966890 100644 --- a/package.json +++ b/package.json @@ -15,74 +15,74 @@ "author": "Dermot Duffy ", "license": "MIT", "dependencies": { - "@cycjimmy/jsmpeg-player": "^6.0.4", + "@cycjimmy/jsmpeg-player": "^6.0.5", "@dermotduffy/custom-card-helpers": "^1.9.0", "@dermotduffy/panzoom": "^4.5.1", "@egjs/hammerjs": "^2.0.17", - "@graphiteds/core": "^1.9.11", + "@graphiteds/core": "^1.9.21", "@lit-labs/scoped-registry-mixin": "^1.0.3", "@lit-labs/task": "^1.1.3", - "@types/bluebird": "^3.5.36", - "component-emitter": "^1.3.0", + "@types/bluebird": "^3.5.42", + "component-emitter": "^1.3.1", "crypto": "^1.0.1", "date-fns": "^3.6.0", "date-fns-tz": "^3.1.3", - "embla-carousel": "8.0.0-rc14", - "embla-carousel-wheel-gestures": "8.0.0-rc04", - "home-assistant-js-websocket": "^8.0.0", + "embla-carousel": "^8.1.4", + "embla-carousel-wheel-gestures": "^8.0.1", + "home-assistant-js-websocket": "^8.2.0", "keycharm": "^0.4.0", - "lit": "^3.1.2", + "lit": "^3.1.4", "lodash-es": "^4.17.21", "masonry-layout": "^4.2.2", - "moment": "^2.29.4", + "moment": "^2.30.1", "p-queue": "^8.0.1", "propagating-hammerjs": "^2.0.1", - "quick-lru": "^6.1.0", + "quick-lru": "^6.1.2", "screenfull": "^6.0.2", "side-drawer": "^3.1.0", "uuid": "^8.3.2", "vis-data": "^7.1.9", "vis-timeline": "^7.7.3", - "vis-util": "^5.0.2", + "vis-util": "^5.0.7", "web-dialog": "^0.0.11", - "xss": "^1.0.14", - "zod": "^3.21.4" + "xss": "^1.0.15", + "zod": "^3.23.8" }, "devDependencies": { - "@babel/core": "^7.19.0", + "@babel/core": "^7.24.7", "@babel/plugin-proposal-class-properties": "^7.18.6", - "@babel/plugin-proposal-decorators": "^7.19.0", + "@babel/plugin-proposal-decorators": "^7.24.7", "@rollup/plugin-babel": "^5.3.1", "@rollup/plugin-commonjs": "^22.0.2", - "@rollup/plugin-image": "^3.0.2", + "@rollup/plugin-image": "^3.0.3", "@rollup/plugin-json": "^4.1.0", "@rollup/plugin-node-resolve": "^13.3.0", "@rollup/plugin-replace": "^4.0.0", "@rollup/plugin-typescript": "^11.1.6", - "@types/lodash-es": "^4.17.5", - "@types/masonry-layout": "^4.2.5", - "@typescript-eslint/eslint-plugin": "^7.12.0", - "@typescript-eslint/parser": "^7.12.0", + "@types/lodash-es": "^4.17.12", + "@types/masonry-layout": "^4.2.8", + "@typescript-eslint/eslint-plugin": "^7.13.0", + "@typescript-eslint/parser": "^7.13.0", "@vitest/coverage-istanbul": "^1.6.0", "docsify-cli": "^4.4.4", "eslint": "^8.57.0", "eslint-config-airbnb-base": "^15.0.0", "eslint-config-prettier": "^9.1.0", - "eslint-plugin-import": "^2.25.4", - "jsdom": "^21.1.1", - "markdown-link-check": "^3.12.1", - "prettier": "^3.3.1", - "rollup": "^2.79.0", + "eslint-plugin-import": "^2.29.1", + "jsdom": "^21.1.2", + "markdown-link-check": "^3.12.2", + "prettier": "^3.3.2", + "rollup": "^2.79.1", "rollup-plugin-git-info": "^1.0.0", - "rollup-plugin-serve": "^2.0.1", + "rollup-plugin-serve": "^2.0.3", "rollup-plugin-styles": "^4.0.0", "rollup-plugin-terser": "^7.0.2", - "rollup-plugin-visualizer": "^5.8.2", - "sass": "^1.54.9", + "rollup-plugin-visualizer": "^5.12.0", + "sass": "^1.77.4", "ts-prune": "^0.10.3", - "type-fest": "^4.18.0", + "type-fest": "^4.20.0", "typescript": "^5.4.5", - "vitest": "^1.5.0", + "vitest": "^1.6.0", "vitest-mock-extended": "^1.3.1" }, "scripts": { @@ -101,7 +101,7 @@ "coverage": "vitest run --coverage" }, "volta": { - "node": "20.12.2", - "yarn": "4.1.1" + "node": "20.14.0", + "yarn": "4.3.0" } } diff --git a/yarn.lock b/yarn.lock index c6260fc8..04680282 100644 --- a/yarn.lock +++ b/yarn.lock @@ -39,6 +39,16 @@ __metadata: languageName: node linkType: hard +"@babel/code-frame@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/code-frame@npm:7.24.7" + dependencies: + "@babel/highlight": "npm:^7.24.7" + picocolors: "npm:^1.0.0" + checksum: 10c0/ab0af539473a9f5aeaac7047e377cb4f4edd255a81d84a76058595f8540784cc3fbe8acf73f1e073981104562490aabfb23008cd66dc677a456a4ed5390fdde6 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.23.5": version: 7.23.5 resolution: "@babel/compat-data@npm:7.23.5" @@ -46,7 +56,14 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.19.0, @babel/core@npm:^7.23.9": +"@babel/compat-data@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/compat-data@npm:7.24.7" + checksum: 10c0/dcd93a5632b04536498fbe2be5af1057f635fd7f7090483d8e797878559037e5130b26862ceb359acbae93ed27e076d395ddb4663db6b28a665756ffd02d324f + languageName: node + linkType: hard + +"@babel/core@npm:^7.23.9": version: 7.24.0 resolution: "@babel/core@npm:7.24.0" dependencies: @@ -69,6 +86,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/core@npm:7.24.7" + dependencies: + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.24.7" + "@babel/generator": "npm:^7.24.7" + "@babel/helper-compilation-targets": "npm:^7.24.7" + "@babel/helper-module-transforms": "npm:^7.24.7" + "@babel/helpers": "npm:^7.24.7" + "@babel/parser": "npm:^7.24.7" + "@babel/template": "npm:^7.24.7" + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10c0/4004ba454d3c20a46ea66264e06c15b82e9f6bdc35f88819907d24620da70dbf896abac1cb4cc4b6bb8642969e45f4d808497c9054a1388a386cf8c12e9b9e0d + languageName: node + linkType: hard + "@babel/generator@npm:^7.23.6": version: 7.23.6 resolution: "@babel/generator@npm:7.23.6" @@ -81,6 +121,18 @@ __metadata: languageName: node linkType: hard +"@babel/generator@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/generator@npm:7.24.7" + dependencies: + "@babel/types": "npm:^7.24.7" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^2.5.1" + checksum: 10c0/06b1f3350baf527a3309e50ffd7065f7aee04dd06e1e7db794ddfde7fe9d81f28df64edd587173f8f9295496a7ddb74b9a185d4bf4de7bb619e6d4ec45c8fd35 + languageName: node + linkType: hard + "@babel/helper-annotate-as-pure@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" @@ -90,6 +142,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-annotate-as-pure@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-annotate-as-pure@npm:7.24.7" + dependencies: + "@babel/types": "npm:^7.24.7" + checksum: 10c0/4679f7df4dffd5b3e26083ae65228116c3da34c3fff2c11ae11b259a61baec440f51e30fd236f7a0435b9d471acd93d0bc5a95df8213cbf02b1e083503d81b9a + languageName: node + linkType: hard + "@babel/helper-compilation-targets@npm:^7.23.6": version: 7.23.6 resolution: "@babel/helper-compilation-targets@npm:7.23.6" @@ -103,7 +164,20 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.24.0": +"@babel/helper-compilation-targets@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-compilation-targets@npm:7.24.7" + dependencies: + "@babel/compat-data": "npm:^7.24.7" + "@babel/helper-validator-option": "npm:^7.24.7" + browserslist: "npm:^4.22.2" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10c0/1d580a9bcacefe65e6bf02ba1dafd7ab278269fef45b5e281d8354d95c53031e019890464e7f9351898c01502dd2e633184eb0bcda49ed2ecd538675ce310f51 + languageName: node + linkType: hard + +"@babel/helper-create-class-features-plugin@npm:^7.18.6": version: 7.24.0 resolution: "@babel/helper-create-class-features-plugin@npm:7.24.0" dependencies: @@ -122,6 +196,25 @@ __metadata: languageName: node linkType: hard +"@babel/helper-create-class-features-plugin@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-create-class-features-plugin@npm:7.24.7" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-function-name": "npm:^7.24.7" + "@babel/helper-member-expression-to-functions": "npm:^7.24.7" + "@babel/helper-optimise-call-expression": "npm:^7.24.7" + "@babel/helper-replace-supers": "npm:^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + "@babel/helper-split-export-declaration": "npm:^7.24.7" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/6b7b47d70b41c00f39f86790cff67acf2bce0289d52a7c182b28e797f4e0e6d69027e3d06eccf1d54dddc2e5dde1df663bb1932437e5f447aeb8635d8d64a6ab + languageName: node + linkType: hard + "@babel/helper-environment-visitor@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-environment-visitor@npm:7.22.20" @@ -129,6 +222,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-environment-visitor@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-environment-visitor@npm:7.24.7" + dependencies: + "@babel/types": "npm:^7.24.7" + checksum: 10c0/36ece78882b5960e2d26abf13cf15ff5689bf7c325b10a2895a74a499e712de0d305f8d78bb382dd3c05cfba7e47ec98fe28aab5674243e0625cd38438dd0b2d + languageName: node + linkType: hard + "@babel/helper-function-name@npm:^7.23.0": version: 7.23.0 resolution: "@babel/helper-function-name@npm:7.23.0" @@ -139,6 +241,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-function-name@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-function-name@npm:7.24.7" + dependencies: + "@babel/template": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/e5e41e6cf86bd0f8bf272cbb6e7c5ee0f3e9660414174435a46653efba4f2479ce03ce04abff2aa2ef9359cf057c79c06cb7b134a565ad9c0e8a50dcdc3b43c4 + languageName: node + linkType: hard + "@babel/helper-hoist-variables@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-hoist-variables@npm:7.22.5" @@ -148,6 +260,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-hoist-variables@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-hoist-variables@npm:7.24.7" + dependencies: + "@babel/types": "npm:^7.24.7" + checksum: 10c0/19ee37563bbd1219f9d98991ad0e9abef77803ee5945fd85aa7aa62a67c69efca9a801696a1b58dda27f211e878b3327789e6fd2a6f6c725ccefe36774b5ce95 + languageName: node + linkType: hard + "@babel/helper-member-expression-to-functions@npm:^7.22.15, @babel/helper-member-expression-to-functions@npm:^7.23.0": version: 7.23.0 resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0" @@ -157,6 +278,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-member-expression-to-functions@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-member-expression-to-functions@npm:7.24.7" + dependencies: + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/9638c1d33cf6aba028461ccd3db6061c76ff863ca0d5013dd9a088bf841f2f77c46956493f9da18355c16759449d23b74cc1de4da357ade5c5c34c858f840f0a + languageName: node + linkType: hard + "@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.22.15": version: 7.22.15 resolution: "@babel/helper-module-imports@npm:7.22.15" @@ -166,6 +297,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-module-imports@npm:7.24.7" + dependencies: + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/97c57db6c3eeaea31564286e328a9fb52b0313c5cfcc7eee4bc226aebcf0418ea5b6fe78673c0e4a774512ec6c86e309d0f326e99d2b37bfc16a25a032498af0 + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.23.3": version: 7.23.3 resolution: "@babel/helper-module-transforms@npm:7.23.3" @@ -181,6 +322,21 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-module-transforms@npm:7.24.7" + dependencies: + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-module-imports": "npm:^7.24.7" + "@babel/helper-simple-access": "npm:^7.24.7" + "@babel/helper-split-export-declaration": "npm:^7.24.7" + "@babel/helper-validator-identifier": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/4f311755fcc3b4cbdb689386309cdb349cf0575a938f0b9ab5d678e1a81bbb265aa34ad93174838245f2ac7ff6d5ddbd0104638a75e4e961958ed514355687b6 + languageName: node + linkType: hard + "@babel/helper-optimise-call-expression@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" @@ -190,13 +346,29 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.24.0": +"@babel/helper-optimise-call-expression@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-optimise-call-expression@npm:7.24.7" + dependencies: + "@babel/types": "npm:^7.24.7" + checksum: 10c0/ca6a9884705dea5c95a8b3ce132d1e3f2ae951ff74987d400d1d9c215dae9c0f9e29924d8f8e131e116533d182675bc261927be72f6a9a2968eaeeaa51eb1d0f + languageName: node + linkType: hard + +"@babel/helper-plugin-utils@npm:^7.18.6": version: 7.24.0 resolution: "@babel/helper-plugin-utils@npm:7.24.0" checksum: 10c0/90f41bd1b4dfe7226b1d33a4bb745844c5c63e400f9e4e8bf9103a7ceddd7d425d65333b564d9daba3cebd105985764d51b4bd4c95822b97c2e3ac1201a8a5da languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-plugin-utils@npm:7.24.7" + checksum: 10c0/c3d38cd9b3520757bb4a279255cc3f956fc0ac1c193964bd0816ebd5c86e30710be8e35252227e0c9d9e0f4f56d9b5f916537f2bc588084b0988b4787a967d31 + languageName: node + linkType: hard + "@babel/helper-replace-supers@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-replace-supers@npm:7.22.20" @@ -210,6 +382,19 @@ __metadata: languageName: node linkType: hard +"@babel/helper-replace-supers@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-replace-supers@npm:7.24.7" + dependencies: + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-member-expression-to-functions": "npm:^7.24.7" + "@babel/helper-optimise-call-expression": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10c0/0e133bb03371dee78e519c334a09c08e1493103a239d9628db0132dfaac3fc16380479ca3c590d278a9b71b624030a338c18ebbfe6d430ebb2e4653775c4b3e3 + languageName: node + linkType: hard + "@babel/helper-simple-access@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-simple-access@npm:7.22.5" @@ -219,6 +404,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-simple-access@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-simple-access@npm:7.24.7" + dependencies: + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/7230e419d59a85f93153415100a5faff23c133d7442c19e0cd070da1784d13cd29096ee6c5a5761065c44e8164f9f80e3a518c41a0256df39e38f7ad6744fed7 + languageName: node + linkType: hard + "@babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5": version: 7.22.5 resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5" @@ -228,6 +423,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.24.7" + dependencies: + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/e3a9b8ac9c262ac976a1bcb5fe59694db5e6f0b4f9e7bdba5c7693b8b5e28113c23bdaa60fe8d3ec32a337091b67720b2053bcb3d5655f5406536c3d0584242b + languageName: node + linkType: hard + "@babel/helper-split-export-declaration@npm:^7.22.6": version: 7.22.6 resolution: "@babel/helper-split-export-declaration@npm:7.22.6" @@ -237,6 +442,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-split-export-declaration@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-split-export-declaration@npm:7.24.7" + dependencies: + "@babel/types": "npm:^7.24.7" + checksum: 10c0/0254577d7086bf09b01bbde98f731d4fcf4b7c3fa9634fdb87929801307c1f6202a1352e3faa5492450fa8da4420542d44de604daf540704ff349594a78184f6 + languageName: node + linkType: hard + "@babel/helper-string-parser@npm:^7.23.4": version: 7.23.4 resolution: "@babel/helper-string-parser@npm:7.23.4" @@ -244,6 +458,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-string-parser@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-string-parser@npm:7.24.7" + checksum: 10c0/47840c7004e735f3dc93939c77b099bb41a64bf3dda0cae62f60e6f74a5ff80b63e9b7cf77b5ec25a324516381fc994e1f62f922533236a8e3a6af57decb5e1e + languageName: node + linkType: hard + "@babel/helper-validator-identifier@npm:^7.22.20": version: 7.22.20 resolution: "@babel/helper-validator-identifier@npm:7.22.20" @@ -251,6 +472,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-identifier@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-validator-identifier@npm:7.24.7" + checksum: 10c0/87ad608694c9477814093ed5b5c080c2e06d44cb1924ae8320474a74415241223cc2a725eea2640dd783ff1e3390e5f95eede978bc540e870053152e58f1d651 + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.23.5": version: 7.23.5 resolution: "@babel/helper-validator-option@npm:7.23.5" @@ -258,6 +486,13 @@ __metadata: languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-validator-option@npm:7.24.7" + checksum: 10c0/21aea2b7bc5cc8ddfb828741d5c8116a84cbc35b4a3184ec53124f08e09746f1f67a6f9217850188995ca86059a7942e36d8965a6730784901def777b7e8a436 + languageName: node + linkType: hard + "@babel/helpers@npm:^7.24.0": version: 7.24.0 resolution: "@babel/helpers@npm:7.24.0" @@ -269,6 +504,16 @@ __metadata: languageName: node linkType: hard +"@babel/helpers@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helpers@npm:7.24.7" + dependencies: + "@babel/template": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/aa8e230f6668773e17e141dbcab63e935c514b4b0bf1fed04d2eaefda17df68e16b61a56573f7f1d4d1e605ce6cc162b5f7e9fdf159fde1fd9b77c920ae47d27 + languageName: node + linkType: hard + "@babel/highlight@npm:^7.23.4": version: 7.23.4 resolution: "@babel/highlight@npm:7.23.4" @@ -280,6 +525,18 @@ __metadata: languageName: node linkType: hard +"@babel/highlight@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/highlight@npm:7.24.7" + dependencies: + "@babel/helper-validator-identifier": "npm:^7.24.7" + chalk: "npm:^2.4.2" + js-tokens: "npm:^4.0.0" + picocolors: "npm:^1.0.0" + checksum: 10c0/674334c571d2bb9d1c89bdd87566383f59231e16bcdcf5bb7835babdf03c9ae585ca0887a7b25bdf78f303984af028df52831c7989fecebb5101cc132da9393a + languageName: node + linkType: hard + "@babel/parser@npm:^7.23.6, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.24.0": version: 7.24.0 resolution: "@babel/parser@npm:7.24.0" @@ -289,6 +546,15 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/parser@npm:7.24.7" + bin: + parser: ./bin/babel-parser.js + checksum: 10c0/8b244756872185a1c6f14b979b3535e682ff08cb5a2a5fd97cc36c017c7ef431ba76439e95e419d43000c5b07720495b00cf29a7f0d9a483643d08802b58819b + languageName: node + linkType: hard + "@babel/plugin-proposal-class-properties@npm:^7.18.6": version: 7.18.6 resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" @@ -301,27 +567,27 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-decorators@npm:^7.19.0": - version: 7.24.0 - resolution: "@babel/plugin-proposal-decorators@npm:7.24.0" +"@babel/plugin-proposal-decorators@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-proposal-decorators@npm:7.24.7" dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.24.0" - "@babel/helper-plugin-utils": "npm:^7.24.0" - "@babel/plugin-syntax-decorators": "npm:^7.24.0" + "@babel/helper-create-class-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-decorators": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/6bf16cb2b5b2f1b63b5ea964853cd3b3419c8285296b5bf64a64127c9d5c1b2e6829e84bd92734e4b71df67686d8f36fb01bb8a45fc52bcece7503b73bc42ec7 + checksum: 10c0/fb4e4711f90fed63aa4dfe34fc5f5a5d0af175725181678f462ee0df2b78a23ae83b9424403c6b957edbc07d2abc80f82f3b9f91baf568bdaf85e8196a9138d5 languageName: node linkType: hard -"@babel/plugin-syntax-decorators@npm:^7.24.0": - version: 7.24.0 - resolution: "@babel/plugin-syntax-decorators@npm:7.24.0" +"@babel/plugin-syntax-decorators@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-syntax-decorators@npm:7.24.7" dependencies: - "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-plugin-utils": "npm:^7.24.7" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/6c11801e062772d4e1b0b418a4732574128b1dfc13193a2909fa93937346746aaa7046f88f6026ff3c80777c967d0fe2e4bb19a1d3fb399e8349c81741e4f471 + checksum: 10c0/d1ecc334af7a5418a6e8ad5e711bf5d5a892ba00e04ba05b90077b9da735585ff8d4141e4fc3ae781b854f48eda9f3a9cfa9f1c80f5f4a697dbded01058a8b63 languageName: node linkType: hard @@ -336,6 +602,17 @@ __metadata: languageName: node linkType: hard +"@babel/template@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/template@npm:7.24.7" + dependencies: + "@babel/code-frame": "npm:^7.24.7" + "@babel/parser": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10c0/95b0b3ee80fcef685b7f4426f5713a855ea2cd5ac4da829b213f8fb5afe48a2a14683c2ea04d446dbc7f711c33c5cd4a965ef34dcbe5bc387c9e966b67877ae3 + languageName: node + linkType: hard + "@babel/traverse@npm:^7.24.0": version: 7.24.0 resolution: "@babel/traverse@npm:7.24.0" @@ -354,6 +631,24 @@ __metadata: languageName: node linkType: hard +"@babel/traverse@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/traverse@npm:7.24.7" + dependencies: + "@babel/code-frame": "npm:^7.24.7" + "@babel/generator": "npm:^7.24.7" + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-function-name": "npm:^7.24.7" + "@babel/helper-hoist-variables": "npm:^7.24.7" + "@babel/helper-split-export-declaration": "npm:^7.24.7" + "@babel/parser": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10c0/a5135e589c3f1972b8877805f50a084a04865ccb1d68e5e1f3b94a8841b3485da4142e33413d8fd76bc0e6444531d3adf1f59f359c11ffac452b743d835068ab + languageName: node + linkType: hard + "@babel/types@npm:^7.22.15, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.6, @babel/types@npm:^7.24.0, @babel/types@npm:^7.8.3": version: 7.24.0 resolution: "@babel/types@npm:7.24.0" @@ -365,7 +660,18 @@ __metadata: languageName: node linkType: hard -"@cycjimmy/jsmpeg-player@npm:^6.0.4": +"@babel/types@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/types@npm:7.24.7" + dependencies: + "@babel/helper-string-parser": "npm:^7.24.7" + "@babel/helper-validator-identifier": "npm:^7.24.7" + to-fast-properties: "npm:^2.0.0" + checksum: 10c0/d9ecbfc3eb2b05fb1e6eeea546836ac30d990f395ef3fe3f75ced777a222c3cfc4489492f72e0ce3d9a5a28860a1ce5f81e66b88cf5088909068b3ff4fab72c1 + languageName: node + linkType: hard + +"@cycjimmy/jsmpeg-player@npm:^6.0.5": version: 6.0.5 resolution: "@cycjimmy/jsmpeg-player@npm:6.0.5" checksum: 10c0/f061a030fcee2b27157e5e6f196b33b9b47d4e7780a75645fd528bb447e3f766613e27136506499d95b3c5901c5a8951182dd55b154f14f637ec8ed6732074b0 @@ -680,14 +986,14 @@ __metadata: languageName: node linkType: hard -"@graphiteds/core@npm:^1.9.11": - version: 1.9.20 - resolution: "@graphiteds/core@npm:1.9.20" +"@graphiteds/core@npm:^1.9.21": + version: 1.9.21 + resolution: "@graphiteds/core@npm:1.9.21" dependencies: "@duetds/date-picker": "npm:^1.4.0" "@popperjs/core": "npm:^2.11.5" "@stencil/core": "npm:^2.20.0" - checksum: 10c0/934f79ef0a19dd581841321df5a0760c4aabdb7c2609ed5a15dbf54faf0ad8442ff86aa120e57215d56f6e914011c14debac99840d87b32929789f407698b176 + checksum: 10c0/bf1685039521861c50ec743a1ca4c7494414e1a7a8b2702b553a4cb46bf1f2372ee90b0049c1aa565c99717709bb690b4403c5e0a6dd694261cd853ea4905e2a languageName: node linkType: hard @@ -798,7 +1104,7 @@ __metadata: languageName: node linkType: hard -"@jridgewell/trace-mapping@npm:^0.3.23": +"@jridgewell/trace-mapping@npm:^0.3.23, @jridgewell/trace-mapping@npm:^0.3.25": version: 0.3.25 resolution: "@jridgewell/trace-mapping@npm:0.3.25" dependencies: @@ -949,7 +1255,7 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-image@npm:^3.0.2": +"@rollup/plugin-image@npm:^3.0.3": version: 3.0.3 resolution: "@rollup/plugin-image@npm:3.0.3" dependencies: @@ -1217,7 +1523,7 @@ __metadata: languageName: node linkType: hard -"@types/bluebird@npm:^3.5.36": +"@types/bluebird@npm:^3.5.42": version: 3.5.42 resolution: "@types/bluebird@npm:3.5.42" checksum: 10c0/ce752a5e277bbc0cdee3dee9c875ac093d1331905a8a5175665ccb8cb76b7b95a84836f92bc46076c2fd1e384a107866893eeeb20f6fb33427482663879faf93 @@ -1279,7 +1585,7 @@ __metadata: languageName: node linkType: hard -"@types/lodash-es@npm:^4.17.5": +"@types/lodash-es@npm:^4.17.12": version: 4.17.12 resolution: "@types/lodash-es@npm:4.17.12" dependencies: @@ -1295,12 +1601,12 @@ __metadata: languageName: node linkType: hard -"@types/masonry-layout@npm:^4.2.5": - version: 4.2.7 - resolution: "@types/masonry-layout@npm:4.2.7" +"@types/masonry-layout@npm:^4.2.8": + version: 4.2.8 + resolution: "@types/masonry-layout@npm:4.2.8" dependencies: "@types/jquery": "npm:*" - checksum: 10c0/81ea3d8c0780ff7a4523dd8e954f4825806ca2c9928e13a19489571f2517e483c0a7143abc322da9fc820392e8c92a8a88aa9eda0a67ceb68a4bd346711aa157 + checksum: 10c0/ca82bc34289ac88978ee6b7847c017370adef09eb44d2d43f0993e215bef7bf926d21ad2dab14cc451a8ac9e002ada9612443ce21a04d53b34ffc3ba6f2b165e languageName: node linkType: hard @@ -1352,15 +1658,15 @@ __metadata: languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:^7.12.0": - version: 7.12.0 - resolution: "@typescript-eslint/eslint-plugin@npm:7.12.0" +"@typescript-eslint/eslint-plugin@npm:^7.13.0": + version: 7.13.0 + resolution: "@typescript-eslint/eslint-plugin@npm:7.13.0" dependencies: "@eslint-community/regexpp": "npm:^4.10.0" - "@typescript-eslint/scope-manager": "npm:7.12.0" - "@typescript-eslint/type-utils": "npm:7.12.0" - "@typescript-eslint/utils": "npm:7.12.0" - "@typescript-eslint/visitor-keys": "npm:7.12.0" + "@typescript-eslint/scope-manager": "npm:7.13.0" + "@typescript-eslint/type-utils": "npm:7.13.0" + "@typescript-eslint/utils": "npm:7.13.0" + "@typescript-eslint/visitor-keys": "npm:7.13.0" graphemer: "npm:^1.4.0" ignore: "npm:^5.3.1" natural-compare: "npm:^1.4.0" @@ -1371,44 +1677,44 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/abf899e07144e8edd8ae010d25e4679e2acded407a10efc6aaa7ee325af8daf0dd149946ad58e46982e29e0a23f56b1e0dd461ef09aab09b0d94fc24ffc827c2 + checksum: 10c0/00a69d029713252c03490e0a9c49c9136d99c9c1888dd3570b1e044c9a740b59c2e488849beda654d6fc0a69e2549445c16d443bcf5832c66b7a4472b42826ae languageName: node linkType: hard -"@typescript-eslint/parser@npm:^7.12.0": - version: 7.12.0 - resolution: "@typescript-eslint/parser@npm:7.12.0" +"@typescript-eslint/parser@npm:^7.13.0": + version: 7.13.0 + resolution: "@typescript-eslint/parser@npm:7.13.0" dependencies: - "@typescript-eslint/scope-manager": "npm:7.12.0" - "@typescript-eslint/types": "npm:7.12.0" - "@typescript-eslint/typescript-estree": "npm:7.12.0" - "@typescript-eslint/visitor-keys": "npm:7.12.0" + "@typescript-eslint/scope-manager": "npm:7.13.0" + "@typescript-eslint/types": "npm:7.13.0" + "@typescript-eslint/typescript-estree": "npm:7.13.0" + "@typescript-eslint/visitor-keys": "npm:7.13.0" debug: "npm:^4.3.4" peerDependencies: eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10c0/223c32a6ba6cee770ee39108fb0a6d132283673d44c751bec85d8792df3382ddb839617787d183dc8fd7686d8a2018bf1ec0f3d63b7010c4370913f249c80fbc + checksum: 10c0/8cf58116d6577c9459db3e3047e337dc41d914bf222a33b20e149515d037e09e6171fbac5af02b66aa6fbad81dd492fa5b7bcd44aaf659d4e9b02ab23100f955 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.12.0": - version: 7.12.0 - resolution: "@typescript-eslint/scope-manager@npm:7.12.0" +"@typescript-eslint/scope-manager@npm:7.13.0": + version: 7.13.0 + resolution: "@typescript-eslint/scope-manager@npm:7.13.0" dependencies: - "@typescript-eslint/types": "npm:7.12.0" - "@typescript-eslint/visitor-keys": "npm:7.12.0" - checksum: 10c0/7af53cd9045cc70459e4f451377affc0ef03e67bd743480ab2cbfebe1b7d8269fc639406966930c5abb26f1b633623c98442c2b60f6257e0ce1555439343d5e9 + "@typescript-eslint/types": "npm:7.13.0" + "@typescript-eslint/visitor-keys": "npm:7.13.0" + checksum: 10c0/0f5c75578ee8cb3c31b9c4e222f4787ea4621fde639f3ac0a467e56250f3cc48bf69304c33b2b8cc8ba5ec69f3977b6c463b8d9e791806af9a8c6a2233505432 languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.12.0": - version: 7.12.0 - resolution: "@typescript-eslint/type-utils@npm:7.12.0" +"@typescript-eslint/type-utils@npm:7.13.0": + version: 7.13.0 + resolution: "@typescript-eslint/type-utils@npm:7.13.0" dependencies: - "@typescript-eslint/typescript-estree": "npm:7.12.0" - "@typescript-eslint/utils": "npm:7.12.0" + "@typescript-eslint/typescript-estree": "npm:7.13.0" + "@typescript-eslint/utils": "npm:7.13.0" debug: "npm:^4.3.4" ts-api-utils: "npm:^1.3.0" peerDependencies: @@ -1416,23 +1722,23 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/41f4aa20d24724b461eb0cdac69d91ef60c2b628fb4a5739e4dbb8378aa4a7ff20c302f60e5d74ce75d5b99fcd3e3d71b9b3c96a1714aac47ce2ce5d6d611fcd + checksum: 10c0/240e9b34e8602444cd234b84c9e3e52c565e3141a4942751f597c38cee48f7cb43c42a093d219ac6404dca2e74b54d2a8121fe66cbc59f404cb0ec2adecd8520 languageName: node linkType: hard -"@typescript-eslint/types@npm:7.12.0": - version: 7.12.0 - resolution: "@typescript-eslint/types@npm:7.12.0" - checksum: 10c0/76786d02a0838750d74ad6e49b026875c0753b81c5a46a56525a1e82d89c0939a13434b03494e3b31b7ffbba7824f426c5b502a12337806a1f6ca560b5dad46c +"@typescript-eslint/types@npm:7.13.0": + version: 7.13.0 + resolution: "@typescript-eslint/types@npm:7.13.0" + checksum: 10c0/73dc59d4b0d0f0fed9f4b9b55f143185259ced5f0ca8ad9efa881eea1ff1cc9ccc1f175af2e2069f7b92a69c9f64f9be29d160c932b8f70a129af6b738b23be0 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.12.0": - version: 7.12.0 - resolution: "@typescript-eslint/typescript-estree@npm:7.12.0" +"@typescript-eslint/typescript-estree@npm:7.13.0": + version: 7.13.0 + resolution: "@typescript-eslint/typescript-estree@npm:7.13.0" dependencies: - "@typescript-eslint/types": "npm:7.12.0" - "@typescript-eslint/visitor-keys": "npm:7.12.0" + "@typescript-eslint/types": "npm:7.13.0" + "@typescript-eslint/visitor-keys": "npm:7.13.0" debug: "npm:^4.3.4" globby: "npm:^11.1.0" is-glob: "npm:^4.0.3" @@ -1442,31 +1748,31 @@ __metadata: peerDependenciesMeta: typescript: optional: true - checksum: 10c0/855be5ba6c3d7540319ad250555055a798deb04855f26abe719a3b8d555a3227d52e09453930bd829e260a72f65a985998b235514ce2872b31615015da3163c0 + checksum: 10c0/75b09384bc14afa3d3623507432d19d8ca91c4e936b1d2c1cfe4654a9c07179f1bc04aa99d1b541e84e40a01536862b23058f462d61b4a797c27d02f64b8aa51 languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.12.0": - version: 7.12.0 - resolution: "@typescript-eslint/utils@npm:7.12.0" +"@typescript-eslint/utils@npm:7.13.0": + version: 7.13.0 + resolution: "@typescript-eslint/utils@npm:7.13.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" - "@typescript-eslint/scope-manager": "npm:7.12.0" - "@typescript-eslint/types": "npm:7.12.0" - "@typescript-eslint/typescript-estree": "npm:7.12.0" + "@typescript-eslint/scope-manager": "npm:7.13.0" + "@typescript-eslint/types": "npm:7.13.0" + "@typescript-eslint/typescript-estree": "npm:7.13.0" peerDependencies: eslint: ^8.56.0 - checksum: 10c0/04241c0313f2d061bc81ec2d5d589c9a723f8c1493e5b83d98f804ff9dac23c5e7157d9bb57bee8b458f40824f56ea65a02ebd344926a37cb58bf151cb4d3bf2 + checksum: 10c0/5391f628775dec1a7033d954a066b77eeb03ac04c0a94690e60d8ebe351b57fdbda51b90cf785c901bcdf68b88ca3bcb5533ac59276b8b626b73eb18ac3280b6 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.12.0": - version: 7.12.0 - resolution: "@typescript-eslint/visitor-keys@npm:7.12.0" +"@typescript-eslint/visitor-keys@npm:7.13.0": + version: 7.13.0 + resolution: "@typescript-eslint/visitor-keys@npm:7.13.0" dependencies: - "@typescript-eslint/types": "npm:7.12.0" + "@typescript-eslint/types": "npm:7.13.0" eslint-visitor-keys: "npm:^3.4.3" - checksum: 10c0/f3aa6704961e65fa8d66fcde57cd28e382412bb8bec2e99312bf8cda38772ae9a74d6d95b9765f76a249bc9ab65624db34b8c00078ebad129b2e1b624e935d90 + checksum: 10c0/5daa45c3358aeab41495c4419cc26fbbe54a42bb18c6f0f70f0ac31cb7bc5890ec6478a1a6bb00b0b8522663fe5466ee0fd2972bd4235b07140918875797f4eb languageName: node linkType: hard @@ -1496,57 +1802,57 @@ __metadata: languageName: node linkType: hard -"@vitest/expect@npm:1.5.0": - version: 1.5.0 - resolution: "@vitest/expect@npm:1.5.0" +"@vitest/expect@npm:1.6.0": + version: 1.6.0 + resolution: "@vitest/expect@npm:1.6.0" dependencies: - "@vitest/spy": "npm:1.5.0" - "@vitest/utils": "npm:1.5.0" + "@vitest/spy": "npm:1.6.0" + "@vitest/utils": "npm:1.6.0" chai: "npm:^4.3.10" - checksum: 10c0/12138caf0831a9bcdf475750fdff27588f03f11ee5101124f9d39951bbcdec39aa6a19a1a30f3ab0ca17374ddfc7399b861e2fcb1548bba302943e8e88512a9c + checksum: 10c0/a4351f912a70543e04960f5694f1f1ac95f71a856a46e87bba27d3eb72a08c5d11d35021cbdc6077452a152e7d93723fc804bba76c2cc53c8896b7789caadae3 languageName: node linkType: hard -"@vitest/runner@npm:1.5.0": - version: 1.5.0 - resolution: "@vitest/runner@npm:1.5.0" +"@vitest/runner@npm:1.6.0": + version: 1.6.0 + resolution: "@vitest/runner@npm:1.6.0" dependencies: - "@vitest/utils": "npm:1.5.0" + "@vitest/utils": "npm:1.6.0" p-limit: "npm:^5.0.0" pathe: "npm:^1.1.1" - checksum: 10c0/a7b693e4121b6159a77f6cbffc03c228cd18c3734e27a968fe26579777f6d7a4d55a02fba396d564df996a91881ee76de80ee5a526d27a4b508f44a9af62d95a + checksum: 10c0/27d67fa51f40effe0e41ee5f26563c12c0ef9a96161f806036f02ea5eb9980c5cdf305a70673942e7a1e3d472d4d7feb40093ae93024ef1ccc40637fc65b1d2f languageName: node linkType: hard -"@vitest/snapshot@npm:1.5.0": - version: 1.5.0 - resolution: "@vitest/snapshot@npm:1.5.0" +"@vitest/snapshot@npm:1.6.0": + version: 1.6.0 + resolution: "@vitest/snapshot@npm:1.6.0" dependencies: magic-string: "npm:^0.30.5" pathe: "npm:^1.1.1" pretty-format: "npm:^29.7.0" - checksum: 10c0/d897070b3a7c008eb58d44ca0dc324c69dfc1f787335e59fb930ae2e8d02a148e6b3c13497a588083a0654bdc430281fdd84276ead4888230314a2984dd9f93d + checksum: 10c0/be027fd268d524589ff50c5fad7b4faa1ac5742b59ac6c1dc6f5a3930aad553560e6d8775e90ac4dfae4be746fc732a6f134ba95606a1519707ce70db3a772a5 languageName: node linkType: hard -"@vitest/spy@npm:1.5.0": - version: 1.5.0 - resolution: "@vitest/spy@npm:1.5.0" +"@vitest/spy@npm:1.6.0": + version: 1.6.0 + resolution: "@vitest/spy@npm:1.6.0" dependencies: tinyspy: "npm:^2.2.0" - checksum: 10c0/0206f1e8431f543474dc6d252b553227d0f286b27226b987b63babb18865e8320e6c3d822c67782aae68555728a57ecdeb7c4e16283dbad49791608a691f26d1 + checksum: 10c0/df66ea6632b44fb76ef6a65c1abbace13d883703aff37cd6d062add6dcd1b883f19ce733af8e0f7feb185b61600c6eb4042a518e4fb66323d0690ec357f9401c languageName: node linkType: hard -"@vitest/utils@npm:1.5.0": - version: 1.5.0 - resolution: "@vitest/utils@npm:1.5.0" +"@vitest/utils@npm:1.6.0": + version: 1.6.0 + resolution: "@vitest/utils@npm:1.6.0" dependencies: diff-sequences: "npm:^29.6.3" estree-walker: "npm:^3.0.3" loupe: "npm:^2.3.7" pretty-format: "npm:^29.7.0" - checksum: 10c0/b9d779ea5c1a5759df4f59e3ba3f3a94816d6c600afe7a2d14b963ea114ce1acedbfe678cbfacb0a20d33cabcce890a08b2ce3fd52e3465f2e0969cc39f7686b + checksum: 10c0/8b0d19835866455eb0b02b31c5ca3d8ad45f41a24e4c7e1f064b480f6b2804dc895a70af332f14c11ed89581011b92b179718523f55f5b14787285a0321b1301 languageName: node linkType: hard @@ -2123,7 +2429,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^5.2.0": +"chalk@npm:^5.3.0": version: 5.3.0 resolution: "chalk@npm:5.3.0" checksum: 10c0/8297d436b2c0f95801103ff2ef67268d362021b8210daf8ddbe349695333eb3610a71122172ff3b0272f1ef2cf7cc2c41fdaa4715f52e49ffe04c56340feed09 @@ -2301,10 +2607,10 @@ __metadata: languageName: node linkType: hard -"commander@npm:^10.0.1": - version: 10.0.1 - resolution: "commander@npm:10.0.1" - checksum: 10c0/53f33d8927758a911094adadda4b2cbac111a5b377d8706700587650fd8f45b0bbe336de4b5c3fe47fd61f420a3d9bd452b6e0e6e5600a7e74d7bf0174f6efe3 +"commander@npm:^12.1.0": + version: 12.1.0 + resolution: "commander@npm:12.1.0" + checksum: 10c0/6e1996680c083b3b897bfc1cfe1c58dfbcd9842fd43e1aaf8a795fbc237f65efcc860a3ef457b318e73f29a4f4a28f6403c3d653d021d960e4632dd45bde54a9 languageName: node linkType: hard @@ -2336,7 +2642,7 @@ __metadata: languageName: node linkType: hard -"component-emitter@npm:^1.3.0": +"component-emitter@npm:^1.3.1": version: 1.3.1 resolution: "component-emitter@npm:1.3.1" checksum: 10c0/e4900b1b790b5e76b8d71b328da41482118c0f3523a516a41be598dc2785a07fd721098d9bf6e22d89b19f4fa4e1025160dc00317ea111633a3e4f75c2b86032 @@ -3003,21 +3309,21 @@ __metadata: languageName: node linkType: hard -"embla-carousel-wheel-gestures@npm:8.0.0-rc04": - version: 8.0.0-rc04 - resolution: "embla-carousel-wheel-gestures@npm:8.0.0-rc04" +"embla-carousel-wheel-gestures@npm:^8.0.1": + version: 8.0.1 + resolution: "embla-carousel-wheel-gestures@npm:8.0.1" dependencies: wheel-gestures: "npm:^2.2.5" peerDependencies: - embla-carousel: 8.0.0-rc03 - checksum: 10c0/3b32b6565de5acd70a8cc3b427cfc411e9e2ed6671ce216efb8706f8897ac68da30e11e419d57aafbc6f9bf1d2405665c9d037002985f7033d770475f0569b62 + embla-carousel: ^8.0.0 || ~8.0.0-rc03 + checksum: 10c0/ce687d1d63177812eebdd1436dbeb6d5f79cbe5a880e102bf4222ecbcffa2d9b89c9e7454c3485e112825f7dac7ad6c73022ac8f5c4166607e0d3de8946af89b languageName: node linkType: hard -"embla-carousel@npm:8.0.0-rc14": - version: 8.0.0-rc14 - resolution: "embla-carousel@npm:8.0.0-rc14" - checksum: 10c0/f8dcb810e43d2f898b60188648b7f23e1dd904b70d4935d067dde4a245ffc0527b793ddb4c744342c0268ad43ca6ca627619ced506d5fe08f27cdc34963b0b03 +"embla-carousel@npm:^8.1.4": + version: 8.1.4 + resolution: "embla-carousel@npm:8.1.4" + checksum: 10c0/8dcd7fa5561fc354dd422440f3e24da8e2bc75617d8c053b88d44a603b69cb123a7ff3deae3eaa174b60a3a2d6bd8852b8ad21c7a3cca4692ce7da4078febf66 languageName: node linkType: hard @@ -3399,7 +3705,7 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-import@npm:^2.25.4": +"eslint-plugin-import@npm:^2.29.1": version: 2.29.1 resolution: "eslint-plugin-import@npm:2.29.1" dependencies: @@ -3799,73 +4105,73 @@ __metadata: version: 0.0.0-use.local resolution: "frigate-hass-card@workspace:." dependencies: - "@babel/core": "npm:^7.19.0" + "@babel/core": "npm:^7.24.7" "@babel/plugin-proposal-class-properties": "npm:^7.18.6" - "@babel/plugin-proposal-decorators": "npm:^7.19.0" - "@cycjimmy/jsmpeg-player": "npm:^6.0.4" + "@babel/plugin-proposal-decorators": "npm:^7.24.7" + "@cycjimmy/jsmpeg-player": "npm:^6.0.5" "@dermotduffy/custom-card-helpers": "npm:^1.9.0" "@dermotduffy/panzoom": "npm:^4.5.1" "@egjs/hammerjs": "npm:^2.0.17" - "@graphiteds/core": "npm:^1.9.11" + "@graphiteds/core": "npm:^1.9.21" "@lit-labs/scoped-registry-mixin": "npm:^1.0.3" "@lit-labs/task": "npm:^1.1.3" "@rollup/plugin-babel": "npm:^5.3.1" "@rollup/plugin-commonjs": "npm:^22.0.2" - "@rollup/plugin-image": "npm:^3.0.2" + "@rollup/plugin-image": "npm:^3.0.3" "@rollup/plugin-json": "npm:^4.1.0" "@rollup/plugin-node-resolve": "npm:^13.3.0" "@rollup/plugin-replace": "npm:^4.0.0" "@rollup/plugin-typescript": "npm:^11.1.6" - "@types/bluebird": "npm:^3.5.36" - "@types/lodash-es": "npm:^4.17.5" - "@types/masonry-layout": "npm:^4.2.5" - "@typescript-eslint/eslint-plugin": "npm:^7.12.0" - "@typescript-eslint/parser": "npm:^7.12.0" + "@types/bluebird": "npm:^3.5.42" + "@types/lodash-es": "npm:^4.17.12" + "@types/masonry-layout": "npm:^4.2.8" + "@typescript-eslint/eslint-plugin": "npm:^7.13.0" + "@typescript-eslint/parser": "npm:^7.13.0" "@vitest/coverage-istanbul": "npm:^1.6.0" - component-emitter: "npm:^1.3.0" + component-emitter: "npm:^1.3.1" crypto: "npm:^1.0.1" date-fns: "npm:^3.6.0" date-fns-tz: "npm:^3.1.3" docsify-cli: "npm:^4.4.4" - embla-carousel: "npm:8.0.0-rc14" - embla-carousel-wheel-gestures: "npm:8.0.0-rc04" + embla-carousel: "npm:^8.1.4" + embla-carousel-wheel-gestures: "npm:^8.0.1" eslint: "npm:^8.57.0" eslint-config-airbnb-base: "npm:^15.0.0" eslint-config-prettier: "npm:^9.1.0" - eslint-plugin-import: "npm:^2.25.4" - home-assistant-js-websocket: "npm:^8.0.0" - jsdom: "npm:^21.1.1" + eslint-plugin-import: "npm:^2.29.1" + home-assistant-js-websocket: "npm:^8.2.0" + jsdom: "npm:^21.1.2" keycharm: "npm:^0.4.0" - lit: "npm:^3.1.2" + lit: "npm:^3.1.4" lodash-es: "npm:^4.17.21" - markdown-link-check: "npm:^3.12.1" + markdown-link-check: "npm:^3.12.2" masonry-layout: "npm:^4.2.2" - moment: "npm:^2.29.4" + moment: "npm:^2.30.1" p-queue: "npm:^8.0.1" - prettier: "npm:^3.3.1" + prettier: "npm:^3.3.2" propagating-hammerjs: "npm:^2.0.1" - quick-lru: "npm:^6.1.0" - rollup: "npm:^2.79.0" + quick-lru: "npm:^6.1.2" + rollup: "npm:^2.79.1" rollup-plugin-git-info: "npm:^1.0.0" - rollup-plugin-serve: "npm:^2.0.1" + rollup-plugin-serve: "npm:^2.0.3" rollup-plugin-styles: "npm:^4.0.0" rollup-plugin-terser: "npm:^7.0.2" - rollup-plugin-visualizer: "npm:^5.8.2" - sass: "npm:^1.54.9" + rollup-plugin-visualizer: "npm:^5.12.0" + sass: "npm:^1.77.4" screenfull: "npm:^6.0.2" side-drawer: "npm:^3.1.0" ts-prune: "npm:^0.10.3" - type-fest: "npm:^4.18.0" + type-fest: "npm:^4.20.0" typescript: "npm:^5.4.5" uuid: "npm:^8.3.2" vis-data: "npm:^7.1.9" vis-timeline: "npm:^7.7.3" - vis-util: "npm:^5.0.2" - vitest: "npm:^1.5.0" + vis-util: "npm:^5.0.7" + vitest: "npm:^1.6.0" vitest-mock-extended: "npm:^1.3.1" web-dialog: "npm:^0.0.11" - xss: "npm:^1.0.14" - zod: "npm:^3.21.4" + xss: "npm:^1.0.15" + zod: "npm:^3.23.8" languageName: unknown linkType: soft @@ -4290,7 +4596,7 @@ __metadata: languageName: node linkType: hard -"home-assistant-js-websocket@npm:^8.0.0": +"home-assistant-js-websocket@npm:^8.2.0": version: 8.2.0 resolution: "home-assistant-js-websocket@npm:8.2.0" checksum: 10c0/9a1f1f5cb39ce0629653347d5ae31a14f14742596c15fea7bd72f4c0ee4ce4613b1172b4f4df52f293b4e5aeb3b5ead75f395d5fe5c4785193e7d00f8355ef5a @@ -4981,7 +5287,7 @@ __metadata: languageName: node linkType: hard -"jsdom@npm:^21.1.1": +"jsdom@npm:^21.1.2": version: 21.1.2 resolution: "jsdom@npm:21.1.2" dependencies: @@ -5227,7 +5533,7 @@ __metadata: languageName: node linkType: hard -"lit@npm:^2.0.0 || ^3.0.0, lit@npm:^3.1.2": +"lit@npm:^2.0.0 || ^3.0.0": version: 3.1.2 resolution: "lit@npm:3.1.2" dependencies: @@ -5249,6 +5555,17 @@ __metadata: languageName: node linkType: hard +"lit@npm:^3.1.4": + version: 3.1.4 + resolution: "lit@npm:3.1.4" + dependencies: + "@lit/reactive-element": "npm:^2.0.4" + lit-element: "npm:^4.0.4" + lit-html: "npm:^3.1.2" + checksum: 10c0/afa4954638e80f627c60bcbd2d800af710b9b3394a36cee9865b5ea5de95b4ec6d33de43ac0bf256b5b7c981d45c7c8ac0c7ddba6fcbd0c67d65986b0279b960 + languageName: node + linkType: hard + "livereload-js@npm:^3.3.1": version: 3.4.1 resolution: "livereload-js@npm:3.4.1" @@ -5454,13 +5771,13 @@ __metadata: languageName: node linkType: hard -"markdown-link-check@npm:^3.12.1": - version: 3.12.1 - resolution: "markdown-link-check@npm:3.12.1" +"markdown-link-check@npm:^3.12.2": + version: 3.12.2 + resolution: "markdown-link-check@npm:3.12.2" dependencies: async: "npm:^3.2.5" - chalk: "npm:^5.2.0" - commander: "npm:^10.0.1" + chalk: "npm:^5.3.0" + commander: "npm:^12.1.0" link-check: "npm:^5.3.0" lodash: "npm:^4.17.21" markdown-link-extractor: "npm:^4.0.2" @@ -5469,7 +5786,7 @@ __metadata: proxy-agent: "npm:^6.4.0" bin: markdown-link-check: markdown-link-check - checksum: 10c0/25d45459dc8b948f75cfea23efb4ba3fbab210d9aa67ab5090dd2d2185b93c5debe43d4c07da1a717e70e3becfd0e84a60f52733990ebf8800f821f2213cb317 + checksum: 10c0/c1d4d2f69322d1ed98437db9f37807f982a3dc9aa1203841f40c71ac4e2a733b6c36311aa6f7f3a6fc34d7713e51c0f3704d55bf59fc607b30360ecfb5465d2d languageName: node linkType: hard @@ -5752,7 +6069,7 @@ __metadata: languageName: node linkType: hard -"moment@npm:^2.29.4": +"moment@npm:^2.30.1": version: 2.30.1 resolution: "moment@npm:2.30.1" checksum: 10c0/865e4279418c6de666fca7786607705fd0189d8a7b7624e2e56be99290ac846f90878a6f602e34b4e0455c549b85385b1baf9966845962b313699e7cb847543a @@ -6813,12 +7130,12 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^3.3.1": - version: 3.3.1 - resolution: "prettier@npm:3.3.1" +"prettier@npm:^3.3.2": + version: 3.3.2 + resolution: "prettier@npm:3.3.2" bin: prettier: bin/prettier.cjs - checksum: 10c0/c25a709c9f0be670dc6bcb190b622347e1dbeb6c3e7df8b0711724cb64d8647c60b839937a4df4df18e9cfb556c2b08ca9d24d9645eb5488a7fc032a2c4d5cb3 + checksum: 10c0/39ed27d17f0238da6dd6571d63026566bd790d3d0edac57c285fbab525982060c8f1e01955fe38134ab10f0951a6076da37f015db8173c02f14bc7f0803a384c languageName: node linkType: hard @@ -6955,7 +7272,7 @@ __metadata: languageName: node linkType: hard -"quick-lru@npm:^6.1.0": +"quick-lru@npm:^6.1.2": version: 6.1.2 resolution: "quick-lru@npm:6.1.2" checksum: 10c0/f499f07bd276eec460c4d7d2ee286c519f3bd189cbbb5ddf3eb929e2182e4997f66b951ea8d24b3f3cee8ed5ac9f0006bf40636f082acd1b38c050a4cbf07ed3 @@ -7142,7 +7459,7 @@ __metadata: languageName: node linkType: hard -"rollup-plugin-serve@npm:^2.0.1": +"rollup-plugin-serve@npm:^2.0.3": version: 2.0.3 resolution: "rollup-plugin-serve@npm:2.0.3" dependencies: @@ -7194,7 +7511,7 @@ __metadata: languageName: node linkType: hard -"rollup-plugin-visualizer@npm:^5.8.2": +"rollup-plugin-visualizer@npm:^5.12.0": version: 5.12.0 resolution: "rollup-plugin-visualizer@npm:5.12.0" dependencies: @@ -7213,7 +7530,7 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^2.63.0, rollup@npm:^2.79.0": +"rollup@npm:^2.63.0, rollup@npm:^2.79.1": version: 2.79.1 resolution: "rollup@npm:2.79.1" dependencies: @@ -7334,16 +7651,16 @@ __metadata: languageName: node linkType: hard -"sass@npm:^1.54.9": - version: 1.71.1 - resolution: "sass@npm:1.71.1" +"sass@npm:^1.77.4": + version: 1.77.4 + resolution: "sass@npm:1.77.4" dependencies: chokidar: "npm:>=3.0.0 <4.0.0" immutable: "npm:^4.0.0" source-map-js: "npm:>=0.6.2 <2.0.0" bin: sass: sass.js - checksum: 10c0/59d79a6e106747746792b0c71908ae0aecdaf9b794d5724ee64e5249412f0d8ebe7ee2bf12946618848f14f949c4f6b530d82da3e62ab31c71198c6f73002130 + checksum: 10c0/b9cb4882bded282aabe38d011adfce375e1f282184fcf93dc3da5d5be834c6aa53c474c15634c351ef7bd85146cfd1cc81343654cc3bcf000d78e856da4225ef languageName: node linkType: hard @@ -8147,10 +8464,10 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^4.18.0": - version: 4.18.0 - resolution: "type-fest@npm:4.18.0" - checksum: 10c0/d16d9be71ceeb5341cfa7e21d9081e843e74791fb60b5e2555caa26c259c9bcbffd965e1a1c8e571856efddb317b4b1802f73938723f399f1070e9db5b182f4e +"type-fest@npm:^4.20.0": + version: 4.20.0 + resolution: "type-fest@npm:4.20.0" + checksum: 10c0/d0b35152f7f0b34b3048fb14d93d8d6dfe6288d443a2ab7b7b8c1dd902278e092aa057ad7cfc30f269f17d42eeb14a19d4d147ecb14dff74a5941c5c82248efa languageName: node linkType: hard @@ -8449,7 +8766,7 @@ __metadata: languageName: node linkType: hard -"vis-util@npm:^5.0.2": +"vis-util@npm:^5.0.7": version: 5.0.7 resolution: "vis-util@npm:5.0.7" peerDependencies: @@ -8459,9 +8776,9 @@ __metadata: languageName: node linkType: hard -"vite-node@npm:1.5.0": - version: 1.5.0 - resolution: "vite-node@npm:1.5.0" +"vite-node@npm:1.6.0": + version: 1.6.0 + resolution: "vite-node@npm:1.6.0" dependencies: cac: "npm:^6.7.14" debug: "npm:^4.3.4" @@ -8470,7 +8787,7 @@ __metadata: vite: "npm:^5.0.0" bin: vite-node: vite-node.mjs - checksum: 10c0/85f9e8616f3612c71193a2bbdfb00f610685108a65eaa7ac535655ca1bd65dda5436ee577465436f715966f34e4b25b54140bbd584fe2c95ea0726acf4ecd351 + checksum: 10c0/0807e6501ac7763e0efa2b4bd484ce99fb207e92c98624c9f8999d1f6727ac026e457994260fa7fdb7060d87546d197081e46a705d05b0136a38b6f03715cbc2 languageName: node linkType: hard @@ -8526,15 +8843,15 @@ __metadata: languageName: node linkType: hard -"vitest@npm:^1.5.0": - version: 1.5.0 - resolution: "vitest@npm:1.5.0" +"vitest@npm:^1.6.0": + version: 1.6.0 + resolution: "vitest@npm:1.6.0" dependencies: - "@vitest/expect": "npm:1.5.0" - "@vitest/runner": "npm:1.5.0" - "@vitest/snapshot": "npm:1.5.0" - "@vitest/spy": "npm:1.5.0" - "@vitest/utils": "npm:1.5.0" + "@vitest/expect": "npm:1.6.0" + "@vitest/runner": "npm:1.6.0" + "@vitest/snapshot": "npm:1.6.0" + "@vitest/spy": "npm:1.6.0" + "@vitest/utils": "npm:1.6.0" acorn-walk: "npm:^8.3.2" chai: "npm:^4.3.10" debug: "npm:^4.3.4" @@ -8548,13 +8865,13 @@ __metadata: tinybench: "npm:^2.5.1" tinypool: "npm:^0.8.3" vite: "npm:^5.0.0" - vite-node: "npm:1.5.0" + vite-node: "npm:1.6.0" why-is-node-running: "npm:^2.2.2" peerDependencies: "@edge-runtime/vm": "*" "@types/node": ^18.0.0 || >=20.0.0 - "@vitest/browser": 1.5.0 - "@vitest/ui": 1.5.0 + "@vitest/browser": 1.6.0 + "@vitest/ui": 1.6.0 happy-dom: "*" jsdom: "*" peerDependenciesMeta: @@ -8572,7 +8889,7 @@ __metadata: optional: true bin: vitest: vitest.mjs - checksum: 10c0/87f6666cccd52678a0e1dbf32e7492e4003580a168114221e4c2d404d53097d886a8be4c5c379e347d0e749affa0ea5416e4e3a0356aeca228a77ee54891ca3c + checksum: 10c0/065da5b8ead51eb174d93dac0cd50042ca9539856dc25e340ea905d668c41961f7e00df3e388e6c76125b2c22091db2e8465f993d0f6944daf9598d549e562e7 languageName: node linkType: hard @@ -8830,15 +9147,15 @@ __metadata: languageName: node linkType: hard -"xss@npm:^1.0.14": - version: 1.0.14 - resolution: "xss@npm:1.0.14" +"xss@npm:^1.0.15": + version: 1.0.15 + resolution: "xss@npm:1.0.15" dependencies: commander: "npm:^2.20.3" cssfilter: "npm:0.0.10" bin: xss: bin/xss - checksum: 10c0/0a9b4d71781c8418a0327e86e5991dffe8d8b58d465d391ea74e3fa102168d1aa70a438c85d6af90e76f457bbb6041350b700bff7ad10077c5d816512f10ee0d + checksum: 10c0/9b31bee62a208f78e2b7bc8154e3ee87d980f4661dc4ab850ce6f4de7bc50eb152f0bdc13fa759ff8ab6d9bfdf8c0d79cf9f6f86249872b92181912309bccd08 languageName: node linkType: hard @@ -8953,9 +9270,9 @@ __metadata: languageName: node linkType: hard -"zod@npm:^3.21.4": - version: 3.22.4 - resolution: "zod@npm:3.22.4" - checksum: 10c0/7578ab283dac0eee66a0ad0fc4a7f28c43e6745aadb3a529f59a4b851aa10872b3890398b3160f257f4b6817b4ce643debdda4fb21a2c040adda7862cab0a587 +"zod@npm:^3.23.8": + version: 3.23.8 + resolution: "zod@npm:3.23.8" + checksum: 10c0/8f14c87d6b1b53c944c25ce7a28616896319d95bc46a9660fe441adc0ed0a81253b02b5abdaeffedbeb23bdd25a0bf1c29d2c12dd919aef6447652dd295e3e69 languageName: node linkType: hard From 7356044a089a16ef8a0569dc4eb965fbe87164c3 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Tue, 11 Jun 2024 15:53:08 -0300 Subject: [PATCH 149/189] Update rollup to v3 and also its plugins --- package.json | 20 +- rollup.config.js | 8 +- yarn.lock | 1279 +++++++++++++++++++++++----------------------- 3 files changed, 666 insertions(+), 641 deletions(-) diff --git a/package.json b/package.json index ba966890..4a969ab3 100644 --- a/package.json +++ b/package.json @@ -50,14 +50,15 @@ }, "devDependencies": { "@babel/core": "^7.24.7", - "@babel/plugin-proposal-class-properties": "^7.18.6", "@babel/plugin-proposal-decorators": "^7.24.7", - "@rollup/plugin-babel": "^5.3.1", - "@rollup/plugin-commonjs": "^22.0.2", + "@babel/plugin-transform-class-properties": "^7.24.7", + "@rollup/plugin-babel": "^6.0.4", + "@rollup/plugin-commonjs": "^26.0.1", "@rollup/plugin-image": "^3.0.3", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-node-resolve": "^13.3.0", - "@rollup/plugin-replace": "^4.0.0", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-replace": "^5.0.7", + "@rollup/plugin-terser": "^0.4.4", "@rollup/plugin-typescript": "^11.1.6", "@types/lodash-es": "^4.17.12", "@types/masonry-layout": "^4.2.8", @@ -72,11 +73,10 @@ "jsdom": "^21.1.2", "markdown-link-check": "^3.12.2", "prettier": "^3.3.2", - "rollup": "^2.79.1", + "rollup": "^3.29.4", "rollup-plugin-git-info": "^1.0.0", - "rollup-plugin-serve": "^2.0.3", - "rollup-plugin-styles": "^4.0.0", - "rollup-plugin-terser": "^7.0.2", + "rollup-plugin-serve": "^1.1.1", + "rollup-plugin-styler": "^1.8.0", "rollup-plugin-visualizer": "^5.12.0", "sass": "^1.77.4", "ts-prune": "^0.10.3", diff --git a/rollup.config.js b/rollup.config.js index 628db8f2..c3b3f421 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -1,10 +1,10 @@ import typescript from '@rollup/plugin-typescript'; import commonjs from '@rollup/plugin-commonjs'; -import nodeResolve from '@rollup/plugin-node-resolve'; -import { terser } from 'rollup-plugin-terser'; +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import terser from '@rollup/plugin-terser'; import serve from 'rollup-plugin-serve'; import json from '@rollup/plugin-json'; -import styles from 'rollup-plugin-styles'; +import styles from 'rollup-plugin-styler'; import image from '@rollup/plugin-image'; import replace from '@rollup/plugin-replace'; import gitInfo from 'rollup-plugin-git-info'; @@ -30,7 +30,7 @@ const serveopts = { * @type {import('rollup').RollupOptions['plugins']} */ const plugins = [ - gitInfo({ enableBuildDate: true, updateVersion: false }), + gitInfo.default({ enableBuildDate: true, updateVersion: false }), styles({ modules: false, // Behavior of inject mode, without actually injecting style diff --git a/yarn.lock b/yarn.lock index 04680282..4d2adda6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,7 +29,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.10.4, @babel/code-frame@npm:^7.23.5": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.23.5": version: 7.23.5 resolution: "@babel/code-frame@npm:7.23.5" dependencies: @@ -133,15 +133,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-annotate-as-pure@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-annotate-as-pure@npm:7.22.5" - dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10c0/5a80dc364ddda26b334bbbc0f6426cab647381555ef7d0cd32eb284e35b867c012ce6ce7d52a64672ed71383099c99d32765b3d260626527bb0e3470b0f58e45 - languageName: node - linkType: hard - "@babel/helper-annotate-as-pure@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-annotate-as-pure@npm:7.24.7" @@ -177,25 +168,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-create-class-features-plugin@npm:^7.18.6": - version: 7.24.0 - resolution: "@babel/helper-create-class-features-plugin@npm:7.24.0" - dependencies: - "@babel/helper-annotate-as-pure": "npm:^7.22.5" - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-function-name": "npm:^7.23.0" - "@babel/helper-member-expression-to-functions": "npm:^7.23.0" - "@babel/helper-optimise-call-expression": "npm:^7.22.5" - "@babel/helper-replace-supers": "npm:^7.22.20" - "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.22.5" - "@babel/helper-split-export-declaration": "npm:^7.22.6" - semver: "npm:^6.3.1" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10c0/341548496df202805489422a160bba75b111d994c64d788a397c35f01784632af48bf06023af8aa2fe72c2c254f8c885b4e0f7f3df5ef17a37370f2feaf80328 - languageName: node - linkType: hard - "@babel/helper-create-class-features-plugin@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-create-class-features-plugin@npm:7.24.7" @@ -269,15 +241,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-member-expression-to-functions@npm:^7.22.15, @babel/helper-member-expression-to-functions@npm:^7.23.0": - version: 7.23.0 - resolution: "@babel/helper-member-expression-to-functions@npm:7.23.0" - dependencies: - "@babel/types": "npm:^7.23.0" - checksum: 10c0/b810daddf093ffd0802f1429052349ed9ea08ef7d0c56da34ffbcdecbdafac86f95bdea2fe30e0e0e629febc7dd41b56cb5eacc10d1a44336d37b755dac31fa4 - languageName: node - linkType: hard - "@babel/helper-member-expression-to-functions@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-member-expression-to-functions@npm:7.24.7" @@ -288,16 +251,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-imports@npm:^7.10.4, @babel/helper-module-imports@npm:^7.22.15": - version: 7.22.15 - resolution: "@babel/helper-module-imports@npm:7.22.15" - dependencies: - "@babel/types": "npm:^7.22.15" - checksum: 10c0/4e0d7fc36d02c1b8c8b3006dfbfeedf7a367d3334a04934255de5128115ea0bafdeb3e5736a2559917f0653e4e437400d54542da0468e08d3cbc86d3bbfa8f30 - languageName: node - linkType: hard - -"@babel/helper-module-imports@npm:^7.24.7": +"@babel/helper-module-imports@npm:^7.18.6, @babel/helper-module-imports@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-module-imports@npm:7.24.7" dependencies: @@ -307,6 +261,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-imports@npm:^7.22.15": + version: 7.22.15 + resolution: "@babel/helper-module-imports@npm:7.22.15" + dependencies: + "@babel/types": "npm:^7.22.15" + checksum: 10c0/4e0d7fc36d02c1b8c8b3006dfbfeedf7a367d3334a04934255de5128115ea0bafdeb3e5736a2559917f0653e4e437400d54542da0468e08d3cbc86d3bbfa8f30 + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.23.3": version: 7.23.3 resolution: "@babel/helper-module-transforms@npm:7.23.3" @@ -337,15 +300,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-optimise-call-expression@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-optimise-call-expression@npm:7.22.5" - dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10c0/31b41a764fc3c585196cf5b776b70cf4705c132e4ce9723f39871f215f2ddbfb2e28a62f9917610f67c8216c1080482b9b05f65dd195dae2a52cef461f2ac7b8 - languageName: node - linkType: hard - "@babel/helper-optimise-call-expression@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-optimise-call-expression@npm:7.24.7" @@ -355,13 +309,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-plugin-utils@npm:^7.18.6": - version: 7.24.0 - resolution: "@babel/helper-plugin-utils@npm:7.24.0" - checksum: 10c0/90f41bd1b4dfe7226b1d33a4bb745844c5c63e400f9e4e8bf9103a7ceddd7d425d65333b564d9daba3cebd105985764d51b4bd4c95822b97c2e3ac1201a8a5da - languageName: node - linkType: hard - "@babel/helper-plugin-utils@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-plugin-utils@npm:7.24.7" @@ -369,19 +316,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-replace-supers@npm:^7.22.20": - version: 7.22.20 - resolution: "@babel/helper-replace-supers@npm:7.22.20" - dependencies: - "@babel/helper-environment-visitor": "npm:^7.22.20" - "@babel/helper-member-expression-to-functions": "npm:^7.22.15" - "@babel/helper-optimise-call-expression": "npm:^7.22.5" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10c0/6b0858811ad46873817c90c805015d63300e003c5a85c147a17d9845fa2558a02047c3cc1f07767af59014b2dd0fa75b503e5bc36e917f360e9b67bb6f1e79f4 - languageName: node - linkType: hard - "@babel/helper-replace-supers@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-replace-supers@npm:7.24.7" @@ -414,15 +348,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-skip-transparent-expression-wrappers@npm:^7.22.5": - version: 7.22.5 - resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.22.5" - dependencies: - "@babel/types": "npm:^7.22.5" - checksum: 10c0/ab7fa2aa709ab49bb8cd86515a1e715a3108c4bb9a616965ba76b43dc346dee66d1004ccf4d222b596b6224e43e04cbc5c3a34459501b388451f8c589fbc3691 - languageName: node - linkType: hard - "@babel/helper-skip-transparent-expression-wrappers@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.24.7" @@ -555,18 +480,6 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-proposal-class-properties@npm:^7.18.6": - version: 7.18.6 - resolution: "@babel/plugin-proposal-class-properties@npm:7.18.6" - dependencies: - "@babel/helper-create-class-features-plugin": "npm:^7.18.6" - "@babel/helper-plugin-utils": "npm:^7.18.6" - peerDependencies: - "@babel/core": ^7.0.0-0 - checksum: 10c0/d5172ac6c9948cdfc387e94f3493ad86cb04035cf7433f86b5d358270b1b9752dc25e176db0c5d65892a246aca7bdb4636672e15626d7a7de4bc0bd0040168d9 - languageName: node - linkType: hard - "@babel/plugin-proposal-decorators@npm:^7.24.7": version: 7.24.7 resolution: "@babel/plugin-proposal-decorators@npm:7.24.7" @@ -591,6 +504,18 @@ __metadata: languageName: node linkType: hard +"@babel/plugin-transform-class-properties@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-class-properties@npm:7.24.7" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10c0/75018a466c7ede3d2397e158891c224ba7fca72864506ce067ddbc02fc65191d44da4d6379c996d0c7f09019e26b5c3f5f1d3a639cd98366519723886f0689d0 + languageName: node + linkType: hard + "@babel/template@npm:^7.22.15, @babel/template@npm:^7.24.0": version: 7.24.0 resolution: "@babel/template@npm:7.24.0" @@ -1221,37 +1146,41 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-babel@npm:^5.3.1": - version: 5.3.1 - resolution: "@rollup/plugin-babel@npm:5.3.1" +"@rollup/plugin-babel@npm:^6.0.4": + version: 6.0.4 + resolution: "@rollup/plugin-babel@npm:6.0.4" dependencies: - "@babel/helper-module-imports": "npm:^7.10.4" - "@rollup/pluginutils": "npm:^3.1.0" + "@babel/helper-module-imports": "npm:^7.18.6" + "@rollup/pluginutils": "npm:^5.0.1" peerDependencies: "@babel/core": ^7.0.0 "@types/babel__core": ^7.1.9 - rollup: ^1.20.0||^2.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: "@types/babel__core": optional: true - checksum: 10c0/2766134dd5567c0d4fd6909d1f511ce9bf3bd9d727e1bc5ffdd6097a3606faca324107ae8e0961839ee4dbb45e5e579ae601efe472fc0a271259aea79920cafa + rollup: + optional: true + checksum: 10c0/5a7c04fa6d608512b597835e749aef33e129ee9ed6cc9e33489b7d43937358fc8aba48b00819604d0bc9b7c20790a6c035e4136e8d9f70cf0d0f056ba547e700 languageName: node linkType: hard -"@rollup/plugin-commonjs@npm:^22.0.2": - version: 22.0.2 - resolution: "@rollup/plugin-commonjs@npm:22.0.2" +"@rollup/plugin-commonjs@npm:^26.0.1": + version: 26.0.1 + resolution: "@rollup/plugin-commonjs@npm:26.0.1" dependencies: - "@rollup/pluginutils": "npm:^3.1.0" + "@rollup/pluginutils": "npm:^5.0.1" commondir: "npm:^1.0.1" - estree-walker: "npm:^2.0.1" - glob: "npm:^7.1.6" - is-reference: "npm:^1.2.1" - magic-string: "npm:^0.25.7" - resolve: "npm:^1.17.0" + estree-walker: "npm:^2.0.2" + glob: "npm:^10.4.1" + is-reference: "npm:1.2.1" + magic-string: "npm:^0.30.3" peerDependencies: - rollup: ^2.68.0 - checksum: 10c0/2b9df23a40493e5ca6dab50b28a7803c0fe73f5fe84c16f38e3e00e38b9a246de450d1ee8dba145ea5dc3c661616a4ae1927b084fdbb47ae3afcac979fdfa1d1 + rollup: ^2.68.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10c0/483290d327bdb4147584c37d73e47df2c717735f1902cd2f66ebc83c7b40ae10e5a8d5e626f24b76ad4ac489eab4a8c13869410aad663810848b0abc89a630cf languageName: node linkType: hard @@ -1281,31 +1210,67 @@ __metadata: languageName: node linkType: hard -"@rollup/plugin-node-resolve@npm:^13.3.0": - version: 13.3.0 - resolution: "@rollup/plugin-node-resolve@npm:13.3.0" +"@rollup/plugin-json@npm:^6.1.0": + version: 6.1.0 + resolution: "@rollup/plugin-json@npm:6.1.0" dependencies: - "@rollup/pluginutils": "npm:^3.1.0" - "@types/resolve": "npm:1.17.1" - deepmerge: "npm:^4.2.2" - is-builtin-module: "npm:^3.1.0" - is-module: "npm:^1.0.0" - resolve: "npm:^1.19.0" + "@rollup/pluginutils": "npm:^5.1.0" peerDependencies: - rollup: ^2.42.0 - checksum: 10c0/6caa32a8304a20f1c9953111b25e9543f4de7d254958d81ce0158ad909e4493946bc2060c4ace23d9748b560ebc84c920ee7bc1b7d50dbf8ba852ef13c91af58 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10c0/9400c431b5e0cf3088ba2eb2d038809a2b0fb2a84ed004997da85582f48cd64958ed3168893c4f2c8109e38652400ed68282d0c92bf8ec07a3b2ef2e1ceab0b7 languageName: node linkType: hard -"@rollup/plugin-replace@npm:^4.0.0": - version: 4.0.0 - resolution: "@rollup/plugin-replace@npm:4.0.0" +"@rollup/plugin-node-resolve@npm:^15.2.3": + version: 15.2.3 + resolution: "@rollup/plugin-node-resolve@npm:15.2.3" dependencies: - "@rollup/pluginutils": "npm:^3.1.0" - magic-string: "npm:^0.25.7" + "@rollup/pluginutils": "npm:^5.0.1" + "@types/resolve": "npm:1.20.2" + deepmerge: "npm:^4.2.2" + is-builtin-module: "npm:^3.2.1" + is-module: "npm:^1.0.0" + resolve: "npm:^1.22.1" peerDependencies: - rollup: ^1.20.0 || ^2.0.0 - checksum: 10c0/90c8983ec6944dcc85bb8f0a4448a57329f43662ca5d6ebf26aad97c3871d39ba7f2d344569bc93f35eb57ddd697470b6fcb255cd1f4a9331f3334b16cb3c1aa + rollup: ^2.78.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10c0/598c15615086f26e28c4b3dbf966682af7fb0e5bc277cc4e57f559668a3be675a63ab261eb34729ce9569c3a51342c48863e50b5efe02e0fc1571828f0113f9d + languageName: node + linkType: hard + +"@rollup/plugin-replace@npm:^5.0.7": + version: 5.0.7 + resolution: "@rollup/plugin-replace@npm:5.0.7" + dependencies: + "@rollup/pluginutils": "npm:^5.0.1" + magic-string: "npm:^0.30.3" + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10c0/1732af42febdb42d96fd7916b65ca94a550a028d1ea5efa40d5d7a99ab3c336e41efac14a77eefef18b956b4b7335969c6252f2a22bf0223dc8b4a7a53f89ed3 + languageName: node + linkType: hard + +"@rollup/plugin-terser@npm:^0.4.4": + version: 0.4.4 + resolution: "@rollup/plugin-terser@npm:0.4.4" + dependencies: + serialize-javascript: "npm:^6.0.1" + smob: "npm:^1.0.0" + terser: "npm:^5.17.4" + peerDependencies: + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + checksum: 10c0/b9cb6c8f02ac1c1344019e9fb854321b74f880efebc41b6bdd84f18331fce0f4a2aadcdb481042245cd3f409b429ac363af71f9efec4a2024731d67d32af36ee languageName: node linkType: hard @@ -1328,7 +1293,7 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^3.0.8, @rollup/pluginutils@npm:^3.1.0": +"@rollup/pluginutils@npm:^3.0.8": version: 3.1.0 resolution: "@rollup/pluginutils@npm:3.1.0" dependencies: @@ -1341,17 +1306,7 @@ __metadata: languageName: node linkType: hard -"@rollup/pluginutils@npm:^4.1.2": - version: 4.2.1 - resolution: "@rollup/pluginutils@npm:4.2.1" - dependencies: - estree-walker: "npm:^2.0.1" - picomatch: "npm:^2.2.2" - checksum: 10c0/3ee56b2c8f1ed8dfd0a92631da1af3a2dfdd0321948f089b3752b4de1b54dc5076701eadd0e5fc18bd191b77af594ac1db6279e83951238ba16bf8a414c64c48 - languageName: node - linkType: hard - -"@rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.1.0": +"@rollup/pluginutils@npm:^5.0.0, @rollup/pluginutils@npm:^5.0.1, @rollup/pluginutils@npm:^5.1.0": version: 5.1.0 resolution: "@rollup/pluginutils@npm:5.1.0" dependencies: @@ -1530,15 +1485,6 @@ __metadata: languageName: node linkType: hard -"@types/cssnano@npm:^5.0.0": - version: 5.0.0 - resolution: "@types/cssnano@npm:5.0.0" - dependencies: - postcss: "npm:^8" - checksum: 10c0/3b939509d65c053c274dc261cef17d9329e02d82784b569e441e01fb61dbcd5c914c5f7f53499cc641a1b224c30a9c814e419f8cb682be249d87fa2ddc20e9ae - languageName: node - linkType: hard - "@types/estree@npm:*, @types/estree@npm:1.0.5, @types/estree@npm:^1.0.0": version: 1.0.5 resolution: "@types/estree@npm:1.0.5" @@ -1626,12 +1572,10 @@ __metadata: languageName: node linkType: hard -"@types/resolve@npm:1.17.1": - version: 1.17.1 - resolution: "@types/resolve@npm:1.17.1" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/6eeb9c27d99bf4b393bf168d43208f63e78cefca5644662a0bdb2bdbf8352386f4f3aca66add138fc41bce5f66fd48a0de430a1473f11b612fbed0375ae78031 +"@types/resolve@npm:1.20.2": + version: 1.20.2 + resolution: "@types/resolve@npm:1.20.2" + checksum: 10c0/c5b7e1770feb5ccfb6802f6ad82a7b0d50874c99331e0c9b259e415e55a38d7a86ad0901c57665d93f75938be2a6a0bc9aa06c9749192cadb2e4512800bbc6e6 languageName: node linkType: hard @@ -2254,7 +2198,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.0.0, browserslist@npm:^4.21.4, browserslist@npm:^4.22.2": +"browserslist@npm:^4.0.0, browserslist@npm:^4.22.2": version: 4.23.0 resolution: "browserslist@npm:4.23.0" dependencies: @@ -2268,6 +2212,20 @@ __metadata: languageName: node linkType: hard +"browserslist@npm:^4.23.0": + version: 4.23.1 + resolution: "browserslist@npm:4.23.1" + dependencies: + caniuse-lite: "npm:^1.0.30001629" + electron-to-chromium: "npm:^1.4.796" + node-releases: "npm:^2.0.14" + update-browserslist-db: "npm:^1.0.16" + bin: + browserslist: cli.js + checksum: 10c0/eb47c7ab9d60db25ce2faca70efeb278faa7282a2f62b7f2fa2f92e5f5251cf65144244566c86559419ff4f6d78f59ea50e39911321ad91f3b27788901f1f5e9 + languageName: node + linkType: hard + "buffer-from@npm:^1.0.0": version: 1.1.2 resolution: "buffer-from@npm:1.1.2" @@ -2370,6 +2328,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001629": + version: 1.0.30001632 + resolution: "caniuse-lite@npm:1.0.30001632" + checksum: 10c0/960af2c7ed4367d6b72a164ecb9050ea9eada28c61e2134baaa712862364b9b6b41247c3ff4c2a497f91e879c5a1c9c7713080ac2d0c72eb4bee5ef2f4e24d62 + languageName: node + linkType: hard + "chai@npm:^4.3.10": version: 4.4.1 resolution: "chai@npm:4.4.1" @@ -2591,7 +2556,7 @@ __metadata: languageName: node linkType: hard -"colord@npm:^2.9.1": +"colord@npm:^2.9.3": version: 2.9.3 resolution: "colord@npm:2.9.3" checksum: 10c0/9699e956894d8996b28c686afe8988720785f476f59335c80ce852ded76ab3ebe252703aec53d9bef54f6219aea6b960fb3d9a8300058a1d0c0d4026460cd110 @@ -2723,6 +2688,23 @@ __metadata: languageName: node linkType: hard +"cosmiconfig@npm:^8.0.0": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" + dependencies: + import-fresh: "npm:^3.3.0" + js-yaml: "npm:^4.1.0" + parse-json: "npm:^5.2.0" + path-type: "npm:^4.0.0" + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10c0/0382a9ed13208f8bfc22ca2f62b364855207dffdb73dc26e150ade78c3093f1cf56172df2dd460c8caf2afa91c0ed4ec8a88c62f8f9cd1cf423d26506aa8797a + languageName: node + linkType: hard + "cp-file@npm:^7.0.0": version: 7.0.0 resolution: "cp-file@npm:7.0.0" @@ -2760,25 +2742,12 @@ __metadata: languageName: node linkType: hard -"css-declaration-sorter@npm:^6.3.1": - version: 6.4.1 - resolution: "css-declaration-sorter@npm:6.4.1" +"css-declaration-sorter@npm:^7.2.0": + version: 7.2.0 + resolution: "css-declaration-sorter@npm:7.2.0" peerDependencies: postcss: ^8.0.9 - checksum: 10c0/b8b664338dac528266a1ed9b27927ac51a907fb16bc1954fa9038b5286c442603bd494cc920c6a3616111309d18ee6b5a85b6d9927938efc942af452a5145160 - languageName: node - linkType: hard - -"css-select@npm:^4.1.3": - version: 4.3.0 - resolution: "css-select@npm:4.3.0" - dependencies: - boolbase: "npm:^1.0.0" - css-what: "npm:^6.0.1" - domhandler: "npm:^4.3.1" - domutils: "npm:^2.8.0" - nth-check: "npm:^2.0.1" - checksum: 10c0/a489d8e5628e61063d5a8fe0fa1cc7ae2478cb334a388a354e91cf2908154be97eac9fa7ed4dffe87a3e06cf6fcaa6016553115335c4fd3377e13dac7bd5a8e1 + checksum: 10c0/d8516be94f8f2daa233ef021688b965c08161624cbf830a4d7ee1099429437c0ee124d35c91b1c659cfd891a68e8888aa941726dab12279bc114aaed60a94606 languageName: node linkType: hard @@ -2795,17 +2764,27 @@ __metadata: languageName: node linkType: hard -"css-tree@npm:^1.1.2, css-tree@npm:^1.1.3": - version: 1.1.3 - resolution: "css-tree@npm:1.1.3" +"css-tree@npm:^2.3.1": + version: 2.3.1 + resolution: "css-tree@npm:2.3.1" dependencies: - mdn-data: "npm:2.0.14" - source-map: "npm:^0.6.1" - checksum: 10c0/499a507bfa39b8b2128f49736882c0dd636b0cd3370f2c69f4558ec86d269113286b7df469afc955de6a68b0dba00bc533e40022a73698081d600072d5d83c1c + mdn-data: "npm:2.0.30" + source-map-js: "npm:^1.0.1" + checksum: 10c0/6f8c1a11d5e9b14bf02d10717fc0351b66ba12594166f65abfbd8eb8b5b490dd367f5c7721db241a3c792d935fc6751fbc09f7e1598d421477ad9fadc30f4f24 languageName: node linkType: hard -"css-what@npm:^6.0.1, css-what@npm:^6.1.0": +"css-tree@npm:~2.2.0": + version: 2.2.1 + resolution: "css-tree@npm:2.2.1" + dependencies: + mdn-data: "npm:2.0.28" + source-map-js: "npm:^1.0.1" + checksum: 10c0/47e87b0f02f8ac22f57eceb65c58011dd142d2158128882a0bf963cf2eabb81a4ebbc2e3790c8289be7919fa8b83750c7b69272bd66772c708143b772ba3c186 + languageName: node + linkType: hard + +"css-what@npm:^6.1.0": version: 6.1.0 resolution: "css-what@npm:6.1.0" checksum: 10c0/a09f5a6b14ba8dcf57ae9a59474722e80f20406c53a61e9aedb0eedc693b135113ffe2983f4efc4b5065ae639442e9ae88df24941ef159c218b231011d733746 @@ -2828,73 +2807,73 @@ __metadata: languageName: node linkType: hard -"cssnano-preset-default@npm:^5.2.14": - version: 5.2.14 - resolution: "cssnano-preset-default@npm:5.2.14" +"cssnano-preset-default@npm:^6.1.2": + version: 6.1.2 + resolution: "cssnano-preset-default@npm:6.1.2" dependencies: - css-declaration-sorter: "npm:^6.3.1" - cssnano-utils: "npm:^3.1.0" - postcss-calc: "npm:^8.2.3" - postcss-colormin: "npm:^5.3.1" - postcss-convert-values: "npm:^5.1.3" - postcss-discard-comments: "npm:^5.1.2" - postcss-discard-duplicates: "npm:^5.1.0" - postcss-discard-empty: "npm:^5.1.1" - postcss-discard-overridden: "npm:^5.1.0" - postcss-merge-longhand: "npm:^5.1.7" - postcss-merge-rules: "npm:^5.1.4" - postcss-minify-font-values: "npm:^5.1.0" - postcss-minify-gradients: "npm:^5.1.1" - postcss-minify-params: "npm:^5.1.4" - postcss-minify-selectors: "npm:^5.2.1" - postcss-normalize-charset: "npm:^5.1.0" - postcss-normalize-display-values: "npm:^5.1.0" - postcss-normalize-positions: "npm:^5.1.1" - postcss-normalize-repeat-style: "npm:^5.1.1" - postcss-normalize-string: "npm:^5.1.0" - postcss-normalize-timing-functions: "npm:^5.1.0" - postcss-normalize-unicode: "npm:^5.1.1" - postcss-normalize-url: "npm:^5.1.0" - postcss-normalize-whitespace: "npm:^5.1.1" - postcss-ordered-values: "npm:^5.1.3" - postcss-reduce-initial: "npm:^5.1.2" - postcss-reduce-transforms: "npm:^5.1.0" - postcss-svgo: "npm:^5.1.0" - postcss-unique-selectors: "npm:^5.1.1" + browserslist: "npm:^4.23.0" + css-declaration-sorter: "npm:^7.2.0" + cssnano-utils: "npm:^4.0.2" + postcss-calc: "npm:^9.0.1" + postcss-colormin: "npm:^6.1.0" + postcss-convert-values: "npm:^6.1.0" + postcss-discard-comments: "npm:^6.0.2" + postcss-discard-duplicates: "npm:^6.0.3" + postcss-discard-empty: "npm:^6.0.3" + postcss-discard-overridden: "npm:^6.0.2" + postcss-merge-longhand: "npm:^6.0.5" + postcss-merge-rules: "npm:^6.1.1" + postcss-minify-font-values: "npm:^6.1.0" + postcss-minify-gradients: "npm:^6.0.3" + postcss-minify-params: "npm:^6.1.0" + postcss-minify-selectors: "npm:^6.0.4" + postcss-normalize-charset: "npm:^6.0.2" + postcss-normalize-display-values: "npm:^6.0.2" + postcss-normalize-positions: "npm:^6.0.2" + postcss-normalize-repeat-style: "npm:^6.0.2" + postcss-normalize-string: "npm:^6.0.2" + postcss-normalize-timing-functions: "npm:^6.0.2" + postcss-normalize-unicode: "npm:^6.1.0" + postcss-normalize-url: "npm:^6.0.2" + postcss-normalize-whitespace: "npm:^6.0.2" + postcss-ordered-values: "npm:^6.0.2" + postcss-reduce-initial: "npm:^6.1.0" + postcss-reduce-transforms: "npm:^6.0.2" + postcss-svgo: "npm:^6.0.3" + postcss-unique-selectors: "npm:^6.0.4" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/d125bdb9ac007f97f920e30be953c550a8e7de0cb9298f67e0bc9744f4b920039046b5a6b817e345872836b08689af747f82fbf2189c8bd48da3e6f0c1087b89 + postcss: ^8.4.31 + checksum: 10c0/af99021f936763850f5f35dc9e6a9dfb0da30856dea36e0420b011da2a447099471db2a5f3d1f5f52c0489da186caf9a439d8f048a80f82617077efb018333fa languageName: node linkType: hard -"cssnano-utils@npm:^3.1.0": - version: 3.1.0 - resolution: "cssnano-utils@npm:3.1.0" +"cssnano-utils@npm:^4.0.2": + version: 4.0.2 + resolution: "cssnano-utils@npm:4.0.2" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/057508645a3e7584decede1045daa5b362dbfa2f5df96c3527c7d52e41e787a3442a56a8ea0c0af6a757f518e79a459ee580a35c323ad0d0eec912afd67d7630 + postcss: ^8.4.31 + checksum: 10c0/260b8c8ffa48b908aa77ef129f9b8648ecd92aed405b20e7fe6b8370779dd603530344fc9d96683d53533246e48b36ac9d2aa5a476b4f81c547bbad86d187f35 languageName: node linkType: hard -"cssnano@npm:^5.0.15": - version: 5.1.15 - resolution: "cssnano@npm:5.1.15" +"cssnano@npm:^6.0.1": + version: 6.1.2 + resolution: "cssnano@npm:6.1.2" dependencies: - cssnano-preset-default: "npm:^5.2.14" - lilconfig: "npm:^2.0.3" - yaml: "npm:^1.10.2" + cssnano-preset-default: "npm:^6.1.2" + lilconfig: "npm:^3.1.1" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/4252e4f4edd7a0fbdd4017825c0f8632b7a12ecbfdd432d2ff7ec268d48eb956a0a10bbf209602181f9f84ceeecea4a864719ecde03aa2cc48f5d9636fcf5f9a + postcss: ^8.4.31 + checksum: 10c0/4df0dc0389b34b38acb09b7cfb07267b0eda95349c6d5e9b7666acc7200bb33359650869a60168e9d878298b05f4ad2c7f070815c90551720a3f4e1037f79691 languageName: node linkType: hard -"csso@npm:^4.2.0": - version: 4.2.0 - resolution: "csso@npm:4.2.0" +"csso@npm:^5.0.5": + version: 5.0.5 + resolution: "csso@npm:5.0.5" dependencies: - css-tree: "npm:^1.1.2" - checksum: 10c0/f8c6b1300efaa0f8855a7905ae3794a29c6496e7f16a71dec31eb6ca7cfb1f058a4b03fd39b66c4deac6cb06bf6b4ba86da7b67d7320389cb9994d52b924b903 + css-tree: "npm:~2.2.0" + checksum: 10c0/ab4beb1e97dd7e207c10e9925405b45f15a6cd1b4880a8686ad573aa6d476aed28b4121a666cffd26c37a26179f7b54741f7c257543003bfb244d06a62ad569b languageName: node linkType: hard @@ -2985,10 +2964,10 @@ __metadata: languageName: node linkType: hard -"decode-uri-component@npm:^0.2.2": - version: 0.2.2 - resolution: "decode-uri-component@npm:0.2.2" - checksum: 10c0/1f4fa54eb740414a816b3f6c24818fbfcabd74ac478391e9f4e2282c994127db02010ce804f3d08e38255493cfe68608b3f5c8e09fd6efc4ae46c807691f7a31 +"decode-uri-component@npm:^0.4.1": + version: 0.4.1 + resolution: "decode-uri-component@npm:0.4.1" + checksum: 10c0/a180bbdb5398ec8270d236a3ac07cb988bbf6097428481780b85840f088951dc0318a8d8f9d56796e1a322b55b29859cea29982f22f9b03af0bc60974c54e591 languageName: node linkType: hard @@ -3194,17 +3173,6 @@ __metadata: languageName: node linkType: hard -"dom-serializer@npm:^1.0.1": - version: 1.4.1 - resolution: "dom-serializer@npm:1.4.1" - dependencies: - domelementtype: "npm:^2.0.1" - domhandler: "npm:^4.2.0" - entities: "npm:^2.0.0" - checksum: 10c0/67d775fa1ea3de52035c98168ddcd59418356943b5eccb80e3c8b3da53adb8e37edb2cc2f885802b7b1765bf5022aec21dfc32910d7f9e6de4c3148f095ab5e0 - languageName: node - linkType: hard - "dom-serializer@npm:^2.0.0": version: 2.0.0 resolution: "dom-serializer@npm:2.0.0" @@ -3216,7 +3184,7 @@ __metadata: languageName: node linkType: hard -"domelementtype@npm:^2.0.1, domelementtype@npm:^2.2.0, domelementtype@npm:^2.3.0": +"domelementtype@npm:^2.3.0": version: 2.3.0 resolution: "domelementtype@npm:2.3.0" checksum: 10c0/686f5a9ef0fff078c1412c05db73a0dce096190036f33e400a07e2a4518e9f56b1e324f5c576a0a747ef0e75b5d985c040b0d51945ce780c0dd3c625a18cd8c9 @@ -3232,15 +3200,6 @@ __metadata: languageName: node linkType: hard -"domhandler@npm:^4.2.0, domhandler@npm:^4.3.1": - version: 4.3.1 - resolution: "domhandler@npm:4.3.1" - dependencies: - domelementtype: "npm:^2.2.0" - checksum: 10c0/5c199c7468cb052a8b5ab80b13528f0db3d794c64fc050ba793b574e158e67c93f8336e87fd81e9d5ee43b0e04aea4d8b93ed7be4899cb726a1601b3ba18538b - languageName: node - linkType: hard - "domhandler@npm:^5.0.2, domhandler@npm:^5.0.3": version: 5.0.3 resolution: "domhandler@npm:5.0.3" @@ -3250,17 +3209,6 @@ __metadata: languageName: node linkType: hard -"domutils@npm:^2.8.0": - version: 2.8.0 - resolution: "domutils@npm:2.8.0" - dependencies: - dom-serializer: "npm:^1.0.1" - domelementtype: "npm:^2.2.0" - domhandler: "npm:^4.2.0" - checksum: 10c0/d58e2ae01922f0dd55894e61d18119924d88091837887bf1438f2327f32c65eb76426bd9384f81e7d6dcfb048e0f83c19b222ad7101176ad68cdc9c695b563db - languageName: node - linkType: hard - "domutils@npm:^3.0.1": version: 3.1.0 resolution: "domutils@npm:3.1.0" @@ -3309,6 +3257,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.4.796": + version: 1.4.798 + resolution: "electron-to-chromium@npm:1.4.798" + checksum: 10c0/0941f9d9e28d7c26fd96a429126782c79811ea0b96f3dc8953cfef83b7f0d3856cbfe0ceb3fae9e619d49ddb990e2c3505147c663ac9cd8e8189c3d2da658edc + languageName: node + linkType: hard + "embla-carousel-wheel-gestures@npm:^8.0.1": version: 8.0.1 resolution: "embla-carousel-wheel-gestures@npm:8.0.1" @@ -3383,13 +3338,6 @@ __metadata: languageName: node linkType: hard -"entities@npm:^2.0.0": - version: 2.2.0 - resolution: "entities@npm:2.2.0" - checksum: 10c0/7fba6af1f116300d2ba1c5673fc218af1961b20908638391b4e1e6d5850314ee2ac3ec22d741b3a8060479911c99305164aed19b6254bde75e7e6b1b2c3f3aa3 - languageName: node - linkType: hard - "entities@npm:^4.2.0, entities@npm:^4.4.0": version: 4.5.0 resolution: "entities@npm:4.5.0" @@ -3603,7 +3551,7 @@ __metadata: languageName: node linkType: hard -"escalade@npm:^3.1.1": +"escalade@npm:^3.1.1, escalade@npm:^3.1.2": version: 3.1.2 resolution: "escalade@npm:3.1.2" checksum: 10c0/6b4adafecd0682f3aa1cd1106b8fff30e492c7015b178bc81b2d2f75106dabea6c6d6e8508fc491bd58e597c74abb0e8e2368f943ecb9393d4162e3c2f3cf287 @@ -3850,7 +3798,7 @@ __metadata: languageName: node linkType: hard -"estree-walker@npm:^2.0.1, estree-walker@npm:^2.0.2": +"estree-walker@npm:^2.0.2": version: 2.0.2 resolution: "estree-walker@npm:2.0.2" checksum: 10c0/53a6c54e2019b8c914dc395890153ffdc2322781acf4bd7d1a32d7aedc1710807bdcd866ac133903d5629ec601fbb50abe8c2e5553c7f5a0afdd9b6af6c945af @@ -3887,13 +3835,6 @@ __metadata: languageName: node linkType: hard -"eventemitter3@npm:^4.0.4": - version: 4.0.7 - resolution: "eventemitter3@npm:4.0.7" - checksum: 10c0/5f6d97cbcbac47be798e6355e3a7639a84ee1f7d9b199a07017f1d2f1e2fe236004d14fa5dfaeba661f94ea57805385e326236a6debbc7145c8877fbc0297c6b - languageName: node - linkType: hard - "eventemitter3@npm:^5.0.1": version: 5.0.1 resolution: "eventemitter3@npm:5.0.1" @@ -3995,10 +3936,10 @@ __metadata: languageName: node linkType: hard -"filter-obj@npm:^1.1.0": - version: 1.1.0 - resolution: "filter-obj@npm:1.1.0" - checksum: 10c0/071e0886b2b50238ca5026c5bbf58c26a7c1a1f720773b8c7813d16ba93d0200de977af14ac143c5ac18f666b2cfc83073f3a5fe6a4e996c49e0863d5500fccf +"filter-obj@npm:^5.1.0": + version: 5.1.0 + resolution: "filter-obj@npm:5.1.0" + checksum: 10c0/716e8ad2bc352e206556b3e5695b3cdff8aab80c53ea4b00c96315bbf467b987df3640575100aef8b84e812cf5ea4251db4cd672bbe33b1e78afea88400c67dd languageName: node linkType: hard @@ -4106,8 +4047,8 @@ __metadata: resolution: "frigate-hass-card@workspace:." dependencies: "@babel/core": "npm:^7.24.7" - "@babel/plugin-proposal-class-properties": "npm:^7.18.6" "@babel/plugin-proposal-decorators": "npm:^7.24.7" + "@babel/plugin-transform-class-properties": "npm:^7.24.7" "@cycjimmy/jsmpeg-player": "npm:^6.0.5" "@dermotduffy/custom-card-helpers": "npm:^1.9.0" "@dermotduffy/panzoom": "npm:^4.5.1" @@ -4115,12 +4056,13 @@ __metadata: "@graphiteds/core": "npm:^1.9.21" "@lit-labs/scoped-registry-mixin": "npm:^1.0.3" "@lit-labs/task": "npm:^1.1.3" - "@rollup/plugin-babel": "npm:^5.3.1" - "@rollup/plugin-commonjs": "npm:^22.0.2" + "@rollup/plugin-babel": "npm:^6.0.4" + "@rollup/plugin-commonjs": "npm:^26.0.1" "@rollup/plugin-image": "npm:^3.0.3" - "@rollup/plugin-json": "npm:^4.1.0" - "@rollup/plugin-node-resolve": "npm:^13.3.0" - "@rollup/plugin-replace": "npm:^4.0.0" + "@rollup/plugin-json": "npm:^6.1.0" + "@rollup/plugin-node-resolve": "npm:^15.2.3" + "@rollup/plugin-replace": "npm:^5.0.7" + "@rollup/plugin-terser": "npm:^0.4.4" "@rollup/plugin-typescript": "npm:^11.1.6" "@types/bluebird": "npm:^3.5.42" "@types/lodash-es": "npm:^4.17.12" @@ -4151,11 +4093,10 @@ __metadata: prettier: "npm:^3.3.2" propagating-hammerjs: "npm:^2.0.1" quick-lru: "npm:^6.1.2" - rollup: "npm:^2.79.1" + rollup: "npm:^3.29.4" rollup-plugin-git-info: "npm:^1.0.0" - rollup-plugin-serve: "npm:^2.0.3" - rollup-plugin-styles: "npm:^4.0.0" - rollup-plugin-terser: "npm:^7.0.2" + rollup-plugin-serve: "npm:^1.1.1" + rollup-plugin-styler: "npm:^1.8.0" rollup-plugin-visualizer: "npm:^5.12.0" sass: "npm:^1.77.4" screenfull: "npm:^6.0.2" @@ -4175,18 +4116,7 @@ __metadata: languageName: unknown linkType: soft -"fs-extra@npm:^10.0.0": - version: 10.1.0 - resolution: "fs-extra@npm:10.1.0" - dependencies: - graceful-fs: "npm:^4.2.0" - jsonfile: "npm:^6.0.1" - universalify: "npm:^2.0.0" - checksum: 10c0/5f579466e7109719d162a9249abbeffe7f426eb133ea486e020b89bc6d67a741134076bf439983f2eb79276ceaf6bd7b7c1e43c3fd67fe889863e69072fb0a5e - languageName: node - linkType: hard - -"fs-extra@npm:^11.2.0": +"fs-extra@npm:^11.0.0, fs-extra@npm:^11.2.0": version: 11.2.0 resolution: "fs-extra@npm:11.2.0" dependencies: @@ -4407,7 +4337,22 @@ __metadata: languageName: node linkType: hard -"glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": +"glob@npm:^10.4.1": + version: 10.4.1 + resolution: "glob@npm:10.4.1" + dependencies: + foreground-child: "npm:^3.1.0" + jackspeak: "npm:^3.1.2" + minimatch: "npm:^9.0.4" + minipass: "npm:^7.1.2" + path-scurry: "npm:^1.11.1" + bin: + glob: dist/esm/bin.mjs + checksum: 10c0/77f2900ed98b9cc2a0e1901ee5e476d664dae3cd0f1b662b8bfd4ccf00d0edc31a11595807706a274ca10e1e251411bbf2e8e976c82bed0d879a9b89343ed379 + languageName: node + linkType: hard + +"glob@npm:^7.1.3, glob@npm:^7.1.4": version: 7.2.3 resolution: "glob@npm:7.2.3" dependencies: @@ -4740,7 +4685,7 @@ __metadata: languageName: node linkType: hard -"import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: @@ -4887,7 +4832,7 @@ __metadata: languageName: node linkType: hard -"is-builtin-module@npm:^3.1.0": +"is-builtin-module@npm:^3.2.1": version: 3.2.1 resolution: "is-builtin-module@npm:3.2.1" dependencies: @@ -5039,7 +4984,7 @@ __metadata: languageName: node linkType: hard -"is-reference@npm:^1.2.1": +"is-reference@npm:1.2.1": version: 1.2.1 resolution: "is-reference@npm:1.2.1" dependencies: @@ -5244,14 +5189,16 @@ __metadata: languageName: node linkType: hard -"jest-worker@npm:^26.2.1": - version: 26.6.2 - resolution: "jest-worker@npm:26.6.2" +"jackspeak@npm:^3.1.2": + version: 3.4.0 + resolution: "jackspeak@npm:3.4.0" dependencies: - "@types/node": "npm:*" - merge-stream: "npm:^2.0.0" - supports-color: "npm:^7.0.0" - checksum: 10c0/07e4dba650381604cda253ab6d5837fe0279c8d68c25884995b45bfe149a7a1e1b5a97f304b4518f257dac2a9ddc1808d57d650649c3ab855e9e60cf824d2970 + "@isaacs/cliui": "npm:^8.0.2" + "@pkgjs/parseargs": "npm:^0.11.0" + dependenciesMeta: + "@pkgjs/parseargs": + optional: true + checksum: 10c0/7e42d1ea411b4d57d43ea8a6afbca9224382804359cb72626d0fc45bb8db1de5ad0248283c3db45fe73e77210750d4fcc7c2b4fe5d24fda94aaa24d658295c5f languageName: node linkType: hard @@ -5466,10 +5413,10 @@ __metadata: languageName: node linkType: hard -"lilconfig@npm:^2.0.3": - version: 2.1.0 - resolution: "lilconfig@npm:2.1.0" - checksum: 10c0/64645641aa8d274c99338e130554abd6a0190533c0d9eb2ce7ebfaf2e05c7d9961f3ffe2bfa39efd3b60c521ba3dd24fa236fe2775fc38501bf82bf49d4678b8 +"lilconfig@npm:^3.1.1": + version: 3.1.2 + resolution: "lilconfig@npm:3.1.2" + checksum: 10c0/f059630b1a9bddaeba83059db00c672b64dc14074e9f232adce32b38ca1b5686ab737eb665c5ba3c32f147f0002b4bee7311ad0386a9b98547b5623e87071fbe languageName: node linkType: hard @@ -5680,6 +5627,13 @@ __metadata: languageName: node linkType: hard +"lru-cache@npm:^10.2.0": + version: 10.2.2 + resolution: "lru-cache@npm:10.2.2" + checksum: 10c0/402d31094335851220d0b00985084288136136992979d0e015f0f1697e15d1c86052d7d53ae86b614e5b058425606efffc6969a31a091085d7a2b80a8a1e26d6 + languageName: node + linkType: hard + "lru-cache@npm:^5.1.1": version: 5.1.1 resolution: "lru-cache@npm:5.1.1" @@ -5705,12 +5659,12 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.25.7": - version: 0.25.9 - resolution: "magic-string@npm:0.25.9" +"magic-string@npm:^0.30.3": + version: 0.30.10 + resolution: "magic-string@npm:0.30.10" dependencies: - sourcemap-codec: "npm:^1.4.8" - checksum: 10c0/37f5e01a7e8b19a072091f0b45ff127cda676232d373ce2c551a162dd4053c575ec048b9cbb4587a1f03adb6c5d0fd0dd49e8ab070cd2c83a4992b2182d9cb56 + "@jridgewell/sourcemap-codec": "npm:^1.4.15" + checksum: 10c0/aa9ca17eae571a19bce92c8221193b6f93ee8511abb10f085e55ffd398db8e4c089a208d9eac559deee96a08b7b24d636ea4ab92f09c6cf42a7d1af51f7fd62b languageName: node linkType: hard @@ -5828,10 +5782,17 @@ __metadata: languageName: node linkType: hard -"mdn-data@npm:2.0.14": - version: 2.0.14 - resolution: "mdn-data@npm:2.0.14" - checksum: 10c0/67241f8708c1e665a061d2b042d2d243366e93e5bf1f917693007f6d55111588b952dcbfd3ea9c2d0969fb754aad81b30fdcfdcc24546495fc3b24336b28d4bd +"mdn-data@npm:2.0.28": + version: 2.0.28 + resolution: "mdn-data@npm:2.0.28" + checksum: 10c0/20000932bc4cd1cde9cba4e23f08cc4f816398af4c15ec81040ed25421d6bf07b5cf6b17095972577fb498988f40f4cb589e3169b9357bb436a12d8e07e5ea7b + languageName: node + linkType: hard + +"mdn-data@npm:2.0.30": + version: 2.0.30 + resolution: "mdn-data@npm:2.0.30" + checksum: 10c0/a2c472ea16cee3911ae742593715aa4c634eb3d4b9f1e6ada0902aa90df13dcbb7285d19435f3ff213ebaa3b2e0c0265c1eb0e3fb278fda7f8919f046a410cd9 languageName: node linkType: hard @@ -5873,7 +5834,7 @@ __metadata: languageName: node linkType: hard -"mime-types@npm:^2.1.12, mime-types@npm:^2.1.34": +"mime-types@npm:^2.1.12, mime-types@npm:^2.1.35": version: 2.1.35 resolution: "mime-types@npm:2.1.35" dependencies: @@ -5891,12 +5852,12 @@ __metadata: languageName: node linkType: hard -"mime@npm:^3": - version: 3.0.0 - resolution: "mime@npm:3.0.0" +"mime@npm:^2": + version: 2.6.0 + resolution: "mime@npm:2.6.0" bin: mime: cli.js - checksum: 10c0/402e792a8df1b2cc41cb77f0dcc46472b7944b7ec29cb5bbcd398624b6b97096728f1239766d3fdeb20551dd8d94738344c195a6ea10c4f906eb0356323b0531 + checksum: 10c0/a7f2589900d9c16e3bdf7672d16a6274df903da958c1643c9c45771f0478f3846dcb1097f31eb9178452570271361e2149310931ec705c037210fc69639c8e6c languageName: node linkType: hard @@ -6038,6 +5999,13 @@ __metadata: languageName: node linkType: hard +"minipass@npm:^7.1.2": + version: 7.1.2 + resolution: "minipass@npm:7.1.2" + checksum: 10c0/b0fd20bb9fb56e5fa9a8bfac539e8915ae07430a619e4b86ff71f5fc757ef3924b23b2c4230393af1eda647ed3d75739e4e0acb250a6b1eb277cf7f8fe449557 + languageName: node + linkType: hard + "minizlib@npm:^2.1.1, minizlib@npm:^2.1.2": version: 2.1.2 resolution: "minizlib@npm:2.1.2" @@ -6212,13 +6180,6 @@ __metadata: languageName: node linkType: hard -"normalize-url@npm:^6.0.1": - version: 6.1.0 - resolution: "normalize-url@npm:6.1.0" - checksum: 10c0/95d948f9bdd2cfde91aa786d1816ae40f8262946e13700bf6628105994fe0ff361662c20af3961161c38a119dc977adeb41fc0b41b1745eb77edaaf9cb22db23 - languageName: node - linkType: hard - "npm-run-path@npm:^5.1.0": version: 5.3.0 resolution: "npm-run-path@npm:5.3.0" @@ -6499,13 +6460,13 @@ __metadata: languageName: node linkType: hard -"p-queue@npm:^6.6.2": - version: 6.6.2 - resolution: "p-queue@npm:6.6.2" +"p-queue@npm:^7.0.0": + version: 7.4.1 + resolution: "p-queue@npm:7.4.1" dependencies: - eventemitter3: "npm:^4.0.4" - p-timeout: "npm:^3.2.0" - checksum: 10c0/5739ecf5806bbeadf8e463793d5e3004d08bb3f6177bd1a44a005da8fd81bb90f80e4633e1fb6f1dfd35ee663a5c0229abe26aebb36f547ad5a858347c7b0d3e + eventemitter3: "npm:^5.0.1" + p-timeout: "npm:^5.0.2" + checksum: 10c0/6dbd22780133bbf9cddd2be344609e23cb813f5c6f1693336a52da26631cf931702d5cfd01818b562079502f796b382fab0c1645124c81e2f509b739a35d1562 languageName: node linkType: hard @@ -6519,7 +6480,7 @@ __metadata: languageName: node linkType: hard -"p-timeout@npm:^3.1.0, p-timeout@npm:^3.2.0": +"p-timeout@npm:^3.1.0": version: 3.2.0 resolution: "p-timeout@npm:3.2.0" dependencies: @@ -6528,6 +6489,13 @@ __metadata: languageName: node linkType: hard +"p-timeout@npm:^5.0.2": + version: 5.1.0 + resolution: "p-timeout@npm:5.1.0" + checksum: 10c0/1b026cf9d5878c64bec4341ca9cda8ec6b8b3aea8a57885ca0fe2b35753a20d767fb6f9d3aa41e1252f42bc95432c05ea33b6b18f271fb10bfb0789591850a41 + languageName: node + linkType: hard + "p-timeout@npm:^6.1.2": version: 6.1.2 resolution: "p-timeout@npm:6.1.2" @@ -6596,7 +6564,7 @@ __metadata: languageName: node linkType: hard -"parse-json@npm:^5.0.0": +"parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" dependencies: @@ -6686,6 +6654,16 @@ __metadata: languageName: node linkType: hard +"path-scurry@npm:^1.11.1": + version: 1.11.1 + resolution: "path-scurry@npm:1.11.1" + dependencies: + lru-cache: "npm:^10.2.0" + minipass: "npm:^5.0.0 || ^6.0.2 || ^7.0.0" + checksum: 10c0/32a13711a2a505616ae1cc1b5076801e453e7aae6ac40ab55b388bb91b9d0547a52f5aaceff710ea400205f18691120d4431e520afbe4266b836fadede15872d + languageName: node + linkType: hard + "path-type@npm:^4.0.0": version: 4.0.0 resolution: "path-type@npm:4.0.0" @@ -6714,6 +6692,13 @@ __metadata: languageName: node linkType: hard +"picocolors@npm:^1.0.1": + version: 1.0.1 + resolution: "picocolors@npm:1.0.1" + checksum: 10c0/c63cdad2bf812ef0d66c8db29583802355d4ca67b9285d846f390cc15c2f6ccb94e8cb7eb6a6e97fc5990a6d3ad4ae42d86c84d3146e667c739a4234ed50d400 + languageName: node + linkType: hard + "picomatch@npm:^2.0.4, picomatch@npm:^2.2.1, picomatch@npm:^2.2.2, picomatch@npm:^2.3.1": version: 2.3.1 resolution: "picomatch@npm:2.3.1" @@ -6739,151 +6724,151 @@ __metadata: languageName: node linkType: hard -"postcss-calc@npm:^8.2.3": - version: 8.2.4 - resolution: "postcss-calc@npm:8.2.4" +"postcss-calc@npm:^9.0.1": + version: 9.0.1 + resolution: "postcss-calc@npm:9.0.1" dependencies: - postcss-selector-parser: "npm:^6.0.9" + postcss-selector-parser: "npm:^6.0.11" postcss-value-parser: "npm:^4.2.0" peerDependencies: postcss: ^8.2.2 - checksum: 10c0/8518a429488c3283ff1560c83a511f6f772329bc61d88875eb7c83e13a8683b7ccbdccaa9946024cf1553da3eacd2f40fcbcebf1095f7fdeb432bf86bc6ba6ba + checksum: 10c0/e0df07337162dbcaac5d6e030c7fd289e21da8766a9daca5d6b2b3c8094bb524ae5d74c70048ea7fe5fe4960ce048c60ac97922d917c3bbff34f58e9d2b0eb0e languageName: node linkType: hard -"postcss-colormin@npm:^5.3.1": - version: 5.3.1 - resolution: "postcss-colormin@npm:5.3.1" +"postcss-colormin@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-colormin@npm:6.1.0" dependencies: - browserslist: "npm:^4.21.4" + browserslist: "npm:^4.23.0" caniuse-api: "npm:^3.0.0" - colord: "npm:^2.9.1" + colord: "npm:^2.9.3" postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/c4ca6f335dd992dc8e3df24bffc3495c4e504eba8489c81cb6836fdce3203f423cf4c0b640c4b63c586f588c59d82adb5313c3c5d1a68113896d18ed71caa462 + postcss: ^8.4.31 + checksum: 10c0/0802963fa0d8f2fe408b2e088117670f5303c69a58c135f0ecf0e5ceff69e95e87111b22c4e29c9adb2f69aa8d3bc175f4e8e8708eeb99c9ffc36c17064de427 languageName: node linkType: hard -"postcss-convert-values@npm:^5.1.3": - version: 5.1.3 - resolution: "postcss-convert-values@npm:5.1.3" +"postcss-convert-values@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-convert-values@npm:6.1.0" dependencies: - browserslist: "npm:^4.21.4" + browserslist: "npm:^4.23.0" postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/cd10a81781a12487b2921ff84a1a068e948a1956b9539a284c202abecf4cacdd3e106eb026026b22dbf70933f4315c824c111f6b71f56c355e47b842ca9b1dec + postcss: ^8.4.31 + checksum: 10c0/a80066965cb58fe8fcaf79f306b32c83fc678e1f0678e43f4db3e9fee06eed6db92cf30631ad348a17492769d44757400493c91a33ee865ee8dedea9234a11f5 languageName: node linkType: hard -"postcss-discard-comments@npm:^5.1.2": - version: 5.1.2 - resolution: "postcss-discard-comments@npm:5.1.2" +"postcss-discard-comments@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-discard-comments@npm:6.0.2" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/cb5ba81623c498e18d406138e7d27d69fc668802a1139a8de69d28e80b3fe222cda7b634940512cae78d04f0c78afcd15d92bcf80e537c6c85fa8ff9cd61d00f + postcss: ^8.4.31 + checksum: 10c0/338a1fcba7e2314d956e5e5b9bd1e12e6541991bf85ac72aed6e229a029bf60edb31f11576b677623576169aa7d9c75e1be259ac7b50d0b735b841b5518f9da9 languageName: node linkType: hard -"postcss-discard-duplicates@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-discard-duplicates@npm:5.1.0" +"postcss-discard-duplicates@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-discard-duplicates@npm:6.0.3" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/3d3a49536c56097c06b4f085412e0cda0854fac1c559563ccb922d9fab6305ff13058cd6fee422aa66c1d7e466add4e7672d7ae2ff551a4af6f1a8d2142d471f + postcss: ^8.4.31 + checksum: 10c0/24d2f00e54668f2837eb38a64b1751d7a4a73b2752f9749e61eb728f1fae837984bc2b339f7f5207aff5f66f72551253489114b59b9ba21782072677a81d7d1b languageName: node linkType: hard -"postcss-discard-empty@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-discard-empty@npm:5.1.1" +"postcss-discard-empty@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-discard-empty@npm:6.0.3" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/36c8b2197af836dbd93168c72cde4edc1f10fe00e564824119da076d3764909745bb60e4ada04052322e26872d1bce6a37c56815f1c48c813a21adca1a41fbdc + postcss: ^8.4.31 + checksum: 10c0/1af08bb29f18eda41edf3602b257d89a4cf0a16f79fc773cfebd4a37251f8dbd9b77ac18efe55d0677d000b43a8adf2ef9328d31961c810e9433a38494a1fa65 languageName: node linkType: hard -"postcss-discard-overridden@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-discard-overridden@npm:5.1.0" +"postcss-discard-overridden@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-discard-overridden@npm:6.0.2" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/7d3fc0b0d90599606fc083327a7c24390f90270a94a0119af4b74815d518948581579281f63b9bfa62e2644edf59bc9e725dc04ea5ba213f697804f3fb4dd8dc + postcss: ^8.4.31 + checksum: 10c0/fda70ef3cd4cb508369c5bbbae44d7760c40ec9f2e65df1cd1b6e0314317fb1d25ae7f64987ca84e66889c1e9d1862487a6ce391c159dfe04d536597bfc5030d languageName: node linkType: hard -"postcss-merge-longhand@npm:^5.1.7": - version: 5.1.7 - resolution: "postcss-merge-longhand@npm:5.1.7" +"postcss-merge-longhand@npm:^6.0.5": + version: 6.0.5 + resolution: "postcss-merge-longhand@npm:6.0.5" dependencies: postcss-value-parser: "npm:^4.2.0" - stylehacks: "npm:^5.1.1" + stylehacks: "npm:^6.1.1" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/4d9f44b03f19522cc81ae4f5b1f2a9ef2db918dbd8b3042d4f1b2461b2230b8ec1269334db6a67a863ba68f64cabd712e6e45340ddb22a3fc03cd34df69d2bf0 + postcss: ^8.4.31 + checksum: 10c0/5a223a7f698c05ab42e9997108a7ff27ea1e0c33a11a353d65a04fc89c3b5b750b9e749550d76b6406329117a055adfc79dde7fee48dca5c8e167a2854ae3fea languageName: node linkType: hard -"postcss-merge-rules@npm:^5.1.4": - version: 5.1.4 - resolution: "postcss-merge-rules@npm:5.1.4" +"postcss-merge-rules@npm:^6.1.1": + version: 6.1.1 + resolution: "postcss-merge-rules@npm:6.1.1" dependencies: - browserslist: "npm:^4.21.4" + browserslist: "npm:^4.23.0" caniuse-api: "npm:^3.0.0" - cssnano-utils: "npm:^3.1.0" - postcss-selector-parser: "npm:^6.0.5" + cssnano-utils: "npm:^4.0.2" + postcss-selector-parser: "npm:^6.0.16" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/e7686cdda052071bf98810ad381e26145c43a2286f9540f04f97ef93101604b78d478dd555db91e5f73751bb353c283ba75c2fcb16a3751ac7d93dc6a0130c41 + postcss: ^8.4.31 + checksum: 10c0/6d8952dbb19b1e59bf5affe0871fa1be6515103466857cff5af879d6cf619659f8642ec7a931cabb7cdbd393d8c1e91748bf70bee70fa3edea010d4e25786d04 languageName: node linkType: hard -"postcss-minify-font-values@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-minify-font-values@npm:5.1.0" +"postcss-minify-font-values@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-minify-font-values@npm:6.1.0" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/7aa4f93a853b657f79a8b28d0e924cafce3720086d9da02ce04b8b2f8de42e18ce32c8f7f1078390fb5ec82468e2d8e771614387cea3563f05fd9fa1798e1c59 + postcss: ^8.4.31 + checksum: 10c0/0d6567170c22a7db42096b5eac298f041614890fbe01759a9fa5ccda432f2bb09efd399d92c11bf6675ae13ccd259db4602fad3c358317dee421df5f7ab0a003 languageName: node linkType: hard -"postcss-minify-gradients@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-minify-gradients@npm:5.1.1" +"postcss-minify-gradients@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-minify-gradients@npm:6.0.3" dependencies: - colord: "npm:^2.9.1" - cssnano-utils: "npm:^3.1.0" + colord: "npm:^2.9.3" + cssnano-utils: "npm:^4.0.2" postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/bcb2802d7c8f0f76c7cff089884844f26c24b95f35c3ec951d7dec8c212495d1873d6ba62d6225ce264570e8e0668e271f9bc79bb6f5d2429c1f8933f4e3021d + postcss: ^8.4.31 + checksum: 10c0/7fcbcec94fe5455b89fe1b424a451198e60e0407c894bbacdc062d9fdef2f8571b483b5c3bb17f22d2f1249431251b2de22e1e4e8b0614d10624f8ee6e71afd2 languageName: node linkType: hard -"postcss-minify-params@npm:^5.1.4": - version: 5.1.4 - resolution: "postcss-minify-params@npm:5.1.4" +"postcss-minify-params@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-minify-params@npm:6.1.0" dependencies: - browserslist: "npm:^4.21.4" - cssnano-utils: "npm:^3.1.0" + browserslist: "npm:^4.23.0" + cssnano-utils: "npm:^4.0.2" postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/debce6f0f7dd9af69b4bb9e467ea1ccccff2d849b6020461a2b9741c0c137340e6076c245dc2e83880180eb2e82936280fa31dfe8608e5a2e3618f3d864314c5 + postcss: ^8.4.31 + checksum: 10c0/e5c38c3e5fb42e2ca165764f983716e57d854a63a477f7389ccc94cd2ab8123707006613bd7f29acc6eafd296fff513aa6d869c98ac52590f886d641cb21a59e languageName: node linkType: hard -"postcss-minify-selectors@npm:^5.2.1": - version: 5.2.1 - resolution: "postcss-minify-selectors@npm:5.2.1" +"postcss-minify-selectors@npm:^6.0.4": + version: 6.0.4 + resolution: "postcss-minify-selectors@npm:6.0.4" dependencies: - postcss-selector-parser: "npm:^6.0.5" + postcss-selector-parser: "npm:^6.0.16" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/f3f4ec110f5f697cfc9dde3e491ff10aa07509bf33cc940aa539e4b5b643d1b9f8bb97f8bb83d05fc96f5eeb220500ebdeffbde513bd176c0671e21c2c96fab9 + postcss: ^8.4.31 + checksum: 10c0/695ec2e1e3a7812b0cabe1105d0ed491760be3d8e9433914fb5af1fc30a84e6dc24089cd31b7e300de620b8e7adf806526c1acf8dd14077a7d1d2820c60a327c languageName: node linkType: hard @@ -6896,16 +6881,16 @@ __metadata: languageName: node linkType: hard -"postcss-modules-local-by-default@npm:^4.0.0": - version: 4.0.4 - resolution: "postcss-modules-local-by-default@npm:4.0.4" +"postcss-modules-local-by-default@npm:^4.0.3": + version: 4.0.5 + resolution: "postcss-modules-local-by-default@npm:4.0.5" dependencies: icss-utils: "npm:^5.0.0" postcss-selector-parser: "npm:^6.0.2" postcss-value-parser: "npm:^4.1.0" peerDependencies: postcss: ^8.1.0 - checksum: 10c0/9ebf464867eb10b29b73501b1466dcac8352ed852ef68ec23571f515daa74401d7ace9a6c72f354542081fdbb47d098c9bc6b05373b553a6e35779d072f967bb + checksum: 10c0/f4ad35abeb685ecb25f80c93d9fe23c8b89ee45ac4185f3560e701b4d7372f9b798577e79c5ed03b6d9c80bc923b001210c127c04ced781f43cda9e32b202a5b languageName: node linkType: hard @@ -6931,141 +6916,150 @@ __metadata: languageName: node linkType: hard -"postcss-normalize-charset@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-charset@npm:5.1.0" +"postcss-normalize-charset@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-charset@npm:6.0.2" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/aa481584d4db48e0dbf820f992fa235e6c41ff3d4701a62d349f33c1ad4c5c7dcdea3096db9ff2a5c9497e9bed2186d594ccdb1b42d57b30f58affba5829ad9c + postcss: ^8.4.31 + checksum: 10c0/af32a3b4cf94163d728b8aa935b2494c9f69fbc96a33b35f67ae15dbdef7fcc8732569df97cbaaf20ca6c0103c39adad0cfce2ba07ffed283796787f6c36f410 languageName: node linkType: hard -"postcss-normalize-display-values@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-display-values@npm:5.1.0" +"postcss-normalize-display-values@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-display-values@npm:6.0.2" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/70b164fda885c097c02c98914fba4cd19b2382ff5f85f77e5315d88a1d477b4803f0f271d95a38e044e2a6c3b781c5c9bfb83222fc577199f2aeb0b8f4254e2f + postcss: ^8.4.31 + checksum: 10c0/782761850c7e697fdb6c3ff53076de716a71b60f9e835efb2f7ef238de347c88b5d55f0d43cf5c608e1ee58de65360e3d9fccd5f20774bba08ded7c87d8a5651 languageName: node linkType: hard -"postcss-normalize-positions@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-normalize-positions@npm:5.1.1" +"postcss-normalize-positions@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-positions@npm:6.0.2" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/910d58991fd38a7cf6ed6471e6fa4a96349690ad1a99a02e8cac46d76ba5045f2fca453088b68b05ff665afd96dc617c4674c68acaeabbe83f502e4963fb78b1 + postcss: ^8.4.31 + checksum: 10c0/9fdd42a47226bbda5f68774f3c4c3a90eb4fa708aef5a997c6a52fe6cac06585c9774038fe3bc1aa86a203c29223b8d8db6ebe7580c1aa293154f2b48db0b038 languageName: node linkType: hard -"postcss-normalize-repeat-style@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-normalize-repeat-style@npm:5.1.1" +"postcss-normalize-repeat-style@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-repeat-style@npm:6.0.2" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/57c3817a2107ebb17e4ceee3831d230c72a3ccc7650f4d5f12aa54f6ea766777401f4f63b2615b721350b2e8c7ae0b0bbc3f1c5ad4e7fa737c9efb92cfa0cbb0 + postcss: ^8.4.31 + checksum: 10c0/9133ccbdf1286920c1cd0d01c1c5fa0bd3251b717f2f3e47d691dcc44978ac1dc419d20d9ae5428bd48ee542059e66b823ba699356f5968ccced5606c7c7ca34 languageName: node linkType: hard -"postcss-normalize-string@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-string@npm:5.1.0" +"postcss-normalize-string@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-string@npm:6.0.2" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/a5e9979998f478d385ddff865bdd8a4870af69fa8c91c9398572a299ff39b39a6bda922a48fab0d2cddc639f30159c39baaed880ed7d13cd27cc64eaa9400b3b + postcss: ^8.4.31 + checksum: 10c0/fecc2d52c4029b24fecf2ca2fb45df5dbdf9f35012194ad4ea80bc7be3252cdcb21a0976400902320595aa6178f2cc625cc804c6b6740aef6efa42105973a205 languageName: node linkType: hard -"postcss-normalize-timing-functions@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-timing-functions@npm:5.1.0" +"postcss-normalize-timing-functions@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-timing-functions@npm:6.0.2" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/afb34d8e313004ae8cd92910bf1a6eb9885f29ae803cd9032b6dfe7b67a9ad93f800976f10e55170b2b08fe9484825e9272629971186812c2764c73843268237 + postcss: ^8.4.31 + checksum: 10c0/a22af0b3374704e59ae70bbbcc66b7029137e284f04e30a2ad548818d1540d6c1ed748dd8f689b9b6df5c1064085a00ad07b6f7e25ffaad49d4e661b616cdeae languageName: node linkType: hard -"postcss-normalize-unicode@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-normalize-unicode@npm:5.1.1" +"postcss-normalize-unicode@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-normalize-unicode@npm:6.1.0" dependencies: - browserslist: "npm:^4.21.4" + browserslist: "npm:^4.23.0" postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/c102888d488d05c53ab10ffcd4e0efb892ef0cc2f9b0abe9c9b175a2d7a9c226981ca6806ed9e5c1b82a8190f2b3a8342a6de800f019b417130661b0787ff6d7 + postcss: ^8.4.31 + checksum: 10c0/ff5746670d94dd97b49a0955c3c71ff516fb4f54bbae257f877d179bacc44a62e50a0fd6e7ddf959f2ca35c335de4266b0c275d880bb57ad7827189339ab1582 languageName: node linkType: hard -"postcss-normalize-url@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-normalize-url@npm:5.1.0" - dependencies: - normalize-url: "npm:^6.0.1" - postcss-value-parser: "npm:^4.2.0" - peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/a016cefd1ef80f74ef9dbed50593d3b533101e93aaadfc292896fddd8d6c3eb732a9fc5cb2e0d27f79c1f60f0fdfc40b045a494b514451e9610c6acf9392eb98 - languageName: node - linkType: hard - -"postcss-normalize-whitespace@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-normalize-whitespace@npm:5.1.1" +"postcss-normalize-url@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-url@npm:6.0.2" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/d7b53dd90fe369bfb9838a40096db904a41f50dadfd04247ec07d7ab5588c3d4e70d1c7f930523bd061cb74e6683cef45c6e6c4eb57ea174ee3fc99f3de222d1 + postcss: ^8.4.31 + checksum: 10c0/4718f1c0657788d2c560b340ee8e0a4eb3eb053eba6fbbf489e9a6e739b4c5f9ce1957f54bd03497c50a1f39962bf6ab9ff6ba4976b69dd160f6afd1670d69b7 languageName: node linkType: hard -"postcss-ordered-values@npm:^5.1.3": - version: 5.1.3 - resolution: "postcss-ordered-values@npm:5.1.3" +"postcss-normalize-whitespace@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-normalize-whitespace@npm:6.0.2" dependencies: - cssnano-utils: "npm:^3.1.0" postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/55abfbd2c7267eefed62a881ed0b5c0c98409c50a589526a3ebb9f8d879979203e523b8888fa84732bdd1ac887f721287a037002fa70c27c8d33f1bcbae9d9c6 + postcss: ^8.4.31 + checksum: 10c0/d5275a88e29a894aeb83a2a833e816d2456dbf3f39961628df596ce205dcc4895186a023812ff691945e0804241ccc53e520d16591b5812288474b474bbaf652 languageName: node linkType: hard -"postcss-reduce-initial@npm:^5.1.2": - version: 5.1.2 - resolution: "postcss-reduce-initial@npm:5.1.2" +"postcss-ordered-values@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-ordered-values@npm:6.0.2" dependencies: - browserslist: "npm:^4.21.4" + cssnano-utils: "npm:^4.0.2" + postcss-value-parser: "npm:^4.2.0" + peerDependencies: + postcss: ^8.4.31 + checksum: 10c0/aece23a289228aa804217a85f8da198d22b9123f02ca1310b81834af380d6fbe115e4300683599b4a2ab7f1c6a1dbd6789724c47c38e2b0a3774f2ea4b4f0963 + languageName: node + linkType: hard + +"postcss-reduce-initial@npm:^6.1.0": + version: 6.1.0 + resolution: "postcss-reduce-initial@npm:6.1.0" + dependencies: + browserslist: "npm:^4.23.0" caniuse-api: "npm:^3.0.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/ddb2ce61c8d0997184f08200eafdf32b3c67e88228fee960f5e2010c32da0c1d8ea07712585bf2b3aaa15f583066401d45db2c1131527c5116ca6794ebebd865 + postcss: ^8.4.31 + checksum: 10c0/a8f28cf51ce9a1b9423cce1a01c1d7cbee90125930ec36435a0073e73aef402d90affe2fd3600c964b679cf738869fda447b95a9acce74414e9d67d5c6ba8646 languageName: node linkType: hard -"postcss-reduce-transforms@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-reduce-transforms@npm:5.1.0" +"postcss-reduce-transforms@npm:^6.0.2": + version: 6.0.2 + resolution: "postcss-reduce-transforms@npm:6.0.2" dependencies: postcss-value-parser: "npm:^4.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/caefaeb78652ad8701b94e91500e38551255e4899fa298a7357519a36cbeebae088eab4535e00f17675a1230f448c4a7077045639d496da4614a46bc41df4add + postcss: ^8.4.31 + checksum: 10c0/755ef27b3d083f586ac831f0c611a66e76f504d27e2100dc7674f6b86afad597901b4520cb889fe58ca70e852aa7fd0c0acb69a63d39dfe6a95860b472394e7c languageName: node linkType: hard -"postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4, postcss-selector-parser@npm:^6.0.5, postcss-selector-parser@npm:^6.0.9": +"postcss-selector-parser@npm:^6.0.11, postcss-selector-parser@npm:^6.0.16": + version: 6.1.0 + resolution: "postcss-selector-parser@npm:6.1.0" + dependencies: + cssesc: "npm:^3.0.0" + util-deprecate: "npm:^1.0.2" + checksum: 10c0/91e9c6434772506bc7f318699dd9d19d32178b52dfa05bed24cb0babbdab54f8fb765d9920f01ac548be0a642aab56bce493811406ceb00ae182bbb53754c473 + languageName: node + linkType: hard + +"postcss-selector-parser@npm:^6.0.2, postcss-selector-parser@npm:^6.0.4": version: 6.0.15 resolution: "postcss-selector-parser@npm:6.0.15" dependencies: @@ -7075,26 +7069,26 @@ __metadata: languageName: node linkType: hard -"postcss-svgo@npm:^5.1.0": - version: 5.1.0 - resolution: "postcss-svgo@npm:5.1.0" +"postcss-svgo@npm:^6.0.3": + version: 6.0.3 + resolution: "postcss-svgo@npm:6.0.3" dependencies: postcss-value-parser: "npm:^4.2.0" - svgo: "npm:^2.7.0" + svgo: "npm:^3.2.0" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/309634a587e38fef244648bc9cd1817e12144868d24f1173d87b1edc14a4a7fca614962b2cb9d93f4801e11bd8d676083986ad40ebab4438cb84731ce1571994 + postcss: ^8.4.31 + checksum: 10c0/994b15a88cbb411f32cfa98957faa5623c76f2d75fede51f5f47238f06b367ebe59c204fecbdaf21ccb9e727239a4b290087e04c502392658a0c881ddfbd61f2 languageName: node linkType: hard -"postcss-unique-selectors@npm:^5.1.1": - version: 5.1.1 - resolution: "postcss-unique-selectors@npm:5.1.1" +"postcss-unique-selectors@npm:^6.0.4": + version: 6.0.4 + resolution: "postcss-unique-selectors@npm:6.0.4" dependencies: - postcss-selector-parser: "npm:^6.0.5" + postcss-selector-parser: "npm:^6.0.16" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/484f6409346d6244c134c5cdcd62f4f2751b269742f95222f13d8bac5fb224471ffe04e28a354670cbe0bdc2707778ead034fc1b801b473ffcbea5436807de30 + postcss: ^8.4.31 + checksum: 10c0/bfb99d8a7c675c93f2e65c9d9d563477bfd46fdce9e2727d42d57982b31ccbaaf944e8034bfbefe48b3119e77fba7eb1b181c19b91cb3a5448058fa66a7c9ae9 languageName: node linkType: hard @@ -7105,7 +7099,18 @@ __metadata: languageName: node linkType: hard -"postcss@npm:^8, postcss@npm:^8.4.35, postcss@npm:^8.4.5": +"postcss@npm:^8.4.31": + version: 8.4.38 + resolution: "postcss@npm:8.4.38" + dependencies: + nanoid: "npm:^3.3.7" + picocolors: "npm:^1.0.0" + source-map-js: "npm:^1.2.0" + checksum: 10c0/955407b8f70cf0c14acf35dab3615899a2a60a26718a63c848cf3c29f2467b0533991b985a2b994430d890bd7ec2b1963e36352b0774a19143b5f591540f7c06 + languageName: node + linkType: hard + +"postcss@npm:^8.4.35": version: 8.4.35 resolution: "postcss@npm:8.4.35" dependencies: @@ -7246,15 +7251,14 @@ __metadata: languageName: node linkType: hard -"query-string@npm:^7.1.0": - version: 7.1.3 - resolution: "query-string@npm:7.1.3" +"query-string@npm:^8.1.0": + version: 8.2.0 + resolution: "query-string@npm:8.2.0" dependencies: - decode-uri-component: "npm:^0.2.2" - filter-obj: "npm:^1.1.0" - split-on-first: "npm:^1.0.0" - strict-uri-encode: "npm:^2.0.0" - checksum: 10c0/a896c08e9e0d4f8ffd89a572d11f668c8d0f7df9c27c6f49b92ab31366d3ba0e9c331b9a620ee747893436cd1f2f821a6327e2bc9776bde2402ac6c270b801b2 + decode-uri-component: "npm:^0.4.1" + filter-obj: "npm:^5.1.0" + split-on-first: "npm:^3.0.0" + checksum: 10c0/ad78256d5464ec80a4c5723c5f134ec4aa341fcc71e1458d2b4d4663aa441c0b0bbe7dcdda60e7f09e81969fd725fb7d6f9ba4e77fd621e11ce4c3ecfb9cdec0 languageName: node linkType: hard @@ -7390,7 +7394,14 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.17.0, resolve@npm:^1.19.0, resolve@npm:^1.21.0, resolve@npm:^1.22.1, resolve@npm:^1.22.4": +"resolve.exports@npm:^2.0.0": + version: 2.0.2 + resolution: "resolve.exports@npm:2.0.2" + checksum: 10c0/cc4cffdc25447cf34730f388dca5021156ba9302a3bad3d7f168e790dc74b2827dff603f1bc6ad3d299bac269828dca96dd77e036dc9fba6a2a1807c47ab5c98 + languageName: node + linkType: hard + +"resolve@npm:^1.22.1, resolve@npm:^1.22.4, resolve@npm:^1.22.8": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -7403,7 +7414,7 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.17.0#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.21.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": +"resolve@patch:resolve@npm%3A^1.22.1#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin": version: 1.22.8 resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: @@ -7459,55 +7470,41 @@ __metadata: languageName: node linkType: hard -"rollup-plugin-serve@npm:^2.0.3": - version: 2.0.3 - resolution: "rollup-plugin-serve@npm:2.0.3" +"rollup-plugin-serve@npm:^1.1.1": + version: 1.1.1 + resolution: "rollup-plugin-serve@npm:1.1.1" dependencies: - mime: "npm:^3" + mime: "npm:^2" opener: "npm:1" - checksum: 10c0/a130760039296c07926ae66552defad6fcefd2da95ed29ba0b468b3356c9323c0015d212c79f8892ae571a9f63904da7615bc51b7b50db51e6d64aba62722b9f + checksum: 10c0/afe8080056f3752fb54f7856e83d786eead72f34f5332d2ebdb97c07d6f130ffa66c1d4973cc664aea9bfcd09ccb2cf95fad2f5c072fefb78445a619d574e186 languageName: node linkType: hard -"rollup-plugin-styles@npm:^4.0.0": - version: 4.0.0 - resolution: "rollup-plugin-styles@npm:4.0.0" +"rollup-plugin-styler@npm:^1.8.0": + version: 1.8.0 + resolution: "rollup-plugin-styler@npm:1.8.0" dependencies: - "@rollup/pluginutils": "npm:^4.1.2" - "@types/cssnano": "npm:^5.0.0" - cosmiconfig: "npm:^7.0.1" - cssnano: "npm:^5.0.15" - fs-extra: "npm:^10.0.0" + "@rollup/pluginutils": "npm:^5.0.0" + cosmiconfig: "npm:^8.0.0" + cssnano: "npm:^6.0.1" + fs-extra: "npm:^11.0.0" icss-utils: "npm:^5.1.0" - mime-types: "npm:^2.1.34" - p-queue: "npm:^6.6.2" - postcss: "npm:^8.4.5" + mime-types: "npm:^2.1.35" + p-queue: "npm:^7.0.0" + postcss: "npm:^8.4.31" postcss-modules-extract-imports: "npm:^3.0.0" - postcss-modules-local-by-default: "npm:^4.0.0" + postcss-modules-local-by-default: "npm:^4.0.3" postcss-modules-scope: "npm:^3.0.0" postcss-modules-values: "npm:^4.0.0" postcss-value-parser: "npm:^4.2.0" - query-string: "npm:^7.1.0" - resolve: "npm:^1.21.0" - source-map-js: "npm:^1.0.1" - tslib: "npm:^2.3.1" + query-string: "npm:^8.1.0" + resolve: "npm:^1.22.8" + resolve.exports: "npm:^2.0.0" + source-map-js: "npm:^1.0.2" + tslib: "npm:^2.6.2" peerDependencies: - rollup: ^2.63.0 - checksum: 10c0/dc9a15918ffa48d271fdaec921c71ec200b340b5ae986a0ea48227cd4e8cea0a9dd2316cc6ae22bb20ddddcee445c03a268e86d00d6b3658d36aeaf5b0e8b9bd - languageName: node - linkType: hard - -"rollup-plugin-terser@npm:^7.0.2": - version: 7.0.2 - resolution: "rollup-plugin-terser@npm:7.0.2" - dependencies: - "@babel/code-frame": "npm:^7.10.4" - jest-worker: "npm:^26.2.1" - serialize-javascript: "npm:^4.0.0" - terser: "npm:^5.0.0" - peerDependencies: - rollup: ^2.0.0 - checksum: 10c0/f79b851c6f7b06555d3a8ce7a4e32abd2b7cb8318e89fb8db73e662fa6e3af1a59920e881d111efc65a7437fd9582b61b1f4859b6fd839ba948616829d92432d + rollup: ^2.63.0 || ^3.0.0 || ^4.0.0 + checksum: 10c0/0be7879e1fb2d5f8e4b80243d00d894f1b25c4ed7a0b5cdbc02be922d57335a46a9bfd470678524f879a33fd4e5b4aa6e45d186ac34a1b0d86bf08eed189a9d1 languageName: node linkType: hard @@ -7530,7 +7527,7 @@ __metadata: languageName: node linkType: hard -"rollup@npm:^2.63.0, rollup@npm:^2.79.1": +"rollup@npm:^2.63.0": version: 2.79.1 resolution: "rollup@npm:2.79.1" dependencies: @@ -7544,6 +7541,20 @@ __metadata: languageName: node linkType: hard +"rollup@npm:^3.29.4": + version: 3.29.4 + resolution: "rollup@npm:3.29.4" + dependencies: + fsevents: "npm:~2.3.2" + dependenciesMeta: + fsevents: + optional: true + bin: + rollup: dist/bin/rollup + checksum: 10c0/65eddf84bf389ea8e4d4c1614b1c6a298d08f8ae785c0c087e723a879190c8aaddbab4aa3b8a0524551b9036750c9f8bfea27b377798accfd2ba5084ceff5aaa + languageName: node + linkType: hard + "rollup@npm:^4.2.0": version: 4.12.0 resolution: "rollup@npm:4.12.0" @@ -7746,12 +7757,12 @@ __metadata: languageName: node linkType: hard -"serialize-javascript@npm:^4.0.0": - version: 4.0.0 - resolution: "serialize-javascript@npm:4.0.0" +"serialize-javascript@npm:^6.0.1": + version: 6.0.2 + resolution: "serialize-javascript@npm:6.0.2" dependencies: randombytes: "npm:^2.1.0" - checksum: 10c0/510dfe7f0311c0b2f7ab06311afa1668ba2969ab2f1faaac0a4924ede76b7f22ba85cfdeaa0052ec5a047bca42c8cd8ac8df8f0efe52f9bd290b3a39ae69fe9d + checksum: 10c0/2dd09ef4b65a1289ba24a788b1423a035581bef60817bea1f01eda8e3bda623f86357665fe7ac1b50f6d4f583f97db9615b3f07b2a2e8cbcb75033965f771dd2 languageName: node linkType: hard @@ -7877,6 +7888,13 @@ __metadata: languageName: node linkType: hard +"smob@npm:^1.0.0": + version: 1.5.0 + resolution: "smob@npm:1.5.0" + checksum: 10c0/a1067f23265812de8357ed27312101af49b89129eb973e3f26ab5856ea774f88cace13342e66e32470f933ccfa916e0e9d0f7ca8bbd4f92dfab2af45c15956c2 + languageName: node + linkType: hard + "socks-proxy-agent@npm:^8.0.1": version: 8.0.2 resolution: "socks-proxy-agent@npm:8.0.2" @@ -7916,6 +7934,13 @@ __metadata: languageName: node linkType: hard +"source-map-js@npm:^1.2.0": + version: 1.2.0 + resolution: "source-map-js@npm:1.2.0" + checksum: 10c0/7e5f896ac10a3a50fe2898e5009c58ff0dc102dcb056ed27a354623a0ece8954d4b2649e1a1b2b52ef2e161d26f8859c7710350930751640e71e374fe2d321a4 + languageName: node + linkType: hard + "source-map-support@npm:~0.5.20": version: 0.5.21 resolution: "source-map-support@npm:0.5.21" @@ -7926,7 +7951,7 @@ __metadata: languageName: node linkType: hard -"source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.1": +"source-map@npm:^0.6.0, source-map@npm:~0.6.1": version: 0.6.1 resolution: "source-map@npm:0.6.1" checksum: 10c0/ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011 @@ -7940,17 +7965,10 @@ __metadata: languageName: node linkType: hard -"sourcemap-codec@npm:^1.4.8": - version: 1.4.8 - resolution: "sourcemap-codec@npm:1.4.8" - checksum: 10c0/f099279fdaae070ff156df7414bbe39aad69cdd615454947ed3e19136bfdfcb4544952685ee73f56e17038f4578091e12b17b283ed8ac013882916594d95b9e6 - languageName: node - linkType: hard - -"split-on-first@npm:^1.0.0": - version: 1.1.0 - resolution: "split-on-first@npm:1.1.0" - checksum: 10c0/56df8344f5a5de8521898a5c090023df1d8b8c75be6228f56c52491e0fc1617a5236f2ac3a066adb67a73231eac216ccea7b5b4a2423a543c277cb2f48d24c29 +"split-on-first@npm:^3.0.0": + version: 3.0.0 + resolution: "split-on-first@npm:3.0.0" + checksum: 10c0/a1262eae12b68de235e1a08e011bf5b42c42621985ddf807e6221fb1e2b3304824913ae7019f18436b96b8fab8aef5f1ad80dedd2385317fdc51b521c3882cd0 languageName: node linkType: hard @@ -7970,13 +7988,6 @@ __metadata: languageName: node linkType: hard -"stable@npm:^0.1.8": - version: 0.1.8 - resolution: "stable@npm:0.1.8" - checksum: 10c0/df74b5883075076e78f8e365e4068ecd977af6c09da510cfc3148a303d4b87bc9aa8f7c48feb67ed4ef970b6140bd9eabba2129e28024aa88df5ea0114cba39d - languageName: node - linkType: hard - "stackback@npm:0.0.2": version: 0.0.2 resolution: "stackback@npm:0.0.2" @@ -8005,13 +8016,6 @@ __metadata: languageName: node linkType: hard -"strict-uri-encode@npm:^2.0.0": - version: 2.0.0 - resolution: "strict-uri-encode@npm:2.0.0" - checksum: 10c0/010cbc78da0e2cf833b0f5dc769e21ae74cdc5d5f5bd555f14a4a4876c8ad2c85ab8b5bdf9a722dc71a11dcd3184085e1c3c0bd50ec6bb85fffc0f28cf82597d - languageName: node - linkType: hard - "string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.0.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" @@ -8140,15 +8144,15 @@ __metadata: languageName: node linkType: hard -"stylehacks@npm:^5.1.1": - version: 5.1.1 - resolution: "stylehacks@npm:5.1.1" +"stylehacks@npm:^6.1.1": + version: 6.1.1 + resolution: "stylehacks@npm:6.1.1" dependencies: - browserslist: "npm:^4.21.4" - postcss-selector-parser: "npm:^6.0.4" + browserslist: "npm:^4.23.0" + postcss-selector-parser: "npm:^6.0.16" peerDependencies: - postcss: ^8.2.15 - checksum: 10c0/402c2b545eeda0e972f125779adddc88df11bcf3a89de60c92026bd98cd49c1abffcd5bfe41766398835e0a1c7e5e72bdb6905809ecbb60716cd8d3a32ea7cd3 + postcss: ^8.4.31 + checksum: 10c0/2dd2bccfd8311ff71492e63a7b8b86c3d7b1fff55d4ba5a2357aff97743e633d351cdc2f5ae3c0057637d00dab4ef5fc5b218a1b370e4585a41df22b5a5128be languageName: node linkType: hard @@ -8175,7 +8179,7 @@ __metadata: languageName: node linkType: hard -"supports-color@npm:^7.0.0, supports-color@npm:^7.1.0": +"supports-color@npm:^7.1.0": version: 7.2.0 resolution: "supports-color@npm:7.2.0" dependencies: @@ -8191,20 +8195,20 @@ __metadata: languageName: node linkType: hard -"svgo@npm:^2.7.0": - version: 2.8.0 - resolution: "svgo@npm:2.8.0" +"svgo@npm:^3.2.0": + version: 3.3.2 + resolution: "svgo@npm:3.3.2" dependencies: "@trysound/sax": "npm:0.2.0" commander: "npm:^7.2.0" - css-select: "npm:^4.1.3" - css-tree: "npm:^1.1.3" - csso: "npm:^4.2.0" + css-select: "npm:^5.1.0" + css-tree: "npm:^2.3.1" + css-what: "npm:^6.1.0" + csso: "npm:^5.0.5" picocolors: "npm:^1.0.0" - stable: "npm:^0.1.8" bin: - svgo: bin/svgo - checksum: 10c0/0741f5d5cad63111a90a0ce7a1a5a9013f6d293e871b75efe39addb57f29a263e45294e485a4d2ff9cc260a5d142c8b5937b2234b4ef05efdd2706fb2d360ecc + svgo: ./bin/svgo + checksum: 10c0/a6badbd3d1d6dbb177f872787699ab34320b990d12e20798ecae915f0008796a0f3c69164f1485c9def399e0ce0a5683eb4a8045e51a5e1c364bb13a0d9f79e1 languageName: node linkType: hard @@ -8236,9 +8240,9 @@ __metadata: languageName: node linkType: hard -"terser@npm:^5.0.0": - version: 5.28.1 - resolution: "terser@npm:5.28.1" +"terser@npm:^5.17.4": + version: 5.31.1 + resolution: "terser@npm:5.31.1" dependencies: "@jridgewell/source-map": "npm:^0.3.3" acorn: "npm:^8.8.2" @@ -8246,7 +8250,7 @@ __metadata: source-map-support: "npm:~0.5.20" bin: terser: bin/terser - checksum: 10c0/e0d9a3cd260b4e35b49e828687658e36b0f50dce7cc2e18f024725846013ffa0e9eb8ac61a7a1bbf6684e6c14493ccf155a0f5937a47c746f534208f9000ac29 + checksum: 10c0/4d49a58f64c11f3742e779a0a03aff69972ca5739decb361d909d22c8f3f7d8e2ec982a928d987d56737ad50229e8ab3f62d8ba993e4b5f360a53ed487d3c06c languageName: node linkType: hard @@ -8420,13 +8424,20 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.0.1, tslib@npm:^2.1.0, tslib@npm:^2.3.1": +"tslib@npm:^2.0.1, tslib@npm:^2.1.0": version: 2.6.2 resolution: "tslib@npm:2.6.2" checksum: 10c0/e03a8a4271152c8b26604ed45535954c0a45296e32445b4b87f8a5abdb2421f40b59b4ca437c4346af0f28179780d604094eb64546bee2019d903d01c6c19bdb languageName: node linkType: hard +"tslib@npm:^2.6.2": + version: 2.6.3 + resolution: "tslib@npm:2.6.3" + checksum: 10c0/2598aef53d9dbe711af75522464b2104724d6467b26a60f2bdac8297d2b5f1f6b86a71f61717384aa8fd897240467aaa7bcc36a0700a0faf751293d1331db39a + languageName: node + linkType: hard + "tweezer.js@npm:^1.4.0": version: 1.5.0 resolution: "tweezer.js@npm:1.5.0" @@ -8667,6 +8678,20 @@ __metadata: languageName: node linkType: hard +"update-browserslist-db@npm:^1.0.16": + version: 1.0.16 + resolution: "update-browserslist-db@npm:1.0.16" + dependencies: + escalade: "npm:^3.1.2" + picocolors: "npm:^1.0.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10c0/5995399fc202adbb51567e4810e146cdf7af630a92cc969365a099150cb00597e425cc14987ca7080b09a4d0cfd2a3de53fbe72eebff171aed7f9bb81f9bf405 + languageName: node + linkType: hard + "update-notifier@npm:^4.1.0": version: 4.1.3 resolution: "update-notifier@npm:4.1.3" @@ -9187,7 +9212,7 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^1.10.0, yaml@npm:^1.10.2": +"yaml@npm:^1.10.0": version: 1.10.2 resolution: "yaml@npm:1.10.2" checksum: 10c0/5c28b9eb7adc46544f28d9a8d20c5b3cb1215a886609a2fd41f51628d8aaa5878ccd628b755dbcd29f6bb4921bd04ffbc6dcc370689bb96e594e2f9813d2605f From f193f9925f557f9275c258ceed70f7e01e2a8aca Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 8 Jun 2024 11:40:05 -0700 Subject: [PATCH 150/189] Add `update` trigger action. --- docs/configuration/profiles.md | 2 +- docs/configuration/view.md | 2 +- docs/troubleshooting.md | 2 +- src/card-controller/triggers-manager.ts | 17 +- src/config/profiles/low-performance.ts | 4 + src/config/types.ts | 17 +- .../card-controller/triggers-manager.test.ts | 356 ++++++++++++------ tests/config/profiles/low-performance.test.ts | 1 + tests/config/types.test.ts | 2 +- 9 files changed, 266 insertions(+), 137 deletions(-) diff --git a/docs/configuration/profiles.md b/docs/configuration/profiles.md index 287e7e07..a3b3a845 100644 --- a/docs/configuration/profiles.md +++ b/docs/configuration/profiles.md @@ -28,7 +28,7 @@ Principles used in the selection of options set by `low-profile` profile mode: - Get 'out of the box' performance similar to the basic "Home Assistant Picture Glance" card. - Do not break the visual aesthetic of the card. -See the [source code](https://github.com/dermotduffy/frigate-hass-card/blob/dev/src/config/profiles/low-performance.ts) for an exhaustive list of options set by this profile. +See the [source code](https://github.com/dermotduffy/frigate-hass-card/blob/dev/src/config/profiles/low-performance.ts) for an exhaustive list of defaults set by this profile. ## `scrubbing` diff --git a/docs/configuration/view.md b/docs/configuration/view.md index f71ce88f..c9436084 100644 --- a/docs/configuration/view.md +++ b/docs/configuration/view.md @@ -120,7 +120,7 @@ view: untrigger_seconds: 0 actions: interaction_mode: inactive - trigger: default + trigger: update untrigger: none keyboard_shortcuts: enabled: true diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index 5d51a4ab..e76eee91 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -56,7 +56,7 @@ This could be for any number of reasons. Chromecast devices can be quite picky on network, DNS and certificate issues, as well as audio and video codecs. Check your Home Assistant log as there may be more information in there. -!>: In particular, for Frigate to support casting of clips, the default ffmpeg +!> In particular, for Frigate to support casting of clips, the default ffmpeg settings for Frigate must be modified, i.e. Frigate does not encode clips in a Chromecast compatible format out of the box (specifically: audio must be enabled in the AAC codec, whether your camera supports audio or not). See the [Frigate diff --git a/src/card-controller/triggers-manager.ts b/src/card-controller/triggers-manager.ts index 46de4752..67d54eab 100644 --- a/src/card-controller/triggers-manager.ts +++ b/src/card-controller/triggers-manager.ts @@ -82,7 +82,8 @@ export class TriggersManager { // If this is a high-fidelity event where we are certain about new media, // don't take action unless it's to change to live (Frigate engine may pump - // out events where there's no new media to show). + // out events where there's no new media to show). Other trigger actions + // (e.g. media, update) do not make sense without having some new media. if ( ev.fidelity === 'high' && !ev.snapshot && @@ -96,7 +97,19 @@ export class TriggersManager { } if (this._hasAllowableInteractionStateForAction()) { - if (triggerAction === 'live') { + if (triggerAction === 'update') { + const view = this._api.getViewManager().getView()?.evolve({ + // Reset the media queries to catch media to be refetched in the + // current view. + query: null, + queryResults: null, + }); + /* istanbul ignore else: the else path cannot be reached, as the camera + cannot be triggered without a view -- @preserve */ + if (view) { + this._api.getViewManager().setView(view.clone()); + } + } else if (triggerAction === 'live') { this._api.getViewManager().setViewByParameters({ viewName: 'live', cameraID: ev.cameraID, diff --git a/src/config/profiles/low-performance.ts b/src/config/profiles/low-performance.ts index 570c8771..92fcea8f 100644 --- a/src/config/profiles/low-performance.ts +++ b/src/config/profiles/low-performance.ts @@ -46,6 +46,7 @@ import { CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_FAVORITE_CONTROL, CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_TIMELINE_CONTROL, CONF_TIMELINE_SHOW_RECORDINGS, + CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER, } from '../../const.js'; export const LOW_PERFORMANCE_PROFILE = { @@ -134,4 +135,7 @@ export const LOW_PERFORMANCE_PROFILE = { // Refresh the live camera image every 10 seconds (same as stock Home // Assistant Picture Glance). [CONF_CAMERAS_GLOBAL_IMAGE_REFRESH_SECONDS]: 10, + + // No trigger actions. + [CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER]: 'none' }; diff --git a/src/config/types.ts b/src/config/types.ts index 09d4dab8..8289ecc3 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -1406,7 +1406,7 @@ const viewConfigDefault = { filter_selected_camera: true, actions: { interaction_mode: 'inactive' as const, - trigger: 'default' as const, + trigger: 'update' as const, untrigger: 'none' as const, }, untrigger_seconds: 0, @@ -1415,26 +1415,25 @@ const viewConfigDefault = { }; export const triggersSchema = z.object({ - filter_selected_camera: z - .boolean() - .default(viewConfigDefault.triggers.filter_selected_camera), - show_trigger_status: z - .boolean() - .default(viewConfigDefault.triggers.show_trigger_status), - actions: z .object({ interaction_mode: z .enum(['all', 'inactive', 'active']) .default(viewConfigDefault.triggers.actions.interaction_mode), trigger: z - .enum(['live', 'default', 'media', 'none']) + .enum(['default', 'live', 'media', 'none', 'update']) .default(viewConfigDefault.triggers.actions.trigger), untrigger: z .enum(['default', 'none']) .default(viewConfigDefault.triggers.actions.untrigger), }) .default(viewConfigDefault.triggers.actions), + filter_selected_camera: z + .boolean() + .default(viewConfigDefault.triggers.filter_selected_camera), + show_trigger_status: z + .boolean() + .default(viewConfigDefault.triggers.show_trigger_status), untrigger_seconds: z.number().default(viewConfigDefault.triggers.untrigger_seconds), }); export type TriggersOptions = z.infer; diff --git a/tests/card-controller/triggers-manager.test.ts b/tests/card-controller/triggers-manager.test.ts index 5ae6b064..e81e8ecb 100644 --- a/tests/card-controller/triggers-manager.test.ts +++ b/tests/card-controller/triggers-manager.test.ts @@ -2,7 +2,11 @@ import { add } from 'date-fns'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { CardController } from '../../src/card-controller/controller'; import { TriggersManager } from '../../src/card-controller/triggers-manager'; -import { TriggersOptions, triggersSchema } from '../../src/config/types'; +import { + FrigateCardView, + TriggersOptions, + triggersSchema, +} from '../../src/config/types'; import { createCameraConfig, createCameraManager, @@ -16,11 +20,12 @@ vi.mock('lodash-es/throttle', () => ({ default: vi.fn((fn) => fn), })); -const baseTriggersConfig: Partial = { +const baseTriggersConfig: TriggersOptions = { untrigger_seconds: 10, filter_selected_camera: false, + show_trigger_status: false, actions: { - trigger: 'live' as const, + trigger: 'update' as const, untrigger: 'default' as const, interaction_mode: 'inactive' as const, }, @@ -30,6 +35,7 @@ const baseTriggersConfig: Partial = { // function reduces it. const createTriggerAPI = (options?: { config?: Partial; + default?: FrigateCardView; interaction?: boolean; }): CardController => { const api = createCardAPI(); @@ -39,6 +45,7 @@ const createTriggerAPI = (options?: { triggers: options?.config ? triggersSchema.parse(options.config) : baseTriggersConfig, + ...(options?.default && { default: options.default }), }, }), ); @@ -101,161 +108,266 @@ describe('TriggersManager', () => { expect(manager.isTriggered()).toBeFalsy(); }); - it('should trigger and untrigger based on low fidelity event', () => { - const api = createTriggerAPI(); - const manager = new TriggersManager(api); - - manager.handleCameraEvent({ - cameraID: 'camera_1', - type: 'new', - }); - - expect(manager.isTriggered()).toBeTruthy(); - expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({ - triggered: new Set(['camera_1']), - }); - - expect(api.getViewManager().setViewByParameters).toBeCalledWith({ - viewName: 'live' as const, - cameraID: 'camera_1' as const, - }); - - vi.mocked(api.getConditionsManager().getState).mockReturnValue({ - triggered: new Set(['camera_1']), - }); - - manager.handleCameraEvent({ - cameraID: 'camera_1', - type: 'end', - }); - - // Will still be triggered, but untrigger timer will be running. - expect(manager.isTriggered()).toBeTruthy(); - - vi.setSystemTime(add(start, { seconds: 10 })); - vi.runOnlyPendingTimers(); - - expect(manager.isTriggered()).toBeFalsy(); - expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({ - triggered: undefined, - }); - - expect(api.getViewManager().setViewDefault).toBeCalled(); - }); - - describe('should treat high fidelity events appropriately', () => { - it('with no media', () => { - const api = createTriggerAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - view: { - default: 'clips', + describe('trigger actions', () => { + it('update', () => { + const api = createTriggerAPI({ + config: { + ...baseTriggersConfig, + actions: { + ...baseTriggersConfig.actions, + trigger: 'update', }, - }), - ); + }, + }); const manager = new TriggersManager(api); + manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new', - fidelity: 'high', - - // Intentionally blank. }); expect(manager.isTriggered()).toBeTruthy(); + expect(api.getViewManager().setView).toBeCalled(); + }); + + it('default', () => { + const api = createTriggerAPI({ + config: { + ...baseTriggersConfig, + actions: { + ...baseTriggersConfig.actions, + trigger: 'default', + }, + }, + }); + + const manager = new TriggersManager(api); + + manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' }); + + expect(manager.isTriggered()).toBeTruthy(); + expect(api.getViewManager().setViewDefault).toBeCalledWith({ + cameraID: 'camera_1', + }); + }); + + it('live', () => { + const api = createTriggerAPI({ + config: { + ...baseTriggersConfig, + actions: { + ...baseTriggersConfig.actions, + trigger: 'live', + }, + }, + }); + + const manager = new TriggersManager(api); + + manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' }); + + expect(manager.isTriggered()).toBeTruthy(); + expect(api.getViewManager().setViewByParameters).toBeCalledWith({ + viewName: 'live', + cameraID: 'camera_1', + }); + }); + + describe('media', () => { + it.each([ + [false, false, null], + [false, true, 'clip' as const], + [true, false, 'snapshot' as const], + [true, true, 'clip' as const], + ])( + 'with snapshot %s and clip %s', + async ( + hasSnapshot: boolean, + hasClip: boolean, + viewName: 'clip' | 'snapshot' | null, + ) => { + const api = createTriggerAPI({ + config: { + actions: { + interaction_mode: 'all', + trigger: 'media', + untrigger: 'none', + }, + }, + }); + const manager = new TriggersManager(api); + + manager.handleCameraEvent({ + cameraID: 'camera_1', + type: 'new', + fidelity: 'high', + snapshot: hasSnapshot, + clip: hasClip, + }); + + if (!viewName) { + expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + } else { + expect(manager.isTriggered()).toBeTruthy(); + expect(api.getViewManager().setViewByParameters).toBeCalledWith({ + cameraID: 'camera_1', + viewName: viewName, + }); + } + }, + ); + }); + + it('none', () => { + const api = createTriggerAPI({ + config: { + ...baseTriggersConfig, + actions: { + ...baseTriggersConfig.actions, + trigger: 'none', + }, + }, + }); + + const manager = new TriggersManager(api); + + manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' }); + + expect(manager.isTriggered()).toBeTruthy(); + expect(api.getViewManager().setView).not.toBeCalled(); + expect(api.getViewManager().setViewDefault).not.toBeCalled(); + expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + }); + }); + + describe('untrigger actions', () => { + it('none', () => { + const api = createTriggerAPI({ + config: { + ...baseTriggersConfig, + actions: { + ...baseTriggersConfig.actions, + trigger: 'none', + untrigger: 'none', + }, + }, + }); + + const manager = new TriggersManager(api); + manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' }); + manager.handleCameraEvent({ cameraID: 'camera_1', type: 'end' }); + + vi.setSystemTime(add(start, { seconds: 10 })); + vi.runOnlyPendingTimers(); + + expect(manager.isTriggered()).toBeFalsy(); + + expect(api.getViewManager().setView).not.toBeCalled(); + expect(api.getViewManager().setViewDefault).not.toBeCalled(); expect(api.getViewManager().setViewByParameters).not.toBeCalled(); }); - it('with media', () => { - const api = createTriggerAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - view: { - default: 'clips', + it('default', () => { + const api = createTriggerAPI({ + config: { + ...baseTriggersConfig, + actions: { + ...baseTriggersConfig.actions, + trigger: 'none', + untrigger: 'default', }, - }), - ); - - const manager = new TriggersManager(api); - manager.handleCameraEvent({ - cameraID: 'camera_1', - type: 'new', - fidelity: 'high', - clip: true, + }, }); - expect(manager.isTriggered()).toBeTruthy(); + const manager = new TriggersManager(api); + manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' }); + manager.handleCameraEvent({ cameraID: 'camera_1', type: 'end' }); + + vi.setSystemTime(add(start, { seconds: 10 })); + vi.runOnlyPendingTimers(); + + expect(manager.isTriggered()).toBeFalsy(); + expect(api.getViewManager().setViewDefault).toBeCalled(); }); }); - it('should change to default view when suitably configured', () => { + it('should manage condition state', () => { const api = createTriggerAPI({ config: { + ...baseTriggersConfig, actions: { - interaction_mode: 'all', - trigger: 'default', + ...baseTriggersConfig.actions, + trigger: 'none', untrigger: 'none', }, }, }); + const manager = new TriggersManager(api); - manager.handleCameraEvent({ - cameraID: 'camera_1', - type: 'new', + manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' }); + + expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({ + triggered: new Set(['camera_1']), + }); + vi.mocked(api.getConditionsManager().getState).mockReturnValue({ + triggered: new Set(['camera_1']), }); - expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setViewDefault).toBeCalledWith({ - cameraID: 'camera_1', + manager.handleCameraEvent({ cameraID: 'camera_1', type: 'end' }); + + vi.setSystemTime(add(start, { seconds: 10 })); + vi.runOnlyPendingTimers(); + + expect(api.getConditionsManager().setState).toHaveBeenLastCalledWith({ + triggered: undefined, }); }); - describe('should change to media view', () => { - it.each([ - [false, false, null], - [false, true, 'clip' as const], - [true, false, 'snapshot' as const], - [true, true, 'clip' as const], - ])( - 'with snapshot %s and clip %s', - async ( - hasSnapshot: boolean, - hasClip: boolean, - viewName: 'clip' | 'snapshot' | null, - ) => { - const api = createTriggerAPI({ - config: { - actions: { - interaction_mode: 'all', - trigger: 'media', - untrigger: 'none', - }, + describe('should take no actions with high-fidelity event', () => { + it('with non-live action', () => { + const api = createTriggerAPI({ + config: { + ...baseTriggersConfig, + actions: { + ...baseTriggersConfig.actions, + trigger: 'media', }, - }); - const manager = new TriggersManager(api); + }, + default: 'live', + }); - manager.handleCameraEvent({ - cameraID: 'camera_1', - type: 'new', - fidelity: 'high', - snapshot: hasSnapshot, - clip: hasClip, - }); + const manager = new TriggersManager(api); - if (!viewName) { - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); - } else { - expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setViewByParameters).toBeCalledWith({ - cameraID: 'camera_1', - viewName: viewName, - }); - } - }, - ); + manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new', fidelity: 'high' }); + + expect(api.getViewManager().setView).not.toBeCalled(); + expect(api.getViewManager().setViewDefault).not.toBeCalled(); + expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + }); + + it('with non-live default', () => { + const api = createTriggerAPI({ + config: { + ...baseTriggersConfig, + actions: { + ...baseTriggersConfig.actions, + trigger: 'default', + }, + }, + default: 'clips', + }); + + const manager = new TriggersManager(api); + + manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new', fidelity: 'high' }); + + expect(api.getViewManager().setView).not.toBeCalled(); + expect(api.getViewManager().setViewDefault).not.toBeCalled(); + expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + }); }); it('should take no actions with human interactions', () => { diff --git a/tests/config/profiles/low-performance.test.ts b/tests/config/profiles/low-performance.test.ts index c048d020..30832789 100644 --- a/tests/config/profiles/low-performance.test.ts +++ b/tests/config/profiles/low-performance.test.ts @@ -50,5 +50,6 @@ it('low performance profile', () => { 'timeline.controls.thumbnails.show_favorite_control': false, 'timeline.controls.thumbnails.show_timeline_control': false, 'timeline.show_recordings': false, + 'view.triggers.actions.trigger': 'none', }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 6e90f23c..62ee482e 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -324,7 +324,7 @@ describe('config defaults', () => { show_trigger_status: false, untrigger_seconds: 0, actions: { - trigger: 'default', + trigger: 'update', untrigger: 'none', interaction_mode: 'inactive', }, From afb9af5eb4acd277fec1d48bc09f3a7a8739bdac Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 10 Jun 2024 20:01:01 -0700 Subject: [PATCH 151/189] Rename several view variables for clarity. --- docs/configuration/view.md | 40 ++++- rollup.config.js | 1 + src/camera-manager/camera.ts | 3 +- src/card-controller/auto-update-manager.ts | 42 ----- src/card-controller/card-element-manager.ts | 2 + src/card-controller/config/config-manager.ts | 12 ++ src/card-controller/controller.ts | 17 +- src/card-controller/default-manager.ts | 92 ++++++++++ src/card-controller/hass-manager.ts | 24 --- src/card-controller/initialization-manager.ts | 4 + src/card-controller/interaction-manager.ts | 5 +- src/card-controller/keyboard-state-manager.ts | 2 +- src/card-controller/types.ts | 22 ++- src/card-controller/view-manager.ts | 6 +- src/config/management.ts | 17 ++ src/config/profiles/low-performance.ts | 2 +- src/config/types.ts | 41 +++-- src/const.ts | 16 +- src/editor.ts | 72 ++++++-- src/localize/languages/ca.json | 26 ++- src/localize/languages/en.json | 19 +- src/localize/languages/fr.json | 26 ++- src/localize/languages/it.json | 26 ++- src/localize/languages/pt-BR.json | 26 ++- src/localize/languages/pt-PT.json | 26 ++- src/utils/ha/index.ts | 2 + src/utils/interaction-mode.ts | 15 ++ .../auto-update-manager.test.ts | 73 -------- .../config/config-manager.test.ts | 33 ++++ tests/card-controller/controller.test.ts | 10 +- tests/card-controller/default-manager.test.ts | 163 ++++++++++++++++++ tests/card-controller/hass-manager.test.ts | 32 +--- .../initialization-manager.test.ts | 13 +- .../interaction-manager.test.ts | 11 +- tests/card-controller/view-manager.test.ts | 4 +- tests/config/management.test.ts | 94 ++++++++++ tests/config/types.test.ts | 11 +- tests/test-utils.ts | 4 +- tests/utils/interaction-mode.test.ts | 19 ++ vite.config.ts | 1 + 40 files changed, 769 insertions(+), 285 deletions(-) delete mode 100644 src/card-controller/auto-update-manager.ts create mode 100644 src/card-controller/default-manager.ts create mode 100644 src/utils/interaction-mode.ts delete mode 100644 tests/card-controller/auto-update-manager.test.ts create mode 100644 tests/card-controller/default-manager.test.ts create mode 100644 tests/utils/interaction-mode.test.ts diff --git a/docs/configuration/view.md b/docs/configuration/view.md index c9436084..9e2ad5dd 100644 --- a/docs/configuration/view.md +++ b/docs/configuration/view.md @@ -13,18 +13,40 @@ view: | `camera_select` | `current` | The [view](view.md?id=supported-views) to show when a new camera is selected (e.g. in the camera menu). If `current` the view is unchanged when a new camera is selected. | | `dark_mode` | `off` | Whether or not to turn dark mode `on`, `off` or `auto` to automatically turn on if the card `interaction_seconds` has expired (i.e. card has been left unattended for that period of time) or if dark mode is enabled in the HA profile theme setting. Dark mode dims the brightness by `25%`. | | `default` | `live` | The view to show in the card by default. The default camera is the first one listed. See [Supported Views](view.md?id=supported-views) below. | +| `default_reset` | | The circumstances and behavior that cause the card to reset to the default view. See below. | | `interaction_seconds` | `300` | After a mouse/touch interaction with the card, it will be considered "interacted with" until this number of seconds elapses without further interaction. May be used as part of an [interaction condition](conditions.md?id=interaction) or with `reset_after_interaction` to reset the view after the interaction is complete. `0` means no interactions are reported / acted upon. | | `keyboard_shortcuts` | See [usage](../usage/keyboard-shortcuts.md) for defaults. | Configure keyboard shortcuts. See below. | | `render_entities` | | **YAML only**: A list of entity ids that should cause the card to re-render 'in-place'. The view/camera is not changed. `update_*` flags do not pertain/relate to the behavior of this flag. This should **very** rarely be needed, but could be useful if the card is both setting and changing HA state of the same object as could be the case for some complex `card_mod` scenarios ([example](https://github.com/dermotduffy/frigate-hass-card/issues/343)). | | `reset_after_interaction` | `true` | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | | `triggers` | | How to react when a camera is [triggered](cameras/README.md?id=triggers). | -| `update_cycle_camera` | `false` | When set to `true` the selected camera is cycled on each default view change. | +| `default_cycle_camera` | `false` | When set to `true` the selected camera is cycled on each default view change. | | `update_entities` | | **YAML only**: A card-wide list of entities that should cause the view to reset to the default (if the entity only pertains to a particular camera use [`triggers`](cameras/README.md?id=triggers) for the selected camera instead. | -| `update_force` | `false` | Whether automated card updates should ignore user interaction. | -| `update_seconds` | `0` | A number of seconds after which to automatically update/refresh the default view. If the default view occurs sooner (e.g. manually) the timer will start over. `0` disables this functionality. | + +## `default_reset` + +Configure the circumstances and behavior that cause the card to reset to the default view. All configuration is under: + +```yaml +view: + default_reset: [...] +``` + +| Option | Default | Description | +| ------------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `after_interaction` | `true` | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | +| `entities` | | A list of entities that should cause the view to reset to the default (if the entity only pertains to a particular camera use [`triggers`](cameras/README.md?id=triggers) for the selected camera instead). | +| `interaction_mode` | `inactive` | Whether the default reset should happen when the card is being interacted with. If `all`, the reset will always happen regardless. If `inactive` the reset will only be taken if the card has _not_ had human interaction recently (as defined by `view.interaction_seconds`). If `active` the reset will only be happen if the card _has_ had human interaction recently. This controls resets triggered by `entities` and `every_seconds`, but not `after_interaction` which by definition requires no interaction. | +| `every_seconds` | `0` | A number of seconds after which to automatically reset to the default view. `0` disables this functionality. | ## `keyboard_shortcuts` +All configuration is under: + +```yaml +view: + keyboard_shortcuts: [...] +``` + Configure the key-bindings for the builtin keyboard shortcuts. See [usage](../usage/keyboard-shortcuts.md) information for defaults on keyboard shortcuts. | Option | Default | Description | @@ -106,11 +128,13 @@ view: default: live camera_select: current interaction_seconds: 300 - update_seconds: 0 - update_force: false - update_cycle_camera: false - update_entities: - - binary_sensor.my_motion_sensor + default_cycle_camera: false + default_reset: + after_interaction: false + entities: + - binary_sensor.my_motion_sensor + every_seconds: 0 + interaction_mode: inactive render_entities: - switch.render_card dark_mode: 'off' diff --git a/rollup.config.js b/rollup.config.js index c3b3f421..5d40a750 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -50,6 +50,7 @@ const plugins = [ }), typescript({ sourceMap: dev, + inlineSources: dev, }), json({ exclude: 'package.json' }), replace({ diff --git a/src/camera-manager/camera.ts b/src/camera-manager/camera.ts index c987b9f3..9e83e5d9 100644 --- a/src/camera-manager/camera.ts +++ b/src/camera-manager/camera.ts @@ -3,6 +3,7 @@ import { CameraConfig } from '../config/types'; import { localize } from '../localize/localize'; import { allPromises } from '../utils/basic'; import { + DestroyCallback, isTriggeredState, parseStateChangeTrigger, subscribeToTrigger, @@ -13,8 +14,6 @@ import { CameraManagerEngine } from './engine'; import { CameraNoIDError } from './error'; import { CameraEventCallback } from './types'; -type DestroyCallback = () => Promise; - export class Camera { protected _config: CameraConfig; protected _engine: CameraManagerEngine; diff --git a/src/card-controller/auto-update-manager.ts b/src/card-controller/auto-update-manager.ts deleted file mode 100644 index bad2f5a7..00000000 --- a/src/card-controller/auto-update-manager.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Timer } from '../utils/timer'; -import { CardAutoRefreshAPI } from './types'; - -export class AutoUpdateManager { - protected _timer = new Timer(); - protected _api: CardAutoRefreshAPI; - - constructor(api: CardAutoRefreshAPI) { - this._api = api; - } - - /** - * Set the update timer to trigger an update refresh every - * `view.update_seconds`. - */ - public startDefaultViewTimer(): void { - this._timer.stop(); - const updateSeconds = this._api.getConfigManager().getConfig()?.view.update_seconds; - if (updateSeconds) { - this._timer.start(updateSeconds, () => { - if (this._isAutomatedUpdateAllowed()) { - this._api.getViewManager().setViewDefault(); - } else { - // Not allowed to update this time around, but try again at the next - // interval. - this.startDefaultViewTimer(); - } - }); - } - } - - protected _isAutomatedUpdateAllowed(): boolean { - const triggers = this._api.getTriggersManager(); - const config = this._api.getConfigManager().getConfig(); - const interactionManager = this._api.getInteractionManager(); - - return ( - !triggers.isTriggered() && - (config?.view.update_force || !interactionManager.hasInteraction()) - ); - } -} diff --git a/src/card-controller/card-element-manager.ts b/src/card-controller/card-element-manager.ts index 5c8b80db..14aa2c48 100644 --- a/src/card-controller/card-element-manager.ts +++ b/src/card-controller/card-element-manager.ts @@ -67,6 +67,7 @@ export class CardElementManager { this._api.getMediaLoadedInfoManager().initialize(); this._api.getMicrophoneManager().initialize(); this._api.getKeyboardStateManager().initialize(); + this._api.getDefaultManager().initialize(); // Whether or not the card is in panel mode on the dashboard. setOrRemoveAttribute(this._element, isCardInPanel(this._element), 'panel'); @@ -123,6 +124,7 @@ export class CardElementManager { this._api.getFullscreenManager().disconnect(); this._api.getKeyboardStateManager().uninitialize(); this._api.getActionsManager().uninitialize(); + this._api.getDefaultManager().uninitialize(); // Uninitialize cameras to cause them to reinitialize on // reconnection, to ensure the state subscription/unsubscription works diff --git a/src/card-controller/config/config-manager.ts b/src/card-controller/config/config-manager.ts index a2b3fa5e..7271ac99 100644 --- a/src/card-controller/config/config-manager.ts +++ b/src/card-controller/config/config-manager.ts @@ -142,6 +142,18 @@ export class ConfigManager { .uninitialize(InitializationAspect.MICROPHONE_CONNECT); } + if ( + previousConfig && + !isEqual( + previousConfig?.view.default_reset, + this._overriddenConfig?.view.default_reset, + ) + ) { + this._api + .getInitializationManager() + .uninitialize(InitializationAspect.DEFAULT_RESET); + } + this._api.getCardElementManager().update(); } } diff --git a/src/card-controller/controller.ts b/src/card-controller/controller.ts index ca69fff8..683611cd 100644 --- a/src/card-controller/controller.ts +++ b/src/card-controller/controller.ts @@ -6,7 +6,7 @@ import { EntityRegistryManager } from '../utils/ha/entity-registry'; import { EntityCache } from '../utils/ha/entity-registry/cache'; import { ResolvedMediaCache } from '../utils/ha/resolved-media'; import { ActionsManager } from './actions/actions-manager'; -import { AutoUpdateManager } from './auto-update-manager'; +import { DefaultManager } from './default-manager'; import { AutomationsManager } from './automations-manager'; import { CameraURLManager } from './camera-url-manager'; import { @@ -32,12 +32,12 @@ import { StyleManager } from './style-manager'; import { TriggersManager } from './triggers-manager'; import { CardActionsManagerAPI, - CardAutoRefreshAPI, CardAutomationsAPI, CardCameraAPI, CardCameraURLAPI, CardConditionAPI, CardConfigAPI, + CardDefaultManagerAPI, CardDownloadAPI, CardElementAPI, CardExpandAPI, @@ -62,11 +62,11 @@ export class CardController implements CardActionsManagerAPI, CardAutomationsAPI, - CardAutoRefreshAPI, CardCameraAPI, CardCameraURLAPI, CardConditionAPI, CardConfigAPI, + CardDefaultManagerAPI, CardDownloadAPI, CardElementAPI, CardExpandAPI, @@ -92,12 +92,12 @@ export class CardController protected _actionsManager = new ActionsManager(this); protected _automationsManager = new AutomationsManager(this); - protected _autoUpdateManager = new AutoUpdateManager(this); protected _cameraManager = new CameraManager(this); protected _cameraURLManager = new CameraURLManager(this); protected _cardElementManager: CardElementManager; protected _conditionsManager: ConditionsManager; protected _configManager = new ConfigManager(this); + protected _defaultManager = new DefaultManager(this); protected _downloadManager = new DownloadManager(this); protected _expandManager = new ExpandManager(this); protected _fullscreenManager = new FullscreenManager(this); @@ -143,10 +143,6 @@ export class CardController return this._automationsManager; } - public getAutoUpdateManager(): AutoUpdateManager { - return this._autoUpdateManager; - } - public getCameraManager(): CameraManager { return this._cameraManager; } @@ -171,6 +167,11 @@ export class CardController public getConfigManager(): ConfigManager { return this._configManager; } + + public getDefaultManager(): DefaultManager { + return this._defaultManager; + } + public getDownloadManager(): DownloadManager { return this._downloadManager; } diff --git a/src/card-controller/default-manager.ts b/src/card-controller/default-manager.ts new file mode 100644 index 00000000..6d782b0e --- /dev/null +++ b/src/card-controller/default-manager.ts @@ -0,0 +1,92 @@ +import PQueue from 'p-queue'; +import { DestroyCallback, subscribeToTrigger } from '../utils/ha'; +import { isActionAllowedBasedOnInteractionState } from '../utils/interaction-mode'; +import { Timer } from '../utils/timer'; +import { CardDefaultManagerAPI } from './types'; + +/** + * Manages automated resetting to the default view. + */ +export class DefaultManager { + protected _timer = new Timer(); + protected _api: CardDefaultManagerAPI; + protected _unsubscribeCallback: DestroyCallback | null = null; + protected _initializationLimit = new PQueue({ concurrency: 1 }); + + constructor(api: CardDefaultManagerAPI) { + this._api = api; + } + + /** + * Initialize the default manager. Requires both hass and configuration to be + * effective (so cannot be called from just the configuration manager, as hass + * will not be available yet) + */ + public async initialize(): Promise { + const result = await this._initializationLimit.add(() => this._reconfigure()); + this._startTimer(); + return !!result; + } + + public uninitialize(): void { + this._timer.stop(); + this._unsubscribeCallback?.(); + this._unsubscribeCallback = null; + } + + protected async _reconfigure(): Promise { + const hass = this._api.getHASSManager().getHASS(); + const config = this._api.getConfigManager().getConfig()?.view.default_reset; + if (!hass || !config) { + return false; + } + + if (this._unsubscribeCallback) { + await this._unsubscribeCallback(); + } + + this._unsubscribeCallback = await subscribeToTrigger( + hass, + () => this._setToDefaultIfAllowed(), + { + entityID: config.entities, + platform: 'state', + stateOnly: true, + }, + ); + + // If the timer is running, restart it with the newly configured timer. + if (this._timer.isRunning()) { + this._timer.stop(); + this._startTimer(); + } + + return true; + } + + protected _setToDefaultIfAllowed(): void { + if (this._isAutomatedUpdateAllowed()) { + this._api.getViewManager().setViewDefault(); + } + } + + protected _isAutomatedUpdateAllowed(): boolean { + const interactionMode = this._api.getConfigManager().getConfig()?.view + .default_reset.interaction_mode; + return ( + !!interactionMode && + isActionAllowedBasedOnInteractionState( + interactionMode, + this._api.getInteractionManager().hasInteraction(), + ) + ); + } + + protected _startTimer(): void { + const timerSeconds = this._api.getConfigManager().getConfig()?.view + .default_reset.every_seconds; + if (timerSeconds) { + this._timer.startRepeated(timerSeconds, () => this._setToDefaultIfAllowed()); + } + } +} diff --git a/src/card-controller/hass-manager.ts b/src/card-controller/hass-manager.ts index 2ada031f..34c35e7d 100644 --- a/src/card-controller/hass-manager.ts +++ b/src/card-controller/hass-manager.ts @@ -37,23 +37,6 @@ export class HASSManager { this._hass = hass; if ( - // Home Assistant pumps a lot of updates through. Re-rendering the card is - // necessary at times (e.g. to update the 'clip' view as new clips - // arrive), but also is a jarring experience for the user (e.g. if they - // are browsing the mini-gallery). Do not allow re-rendering from a Home - // Assistant update if there's been recent interaction (e.g. clicks on the - // card) or if there is media active playing. - this._isAutomatedViewUpdateAllowed() && - isHassDifferent( - this._hass, - oldHass, - this._api.getConfigManager().getConfig()?.view.update_entities ?? [], - ) - ) { - // If entities being monitored have changed then reset the view to the - // default. - this._api.getViewManager().setViewDefault(); - } else if ( isHassDifferent(this._hass, oldHass, [ ...(this._api.getConfigManager().getConfig()?.view.render_entities ?? []), @@ -75,11 +58,4 @@ export class HASSManager { // Dark mode may depend on HASS. this._api.getStyleManager().setLightOrDarkMode(); } - - protected _isAutomatedViewUpdateAllowed(): boolean { - return ( - this._api.getConfigManager().getConfig()?.view.update_force || - !this._api.getInteractionManager().hasInteraction() - ); - } } diff --git a/src/card-controller/initialization-manager.ts b/src/card-controller/initialization-manager.ts index cbc23190..a8de6c75 100644 --- a/src/card-controller/initialization-manager.ts +++ b/src/card-controller/initialization-manager.ts @@ -9,6 +9,7 @@ export enum InitializationAspect { MEDIA_PLAYERS = 'media-players', CAMERAS = 'cameras', MICROPHONE_CONNECT = 'microphone-connect', + DEFAULT_RESET = 'default-reset', } export class InitializationManager { @@ -125,6 +126,7 @@ export class InitializationManager { if ( this._initializer.isInitializedMultiple([ + InitializationAspect.DEFAULT_RESET, ...(config.menu.buttons.media_player.enabled ? [InitializationAspect.MEDIA_PLAYERS] : []), @@ -135,6 +137,8 @@ export class InitializationManager { if ( !(await this._initializer.initializeMultipleIfNecessary({ + [InitializationAspect.DEFAULT_RESET]: async () => + await this._api.getDefaultManager().initialize(), ...(config.menu.buttons.media_player.enabled && { [InitializationAspect.MEDIA_PLAYERS]: async () => await this._api.getMediaPlayerManager().initialize(), diff --git a/src/card-controller/interaction-manager.ts b/src/card-controller/interaction-manager.ts index 64a43912..350a6fcb 100644 --- a/src/card-controller/interaction-manager.ts +++ b/src/card-controller/interaction-manager.ts @@ -41,7 +41,10 @@ export class InteractionManager { this._api.getConditionsManager().setState({ interaction: false }); if (!this._api.getTriggersManager().isTriggered()) { - if (this._api.getConfigManager().getConfig()?.view.reset_after_interaction) { + if ( + this._api.getConfigManager().getConfig()?.view.default_reset + .after_interaction + ) { this._api.getViewManager().setViewDefault(); } this._api.getStyleManager().setLightOrDarkMode(); diff --git a/src/card-controller/keyboard-state-manager.ts b/src/card-controller/keyboard-state-manager.ts index 53a24a6c..b2ad3626 100644 --- a/src/card-controller/keyboard-state-manager.ts +++ b/src/card-controller/keyboard-state-manager.ts @@ -1,5 +1,5 @@ import { CardKeyboardStateAPI, KeysState } from './types'; -import isEqual from 'lodash/isEqual'; +import isEqual from 'lodash-es/isEqual'; export class KeyboardStateManager { protected _api: CardKeyboardStateAPI; diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index 7eb9ebf7..a77d89af 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -3,7 +3,7 @@ import type { ConditionsManager } from './conditions-manager'; import type { EntityRegistryManager } from '../utils/ha/entity-registry'; import type { ResolvedMediaCache } from '../utils/ha/resolved-media'; import type { ActionsManager } from './actions/actions-manager'; -import type { AutoUpdateManager } from './auto-update-manager'; +import type { DefaultManager } from './default-manager'; import type { AutomationsManager } from './automations-manager'; import type { CameraURLManager } from './camera-url-manager'; import type { CardElementManager } from './card-element-manager'; @@ -60,13 +60,6 @@ export interface CardAutomationsAPI { getMessageManager(): MessageManager; } -export interface CardAutoRefreshAPI { - getConfigManager(): ConfigManager; - getInteractionManager(): InteractionManager; - getTriggersManager(): TriggersManager; - getViewManager(): ViewManager; -} - export interface CardCameraAPI { getActionsManager(): ActionsManager; getConfigManager(): ConfigManager; @@ -92,6 +85,7 @@ export interface CardConfigAPI { getCardElementManager(): CardElementManager; getConditionsManager(): ConditionsManager; getConfigManager(): ConfigManager; + getDefaultManager(): DefaultManager; getInitializationManager(): InitializationManager; getMediaLoadedInfoManager(): MediaLoadedInfoManager; getMessageManager(): MessageManager; @@ -104,6 +98,14 @@ export interface CardConfigLoaderAPI { getAutomationsManager(): AutomationsManager; } +export interface CardDefaultManagerAPI { + getConfigManager(): ConfigManager; + getHASSManager(): HASSManager; + getInteractionManager(): InteractionManager; + getTriggersManager(): TriggersManager; + getViewManager(): ViewManager; +} + export interface CardDownloadAPI { getCameraManager(): CameraManager; getHASSManager(): HASSManager; @@ -115,6 +117,7 @@ export interface CardDownloadAPI { export interface CardElementAPI { getActionsManager(): ActionsManager; getCameraManager(): CameraManager; + getDefaultManager(): DefaultManager; getExpandManager(): ExpandManager; getFullscreenManager(): FullscreenManager; getInitializationManager(): InitializationManager; @@ -143,6 +146,7 @@ export interface CardHASSAPI { getCardElementManager(): CardElementManager; getConditionsManager(): ConditionsManager; getConfigManager(): ConfigManager; + getDefaultManager(): DefaultManager; getInteractionManager(): InteractionManager; getMediaPlayerManager(): MediaPlayerManager; getMessageManager(): MessageManager; @@ -155,6 +159,7 @@ export interface CardInitializerAPI { getCameraManager(): CameraManager; getCardElementManager(): CardElementManager; getConfigManager(): ConfigManager; + getDefaultManager(): DefaultManager; getEntityRegistryManager(): EntityRegistryManager; getHASSManager(): HASSManager; getMediaPlayerManager(): MediaPlayerManager; @@ -233,7 +238,6 @@ export interface CardTriggersAPI { } export interface CardViewAPI { - getAutoUpdateManager(): AutoUpdateManager; getCameraManager(): CameraManager; getCardElementManager(): CardElementManager; getConditionsManager(): ConditionsManager; diff --git a/src/card-controller/view-manager.ts b/src/card-controller/view-manager.ts index 5a369700..655d7ab3 100644 --- a/src/card-controller/view-manager.ts +++ b/src/card-controller/view-manager.ts @@ -55,7 +55,7 @@ export class ViewManager { let forceCameraID: string | null = params?.cameraID ?? null; const viewName = config.view.default; - if (!forceCameraID && this._view?.camera && config.view.update_cycle_camera) { + if (!forceCameraID && this._view?.camera && config.view.default_cycle_camera) { const cameraIDs = [ ...getCameraIDsForViewName(this._api.getCameraManager(), viewName), ]; @@ -69,10 +69,6 @@ export class ViewManager { viewName: viewName, ...(forceCameraID && { cameraID: forceCameraID }), }); - - // Restart the refresh timer, so the default view is refreshed at a fixed - // interval from now (if so configured). - this._api.getAutoUpdateManager().startDefaultViewTimer(); } } diff --git a/src/config/management.ts b/src/config/management.ts index 031abd2a..9f7d73ae 100644 --- a/src/config/management.ts +++ b/src/config/management.ts @@ -25,7 +25,11 @@ import { CONF_OVERRIDES, CONF_PROFILES, CONF_TIMELINE_EVENTS_MEDIA_TYPE, + CONF_VIEW_DEFAULT_CYCLE_CAMERA, CONF_VIEW_INTERACTION_SECONDS, + CONF_VIEW_DEFAULT_RESET_EVERY_SECONDS, + CONF_VIEW_DEFAULT_RESET_ENTITIES, + CONF_VIEW_DEFAULT_RESET_INTERACTION_MODE, CONF_VIEW_TRIGGERS, CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER, CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER, @@ -805,4 +809,17 @@ const UPGRADES = [ keepOriginal: true, }), upgradeWithOverrides('live.controls.ptz', ptzControlSettingsTransform), + upgradeMoveToWithOverrides('view.update_cycle_camera', CONF_VIEW_DEFAULT_CYCLE_CAMERA), + upgradeMoveToWithOverrides( + 'view.update_force', + CONF_VIEW_DEFAULT_RESET_INTERACTION_MODE, + { + transform: (val) => (val === true ? 'all' : null), + }, + ), + upgradeMoveToWithOverrides( + 'view.update_seconds', + CONF_VIEW_DEFAULT_RESET_EVERY_SECONDS, + ), + upgradeMoveToWithOverrides('view.update_entities', CONF_VIEW_DEFAULT_RESET_ENTITIES), ]; diff --git a/src/config/profiles/low-performance.ts b/src/config/profiles/low-performance.ts index 92fcea8f..e80e07cc 100644 --- a/src/config/profiles/low-performance.ts +++ b/src/config/profiles/low-performance.ts @@ -137,5 +137,5 @@ export const LOW_PERFORMANCE_PROFILE = { [CONF_CAMERAS_GLOBAL_IMAGE_REFRESH_SECONDS]: 10, // No trigger actions. - [CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER]: 'none' + [CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER]: 'none', }; diff --git a/src/config/types.ts b/src/config/types.ts index 8289ecc3..e62089ec 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -1396,16 +1396,18 @@ const viewConfigDefault = { default: FRIGATE_CARD_VIEW_DEFAULT, camera_select: 'current' as const, interaction_seconds: 300, - reset_after_interaction: true, - update_seconds: 0, - update_force: false, - update_cycle_camera: false, + default_reset: { + every_seconds: 0, + after_interaction: false, + entities: [], + interaction_mode: 'inactive' as const, + }, + default_cycle_camera: false, dark_mode: 'off' as const, triggers: { show_trigger_status: false, filter_selected_camera: true, actions: { - interaction_mode: 'inactive' as const, trigger: 'update' as const, untrigger: 'none' as const, }, @@ -1414,12 +1416,13 @@ const viewConfigDefault = { keyboard_shortcuts: keyboardShortcutsDefault, }; +const interactionModeSchema = z.enum(['all', 'inactive', 'active']).default('inactive'); +export type InteractionMode = z.infer; + export const triggersSchema = z.object({ actions: z .object({ - interaction_mode: z - .enum(['all', 'inactive', 'active']) - .default(viewConfigDefault.triggers.actions.interaction_mode), + interaction_mode: interactionModeSchema, trigger: z .enum(['default', 'live', 'media', 'none', 'update']) .default(viewConfigDefault.triggers.actions.trigger), @@ -1447,13 +1450,21 @@ const viewConfigSchema = z .enum([...FRIGATE_CARD_VIEWS_USER_SPECIFIED, 'current']) .default(viewConfigDefault.camera_select), interaction_seconds: z.number().default(viewConfigDefault.interaction_seconds), - reset_after_interaction: z - .boolean() - .default(viewConfigDefault.reset_after_interaction), - update_seconds: z.number().default(viewConfigDefault.update_seconds), - update_force: z.boolean().default(viewConfigDefault.update_force), - update_cycle_camera: z.boolean().default(viewConfigDefault.update_cycle_camera), - update_entities: z.string().array().optional(), + default_cycle_camera: z.boolean().default(viewConfigDefault.default_cycle_camera), + + default_reset: z + .object({ + after_interaction: z + .boolean() + .default(viewConfigDefault.default_reset.after_interaction), + every_seconds: z.number().default(viewConfigDefault.default_reset.every_seconds), + entities: z.string().array().default(viewConfigDefault.default_reset.entities), + interaction_mode: interactionModeSchema.default( + viewConfigDefault.default_reset.interaction_mode, + ), + }) + .default(viewConfigDefault.default_reset), + render_entities: z.string().array().optional(), dark_mode: z.enum(['on', 'off', 'auto']).optional(), triggers: triggersSchema.default(viewConfigDefault.triggers), diff --git a/src/const.ts b/src/const.ts index 0593f1e5..0b13b4a4 100644 --- a/src/const.ts +++ b/src/const.ts @@ -123,11 +123,17 @@ export const CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_ZOOM_OUT = `${CONF_VIEW_KEYBOARD_SHORTCUTS}.ptz_zoom_out` as const; export const CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_HOME = `${CONF_VIEW_KEYBOARD_SHORTCUTS}.ptz_home` as const; -export const CONF_VIEW_UPDATE_CYCLE_CAMERA = `${CONF_VIEW}.update_cycle_camera` as const; -export const CONF_VIEW_UPDATE_FORCE = `${CONF_VIEW}.update_force` as const; -export const CONF_VIEW_UPDATE_SECONDS = `${CONF_VIEW}.update_seconds` as const; -export const CONF_VIEW_RESET_AFTER_INTERACTION = - `${CONF_VIEW}.reset_after_interaction` as const; +export const CONF_VIEW_DEFAULT_CYCLE_CAMERA = + `${CONF_VIEW}.default_cycle_camera` as const; +export const CONF_VIEW_DEFAULT_RESET = `${CONF_VIEW}.default_reset` as const; +export const CONF_VIEW_DEFAULT_RESET_INTERACTION_MODE = + `${CONF_VIEW_DEFAULT_RESET}.interaction_mode` as const; +export const CONF_VIEW_DEFAULT_RESET_EVERY_SECONDS = + `${CONF_VIEW_DEFAULT_RESET}.every_seconds` as const; +export const CONF_VIEW_DEFAULT_RESET_ENTITIES = + `${CONF_VIEW_DEFAULT_RESET}.entities` as const; +export const CONF_VIEW_DEFAULT_RESET_AFTER_INTERACTION = + `${CONF_VIEW_DEFAULT_RESET}.after_interaction` as const; export const CONF_VIEW_TRIGGERS = `${CONF_VIEW}.triggers` as const; export const CONF_VIEW_TRIGGERS_SHOW_TRIGGER_STATUS = `${CONF_VIEW_TRIGGERS}.show_trigger_status` as const; diff --git a/src/editor.ts b/src/editor.ts index bbc7ed33..9839194b 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -201,7 +201,7 @@ import { CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_UP, CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_ZOOM_IN, CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_ZOOM_OUT, - CONF_VIEW_RESET_AFTER_INTERACTION, + CONF_VIEW_DEFAULT_RESET_AFTER_INTERACTION, CONF_VIEW_TRIGGERS, CONF_VIEW_TRIGGERS_ACTIONS, CONF_VIEW_TRIGGERS_ACTIONS_INTERACTION_MODE, @@ -210,10 +210,12 @@ import { CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA, CONF_VIEW_TRIGGERS_SHOW_TRIGGER_STATUS, CONF_VIEW_TRIGGERS_UNTRIGGER_SECONDS, - CONF_VIEW_UPDATE_CYCLE_CAMERA, - CONF_VIEW_UPDATE_FORCE, - CONF_VIEW_UPDATE_SECONDS, + CONF_VIEW_DEFAULT_CYCLE_CAMERA, MEDIA_CHUNK_SIZE_MAX, + CONF_VIEW_DEFAULT_RESET, + CONF_VIEW_DEFAULT_RESET_EVERY_SECONDS, + CONF_VIEW_DEFAULT_RESET_INTERACTION_MODE, + CONF_VIEW_DEFAULT_RESET_ENTITIES, } from './const.js'; import { localize } from './localize/localize.js'; import frigate_card_editor_style from './scss/editor.scss'; @@ -263,6 +265,7 @@ const MENU_PERFORMANCE_FEATURES = 'performance.features'; const MENU_PERFORMANCE_STYLE = 'performance.style'; const MENU_TIMELINE_CONTROLS_THUMBNAILS = 'timeline.controls.thumbnails'; const MENU_VIEW_KEYBOARD_SHORTCUTS = 'view.keyboard_shortcuts'; +const MENU_VIEW_DEFAULT_RESET = 'view.default_reset'; const MENU_VIEW_TRIGGERS = 'view.triggers'; const MENU_VIEW_TRIGGERS_ACTIONS = 'view.triggers.actions'; @@ -813,6 +816,22 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor }, ]; + protected _defaultResetInteractionModes: EditorSelectOption[] = [ + { value: '', label: '' }, + { + value: 'all', + label: localize('config.view.default_reset.interaction_modes.all'), + }, + { + value: 'inactive', + label: localize('config.view.default_reset.interaction_modes.inactive'), + }, + { + value: 'active', + label: localize('config.view.default_reset.interaction_modes.active'), + }, + ]; + public setConfig(config: RawFrigateCardConfig): void { // Note: This does not use Zod to parse the full configuration, so it may be // partially or completely invalid. It's more useful to have a partially @@ -1068,6 +1087,36 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ); } + protected _renderViewDefaultResetMenu(): TemplateResult { + return this._putInSubmenu( + MENU_VIEW_DEFAULT_RESET, + true, + `config.${CONF_VIEW_DEFAULT_RESET}.editor_label`, + { name: 'mdi:restart' }, + html` + ${this._renderSwitch( + CONF_VIEW_DEFAULT_RESET_AFTER_INTERACTION, + this._defaults.view.default_reset.after_interaction, + )} + ${this._renderNumberInput(CONF_VIEW_DEFAULT_RESET_EVERY_SECONDS)} + ${this._renderOptionSelector( + CONF_VIEW_DEFAULT_RESET_INTERACTION_MODE, + this._defaultResetInteractionModes, + { + label: localize('config.view.default_reset.interaction_mode'), + }, + )}, + ${this._renderOptionSelector( + CONF_VIEW_DEFAULT_RESET_ENTITIES, + this.hass ? getEntitiesFromHASS(this.hass) : [], + { + multiple: true, + }, + )} + `, + ); + } + protected _renderViewTriggersMenu(): TemplateResult { return this._putInSubmenu( MENU_VIEW_TRIGGERS, @@ -2330,19 +2379,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderOptionSelector(CONF_VIEW_DARK_MODE, this._darkModes)} ${this._renderNumberInput(CONF_VIEW_INTERACTION_SECONDS)} ${this._renderSwitch( - CONF_VIEW_RESET_AFTER_INTERACTION, - this._defaults.view.reset_after_interaction, + CONF_VIEW_DEFAULT_CYCLE_CAMERA, + this._defaults.view.default_cycle_camera, )} - ${this._renderNumberInput(CONF_VIEW_UPDATE_SECONDS)} - ${this._renderSwitch( - CONF_VIEW_UPDATE_FORCE, - this._defaults.view.update_force, - )} - ${this._renderSwitch( - CONF_VIEW_UPDATE_CYCLE_CAMERA, - this._defaults.view.update_cycle_camera, - )} - ${this._renderViewTriggersMenu()} + ${this._renderViewDefaultResetMenu()} ${this._renderViewTriggersMenu()} ${this._renderViewKeyboardShortcutMenu()} ` diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json index 01d3b62c..9492db6f 100644 --- a/src/localize/languages/ca.json +++ b/src/localize/languages/ca.json @@ -436,12 +436,31 @@ "on": "Activat" }, "default": "Vista per defecte", + "default_cycle_camera": "Passeu per les càmeres quan s'actualitzi la vista predeterminada", + "default_reset": { + "after_interaction": "Restableix la vista predeterminada després de la interacció de l'usuari", + "editor_label": "", + "entities": "", + "every_seconds": "Actualitza la vista predeterminada cada X segons (0=mai)", + "interaction_mode": "", + "interaction_modes": { + "active": "", + "all": "", + "inactive": "" + } + }, "interaction_seconds": "Segons després de l'acció de l'usuari per continuar interactuant (0=mai)", "keyboard_shortcuts": { "editor_label": "", - "enabled": "" + "enabled": "", + "ptz_down": "", + "ptz_home": "", + "ptz_left": "", + "ptz_right": "", + "ptz_up": "", + "ptz_zoom_in": "", + "ptz_zoom_out": "" }, - "reset_after_interaction": "Restableix la vista predeterminada després de la interacció de l'usuari", "triggers": { "actions": { "editor_label": "Activar accions", @@ -469,9 +488,6 @@ "show_trigger_status": "Mostra la vora intermitent quan s'activa", "untrigger_seconds": "Segons després del canvi d'estat inactiu a desactivat" }, - "update_cycle_camera": "Passeu per les càmeres quan s'actualitzi la vista predeterminada", - "update_force": "Força les actualitzacions de la targeta (ignora la interacció de l'usuari)", - "update_seconds": "Actualitza la vista predeterminada cada X segons (0=mai)", "views": { "clip": "Clip més recent", "clips": "Galeria de clips", diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index e7d8d321..72f3ff79 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -362,7 +362,6 @@ "camera_ui": "Camera user interface", "cameras": "Cameras", "clips": "Clips", - "ptz_home": "PTZ Home", "display_mode": "Display mode", "download": "Download", "enabled": "Button enabled", @@ -378,6 +377,7 @@ "play": "Play / Pause", "priority": "Priority", "ptz_controls": "Show PTZ controls", + "ptz_home": "PTZ Home", "recordings": "Recordings", "screenshot": "Screenshot", "snapshots": "Snapshots", @@ -436,6 +436,19 @@ "on": "On" }, "default": "Default view", + "default_cycle_camera": "Cycle through cameras when default view updates", + "default_reset": { + "after_interaction": "Reset to the default view after user interaction ends", + "editor_label": "Default view reset behavior", + "entities": "Reset to the default view on entity state change", + "every_seconds": "Reset to default view every X seconds (0=never)", + "interaction_mode": "How default reset behaves when the card has human interaction", + "interaction_modes": { + "active": "Only allow reset when card has active human interaction", + "all": "Reset regardless of human interaction", + "inactive": "Only reset when card has no human interaction" + } + }, "interaction_seconds": "Seconds after user action to remain interacted with (0=never)", "keyboard_shortcuts": { "editor_label": "Keyboard shortcuts", @@ -448,7 +461,6 @@ "ptz_zoom_in": "PTZ Zoom In", "ptz_zoom_out": "PTZ Zoom Out" }, - "reset_after_interaction": "Reset to the default view after user interaction", "triggers": { "actions": { "editor_label": "Trigger actions", @@ -476,9 +488,6 @@ "show_trigger_status": "Show pulsing border when triggered", "untrigger_seconds": "Seconds after inactive state change to untrigger" }, - "update_cycle_camera": "Cycle through cameras when default view updates", - "update_force": "Force card updates (ignore user interaction)", - "update_seconds": "Refresh default view every X seconds (0=never)", "views": { "clip": "Most recent clip", "clips": "Clips gallery", diff --git a/src/localize/languages/fr.json b/src/localize/languages/fr.json index 5d435d66..43acdfe4 100644 --- a/src/localize/languages/fr.json +++ b/src/localize/languages/fr.json @@ -436,12 +436,31 @@ "on": "Activé" }, "default": "Vue par défaut", + "default_cycle_camera": "Parcourez les caméras lorsque la vue par défaut est mise à jour", + "default_reset": { + "after_interaction": "", + "editor_label": "", + "entities": "", + "every_seconds": "Actualiser la vue par défaut toutes les X secondes (0=jamais)", + "interaction_mode": "", + "interaction_modes": { + "active": "", + "all": "", + "inactive": "" + } + }, "interaction_seconds": "", "keyboard_shortcuts": { "editor_label": "", - "enabled": "" + "enabled": "", + "ptz_down": "", + "ptz_home": "", + "ptz_left": "", + "ptz_right": "", + "ptz_up": "", + "ptz_zoom_in": "", + "ptz_zoom_out": "" }, - "reset_after_interaction": "", "triggers": { "actions": { "editor_label": "", @@ -469,9 +488,6 @@ "show_trigger_status": "Afficher la bordure clignotante lors du déclenchement", "untrigger_seconds": "Quelques secondes après le changement d'état inactif pour débloquer" }, - "update_cycle_camera": "Parcourez les caméras lorsque la vue par défaut est mise à jour", - "update_force": "Forcer les mises à jour de la carte (ignorer l'interaction de l'utilisateur)", - "update_seconds": "Actualiser la vue par défaut toutes les X secondes (0=jamais)", "views": { "clip": "Clip le plus récent", "clips": "Galerie de clips", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 08276c1a..70527221 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -436,12 +436,31 @@ "on": "On" }, "default": "Visualizzazione predefinita", + "default_cycle_camera": "Scorri le telecamere quando si aggiorna la visualizzazione predefinita", + "default_reset": { + "after_interaction": "", + "editor_label": "", + "entities": "", + "every_seconds": "Aggiorna la visualizzazione predefinita ogni x secondi (0 = mai)", + "interaction_mode": "", + "interaction_modes": { + "active": "", + "all": "", + "inactive": "" + } + }, "interaction_seconds": "", "keyboard_shortcuts": { "editor_label": "", - "enabled": "" + "enabled": "", + "ptz_down": "", + "ptz_home": "", + "ptz_left": "", + "ptz_right": "", + "ptz_up": "", + "ptz_zoom_in": "", + "ptz_zoom_out": "" }, - "reset_after_interaction": "", "triggers": { "actions": { "editor_label": "", @@ -469,9 +488,6 @@ "show_trigger_status": "Mostra bordo pulsante quando attivato", "untrigger_seconds": "Reimposta la vista ai valori predefiniti dopo aver annullato l'attivazione" }, - "update_cycle_camera": "Scorri le telecamere quando si aggiorna la visualizzazione predefinita", - "update_force": "Aggiornamenti della scheda forza (ignora l'interazione dell'utente)", - "update_seconds": "Aggiorna la visualizzazione predefinita ogni x secondi (0 = mai)", "views": { "clip": "Clip più recente", "clips": "Galleria delle clip", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index df882da2..865334e1 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -436,12 +436,31 @@ "on": "Ligado" }, "default": "Visualização padrão", + "default_cycle_camera": "Percorrer as câmeras quando a visualização padrão for atualizada", + "default_reset": { + "after_interaction": "", + "editor_label": "", + "entities": "", + "every_seconds": "Atualize a visualização padrão a cada X segundos (0 = nunca)", + "interaction_mode": "", + "interaction_modes": { + "active": "", + "all": "", + "inactive": "" + } + }, "interaction_seconds": "", "keyboard_shortcuts": { "editor_label": "", - "enabled": "" + "enabled": "", + "ptz_down": "", + "ptz_home": "", + "ptz_left": "", + "ptz_right": "", + "ptz_up": "", + "ptz_zoom_in": "", + "ptz_zoom_out": "" }, - "reset_after_interaction": "", "triggers": { "actions": { "editor_label": "", @@ -469,9 +488,6 @@ "show_trigger_status": "Pulsar borda quando acionado", "untrigger_seconds": "Segundos após a mudar para o estado inativo para desacionar" }, - "update_cycle_camera": "Percorrer as câmeras quando a visualização padrão for atualizada", - "update_force": "Forçar atualizações do cartão (ignore a interação do usuário)", - "update_seconds": "Atualize a visualização padrão a cada X segundos (0 = nunca)", "views": { "clip": "Clipe mais recente", "clips": "Galeria de clipes", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index ad966a0b..119c7ada 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -436,12 +436,31 @@ "on": "Ligado" }, "default": "Visualização padrão", + "default_cycle_camera": "Percorrer as câmeras quando a visualização padrão for atualizada", + "default_reset": { + "after_interaction": "", + "editor_label": "", + "entities": "", + "every_seconds": "Atualize a visualização padrão a cada X segundos (0 = nunca)", + "interaction_mode": "", + "interaction_modes": { + "active": "", + "all": "", + "inactive": "" + } + }, "interaction_seconds": "", "keyboard_shortcuts": { "editor_label": "", - "enabled": "" + "enabled": "", + "ptz_down": "", + "ptz_home": "", + "ptz_left": "", + "ptz_right": "", + "ptz_up": "", + "ptz_zoom_in": "", + "ptz_zoom_out": "" }, - "reset_after_interaction": "", "triggers": { "actions": { "editor_label": "", @@ -469,9 +488,6 @@ "show_trigger_status": "Exibir estado do gatilho", "untrigger_seconds": "Segundos após a mudar para o estado inativo para desacionar" }, - "update_cycle_camera": "Percorrer as câmeras quando a visualização padrão for atualizada", - "update_force": "Forçar atualizações do cartão (ignore a interação do Utilizador)", - "update_seconds": "Atualize a visualização padrão a cada X segundos (0 = nunca)", "views": { "clip": "Clipe mais recente", "clips": "Galeria de clipes", diff --git a/src/utils/ha/index.ts b/src/utils/ha/index.ts index 1d52a860..1a85e69a 100644 --- a/src/utils/ha/index.ts +++ b/src/utils/ha/index.ts @@ -24,6 +24,8 @@ import { SubscriptionUnsubscribe, } from './types.js'; +export type DestroyCallback = () => Promise; + /** * Make a HomeAssistant websocket request. May throw. * @param hass The HomeAssistant object to send the request with. diff --git a/src/utils/interaction-mode.ts b/src/utils/interaction-mode.ts new file mode 100644 index 00000000..a500f7b5 --- /dev/null +++ b/src/utils/interaction-mode.ts @@ -0,0 +1,15 @@ +import { InteractionMode } from '../config/types'; + +export const isActionAllowedBasedOnInteractionState = ( + interactionMode: InteractionMode, + interactionState: boolean, +): boolean => { + switch (interactionMode) { + case 'all': + return true; + case 'active': + return interactionState; + case 'inactive': + return !interactionState; + } +}; diff --git a/tests/card-controller/auto-update-manager.test.ts b/tests/card-controller/auto-update-manager.test.ts deleted file mode 100644 index 34382e1b..00000000 --- a/tests/card-controller/auto-update-manager.test.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { add } from 'date-fns'; -import { afterEach, describe, expect, it, vi } from 'vitest'; -import { AutoUpdateManager } from '../../src/card-controller/auto-update-manager'; -import { createCardAPI, createConfig } from '../test-utils'; - -// @vitest-environment jsdom -describe('AutoUpdateManager', () => { - const start = new Date('2023-09-23T19:12:00'); - - afterEach(() => { - vi.useRealTimers(); - }); - - it('should set default view when allowed', () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - view: { - update_seconds: 10, - }, - }), - ); - // Card is triggered. - vi.mocked(api.getTriggersManager().isTriggered).mockReturnValue(true); - vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(false); - - vi.useFakeTimers(); - vi.setSystemTime(start); - - const manager = new AutoUpdateManager(api); - manager.startDefaultViewTimer(); - - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - - vi.setSystemTime(add(start, { seconds: 10 })); - vi.runOnlyPendingTimers(); - - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - - vi.mocked(api.getTriggersManager().isTriggered).mockReturnValue(false); - - vi.setSystemTime(add(start, { seconds: 20 })); - vi.runOnlyPendingTimers(); - - expect(api.getViewManager().setViewDefault).toBeCalled(); - }); - - it('should not set default view when not configured', () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - view: { - update_seconds: 0, - }, - }), - ); - vi.mocked(api.getTriggersManager().isTriggered).mockReturnValue(false); - vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(false); - - vi.useFakeTimers(); - vi.setSystemTime(start); - - const manager = new AutoUpdateManager(api); - manager.startDefaultViewTimer(); - - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - - vi.setSystemTime(add(start, { seconds: 10 })); - vi.runOnlyPendingTimers(); - - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - }); -}); diff --git a/tests/card-controller/config/config-manager.test.ts b/tests/card-controller/config/config-manager.test.ts index de06f683..2272b86e 100644 --- a/tests/card-controller/config/config-manager.test.ts +++ b/tests/card-controller/config/config-manager.test.ts @@ -301,5 +301,38 @@ describe('ConfigManager', () => { InitializationAspect.MICROPHONE_CONNECT, ); }); + + it('view.default_reset', () => { + const api = createCardAPI(); + const manager = new ConfigManager(api); + const config_1 = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + view: { + default_reset: { + every_seconds: 1, + }, + }, + }; + vi.mocked(getOverriddenConfig).mockReturnValue(createConfig(config_1)); + + manager.setConfig(config_1); + expect(api.getInitializationManager().uninitialize).not.toBeCalled(); + + const config_2 = { + ...config_1, + view: { + default_reset: { + every_seconds: 2, + }, + }, + }; + vi.mocked(getOverriddenConfig).mockReturnValue(createConfig(config_2)); + manager.computeOverrideConfig(); + + expect(api.getInitializationManager().uninitialize).toBeCalledWith( + InitializationAspect.DEFAULT_RESET, + ); + }); }); }); diff --git a/tests/card-controller/controller.test.ts b/tests/card-controller/controller.test.ts index ca4f6d7b..f2ae1f97 100644 --- a/tests/card-controller/controller.test.ts +++ b/tests/card-controller/controller.test.ts @@ -1,7 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { CameraManager } from '../../src/camera-manager/manager'; import { ActionsManager } from '../../src/card-controller/actions/actions-manager'; -import { AutoUpdateManager } from '../../src/card-controller/auto-update-manager'; import { AutomationsManager } from '../../src/card-controller/automations-manager'; import { CameraURLManager } from '../../src/card-controller/camera-url-manager'; import { @@ -11,6 +10,7 @@ import { import { ConditionsManager } from '../../src/card-controller/conditions-manager'; import { ConfigManager } from '../../src/card-controller/config/config-manager'; import { CardController } from '../../src/card-controller/controller'; +import { DefaultManager } from '../../src/card-controller/default-manager'; import { DownloadManager } from '../../src/card-controller/download-manager'; import { ExpandManager } from '../../src/card-controller/expand-manager'; import { FullscreenManager } from '../../src/card-controller/fullscreen-manager'; @@ -32,12 +32,12 @@ import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media'; vi.mock('../../src/camera-manager/manager'); vi.mock('../../src/card-controller/actions/actions-manager'); -vi.mock('../../src/card-controller/auto-update-manager'); vi.mock('../../src/card-controller/automations-manager'); vi.mock('../../src/card-controller/camera-url-manager'); vi.mock('../../src/card-controller/card-element-manager'); vi.mock('../../src/card-controller/conditions-manager'); vi.mock('../../src/card-controller/config/config-manager'); +vi.mock('../../src/card-controller/default-manager'); vi.mock('../../src/card-controller/download-manager'); vi.mock('../../src/card-controller/expand-manager'); vi.mock('../../src/card-controller/fullscreen-manager'); @@ -107,9 +107,9 @@ describe('CardController', () => { ); }); - it('getAutoUpdateManager', () => { - expect(createController().getAutoUpdateManager()).toBe( - vi.mocked(AutoUpdateManager).mock.instances[0], + it('getDefaultManager', () => { + expect(createController().getDefaultManager()).toBe( + vi.mocked(DefaultManager).mock.instances[0], ); }); diff --git a/tests/card-controller/default-manager.test.ts b/tests/card-controller/default-manager.test.ts new file mode 100644 index 00000000..fedb496e --- /dev/null +++ b/tests/card-controller/default-manager.test.ts @@ -0,0 +1,163 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { DefaultManager } from '../../src/card-controller/default-manager'; +import { + callHASubscribeMessageHandler, + createCardAPI, + createConfig, + createHASS, +} from '../test-utils'; + +// @vitest-environment jsdom +describe('DefaultManager', () => { + afterEach(() => { + vi.useRealTimers(); + }); + + describe('time based', () => { + it('should set default view when allowed', async () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + default_reset: { + every_seconds: 10, + }, + }, + }), + ); + vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(true); + + vi.useFakeTimers(); + + const manager = new DefaultManager(api); + await manager.initialize(); + + expect(api.getViewManager().setViewDefault).not.toBeCalled(); + + vi.runOnlyPendingTimers(); + + expect(api.getViewManager().setViewDefault).not.toBeCalled(); + + vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(false); + vi.runOnlyPendingTimers(); + + expect(api.getViewManager().setViewDefault).toBeCalledTimes(1); + + manager.uninitialize(); + vi.runOnlyPendingTimers(); + + expect(api.getViewManager().setViewDefault).toBeCalledTimes(1); + }); + + it('should not set default view when not configured', () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + default_reset: { + every_seconds: 0, + }, + }, + }), + ); + vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(false); + + vi.useFakeTimers(); + + const manager = new DefaultManager(api); + manager.initialize(); + + expect(api.getViewManager().setViewDefault).not.toBeCalled(); + + vi.runOnlyPendingTimers(); + + expect(api.getViewManager().setViewDefault).not.toBeCalled(); + }); + + it('should restart timer when reconfigured', async () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + default_reset: { + every_seconds: 10, + }, + }, + }), + ); + vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(false); + + const hass = createHASS(); + const unsubcribeCallback = vi.fn(); + vi.mocked(hass.connection.subscribeMessage).mockResolvedValue(unsubcribeCallback); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + vi.useFakeTimers(); + + const manager = new DefaultManager(api); + + await manager.initialize(); + expect(api.getViewManager().setViewDefault).not.toBeCalled(); + + vi.runOnlyPendingTimers(); + + expect(api.getViewManager().setViewDefault).toBeCalled(); + }); + }); + + describe('state based', () => { + it('should set default view when state changed', async () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + default_reset: { + every_seconds: 10, + }, + }, + }), + ); + vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(false); + + const hass = createHASS(); + const unsubcribeCallback = vi.fn(); + vi.mocked(hass.connection.subscribeMessage).mockResolvedValue(unsubcribeCallback); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const manager = new DefaultManager(api); + await manager.initialize(); + + callHASubscribeMessageHandler(hass, { + variables: { + trigger: { + from_state: { + entity_id: 'binary_sensor.foo', + state: 'off', + }, + to_state: { + entity_id: 'binary_sensor.foo', + state: 'on', + }, + }, + }, + }); + + await manager.initialize(); + expect(unsubcribeCallback).toBeCalledTimes(1); + + expect(api.getViewManager().setViewDefault).toBeCalledTimes(1); + }); + + it('should not monitor state without config', async () => { + const api = createCardAPI(); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); + + const manager = new DefaultManager(api); + await manager.initialize(); + + const mock = vi.mocked(hass.connection.subscribeMessage).mock; + expect(mock.calls.length).toBe(0); + }); + }); +}); diff --git a/tests/card-controller/hass-manager.test.ts b/tests/card-controller/hass-manager.test.ts index 3d0a1fa3..6bf3bf5a 100644 --- a/tests/card-controller/hass-manager.test.ts +++ b/tests/card-controller/hass-manager.test.ts @@ -146,7 +146,7 @@ describe('HASSManager', () => { }); }); - describe('should set default view when', () => { + describe('should not set default view when', () => { it('selected camera is unknown', () => { const api = createAPIWithoutMediaPlayers(); vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); @@ -178,15 +178,18 @@ describe('HASSManager', () => { expect(api.getViewManager().setViewDefault).not.toBeCalled(); }); - it('view.update_entities changes', () => { + it('when there is card interaction', () => { const api = createAPIWithoutMediaPlayers(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { - update_entities: ['sensor.force_default_view'], + default_reset: { + entities: ['sensor.force_default_view'], + }, }, }), ); + vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(true); const manager = new HASSManager(api); const hass = createHASS({ @@ -195,7 +198,7 @@ describe('HASSManager', () => { manager.setHASS(hass); - expect(api.getViewManager().setViewDefault).toBeCalled(); + expect(api.getViewManager().setViewDefault).not.toBeCalled(); }); }); @@ -236,25 +239,4 @@ describe('HASSManager', () => { expect(api.getCardElementManager().update).toBeCalled(); }); }); - - it('set view default is not called when there is card interaction', () => { - const api = createAPIWithoutMediaPlayers(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - view: { - update_entities: ['sensor.force_default_view'], - }, - }), - ); - vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(true); - - const manager = new HASSManager(api); - const hass = createHASS({ - 'sensor.force_default_view': createStateEntity(), - }); - - manager.setHASS(hass); - - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - }); }); diff --git a/tests/card-controller/initialization-manager.test.ts b/tests/card-controller/initialization-manager.test.ts index 6ba18553..fb8ba160 100644 --- a/tests/card-controller/initialization-manager.test.ts +++ b/tests/card-controller/initialization-manager.test.ts @@ -208,9 +208,13 @@ describe('InitializationManager', () => { expect(await manager.initializeBackgroundIfNecessary()).toBeFalsy(); }); - it('successfully with minimal initializers', async () => { + it('successfully when already initialized', async () => { const api = createCardAPI(); - const manager = new InitializationManager(api); + + const initializer = mock(); + initializer.isInitializedMultiple.mockReturnValue(true); + + const manager = new InitializationManager(api, initializer); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ @@ -226,6 +230,8 @@ describe('InitializationManager', () => { expect(await manager.initializeBackgroundIfNecessary()).toBeTruthy(); expect(api.getMediaPlayerManager().initialize).not.toBeCalled(); + expect(api.getDefaultManager().initialize).not.toBeCalled(); + expect(api.getCardElementManager().update).not.toBeCalled(); }); it('successfully with all inititalizers', async () => { @@ -246,10 +252,11 @@ describe('InitializationManager', () => { expect(await manager.initializeBackgroundIfNecessary()).toBeTruthy(); expect(api.getMediaPlayerManager().initialize).toBeCalled(); + expect(api.getDefaultManager().initialize).toBeCalled(); expect(api.getCardElementManager().update).toBeCalled(); }); - it('with media player in progress', async () => { + it('with initializers in progress', async () => { const api = createCardAPI(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( diff --git a/tests/card-controller/interaction-manager.test.ts b/tests/card-controller/interaction-manager.test.ts index 8c17ae03..b0e2546a 100644 --- a/tests/card-controller/interaction-manager.test.ts +++ b/tests/card-controller/interaction-manager.test.ts @@ -23,12 +23,15 @@ describe('InteractionManager', () => { expect(api.getConditionsManager().setState).toBeCalledWith({ interaction: false }); }); - it('should take action when interaction is reported', () => { + it('should take action after interaction ends', () => { const api = createCardAPI(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { interaction_seconds: 10, + default_reset: { + after_interaction: true, + }, }, }), ); @@ -90,12 +93,14 @@ describe('InteractionManager', () => { expect(api.getViewManager().setViewDefault).not.toBeCalled(); }); - it('should not take action without reset_after_interaction', () => { + it('should not take action without default_reset.after_interaction', () => { const api = createCardAPI(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { - reset_after_interaction: false, + default_reset: { + after_interaction: false, + }, interaction_seconds: 10, }, }), diff --git a/tests/card-controller/view-manager.test.ts b/tests/card-controller/view-manager.test.ts index c0bed650..ae911bb4 100644 --- a/tests/card-controller/view-manager.test.ts +++ b/tests/card-controller/view-manager.test.ts @@ -129,7 +129,6 @@ describe('ViewManager.setViewDefault', () => { expect(manager.getView()?.view).toBe('live'); expect(manager.getView()?.camera).toBe('camera'); - expect(api.getAutoUpdateManager().startDefaultViewTimer).toBeCalled(); }); it('should not set default view without config', () => { @@ -140,7 +139,6 @@ describe('ViewManager.setViewDefault', () => { manager.setViewDefault(); expect(manager.getView()).toBeNull(); - expect(api.getAutoUpdateManager().startDefaultViewTimer).not.toBeCalled(); }); it('should cycle camera when configured', () => { @@ -161,7 +159,7 @@ describe('ViewManager.setViewDefault', () => { vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { - update_cycle_camera: true, + default_cycle_camera: true, }, }), ); diff --git a/tests/config/management.test.ts b/tests/config/management.test.ts index bd9cfbcb..1ba51ed9 100644 --- a/tests/config/management.test.ts +++ b/tests/config/management.test.ts @@ -25,6 +25,7 @@ import { frigateCardConfigSchema, } from '../../src/config/types'; import { getParseErrorPaths } from '../../src/utils/zod'; +import { update } from 'lodash-es'; describe('general functions', () => { it('should set value', () => { @@ -134,6 +135,7 @@ describe('upgrade functions', () => { }); }); it('with non-number', () => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars expect(createRangedTransform((_val) => 'foo')(1)).toBe('foo'); }); }); @@ -220,6 +222,7 @@ describe('upgrade functions', () => { c: 10, }; expect( + // eslint-disable-next-line @typescript-eslint/no-unused-vars moveConfigValue(config, 'c', 'd', { transform: (_val) => null }), ).toBeTruthy(); expect(config).toEqual({}); @@ -231,6 +234,7 @@ describe('upgrade functions', () => { }; expect( moveConfigValue(config, 'c', 'd', { + // eslint-disable-next-line @typescript-eslint/no-unused-vars transform: (_val) => null, keepOriginal: true, }), @@ -244,6 +248,7 @@ describe('upgrade functions', () => { c: 10, }; expect( + // eslint-disable-next-line @typescript-eslint/no-unused-vars moveConfigValue(config, 'c', 'd', { transform: (_val) => undefined }), ).toBeFalsy(); expect(config).toEqual({ c: 10 }); @@ -294,11 +299,13 @@ describe('upgrade functions', () => { describe('should upgrade array', () => { it('in case of non-array', () => { const config = { c: 10 }; + // eslint-disable-next-line @typescript-eslint/no-unused-vars expect(upgradeArrayOfObjects('c', (_val) => false)(config)).toBeFalsy(); }); it('in case of non-object items', () => { const config = { c: [10, 11] }; + // eslint-disable-next-line @typescript-eslint/no-unused-vars expect(upgradeArrayOfObjects('c', (_val) => false)(config)).toBeFalsy(); }); @@ -328,6 +335,7 @@ describe('upgrade functions', () => { describe('should recursively upgrade', () => { it('ignoring simple objects', () => { const config = { c: 10, d: 10 }; + // eslint-disable-next-line @typescript-eslint/no-unused-vars expect(upgradeObjectRecursively((_val) => false)(config)).toBeFalsy(); expect(config).toEqual({ c: 10, d: 10 }); }); @@ -3099,5 +3107,91 @@ describe('should handle version specific upgrades', () => { postUpgradeChecks(config); }); }); + + it('view.update_cycle_camera -> view.default_cycle_camera', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + view: { + update_cycle_camera: true, + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config.view).toEqual({ + default_cycle_camera: true, + }); + postUpgradeChecks(config); + }); + + describe('view.update_force -> view.default_reset.interaction_mode', () => { + it('should convert to all when true', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + view: { + update_force: true, + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config.view).toEqual({ + default_reset: { + interaction_mode: 'all', + }, + }); + postUpgradeChecks(config); + }); + + it('should remove when false', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + view: { + update_force: false, + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config.view).toEqual({}); + postUpgradeChecks(config); + }); + }); + + it('view.update_seconds', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + view: { + update_seconds: 42, + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config.view).toEqual({ + default_reset: { + every_seconds: 42, + }, + }); + postUpgradeChecks(config); + }); + + it('view.update_entities', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + view: { + update_entities: ['binary_sensor.foo', 'camera.bar'], + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config.view).toEqual({ + default_reset: { + entities: ['binary_sensor.foo', 'camera.bar'], + }, + }); + postUpgradeChecks(config); + }); }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 62ee482e..5b926078 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -331,10 +331,13 @@ describe('config defaults', () => { filter_selected_camera: true, }, interaction_seconds: 300, - reset_after_interaction: true, - update_cycle_camera: false, - update_force: false, - update_seconds: 0, + default_cycle_camera: false, + default_reset: { + after_interaction: false, + every_seconds: 0, + entities: [], + interaction_mode: 'inactive', + }, }, }); }); diff --git a/tests/test-utils.ts b/tests/test-utils.ts index 6b97f48e..2e5defb3 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -15,7 +15,7 @@ import { CameraManagerMediaCapabilities, } from '../src/camera-manager/types'; import { ActionsManager } from '../src/card-controller/actions/actions-manager'; -import { AutoUpdateManager } from '../src/card-controller/auto-update-manager'; +import { DefaultManager } from '../src/card-controller/default-manager'; import { AutomationsManager } from '../src/card-controller/automations-manager'; import { CameraURLManager } from '../src/card-controller/camera-url-manager'; import { CardElementManager } from '../src/card-controller/card-element-manager'; @@ -434,7 +434,7 @@ export const createCardAPI = (): CardController => { api.getActionsManager.mockReturnValue(mock()); api.getAutomationsManager.mockReturnValue(mock()); - api.getAutoUpdateManager.mockReturnValue(mock()); + api.getDefaultManager.mockReturnValue(mock()); api.getCameraManager.mockReturnValue(mock()); api.getCameraURLManager.mockReturnValue(mock()); api.getCardElementManager.mockReturnValue(mock()); diff --git a/tests/utils/interaction-mode.test.ts b/tests/utils/interaction-mode.test.ts new file mode 100644 index 00000000..41e68b9e --- /dev/null +++ b/tests/utils/interaction-mode.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, it } from 'vitest'; +import { isActionAllowedBasedOnInteractionState } from '../../src/utils/interaction-mode'; + +describe('isActionAllowedBasedOnInteractionState', () => { + it('should handle interactionMode: all', () => { + expect(isActionAllowedBasedOnInteractionState('all', true)).toBeTruthy(); + expect(isActionAllowedBasedOnInteractionState('all', false)).toBeTruthy(); + }); + + it('should handle interactionMode: active', () => { + expect(isActionAllowedBasedOnInteractionState('active', true)).toBeTruthy(); + expect(isActionAllowedBasedOnInteractionState('active', false)).toBeFalsy(); + }); + + it('should handle interactionMode: inactive', () => { + expect(isActionAllowedBasedOnInteractionState('inactive', true)).toBeFalsy(); + expect(isActionAllowedBasedOnInteractionState('inactive', false)).toBeTruthy(); + }); +}); diff --git a/vite.config.ts b/vite.config.ts index 74dd7e43..a35a2154 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -34,6 +34,7 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'utils/endpoint.ts', 'utils/ha/entity-registry/types.ts', 'utils/ha/types.ts', + 'utils/interaction-mode.ts', 'utils/media-info.ts', 'utils/media-layout.ts', 'utils/media-to-view.ts', From 8c7c2c8c18cb1b2937f5d2f3bb7958abe5c37e04 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 11 Jun 2024 19:48:10 -0700 Subject: [PATCH 152/189] Use an automation to change view to default. --- src/card-controller/card-element-manager.ts | 18 ++-- src/card-controller/default-manager.ts | 18 ++++ src/card-controller/interaction-manager.ts | 11 +-- src/card-controller/types.ts | 1 + src/utils/action.ts | 2 +- tests/card-controller/default-manager.test.ts | 64 ++++++++++++++ .../interaction-manager.test.ts | 84 +------------------ 7 files changed, 101 insertions(+), 97 deletions(-) diff --git a/src/card-controller/card-element-manager.ts b/src/card-controller/card-element-manager.ts index 14aa2c48..f8587919 100644 --- a/src/card-controller/card-element-manager.ts +++ b/src/card-controller/card-element-manager.ts @@ -79,6 +79,10 @@ export class CardElementManager { 'mousemove', this._api.getInteractionManager().reportInteraction, ); + this._element.addEventListener( + 'wheel', + this._api.getInteractionManager().reportInteraction, + ); this._element.addEventListener( 'll-custom', this._api.getActionsManager().handleCustomActionEvent, @@ -129,11 +133,15 @@ export class CardElementManager { // Uninitialize cameras to cause them to reinitialize on // reconnection, to ensure the state subscription/unsubscription works // correctly for triggers. - this._api.getInitializationManager().uninitialize(InitializationAspect.CAMERAS), - this._element.removeEventListener( - 'mousemove', - this._api.getInteractionManager().reportInteraction, - ); + this._api.getInitializationManager().uninitialize(InitializationAspect.CAMERAS); + this._element.removeEventListener( + 'mousemove', + this._api.getInteractionManager().reportInteraction, + ); + this._element.removeEventListener( + 'wheel', + this._api.getInteractionManager().reportInteraction, + ); this._element.removeEventListener( 'll-custom', this._api.getActionsManager().handleCustomActionEvent, diff --git a/src/card-controller/default-manager.ts b/src/card-controller/default-manager.ts index 6d782b0e..88d10027 100644 --- a/src/card-controller/default-manager.ts +++ b/src/card-controller/default-manager.ts @@ -3,6 +3,7 @@ import { DestroyCallback, subscribeToTrigger } from '../utils/ha'; import { isActionAllowedBasedOnInteractionState } from '../utils/interaction-mode'; import { Timer } from '../utils/timer'; import { CardDefaultManagerAPI } from './types'; +import { createGeneralAction } from '../utils/action'; /** * Manages automated resetting to the default view. @@ -25,6 +26,22 @@ export class DefaultManager { public async initialize(): Promise { const result = await this._initializationLimit.add(() => this._reconfigure()); this._startTimer(); + + if (this._api.getConfigManager().getConfig()?.view.default_reset.after_interaction) { + this._api.getAutomationsManager().addAutomations([ + { + actions: [createGeneralAction('default')], + conditions: [ + { + condition: 'interaction' as const, + interaction: false, + }, + ], + tag: this, + }, + ]); + } + return !!result; } @@ -32,6 +49,7 @@ export class DefaultManager { this._timer.stop(); this._unsubscribeCallback?.(); this._unsubscribeCallback = null; + this._api.getAutomationsManager().deleteAutomations(this); } protected async _reconfigure(): Promise { diff --git a/src/card-controller/interaction-manager.ts b/src/card-controller/interaction-manager.ts index 350a6fcb..287fe4ca 100644 --- a/src/card-controller/interaction-manager.ts +++ b/src/card-controller/interaction-manager.ts @@ -39,16 +39,7 @@ export class InteractionManager { this._timer.start(timeoutSeconds, () => { this._api.getConditionsManager().setState({ interaction: false }); - - if (!this._api.getTriggersManager().isTriggered()) { - if ( - this._api.getConfigManager().getConfig()?.view.default_reset - .after_interaction - ) { - this._api.getViewManager().setViewDefault(); - } - this._api.getStyleManager().setLightOrDarkMode(); - } + this._api.getStyleManager().setLightOrDarkMode(); }); } } diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index a77d89af..f5c627c6 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -99,6 +99,7 @@ export interface CardConfigLoaderAPI { } export interface CardDefaultManagerAPI { + getAutomationsManager(): AutomationsManager; getConfigManager(): ConfigManager; getHASSManager(): HASSManager; getInteractionManager(): InteractionManager; diff --git a/src/utils/action.ts b/src/utils/action.ts index b3ec8805..d26af9be 100644 --- a/src/utils/action.ts +++ b/src/utils/action.ts @@ -39,7 +39,7 @@ export function createGeneralAction( options?: { cardID?: string; }, -): FrigateCardCustomAction | null { +): FrigateCardCustomAction { return { action: 'fire-dom-event', frigate_card_action: action, diff --git a/tests/card-controller/default-manager.test.ts b/tests/card-controller/default-manager.test.ts index fedb496e..5f3be314 100644 --- a/tests/card-controller/default-manager.test.ts +++ b/tests/card-controller/default-manager.test.ts @@ -160,4 +160,68 @@ describe('DefaultManager', () => { expect(mock.calls.length).toBe(0); }); }); + + describe('interaction based', () => { + it('should not register automation on initialization', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + default_reset: { + after_interaction: false, + }, + }, + }), + ); + + const manager = new DefaultManager(api); + await manager.initialize(); + + expect(api.getAutomationsManager().addAutomations).not.toBeCalled(); + }); + + it('should register automation on initialization', async () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + default_reset: { + after_interaction: true, + }, + }, + }), + ); + + const manager = new DefaultManager(api); + await manager.initialize(); + + expect(api.getAutomationsManager().addAutomations).toBeCalledWith([ + { + actions: [ + { + action: 'fire-dom-event', + frigate_card_action: 'default', + }, + ], + conditions: [ + { + condition: 'interaction', + interaction: false, + }, + ], + tag: expect.anything(), + }, + ]); + }); + + it('should remove automation on uninitalize', async () => { + const api = createCardAPI(); + const manager = new DefaultManager(api); + await manager.uninitialize(); + + expect(api.getAutomationsManager().deleteAutomations).toBeCalledWith(manager); + }); + }); }); diff --git a/tests/card-controller/interaction-manager.test.ts b/tests/card-controller/interaction-manager.test.ts index b0e2546a..d0426f0d 100644 --- a/tests/card-controller/interaction-manager.test.ts +++ b/tests/card-controller/interaction-manager.test.ts @@ -23,58 +23,6 @@ describe('InteractionManager', () => { expect(api.getConditionsManager().setState).toBeCalledWith({ interaction: false }); }); - it('should take action after interaction ends', () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - view: { - interaction_seconds: 10, - default_reset: { - after_interaction: true, - }, - }, - }), - ); - const manager = new InteractionManager(api); - vi.useFakeTimers(); - vi.setSystemTime(start); - - manager.reportInteraction(); - - expect(manager.hasInteraction()).toBeTruthy(); - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - - vi.mocked(api.getTriggersManager().isTriggered).mockReturnValue(false); - vi.setSystemTime(add(start, { seconds: 10 })); - vi.runOnlyPendingTimers(); - - expect(api.getViewManager().setViewDefault).toBeCalled(); - }); - - it('should not take action when triggered', () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - view: { - interaction_seconds: 10, - }, - }), - ); - const manager = new InteractionManager(api); - vi.useFakeTimers(); - vi.setSystemTime(start); - - manager.reportInteraction(); - - vi.mocked(api.getTriggersManager().isTriggered).mockReturnValue(true); - vi.setSystemTime(add(start, { seconds: 10 })); - vi.runOnlyPendingTimers(); - - // First call is blocked by triggers (above), so interaction will report - // true but the default view will not have been set. - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - }); - it('should not take action without an interaction timeout', () => { const api = createCardAPI(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( @@ -88,35 +36,7 @@ describe('InteractionManager', () => { manager.reportInteraction(); - // First call is blocked by triggers (above), so interaction will report - // true but the default view will not have been set. - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - }); - - it('should not take action without default_reset.after_interaction', () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - view: { - default_reset: { - after_interaction: false, - }, - interaction_seconds: 10, - }, - }), - ); - const manager = new InteractionManager(api); - vi.useFakeTimers(); - vi.setSystemTime(start); - - manager.reportInteraction(); - - vi.setSystemTime(add(start, { seconds: 10 })); - vi.runOnlyPendingTimers(); - - // First call is blocked by triggers (above), so interaction will report - // true but the default view will not have been set. - expect(api.getViewManager().setViewDefault).not.toBeCalled(); + expect(manager.hasInteraction()).toBeFalsy(); }); it('should set condition state', () => { @@ -140,6 +60,7 @@ describe('InteractionManager', () => { interaction: true, }), ); + expect(manager.hasInteraction()).toBeTruthy(); vi.setSystemTime(add(start, { seconds: 10 })); vi.runOnlyPendingTimers(); @@ -149,5 +70,6 @@ describe('InteractionManager', () => { interaction: false, }), ); + expect(manager.hasInteraction()).toBeFalsy(); }); }); From 33dee472050052d2291a943a1122b72ef691b52f Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Fri, 14 Jun 2024 19:21:55 -0700 Subject: [PATCH 153/189] Tiny fixes. --- .prettierignore | 1 + src/card-controller/triggers-manager.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.prettierignore b/.prettierignore index b51ecd95..1eeeaddd 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1 +1,2 @@ docs/js/ +.devcontainer/ diff --git a/src/card-controller/triggers-manager.ts b/src/card-controller/triggers-manager.ts index 67d54eab..6e3e41ae 100644 --- a/src/card-controller/triggers-manager.ts +++ b/src/card-controller/triggers-manager.ts @@ -107,7 +107,7 @@ export class TriggersManager { /* istanbul ignore else: the else path cannot be reached, as the camera cannot be triggered without a view -- @preserve */ if (view) { - this._api.getViewManager().setView(view.clone()); + this._api.getViewManager().setView(view); } } else if (triggerAction === 'live') { this._api.getViewManager().setViewByParameters({ From d5c4e56c45b1baf5be60283521ce2da5681148ec Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Fri, 26 Jul 2024 19:15:38 -0700 Subject: [PATCH 154/189] Refactor views to support dynamic updates. --- project.inlang/.gitignore | 1 + rollup.config.js | 1 + .../actions/actions/camera-select.ts | 8 +- .../actions/actions/display-mode-select.ts | 6 +- .../actions/actions/substream-off.ts | 5 +- .../actions/actions/substream-on.ts | 5 +- .../actions/actions/substream-select.ts | 5 +- src/card-controller/actions/actions/view.ts | 11 +- src/card-controller/controller.ts | 2 +- src/card-controller/initialization-manager.ts | 4 +- src/card-controller/query-string-manager.ts | 36 +- src/card-controller/triggers-manager.ts | 52 +- src/card-controller/types.ts | 2 +- src/card-controller/view-manager.ts | 323 ----- src/card-controller/view/factory.ts | 373 ++++++ .../view/modifiers/merge-context.ts | 15 + .../view/modifiers/remove-context-property.ts | 17 + .../view/modifiers/remove-context.ts | 15 + .../view/modifiers/substream-off.ts | 10 + .../view/modifiers/substream-on.ts | 35 + .../view/modifiers/substream-select.ts | 15 + src/card-controller/view/query-executor.ts | 131 +++ src/card-controller/view/types.ts | 80 ++ src/card-controller/view/view-manager.ts | 164 +++ src/card.ts | 8 +- src/components-lib/live/live-controller.ts | 94 +- src/components-lib/media-filter-controller.ts | 72 +- src/components-lib/menu-button-controller.ts | 2 +- src/components-lib/zoom/zoom-view-context.ts | 28 +- src/components/gallery.ts | 100 +- src/components/live/live.ts | 150 +-- src/components/media-filter.ts | 46 +- src/components/select.ts | 13 +- src/components/surround.ts | 60 +- src/components/thumbnail-carousel.ts | 26 +- src/components/thumbnail.ts | 45 +- src/components/timeline-core.ts | 271 +++-- src/components/timeline.ts | 6 +- src/components/title-control.ts | 2 +- src/components/viewer.ts | 287 ++--- src/components/views.ts | 63 +- src/config/types.ts | 4 - src/const.ts | 1 - src/editor.ts | 2 - src/utils/find-best-media-index.ts | 48 + src/utils/media-to-view.ts | 282 ----- src/utils/substream.ts | 15 + src/view/view.ts | 158 +-- .../actions/actions/camera-select.test.ts | 36 +- .../actions/display-mode-select.test.ts | 6 +- .../actions/actions/substream-off.test.ts | 5 +- .../actions/actions/substream-on.test.ts | 5 +- .../actions/actions/substream-select.test.ts | 7 +- .../actions/actions/view.test.ts | 6 +- tests/card-controller/controller.test.ts | 4 +- .../initialization-manager.test.ts | 2 +- .../query-string-manager.test.ts | 42 +- .../card-controller/triggers-manager.test.ts | 107 +- tests/card-controller/view-manager.test.ts | 1035 ----------------- tests/card-controller/view/factory.test.ts | 751 ++++++++++++ .../view/modifiers/merge-context.test.ts | 28 + .../modifiers/remove-context-property.test.ts | 25 + .../view/modifiers/remove-context.test.ts | 26 + .../view/modifiers/substream-off.test.ts | 20 + .../view/modifiers/substream-on.test.ts | 101 ++ .../view/modifiers/substream-select.test.ts | 19 + .../view/query-executor.test.ts | 360 ++++++ tests/card-controller/view/test-utils.ts | 41 + .../card-controller/view/view-manager.test.ts | 363 ++++++ .../live/live-controller.test.ts | 219 +--- .../media-filter-controller.test.ts | 222 ++-- .../menu-button-controller.test.ts | 2 +- .../zoom/zoom-view-context.test.ts | 32 +- tests/test-utils.ts | 24 +- tests/utils/media-to-view.test.ts | 600 ---------- tests/utils/substream.test.ts | 44 +- tests/view/view-to-cameras.test.ts | 3 + tests/view/view.test.ts | 365 +----- vite.config.ts | 1 - yarn.lock | 135 ++- 80 files changed, 3714 insertions(+), 4021 deletions(-) create mode 100644 project.inlang/.gitignore delete mode 100644 src/card-controller/view-manager.ts create mode 100644 src/card-controller/view/factory.ts create mode 100644 src/card-controller/view/modifiers/merge-context.ts create mode 100644 src/card-controller/view/modifiers/remove-context-property.ts create mode 100644 src/card-controller/view/modifiers/remove-context.ts create mode 100644 src/card-controller/view/modifiers/substream-off.ts create mode 100644 src/card-controller/view/modifiers/substream-on.ts create mode 100644 src/card-controller/view/modifiers/substream-select.ts create mode 100644 src/card-controller/view/query-executor.ts create mode 100644 src/card-controller/view/types.ts create mode 100644 src/card-controller/view/view-manager.ts create mode 100644 src/utils/find-best-media-index.ts delete mode 100644 src/utils/media-to-view.ts delete mode 100644 tests/card-controller/view-manager.test.ts create mode 100644 tests/card-controller/view/factory.test.ts create mode 100644 tests/card-controller/view/modifiers/merge-context.test.ts create mode 100644 tests/card-controller/view/modifiers/remove-context-property.test.ts create mode 100644 tests/card-controller/view/modifiers/remove-context.test.ts create mode 100644 tests/card-controller/view/modifiers/substream-off.test.ts create mode 100644 tests/card-controller/view/modifiers/substream-on.test.ts create mode 100644 tests/card-controller/view/modifiers/substream-select.test.ts create mode 100644 tests/card-controller/view/query-executor.test.ts create mode 100644 tests/card-controller/view/test-utils.ts create mode 100644 tests/card-controller/view/view-manager.test.ts delete mode 100644 tests/utils/media-to-view.test.ts diff --git a/project.inlang/.gitignore b/project.inlang/.gitignore new file mode 100644 index 00000000..5e465967 --- /dev/null +++ b/project.inlang/.gitignore @@ -0,0 +1 @@ +cache \ No newline at end of file diff --git a/rollup.config.js b/rollup.config.js index 5d40a750..33ca36e7 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -51,6 +51,7 @@ const plugins = [ typescript({ sourceMap: dev, inlineSources: dev, + exclude: ["tests/**/*.test.ts"], }), json({ exclude: 'package.json' }), replace({ diff --git a/src/card-controller/actions/actions/camera-select.ts b/src/card-controller/actions/actions/camera-select.ts index c5f82ce2..395b47d3 100644 --- a/src/card-controller/actions/actions/camera-select.ts +++ b/src/card-controller/actions/actions/camera-select.ts @@ -16,9 +16,11 @@ export class CameraSelectAction extends FrigateCardAction { public async execute(api: CardActionsAPI): Promise { - await api.getViewManager().setViewWithNewDisplayMode(this._action.display_mode); + await api.getViewManager().setViewByParametersWithNewQuery({ + params: { + displayMode: this._action.display_mode, + }, + }); } } diff --git a/src/card-controller/actions/actions/substream-off.ts b/src/card-controller/actions/actions/substream-off.ts index 8503e4a1..0a89b7a6 100644 --- a/src/card-controller/actions/actions/substream-off.ts +++ b/src/card-controller/actions/actions/substream-off.ts @@ -1,9 +1,12 @@ import { GeneralActionConfig } from '../../../config/types'; import { CardActionsAPI } from '../../types'; +import { SubstreamOffViewModifier } from '../../view/modifiers/substream-off'; import { FrigateCardAction } from './base'; export class SubstreamOffAction extends FrigateCardAction { public async execute(api: CardActionsAPI): Promise { - api.getViewManager().setViewWithoutSubstream(); + api.getViewManager().setViewByParameters({ + modifiers: [new SubstreamOffViewModifier()], + }); } } diff --git a/src/card-controller/actions/actions/substream-on.ts b/src/card-controller/actions/actions/substream-on.ts index 0fd13310..78e6976d 100644 --- a/src/card-controller/actions/actions/substream-on.ts +++ b/src/card-controller/actions/actions/substream-on.ts @@ -1,9 +1,12 @@ import { GeneralActionConfig } from '../../../config/types'; import { CardActionsAPI } from '../../types'; +import { SubstreamOnViewModifier } from '../../view/modifiers/substream-on'; import { FrigateCardAction } from './base'; export class SubstreamOnAction extends FrigateCardAction { public async execute(api: CardActionsAPI): Promise { - api.getViewManager().setViewWithSubstream(); + api.getViewManager().setViewByParameters({ + modifiers: [new SubstreamOnViewModifier(api)], + }); } } diff --git a/src/card-controller/actions/actions/substream-select.ts b/src/card-controller/actions/actions/substream-select.ts index 7935ca5d..ec55c5f6 100644 --- a/src/card-controller/actions/actions/substream-select.ts +++ b/src/card-controller/actions/actions/substream-select.ts @@ -1,9 +1,12 @@ import { SubstreamSelectActionConfig } from '../../../config/types'; import { CardActionsAPI } from '../../types'; +import { SubstreamSelectViewModifier } from '../../view/modifiers/substream-select'; import { FrigateCardAction } from './base'; export class SubstreamSelectAction extends FrigateCardAction { public async execute(api: CardActionsAPI): Promise { - api.getViewManager().setViewWithSubstream(this._action.camera); + api.getViewManager().setViewByParameters({ + modifiers: [new SubstreamSelectViewModifier(this._action.camera)], + }); } } diff --git a/src/card-controller/actions/actions/view.ts b/src/card-controller/actions/actions/view.ts index 045b65de..55e03e24 100644 --- a/src/card-controller/actions/actions/view.ts +++ b/src/card-controller/actions/actions/view.ts @@ -4,13 +4,10 @@ import { FrigateCardAction } from './base'; export class ViewAction extends FrigateCardAction { public async execute(api: CardActionsAPI): Promise { - api.getViewManager().setViewByParameters({ - viewName: this._action.frigate_card_action, - - // Note: This function needs to process (view-related) commands even when - // _view has not yet been initialized (since it may be used to set a view - // via the querystring). - cameraID: api.getViewManager().getView()?.camera, + api.getViewManager().setViewByParametersWithNewQuery({ + params: { + view: this._action.frigate_card_action, + }, }); } } diff --git a/src/card-controller/controller.ts b/src/card-controller/controller.ts index 683611cd..758f1f31 100644 --- a/src/card-controller/controller.ts +++ b/src/card-controller/controller.ts @@ -55,7 +55,7 @@ import { CardTriggersAPI, CardViewAPI, } from './types'; -import { ViewManager } from './view-manager'; +import { ViewManager } from './view/view-manager'; import { KeyboardStateManager } from './keyboard-state-manager'; export class CardController diff --git a/src/card-controller/initialization-manager.ts b/src/card-controller/initialization-manager.ts index a8de6c75..7b5a78da 100644 --- a/src/card-controller/initialization-manager.ts +++ b/src/card-controller/initialization-manager.ts @@ -100,10 +100,10 @@ export class InitializationManager { if (hasViewRelatedActions) { this._api.getQueryStringManager().executeViewRelated(); } else { - this._api.getViewManager().setViewDefault({ failSafe: true }); + this._api.getViewManager().setViewDefaultWithNewQuery({ failSafe: true }); } } else { - // If we already have a view something (e.g. cameras) may have been + // If we already have a view, something (e.g. cameras) may have been // reinitialized, be sure to ask for an update. this._api.getCardElementManager().update(); } diff --git a/src/card-controller/query-string-manager.ts b/src/card-controller/query-string-manager.ts index 15d3a1a6..9009bb67 100644 --- a/src/card-controller/query-string-manager.ts +++ b/src/card-controller/query-string-manager.ts @@ -1,11 +1,13 @@ import { FrigateCardCustomAction, ViewActionConfig } from '../config/types'; import { createCameraAction, createGeneralAction } from '../utils/action.js'; +import { ViewParameters } from '../view/view'; import { CardQueryStringAPI } from './types'; -import { ViewManagerSetViewParameters } from './view-manager'; +import { SubstreamSelectViewModifier } from './view/modifiers/substream-select'; interface QueryStringViewIntent { - view?: ViewManagerSetViewParameters & { + view?: Partial & { default?: boolean; + substream?: string; }; other?: FrigateCardCustomAction[]; } @@ -35,18 +37,26 @@ export class QueryStringManager { this._executeNonViewRelated(intent); }; - protected _executeViewRelated(intent: QueryStringViewIntent): void { + protected async _executeViewRelated(intent: QueryStringViewIntent): Promise { if (intent.view) { if (intent.view.default) { - this._api.getViewManager().setViewDefault({ - ...(intent.view.cameraID && { cameraID: intent.view.cameraID }), - ...(intent.view.substream && { substream: intent.view.substream }), + await this._api.getViewManager().setViewDefaultWithNewQuery({ + params: { + camera: intent.view.camera, + }, + ...(intent.view.substream && { + modifiers: [new SubstreamSelectViewModifier(intent.view.substream)], + }), }); } else { - this._api.getViewManager().setViewByParameters({ - ...(intent.view.viewName && { viewName: intent.view.viewName }), - ...(intent.view.cameraID && { cameraID: intent.view.cameraID }), - ...(intent.view.substream && { substream: intent.view.substream }), + await this._api.getViewManager().setViewByParametersWithNewQuery({ + params: { + ...(intent.view.view && { view: intent.view.view }), + ...(intent.view.camera && { camera: intent.view.camera }), + }, + ...(intent.view.substream && { + modifiers: [new SubstreamSelectViewModifier(intent.view.substream)], + }), }); } } @@ -68,13 +78,13 @@ export class QueryStringManager { const result: QueryStringViewIntent = {}; for (const action of this._getActions()) { if (this._isViewAction(action)) { - (result.view ??= {}).viewName = action.frigate_card_action; + (result.view ??= {}).view = action.frigate_card_action; (result.view ??= {}).default = undefined; } else if (action.frigate_card_action === 'default') { (result.view ??= {}).default = true; - (result.view ??= {}).viewName = undefined; + (result.view ??= {}).view = undefined; } else if (action.frigate_card_action === 'camera_select') { - (result.view ??= {}).cameraID = action.camera; + (result.view ??= {}).camera = action.camera; } else if (action.frigate_card_action === 'live_substream_select') { (result.view ??= {}).substream = action.camera; } else { diff --git a/src/card-controller/triggers-manager.ts b/src/card-controller/triggers-manager.ts index 6e3e41ae..bebd92ee 100644 --- a/src/card-controller/triggers-manager.ts +++ b/src/card-controller/triggers-manager.ts @@ -36,7 +36,7 @@ export class TriggersManager { return sorted.length ? sorted[0][0] : null; } - public handleCameraEvent(ev: CameraEvent): void { + public async handleCameraEvent(ev: CameraEvent): Promise { const triggersConfig = this._api.getConfigManager().getConfig()?.view.triggers; const selectedCameraID = this._api.getViewManager().getView()?.camera; @@ -60,7 +60,7 @@ export class TriggersManager { this._triggeredCameras.set(ev.cameraID, new Date()); this._setConditionStateIfNecessary(); - this._throttledTriggerAction(ev); + await this._throttledTriggerAction(ev); } protected _hasAllowableInteractionStateForAction(): boolean { @@ -75,7 +75,7 @@ export class TriggersManager { ); } - protected _triggerAction(ev: CameraEvent): void { + protected async _triggerAction(ev: CameraEvent): Promise { const triggerAction = this._api.getConfigManager().getConfig()?.view.triggers .actions.trigger; const defaultView = this._api.getConfigManager().getConfig()?.view.default; @@ -98,30 +98,30 @@ export class TriggersManager { if (this._hasAllowableInteractionStateForAction()) { if (triggerAction === 'update') { - const view = this._api.getViewManager().getView()?.evolve({ - // Reset the media queries to catch media to be refetched in the - // current view. - query: null, - queryResults: null, - }); - /* istanbul ignore else: the else path cannot be reached, as the camera - cannot be triggered without a view -- @preserve */ - if (view) { - this._api.getViewManager().setView(view); - } + await this._api + .getViewManager() + .setViewByParametersWithNewQuery({ + queryExecutorOptions: { useCache: false }, + }); } else if (triggerAction === 'live') { - this._api.getViewManager().setViewByParameters({ - viewName: 'live', - cameraID: ev.cameraID, + await this._api.getViewManager().setViewByParametersWithNewQuery({ + params: { + view: 'live', + camera: ev.cameraID, + }, }); } else if (triggerAction === 'default') { - this._api.getViewManager().setViewDefault({ - cameraID: ev.cameraID, + await this._api.getViewManager().setViewDefaultWithNewQuery({ + params: { + camera: ev.cameraID, + }, }); } else if (ev.fidelity === 'high' && triggerAction === 'media') { - this._api.getViewManager().setViewByParameters({ - viewName: ev.clip ? 'clip' : 'snapshot', - cameraID: ev.cameraID, + await this._api.getViewManager().setViewByParametersWithNewQuery({ + params: { + view: ev.clip ? 'clip' : 'snapshot', + camera: ev.cameraID, + }, }); } } @@ -143,12 +143,12 @@ export class TriggersManager { } } - protected _untriggerAction(cameraID: string): void { + protected async _untriggerAction(cameraID: string): Promise { const action = this._api.getConfigManager().getConfig()?.view.triggers .actions.untrigger; if (action === 'default' && this._hasAllowableInteractionStateForAction()) { - this._api.getViewManager().setViewDefault(); + await this._api.getViewManager().setViewDefaultWithNewQuery(); } this._triggeredCameras.delete(cameraID); this._deleteTimer(cameraID); @@ -168,8 +168,8 @@ export class TriggersManager { reached, as there's no way to have the untrigger call happen without a config. -- @preserve */ this._api.getConfigManager().getConfig()?.view.triggers.untrigger_seconds ?? 0, - () => { - this._untriggerAction(cameraID); + async () => { + await this._untriggerAction(cameraID); }, ); } diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index f5c627c6..cca66b7a 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -20,7 +20,7 @@ import type { MessageManager } from './message-manager'; import type { MicrophoneManager } from './microphone-manager'; import type { StyleManager } from './style-manager'; import type { TriggersManager } from './triggers-manager'; -import type { ViewManager } from './view-manager'; +import type { ViewManager } from './view/view-manager'; import type { QueryStringManager } from './query-string-manager'; import { KeyboardStateManager } from './keyboard-state-manager'; import { Automation } from '../config/types'; diff --git a/src/card-controller/view-manager.ts b/src/card-controller/view-manager.ts deleted file mode 100644 index 655d7ab3..00000000 --- a/src/card-controller/view-manager.ts +++ /dev/null @@ -1,323 +0,0 @@ -import isEqual from 'lodash-es/isEqual'; -import { ViewContext } from 'view'; -import { - FRIGATE_CARD_VIEW_DEFAULT, - FrigateCardConfig, - FrigateCardView, - ViewDisplayMode, -} from '../config/types'; -import { localize } from '../localize/localize'; -import { log } from '../utils/debug'; -import { executeMediaQueryForView } from '../utils/media-to-view'; -import { View } from '../view/view'; -import { getCameraIDsForViewName } from '../view/view-to-cameras'; -import { CardViewAPI } from './types'; - -interface ViewManagerSetViewDefaultParameters { - cameraID?: string; - substream?: string; - - // When failSafe is true, the view will be changed to the default view, or the - // `live` view if the default view is not supported, or failing that an error - // message is shown. Without `failSafe` the view will just not be changed if - // unsupported. - failSafe?: boolean; -} - -export interface ViewManagerSetViewParameters - extends ViewManagerSetViewDefaultParameters { - viewName?: FrigateCardView; -} - -export class ViewManager { - protected _view: View | null = null; - protected _api: CardViewAPI; - - constructor(api: CardViewAPI) { - this._api = api; - } - - public getView(): View | null { - return this._view; - } - - public hasView(): boolean { - return !!this.getView(); - } - - public setView(view: View): void { - this._setView(view); - } - - public setViewDefault(params?: ViewManagerSetViewDefaultParameters): void { - const config = this._api.getConfigManager().getConfig(); - if (config) { - let forceCameraID: string | null = params?.cameraID ?? null; - const viewName = config.view.default; - - if (!forceCameraID && this._view?.camera && config.view.default_cycle_camera) { - const cameraIDs = [ - ...getCameraIDsForViewName(this._api.getCameraManager(), viewName), - ]; - const currentIndex = cameraIDs.indexOf(this._view.camera); - const targetIndex = currentIndex + 1 >= cameraIDs.length ? 0 : currentIndex + 1; - forceCameraID = cameraIDs[targetIndex]; - } - - this.setViewByParameters({ - ...params, - viewName: viewName, - ...(forceCameraID && { cameraID: forceCameraID }), - }); - } - } - - public setViewByParameters(params: ViewManagerSetViewParameters): void { - const config = this._api.getConfigManager().getConfig(); - - if (config) { - let cameraID: string | null = null; - - let viewName = params?.viewName ?? this._view?.view ?? config.view.default; - const allCameraIDs = this._api.getCameraManager().getStore().getCameraIDs(); - if (params?.cameraID && allCameraIDs.has(params.cameraID)) { - cameraID = params.cameraID; - } else { - const viewCameraIDs = getCameraIDsForViewName( - this._api.getCameraManager(), - viewName, - ); - - // Reset to the default camera. - cameraID = viewCameraIDs.keys().next().value; - } - - if (!cameraID) { - if (params.failSafe) { - const camerasToCapabilities = [ - ...this._api.getCameraManager().getStore().getCameras(), - ].reduce((acc, [cameraID, camera]) => { - const capabilities = camera.getCapabilities()?.getRawCapabilities(); - if (capabilities) { - acc[cameraID] = capabilities; - } - return acc; - }, {}); - - this._api.getMessageManager().setMessageIfHigherPriority({ - type: 'error', - message: localize('error.no_supported_cameras'), - context: { - view: viewName, - cameras_capabilities: camerasToCapabilities, - }, - }); - } - return; - } - - if (!this.isViewSupportedByCamera(cameraID, viewName)) { - if (params.failSafe) { - if (this.isViewSupportedByCamera(cameraID, FRIGATE_CARD_VIEW_DEFAULT)) { - viewName = FRIGATE_CARD_VIEW_DEFAULT; - } else { - const capabilities = this._api - .getCameraManager() - .getStore() - .getCamera(cameraID) - ?.getCapabilities() - ?.getRawCapabilities(); - this._api.getMessageManager().setMessageIfHigherPriority({ - type: 'error', - message: localize('error.no_supported_camera'), - context: { - view: viewName, - camera: cameraID, - ...(capabilities && { camera_capabilities: capabilities }), - }, - }); - return; - } - } else { - return; - } - } - - const displayMode = - this._view?.displayMode ?? this._getDefaultDisplayModeForView(viewName, config); - let view: View = new View({ - view: viewName, - camera: cameraID, - displayMode: displayMode, - }); - if (params.substream) { - view = this._createViewWithSelectedSubstream(view, params.substream); - } - this._setView(view); - } - } - - public setViewWithMergedContext(context: ViewContext | null): void { - if (this._view) { - return this._setView(this._view?.clone().mergeInContext(context)); - } - } - - public reset(): void { - this._view = null; - } - - protected _getCameraIDsInvolvedInView(view: View): Set { - return view.supportsMultipleDisplayModes() && view.isGrid() - ? getCameraIDsForViewName(this._api.getCameraManager(), view.view) - : getCameraIDsForViewName(this._api.getCameraManager(), view.view, view.camera); - } - - public async setViewWithNewDisplayMode(displayMode: ViewDisplayMode): Promise { - const hass = this._api.getHASSManager().getHASS(); - - if (this._view && hass) { - const view = this._view.evolve({ - displayMode: displayMode, - }); - - const expectedCameraIDs = this._getCameraIDsInvolvedInView(view); - const queryCameraIDs = view.query?.getQueryCameraIDs(); - - if (!isEqual(expectedCameraIDs, queryCameraIDs) && view && view.query) { - // If the user requests a grid but the current query does not have a - // query for more than one camera, reset the query results, change the - // existing query to refer to all cameras and execute it to fetch new - // results. - let viewWithNewQuery: View | null = null; - try { - viewWithNewQuery = await executeMediaQueryForView( - this._api.getCameraManager(), - view, - view.query.clone().setQueryCameraIDs(expectedCameraIDs), - ); - } catch (e: unknown) { - this._api.getMessageManager().setErrorIfHigherPriority(e); - } - - if (viewWithNewQuery) { - return this._setView(viewWithNewQuery); - } - } else { - return this._setView(view); - } - } - } - - public setViewWithSubstream(substream?: string): void { - if (!this._view) { - return; - } - this._setView( - substream - ? this._createViewWithSelectedSubstream(this._view, substream) - : this._createViewWithNextStream(this._view), - ); - } - - public setViewWithoutSubstream(): void { - const view = this._createViewWithoutSubstream(); - if (view) { - return this._setView(view); - } - } - - public isViewSupportedByCamera(cameraID: string, view: FrigateCardView): boolean { - return !!getCameraIDsForViewName(this._api.getCameraManager(), view, cameraID).size; - } - - protected _getDefaultDisplayModeForView( - viewName: FrigateCardView, - config?: FrigateCardConfig, - ): ViewDisplayMode { - let mode: ViewDisplayMode | null = null; - switch (viewName) { - case 'media': - case 'clip': - case 'recording': - case 'snapshot': - mode = config?.media_viewer.display?.mode ?? null; - break; - case 'live': - mode = config?.live.display?.mode ?? null; - break; - } - return mode ?? 'single'; - } - - protected _setView(view: View): void { - const oldView = this._view; - View.adoptFromViewIfAppropriate(view, oldView); - - log( - this._api.getConfigManager().getCardWideConfig(), - `Frigate Card view change: `, - view, - ); - this._view = view; - - if (View.isMajorMediaChange(oldView, view)) { - this._api.getMediaLoadedInfoManager().clear(); - } - - if (oldView?.view !== view.view) { - this._api.getCardElementManager().scrollReset(); - } - - this._api.getMessageManager().reset(); - this._api.getStyleManager().setExpandedMode(); - - this._api.getConditionsManager()?.setState({ - view: view.view, - camera: view.camera, - displayMode: view.displayMode ?? undefined, - }); - - this._api.getCardElementManager().update(); - } - - protected _createViewWithSelectedSubstream(baseView: View, substreamID: string): View { - const overrides: Map = - baseView?.context?.live?.overrides ?? new Map(); - overrides.set(baseView.camera, substreamID); - return baseView.clone().mergeInContext({ - live: { overrides: overrides }, - }); - } - - protected _createViewWithNextStream(baseView: View): View { - const dependencies = [ - ...this._api.getCameraManager().getStore().getAllDependentCameras(baseView.camera), - ]; - if (dependencies.length <= 1) { - return baseView.clone(); - } - - const view = baseView.clone(); - const overrides: Map = view.context?.live?.overrides ?? new Map(); - const currentOverride = overrides.get(view.camera) ?? view.camera; - const currentIndex = dependencies.indexOf(currentOverride); - const newIndex = currentIndex < 0 ? 0 : (currentIndex + 1) % dependencies.length; - overrides.set(view.camera, dependencies[newIndex]); - view.mergeInContext({ live: { overrides: overrides } }); - - return view; - } - - protected _createViewWithoutSubstream(): View | null { - if (!this._view) { - return null; - } - const view = this._view.clone(); - const overrides: Map | undefined = view.context?.live?.overrides; - if (overrides && overrides.has(view.camera)) { - view.context?.live?.overrides?.delete(view.camera); - } - return view; - } -} diff --git a/src/card-controller/view/factory.ts b/src/card-controller/view/factory.ts new file mode 100644 index 00000000..9f43d5f3 --- /dev/null +++ b/src/card-controller/view/factory.ts @@ -0,0 +1,373 @@ +import { sub } from 'date-fns'; +import { + FRIGATE_CARD_VIEW_DEFAULT, + FrigateCardConfig, + FrigateCardView, + ViewDisplayMode, +} from '../../config/types'; +import { localize } from '../../localize/localize'; +import { ClipsOrSnapshotsOrAll } from '../../types'; +import { View, ViewParameters } from '../../view/view'; +import { getCameraIDsForViewName } from '../../view/view-to-cameras'; +import { CardViewAPI } from '../types'; +import { QueryExecutor } from './query-executor'; +import { + QueryExecutorOptions, + QueryWithResults, + ViewFactoryOptions, + ViewIncompatible, + ViewNoCameraError, +} from './types'; + +export class ViewFactory { + protected _api: CardViewAPI; + protected _executor: QueryExecutor; + + constructor(api: CardViewAPI, executor?: QueryExecutor) { + this._api = api; + this._executor = executor ?? new QueryExecutor(api); + } + + public getViewDefault(options?: ViewFactoryOptions): View | null { + const config = this._api.getConfigManager().getConfig(); + if (!config) { + return null; + } + + let forceCameraID: string | null = options?.params?.camera ?? null; + const viewName = options?.params?.view ?? config.view.default; + + if ( + !forceCameraID && + options?.baseView?.camera && + config.view.default_cycle_camera + ) { + const cameraIDs = [ + ...getCameraIDsForViewName(this._api.getCameraManager(), viewName), + ]; + const currentIndex = cameraIDs.indexOf(options?.baseView?.camera); + const targetIndex = currentIndex + 1 >= cameraIDs.length ? 0 : currentIndex + 1; + forceCameraID = cameraIDs[targetIndex]; + } + + return this.getViewByParameters({ + params: { + ...options?.params, + view: viewName, + ...(forceCameraID && { camera: forceCameraID }), + }, + baseView: options?.baseView, + }); + } + + public getViewByParameters(options?: ViewFactoryOptions): View | null { + const config = this._api.getConfigManager().getConfig(); + if (!config) { + return null; + } + + let cameraID: string | null = + options?.params?.camera ?? options?.baseView?.camera ?? null; + let viewName = + options?.params?.view ?? options?.baseView?.view ?? config.view.default; + + const allCameraIDs = this._api.getCameraManager().getStore().getCameraIDs(); + + if (!cameraID || !allCameraIDs.has(cameraID)) { + const viewCameraIDs = getCameraIDsForViewName( + this._api.getCameraManager(), + viewName, + ); + + // Reset to the default camera. + cameraID = viewCameraIDs.keys().next().value; + } + + if (!cameraID) { + const camerasToCapabilities = [ + ...this._api.getCameraManager().getStore().getCameras(), + ].reduce((acc, [cameraID, camera]) => { + const capabilities = camera.getCapabilities()?.getRawCapabilities(); + if (capabilities) { + acc[cameraID] = capabilities; + } + return acc; + }, {}); + + throw new ViewNoCameraError(localize('error.no_supported_cameras'), { + view: viewName, + cameras_capabilities: camerasToCapabilities, + }); + } + + if (!this.isViewSupportedByCamera(cameraID, viewName)) { + if ( + options?.failSafe && + this.isViewSupportedByCamera(cameraID, FRIGATE_CARD_VIEW_DEFAULT) + ) { + viewName = FRIGATE_CARD_VIEW_DEFAULT; + } else { + const capabilities = this._api + .getCameraManager() + .getStore() + .getCamera(cameraID) + ?.getCapabilities() + ?.getRawCapabilities(); + + throw new ViewIncompatible(localize('error.no_supported_camera'), { + view: viewName, + camera: cameraID, + ...(capabilities && { camera_capabilities: capabilities }), + }); + } + } + + const displayMode = + options?.params?.displayMode ?? + options?.baseView?.displayMode ?? + this._getDefaultDisplayModeForView(viewName, config); + + const viewParameters: ViewParameters = { + ...options?.params, + view: viewName, + camera: cameraID, + displayMode: displayMode, + }; + + const view = options?.baseView + ? options.baseView.evolve(viewParameters) + : new View(viewParameters); + + if (options?.modifiers) { + options.modifiers.forEach((modifier) => modifier.modify(view)); + } + return view; + } + + public async getViewDefaultWithNewQuery( + options?: ViewFactoryOptions, + ): Promise { + return this._executeNewQuery(this.getViewDefault(options), { + ...options, + queryExecutorOptions: { + useCache: false, + ...options?.queryExecutorOptions, + }, + }); + } + + public async getViewByParametersWithNewQuery( + options?: ViewFactoryOptions, + ): Promise { + return this._executeNewQuery(this.getViewByParameters(options), { + ...options, + queryExecutorOptions: { + useCache: false, + ...options?.queryExecutorOptions, + }, + }); + } + + public async getViewByParametersWithExistingQuery( + options?: ViewFactoryOptions, + ): Promise { + const view = this.getViewByParameters(options); + if (view?.query) { + view.queryResults = await this._executor.execute( + view.query, + options?.queryExecutorOptions, + ); + } + return view; + } + + protected async _executeNewQuery( + view: View | null, + options?: ViewFactoryOptions, + ): Promise { + const config = this._api.getConfigManager().getConfig(); + if ( + !config || + /* istanbul ignore next: this path cannot be reached as the only way for + view to be null here, is if the config is also null -- @preserve */ + !view + ) { + return null; + } + + const executeMediaQuery = async ( + mediaType: ClipsOrSnapshotsOrAll | 'recordings' | null, + ): Promise => { + /* istanbul ignore if: this path cannot be reached -- @preserve */ + if (!mediaType) { + return false; + } + return await this._executeMediaQuery( + view, + mediaType === 'recordings' ? 'recordings' : 'events', + { + eventsMediaType: mediaType === 'recordings' ? undefined : mediaType, + executorOptions: options?.queryExecutorOptions, + }, + ); + }; + + // Implementation note: For new queries, if the query itself fails that is + // just ignored and the view is returned anyway (e.g. if the user changes to + // live but the thumbnail fetch fails, it is better to change to live and + // show no thumbnails than not change to live). + const mediaType = view.getDefaultMediaType(); + const baseView = options?.baseView; + const switchingToGalleryFromViewer = + baseView?.isViewerView() && view.isGalleryView(); + + if (switchingToGalleryFromViewer && baseView?.query && baseView?.queryResults) { + // If the user is currently using the viewer, and then switches to the + // gallery we make an attempt to keep the query/queryResults the same so + // the gallery can be used to click back and forth to the viewer, and the + // selected media can be centered in the gallery. See the matching code in + // `updated()` in `gallery.ts`. We specifically must ensure that the new + // target media of the gallery (e.g. clips, snapshots or recordings) is + // equal to the queries that are currently used in the viewer. + // + // See: https://github.com/dermotduffy/frigate-hass-card/issues/885 + view.query = baseView.query; + view.queryResults = baseView.queryResults; + } else { + switch (view.view) { + case 'live': + this._setTimelineWindowToLive(view); + if (config.live.controls.thumbnails.mode !== 'none') { + await executeMediaQuery( + config.live.controls.thumbnails.media_type === 'recordings' + ? 'recordings' + : config.live.controls.thumbnails.events_media_type, + ); + } + break; + + case 'media': + // If the user is looking at media in the `media` view and then + // changes camera (via the menu) it should default to showing clips + // for the new camera. + if (baseView && view.camera !== baseView.camera) { + await executeMediaQuery('clips'); + } + break; + + // Gallery views: + case 'clips': + case 'snapshots': + case 'recordings': + await executeMediaQuery(mediaType); + break; + + // Viewer views: + case 'clip': + case 'snapshot': + case 'recording': + if (config.media_viewer.controls.thumbnails.mode !== 'none') { + await executeMediaQuery(mediaType); + } + break; + } + } + + this._setOrRemoveSeekTime( + view, + options?.queryExecutorOptions?.selectResult?.time?.time, + ); + return view; + } + + protected _setTimelineWindowToLive(view: View): void { + const now = new Date(); + const liveConfig = this._api.getConfigManager().getConfig()?.live; + + /* istanbul ignore if: this if branch cannot be reached as if the config is + empty this function is never called -- @preserve */ + if (!liveConfig) { + return; + } + + view.mergeInContext({ + // Force the window to start at the most recent time, not + // necessarily when the most recent event/recording was: + // https://github.com/dermotduffy/frigate-hass-card/issues/1301 + timeline: { + window: { + start: sub(now, { + seconds: liveConfig.controls.timeline.window_seconds, + }), + end: now, + }, + }, + }); + } + + protected _setOrRemoveSeekTime(view: View, time?: Date): void { + if (time) { + view.mergeInContext({ + mediaViewer: { + seek: time, + }, + }); + } else { + view.removeContextProperty('mediaViewer', 'seek'); + } + } + + protected async _executeMediaQuery( + view: View, + mediaType: 'events' | 'recordings', + options?: { + eventsMediaType?: ClipsOrSnapshotsOrAll; + executorOptions?: QueryExecutorOptions; + }, + ): Promise { + const queryWithResults: QueryWithResults | null = + mediaType === 'events' + ? await this._executor.executeDefaultEventQuery({ + ...(!view.isGrid() && { cameraID: view.camera }), + eventsMediaType: options?.eventsMediaType, + executorOptions: options?.executorOptions, + }) + : mediaType === 'recordings' + ? await this._executor.executeDefaultRecordingQuery({ + ...(!view.isGrid() && { cameraID: view.camera }), + executorOptions: options?.executorOptions, + }) + : /* istanbul ignore next -- @preserve */ + null; + if (!queryWithResults) { + return false; + } + + view.query = queryWithResults.query; + view.queryResults = queryWithResults.queryResults; + return true; + } + + public isViewSupportedByCamera(cameraID: string, view: FrigateCardView): boolean { + return !!getCameraIDsForViewName(this._api.getCameraManager(), view, cameraID).size; + } + + protected _getDefaultDisplayModeForView( + viewName: FrigateCardView, + config?: FrigateCardConfig, + ): ViewDisplayMode { + let mode: ViewDisplayMode | null = null; + switch (viewName) { + case 'media': + case 'clip': + case 'recording': + case 'snapshot': + mode = config?.media_viewer.display?.mode ?? null; + break; + case 'live': + mode = config?.live.display?.mode ?? null; + break; + } + return mode ?? 'single'; + } +} diff --git a/src/card-controller/view/modifiers/merge-context.ts b/src/card-controller/view/modifiers/merge-context.ts new file mode 100644 index 00000000..96f86b33 --- /dev/null +++ b/src/card-controller/view/modifiers/merge-context.ts @@ -0,0 +1,15 @@ +import { ViewContext } from "view"; +import { View } from "../../../view/view"; +import { ViewModifier } from "../types"; + +export class MergeContextViewModifier implements ViewModifier { + protected _context?: ViewContext | null; + + constructor(context?: ViewContext | null) { + this._context = context; + } + + public modify(view: View): void { + view.mergeInContext(this._context); + } +} diff --git a/src/card-controller/view/modifiers/remove-context-property.ts b/src/card-controller/view/modifiers/remove-context-property.ts new file mode 100644 index 00000000..75c2d9eb --- /dev/null +++ b/src/card-controller/view/modifiers/remove-context-property.ts @@ -0,0 +1,17 @@ +import { ViewContext } from 'view'; +import { View } from '../../../view/view'; +import { ViewModifier } from '../types'; + +export class RemoveContextPropertyViewModifier implements ViewModifier { + protected _key: keyof ViewContext; + protected _property: PropertyKey; + + constructor(key: keyof ViewContext, property: PropertyKey) { + this._key = key; + this._property = property; + } + + public modify(view: View): void { + view.removeContextProperty(this._key, this._property); + } +} diff --git a/src/card-controller/view/modifiers/remove-context.ts b/src/card-controller/view/modifiers/remove-context.ts new file mode 100644 index 00000000..52e33c21 --- /dev/null +++ b/src/card-controller/view/modifiers/remove-context.ts @@ -0,0 +1,15 @@ +import { ViewContext } from "view"; +import { View } from "../../../view/view"; +import { ViewModifier } from "../types"; + +export class RemoveContextViewModifier implements ViewModifier { + protected _keys: (keyof ViewContext)[]; + + constructor(keys: (keyof ViewContext)[]) { + this._keys = keys; + } + + public modify(view: View): void { + this._keys.forEach((key) => view.removeContext(key)); + } +} diff --git a/src/card-controller/view/modifiers/substream-off.ts b/src/card-controller/view/modifiers/substream-off.ts new file mode 100644 index 00000000..c9eaf443 --- /dev/null +++ b/src/card-controller/view/modifiers/substream-off.ts @@ -0,0 +1,10 @@ +import { removeSubstream } from '../../../utils/substream'; +import { View } from '../../../view/view'; +import { ViewModifier } from '../types'; + +export class SubstreamOffViewModifier implements ViewModifier { + public modify(view: View): void { + removeSubstream(view); + } +} + diff --git a/src/card-controller/view/modifiers/substream-on.ts b/src/card-controller/view/modifiers/substream-on.ts new file mode 100644 index 00000000..b3e1ac74 --- /dev/null +++ b/src/card-controller/view/modifiers/substream-on.ts @@ -0,0 +1,35 @@ +import { CameraManager } from '../../../camera-manager/manager'; +import { getStreamCameraID, setSubstream } from '../../../utils/substream'; +import { View } from '../../../view/view'; +import { ViewModifier } from '../types'; + +interface SubstreamOnViewModifierAPI { + getCameraManager(): CameraManager; +} + +export class SubstreamOnViewModifier implements ViewModifier { + protected _api: SubstreamOnViewModifierAPI; + + constructor(api: SubstreamOnViewModifierAPI) { + this._api = api; + } + + public modify(view: View): void { + const dependencies = [ + ...this._api + .getCameraManager() + .getStore() + .getAllDependentCameras(view.camera, 'substream'), + ]; + + if (dependencies.length <= 1) { + return; + } + + const currentOverride = getStreamCameraID(view); + const currentIndex = dependencies.indexOf(currentOverride); + const newIndex = currentIndex < 0 ? 0 : (currentIndex + 1) % dependencies.length; + + setSubstream(view, dependencies[newIndex]); + } +} diff --git a/src/card-controller/view/modifiers/substream-select.ts b/src/card-controller/view/modifiers/substream-select.ts new file mode 100644 index 00000000..af36777c --- /dev/null +++ b/src/card-controller/view/modifiers/substream-select.ts @@ -0,0 +1,15 @@ +import { setSubstream } from '../../../utils/substream'; +import { View } from '../../../view/view'; +import { ViewModifier } from '../types'; + +export class SubstreamSelectViewModifier implements ViewModifier { + protected _substreamID: string; + + constructor(substreamID: string) { + this._substreamID = substreamID; + } + + public modify(view: View): void { + setSubstream(view, this._substreamID); + } +} diff --git a/src/card-controller/view/query-executor.ts b/src/card-controller/view/query-executor.ts new file mode 100644 index 00000000..8e3df7e1 --- /dev/null +++ b/src/card-controller/view/query-executor.ts @@ -0,0 +1,131 @@ +import { CapabilitySearchOptions, MediaQuery } from '../../camera-manager/types'; +import { MEDIA_CHUNK_SIZE_DEFAULT } from '../../const'; +import { ClipsOrSnapshotsOrAll } from '../../types'; +import { findBestMediaIndex } from '../../utils/find-best-media-index'; +import { + EventMediaQueries, + MediaQueries, + RecordingMediaQueries, +} from '../../view/media-queries'; +import { MediaQueriesResults } from '../../view/media-queries-results'; +import { CardViewAPI } from '../types'; +import { QueryExecutorOptions, QueryWithResults } from './types'; + +export class QueryExecutor { + protected _api: CardViewAPI; + + constructor(api: CardViewAPI) { + this._api = api; + } + + public async executeDefaultEventQuery(options?: { + cameraID?: string; + eventsMediaType?: ClipsOrSnapshotsOrAll; + executorOptions?: QueryExecutorOptions; + }): Promise { + const capabilitySearch: CapabilitySearchOptions = + !options?.eventsMediaType || options?.eventsMediaType === 'all' + ? { + anyCapabilities: ['clips', 'snapshots'], + } + : options.eventsMediaType; + + const cameraManager = this._api.getCameraManager(); + const cameraIDs = options?.cameraID + ? cameraManager + .getStore() + .getAllDependentCameras(options.cameraID, capabilitySearch) + : cameraManager.getStore().getCameraIDsWithCapability(capabilitySearch); + if (!cameraIDs.size) { + return null; + } + + const rawQueries = cameraManager.generateDefaultEventQueries(cameraIDs, { + limit: this._getChunkLimit(), + ...(options?.eventsMediaType === 'clips' && { hasClip: true }), + ...(options?.eventsMediaType === 'snapshots' && { hasSnapshot: true }), + }); + if (!rawQueries) { + return null; + } + const queries = new EventMediaQueries(rawQueries); + const results = await this.execute(queries, options?.executorOptions); + return results + ? { + query: queries, + queryResults: results, + } + : null; + } + + public async executeDefaultRecordingQuery(options?: { + cameraID?: string; + executorOptions?: QueryExecutorOptions; + }): Promise { + const cameraManager = this._api.getCameraManager(); + const cameraIDs = options?.cameraID + ? cameraManager.getStore().getAllDependentCameras(options.cameraID, 'recordings') + : cameraManager.getStore().getCameraIDsWithCapability('recordings'); + if (!cameraIDs.size) { + return null; + } + + const rawQueries = cameraManager.generateDefaultRecordingQueries(cameraIDs, { + limit: this._getChunkLimit(), + }); + if (!rawQueries) { + return null; + } + const queries = new RecordingMediaQueries(rawQueries); + const results = await this.execute(queries, options?.executorOptions); + return results ? { query: queries, queryResults: results } : null; + } + + public async execute( + query: MediaQueries, + executorOptions?: QueryExecutorOptions, + ): Promise { + const queries = query.getQueries(); + if (!queries) { + return null; + } + + const mediaArray = await this._api + .getCameraManager() + .executeMediaQueries(queries, { + useCache: executorOptions?.useCache, + }); + if (!mediaArray) { + return null; + } + + const queryResults = new MediaQueriesResults({ results: mediaArray }); + if (executorOptions?.rejectResults?.(queryResults)) { + return null; + } + + if (executorOptions?.selectResult?.id) { + queryResults.selectBestResult((media) => + media.findIndex((m) => m.getID() === executorOptions.selectResult?.id), + ); + } else if (executorOptions?.selectResult?.func) { + queryResults.selectResultIfFound(executorOptions.selectResult.func); + } else if (executorOptions?.selectResult?.time) { + queryResults.selectBestResult((media) => + findBestMediaIndex( + media, + executorOptions.selectResult?.time?.time as Date, + executorOptions.selectResult?.time?.favorCameraID, + ), + ); + } + return queryResults; + } + + protected _getChunkLimit(): number { + const cardWideConfig = this._api.getConfigManager().getCardWideConfig(); + return ( + cardWideConfig?.performance?.features.media_chunk_size ?? MEDIA_CHUNK_SIZE_DEFAULT + ); + } +} diff --git a/src/card-controller/view/types.ts b/src/card-controller/view/types.ts new file mode 100644 index 00000000..a1aae634 --- /dev/null +++ b/src/card-controller/view/types.ts @@ -0,0 +1,80 @@ +import { ViewContext } from 'view'; +import { FrigateCardView } from '../../config/types.js'; +import { FrigateCardError } from '../../types.js'; +import { MediaQueriesResults } from '../../view/media-queries-results.js'; +import { MediaQueries } from '../../view/media-queries.js'; +import { ViewMedia } from '../../view/media.js'; +import { View, ViewParameters } from '../../view/view.js'; + +export interface ViewModifier { + modify(view: View): void; +} + +export interface QueryExecutorOptions { + // Select the result of a query, based on time, an id match or an arbitrary + // function. If no parameter is specified, the latest media will be selected + // by default. + selectResult?: { + time?: { + time: Date; + favorCameraID?: string; + }; + id?: string; + func?: (media: ViewMedia) => boolean; + }; + rejectResults?: (results: MediaQueriesResults) => boolean; + useCache?: boolean; +} + +export interface QueryWithResults { + query: MediaQueries; + queryResults: MediaQueriesResults; +} + +export interface ViewFactoryOptions { + // An existing view to evolve from. + baseView?: View | null; + + // View parameters to set/evolve. + params?: Partial; + + // Modifiers to the view once created. + modifiers?: ViewModifier[]; + + // When failSafe is true the view will be changed to the default view, or the + // `live` view if the configured default view is not supported. + failSafe?: boolean; + + // Options for the query executor that control how a query is executed and the + // result selected. + queryExecutorOptions?: QueryExecutorOptions; +} + +export interface ViewManagerEpoch { + manager: ViewManagerInterface; + + oldView?: View; +} + +export interface ViewManagerInterface { + getEpoch(): ViewManagerEpoch; + + getView(): View | null; + hasView(): boolean; + reset(): void; + + setViewDefault(options?: ViewFactoryOptions): void; + setViewByParameters(options?: ViewFactoryOptions): void; + + setViewDefaultWithNewQuery(options?: ViewFactoryOptions): Promise; + setViewByParametersWithNewQuery(options?: ViewFactoryOptions): Promise; + setViewByParametersWithExistingQuery(options?: ViewFactoryOptions): Promise; + + setViewWithMergedContext(context: ViewContext | null): void; + + isViewSupportedByCamera(cameraID: string, view: FrigateCardView): boolean; + hasMajorMediaChange(oldView?: View | null): boolean; +} + +export class ViewNoCameraError extends FrigateCardError {} +export class ViewIncompatible extends FrigateCardError {} diff --git a/src/card-controller/view/view-manager.ts b/src/card-controller/view/view-manager.ts new file mode 100644 index 00000000..da6ccde6 --- /dev/null +++ b/src/card-controller/view/view-manager.ts @@ -0,0 +1,164 @@ +import { ViewContext } from 'view'; +import { FrigateCardView } from '../../config/types'; +import { log } from '../../utils/debug'; +import { getStreamCameraID } from '../../utils/substream'; +import { View } from '../../view/view'; +import { getCameraIDsForViewName } from '../../view/view-to-cameras'; +import { CardViewAPI } from '../types'; +import { ViewFactory } from './factory'; +import { ViewFactoryOptions, ViewManagerEpoch, ViewManagerInterface } from './types'; + +export class ViewManager implements ViewManagerInterface { + protected _view: View | null = null; + protected _factory: ViewFactory; + protected _api: CardViewAPI; + protected _epoch: ViewManagerEpoch = this._createEpoch(); + + constructor(api: CardViewAPI, factory?: ViewFactory) { + this._api = api; + this._factory = factory ?? new ViewFactory(api); + } + + public getEpoch(): ViewManagerEpoch { + return this._epoch; + } + protected _createEpoch(oldView?: View | null): ViewManagerEpoch { + return { + manager: this, + ...(oldView && { oldView }), + }; + } + + public getView(): View | null { + return this._view; + } + public hasView(): boolean { + return !!this.getView(); + } + public reset(): void { + if (this._view) { + this._setView(null); + } + } + + setViewDefault = (options?: ViewFactoryOptions): void => + this._setViewGeneric(this._factory.getViewDefault, options); + + setViewByParameters = (options?: ViewFactoryOptions): void => + this._setViewGeneric(this._factory.getViewByParameters, options); + + setViewDefaultWithNewQuery = async (options?: ViewFactoryOptions): Promise => + await this._setViewGenericAsync(this._factory.getViewDefaultWithNewQuery, options); + + setViewByParametersWithNewQuery = async ( + options?: ViewFactoryOptions, + ): Promise => + await this._setViewGenericAsync( + this._factory.getViewByParametersWithNewQuery, + options, + ); + + setViewByParametersWithExistingQuery = async ( + options?: ViewFactoryOptions, + ): Promise => + await this._setViewGenericAsync( + this._factory.getViewByParametersWithExistingQuery, + options, + ); + + protected _setViewGeneric( + factoryFunc: (options?: ViewFactoryOptions) => View | null, + options?: ViewFactoryOptions, + ): void { + let view: View | null = null; + try { + view = factoryFunc({ + baseView: this._view, + ...options, + }); + } catch (e) { + return this._api.getMessageManager().setErrorIfHigherPriority(e); + } + view && this._setView(view); + } + + protected async _setViewGenericAsync( + factoryFunc: (options?: ViewFactoryOptions) => Promise, + options?: ViewFactoryOptions, + ): Promise { + let view: View | null = null; + try { + view = await factoryFunc({ + baseView: this._view, + ...options, + }); + } catch (e) { + return this._api.getMessageManager().setErrorIfHigherPriority(e); + } + view && this._setView(view); + } + + public setViewWithMergedContext(context: ViewContext | null): void { + if (this._view) { + return this._setView(this._view?.clone().mergeInContext(context)); + } + } + + public isViewSupportedByCamera(cameraID: string, view: FrigateCardView): boolean { + return !!getCameraIDsForViewName(this._api.getCameraManager(), view, cameraID).size; + } + + /** + * Detect if the current view has a major "media change" for the given previous view. + * @param oldView The previous view. + * @returns True if the view change is a real media change. + */ + public hasMajorMediaChange(oldView?: View | null): boolean { + return ( + !!oldView !== !!this._view || + oldView?.view !== this._view?.view || + oldView?.camera !== this._view?.camera || + // When in live mode, take overrides (substreams) into account in deciding + // if this is a major media change. + (this._view?.view === 'live' && + oldView && + getStreamCameraID(oldView) !== getStreamCameraID(this._view)) || + // When in the live view, the queryResults contain the events that + // happened in the past -- not reflective of the actual live media viewer + // the user is seeing. + (this._view?.view !== 'live' && oldView?.queryResults !== this._view?.queryResults) + ); + } + + protected _setView(view: View | null): void { + const oldView = this._view; + + log( + this._api.getConfigManager().getCardWideConfig(), + `Frigate Card view change: `, + view, + ); + + this._view = view; + this._epoch = this._createEpoch(oldView); + + if (this.hasMajorMediaChange(oldView)) { + this._api.getMediaLoadedInfoManager().clear(); + } + + if (oldView?.view !== view?.view) { + this._api.getCardElementManager().scrollReset(); + } + + this._api.getMessageManager().reset(); + this._api.getStyleManager().setExpandedMode(); + + this._api.getConditionsManager()?.setState({ + view: view?.view, + camera: view?.camera, + displayMode: view?.displayMode ?? undefined, + }); + + this._api.getCardElementManager().update(); + } +} diff --git a/src/card.ts b/src/card.ts index f36bdbe3..8f9000c5 100644 --- a/src/card.ts +++ b/src/card.ts @@ -4,7 +4,6 @@ import { customElement } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { Ref, createRef, ref } from 'lit/directives/ref.js'; import { styleMap } from 'lit/directives/style-map.js'; -import { ViewContext } from 'view'; import 'web-dialog'; import pkg from '../package.json'; import { actionHandler } from './action-handler-directive.js'; @@ -26,7 +25,6 @@ import { localize } from './localize/localize.js'; import cardStyle from './scss/card.scss'; import { ExtendedHomeAssistant, MediaLoadedInfo, Message } from './types.js'; import { frigateCardHasAction } from './utils/action.js'; -import { View } from './view/view.js'; // *************************************************************************** // General Card-Wide Notes @@ -268,10 +266,6 @@ class FrigateCard extends LitElement { style="${styleMap(this._controller.getStyleManager().getAspectRatioStyle())}" @frigate-card:message=${(ev: CustomEvent) => this._controller.getMessageManager().setMessageIfHigherPriority(ev.detail)} - @frigate-card:view:change=${(ev: CustomEvent) => - this._controller.getViewManager().setView(ev.detail)} - @frigate-card:view:change-context=${(ev: CustomEvent) => - this._controller.getViewManager().setViewWithMergedContext(ev.detail)} @frigate-card:media:loaded=${(ev: CustomEvent) => this._controller.getMediaLoadedInfoManager().set(ev.detail)} @frigate-card:media:unloaded=${() => @@ -299,7 +293,7 @@ class FrigateCard extends LitElement { html`; - - fetchThumbnails?: boolean; } declare module 'view' { @@ -36,8 +25,7 @@ interface LastMediaLoadedInfo { type LiveControllerHost = LitElement & FrigateCardMediaLoadedEventTarget & - FrigateCardMessageEventTarget & - FrigateCardViewChangeEventTarget; + FrigateCardMessageEventTarget; export class LiveController implements ReactiveController { protected _host: LiveControllerHost; @@ -71,7 +59,7 @@ export class LiveController implements ReactiveController { // Don't process updates if it's in the background and a message was // received (otherwise an error message thrown by the background live // component may continually be re-spammed hitting performance). - return !this._inBackground || !this._messageReceived; + return !(this._inBackground && this._messageReceived); } public hostConnected(): void { @@ -79,7 +67,6 @@ export class LiveController implements ReactiveController { this._host.addEventListener('frigate-card:media:loaded', this._handleMediaLoaded); this._host.addEventListener('frigate-card:message', this._handleMessage); - this._host.addEventListener('frigate-card:view:change', this._handleViewChange); } public hostDisconnected(): void { @@ -87,7 +74,6 @@ export class LiveController implements ReactiveController { this._host.removeEventListener('frigate-card:media:loaded', this._handleMediaLoaded); this._host.removeEventListener('frigate-card:message', this._handleMessage); - this._host.removeEventListener('frigate-card:view:change', this._handleViewChange); } public clearMessageReceived(): void { @@ -124,12 +110,6 @@ export class LiveController implements ReactiveController { } }; - protected _handleViewChange = (ev: CustomEvent): void => { - if (this._inBackground) { - ev.stopPropagation(); - } - }; - protected _intersectionHandler(entries: IntersectionObserverEntry[]): void { const wasInBackground = this._inBackground; this._inBackground = !entries.some((entry) => entry.isIntersecting); @@ -150,74 +130,4 @@ export class LiveController implements ReactiveController { this._host.requestUpdate(); } } - - /** - * Fetch thumbnail media when a target is not already specified in the view - * (e.g. first time live is visited). - */ - public async fetchMediaInBackgroundIfNecessary( - view: View, - cameraManager: CameraManager, - cardWideConfig: CardWideConfig, - overriddenLiveConfig: LiveConfig, - ): Promise { - if ( - this._inBackground || - // Only fetch media if there isn't any already. - view.query || - overriddenLiveConfig.controls.thumbnails.mode === 'none' || - view.context?.live?.fetchThumbnails === false - ) { - return; - } - - const mediaType = overriddenLiveConfig.controls.thumbnails.media_type; - const now = new Date(); - const viewContext: ViewContext = { - // Force the window to start at the most recent time, not - // necessarily when the most recent event/recording was: - // https://github.com/dermotduffy/frigate-hass-card/issues/1301 - timeline: { - window: { - start: sub(now, { - seconds: overriddenLiveConfig.controls.timeline.window_seconds, - }), - end: now, - }, - }, - }; - - /* istanbul ignore else: the else path cannot be reached -- @preserve */ - if (mediaType === 'events') { - await changeViewToRecentEventsForCameraAndDependents( - this._host, - cameraManager, - cardWideConfig, - view, - { - allCameras: view.isGrid(), - targetView: view.view, - eventsMediaType: overriddenLiveConfig.controls.thumbnails.events_media_type, - select: 'latest', - // Force the window to start at the most recent time, not - // necessarily when the most recent event was: - // https://github.com/dermotduffy/frigate-hass-card/issues/1301 - viewContext: viewContext, - }, - ); - } else if (mediaType === 'recordings') { - await changeViewToRecentRecordingForCameraAndDependents( - this._host, - cameraManager, - cardWideConfig, - view, - { - allCameras: view.isGrid(), - targetView: view.view, - select: 'latest', - viewContext: viewContext, - }, - ); - } - } } diff --git a/src/components-lib/media-filter-controller.ts b/src/components-lib/media-filter-controller.ts index 5a46f6f1..a92b6321 100644 --- a/src/components-lib/media-filter-controller.ts +++ b/src/components-lib/media-filter-controller.ts @@ -21,10 +21,9 @@ import { SelectOption, SelectValues } from '../components/select'; import { CardWideConfig } from '../config/types'; import { localize } from '../localize/localize'; import { errorToConsole, formatDate, prettifyTitle } from '../utils/basic'; -import { executeMediaQueryForViewWithErrorDispatching } from '../utils/media-to-view'; import { EventMediaQueries, RecordingMediaQueries } from '../view/media-queries'; import { MediaQueriesClassifier } from '../view/media-queries-classifier'; -import { View } from '../view/view'; +import { ViewManagerInterface } from '../card-controller/view/types'; interface MediaFilterControls { events: boolean; @@ -77,6 +76,7 @@ export class MediaFilterController { protected _favoriteOptions: SelectOption[]; protected _defaults: MediaFilterCoreDefaults | null = null; + protected _viewManager: ViewManagerInterface | null = null; constructor(host: LitElement) { this._host = host; @@ -154,10 +154,12 @@ export class MediaFilterController { public getDefaults(): MediaFilterCoreDefaults | null { return this._defaults; } + public setViewManager(viewManager: ViewManagerInterface | null): void { + this._viewManager = viewManager; + } public async valueChangeHandler( cameraManager: CameraManager, - view: View, cardWideConfig: CardWideConfig, values: { camera?: string | string[]; @@ -234,20 +236,15 @@ export class MediaFilterController { }, ]); - ( - await executeMediaQueryForViewWithErrorDispatching( - this._host, - cameraManager, - view, - queries, - { - // See 'A note on views' above for these two arguments. - ...(cameraIDs.size === 1 && { targetCameraID: [...cameraIDs][0] }), - targetView: - values.mediaType === MediaFilterMediaType.Clips ? 'clips' : 'snapshots', - }, - ) - )?.dispatchChangeEvent(this._host); + this._viewManager?.setViewByParametersWithExistingQuery({ + params: { + query: queries, + + // See 'A note on views' above for these two arguments + ...(cameraIDs.size === 1 && { camera: [...cameraIDs][0] }), + view: values.mediaType === MediaFilterMediaType.Clips ? 'clips' : 'snapshots', + }, + }); } else { const queries = new RecordingMediaQueries([ { @@ -262,19 +259,15 @@ export class MediaFilterController { }, ]); - ( - await executeMediaQueryForViewWithErrorDispatching( - this._host, - cameraManager, - view, - queries, - { - // See 'A note on views' above for these two arguments. - ...(cameraIDs.size === 1 && { targetCameraID: [...cameraIDs][0] }), - targetView: 'recordings', - }, - ) - )?.dispatchChangeEvent(this._host); + this._viewManager?.setViewByParametersWithExistingQuery({ + params: { + query: queries, + + // See 'A note on views' above for these two arguments + ...(cameraIDs.size === 1 && { camera: [...cameraIDs][0] }), + view: 'recordings', + }, + }); } // Need to ensure we update the element as the date-picker selections may @@ -288,10 +281,11 @@ export class MediaFilterController { }); } - public computeInitialDefaultsFromView(cameraManager: CameraManager, view: View): void { - const queries = view.query?.getQueries(); + public computeInitialDefaultsFromView(cameraManager: CameraManager): void { + const view = this._viewManager?.getView(); + const queries = view?.query?.getQueries(); const allCameraIDs = this._getAllCameraIDs(cameraManager); - if (!queries || !allCameraIDs.size) { + if (!view || !queries || !allCameraIDs.size) { return; } @@ -444,14 +438,10 @@ export class MediaFilterController { this._host.requestUpdate(); } - public getControlsToShow( - cameraManager: CameraManager, - view: View, - ): MediaFilterControls { - const events = !!(view.query && MediaQueriesClassifier.areEventQueries(view.query)); - const recordings = !!( - view.query && MediaQueriesClassifier.areRecordingQueries(view.query) - ); + public getControlsToShow(cameraManager: CameraManager): MediaFilterControls { + const view = this._viewManager?.getView(); + const events = MediaQueriesClassifier.areEventQueries(view?.query); + const recordings = MediaQueriesClassifier.areRecordingQueries(view?.query); const managerCapabilities = cameraManager.getAggregateCameraCapabilities(); return { diff --git a/src/components-lib/menu-button-controller.ts b/src/components-lib/menu-button-controller.ts index 160b256f..5e1e7fd1 100644 --- a/src/components-lib/menu-button-controller.ts +++ b/src/components-lib/menu-button-controller.ts @@ -3,7 +3,7 @@ import { StyleInfo } from 'lit/directives/style-map'; import { CameraManager } from '../camera-manager/manager'; import { MediaPlayerManager } from '../card-controller/media-player-manager'; import { MicrophoneManager } from '../card-controller/microphone-manager'; -import { ViewManager } from '../card-controller/view-manager'; +import { ViewManager } from '../card-controller/view/view-manager'; import { FRIGATE_CARD_VIEWS_USER_SPECIFIED, FrigateCardConfig, diff --git a/src/components-lib/zoom/zoom-view-context.ts b/src/components-lib/zoom/zoom-view-context.ts index bd13e89c..3b67e80f 100644 --- a/src/components-lib/zoom/zoom-view-context.ts +++ b/src/components-lib/zoom/zoom-view-context.ts @@ -1,6 +1,7 @@ import { ViewContext } from 'view'; -import { dispatchViewContextChangeEvent } from '../../view/view.js'; -import { ZoomSettingsObserved, PartialZoomSettings } from './types.js'; +import { MergeContextViewModifier } from '../../card-controller/view/modifiers/merge-context.js'; +import { ViewManagerInterface } from '../../card-controller/view/types.js'; +import { PartialZoomSettings, ZoomSettingsObserved } from './types.js'; interface ZoomViewContext { observed?: ZoomSettingsObserved; @@ -38,19 +39,22 @@ export const generateViewContextForZoom = ( }; /** - * Convenience wrapper to convert zoom settings into a dispatched view context - * change. + * Convenience wrapper to convert zoom settings into a view change */ export const handleZoomSettingsObservedEvent = ( - element: EventTarget, ev: CustomEvent, + viewManager?: ViewManagerInterface, targetID?: string, ): void => { - targetID && - dispatchViewContextChangeEvent( - element, - generateViewContextForZoom(targetID, { - observed: ev.detail, - }), - ); + viewManager && + targetID && + viewManager.setViewByParameters({ + modifiers: [ + new MergeContextViewModifier( + generateViewContextForZoom(targetID, { + observed: ev.detail, + }), + ), + ], + }); }; diff --git a/src/components/gallery.ts b/src/components/gallery.ts index c98608c7..55e5e73a 100644 --- a/src/components/gallery.ts +++ b/src/components/gallery.ts @@ -24,20 +24,16 @@ import galleryStyle from '../scss/gallery.scss'; import { ExtendedHomeAssistant } from '../types.js'; import { stopEventFromActivatingCardWideActions } from '../utils/action.js'; import { errorToConsole, sleep } from '../utils/basic'; -import { - changeViewToRecentEventsForCameraAndDependents, - changeViewToRecentRecordingForCameraAndDependents, -} from '../utils/media-to-view.js'; import { ViewMedia } from '../view/media'; import { EventMediaQueries, RecordingMediaQueries } from '../view/media-queries'; import { MediaQueriesClassifier } from '../view/media-queries-classifier'; import { MediaQueriesResults } from '../view/media-queries-results'; -import { View } from '../view/view.js'; import './media-filter'; import { renderMessage, renderProgressIndicator } from './message.js'; import './surround-basic'; import './thumbnail.js'; import { THUMBNAIL_DETAILS_WIDTH_MIN } from './thumbnail.js'; +import { ViewManagerEpoch } from '../card-controller/view/types.js'; const GALLERY_MEDIA_FILTER_MENU_ICONS = { closed: 'mdi:filter-cog-outline', @@ -52,7 +48,7 @@ export class FrigateCardGallery extends LitElement { public hass?: ExtendedHomeAssistant; @property({ attribute: false }) - public view?: Readonly; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public galleryConfig?: GalleryConfig; @@ -68,43 +64,16 @@ export class FrigateCardGallery extends LitElement { * @returns A rendered template. */ protected render(): TemplateResult | void { + const view = this.viewManagerEpoch?.manager.getView(); if ( !this.hass || - !this.view || - !this.view.isGalleryView() || + !view?.isGalleryView() || !this.cameraManager || !this.cardWideConfig ) { return; } - if (!this.view.query) { - if (this.view.is('recordings')) { - changeViewToRecentRecordingForCameraAndDependents( - this, - this.cameraManager, - this.cardWideConfig, - this.view, - ); - } else { - const eventsMediaType = this.view.is('snapshots') - ? 'snapshots' - : this.view.is('clips') - ? 'clips' - : null; - changeViewToRecentEventsForCameraAndDependents( - this, - this.cameraManager, - this.cardWideConfig, - this.view, - { - ...(eventsMediaType && { eventsMediaType: eventsMediaType }), - }, - ); - } - return renderProgressIndicator({ cardWideConfig: this.cardWideConfig }); - } - return html` @@ -126,7 +95,7 @@ export class FrigateCardGallery extends LitElement { : ''} ; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public galleryConfig?: GalleryConfig; @@ -328,13 +297,15 @@ export class FrigateCardGalleryCore extends LitElement { direction: 'earlier' | 'later', useCache = true, ): Promise { - if (!this.cameraManager || !this.hass || !this.view) { + const view = this.viewManagerEpoch?.manager.getView(); + + if (!this.cameraManager || !this.hass || !view) { return; } - const query = this.view?.query; + const query = view.query; const rawQueries = query?.getQueries() ?? null; - const existingMedia = this.view.queryResults?.getResults(); + const existingMedia = view.queryResults?.getResults(); if (!query || !rawQueries || !existingMedia) { return; } @@ -362,16 +333,17 @@ export class FrigateCardGalleryCore extends LitElement { : null; if (newMediaQueries) { - this.view - ?.evolve({ + this.viewManagerEpoch?.manager.setViewByParameters({ + baseView: view, + params: { query: newMediaQueries, queryResults: new MediaQueriesResults({ results: extension.results, }).selectResultIfFound( - (media) => media === this.view?.queryResults?.getSelectedResult(), + (media) => media === view.queryResults?.getSelectedResult(), ), - }) - .dispatchChangeEvent(this); + }, + }); } } } @@ -395,19 +367,18 @@ export class FrigateCardGalleryCore extends LitElement { ); } } - if (changedProps.has('view')) { + if (changedProps.has('viewManagerEpoch')) { // If the view changes, always render the bottom loader to allow for the // view to be extended once the bottom loader becomes visible. this._showLoaderBottom = true; - const oldView: View | undefined = changedProps.get('view'); - if ( - oldView?.queryResults?.getResults() !== this.view?.queryResults?.getResults() - ) { + const view = this.viewManagerEpoch?.manager.getView(); + const oldView = this.viewManagerEpoch?.oldView; + if (!this._media || oldView?.queryResults?.getResults() !== view?.queryResults?.getResults()) { // Gallery places the most recent media at the top (the query results place // the most recent media at the end for use in the viewer). This is copied // to a new array to avoid reversing the query results in place. - this._media = [...(this.view?.queryResults?.getResults() ?? [])].reverse(); + this._media = [...(view?.queryResults?.getResults() ?? [])].reverse(); } } } @@ -417,11 +388,12 @@ export class FrigateCardGalleryCore extends LitElement { * @returns A rendered template. */ protected render(): TemplateResult | void { - if (!this._media || !this.hass || !this.view || !this.view.isGalleryView()) { + if (!this._media || !this.hass) { return html``; } - if ((this.view?.queryResults?.getResultsCount() ?? 0) === 0) { + const view = this.viewManagerEpoch?.manager.getView(); + if (!view?.queryResults || view.queryResults.getResultsCount() === 0) { // Note that this is not throwing up an error message for the card to // handle (as typical), but rather directly rendering the message into the // gallery. This is to allow the filter to still be available when a given @@ -433,7 +405,7 @@ export class FrigateCardGalleryCore extends LitElement { }); } - const selected = this.view?.queryResults?.getSelectedResult(); + const selected = view.queryResults.getSelectedResult(); return html`
      ${this._showLoaderTop ? html`${renderProgressIndicator({ @@ -454,7 +426,7 @@ export class FrigateCardGalleryCore extends LitElement { .hass=${this.hass} .cameraManager=${this.cameraManager} .media=${media} - .view=${this.view} + .viewManagerEpoch=${this.viewManagerEpoch} ?details=${!!this.galleryConfig?.controls.thumbnails.show_details} ?show_favorite_control=${!!this.galleryConfig?.controls.thumbnails .show_favorite_control} @@ -463,17 +435,17 @@ export class FrigateCardGalleryCore extends LitElement { ?show_download_control=${!!this.galleryConfig?.controls.thumbnails .show_download_control} @click=${(ev: Event) => { - if (this.view && this._media) { - this.view - .evolve({ + if (this._media) { + this.viewManagerEpoch?.manager.setViewByParameters({ + params: { view: 'media', - queryResults: this.view.queryResults?.clone().selectIndex( + queryResults: view.queryResults?.clone().selectIndex( // Media in the gallery is reversed vs the queryResults (see // note above). this._media.length - index - 1, ), - }) - .dispatchChangeEvent(this); + }, + }); } stopEventFromActivatingCardWideActions(ev); }} @@ -504,9 +476,9 @@ export class FrigateCardGalleryCore extends LitElement { // See: https://github.com/dermotduffy/frigate-hass-card/issues/885 if ( // If this update cycle updated the view ... - changedProps.has('view') && + changedProps.has('viewManagerEpoch') && // ... and it wasn't set at all prior ... - !changedProps.get('view') && + !changedProps.get('viewManagerEpoch') && // ... and there is a thumbnail rendered that is selected. this._refSelected.value ) { diff --git a/src/components/live/live.ts b/src/components/live/live.ts index c435f88b..2f440e43 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -19,8 +19,14 @@ import { getOverriddenConfig, } from '../../card-controller/conditions-manager.js'; import { ReadonlyMicrophoneManager } from '../../card-controller/microphone-manager.js'; +import { ViewManagerEpoch } from '../../card-controller/view/types.js'; import { LiveController } from '../../components-lib/live/live-controller.js'; import { MediaGridSelected } from '../../components-lib/media-grid-controller.js'; +import { + PartialZoomSettings, + ZoomSettingsObserved, +} from '../../components-lib/zoom/types.js'; +import { handleZoomSettingsObservedEvent } from '../../components-lib/zoom/zoom-view-context.js'; import { CameraConfig, CardWideConfig, @@ -48,7 +54,8 @@ import { getStateObjOrDispatchError } from '../../utils/get-state-obj.js'; import { dispatchMediaUnloadedEvent } from '../../utils/media-info.js'; import { updateElementStyleFromMediaLayoutConfig } from '../../utils/media-layout.js'; import { playMediaMutingIfNecessary } from '../../utils/media.js'; -import { dispatchViewContextChangeEvent, View } from '../../view/view.js'; +import { getStreamCameraID } from '../../utils/substream.js'; +import { View } from '../../view/view.js'; import { EmblaCarouselPlugins } from '../carousel.js'; import { renderMessage } from '../message.js'; import '../next-prev-control.js'; @@ -60,12 +67,6 @@ import { FrigateCardTitleControl, getDefaultTitleConfigForView, } from '../title-control.js'; -import { - PartialZoomSettings, - ZoomSettingsObserved, -} from '../../components-lib/zoom/types.js'; -import { handleZoomSettingsObservedEvent } from '../../components-lib/zoom/zoom-view-context.js'; -import { getStreamCameraID } from '../../utils/substream.js'; const FRIGATE_CARD_LIVE_PROVIDER = 'frigate-card-live-provider'; @@ -78,7 +79,7 @@ export class FrigateCardLive extends LitElement { public hass?: ExtendedHomeAssistant; @property({ attribute: false }) - public view?: Readonly; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public nonOverriddenLiveConfig?: LiveConfig; @@ -108,38 +109,16 @@ export class FrigateCardLive extends LitElement { return this._controller.shouldUpdate(); } - protected willUpdate(changedProperties: PropertyValues): void { - if ( - ['view', 'cameraManager', 'cardWideConfig', 'overriddenLiveConfig'].some((prop) => - changedProperties.has(prop), - ) && - this.view && - this.cameraManager && - this.cardWideConfig && - this.overriddenLiveConfig - ) { - this._controller.fetchMediaInBackgroundIfNecessary( - this.view, - this.cameraManager, - this.cardWideConfig, - this.overriddenLiveConfig, - ); - } - + protected willUpdate(): void { this._controller.clearMessageReceived(); } protected render(): TemplateResult | void { - if ( - !this.hass || - !this.nonOverriddenLiveConfig || - !this.cameraManager || - !this.view - ) { + if (!this.hass || !this.nonOverriddenLiveConfig || !this.cameraManager) { return; } - // Notes: + // Implementation notes: // - See use of liveConfig and not config below -- the underlying carousel // will independently override the liveConfig to reflect the camera in the // carousel (not necessarily the selected camera). @@ -153,7 +132,7 @@ export class FrigateCardLive extends LitElement { html` ; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public nonOverriddenLiveConfig?: LiveConfig; @@ -207,13 +186,14 @@ export class FrigateCardLiveGrid extends LitElement { public triggeredCameraIDs?: Set; protected _renderCarousel(cameraID?: string): TemplateResult { - const triggeredCameraID = cameraID ?? this.view?.camera; + const view = this.viewManagerEpoch?.manager.getView(); + const triggeredCameraID = cameraID ?? view?.camera; return html` 1 ); } protected willUpdate(changedProps: PropertyValues): void { - if (changedProps.has('view') && this._needsGrid()) { + if (changedProps.has('viewManagerEpoch') && this._needsGrid()) { import('../media-grid.js'); } } @@ -261,16 +242,13 @@ export class FrigateCardLiveGrid extends LitElement { if (!cameraIDs?.size || !this._needsGrid()) { return this._renderCarousel(); } + return html` ) => this._gridSelectCamera(ev.detail.selected)} - @frigate-card:view:change=${(ev: CustomEvent) => { - ev.stopPropagation(); - this._gridSelectCamera(ev.detail.camera, ev.detail); - }} > ${[...cameraIDs].map((cameraID) => this._renderCarousel(cameraID))} @@ -288,7 +266,7 @@ export class FrigateCardLiveCarousel extends LitElement { public hass?: ExtendedHomeAssistant; @property({ attribute: false }) - public view?: Readonly; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public nonOverriddenLiveConfig?: LiveConfig; @@ -331,12 +309,13 @@ export class FrigateCardLiveCarousel extends LitElement { protected _getSelectedCameraIndex(): number { const cameraIDs = this.cameraManager?.getStore().getCameraIDsWithCapability('live'); - if (!cameraIDs?.size || !this.view || this.viewFilterCameraID) { + const view = this.viewManagerEpoch?.manager.getView(); + if (!cameraIDs?.size || !view || this.viewFilterCameraID) { // If the carousel is limited to a single cameraID, the first (only) // element is always the selected one. return 0; } - return Math.max(0, Array.from(cameraIDs).indexOf(this.view.camera)); + return Math.max(0, Array.from(cameraIDs).indexOf(view.camera)); } protected _getPlugins(): EmblaCarouselPlugins { @@ -393,6 +372,7 @@ export class FrigateCardLiveCarousel extends LitElement { return [[], {}]; } + const view = this.viewManagerEpoch?.manager.getView(); const cameraIDs = this.viewFilterCameraID ? new Set([this.viewFilterCameraID]) : this.cameraManager?.getStore().getCameraIDsWithCapability('live'); @@ -403,8 +383,7 @@ export class FrigateCardLiveCarousel extends LitElement { for (const [cameraID, cameraConfig] of this.cameraManager .getStore() .getCameraConfigEntries(cameraIDs)) { - const liveCameraID = - this.view?.context?.live?.overrides?.get(cameraID) ?? cameraID; + const liveCameraID = this._getSubstreamCameraID(cameraID, view); const liveCameraConfig = cameraID === liveCameraID ? cameraConfig @@ -430,17 +409,11 @@ export class FrigateCardLiveCarousel extends LitElement { protected _setViewCameraID(cameraID?: string | null): void { if (cameraID) { - this.view - ?.evolve({ + this.viewManagerEpoch?.manager.setViewByParametersWithNewQuery({ + params: { camera: cameraID, - // Reset the query and query results. - query: null, - queryResults: null, - }) - // Don't yet fetch thumbnails (they will be fetched when the carousel - // settles). - .mergeInContext({ live: { fetchThumbnails: false } }) - .dispatchChangeEvent(this); + }, + }); } } @@ -490,12 +463,13 @@ export class FrigateCardLiveCarousel extends LitElement { ).live as LiveConfig; const cameraMetadata = this.cameraManager.getCameraMetadata(cameraID); + const view = this.viewManagerEpoch?.manager.getView(); return html`
      ) => - handleZoomSettingsObservedEvent(this, ev, cameraID)} + handleZoomSettingsObservedEvent( + ev, + this.viewManagerEpoch?.manager, + cameraID, + )} >
      @@ -520,11 +498,13 @@ export class FrigateCardLiveCarousel extends LitElement { const cameraIDs = this.cameraManager ? [...this.cameraManager?.getStore().getCameraIDsWithCapability('live')] : []; - if (this.viewFilterCameraID || cameraIDs.length <= 1 || !this.view || !this.hass) { + const view = this.viewManagerEpoch?.manager.getView(); + + if (this.viewFilterCameraID || cameraIDs.length <= 1 || !view || !this.hass) { return [null, null]; } - const cameraID = this.viewFilterCameraID ?? this.view.camera; + const cameraID = this.viewFilterCameraID ?? view.camera; const currentIndex = cameraIDs.indexOf(cameraID); if (currentIndex < 0) { @@ -537,8 +517,13 @@ export class FrigateCardLiveCarousel extends LitElement { ]; } + protected _getSubstreamCameraID(cameraID: string, view?: View | null): string { + return view?.context?.live?.overrides?.get(cameraID) ?? cameraID; + } + protected render(): TemplateResult | void { - if (!this.overriddenLiveConfig || !this.view || !this.hass || !this.cameraManager) { + const view = this.viewManagerEpoch?.manager.getView(); + if (!this.overriddenLiveConfig || !this.hass || !view || !this.cameraManager) { return; } @@ -551,23 +536,19 @@ export class FrigateCardLiveCarousel extends LitElement { const hasMultipleCameras = slides.length > 1; const [prevID, nextID] = this._getCameraIDsOfNeighbors(); - const getOverrideCameraID = (cameraID: string): string => { - return this.view?.context?.live?.overrides?.get(cameraID) ?? cameraID; - }; - const cameraMetadataPrevious = prevID - ? this.cameraManager.getCameraMetadata(getOverrideCameraID(prevID)) + ? this.cameraManager.getCameraMetadata(this._getSubstreamCameraID(prevID, view)) : null; - const cameraID = this.viewFilterCameraID ?? this.view.camera; + const cameraID = this.viewFilterCameraID ?? view.camera; const cameraMetadataCurrent = this.cameraManager.getCameraMetadata( - getOverrideCameraID(cameraID), + this._getSubstreamCameraID(cameraID, view), ); const cameraMetadataNext = nextID - ? this.cameraManager.getCameraMetadata(getOverrideCameraID(nextID)) + ? this.cameraManager.getCameraMetadata(this._getSubstreamCameraID(nextID, view)) : null; const titleConfig = getDefaultTitleConfigForView( - this.view, + view, this.overriddenLiveConfig?.controls.title, ); @@ -592,10 +573,6 @@ export class FrigateCardLiveCarousel extends LitElement { .selected=${this._getSelectedCameraIndex()} transitionEffect=${this._getTransitionEffect()} @frigate-card:carousel:select=${this._setViewHandler.bind(this)} - @frigate-card:carousel:settle=${() => { - // Fetch the thumbnails after the carousel has settled. - dispatchViewContextChangeEvent(this, { live: { fetchThumbnails: true } }); - }} @frigate-card:media:loaded=${() => { if (this._refTitleControl.value) { this._refTitleControl.value.show(); @@ -639,9 +616,8 @@ export class FrigateCardLiveCarousel extends LitElement { ${cameraMetadataCurrent && titleConfig diff --git a/src/components/media-filter.ts b/src/components/media-filter.ts index b85be987..e7a6bb06 100644 --- a/src/components/media-filter.ts +++ b/src/components/media-filter.ts @@ -21,11 +21,11 @@ import { import { CardWideConfig } from '../config/types'; import { localize } from '../localize/localize'; import mediaFilterStyle from '../scss/media-filter.scss'; -import { View } from '../view/view'; import { FrigateCardDatePicker } from './date-picker'; import './date-picker.js'; import { FrigateCardSelect } from './select'; import './select.js'; +import { ViewManagerEpoch } from '../card-controller/view/types'; @customElement('frigate-card-media-filter') class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) { @@ -36,7 +36,7 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) { public cameraManager?: CameraManager; @property({ attribute: false }) - public view?: View; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public cardWideConfig?: CardWideConfig; @@ -59,46 +59,49 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) { protected _refTags: Ref = createRef(); protected willUpdate(changedProps: PropertyValues): void { + if (changedProps.has('viewManagerEpoch')) { + this._mediaFilterController.setViewManager(this.viewManagerEpoch?.manager ?? null); + } + if (changedProps.has('cameraManager') && this.cameraManager) { this._mediaFilterController.computeCameraOptions(this.cameraManager); this._mediaFilterController.computeMetadataOptions(this.cameraManager); } + + // The first time the viewManager is set, compute the initial default selections. if ( - changedProps.has('view') && - !changedProps.get('view') && - this.view && + !changedProps.get('viewManager') && + this.viewManagerEpoch && this.cameraManager ) { - this._mediaFilterController.computeInitialDefaultsFromView( - this.cameraManager, - this.view, - ); + this._mediaFilterController.computeInitialDefaultsFromView(this.cameraManager); } } protected render(): TemplateResult | void { const valueChange = async () => { - if (!this.cameraManager || !this.view || !this.cardWideConfig) { + if (!this.cameraManager || !this.viewManagerEpoch || !this.cardWideConfig) { return; } await this._mediaFilterController.valueChangeHandler( this.cameraManager, - this.view, this.cardWideConfig, { - camera: this._refCamera.value?.value, - mediaType: this._refMediaType.value?.value as MediaFilterMediaType | undefined, + camera: this._refCamera.value?.value ?? undefined, + mediaType: (this._refMediaType.value?.value ?? undefined) as + | MediaFilterMediaType + | undefined, when: { - selected: this._refWhen.value?.value, + selected: this._refWhen.value?.value ?? undefined, from: this._refWhenFrom.value?.value, to: this._refWhenTo.value?.value, }, - favorite: this._refFavorite.value?.value as + favorite: (this._refFavorite.value?.value ?? undefined) as | MediaFilterCoreFavoriteSelection | undefined, - where: this._refWhere.value?.value, - what: this._refWhat.value?.value, - tags: this._refTags.value?.value, + where: this._refWhere.value?.value ?? undefined, + what: this._refWhat.value?.value ?? undefined, + tags: this._refTags.value?.value ?? undefined, }, ); }; @@ -119,14 +122,11 @@ class FrigateCardMediaFilter extends ScopedRegistryHost(LitElement) { await valueChange(); }; - if (!this.cameraManager || !this.view) { + if (!this.cameraManager || !this.viewManagerEpoch) { return; } - const controls = this._mediaFilterController.getControlsToShow( - this.cameraManager, - this.view, - ); + const controls = this._mediaFilterController.getControlsToShow(this.cameraManager); const defaults = this._mediaFilterController.getDefaults(); const whatOptions = this._mediaFilterController.getWhatOptions(); const tagsOptions = this._mediaFilterController.getTagsOptions(); diff --git a/src/components/select.ts b/src/components/select.ts index 3a1bca79..94393e96 100644 --- a/src/components/select.ts +++ b/src/components/select.ts @@ -31,7 +31,7 @@ export class FrigateCardSelect extends ScopedRegistryHost(LitElement) { public options?: SelectOption[]; @property({ attribute: false, hasChanged: contentsChanged }) - public value?: SelectValues; + public value: SelectValues | null = null; @property({ attribute: false, hasChanged: contentsChanged }) public initialValue?: SelectValues; @@ -56,7 +56,7 @@ export class FrigateCardSelect extends ScopedRegistryHost(LitElement) { }; public reset(): void { - this.value = undefined; + this.value = null; } // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -66,8 +66,15 @@ export class FrigateCardSelect extends ScopedRegistryHost(LitElement) { // the change event even if the value has not actually changed. Prevent that // from propagating upwards. if (value !== undefined && !isEqual(this.value, value)) { + const initialValueSet = this.value === null; this.value = value; - dispatchFrigateCardEvent(this, 'select:change', value); + + // The underlying gr-select element will call on the first first value set + // (even when the user has not interacted with the control). Do not + // dispatch events for this. + if (!initialValueSet) { + dispatchFrigateCardEvent(this, 'select:change', value); + } } } diff --git a/src/components/surround.ts b/src/components/surround.ts index 45ee50f1..c48b5c7b 100644 --- a/src/components/surround.ts +++ b/src/components/surround.ts @@ -8,6 +8,8 @@ import { } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { CameraManager } from '../camera-manager/manager.js'; +import { RemoveContextViewModifier } from '../card-controller/view/modifiers/remove-context.js'; +import { ViewManagerEpoch } from '../card-controller/view/types.js'; import { CardWideConfig, MiniTimelineControlConfig, @@ -16,7 +18,6 @@ import { import basicBlockStyle from '../scss/basic-block.scss'; import { ExtendedHomeAssistant } from '../types.js'; import { contentsChanged, dispatchFrigateCardEvent } from '../utils/basic.js'; -import { View } from '../view/view.js'; import './surround-basic.js'; import { ThumbnailCarouselTap } from './thumbnail-carousel.js'; @@ -26,7 +27,7 @@ export class FrigateCardSurround extends LitElement { public hass?: ExtendedHomeAssistant; @property({ attribute: false }) - public view?: Readonly; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false, hasChanged: contentsChanged }) public thumbnailConfig?: ThumbnailsControlConfig; @@ -60,42 +61,47 @@ export class FrigateCardSurround extends LitElement { // Only reset the timeline cameraIDs when the media or display mode // materially changes (and not on every view change, since the view will // change frequently when the user is scrubbing video). - const oldView = changedProperties.get('view'); + const view = this.viewManagerEpoch?.manager.getView(); if ( - changedProperties.has('view') && - (View.isMajorMediaChange(oldView, this.view) || - oldView.displayMode !== this.view?.displayMode) + changedProperties.has('viewManagerEpoch') && + (this.viewManagerEpoch?.manager.hasMajorMediaChange( + this.viewManagerEpoch?.oldView, + ) || + this.viewManagerEpoch?.oldView?.displayMode !== view?.displayMode) ) { this._cameraIDsForTimeline = this._getCameraIDsForTimeline() ?? undefined; } } protected _getCameraIDsForTimeline(): Set | null { - if (!this.view || !this.cameraManager) { + const view = this.viewManagerEpoch?.manager.getView(); + if (!view || !this.cameraManager) { return null; } - if (this.view.is('live')) { + + if (view.is('live')) { const capabilitySearch = { anyCapabilities: ['clips' as const, 'snapshots' as const, 'recordings' as const], }; - if (this.view.supportsMultipleDisplayModes() && this.view.isGrid()) { + if (view.supportsMultipleDisplayModes() && view.isGrid()) { return this.cameraManager .getStore() .getCameraIDsWithCapability(capabilitySearch); } else { return this.cameraManager .getStore() - .getAllDependentCameras(this.view.camera, capabilitySearch); + .getAllDependentCameras(view.camera, capabilitySearch); } } - if (this.view.isViewerView()) { - return this.view.query?.getQueryCameraIDs() ?? null; + if (view.isViewerView()) { + return view.query?.getQueryCameraIDs() ?? null; } return null; } protected render(): TemplateResult | void { - if (!this.hass || !this.view) { + const view = this.viewManagerEpoch?.manager.getView(); + if (!this.hass || !view) { return; } @@ -122,27 +128,25 @@ export class FrigateCardSurround extends LitElement { .hass=${this.hass} .config=${this.thumbnailConfig} .cameraManager=${this.cameraManager} - .fadeThumbnails=${this.view.isViewerView()} - .view=${this.view} - .selected=${this.view.queryResults?.getSelectedIndex() ?? undefined} - @frigate-card:view:change=${(ev: CustomEvent) => changeDrawer(ev, 'close')} + .fadeThumbnails=${view.isViewerView()} + .viewManagerEpoch=${this.viewManagerEpoch} + .selected=${view.queryResults?.getSelectedIndex() ?? undefined} @frigate-card:thumbnail-carousel:tap=${( ev: CustomEvent, ) => { const media = ev.detail.queryResults.getSelectedResult(); if (media) { - this.view - ?.evolve({ + this.viewManagerEpoch?.manager.setViewByParameters({ + params: { view: 'media', queryResults: ev.detail.queryResults, ...(media.getCameraID() && { camera: media.getCameraID() }), - }) - .removeContext('timeline') - .removeContext('mediaViewer') - // Send the view change from the source of the tap event, so - // the view change will be caught by the handler above (to - // close the drawer). - .dispatchChangeEvent(ev.composedPath()[0]); + }, + modifiers: [ + new RemoveContextViewModifier(['timeline', 'mediaViewer']), + ], + }); + changeDrawer(ev, 'close'); } }} > @@ -152,8 +156,8 @@ export class FrigateCardSurround extends LitElement { ? html` ; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public cameraManager?: CameraManager; @@ -62,13 +62,13 @@ export class FrigateCardThumbnailCarousel extends LitElement { 'cameraManager', 'config', 'transitionEffect', - 'view', + 'viewManagerEpoch', ] as const; if (renderProperties.some((prop) => changedProps.has(prop))) { this._thumbnailSlides = this._renderSlides(); } - if (changedProps.has('view')) { + if (changedProps.has('viewManagerEpoch')) { this.style.setProperty( '--frigate-card-carousel-thumbnail-opacity', !this.fadeThumbnails || this._getSelectedSlide() === null ? '1.0' : '0.4', @@ -76,16 +76,19 @@ export class FrigateCardThumbnailCarousel extends LitElement { } } - protected _getSelectedSlide(view?: View): number | null { - return (view ?? this.view)?.queryResults?.getSelectedIndex() ?? null; + protected _getSelectedSlide(): number | null { + return ( + this.viewManagerEpoch?.manager.getView()?.queryResults?.getSelectedIndex() ?? null + ); } protected _renderSlides(): TemplateResult[] { const slides: TemplateResult[] = []; - const seekTarget = this.view?.context?.mediaViewer?.seek; + const view = this.viewManagerEpoch?.manager.getView(); + const seekTarget = view?.context?.mediaViewer?.seek; const selectedIndex = this._getSelectedSlide(); - for (const media of this.view?.queryResults?.getResults() ?? []) { + for (const media of view?.queryResults?.getResults() ?? []) { const index = slides.length; const classes = { embla__slide: true, @@ -98,19 +101,20 @@ export class FrigateCardThumbnailCarousel extends LitElement { .cameraManager=${this.cameraManager} .hass=${this.hass} .media=${media} - .view=${this.view} + .viewManagerEpoch=${this.viewManagerEpoch} .seek=${seekTarget && media.includesTime(seekTarget) ? seekTarget : undefined} ?details=${!!this.config?.show_details} ?show_favorite_control=${this.config?.show_favorite_control} ?show_timeline_control=${this.config?.show_timeline_control} ?show_download_control=${this.config?.show_download_control} @click=${(ev: Event) => { - if (this.view && this.view.queryResults) { + const view = this.viewManagerEpoch?.manager.getView(); + if (view && view.queryResults) { dispatchFrigateCardEvent( this, 'thumbnail-carousel:tap', { - queryResults: this.view.queryResults.clone().selectIndex(index), + queryResults: view.queryResults.clone().selectIndex(index), }, ); } diff --git a/src/components/thumbnail.ts b/src/components/thumbnail.ts index 61f4464f..6a34dce4 100644 --- a/src/components/thumbnail.ts +++ b/src/components/thumbnail.ts @@ -1,3 +1,4 @@ +import { Task, TaskStatus } from '@lit-labs/task'; import { format } from 'date-fns'; import { CSSResult, @@ -9,11 +10,14 @@ import { } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; +import { CameraManager } from '../camera-manager/manager.js'; +import { ViewManagerEpoch } from '../card-controller/view/types.js'; import { localize } from '../localize/localize.js'; import thumbnailDetailsStyle from '../scss/thumbnail-details.scss'; import thumbnailFeatureEventStyle from '../scss/thumbnail-feature-event.scss'; import thumbnailFeatureRecordingStyle from '../scss/thumbnail-feature-recording.scss'; import thumbnailStyle from '../scss/thumbnail.scss'; +import type { ExtendedHomeAssistant } from '../types.js'; import { stopEventFromActivatingCardWideActions } from '../utils/action.js'; import { errorToConsole, @@ -21,17 +25,13 @@ import { getDurationString, prettifyTitle, } from '../utils/basic.js'; +import { downloadMedia } from '../utils/download.js'; import { renderTask } from '../utils/task.js'; import { createFetchThumbnailTask, FetchThumbnailTaskArgs } from '../utils/thumbnail.js'; -import { View } from '../view/view.js'; -import { Task, TaskStatus } from '@lit-labs/task'; - -import type { ExtendedHomeAssistant } from '../types.js'; -import { EventViewMedia, RecordingViewMedia, ViewMedia } from '../view/media.js'; -import { CameraManager } from '../camera-manager/manager.js'; import { ViewMediaClassifier } from '../view/media-classifier.js'; -import { downloadMedia } from '../utils/download.js'; +import { EventViewMedia, RecordingViewMedia, ViewMedia } from '../view/media.js'; import { dispatchFrigateCardErrorEvent } from './message.js'; +import { RemoveContextViewModifier } from '../card-controller/view/modifiers/remove-context.js'; // The minimum width of a thumbnail with details enabled. export const THUMBNAIL_DETAILS_WIDTH_MIN = 300; @@ -335,22 +335,22 @@ export class FrigateCardThumbnailDetailsRecording extends LitElement { @customElement('frigate-card-thumbnail') export class FrigateCardThumbnail extends LitElement { - // Performance: During timeline scrubbing, hass may be updated - // continuously. As it is not needed for the thumbnail rendering itself, it - // does not trigger a re-render. The HomeAssistant object may be required for - // thumbnail signing (after initial signing the thumbnail is stored in a data - // URL, so the signing will not expire). + // Performance: During timeline scrubbing, hass may be updated continuously. + // As it is not needed for the thumbnail rendering itself, it does not trigger + // a re-render. The HomeAssistant object may be required for thumbnail signing + // (after initial signing the thumbnail is stored in a data URL, so the + // signing will not expire). public hass?: ExtendedHomeAssistant; // Performance: During timeline scrubbing, the view will be updated // continuously. As it is not needed for the thumbnail rendering itself, it // does not trigger a re-render. - public view?: Readonly; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public cameraManager?: CameraManager; - @property({ attribute: true }) + @property({ attribute: false }) public media?: ViewMedia; @property({ attribute: true, type: Boolean }) @@ -467,18 +467,19 @@ export class FrigateCardThumbnail extends LitElement { title=${localize('thumbnail.timeline')} @click=${(ev: Event) => { stopEventFromActivatingCardWideActions(ev); - if (!this.view || !this.media) { + if (!this.viewManagerEpoch || !this.media) { return; } - this.view - .evolve({ + this.viewManagerEpoch.manager.setViewByParameters({ + params: { view: 'timeline', - queryResults: this.view.queryResults - ?.clone() + queryResults: this.viewManagerEpoch?.manager + .getView() + ?.queryResults?.clone() .selectResultIfFound((media) => media === this.media), - }) - .removeContext('timeline') - .dispatchChangeEvent(this); + }, + modifiers: [new RemoveContextViewModifier(['timeline'])], + }); }} >` : ''} diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 84eb0a20..502ac0cc 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -1,14 +1,14 @@ import { add, differenceInSeconds, sub } from 'date-fns'; import { CSSResultGroup, - html, LitElement, PropertyValues, TemplateResult, + html, unsafeCSS, } from 'lit'; import { customElement, property, state } from 'lit/decorators.js'; -import { createRef, ref, Ref } from 'lit/directives/ref.js'; +import { Ref, createRef, ref } from 'lit/directives/ref.js'; import isEqual from 'lodash-es/isEqual'; import throttle from 'lodash-es/throttle'; import { ViewContext } from 'view'; @@ -26,6 +26,8 @@ import { CameraManager } from '../camera-manager/manager'; import { rangesOverlap } from '../camera-manager/range'; import { MediaQuery } from '../camera-manager/types'; import { convertRangeToCacheFriendlyTimes } from '../camera-manager/utils/range-to-cache-friendly'; +import { MergeContextViewModifier } from '../card-controller/view/modifiers/merge-context'; +import { ViewManagerEpoch } from '../card-controller/view/types'; import { FrigateCardTimelineItem, TimelineDataSource, @@ -33,11 +35,11 @@ import { import { CameraConfig, CardWideConfig, - frigateCardConfigDefaults, FrigateCardView, ThumbnailsControlBaseConfig, TimelineCoreConfig, TimelinePanMode, + frigateCardConfigDefaults, } from '../config/types'; import { localize } from '../localize/localize'; import timelineCoreStyle from '../scss/timeline-core.scss'; @@ -51,10 +53,7 @@ import { isTruthy, setOrRemoveAttribute, } from '../utils/basic'; -import { - executeMediaQueryForViewWithErrorDispatching, - findBestMediaIndex, -} from '../utils/media-to-view'; +import { findBestMediaIndex } from '../utils/find-best-media-index'; import { ViewMedia } from '../view/media'; import { ViewMediaClassifier } from '../view/media-classifier'; import { @@ -67,7 +66,7 @@ import { MediaQueriesType, } from '../view/media-queries-classifier'; import { MediaQueriesResults } from '../view/media-queries-results'; -import { View } from '../view/view'; +import { mergeViewContext } from '../view/view'; import './date-picker.js'; import { DatePickerEvent, FrigateCardDatePicker } from './date-picker.js'; import './thumbnail.js'; @@ -107,7 +106,7 @@ interface ThumbnailDataRequest { cameraManager?: CameraManager; cameraConfig?: CameraConfig; media?: ViewMedia; - view?: View; + viewManagerEpoch?: ViewManagerEpoch; } class ThumbnailDataRequestEvent extends CustomEvent {} @@ -115,7 +114,7 @@ class ThumbnailDataRequestEvent extends CustomEvent {} const TIMELINE_TARGET_BAR_ID = 'target_bar'; /** - * A simgple thumbnail wrapper class for use in the timeline where LIT data + * A simgple thumbnail wrapper class for use in the timeline where Lit data * bindings are not available. */ @customElement('frigate-card-timeline-thumbnail') @@ -160,7 +159,7 @@ export class FrigateCardTimelineThumbnail extends LitElement { !dataRequest.cameraManager || !dataRequest.cameraConfig || !dataRequest.media || - !dataRequest.view + !dataRequest.viewManagerEpoch ) { return html``; } @@ -169,7 +168,7 @@ export class FrigateCardTimelineThumbnail extends LitElement { .hass=${dataRequest.hass} .cameraManager=${dataRequest.cameraManager} .media=${dataRequest.media} - .view=${dataRequest.view} + .viewManagerEpoch=${dataRequest.viewManagerEpoch} ?details=${this.details} > `; @@ -182,12 +181,12 @@ export class FrigateCardTimelineCore extends LitElement { public hass?: ExtendedHomeAssistant; @property({ attribute: false }) - public view?: Readonly; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false, hasChanged: contentsChanged }) public timelineConfig?: TimelineCoreConfig; - @property({ attribute: true, type: Boolean }) + @property({ attribute: false }) public thumbnailConfig?: ThumbnailsControlBaseConfig; // Whether or not this is a mini-timeline (in mini-mode the component takes a @@ -269,11 +268,11 @@ export class FrigateCardTimelineCore extends LitElement { request.detail.cameraConfig = cameraConfig; request.detail.cameraManager = this.cameraManager; request.detail.media = media; - request.detail.view = this.view; + request.detail.viewManagerEpoch = this.viewManagerEpoch; } protected render(): TemplateResult | void { - if (!this.hass || !this.view || !this.timelineConfig || !this.cameraIDs?.size) { + if (!this.hass || !this.timelineConfig || !this.cameraIDs?.size) { return; } @@ -383,6 +382,7 @@ export class FrigateCardTimelineCore extends LitElement { return; } + const view = this.viewManagerEpoch?.manager.getView(); const panMode = this._getEffectivePanMode(); const targetBarOn = this._shouldSupportSeeking() && @@ -392,7 +392,7 @@ export class FrigateCardTimelineCore extends LitElement { const item = this._timelineSource?.dataset?.get(id); return ( panMode !== 'seek-in-camera' || - item?.media?.getCameraID() === this.view?.camera, + item?.media?.getCameraID() === view?.camera, item && item.start && item.end && @@ -450,14 +450,15 @@ export class FrigateCardTimelineCore extends LitElement { targetTime: Date, properties: TimelineRangeChange, ): Promise { - const results = this.view?.queryResults; + const view = this.viewManagerEpoch?.manager.getView(); + const results = view?.queryResults; const media = results?.getResults(); const panMode = this._getEffectivePanMode(); if ( !media || !results || !this._timeline || - !this.view || + !view || !this.hass || !this.cameraManager || panMode === 'pan' @@ -473,7 +474,7 @@ export class FrigateCardTimelineCore extends LitElement { .clone() .resetSelectedResult() .selectBestResult( - (mediaArray) => findBestMediaIndex(mediaArray, targetTime, this.view?.camera), + (mediaArray) => findBestMediaIndex(mediaArray, targetTime, view?.camera), { allCameras: true, main: true, @@ -484,9 +485,9 @@ export class FrigateCardTimelineCore extends LitElement { .clone() .resetSelectedResult() .selectBestResult((mediaArray) => findBestMediaIndex(mediaArray, targetTime), { - cameraID: this.view.camera, + cameraID: view.camera, }) - .promoteCameraSelectionToMainSelection(this.view.camera); + .promoteCameraSelectionToMainSelection(view.camera); } else if (panMode === 'seek-in-media') { newResults = results; } @@ -495,20 +496,23 @@ export class FrigateCardTimelineCore extends LitElement { ? targetTime >= new Date() ? 'live' : 'media' - : this.view.view; + : view.view; const selectedCamera = newResults?.getSelectedResult()?.getCameraID(); - this.view - .evolve({ + + this.viewManagerEpoch?.manager.setViewByParameters({ + params: { ...(selectedCamera && { camera: selectedCamera }), view: desiredView, queryResults: newResults, - }) // Whether or not to set the timeline window. - .mergeInContext({ - ...(canSeek && { mediaViewer: { seek: targetTime } }), - ...this._getTimelineContext({ start: properties.start, end: properties.end }), - }) - .dispatchChangeEvent(this); + }, + modifiers: [ + new MergeContextViewModifier({ + ...(canSeek && { mediaViewer: { seek: targetTime } }), + ...this._getTimelineContext({ start: properties.start, end: properties.end }), + }), + ], + }); } protected _getEffectivePanMode(): TimelinePanMode { @@ -533,22 +537,18 @@ export class FrigateCardTimelineCore extends LitElement { stopEventFromActivatingCardWideActions(properties.event); } + const view = this.viewManagerEpoch?.manager.getView(); + if ( this._ignoreClick || - !this.hass || - !this._timeline || - !this.view || - !this.cameraManager || - !this.cardWideConfig || - !this.cameraIDs || - !this.cameraIDs.size || + !view || + !this.viewManagerEpoch || !this._timelineSource || !properties.what ) { return; } - let view: View | null = null; let drawerAction: 'open' | 'close' = 'close'; if ( @@ -558,29 +558,35 @@ export class FrigateCardTimelineCore extends LitElement { ) { const query = this._createMediaQueries('recording'); if (query) { - view = await executeMediaQueryForViewWithErrorDispatching( - this, - this.cameraManager, - this.view, - query, - { - targetView: 'recording', - targetTime: properties.time, - select: 'time', + await this.viewManagerEpoch?.manager.setViewByParametersWithExistingQuery({ + baseView: view, + params: { view: 'recording', query: query }, + queryExecutorOptions: { + selectResult: { + time: { + time: properties.time, + }, + }, }, - ); + }); } } else if (properties.item && properties.what === 'item') { const cameraID = String(properties.group); + const id = String(properties.item); + const criteria = { main: true, - ...(cameraID && this.view.isGrid() && { cameraID: cameraID }), + ...(cameraID && view.isGrid() && { cameraID: cameraID }), }; - const newResults = this.view.queryResults + const newResults = view.queryResults ?.clone() .resetSelectedResult() .selectResultIfFound((media) => media.getID() === properties.item, criteria); + const context: ViewContext = mergeViewContext(this._getTimelineContext(), { + mediaViewer: { seek: properties.time }, + }); + if (!newResults || !newResults.hasSelectedResult()) { // This can happen in a few situations: // - If this is a recording query (with recorded hours) and an event is @@ -589,36 +595,34 @@ export class FrigateCardTimelineCore extends LitElement { // gallery (i.e. any case where the thumbnails may not be match the // events on the timeline, e.g. in the snapshots viewer but // mini-timeline showing all media). - const fullEventView = await this._createViewWithMediaQueries( - this._createMediaQueries('event'), - { - selectedItem: properties.item, - targetView: 'media', - }, - ); - if (fullEventView?.queryResults?.hasResults()) { - view = fullEventView; + const query = this._createMediaQueries('event'); + if (query) { + await this.viewManagerEpoch?.manager.setViewByParametersWithExistingQuery({ + params: { view: 'media', query: query }, + queryExecutorOptions: { + selectResult: { + id: id, + }, + rejectResults: (results) => !results.hasResults(), + }, + modifiers: [new MergeContextViewModifier(context)], + }); } } else { - view = this.view.evolve({ - queryResults: newResults, - view: this.itemClickAction === 'play' ? 'media' : this.view.view, + this.viewManagerEpoch.manager.setViewByParameters({ + params: { + queryResults: newResults, + view: this.itemClickAction === 'play' ? 'media' : view.view, + }, + modifiers: [new MergeContextViewModifier(context)], }); } - if (view?.queryResults?.hasResults()) { - view.mergeInContext({ mediaViewer: { seek: properties.time } }); - } - view?.mergeInContext(this._getTimelineContext()); - - if (this.itemClickAction === 'select' && view) { + if (this.itemClickAction === 'select') { drawerAction = 'open'; } } - if (view) { - view.dispatchChangeEvent(this); - } dispatchFrigateCardEvent(this, `thumbnails:${drawerAction}`); this._ignoreClick = false; @@ -648,10 +652,11 @@ export class FrigateCardTimelineCore extends LitElement { event: Event & { additionalEvent: string }; }): Promise { this._removeTargetBar(); + const view = this.viewManagerEpoch?.manager.getView(); if ( !this._timeline || - !this.view || + !view || // When in mini mode, something else is in charge of the primary media // population (e.g. the live view), in this case only act when the user // themselves are interacting with the timeline. @@ -662,23 +667,34 @@ export class FrigateCardTimelineCore extends LitElement { await this._timelineSource?.refresh(this._getPrefetchWindow(properties)); - const queryType = MediaQueriesClassifier.getQueriesType(this.view.query); + const queryType = MediaQueriesClassifier.getQueriesType(view.query); if (!queryType) { return; } const mediaQuery = this._createMediaQueries(queryType); - const newView = await this._createViewWithMediaQueries(mediaQuery); - // Specifically avoid dispatching new results on range change unless there - // is something to be gained by doing so. Example usecase: On initial view - // load in mini timeline mode, the first 50 events are fetched -- the - // first drag of the timeline should not dispatch new results unless - // something is actually useful (as otherwise it creates a visible - // 'flicker' for the user as the viewer reloads all the media). - const newResults = newView?.queryResults; - if (newView && newResults && !this.view.queryResults?.isSupersetOf(newResults)) { - newView?.mergeInContext(this._getTimelineContext())?.dispatchChangeEvent(this); - } + await this.viewManagerEpoch?.manager.setViewByParametersWithExistingQuery({ + params: { + query: mediaQuery, + }, + queryExecutorOptions: { + // Reject the new results unless there is something to be gained (i.e. they + // are not a subset of the existing results). Example usecase: On initial + // view load in mini timeline mode, the first 50 events are fetched -- the + // first drag of the timeline should not dispatch new results unless + // something is actually useful (as otherwise it creates a visible 'flicker' + // for the user as the viewer reloads all the media). + rejectResults: (results) => !!view.queryResults?.isSupersetOf(results), + selectResult: { + id: + this.viewManagerEpoch?.manager + .getView() + ?.queryResults?.getSelectedResult() + ?.getID() ?? undefined, + }, + }, + modifiers: [new MergeContextViewModifier(this._getTimelineContext())], + }); } protected _createMediaQueries( @@ -706,46 +722,6 @@ export class FrigateCardTimelineCore extends LitElement { return null; } - protected async _createViewWithMediaQueries( - query: MediaQueries | null, - options?: { - targetView?: FrigateCardView; - selectedItem?: IdType; - }, - ): Promise { - if (!this.hass || !this.cameraManager || !this.view || !query) { - return null; - } - const view = await executeMediaQueryForViewWithErrorDispatching( - this, - this.cameraManager, - this.view, - query, - { - targetView: options?.targetView, - select: 'latest', - }, - ); - if (!view) { - return null; - } - if (options?.selectedItem) { - view.queryResults?.selectResultIfFound( - (media) => media.getID() === options.selectedItem, - ); - } else { - // If not asked to select a new item, persist the currently selected item - // if possible. - const currentlySelectedResult = this.view.queryResults?.getSelectedResult(); - if (currentlySelectedResult) { - view.queryResults?.selectResultIfFound( - (media) => media.getID() === currentlySelectedResult.getID(), - ); - } - } - return view; - } - /** * Build the visjs dataset to render on the timeline. * @returns The dataset. @@ -937,10 +913,11 @@ export class FrigateCardTimelineCore extends LitElement { } protected _getAllSelectedMediaIDsFromView(): IdType[] { + const view = this.viewManagerEpoch?.manager.getView(); return ( - this.view?.queryResults?.getMultipleSelectedResults({ + view?.queryResults?.getMultipleSelectedResults({ main: true, - ...(this.view.isGrid() && { allCameras: true }), + ...(view.isGrid() && { allCameras: true }), }) ?? [] ) .filter((media) => ViewMediaClassifier.isEvent(media)) @@ -952,7 +929,8 @@ export class FrigateCardTimelineCore extends LitElement { * Update the timeline from the view object. */ protected async _updateTimelineFromView(): Promise { - if (!this.view || !this.timelineConfig || !this._timelineSource || !this._timeline) { + const view = this.viewManagerEpoch?.manager.getView(); + if (!view || !this.timelineConfig || !this._timelineSource || !this._timeline) { return; } @@ -965,7 +943,7 @@ export class FrigateCardTimelineCore extends LitElement { // perfectly center on the media. let desiredWindow = timelineWindow; - const media = this.view.queryResults?.getSelectedResult(); + const media = view.queryResults?.getSelectedResult(); const mediaStartTime = media?.getStartTime() ?? null; const mediaEndTime = media?.getEndTime() ?? null; const mediaIsEvent = media ? ViewMediaClassifier.isEvent(media) : false; @@ -976,7 +954,7 @@ export class FrigateCardTimelineCore extends LitElement { // range effectively starts/ends at the same time. { start: mediaStartTime, end: mediaEndTime ?? mediaStartTime } : null; - const context = this.view.context?.timeline; + const context = view.context?.timeline; if (context && context.window) { desiredWindow = context.window; @@ -1048,7 +1026,7 @@ export class FrigateCardTimelineCore extends LitElement { // Also don't generate thumbnails in mini-timelines (they will already have // been generated). - const queryType = MediaQueriesClassifier.getQueriesType(this.view.query); + const queryType = MediaQueriesClassifier.getQueriesType(view.query); if (!queryType) { return; } @@ -1062,15 +1040,31 @@ export class FrigateCardTimelineCore extends LitElement { freshMediaQuery && !this._alreadyHasAcceptableMediaQuery(freshMediaQuery) ) { - (await this._createViewWithMediaQueries(freshMediaQuery)) - ?.mergeInContext(this._getTimelineContext(desiredWindow)) - .dispatchChangeEvent(this); + const currentlySelectedResult = this.viewManagerEpoch?.manager + .getView() + ?.queryResults?.getSelectedResult(); + + await this.viewManagerEpoch?.manager.setViewByParametersWithExistingQuery({ + params: { + query: freshMediaQuery, + }, + queryExecutorOptions: { + selectResult: { + id: currentlySelectedResult?.getID() ?? undefined, + }, + }, + modifiers: [ + new MergeContextViewModifier(this._getTimelineContext(desiredWindow)), + ], + }); } } protected _alreadyHasAcceptableMediaQuery(freshMediaQuery: MediaQueries): boolean { - const currentQueries = this.view?.query?.getQueries(); - const currentResultTimestamp = this.view?.queryResults?.getResultsTimestamp(); + const view = this.viewManagerEpoch?.manager.getView(); + + const currentQueries = view?.query?.getQueries(); + const currentResultTimestamp = view?.queryResults?.getResultsTimestamp(); return ( !!this.cameraManager && @@ -1089,10 +1083,11 @@ export class FrigateCardTimelineCore extends LitElement { * @returns The TimelineViewContext object. */ protected _getTimelineContext(window?: TimelineWindow): ViewContext { + const view = this.viewManagerEpoch?.manager.getView(); const newWindow = window ?? this._timeline?.getWindow(); return { timeline: { - ...this.view?.context?.timeline, + ...view?.context?.timeline, ...(newWindow && { window: newWindow }), }, }; @@ -1225,7 +1220,7 @@ export class FrigateCardTimelineCore extends LitElement { // `this._timeline.setwindow()` being entirely ignored. Example case: // Clicking the timeline control on a recording thumbnail. window.requestAnimationFrame(this._updateTimelineFromView.bind(this)); - } else if (changedProperties.has('view')) { + } else if (changedProperties.has('viewManagerEpoch')) { this._updateTimelineFromView(); } } diff --git a/src/components/timeline.ts b/src/components/timeline.ts index 08f737e6..4e0c11e9 100644 --- a/src/components/timeline.ts +++ b/src/components/timeline.ts @@ -1,10 +1,10 @@ import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { CameraManager } from '../camera-manager/manager'; +import { ViewManagerEpoch } from '../card-controller/view/types'; import { CardWideConfig, TimelineConfig } from '../config/types'; import basicBlockStyle from '../scss/basic-block.scss'; import { ExtendedHomeAssistant } from '../types'; -import { View } from '../view/view'; import './surround.js'; import './timeline-core.js'; @@ -14,7 +14,7 @@ export class FrigateCardTimeline extends LitElement { public hass?: ExtendedHomeAssistant; @property({ attribute: false }) - public view?: Readonly; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public timelineConfig?: TimelineConfig; @@ -33,7 +33,7 @@ export class FrigateCardTimeline extends LitElement { return html` , + view?: Readonly | null, baseConfig?: TitleControlConfig, ): TitleControlConfig | null => { if (!baseConfig && view?.isGrid()) { diff --git a/src/components/viewer.ts b/src/components/viewer.ts index d8deceda..3c79774b 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -11,6 +11,8 @@ import { guard } from 'lit/directives/guard.js'; import { ifDefined } from 'lit/directives/if-defined.js'; import { createRef, Ref, ref } from 'lit/directives/ref.js'; import { CameraManager } from '../camera-manager/manager.js'; +import { RemoveContextPropertyViewModifier } from '../card-controller/view/modifiers/remove-context-property.js'; +import { ViewManagerEpoch } from '../card-controller/view/types.js'; import { MediaGridSelected } from '../components-lib/media-grid-controller.js'; import { ZoomSettingsObserved } from '../components-lib/zoom/types.js'; import { handleZoomSettingsObservedEvent } from '../components-lib/zoom/zoom-view-context.js'; @@ -41,7 +43,6 @@ import { mayHaveAudio } from '../utils/audio.js'; import { aspectRatioToString, contentsChanged, - errorToConsole, setOrRemoveAttribute, } from '../utils/basic.js'; import { CarouselSelected } from '../utils/embla/carousel-controller.js'; @@ -58,10 +59,6 @@ import { dispatchMediaVolumeChangeEvent, } from '../utils/media-info.js'; import { updateElementStyleFromMediaLayoutConfig } from '../utils/media-layout.js'; -import { - changeViewToRecentEventsForCameraAndDependents, - changeViewToRecentRecordingForCameraAndDependents, -} from '../utils/media-to-view.js'; import { hideMediaControlsTemporarily, MEDIA_LOAD_CONTROLS_HIDE_SECONDS, @@ -71,9 +68,7 @@ import { import { screenshotMedia } from '../utils/screenshot.js'; import { ViewMediaClassifier } from '../view/media-classifier'; import { MediaQueriesClassifier } from '../view/media-queries-classifier'; -import { MediaQueriesResults } from '../view/media-queries-results.js'; import { VideoContentType, ViewMedia } from '../view/media.js'; -import { View } from '../view/view.js'; import type { EmblaCarouselPlugins } from './carousel.js'; import './next-prev-control.js'; import './ptz'; @@ -110,7 +105,7 @@ export class FrigateCardViewer extends LitElement { public hass?: ExtendedHomeAssistant; @property({ attribute: false }) - public view?: Readonly; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public viewerConfig?: ViewerConfig; @@ -127,7 +122,7 @@ export class FrigateCardViewer extends LitElement { protected render(): TemplateResult | void { if ( !this.hass || - !this.view || + !this.viewManagerEpoch || !this.viewerConfig || !this.cameraManager || !this.cardWideConfig @@ -135,55 +130,20 @@ export class FrigateCardViewer extends LitElement { return; } - if (!this.view.queryResults?.hasResults()) { - // If the query is not specified, the view must tell us which mediaType to - // search for. When the query *is* specified, the view is not required to - // indicate the media type (e.g. the mixed 'media' view from the - // timeline). - const mediaType = this.view.getDefaultMediaType(); - if (!mediaType) { - // Directly render an error message (instead of dispatching it upwards) - // to preserve the mini-timeline if the user pans into an area with no - // media. - return renderMessage({ - type: 'info', - message: localize('common.no_media'), - icon: 'mdi:multimedia', - }); - } - - if (mediaType === 'recordings') { - changeViewToRecentRecordingForCameraAndDependents( - this, - this.cameraManager, - this.cardWideConfig, - this.view, - { - allCameras: this.view.isGrid(), - targetView: 'recording', - useCache: false, - }, - ); - } else { - changeViewToRecentEventsForCameraAndDependents( - this, - this.cameraManager, - this.cardWideConfig, - this.view, - { - allCameras: this.view.isGrid(), - targetView: 'media', - eventsMediaType: mediaType, - useCache: false, - }, - ); - } - return renderProgressIndicator({ cardWideConfig: this.cardWideConfig }); + if (!this.viewManagerEpoch.manager.getView()?.queryResults?.hasResults()) { + // Directly render an error message (instead of dispatching it upwards) + // to preserve the mini-timeline if the user pans into an area with no + // media. + return renderMessage({ + type: 'info', + message: localize('common.no_media'), + icon: 'mdi:multimedia', + }); } return html` ; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public viewFilterCameraID?: string; @@ -227,6 +187,9 @@ export class FrigateCardViewerCarousel extends LitElement { @property({ attribute: false }) public cameraManager?: CameraManager; + @property({ attribute: false }) + public showControls = true; + @state() protected _selected = 0; @@ -241,12 +204,14 @@ export class FrigateCardViewerCarousel extends LitElement { updated(changedProperties: PropertyValues): void { super.updated(changedProperties); - if (changedProperties.has('view')) { - const oldView = changedProperties.get('view') as View | undefined; + if (changedProperties.has('viewManagerEpoch')) { // Seek into the video if the seek time has changed (this is also called // on media load, since the media may or may not have been loaded at // this point). - if (this.view?.context?.mediaViewer !== oldView?.context?.mediaViewer) { + if ( + this.viewManagerEpoch?.manager.getView()?.context?.mediaViewer !== + this.viewManagerEpoch?.oldView?.context?.mediaViewer + ) { this._seekHandler(); } } @@ -324,7 +289,9 @@ export class FrigateCardViewerCarousel extends LitElement { } protected _setViewSelectedIndex(index: number): void { - if (!this._media) { + const view = this.viewManagerEpoch?.manager.getView(); + + if (!this._media || !view) { return; } @@ -335,7 +302,7 @@ export class FrigateCardViewerCarousel extends LitElement { return; } - const newResults = this.view?.queryResults + const newResults = view?.queryResults ?.clone() .selectIndex(index, this.viewFilterCameraID); if (!newResults) { @@ -345,15 +312,14 @@ export class FrigateCardViewerCarousel extends LitElement { .getSelectedResult(this.viewFilterCameraID) ?.getCameraID(); - this.view - ?.evolve({ + this.viewManagerEpoch?.manager.setViewByParameters({ + params: { queryResults: newResults, - // Always change the camera to the owner of the selected media. ...(cameraID && { camera: cameraID }), - }) - .removeContextProperty('mediaViewer', 'seek') - .dispatchChangeEvent(this); + }, + modifiers: [new RemoveContextPropertyViewModifier('mediaViewer', 'seek')], + }); } /** @@ -395,17 +361,13 @@ export class FrigateCardViewerCarousel extends LitElement { return slides; } - /** - * Called when an update will occur. - * @param changedProps The changed properties - */ protected willUpdate(changedProps: PropertyValues): void { - if (changedProps.has('view')) { - const newMedia = - this.view?.queryResults?.getResults(this.viewFilterCameraID) ?? null; + if (changedProps.has('viewManagerEpoch')) { + const view = this.viewManagerEpoch?.manager.getView(); + const newMedia = view?.queryResults?.getResults(this.viewFilterCameraID) ?? null; const newSelected = - this.view?.queryResults?.getSelectedIndex(this.viewFilterCameraID) ?? 0; - const newSeek = this.view?.context?.mediaViewer?.seek; + view?.queryResults?.getSelectedIndex(this.viewFilterCameraID) ?? 0; + const newSeek = view?.context?.mediaViewer?.seek; if (newMedia !== this._media || newSelected !== this._selected || !newSeek) { setOrRemoveAttribute(this, false, 'unseekable'); @@ -449,8 +411,9 @@ export class FrigateCardViewerCarousel extends LitElement { selectedMedia.getCameraID(), ); + const view = this.viewManagerEpoch?.manager.getView(); const titleConfig = getDefaultTitleConfigForView( - this.view, + view, this.viewerConfig?.controls.title, ); @@ -474,38 +437,42 @@ export class FrigateCardViewerCarousel extends LitElement { this._player = null; }} > - { - scroll('previous'); - stopEventFromActivatingCardWideActions(ev); - }} - > - ${guard([this._media, this.view], () => this._getSlides())} - { - scroll('next'); - stopEventFromActivatingCardWideActions(ev); - }} - > + ${this.showControls + ? html` { + scroll('previous'); + stopEventFromActivatingCardWideActions(ev); + }} + >` + : ''} + ${guard([this._media, view], () => this._getSlides())} + ${this.showControls + ? html` { + scroll('next'); + stopEventFromActivatingCardWideActions(ev); + }} + >` + : ''} - ${this.view + ${view ? html` ` : ''} @@ -530,7 +497,8 @@ export class FrigateCardViewerCarousel extends LitElement { * Fire a media show event when a slide is selected. */ protected async _seekHandler(): Promise { - const seek = this.view?.context?.mediaViewer?.seek; + const view = this.viewManagerEpoch?.manager.getView(); + const seek = view?.context?.mediaViewer?.seek; if (!this.hass || !seek || !this._media || !this._player) { return; } @@ -556,14 +524,15 @@ export class FrigateCardViewerCarousel extends LitElement { } protected _renderMediaItem(media: ViewMedia): TemplateResult | null { - if (!this.hass || !this.view || !this.viewerConfig) { + const view = this.viewManagerEpoch?.manager.getView(); + if (!this.hass || !view || !this.viewerConfig) { return null; } return html`
      ; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public viewerConfig?: ViewerConfig; @@ -600,66 +569,64 @@ export class FrigateCardViewerGrid extends LitElement { public cameraManager?: CameraManager; protected _renderCarousel(filterCamera?: string): TemplateResult { + const selectedCameraID = this.viewManagerEpoch?.manager.getView()?.camera; return html` `; } - protected _gridSelectCamera(cameraID: string, view?: View): void { - const newView = view ?? this.view; - const promotedQueryResults = newView?.queryResults - ?.clone() - .promoteCameraSelectionToMainSelection(cameraID); - newView - ?.evolve({ - camera: cameraID, - queryResults: promotedQueryResults, - }) - .dispatchChangeEvent(this); - } - protected willUpdate(changedProps: PropertyValues): void { - if (changedProps.has('view') && this._needsGrid()) { + if (changedProps.has('viewManagerEpoch') && this._needsGrid()) { import('./media-grid.js'); } } protected _needsGrid(): boolean { - const cameraIDs = this.view?.queryResults?.getCameraIDs(); + const view = this.viewManagerEpoch?.manager.getView(); + const cameraIDs = view?.queryResults?.getCameraIDs(); return ( - !!this.view?.isGrid() && - !!this.view?.supportsMultipleDisplayModes() && + !!view?.isGrid() && + !!view?.supportsMultipleDisplayModes() && (cameraIDs?.size ?? 0) > 1 ); } + protected _gridSelectCamera(cameraID: string): void { + const view = this.viewManagerEpoch?.manager.getView(); + this.viewManagerEpoch?.manager.setViewByParameters({ + params: { + camera: cameraID, + queryResults: view?.queryResults + ?.clone() + .promoteCameraSelectionToMainSelection(cameraID), + }, + }); + } + protected render(): TemplateResult { - const cameraIDs = this.view?.queryResults?.getCameraIDs(); + const view = this.viewManagerEpoch?.manager.getView(); + const cameraIDs = view?.queryResults?.getCameraIDs(); if (!cameraIDs || !this._needsGrid()) { return this._renderCarousel(); } return html` ) => this._gridSelectCamera(ev.detail.selected)} - @frigate-card:view:change=${(ev: CustomEvent) => { - ev.stopPropagation(); - const childView = ev.detail; - this._gridSelectCamera(childView.camera, childView); - }} > ${[...cameraIDs].map((cameraID) => this._renderCarousel(cameraID))} @@ -680,7 +647,7 @@ export class FrigateCardViewerProvider public hass?: ExtendedHomeAssistant; @property({ attribute: false }) - public view?: Readonly; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public media?: ViewMedia; @@ -788,21 +755,22 @@ export class FrigateCardViewerProvider * Dispatch a clip view that matches the current (snapshot) query. */ protected async _dispatchRelatedClipView(): Promise { + const view = this.viewManagerEpoch?.manager.getView(); if ( !this.hass || - !this.view || + !view || !this.cameraManager || !this.media || // If this specific media item has no clip, then do nothing (even if all // the other media items do). !ViewMediaClassifier.isEvent(this.media) || - !MediaQueriesClassifier.areEventQueries(this.view.query) + !MediaQueriesClassifier.areEventQueries(view.query) ) { return; } // Convert the query to a clips equivalent. - const clipQuery = this.view.query.clone(); + const clipQuery = view.query.clone(); clipQuery.convertToClipsQueries(); const queries = clipQuery.getQueries(); @@ -810,32 +778,18 @@ export class FrigateCardViewerProvider return; } - let mediaArray: ViewMedia[] | null; - try { - mediaArray = await this.cameraManager.executeMediaQueries(queries); - } catch (e) { - errorToConsole(e as Error); - return; - } - if (!mediaArray) { - return; - } - - const results = new MediaQueriesResults({ results: mediaArray }); - results.selectResultIfFound( - (clipMedia) => clipMedia.getID() === this.media?.getID(), - ); - if (!results.hasSelectedResult()) { - return; - } - - this.view - .evolve({ + await this.viewManagerEpoch?.manager.setViewByParametersWithExistingQuery({ + params: { view: 'media', query: clipQuery, - queryResults: results, - }) - .dispatchChangeEvent(this); + }, + queryExecutorOptions: { + selectResult: { + id: this.media.getID() ?? undefined, + }, + rejectResults: (results) => !results.hasSelectedResult(), + }, + }); } protected willUpdate(changedProps: PropertyValues): void { @@ -881,6 +835,7 @@ export class FrigateCardViewerProvider const cameraID = this.media.getCameraID(); const mediaID = this.media.getID() ?? undefined; const cameraConfig = this.cameraManager?.getStore().getCameraConfig(cameraID); + const view = this.viewManagerEpoch?.manager.getView(); return this.viewerConfig?.zoomable ? html` this.setControls(false)} @frigate-card:zoom:unzoomed=${() => this.setControls()} @frigate-card:zoom:change=${(ev: CustomEvent) => - handleZoomSettingsObservedEvent(this, ev, mediaID)} + handleZoomSettingsObservedEvent(ev, this.viewManagerEpoch?.manager, mediaID)} > ${template} ` @@ -906,7 +859,7 @@ export class FrigateCardViewerProvider } protected render(): TemplateResult | void { - if (!this.load || !this.media || !this.hass || !this.view || !this.viewerConfig) { + if (!this.load || !this.media || !this.hass || !this.viewerConfig) { return; } diff --git a/src/components/views.ts b/src/components/views.ts index 160ffeb0..8d735574 100644 --- a/src/components/views.ts +++ b/src/components/views.ts @@ -11,6 +11,7 @@ import { classMap } from 'lit/directives/class-map.js'; import { CameraManager } from '../camera-manager/manager.js'; import { ConditionsManagerEpoch } from '../card-controller/conditions-manager.js'; import { ReadonlyMicrophoneManager } from '../card-controller/microphone-manager.js'; +import { ViewManagerEpoch } from '../card-controller/view/types.js'; import { CardWideConfig, FrigateCardConfig, @@ -19,8 +20,6 @@ import { import viewsStyle from '../scss/views.scss'; import { ExtendedHomeAssistant } from '../types.js'; import { ResolvedMediaCache } from '../utils/ha/resolved-media.js'; -import { View } from '../view/view.js'; -import './surround.js'; // As a special case: Diagnostics is not dynamically loaded in case something goes wrong. import './diagnostics.js'; @@ -31,7 +30,7 @@ export class FrigateCardViews extends LitElement { public hass?: ExtendedHomeAssistant; @property({ attribute: false }) - public view?: Readonly; + public viewManagerEpoch?: ViewManagerEpoch; @property({ attribute: false }) public cameraManager?: CameraManager; @@ -64,17 +63,18 @@ export class FrigateCardViews extends LitElement { public triggeredCameraIDs?: Set; protected willUpdate(changedProps: PropertyValues): void { - if (changedProps.has('view') || changedProps.has('config')) { - if (this.view?.is('live') || this._shouldLivePreload()) { + if (changedProps.has('viewManagerEpoch') || changedProps.has('config')) { + const view = this.viewManagerEpoch?.manager.getView(); + if (view?.is('live') || this._shouldLivePreload()) { import('./live/live.js'); } - if (this.view?.isGalleryView()) { + if (view?.isGalleryView()) { import('./gallery.js'); - } else if (this.view?.isViewerView()) { + } else if (view?.isViewerView()) { import('./viewer.js'); - } else if (this.view?.is('image')) { + } else if (view?.is('image')) { import('./image.js'); - } else if (this.view?.is('timeline')) { + } else if (view?.is('timeline')) { import('./timeline.js'); } } @@ -108,10 +108,11 @@ export class FrigateCardViews extends LitElement { } protected _shouldLivePreload(): boolean { + const view = this.viewManagerEpoch?.manager.getView(); return ( // Special case: Never preload for diagnostics -- we want that to be as // minimal as possible. - !!this.overriddenConfig?.live.preload && !this.view?.is('diagnostics') + !!this.overriddenConfig?.live.preload && !view?.is('diagnostics') ); } @@ -129,67 +130,69 @@ export class FrigateCardViews extends LitElement { return html``; } + const view = this.viewManagerEpoch?.manager.getView(); + // Render but hide the live view if there's a message, or if it's preload // mode and the view is not live. const liveClasses = { - hidden: this._shouldLivePreload() && !this.view?.is('live'), + hidden: this._shouldLivePreload() && !view?.is('live'), }; const overallClasses = { hidden: !!this.hide, }; - const thumbnailConfig = this.view?.is('live') + const thumbnailConfig = view?.is('live') ? this.overriddenConfig.live.controls.thumbnails - : this.view?.isViewerView() + : view?.isViewerView() ? this.overriddenConfig.media_viewer.controls.thumbnails - : this.view?.is('timeline') + : view?.is('timeline') ? this.overriddenConfig.timeline.controls.thumbnails : undefined; - const miniTimelineConfig = this.view?.is('live') + const miniTimelineConfig = view?.is('live') ? this.overriddenConfig.live.controls.timeline - : this.view?.isViewerView() + : view?.isViewerView() ? this.overriddenConfig.media_viewer.controls.timeline : undefined; - const cameraConfig = this.view - ? this.cameraManager?.getStore().getCameraConfig(this.view.camera) ?? null + const cameraConfig = view + ? this.cameraManager?.getStore().getCameraConfig(view.camera) ?? null : null; return html` - ${!this.hide && this.view?.is('image') && cameraConfig + ${!this.hide && view?.is('image') && cameraConfig ? html` ` : ``} - ${!this.hide && this.view?.isGalleryView() + ${!this.hide && view?.isGalleryView() ? html` ` : ``} - ${!this.hide && this.view?.isViewerView() + ${!this.hide && view?.isViewerView() ? html` ` : ``} - ${!this.hide && this.view?.is('timeline') + ${!this.hide && view?.is('timeline') ? html` ` : ``} - ${!this.hide && this.view?.is('diagnostics') + ${!this.hide && view?.is('diagnostics') ? html` uses nonOverriddenConfig rather than the // overriden config as it does it's own overriding as part of the camera // carousel. - this._shouldLivePreload() || (!this.hide && this.view?.is('live')) + this._shouldLivePreload() || (!this.hide && view?.is('live')) ? html` ` : ''} ${this._renderOptionSetHeader('timeline')} diff --git a/src/utils/find-best-media-index.ts b/src/utils/find-best-media-index.ts new file mode 100644 index 00000000..f59c3c55 --- /dev/null +++ b/src/utils/find-best-media-index.ts @@ -0,0 +1,48 @@ +import { ViewMedia } from '../view/media'; + +/** + * Find the longest matching media object that contains a given targetTime. + * Longest is chosen to give the most stability to the media viewer. + * @param mediaArray The media. + * @param targetTime The target time used to find the relevant child. + * @returns The childindex or null if no matching child is found. + */ +export const findBestMediaIndex = ( + mediaArray: ViewMedia[], + targetTime: Date, + favorCameraID?: string, +): number | null => { + let bestMatch: + | { + index: number; + duration: number; + cameraID: string; + } + | undefined; + + for (const [i, media] of mediaArray.entries()) { + const start = media.getStartTime(); + const end = media.getUsableEndTime(); + + if (media.includesTime(targetTime) && start && end) { + const duration = end.getTime() - start.getTime(); + + if ( + // No best match so far ... + !bestMatch || + // ... or there is a best-match, but it's from a non-favored camera (unlike this one) ... + (favorCameraID && + bestMatch.cameraID !== favorCameraID && + media.getCameraID() === favorCameraID) || + // ... or this match is longer and either there's no favored camera or this is it. + (duration > bestMatch.duration && + (!favorCameraID || + bestMatch.cameraID !== favorCameraID || + media.getCameraID() === favorCameraID)) + ) { + bestMatch = { index: i, duration: duration, cameraID: media.getCameraID() }; + } + } + } + return bestMatch ? bestMatch.index : null; +}; diff --git a/src/utils/media-to-view.ts b/src/utils/media-to-view.ts deleted file mode 100644 index 718f2646..00000000 --- a/src/utils/media-to-view.ts +++ /dev/null @@ -1,282 +0,0 @@ -import { ViewContext } from 'view'; -import { CameraManager } from '../camera-manager/manager'; -import { CapabilitySearchOptions, MediaQuery } from '../camera-manager/types'; -import { dispatchFrigateCardErrorEvent } from '../components/message'; -import { CardWideConfig, FrigateCardView } from '../config/types'; -import { MEDIA_CHUNK_SIZE_DEFAULT } from '../const'; -import { ClipsOrSnapshotsOrAll } from '../types'; -import { ViewMedia } from '../view/media'; -import { - EventMediaQueries, - MediaQueries, - RecordingMediaQueries, -} from '../view/media-queries'; -import { MediaQueriesResults } from '../view/media-queries-results'; -import { View } from '../view/view'; -import { errorToConsole } from './basic'; - -type ResultSelectType = 'latest' | 'time' | 'none'; - -export const changeViewToRecentEventsForCameraAndDependents = async ( - element: HTMLElement, - cameraManager: CameraManager, - cardWideConfig: CardWideConfig, - view: View, - options?: { - allCameras?: boolean; - eventsMediaType?: ClipsOrSnapshotsOrAll; - targetView?: FrigateCardView; - select?: ResultSelectType; - useCache?: boolean; - viewContext?: ViewContext; - }, -): Promise => { - const capabilitySearch: CapabilitySearchOptions = - !options?.eventsMediaType || options?.eventsMediaType === 'all' - ? { - anyCapabilities: ['clips', 'snapshots'], - } - : options.eventsMediaType; - - const cameraIDs = options?.allCameras - ? cameraManager.getStore().getCameraIDsWithCapability(capabilitySearch) - : cameraManager.getStore().getAllDependentCameras(view.camera, capabilitySearch); - if (!cameraIDs.size) { - return; - } - - const queries = createQueriesForEventsView(cameraManager, cardWideConfig, cameraIDs, { - eventsMediaType: options?.eventsMediaType, - }); - if (!queries) { - return; - } - - ( - await executeMediaQueryForViewWithErrorDispatching( - element, - cameraManager, - view, - queries, - { - targetView: options?.targetView, - select: options?.select, - useCache: options?.useCache, - viewContext: options?.viewContext, - }, - ) - )?.dispatchChangeEvent(element); -}; - -const createQueriesForEventsView = ( - cameraManager: CameraManager, - cardWideConfig: CardWideConfig, - cameraIDs: Set, - options?: { - eventsMediaType?: ClipsOrSnapshotsOrAll; - }, -): EventMediaQueries | null => { - const limit = - cardWideConfig.performance?.features.media_chunk_size ?? MEDIA_CHUNK_SIZE_DEFAULT; - const eventQueries = cameraManager.generateDefaultEventQueries(cameraIDs, { - limit: limit, - ...(options?.eventsMediaType === 'clips' && { hasClip: true }), - ...(options?.eventsMediaType === 'snapshots' && { hasSnapshot: true }), - }); - return eventQueries ? new EventMediaQueries(eventQueries) : null; -}; - -/** - * Change the view to a recent recording. - * @param element The element to dispatch the view change from. - * @param hass The Home Assistant object. - * @param cameraManager The datamanager to use for data access. - * @param cameras The camera configurations. - * @param view The current view. - * @param options A set of cameraIDs to fetch recordings for, and a targetView to dispatch to. - */ -export const changeViewToRecentRecordingForCameraAndDependents = async ( - element: HTMLElement, - cameraManager: CameraManager, - cardWideConfig: CardWideConfig, - view: View, - options?: { - allCameras?: boolean; - targetView?: FrigateCardView; - select?: ResultSelectType; - useCache?: boolean; - viewContext?: ViewContext; - }, -): Promise => { - const cameraIDs = options?.allCameras - ? cameraManager.getStore().getCameraIDsWithCapability('recordings') - : cameraManager.getStore().getAllDependentCameras(view.camera, 'recordings'); - if (!cameraIDs.size) { - return; - } - - const queries = createQueriesForRecordingsView( - cameraManager, - cardWideConfig, - cameraIDs, - ); - if (!queries) { - return; - } - - ( - await executeMediaQueryForViewWithErrorDispatching( - element, - cameraManager, - view, - queries, - { - targetView: options?.targetView, - select: options?.select, - useCache: options?.useCache, - viewContext: options?.viewContext, - }, - ) - )?.dispatchChangeEvent(element); -}; - -const createQueriesForRecordingsView = ( - cameraManager: CameraManager, - cardWideConfig: CardWideConfig, - cameraIDs: Set, -): RecordingMediaQueries | null => { - const limit = - cardWideConfig.performance?.features.media_chunk_size ?? MEDIA_CHUNK_SIZE_DEFAULT; - const recordingQueries = cameraManager.generateDefaultRecordingQueries(cameraIDs, { - limit: limit, - }); - return recordingQueries ? new RecordingMediaQueries(recordingQueries) : null; -}; - -export const executeMediaQueryForView = async ( - cameraManager: CameraManager, - view: View, - query: MediaQueries, - options?: { - targetCameraID?: string; - targetView?: FrigateCardView; - targetTime?: Date; - select?: ResultSelectType; - useCache?: boolean; - viewContext?: ViewContext; - }, -): Promise => { - const queries = query.getQueries(); - if (!queries) { - return null; - } - - const mediaArray = await cameraManager.executeMediaQueries(queries, { - useCache: options?.useCache, - }); - if (!mediaArray) { - return null; - } - - const queryResults = new MediaQueriesResults({ results: mediaArray }); - let viewerContext: ViewContext | undefined = {}; - const cameraID = options?.targetCameraID ?? view.camera; - - if (options?.select === 'time' && options?.targetTime) { - queryResults.selectBestResult((media) => - findBestMediaIndex(media, options.targetTime as Date, cameraID), - ); - viewerContext = { - mediaViewer: { - seek: options.targetTime, - }, - }; - } - - return view - .evolve({ - query: query, - queryResults: queryResults, - view: options?.targetView, - camera: cameraID, - }) - .mergeInContext(options?.viewContext) - .mergeInContext(viewerContext); -}; - -export const executeMediaQueryForViewWithErrorDispatching = async ( - element: HTMLElement, - cameraManager: CameraManager, - view: View, - query: MediaQueries, - options?: { - targetCameraID?: string; - targetView?: FrigateCardView; - targetTime?: Date; - select?: ResultSelectType; - useCache?: boolean; - viewContext?: ViewContext; - }, -): Promise => { - try { - return await executeMediaQueryForView(cameraManager, view, query, { - targetCameraID: options?.targetCameraID, - targetView: options?.targetView, - targetTime: options?.targetTime, - select: options?.select, - useCache: options?.useCache, - viewContext: options?.viewContext, - }); - } catch (e: unknown) { - errorToConsole(e as Error); - dispatchFrigateCardErrorEvent(element, e as Error); - } - return null; -}; - -/** - * Find the longest matching media object that contains a given targetTime. - * Longest is chosen to give the most stability to the media viewer. - * @param mediaArray The media. - * @param targetTime The target time used to find the relevant child. - * @returns The childindex or null if no matching child is found. - */ -export const findBestMediaIndex = ( - mediaArray: ViewMedia[], - targetTime: Date, - favorCameraID?: string, -): number | null => { - let bestMatch: - | { - index: number; - duration: number; - cameraID: string; - } - | undefined; - - for (const [i, media] of mediaArray.entries()) { - const start = media.getStartTime(); - const end = media.getUsableEndTime(); - - if (media.includesTime(targetTime) && start && end) { - const duration = end.getTime() - start.getTime(); - - if ( - // No best match so far ... - !bestMatch || - // ... or there is a best-match, but it's from a non-favored camera (unlike this one) ... - (favorCameraID && - bestMatch.cameraID !== favorCameraID && - media.getCameraID() === favorCameraID) || - // ... or this match is longer and either there's no favored camera or this is it. - (duration > bestMatch.duration && - (!favorCameraID || - bestMatch.cameraID !== favorCameraID || - media.getCameraID() === favorCameraID)) - ) { - bestMatch = { index: i, duration: duration, cameraID: media.getCameraID() }; - } - } - } - return bestMatch ? bestMatch.index : null; -}; diff --git a/src/utils/substream.ts b/src/utils/substream.ts index 938eb218..7f1aafaa 100644 --- a/src/utils/substream.ts +++ b/src/utils/substream.ts @@ -7,3 +7,18 @@ export const getStreamCameraID = (view: View, cameraID?: string): string => { export const hasSubstream = (view: View): boolean => { return getStreamCameraID(view) !== view.camera; }; + +export const setSubstream = (view: View, substreamID: string): void => { + const overrides: Map = view.context?.live?.overrides ?? new Map(); + overrides.set(view.camera, substreamID); + view.mergeInContext({ + live: { overrides: overrides }, + }); +}; + +export const removeSubstream = (view: View): void => { + const overrides: Map | undefined = view.context?.live?.overrides; + if (overrides && overrides.has(view.camera)) { + view.context?.live?.overrides?.delete(view.camera); + } +}; diff --git a/src/view/view.ts b/src/view/view.ts index 918ff818..b2cde44e 100644 --- a/src/view/view.ts +++ b/src/view/view.ts @@ -1,11 +1,8 @@ +import merge from 'lodash-es/merge'; import { ViewContext } from 'view'; import { FrigateCardView, ViewDisplayMode } from '../config/types.js'; -import { ClipsOrSnapshots } from '../types.js'; -import { dispatchFrigateCardEvent } from '../utils/basic.js'; import { MediaQueries } from './media-queries'; -import { MediaQueriesClassifier } from './media-queries-classifier.js'; import { MediaQueriesResults } from './media-queries-results'; -import merge from 'lodash-es/merge'; interface ViewEvolveParameters { view?: FrigateCardView; @@ -21,6 +18,10 @@ export interface ViewParameters extends ViewEvolveParameters { camera: string; } +export const mergeViewContext = (a?: ViewContext | null, b?: ViewContext | null): ViewContext => { + return merge({}, a, b); +} + export class View { public view: FrigateCardView; public camera: string; @@ -38,109 +39,6 @@ export class View { this.displayMode = params.displayMode ?? null; } - /** - * Detect if a view change represents a major "media change" for the given - * view. - * @param prev The previous view. - * @param curr The current view. - * @returns True if the view change is a real media change. - */ - public static isMajorMediaChange(prev?: View | null, curr?: View): boolean { - return ( - !prev || - !curr || - prev.view !== curr.view || - prev.camera !== curr.camera || - // When in live mode, take overrides (substreams) into account in deciding - // if this is a major media change. - (curr.view === 'live' && - prev.context?.live?.overrides?.get(prev.camera) !== - curr.context?.live?.overrides?.get(curr.camera)) || - // When in the live view, the queryResults contain the events that - // happened in the past -- not reflective of the actual live media viewer - // the user is seeing. - (curr.view !== 'live' && prev.queryResults !== curr.queryResults) - ); - } - - public static adoptFromViewIfAppropriate(next: View, curr?: View | null): void { - if (!curr) { - return; - } - - // In certain cases it may make sense to adopt parameters from a prior view. - // - // * Case #1: If the user is currently using the viewer, and then switches - // to the gallery we make an attempt to keep the query/queryResults the - // same so the gallery can be used to click back and forth to the viewer, - // and the selected media can be centered in the gallery. See the matching - // code in `updated()` in `gallery.ts`. We specifically must ensure that - // the new target media of the gallery (e.g. clips, snapshots or - // recordings) is equal to the queries that are currently used in the - // viewer. See: - // https://github.com/dermotduffy/frigate-hass-card/issues/885 - // - // * Case #2: If the user is looking at media in the `media` view and then - // changes camera to the *current* camera (via the menu) it will cause a - // new view to issue without a query and just the 'media' view, which - // means the viewer cannot know what kind of media to fetch. - // - // * Case #3: Staying within the live view in order to preserve substreams - // turned on. See: - // https://github.com/dermotduffy/frigate-hass-card/issues/1122 - // - - let currentQueriesView: ClipsOrSnapshots | 'recordings' | null = null; - if (MediaQueriesClassifier.areEventQueries(curr.query)) { - const queries = curr.query.getQueries(); - if ( - queries?.every((query) => query.hasClip) || - queries?.every( - (query) => query.hasClip === undefined && query.hasSnapshot === undefined, - ) - ) { - currentQueriesView = 'clips'; - } else if (queries?.every((query) => query.hasSnapshot)) { - currentQueriesView = 'snapshots'; - } - } else if (MediaQueriesClassifier.areRecordingQueries(curr.query)) { - currentQueriesView = 'recordings'; - } - - const hasNoQueryOrResults = !next.query || !next.queryResults; - const switchingToGalleryFromViewer = - curr.isViewerView() && next.isGalleryView() && next.view === currentQueriesView; - const switchingToMediaFromMedia = curr?.is('media') && next.is('media'); - - if (hasNoQueryOrResults) { - if (switchingToGalleryFromViewer && curr.query && curr.queryResults) { - next.query = curr.query; - next.queryResults = curr.queryResults; - } else if (switchingToMediaFromMedia && currentQueriesView) { - next.view = - currentQueriesView === 'clips' - ? 'clip' - : currentQueriesView === 'snapshots' - ? 'snapshot' - : 'recording'; - } - } - - if ( - curr.is('live') && - next.is('live') && - curr.context?.live?.overrides && - !next.context?.live?.overrides - ) { - const nextLiveContext = next.context?.live ?? {}; - nextLiveContext.overrides = curr.context.live.overrides; - next.mergeInContext({ live: nextLiveContext }); - } - } - - /** - * Clone a view. - */ public clone(): View { return new View({ view: this.view, @@ -178,7 +76,7 @@ export class View { * @returns This view. */ public mergeInContext(context?: ViewContext | null): View { - this.context = merge({}, this.context, context); + this.context = mergeViewContext(this.context, context); return this; } @@ -259,48 +157,4 @@ export class View { public isGrid(): boolean { return this.displayMode === 'grid'; } - - /** - * Dispatch an event to request a view change. - * @param target The target dispatching the event. - */ - public dispatchChangeEvent(target: EventTarget): void { - dispatchFrigateCardEvent(target, 'view:change', this); - } } - -// Facilitates correct typing of event handlers. -export interface FrigateCardViewChangeEventTarget extends EventTarget { - addEventListener( - event: 'frigate-card:view:change', - listener: (this: FrigateCardViewChangeEventTarget, ev: CustomEvent) => void, - options?: AddEventListenerOptions | boolean, - ): void; - addEventListener( - type: string, - callback: EventListenerOrEventListenerObject, - options?: AddEventListenerOptions | boolean, - ): void; - removeEventListener( - event: 'frigate-card:view:change', - listener: (this: FrigateCardViewChangeEventTarget, ev: CustomEvent) => void, - options?: boolean | EventListenerOptions, - ): void; - removeEventListener( - type: string, - callback: EventListenerOrEventListenerObject, - options?: boolean | EventListenerOptions, - ): void; -} - -/** - * Dispatch an event to change the view context. - * @param target The EventTarget to send the event from. - * @param context The context to change. - */ -export const dispatchViewContextChangeEvent = ( - target: EventTarget, - context: ViewContext | null, -): void => { - dispatchFrigateCardEvent(target, 'view:change-context', context); -}; diff --git a/tests/card-controller/actions/actions/camera-select.test.ts b/tests/card-controller/actions/actions/camera-select.test.ts index 7c2abc2c..57d30a19 100644 --- a/tests/card-controller/actions/actions/camera-select.test.ts +++ b/tests/card-controller/actions/actions/camera-select.test.ts @@ -19,10 +19,12 @@ describe('should handle camera_select action', () => { await action.execute(api); - expect(api.getViewManager().setViewByParameters).toBeCalledWith( + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith( expect.objectContaining({ - viewName: 'live', - cameraID: 'camera', + params: { + view: 'live', + camera: 'camera', + }, failSafe: true, }), ); @@ -49,10 +51,12 @@ describe('should handle camera_select action', () => { await action.execute(api); - expect(api.getViewManager().setViewByParameters).toBeCalledWith( + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith( expect.objectContaining({ - viewName: 'timeline', - cameraID: 'camera', + params: { + view: 'timeline', + camera: 'camera', + }, failSafe: true, }), ); @@ -86,10 +90,12 @@ describe('should handle camera_select action', () => { await action.execute(api); - expect(api.getViewManager().setViewByParameters).toBeCalledWith( + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith( expect.objectContaining({ - viewName: 'clips', - cameraID: 'camera', + params: { + view: 'clips', + camera: 'camera', + }, failSafe: true, }), ); @@ -114,10 +120,12 @@ describe('should handle camera_select action', () => { await action.execute(api); - expect(api.getViewManager().setViewByParameters).toBeCalledWith( + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith( expect.objectContaining({ - viewName: 'live', - cameraID: 'camera', + params: { + view: 'live', + camera: 'camera', + }, failSafe: true, }), ); @@ -141,7 +149,7 @@ describe('should handle camera_select action', () => { await action.execute(api); - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled(); }); it('without a current view', async () => { @@ -158,6 +166,6 @@ describe('should handle camera_select action', () => { await action.execute(api); - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled(); }); }); diff --git a/tests/card-controller/actions/actions/display-mode-select.test.ts b/tests/card-controller/actions/actions/display-mode-select.test.ts index 57da6936..7c7900e5 100644 --- a/tests/card-controller/actions/actions/display-mode-select.test.ts +++ b/tests/card-controller/actions/actions/display-mode-select.test.ts @@ -15,5 +15,9 @@ it('should handle default action', async () => { await action.execute(api); - expect(api.getViewManager().setViewWithNewDisplayMode).toBeCalledWith('grid'); + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({ + params: { + displayMode: 'grid', + }, + }); }); diff --git a/tests/card-controller/actions/actions/substream-off.test.ts b/tests/card-controller/actions/actions/substream-off.test.ts index 149b2d17..03b86187 100644 --- a/tests/card-controller/actions/actions/substream-off.test.ts +++ b/tests/card-controller/actions/actions/substream-off.test.ts @@ -1,6 +1,7 @@ import { expect, it } from 'vitest'; import { SubstreamOffAction } from '../../../../src/card-controller/actions/actions/substream-off'; import { createCardAPI } from '../../../test-utils'; +import { SubstreamOffViewModifier } from '../../../../src/card-controller/view/modifiers/substream-off'; it('should handle live_substream_off action', async () => { const api = createCardAPI(); @@ -14,5 +15,7 @@ it('should handle live_substream_off action', async () => { await action.execute(api); - expect(api.getViewManager().setViewWithoutSubstream).toBeCalled(); + expect(api.getViewManager().setViewByParameters).toBeCalledWith({ + modifiers: [expect.any(SubstreamOffViewModifier)], + }); }); diff --git a/tests/card-controller/actions/actions/substream-on.test.ts b/tests/card-controller/actions/actions/substream-on.test.ts index 21ede4bf..b37061f3 100644 --- a/tests/card-controller/actions/actions/substream-on.test.ts +++ b/tests/card-controller/actions/actions/substream-on.test.ts @@ -1,6 +1,7 @@ import { expect, it } from 'vitest'; import { SubstreamOnAction } from '../../../../src/card-controller/actions/actions/substream-on'; import { createCardAPI } from '../../../test-utils'; +import { SubstreamOnViewModifier } from '../../../../src/card-controller/view/modifiers/substream-on'; it('should handle live_substream_on action', async () => { const api = createCardAPI(); @@ -14,5 +15,7 @@ it('should handle live_substream_on action', async () => { await action.execute(api); - expect(api.getViewManager().setViewWithSubstream).toBeCalledWith(); + expect(api.getViewManager().setViewByParameters).toBeCalledWith({ + modifiers: [expect.any(SubstreamOnViewModifier)], + }); }); diff --git a/tests/card-controller/actions/actions/substream-select.test.ts b/tests/card-controller/actions/actions/substream-select.test.ts index 7ab186f8..a0f326f9 100644 --- a/tests/card-controller/actions/actions/substream-select.test.ts +++ b/tests/card-controller/actions/actions/substream-select.test.ts @@ -1,6 +1,7 @@ import { expect, it } from 'vitest'; import { SubstreamSelectAction } from '../../../../src/card-controller/actions/actions/substream-select'; import { createCardAPI } from '../../../test-utils'; +import { SubstreamSelectViewModifier } from '../../../../src/card-controller/view/modifiers/substream-select'; it('should handle live_substream_select action', async () => { const api = createCardAPI(); @@ -15,5 +16,9 @@ it('should handle live_substream_select action', async () => { await action.execute(api); - expect(api.getViewManager().setViewWithSubstream).toBeCalledWith('substream'); + expect(api.getViewManager().setViewByParameters).toBeCalledWith( + expect.objectContaining({ + modifiers: expect.arrayContaining([expect.any(SubstreamSelectViewModifier)]), + }), + ); }); diff --git a/tests/card-controller/actions/actions/view.test.ts b/tests/card-controller/actions/actions/view.test.ts index 16f17f79..41215a63 100644 --- a/tests/card-controller/actions/actions/view.test.ts +++ b/tests/card-controller/actions/actions/view.test.ts @@ -27,9 +27,11 @@ describe('should handle view action', () => { await action.execute(api); - expect(api.getViewManager().setViewByParameters).toBeCalledWith( + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith( expect.objectContaining({ - viewName: viewName, + params: { + view: viewName, + }, }), ); }); diff --git a/tests/card-controller/controller.test.ts b/tests/card-controller/controller.test.ts index f2ae1f97..6148cb7e 100644 --- a/tests/card-controller/controller.test.ts +++ b/tests/card-controller/controller.test.ts @@ -25,7 +25,7 @@ import { MicrophoneManager } from '../../src/card-controller/microphone-manager' import { QueryStringManager } from '../../src/card-controller/query-string-manager'; import { StyleManager } from '../../src/card-controller/style-manager'; import { TriggersManager } from '../../src/card-controller/triggers-manager'; -import { ViewManager } from '../../src/card-controller/view-manager'; +import { ViewManager } from '../../src/card-controller/view/view-manager'; import { FrigateCardEditor } from '../../src/editor'; import { EntityRegistryManager } from '../../src/utils/ha/entity-registry'; import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media'; @@ -52,7 +52,7 @@ vi.mock('../../src/card-controller/microphone-manager'); vi.mock('../../src/card-controller/query-string-manager'); vi.mock('../../src/card-controller/style-manager'); vi.mock('../../src/card-controller/triggers-manager'); -vi.mock('../../src/card-controller/view-manager'); +vi.mock('../../src/card-controller/view/view-manager'); vi.mock('../../src/utils/ha/entity-registry'); vi.mock('../../src/utils/ha/resolved-media'); diff --git a/tests/card-controller/initialization-manager.test.ts b/tests/card-controller/initialization-manager.test.ts index fb8ba160..add474ce 100644 --- a/tests/card-controller/initialization-manager.test.ts +++ b/tests/card-controller/initialization-manager.test.ts @@ -110,7 +110,7 @@ describe('InitializationManager', () => { expect(loadLanguages).toBeCalled(); expect(sideLoadHomeAssistantElements).toBeCalled(); expect(api.getCameraManager().initializeCamerasFromConfig).toBeCalled(); - expect(api.getViewManager().setViewDefault).toBeCalled(); + expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled(); expect(api.getMicrophoneManager().connect).not.toBeCalled(); }); diff --git a/tests/card-controller/query-string-manager.test.ts b/tests/card-controller/query-string-manager.test.ts index 7d1c6427..6ee8ae42 100644 --- a/tests/card-controller/query-string-manager.test.ts +++ b/tests/card-controller/query-string-manager.test.ts @@ -1,6 +1,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { QueryStringManager } from '../../src/card-controller/query-string-manager'; +import { SubstreamSelectViewModifier } from '../../src/card-controller/view/modifiers/substream-select'; import { createCardAPI } from '../test-utils'; const setQueryString = (qs: string): void => { @@ -51,8 +52,10 @@ describe('QueryStringManager', () => { manager.executeAll(); expect(manager.hasViewRelatedActions()).toBeTruthy(); - expect(api.getViewManager().setViewByParameters).toBeCalledWith({ - viewName: viewName, + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({ + params: { + view: viewName, + }, }); }); }); @@ -92,7 +95,7 @@ describe('QueryStringManager', () => { manager.executeAll(); - expect(api.getViewManager().setViewDefault).toBeCalled(); + expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled(); expect(manager.hasViewRelatedActions()).toBeTruthy(); expect(api.getActionsManager().executeActions).not.toBeCalled(); @@ -107,8 +110,10 @@ describe('QueryStringManager', () => { manager.executeAll(); - expect(api.getViewManager().setViewByParameters).toBeCalledWith({ - cameraID: 'camera.office', + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({ + params: { + camera: 'camera.office', + }, }); expect(manager.hasViewRelatedActions()).toBeTruthy(); @@ -124,8 +129,9 @@ describe('QueryStringManager', () => { manager.executeAll(); - expect(api.getViewManager().setViewByParameters).toBeCalledWith({ - substream: 'camera.office_hd', + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({ + modifiers: [expect.any(SubstreamSelectViewModifier)], + params: {}, }); expect(manager.hasViewRelatedActions()).toBeTruthy(); @@ -190,8 +196,10 @@ describe('QueryStringManager', () => { manager.executeAll(); expect(manager.hasViewRelatedActions()).toBeTruthy(); - expect(api.getViewManager().setViewByParameters).toBeCalledWith({ - viewName: viewName, + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({ + params: { + view: viewName, + }, }); }); }); @@ -230,11 +238,13 @@ describe('QueryStringManager', () => { manager.executeAll(); - expect(api.getViewManager().setViewDefault).toBeCalledWith({ - cameraID: 'camera.kitchen', - substream: 'camera.kitchen_hd', + expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalledWith({ + params: { + camera: 'camera.kitchen', + }, + modifiers: [expect.any(SubstreamSelectViewModifier)], }); - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled(); }); it('multiple cameras specified', () => { @@ -248,8 +258,10 @@ describe('QueryStringManager', () => { manager.executeAll(); - expect(api.getViewManager().setViewByParameters).toBeCalledWith({ - cameraID: 'camera.office', + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({ + params: { + camera: 'camera.office', + }, }); }); }); diff --git a/tests/card-controller/triggers-manager.test.ts b/tests/card-controller/triggers-manager.test.ts index e81e8ecb..88b058e6 100644 --- a/tests/card-controller/triggers-manager.test.ts +++ b/tests/card-controller/triggers-manager.test.ts @@ -14,6 +14,7 @@ import { createConfig, createStore, createView, + flushPromises, } from '../test-utils'; vi.mock('lodash-es/throttle', () => ({ @@ -109,7 +110,7 @@ describe('TriggersManager', () => { }); describe('trigger actions', () => { - it('update', () => { + it('update', async () => { const api = createTriggerAPI({ config: { ...baseTriggersConfig, @@ -122,16 +123,18 @@ describe('TriggersManager', () => { const manager = new TriggersManager(api); - manager.handleCameraEvent({ + await manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new', }); expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setView).toBeCalled(); + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({ + queryExecutorOptions: { useCache: false }, + }); }); - it('default', () => { + it('default', async () => { const api = createTriggerAPI({ config: { ...baseTriggersConfig, @@ -144,11 +147,13 @@ describe('TriggersManager', () => { const manager = new TriggersManager(api); - manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' }); + await manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' }); expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setViewDefault).toBeCalledWith({ - cameraID: 'camera_1', + expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalledWith({ + params: { + camera: 'camera_1', + }, }); }); @@ -168,9 +173,11 @@ describe('TriggersManager', () => { manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' }); expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setViewByParameters).toBeCalledWith({ - viewName: 'live', - cameraID: 'camera_1', + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({ + params: { + view: 'live', + camera: 'camera_1', + }, }); }); @@ -207,12 +214,16 @@ describe('TriggersManager', () => { }); if (!viewName) { - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + expect( + api.getViewManager().setViewByParametersWithNewQuery, + ).not.toBeCalled(); } else { expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setViewByParameters).toBeCalledWith({ - cameraID: 'camera_1', - viewName: viewName, + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({ + params: { + camera: 'camera_1', + view: viewName, + }, }); } }, @@ -235,9 +246,8 @@ describe('TriggersManager', () => { manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' }); expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setView).not.toBeCalled(); - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled(); + expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled(); }); }); @@ -263,12 +273,11 @@ describe('TriggersManager', () => { expect(manager.isTriggered()).toBeFalsy(); - expect(api.getViewManager().setView).not.toBeCalled(); - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled(); + expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled(); }); - it('default', () => { + it('default', async () => { const api = createTriggerAPI({ config: { ...baseTriggersConfig, @@ -281,15 +290,16 @@ describe('TriggersManager', () => { }); const manager = new TriggersManager(api); - manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' }); - manager.handleCameraEvent({ cameraID: 'camera_1', type: 'end' }); + await manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new' }); + await manager.handleCameraEvent({ cameraID: 'camera_1', type: 'end' }); vi.setSystemTime(add(start, { seconds: 10 })); vi.runOnlyPendingTimers(); + await flushPromises(); expect(manager.isTriggered()).toBeFalsy(); - expect(api.getViewManager().setViewDefault).toBeCalled(); + expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled(); }); }); @@ -343,9 +353,8 @@ describe('TriggersManager', () => { manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new', fidelity: 'high' }); - expect(api.getViewManager().setView).not.toBeCalled(); - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled(); + expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled(); }); it('with non-live default', () => { @@ -364,9 +373,8 @@ describe('TriggersManager', () => { manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new', fidelity: 'high' }); - expect(api.getViewManager().setView).not.toBeCalled(); - expect(api.getViewManager().setViewDefault).not.toBeCalled(); - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled(); + expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled(); }); }); @@ -384,7 +392,8 @@ describe('TriggersManager', () => { expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled(); + expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled(); manager.handleCameraEvent({ cameraID: 'camera_1', @@ -396,7 +405,8 @@ describe('TriggersManager', () => { expect(manager.isTriggered()).toBeFalsy(); - expect(api.getViewManager().setViewDefault).not.toBeCalled(); + expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled(); + expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled(); }); it('should take no actions when actions are set to none', () => { @@ -415,7 +425,8 @@ describe('TriggersManager', () => { type: 'new', }); expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setViewByParameters).not.toBeCalled(); + expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled(); + expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled(); manager.handleCameraEvent({ cameraID: 'camera_1', @@ -426,10 +437,11 @@ describe('TriggersManager', () => { vi.runOnlyPendingTimers(); expect(manager.isTriggered()).toBeFalsy(); - expect(api.getViewManager().setViewDefault).not.toBeCalled(); + expect(api.getViewManager().setViewDefaultWithNewQuery).not.toBeCalled(); + expect(api.getViewManager().setViewByParametersWithNewQuery).not.toBeCalled(); }); - it('should take actions with human interactions when interaction mode is active', () => { + it('should take actions with human interactions when interaction mode is active', async () => { const api = createTriggerAPI({ // Interaction present. interaction: true, @@ -443,31 +455,34 @@ describe('TriggersManager', () => { }, }); const manager = new TriggersManager(api); - manager.handleCameraEvent({ + await manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new', }); expect(manager.isTriggered()).toBeTruthy(); - expect(api.getViewManager().setViewByParameters).toBeCalledWith({ - viewName: 'live' as const, - cameraID: 'camera_1' as const, + expect(api.getViewManager().setViewByParametersWithNewQuery).toBeCalledWith({ + params: { + view: 'live' as const, + camera: 'camera_1' as const, + } }); - manager.handleCameraEvent({ + await manager.handleCameraEvent({ cameraID: 'camera_1', type: 'end', }); vi.setSystemTime(add(start, { seconds: 10 })); vi.runOnlyPendingTimers(); + await flushPromises(); expect(manager.isTriggered()).toBeFalsy(); - expect(api.getViewManager().setViewDefault).toBeCalled(); + expect(api.getViewManager().setViewDefaultWithNewQuery).toBeCalled(); }); - it('should report multiple triggered cameras', () => { + it('should report multiple triggered cameras', async () => { const api = createTriggerAPI(); vi.mocked(api.getCameraManager().getStore).mockReturnValue( createStore([ @@ -496,11 +511,11 @@ describe('TriggersManager', () => { expect(manager.getMostRecentlyTriggeredCameraID()).toBeNull(); expect(manager.getTriggeredCameraIDs()).toEqual(new Set()); - manager.handleCameraEvent({ + await manager.handleCameraEvent({ cameraID: 'camera_1', type: 'new', }); - manager.handleCameraEvent({ + await manager.handleCameraEvent({ cameraID: 'camera_2', type: 'new', }); @@ -513,7 +528,7 @@ describe('TriggersManager', () => { manager.getMostRecentlyTriggeredCameraID(), ); - manager.handleCameraEvent({ + await manager.handleCameraEvent({ cameraID: 'camera_1', type: 'end', }); @@ -521,6 +536,8 @@ describe('TriggersManager', () => { vi.setSystemTime(add(start, { seconds: 10 })); vi.runOnlyPendingTimers(); + await flushPromises(); + expect(manager.getTriggeredCameraIDs()).toEqual(new Set(['camera_2'])); expect(manager.getMostRecentlyTriggeredCameraID()).toBe('camera_2'); }); diff --git a/tests/card-controller/view-manager.test.ts b/tests/card-controller/view-manager.test.ts deleted file mode 100644 index ae911bb4..00000000 --- a/tests/card-controller/view-manager.test.ts +++ /dev/null @@ -1,1035 +0,0 @@ -import { describe, expect, it, vi } from 'vitest'; -import { QueryType } from '../../src/camera-manager/types'; -import { ViewManager } from '../../src/card-controller/view-manager'; -import { FrigateCardView } from '../../src/config/types'; -import { executeMediaQueryForView } from '../../src/utils/media-to-view'; -import { EventMediaQueries } from '../../src/view/media-queries'; -import { MediaQueriesResults } from '../../src/view/media-queries-results'; -import { View } from '../../src/view/view'; -import { - createCameraConfig, - createCameraManager, - createCapabilities, - createCardAPI, - createConfig, - createHASS, - createStore, - createView, - generateViewMediaArray, -} from '../test-utils'; - -vi.mock('../../src/utils/media-to-view'); - -describe('ViewManager.setView', () => { - it('should set view', () => { - const api = createCardAPI(); - const manager = new ViewManager(api); - - const view = createView({ - view: 'live', - camera: 'camera', - displayMode: 'grid', - }); - manager.setView(view); - - expect(manager.getView()).toBe(view); - expect(manager.hasView()).toBeTruthy(); - expect(api.getMediaLoadedInfoManager().clear).toBeCalled(); - expect(api.getCardElementManager().scrollReset).toBeCalled(); - expect(api.getMessageManager().reset).toBeCalled(); - expect(api.getStyleManager().setExpandedMode).toBeCalled(); - expect(api.getConditionsManager()?.setState).toBeCalledWith({ - view: 'live', - camera: 'camera', - displayMode: 'grid', - }); - expect(api.getCardElementManager().update).toBeCalled(); - }); - - it('should set view with minor changes without media clearing or scroll', () => { - const api = createCardAPI(); - const manager = new ViewManager(api); - - const view_1 = createView({ - view: 'live', - camera: 'camera', - }); - manager.setView(view_1); - - vi.mocked(api.getMediaLoadedInfoManager().clear).mockClear(); - vi.mocked(api.getCardElementManager().scrollReset).mockClear(); - - const view_2 = createView({ - view: 'live', - camera: 'camera', - displayMode: 'single', - }); - - manager.setView(view_2); - - expect(manager.getView()).toBe(view_2); - - // The new view is neither a major media change, nor a different view name, - // so media clearing and scrolling should not happen. - expect(api.getMediaLoadedInfoManager().clear).not.toBeCalled(); - expect(api.getCardElementManager().scrollReset).not.toBeCalled(); - }); - - it('should set view with new context', () => { - const api = createCardAPI(); - const manager = new ViewManager(api); - const context = { live: { fetchThumbnails: false } }; - - // Setting context with no existing view does nothing. - manager.setViewWithMergedContext(context); - expect(manager.getView()).toBeNull(); - - const view = createView({ - view: 'live', - camera: 'camera', - }); - manager.setView(view); - manager.setViewWithMergedContext(context); - - expect(manager.getView()?.camera).toBe('camera'); - expect(manager.getView()?.view).toBe('live'); - expect(manager.getView()?.context).toEqual(context); - }); -}); - -describe('ViewManager.reset', () => { - it('should reset', () => { - const manager = new ViewManager(createCardAPI()); - - const view = createView(); - manager.setView(view); - manager.reset(); - - expect(manager.getView()).toBeNull(); - expect(manager.hasView()).toBeFalsy(); - }); -}); - -describe('ViewManager.setViewDefault', () => { - it('should set default view', () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera', - capabilities: createCapabilities({ live: true }), - }, - ]), - ); - - const manager = new ViewManager(api); - manager.setViewDefault(); - - expect(manager.getView()?.view).toBe('live'); - expect(manager.getView()?.camera).toBe('camera'); - }); - - it('should not set default view without config', () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(null); - - const manager = new ViewManager(api); - manager.setViewDefault(); - - expect(manager.getView()).toBeNull(); - }); - - it('should cycle camera when configured', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera_1', - capabilities: createCapabilities({ live: true }), - }, - { - cameraID: 'camera_2', - capabilities: createCapabilities({ live: true }), - }, - ]), - ); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - view: { - default_cycle_camera: true, - }, - }), - ); - const manager = new ViewManager(api); - - manager.setViewDefault(); - expect(manager.getView()?.camera).toBe('camera_1'); - - manager.setViewDefault(); - expect(manager.getView()?.camera).toBe('camera_2'); - - manager.setViewDefault(); - expect(manager.getView()?.camera).toBe('camera_1'); - - // When a parameter is specified, it will not cycle. - manager.setViewDefault({ cameraID: 'camera_1' }); - expect(manager.getView()?.camera).toBe('camera_1'); - }); - - it('should respect parameters', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ live: true }), - }, - { - cameraID: 'camera.office', - capabilities: createCapabilities({ live: true }), - }, - ]), - ); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - const manager = new ViewManager(api); - - manager.setViewDefault({ - cameraID: 'camera.office', - substream: 'camera.office_hd', - }); - expect(manager.getView()?.view).toBe('live'); - expect(manager.getView()?.camera).toBe('camera.office'); - expect(manager.getView()?.context?.live?.overrides).toEqual( - new Map([['camera.office', 'camera.office_hd']]), - ); - }); -}); - -describe('ViewManager.setViewByParameters', () => { - it('should set view by parameters specifying camera and view', () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ clips: true }), - }, - ]), - ); - vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createCapabilities({ - clips: true, - }), - ); - - const manager = new ViewManager(api); - manager.setViewByParameters({ - cameraID: 'camera.kitchen', - viewName: 'clips', - }); - - expect(manager.getView()?.view).toBe('clips'); - expect(manager.getView()?.camera).toBe('camera.kitchen'); - }); - - it('should set view by parameters using existing view if unspecified', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ clips: true }), - }, - { - cameraID: 'camera.office', - capabilities: createCapabilities({ clips: true }), - }, - ]), - ); - vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createCapabilities({ - clips: true, - }), - ); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - - const manager = new ViewManager(api); - manager.setViewByParameters({ - cameraID: 'camera.kitchen', - viewName: 'clips', - }); - - manager.setViewByParameters({ - cameraID: 'camera.office', - }); - - expect(manager.getView()?.view).toBe('clips'); - expect(manager.getView()?.camera).toBe('camera.office'); - }); - - it('should set view by parameters using config as fallback', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ live: true }), - }, - ]), - ); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - - const manager = new ViewManager(api); - manager.setViewByParameters({ - cameraID: 'camera.kitchen', - // No prior view, and no specified view. This could happen during query - // string based initialization. - }); - - expect(manager.getView()?.view).toBe('live'); - expect(manager.getView()?.camera).toBe('camera.kitchen'); - }); - - it('should not set view by parameters without config', () => { - const manager = new ViewManager(createCardAPI()); - - manager.setViewByParameters({ - viewName: 'live', - }); - - expect(manager.getView()).toBeNull(); - }); - - describe('should handle unsupported view', () => { - it('without camera without failsafe', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ snapshots: false }), - }, - ]), - ); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - - const manager = new ViewManager(api); - manager.setViewByParameters({ - // Since no camera is specified, and no camera supports the capabilities - // necessary for this view, the view will be null. - viewName: 'snapshots', - }); - - expect(manager.getView()).toBeNull(); - }); - - it('without camera with failsafe', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ snapshots: false }), - }, - { - cameraID: 'camera.office', - // No capabilities. - capabilities: null, - }, - ]), - ); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - - const manager = new ViewManager(api); - manager.setViewByParameters({ - // Since no camera is specified, and no camera supports the capabilities - // necessary for this view, and since failSafe is specified, an error - // will be shown. - viewName: 'snapshots', - failSafe: true, - }); - - expect(manager.getView()).toBeNull(); - expect(manager.hasView()).toBeFalsy(); - expect(api.getMessageManager().setMessageIfHigherPriority).toBeCalledWith( - expect.objectContaining({ - type: 'error', - message: 'No cameras support this view', - context: { - view: 'snapshots', - cameras_capabilities: { - 'camera.kitchen': { - 'favorite-events': false, - 'favorite-recordings': false, - clips: false, - live: false, - recordings: false, - seek: false, - snapshots: false, - }, - }, - }, - }), - ); - }); - - it('with camera without failsafe', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ snapshots: false }), - }, - ]), - ); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createCapabilities({ - snapshots: false, - }), - ); - - const manager = new ViewManager(api); - manager.setViewByParameters({ - cameraID: 'camera.kitchen', - viewName: 'snapshots', - }); - - expect(manager.hasView()).toBeFalsy(); - expect(manager.getView()).toBeNull(); - }); - - it('with camera with failsafe', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ snapshots: false, live: true }), - }, - ]), - ); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createCapabilities({ - snapshots: false, - live: true, - }), - ); - - const manager = new ViewManager(api); - manager.setViewByParameters({ - cameraID: 'camera.kitchen', - viewName: 'snapshots', - failSafe: true, - }); - - expect(manager.hasView()).toBeTruthy(); - expect(manager.getView()?.view).toBe('live'); - }); - - it('with camera with failsafe when live unsupported', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ snapshots: false, live: false }), - }, - ]), - ); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createCapabilities({ - snapshots: false, - live: false, - }), - ); - - const manager = new ViewManager(api); - manager.setViewByParameters({ - cameraID: 'camera.kitchen', - viewName: 'snapshots', - failSafe: true, - }); - - expect(manager.hasView()).toBeFalsy(); - expect(manager.getView()).toBeNull(); - expect(api.getMessageManager().setMessageIfHigherPriority).toBeCalledWith( - expect.objectContaining({ - type: 'error', - message: 'The selected camera does not support this view', - context: { - view: 'snapshots', - camera: 'camera.kitchen', - camera_capabilities: { - 'favorite-events': false, - 'favorite-recordings': false, - clips: false, - live: false, - recordings: false, - seek: false, - snapshots: false, - }, - }, - }), - ); - }); - }); - - describe('should set view by parameters and respect display mode in config for view', () => { - it.each([ - ['media' as const], - ['clip' as const], - ['recording' as const], - ['snapshot' as const], - ['live' as const], - ])('%s', (viewName: FrigateCardView) => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ - live: true, - clips: true, - recordings: true, - snapshots: true, - }), - }, - ]), - ); - vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createCapabilities({ - live: true, - clips: true, - recordings: true, - snapshots: true, - }), - ); - - vi.mocked(api.getConfigManager()).getConfig.mockReturnValue( - createConfig({ - media_viewer: { - display: { - mode: 'grid', - }, - }, - live: { - display: { - mode: 'grid', - }, - }, - }), - ); - const manager = new ViewManager(api); - - manager.setViewByParameters({ - cameraID: 'camera.kitchen', - viewName: viewName, - }); - - expect(manager.getView()?.displayMode).toBe('grid'); - }); - }); - - describe('should set view by parameters and leave display mode unset for view', () => { - it.each([ - ['media' as const], - ['clip' as const], - ['recording' as const], - ['snapshot' as const], - ['live' as const], - ])('%s', (viewName: FrigateCardView) => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ - live: true, - clips: true, - recordings: true, - snapshots: true, - }), - }, - ]), - ); - vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( - createCapabilities({ - live: true, - clips: true, - recordings: true, - snapshots: true, - }), - ); - - const manager = new ViewManager(api); - - manager.setViewByParameters({ - cameraID: 'camera.kitchen', - viewName: viewName, - }); - - expect(manager.getView()?.displayMode).toBe('single'); - }); - }); -}); - -// @vitest-environment jsdom -describe('ViewManager.setViewWithNewDisplayMode', () => { - it('should set display mode', async () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - - const manager = new ViewManager(api); - manager.setView(createView()); - - await manager.setViewWithNewDisplayMode('grid'); - - expect(manager.getView()?.displayMode).toBe('grid'); - }); - - it('should not set display mode without view', async () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - const manager = new ViewManager(api); - - manager.setViewWithNewDisplayMode('grid'); - - expect(manager.getView()).toBeNull(); - }); - - it('should set display mode to grid and create new query', async () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ - clips: true, - recordings: true, - snapshots: true, - }), - }, - { - cameraID: 'camera.office', - capabilities: createCapabilities({ - clips: true, - recordings: true, - snapshots: true, - }), - }, - ]), - ); - - const hass = createHASS(); - vi.mocked(api.getHASSManager()).getHASS.mockReturnValue(hass); - - const mediaArray = generateViewMediaArray({ count: 5 }); - vi.mocked(executeMediaQueryForView).mockResolvedValue( - new View({ - view: 'clip', - camera: 'camera.kitchen', - queryResults: new MediaQueriesResults({ results: mediaArray }), - }), - ); - - const manager = new ViewManager(api); - const query = new EventMediaQueries([ - { type: QueryType.Event, cameraIDs: new Set(['camera_1']), hasClip: true }, - ]); - - manager.setView( - createView({ - camera: 'camera_1', - view: 'clip', - query: query, - }), - ); - - await manager.setViewWithNewDisplayMode('grid'); - - expect(manager.getView()?.queryResults?.getResults()).toBe(mediaArray); - }); - - it('should set display mode to single and create new query', async () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ - clips: true, - recordings: true, - snapshots: true, - }), - }, - { - cameraID: 'camera.office', - capabilities: createCapabilities({ - clips: true, - recordings: true, - snapshots: true, - }), - }, - ]), - ); - - const hass = createHASS(); - vi.mocked(api.getHASSManager()).getHASS.mockReturnValue(hass); - - const mediaArray = generateViewMediaArray({ count: 5 }); - vi.mocked(executeMediaQueryForView).mockResolvedValue( - new View({ - view: 'clip', - camera: 'camera.kitchen', - queryResults: new MediaQueriesResults({ results: mediaArray }), - }), - ); - - const manager = new ViewManager(api); - const query = new EventMediaQueries([ - { - type: QueryType.Event, - cameraIDs: new Set(['camera.kitchen', 'camera.office']), - hasClip: true, - }, - ]); - - manager.setView( - createView({ - view: 'clip', - camera: 'camera.office', - query: query, - }), - ); - - await manager.setViewWithNewDisplayMode('single'); - - expect(manager.getView()?.queryResults?.getResults()).toBe(mediaArray); - }); - - it('should set display mode to single and handle failed new query', async () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ - clips: true, - recordings: true, - snapshots: true, - }), - }, - { - cameraID: 'camera.office', - capabilities: createCapabilities({ - clips: true, - recordings: true, - snapshots: true, - }), - }, - ]), - ); - - const manager = new ViewManager(api); - const query = new EventMediaQueries([ - { - type: QueryType.Event, - cameraIDs: new Set(['camera.kitchen', 'camera.office']), - hasClip: true, - }, - ]); - - const originalView = createView({ - view: 'clip', - camera: 'camera.office', - query: query, - }); - manager.setView(originalView); - - // Query execution fails / returns null. - vi.mocked(executeMediaQueryForView).mockRejectedValue(null); - - await manager.setViewWithNewDisplayMode('single'); - - expect(manager.getView()).toBe(originalView); - }); - - it('should set display mode and handle empty new query results', async () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ - clips: true, - recordings: true, - snapshots: true, - }), - }, - { - cameraID: 'camera.office', - capabilities: createCapabilities({ - clips: true, - recordings: true, - snapshots: true, - }), - }, - ]), - ); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); - - const manager = new ViewManager(api); - - const query = new EventMediaQueries([ - { - type: QueryType.Event, - cameraIDs: new Set(['camera.kitchen']), - hasClip: true, - }, - ]); - const originalView = createView({ - view: 'clip', - camera: 'camera.office', - query: query, - }); - manager.setView(originalView); - - await manager.setViewWithNewDisplayMode('grid'); - - vi.mocked(executeMediaQueryForView).mockResolvedValue(null); - - // Empty queries will not be executed, so view will not be changed. - expect(manager.getView()?.displayMode).toBeNull(); - }); -}); - -describe('ViewManager.setViewWithSubstream', () => { - it('should set new equal view with no dependencies', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - }, - ]), - ); - const manager = new ViewManager(api); - const view = createView({ - view: 'live', - camera: 'camera', - }); - - manager.setView(view); - manager.setViewWithSubstream(); - - expect(manager.getView()?.camera).toBe(view.camera); - expect(manager.getView()?.view).toBe(view.view); - expect(manager.getView()?.context).toEqual(view.context); - }); - - it('should set new view with next substream', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - config: createCameraConfig({ - dependencies: { - cameras: ['camera.kitchen_hd'], - }, - }), - }, - { - cameraID: 'camera.kitchen_hd', - }, - ]), - ); - const manager = new ViewManager(api); - const view = createView({ - view: 'live', - camera: 'camera.kitchen', - }); - - manager.setView(view); - manager.setViewWithSubstream(); - - expect(manager.getView()?.context?.live?.overrides).toEqual( - new Map([['camera.kitchen', 'camera.kitchen_hd']]), - ); - }); - - it('should set new view with next substream when view has invalid substream', () => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - config: createCameraConfig({ - dependencies: { - cameras: ['camera.kitchen_hd'], - }, - }), - }, - { - cameraID: 'camera.kitchen_hd', - }, - ]), - ); - const manager = new ViewManager(api); - const view = createView({ - view: 'live', - camera: 'camera.kitchen', - context: { - live: { - overrides: new Map([['camera.kitchen', 'camera-that-does-not-exist']]), - }, - }, - }); - - manager.setView(view); - manager.setViewWithSubstream(); - - expect(manager.getView()?.context?.live?.overrides).toEqual( - new Map([['camera.kitchen', 'camera.kitchen']]), - ); - }); - - it('should set new view with selected substream', () => { - const view = createView({ - view: 'live', - camera: 'camera', - }); - - const manager = new ViewManager(createCardAPI()); - manager.setView(view); - manager.setViewWithSubstream('substream'); - - expect(manager.getView()?.context?.live?.overrides).toEqual( - new Map([['camera', 'substream']]), - ); - }); - - it('should not set view with next substream without an existing view', () => { - const manager = new ViewManager(createCardAPI()); - manager.setViewWithSubstream(); - expect(manager.getView()).toBeNull(); - }); - - it('should not set view with selected substream without an existing view', () => { - const manager = new ViewManager(createCardAPI()); - manager.setViewWithSubstream('substream'); - expect(manager.getView()).toBeNull(); - }); - - it('should not set view without substream without an existing view', () => { - const manager = new ViewManager(createCardAPI()); - manager.setViewWithoutSubstream(); - expect(manager.getView()).toBeNull(); - }); - - it('should set new view without substream', () => { - const view = createView({ - view: 'live', - camera: 'camera', - context: { - live: { - overrides: new Map([['camera', 'camera']]), - }, - }, - }); - - const manager = new ViewManager(createCardAPI()); - manager.setView(view); - manager.setViewWithoutSubstream(); - - expect(manager.getView()?.context?.live?.overrides).toEqual(new Map()); - }); - - it('should set new view without substream', () => { - const view = createView({ - view: 'live', - camera: 'camera', - context: { - live: { - overrides: new Map([['camera-2', 'camera-3']]), - }, - }, - }); - - const manager = new ViewManager(createCardAPI()); - manager.setView(view); - manager.setViewWithoutSubstream(); - - expect(manager.getView()?.context?.live?.overrides).toEqual( - view.context?.live?.overrides, - ); - }); -}); - -describe('ViewManager.isViewSupportedByCamera', () => { - it.each([ - ['live' as const, false], - ['image' as const, true], - ['diagnostics' as const, true], - ['clip' as const, false], - ['clips' as const, false], - ['snapshot' as const, false], - ['snapshots' as const, false], - ['recording' as const, false], - ['recordings' as const, false], - ['timeline' as const, false], - ['media' as const, false], - ])('%s', (viewName: FrigateCardView, expected: boolean) => { - const api = createCardAPI(); - vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); - vi.mocked(api.getCameraManager().getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera.kitchen', - capabilities: createCapabilities({ - live: false, - 'favorite-events': false, - 'favorite-recordings': false, - seek: false, - clips: false, - recordings: false, - snapshots: false, - }), - }, - ]), - ); - const manager = new ViewManager(api); - - expect(manager.isViewSupportedByCamera('camera', viewName)).toBe(expected); - }); -}); diff --git a/tests/card-controller/view/factory.test.ts b/tests/card-controller/view/factory.test.ts new file mode 100644 index 00000000..7e84115c --- /dev/null +++ b/tests/card-controller/view/factory.test.ts @@ -0,0 +1,751 @@ +import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { ViewFactory } from '../../../src/card-controller/view/factory'; +import { QueryExecutor } from '../../../src/card-controller/view/query-executor'; +import { ViewModifier } from '../../../src/card-controller/view/types'; +import { FrigateCardView, ViewDisplayMode } from '../../../src/config/types'; +import { + EventMediaQueries, + RecordingMediaQueries, +} from '../../../src/view/media-queries'; +import { MediaQueriesResults } from '../../../src/view/media-queries-results'; +import { View } from '../../../src/view/view'; +import { + createCameraManager, + createCapabilities, + createCardAPI, + createConfig, + createStore, +} from '../../test-utils'; +import { createPopulatedAPI } from './test-utils'; + +describe('getViewDefault', () => { + it('should return null without config', () => { + const factory = new ViewFactory(createCardAPI()); + expect(factory.getViewDefault()).toBeNull(); + }); + + it('should create view', () => { + const factory = new ViewFactory(createPopulatedAPI()); + const view = factory.getViewDefault(); + + expect(view?.is('live')).toBeTruthy(); + expect(view?.camera).toBe('camera.office'); + }); + + it('should cycle camera when configured', () => { + const api = createPopulatedAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + default_cycle_camera: true, + }, + }), + ); + + const factory = new ViewFactory(api); + + let view = factory.getViewDefault(); + expect(view?.camera).toBe('camera.office'); + + view = factory.getViewDefault({ baseView: view }); + expect(view?.camera).toBe('camera.kitchen'); + + view = factory.getViewDefault({ baseView: view }); + expect(view?.camera).toBe('camera.office'); + + // When a parameter is specified, it will not cycle. + view = factory.getViewDefault({ + params: { camera: 'camera.office' }, + baseView: view, + }); + expect(view?.camera).toBe('camera.office'); + }); + + it('should respect parameters', () => { + const factory = new ViewFactory(createPopulatedAPI()); + const view = factory.getViewDefault({ + params: { + camera: 'camera.office', + }, + }); + + expect(view?.is('live')).toBeTruthy(); + expect(view?.camera).toBe('camera.office'); + }); +}); + +describe('getViewByParameters', () => { + it('should get view by parameters specifying camera and view', () => { + const api = createPopulatedAPI(); + vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( + createCapabilities({ + clips: true, + }), + ); + + const factory = new ViewFactory(api); + const view = factory.getViewByParameters({ + params: { + camera: 'camera.kitchen', + view: 'clips', + }, + }); + + expect(view?.is('clips')).toBeTruthy(); + expect(view?.camera).toBe('camera.kitchen'); + }); + + it('should get view by parameters using base view if unspecified', () => { + const api = createPopulatedAPI(); + vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( + createCapabilities({ + clips: true, + }), + ); + + const factory = new ViewFactory(api); + const baseView = new View({ + camera: 'camera.kitchen', + view: 'clips', + }); + + const view = factory.getViewByParameters({ + baseView: baseView, + params: { + camera: 'camera.office', + }, + }); + + expect(view?.view).toBe('clips'); + expect(view?.camera).toBe('camera.office'); + }); + + it('should set view by parameters using config as fallback', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: createCapabilities({ live: true }), + }, + ]), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + + const factory = new ViewFactory(api); + const view = factory.getViewByParameters({ + params: { + camera: 'camera.kitchen', + + // No prior view, and no specified view. This could happen during query + // string based initialization. + }, + }); + + expect(view?.is('live')).toBeTruthy(); + expect(view?.camera).toBe('camera.kitchen'); + }); + + it('should not set view by parameters without config', () => { + const factory = new ViewFactory(createCardAPI()); + + const view = factory.getViewByParameters({ + params: { + view: 'live', + }, + }); + + expect(view).toBeNull(); + }); + + it('should throw without camera and without failsafe', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: createCapabilities({ snapshots: false }), + }, + { + cameraID: 'camera.office', + // No capabilities. + capabilities: null, + }, + ]), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + + const factory = new ViewFactory(api); + expect(() => + factory.getViewByParameters({ + // Since no camera is specified, and no camera supports the capabilities + // necessary for this view, the view will be null. + params: { + view: 'snapshots', + }, + }), + ).toThrowError(/No cameras support this view/); + }); + + describe('should handle unsupported view', () => { + it('should throw without failsafe', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: createCapabilities({ snapshots: false }), + }, + ]), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( + createCapabilities({ + snapshots: false, + }), + ); + + const factory = new ViewFactory(api); + expect(() => + factory.getViewByParameters({ + params: { + camera: 'camera.kitchen', + view: 'snapshots', + }, + }), + ).toThrowError(/The selected camera does not support this view/); + }); + + it('should choose live view with failsafe', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: createCapabilities({ live: true, snapshots: false }), + }, + ]), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + vi.mocked(api.getCameraManager().getAggregateCameraCapabilities).mockReturnValue( + createCapabilities({ + live: true, + snapshots: false, + }), + ); + + const factory = new ViewFactory(api); + const view = factory.getViewByParameters({ + params: { + camera: 'camera.kitchen', + view: 'snapshots', + }, + failSafe: true, + }); + expect(view?.is('live')).toBeTruthy(); + }); + }); + + it('should call modifiers', () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.office', + capabilities: createCapabilities({ live: true }), + }, + ]), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig()); + + const modifyCallback = vi.fn(); + class TestViewModifier implements ViewModifier { + modify = modifyCallback; + } + + const view = new View({ + view: 'live', + camera: 'camera.office', + }); + const factory = new ViewFactory(api); + const modifiedView = factory.getViewByParameters({ + baseView: view, + modifiers: [new TestViewModifier()], + }); + + expect(modifiedView?.is('live')).toBeTruthy(); + expect(modifiedView?.camera).toBe('camera.office'); + expect(view).not.toBe(modifiedView); + expect(modifyCallback).toHaveBeenCalledWith(modifiedView); + }); + + describe('should get correct default display mode', () => { + describe.each([['single' as const], ['grid' as const]])( + '%s', + (displayMode: ViewDisplayMode) => { + it.each([ + ['media' as const], + ['clip' as const], + ['recording' as const], + ['snapshot' as const], + ['live' as const], + ])('%s', (viewName: FrigateCardView) => { + const api = createPopulatedAPI({ + media_viewer: { + display: { + mode: displayMode, + }, + }, + live: { + display: { + mode: displayMode, + }, + }, + }); + + const factory = new ViewFactory(api); + expect( + factory.getViewByParameters({ + params: { + view: viewName, + }, + })?.displayMode, + ).toBe(displayMode); + }); + }, + ); + }); +}); + +describe('getViewByParametersWithNewQuery', () => { + it('should not execute query without config', async () => { + const factory = new ViewFactory(createCardAPI()); + expect(await factory.getViewByParametersWithNewQuery()).toBeNull(); + }); + + describe('with a live view', () => { + beforeAll(() => { + vi.useFakeTimers(); + vi.setSystemTime(new Date('2024-07-21T13:22:06Z')); + }); + + afterAll(() => { + vi.useRealTimers(); + }); + + it('should set timeline window', async () => { + const executor = mock(); + const factory = new ViewFactory(createPopulatedAPI(), executor); + const view = await factory.getViewByParametersWithNewQuery({ + params: { + view: 'live', + }, + }); + + expect(view?.context).toEqual({ + timeline: { + window: { + start: new Date('2024-07-21T12:22:06.000Z'), + end: new Date('2024-07-21T13:22:06.000Z'), + }, + }, + }); + }); + + it('should not fetch anything if configured for no thumbnails', async () => { + const executor = mock(); + const factory = new ViewFactory( + createPopulatedAPI({ + live: { + controls: { + thumbnails: { + mode: 'none' as const, + }, + }, + }, + }), + executor, + ); + const view = await factory.getViewByParametersWithNewQuery({ + params: { + view: 'live', + }, + }); + + expect(view?.query).toBeNull(); + expect(view?.queryResults).toBeNull(); + expect(executor.executeDefaultEventQuery).not.toHaveBeenCalled(); + expect(executor.executeDefaultRecordingQuery).not.toHaveBeenCalled(); + }); + + it('should fetch events', async () => { + const executor = mock(); + const query = new EventMediaQueries(); + const queryResults = new MediaQueriesResults(); + + executor.executeDefaultEventQuery.mockResolvedValue({ + query: query, + queryResults: queryResults, + }); + + const factory = new ViewFactory(createPopulatedAPI(), executor); + const view = await factory.getViewByParametersWithNewQuery({ + params: { + view: 'live', + }, + }); + + expect(view?.query).toBe(query); + expect(view?.queryResults).toBe(queryResults); + expect(executor.executeDefaultEventQuery).toBeCalledWith({ + cameraID: 'camera.office', + eventsMediaType: 'all', + executorOptions: { + useCache: false, + }, + }); + expect(executor.executeDefaultRecordingQuery).not.toHaveBeenCalled(); + }); + + it('should fetch recordings', async () => { + const executor = mock(); + const query = new RecordingMediaQueries(); + const queryResults = new MediaQueriesResults(); + + executor.executeDefaultRecordingQuery.mockResolvedValue({ + query: query, + queryResults: queryResults, + }); + + const factory = new ViewFactory( + createPopulatedAPI({ + live: { + controls: { + thumbnails: { + media_type: 'recordings', + }, + }, + }, + }), + executor, + ); + const view = await factory.getViewByParametersWithNewQuery({ + params: { + view: 'live', + }, + }); + + expect(view?.query).toBe(query); + expect(view?.queryResults).toBe(queryResults); + expect(executor.executeDefaultEventQuery).not.toBeCalled(); + expect(executor.executeDefaultRecordingQuery).toBeCalledWith({ + cameraID: 'camera.office', + executorOptions: { + useCache: false, + }, + }); + }); + }); + + describe('with a media view', () => { + it('should do nothing with same camera', async () => { + const executor = mock(); + const factory = new ViewFactory(createPopulatedAPI(), executor); + const baseView = new View({ + view: 'media', + camera: 'camera.office', + }); + const view = await factory.getViewByParametersWithNewQuery({ + baseView: baseView, + params: { + view: 'media', + }, + }); + + expect(view?.query).toBeNull(); + expect(view?.queryResults).toBeNull(); + expect(executor.executeDefaultEventQuery).not.toHaveBeenCalled(); + expect(executor.executeDefaultRecordingQuery).not.toHaveBeenCalled(); + }); + + it('should fetch clips with different camera', async () => { + const executor = mock(); + const query = new EventMediaQueries(); + const queryResults = new MediaQueriesResults(); + + executor.executeDefaultEventQuery.mockResolvedValue({ + query: query, + queryResults: queryResults, + }); + + const factory = new ViewFactory(createPopulatedAPI(), executor); + const baseView = new View({ + view: 'media', + camera: 'camera.office', + }); + const view = await factory.getViewByParametersWithNewQuery({ + baseView: baseView, + params: { + view: 'media', + camera: 'camera.kitchen', + }, + }); + + expect(view?.query).toBe(query); + expect(view?.queryResults).toBe(queryResults); + expect(executor.executeDefaultEventQuery).toBeCalledWith({ + cameraID: 'camera.kitchen', + eventsMediaType: 'clips', + executorOptions: { + useCache: false, + }, + }); + expect(executor.executeDefaultRecordingQuery).not.toHaveBeenCalled(); + }); + }); + + describe('with an events-based view', () => { + it.each([ + ['clip' as const, 'clips' as const], + ['clips' as const, 'clips' as const], + ['snapshot' as const, 'snapshots' as const], + ['snapshots' as const, 'snapshots' as const], + ])( + '%s', + async (viewName: FrigateCardView, eventsMediaType: 'clips' | 'snapshots') => { + const executor = mock(); + const query = new EventMediaQueries(); + const queryResults = new MediaQueriesResults(); + + executor.executeDefaultEventQuery.mockResolvedValue({ + query: query, + queryResults: queryResults, + }); + + const factory = new ViewFactory(createPopulatedAPI(), executor); + const view = await factory.getViewByParametersWithNewQuery({ + params: { + view: viewName, + }, + }); + + expect(view?.query).toBe(query); + expect(view?.queryResults).toBe(queryResults); + expect(executor.executeDefaultEventQuery).toBeCalledWith({ + cameraID: 'camera.office', + eventsMediaType: eventsMediaType, + executorOptions: { + useCache: false, + }, + }); + expect(executor.executeDefaultRecordingQuery).not.toHaveBeenCalled(); + }, + ); + }); + + describe('with an recordings-based view', () => { + it.each([['recording' as const], ['recordings' as const]])( + '%s', + async (viewName: FrigateCardView) => { + const executor = mock(); + const query = new RecordingMediaQueries(); + const queryResults = new MediaQueriesResults(); + + executor.executeDefaultRecordingQuery.mockResolvedValue({ + query: query, + queryResults: queryResults, + }); + + const factory = new ViewFactory(createPopulatedAPI(), executor); + const view = await factory.getViewByParametersWithNewQuery({ + params: { + view: viewName, + }, + }); + + expect(view?.query).toBe(query); + expect(view?.queryResults).toBe(queryResults); + expect(executor.executeDefaultEventQuery).not.toHaveBeenCalled(); + expect(executor.executeDefaultRecordingQuery).toBeCalledWith({ + cameraID: 'camera.office', + executorOptions: { + useCache: false, + }, + }); + }, + ); + }); + + describe('with an media viewer view', () => { + it('hould not fetch anything if configured for no thumbnails', async () => { + const executor = mock(); + const factory = new ViewFactory( + createPopulatedAPI({ + media_viewer: { + controls: { + thumbnails: { + mode: 'none' as const, + }, + }, + }, + }), + executor, + ); + const view = await factory.getViewByParametersWithNewQuery({ + params: { + view: 'clip', + }, + }); + + expect(view?.query).toBeNull(); + expect(view?.queryResults).toBeNull(); + expect(executor.executeDefaultEventQuery).not.toHaveBeenCalled(); + expect(executor.executeDefaultRecordingQuery).not.toHaveBeenCalled(); + }); + }); + + describe('when changing to gallery from the media viewer', () => { + it('should adopt query and results', async () => { + const executor = mock(); + const factory = new ViewFactory(createPopulatedAPI(), executor); + + const baseView = new View({ + view: 'media', + camera: 'camera.office', + query: new EventMediaQueries(), + queryResults: new MediaQueriesResults(), + }); + + const view = await factory.getViewByParametersWithNewQuery({ + baseView: baseView, + params: { + view: 'clips', + }, + }); + + expect(view?.query).toBe(baseView.query); + expect(view?.queryResults).toBe(baseView.queryResults); + expect(executor.executeDefaultEventQuery).not.toHaveBeenCalled(); + expect(executor.executeDefaultRecordingQuery).not.toHaveBeenCalled(); + }); + }); + + describe('when set or remove seek time', () => { + it('should set seek time when results are selected based on time', async () => { + const now = new Date(); + const executor = mock(); + const factory = new ViewFactory(createPopulatedAPI(), executor); + + const view = await factory.getViewByParametersWithNewQuery({ + params: { + view: 'clips', + }, + queryExecutorOptions: { + selectResult: { + time: { + time: now, + }, + }, + }, + }); + + expect(view?.context).toEqual({ + mediaViewer: { + seek: now, + }, + }); + }); + + it('should remove seek time when results are not selected based on time', async () => { + const executor = mock(); + const factory = new ViewFactory(createPopulatedAPI(), executor); + + const view = await factory.getViewByParametersWithNewQuery({ + baseView: new View({ + view: 'clips', + camera: 'camera.office', + context: { + mediaViewer: { + seek: new Date(), + }, + }, + }), + params: { + view: 'clips', + }, + }); + + expect(view?.context?.mediaViewer?.seek).toBeUndefined(); + }); + }); +}); + +describe('getViewDefaultWithNewQuery', () => { + it('should fetch events', async () => { + const executor = mock(); + const query = new EventMediaQueries(); + const queryResults = new MediaQueriesResults(); + + executor.executeDefaultEventQuery.mockResolvedValue({ + query: query, + queryResults: queryResults, + }); + + const factory = new ViewFactory(createPopulatedAPI(), executor); + const view = await factory.getViewDefaultWithNewQuery(); + + expect(view?.query).toBe(query); + expect(view?.queryResults).toBe(queryResults); + expect(executor.executeDefaultEventQuery).toBeCalledWith({ + cameraID: 'camera.office', + eventsMediaType: 'all', + executorOptions: { + useCache: false, + }, + }); + expect(executor.executeDefaultRecordingQuery).not.toHaveBeenCalled(); + }); +}); + +describe('getViewByParametersWithExistingQuery', () => { + it('should not execute anything when query is absent', async () => { + const executor = mock(); + const factory = new ViewFactory(createPopulatedAPI(), executor); + const view = await factory.getViewByParametersWithExistingQuery({ + params: { + view: 'live', + camera: 'camera.office', + }, + }); + + expect(view?.query).toBeNull(); + expect(view?.queryResults).toBeNull(); + expect(executor.executeDefaultEventQuery).not.toBeCalled(); + expect(executor.executeDefaultRecordingQuery).not.toBeCalled(); + }); + + it('should set query results', async () => { + const executor = mock(); + const queryResults = new MediaQueriesResults(); + executor.execute.mockResolvedValue(queryResults); + + const factory = new ViewFactory(createPopulatedAPI(), executor); + const query = new RecordingMediaQueries(); + const view = await factory.getViewByParametersWithExistingQuery({ + params: { + view: 'live', + camera: 'camera.office', + query: query, + }, + }); + + expect(view?.query).toBe(query); + expect(view?.queryResults).toBe(queryResults); + }); +}); diff --git a/tests/card-controller/view/modifiers/merge-context.test.ts b/tests/card-controller/view/modifiers/merge-context.test.ts new file mode 100644 index 00000000..43e91f41 --- /dev/null +++ b/tests/card-controller/view/modifiers/merge-context.test.ts @@ -0,0 +1,28 @@ +import { ViewContext } from 'view'; +import { expect, it } from 'vitest'; +import { MergeContextViewModifier } from '../../../../src/card-controller/view/modifiers/merge-context'; +import { createView } from '../../../test-utils'; + +it('should merge context', () => { + const context: ViewContext = { + timeline: { + window: { + start: new Date(), + end: new Date(), + }, + }, + }; + const modifier = new MergeContextViewModifier(context); + + const view = createView({ + view: 'live', + camera: 'camera', + displayMode: 'grid', + }); + + expect(view.context).toBeNull(); + + modifier.modify(view); + + expect(view.context).toEqual(context); +}); diff --git a/tests/card-controller/view/modifiers/remove-context-property.test.ts b/tests/card-controller/view/modifiers/remove-context-property.test.ts new file mode 100644 index 00000000..ba4f5241 --- /dev/null +++ b/tests/card-controller/view/modifiers/remove-context-property.test.ts @@ -0,0 +1,25 @@ +import { expect, it } from 'vitest'; +import { createView } from '../../../test-utils'; +import { RemoveContextPropertyViewModifier } from '../../../../src/card-controller/view/modifiers/remove-context-property'; + +it('should remove context property', () => { + const modifier = new RemoveContextPropertyViewModifier('timeline', 'window'); + + const view = createView({ + view: 'live', + camera: 'camera', + displayMode: 'grid', + context: { + timeline: { + window: { + start: new Date(), + end: new Date(), + }, + }, + }, + }); + + modifier.modify(view); + + expect(view.context).toEqual({ timeline: {} }); +}); diff --git a/tests/card-controller/view/modifiers/remove-context.test.ts b/tests/card-controller/view/modifiers/remove-context.test.ts new file mode 100644 index 00000000..28795272 --- /dev/null +++ b/tests/card-controller/view/modifiers/remove-context.test.ts @@ -0,0 +1,26 @@ +import { expect, it } from 'vitest'; +import { createView } from '../../../test-utils'; +import { RemoveContextViewModifier } from '../../../../src/card-controller/view/modifiers/remove-context'; + +it('should remove context property', () => { + const modifier = new RemoveContextViewModifier(['timeline']); + + const view = createView({ + view: 'live', + camera: 'camera', + displayMode: 'grid', + context: { + timeline: { + window: { + start: new Date(), + end: new Date(), + }, + }, + }, + }); + + modifier.modify(view); + + expect(view.context).toEqual({}); +}); + \ No newline at end of file diff --git a/tests/card-controller/view/modifiers/substream-off.test.ts b/tests/card-controller/view/modifiers/substream-off.test.ts new file mode 100644 index 00000000..d58d0fbf --- /dev/null +++ b/tests/card-controller/view/modifiers/substream-off.test.ts @@ -0,0 +1,20 @@ +import { expect, it } from 'vitest'; +import { createView } from '../../../test-utils'; +import { SubstreamOffViewModifier } from '../../../../src/card-controller/view/modifiers/substream-off'; +import { hasSubstream, setSubstream } from '../../../../src/utils/substream'; + +it('should turn off substream', () => { + const view = createView({ + view: 'live', + camera: 'camera', + displayMode: 'grid', + }); + + setSubstream(view, 'substream'); + expect(hasSubstream(view)).toBe(true); + + const modifier = new SubstreamOffViewModifier(); + modifier.modify(view); + + expect(hasSubstream(view)).toBe(false); +}); diff --git a/tests/card-controller/view/modifiers/substream-on.test.ts b/tests/card-controller/view/modifiers/substream-on.test.ts new file mode 100644 index 00000000..cbba3e27 --- /dev/null +++ b/tests/card-controller/view/modifiers/substream-on.test.ts @@ -0,0 +1,101 @@ +import { describe, expect, it, vi } from 'vitest'; +import { CardController } from '../../../../src/card-controller/controller'; +import { SubstreamOnViewModifier } from '../../../../src/card-controller/view/modifiers/substream-on'; +import { RawFrigateCardConfig } from '../../../../src/config/types'; +import { getStreamCameraID, hasSubstream, setSubstream } from '../../../../src/utils/substream'; +import { + createCameraConfig, + createCameraManager, + createCapabilities, + createCardAPI, + createConfig, + createStore, + createView, +} from '../../../test-utils'; + +const createAPIWithSubstreams = (config?: RawFrigateCardConfig): CardController => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.office', + capabilities: createCapabilities({ + live: true, + substream: true, + }), + config: createCameraConfig({ + dependencies: { + all_cameras: true, + }, + }), + }, + { + cameraID: 'camera.kitchen', + capabilities: createCapabilities({ + substream: true, + }), + }, + ]), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig(config)); + return api; +}; + +describe('should turn on substream', () => { + it('substream available', () => { + const view = createView({ + view: 'live', + camera: 'camera.office', + }); + + expect(hasSubstream(view)).toBe(false); + + const api = createAPIWithSubstreams(); + + const modifier = new SubstreamOnViewModifier(api); + modifier.modify(view); + + expect(hasSubstream(view)).toBe(true); + expect(getStreamCameraID(view)).toBe('camera.kitchen'); + + modifier.modify(view); + + expect(hasSubstream(view)).toBe(false); + expect(getStreamCameraID(view)).toBe('camera.office'); + }); + + it('malformed substream', () => { + const view = createView({ + view: 'live', + camera: 'camera.office', + }); + + const api = createAPIWithSubstreams(); + + setSubstream(view, 'NOT_A_REAL_CAMERA'); + + const modifier = new SubstreamOnViewModifier(api); + modifier.modify(view); + + expect(hasSubstream(view)).toBe(false); + expect(getStreamCameraID(view)).toBe('camera.office'); + }); + + it('substream unavailable', () => { + const view = createView({ + view: 'live', + camera: 'camera.office', + }); + + expect(hasSubstream(view)).toBe(false); + + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + + const modifier = new SubstreamOnViewModifier(api); + modifier.modify(view); + + expect(hasSubstream(view)).toBe(false); + }); +}); diff --git a/tests/card-controller/view/modifiers/substream-select.test.ts b/tests/card-controller/view/modifiers/substream-select.test.ts new file mode 100644 index 00000000..7c1a4455 --- /dev/null +++ b/tests/card-controller/view/modifiers/substream-select.test.ts @@ -0,0 +1,19 @@ +import { expect, it } from 'vitest'; +import { SubstreamSelectViewModifier } from '../../../../src/card-controller/view/modifiers/substream-select'; +import { getStreamCameraID, hasSubstream } from '../../../../src/utils/substream'; +import { createView } from '../../../test-utils'; + +it('should select substream', () => { + const view = createView({ + view: 'live', + camera: 'camera.office', + }); + + expect(hasSubstream(view)).toBe(false); + + const modifier = new SubstreamSelectViewModifier('substream'); + modifier.modify(view); + + expect(hasSubstream(view)).toBe(true); + expect(getStreamCameraID(view)).toBe('substream'); +}); diff --git a/tests/card-controller/view/query-executor.test.ts b/tests/card-controller/view/query-executor.test.ts new file mode 100644 index 00000000..61355da4 --- /dev/null +++ b/tests/card-controller/view/query-executor.test.ts @@ -0,0 +1,360 @@ +import { add } from 'date-fns'; +import { describe, expect, it, vi } from 'vitest'; +import { QueryType } from '../../../src/camera-manager/types'; +import { QueryExecutor } from '../../../src/card-controller/view/query-executor'; +import { ClipsOrSnapshotsOrAll } from '../../../src/types'; +import { EventMediaQueries } from '../../../src/view/media-queries'; +import { + TestViewMedia, + createCameraManager, + createCardAPI, + createStore, + generateViewMediaArray, +} from '../../test-utils'; +import { createPopulatedAPI } from './test-utils'; + +describe('executeDefaultEventQuery', () => { + it('should return null without cameras', async () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue(createStore()); + + const executor = new QueryExecutor(api); + expect( + await executor.executeDefaultEventQuery({ + cameraID: 'camera.office', + }), + ).toBeNull(); + }); + + it('should return null without queries', async () => { + const api = createPopulatedAPI(); + vi.mocked(api.getCameraManager().generateDefaultEventQueries).mockReturnValue(null); + + const executor = new QueryExecutor(api); + expect( + await executor.executeDefaultEventQuery({ + cameraID: 'camera.office', + }), + ).toBeNull(); + }); + + describe('should return query results for specified camera', async () => { + it.each([['all' as const], ['clips' as const], ['snapshots' as const], [undefined]])( + '%s', + async (mediaType?: ClipsOrSnapshotsOrAll) => { + const api = createPopulatedAPI(); + const media = generateViewMediaArray(); + const rawQueries = [ + { type: QueryType.Event as const, cameraIDs: new Set(['camera.office']) }, + ]; + vi.mocked(api.getCameraManager().generateDefaultEventQueries).mockReturnValue( + rawQueries, + ); + vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media); + + const executor = new QueryExecutor(api); + const results = await executor.executeDefaultEventQuery({ + cameraID: 'camera.office', + eventsMediaType: mediaType, + }); + + expect(results?.query.getQueries()).toEqual(rawQueries); + expect(results?.queryResults.getResults()).toEqual(media); + expect(api.getCameraManager().generateDefaultEventQueries).toBeCalledWith( + new Set(['camera.office']), + { + limit: 50, + ...(mediaType === 'clips' && { hasClip: true }), + ...(mediaType === 'snapshots' && { hasSnapshot: true }), + }, + ); + }, + ); + }); + + it('should return query results for all cameras', async () => { + const api = createPopulatedAPI(); + const media = generateViewMediaArray(); + const rawQueries = [ + { + type: QueryType.Event as const, + cameraIDs: new Set(['camera.office', 'camera.kitchen']), + }, + ]; + vi.mocked(api.getCameraManager().generateDefaultEventQueries).mockReturnValue( + rawQueries, + ); + vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media); + + const executor = new QueryExecutor(api); + const results = await executor.executeDefaultEventQuery(); + + expect(results?.query.getQueries()).toEqual(rawQueries); + expect(results?.queryResults.getResults()).toEqual(media); + expect(api.getCameraManager().generateDefaultEventQueries).toBeCalledWith( + new Set(['camera.office', 'camera.kitchen']), + { + limit: 50, + }, + ); + }); + + it('should return null when query returns null', async () => { + const api = createPopulatedAPI(); + const rawQueries = [ + { + type: QueryType.Event as const, + cameraIDs: new Set(['camera.office']), + }, + ]; + vi.mocked(api.getCameraManager().generateDefaultEventQueries).mockReturnValue( + rawQueries, + ); + vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(null); + + const executor = new QueryExecutor(api); + expect( + await executor.executeDefaultEventQuery({ cameraID: 'camera.office' }), + ).toBeNull(); + expect(api.getCameraManager().generateDefaultEventQueries).toBeCalledWith( + new Set(['camera.office']), + { + limit: 50, + }, + ); + }); +}); + +describe('executeDefaultRecordingQuery', () => { + it('should return null without cameras', async () => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue(createStore()); + + const executor = new QueryExecutor(api); + expect( + await executor.executeDefaultRecordingQuery({ + cameraID: 'camera.office', + }), + ).toBeNull(); + }); + + it('should return null without queries', async () => { + const api = createPopulatedAPI(); + vi.mocked(api.getCameraManager().generateDefaultRecordingQueries).mockReturnValue( + null, + ); + + const executor = new QueryExecutor(api); + expect( + await executor.executeDefaultRecordingQuery({ + cameraID: 'camera.office', + }), + ).toBeNull(); + }); + + it('should return query results for specified camera', async () => { + const api = createPopulatedAPI(); + const media = generateViewMediaArray(); + const rawQueries = [ + { type: QueryType.Recording as const, cameraIDs: new Set(['camera.office']) }, + ]; + vi.mocked(api.getCameraManager().generateDefaultRecordingQueries).mockReturnValue( + rawQueries, + ); + vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media); + + const executor = new QueryExecutor(api); + const results = await executor.executeDefaultRecordingQuery({ + cameraID: 'camera.office', + }); + + expect(results?.query.getQueries()).toEqual(rawQueries); + expect(results?.queryResults.getResults()).toEqual(media); + expect(api.getCameraManager().generateDefaultRecordingQueries).toBeCalledWith( + new Set(['camera.office']), + { + limit: 50, + }, + ); + }); + + it('should return query results for all cameras', async () => { + const api = createPopulatedAPI(); + const media = generateViewMediaArray(); + const rawQueries = [ + { + type: QueryType.Recording as const, + cameraIDs: new Set(['camera.office', 'camera.kitchen']), + }, + ]; + vi.mocked(api.getCameraManager().generateDefaultRecordingQueries).mockReturnValue( + rawQueries, + ); + vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media); + + const executor = new QueryExecutor(api); + const results = await executor.executeDefaultRecordingQuery(); + + expect(results?.query.getQueries()).toEqual(rawQueries); + expect(results?.queryResults.getResults()).toEqual(media); + expect(api.getCameraManager().generateDefaultRecordingQueries).toBeCalledWith( + new Set(['camera.office', 'camera.kitchen']), + { + limit: 50, + }, + ); + }); + + it('should return null when query returns null', async () => { + const api = createPopulatedAPI(); + const rawQueries = [ + { + type: QueryType.Recording as const, + cameraIDs: new Set(['camera.office']), + }, + ]; + vi.mocked(api.getCameraManager().generateDefaultRecordingQueries).mockReturnValue( + rawQueries, + ); + vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(null); + + const executor = new QueryExecutor(api); + expect( + await executor.executeDefaultRecordingQuery({ cameraID: 'camera.office' }), + ).toBeNull(); + expect(api.getCameraManager().generateDefaultRecordingQueries).toBeCalledWith( + new Set(['camera.office']), + { + limit: 50, + }, + ); + }); +}); + +describe('execute', () => { + it('should return null when query is empty', async () => { + const executor = new QueryExecutor(createCardAPI()); + expect(await executor.execute(new EventMediaQueries())).toBeNull(); + }); + + describe('should handle result rejections', () => { + it('rejected', async () => { + const api = createPopulatedAPI(); + const media = generateViewMediaArray(); + vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media); + + const query = new EventMediaQueries([ + { + type: QueryType.Event as const, + cameraIDs: new Set(['camera.office']), + }, + ]); + const executor = new QueryExecutor(api); + + expect(await executor.execute(query, { rejectResults: (_) => true })).toBeNull(); + }); + + it('not rejected', async () => { + const api = createPopulatedAPI(); + const media = generateViewMediaArray(); + vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media); + + const query = new EventMediaQueries([ + { + type: QueryType.Event as const, + cameraIDs: new Set(['camera.office']), + }, + ]); + const executor = new QueryExecutor(api); + + expect( + await executor.execute(query, { rejectResults: (_) => false }), + ).not.toBeNull(); + }); + }); + + describe('should select', () => { + it('by id', async () => { + const api = createPopulatedAPI(); + const media = generateViewMediaArray({ + cameraIDs: ['camera.office'], + count: 100, + }); + vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media); + + const query = new EventMediaQueries([ + { + type: QueryType.Event as const, + cameraIDs: new Set(['camera.office']), + }, + ]); + const executor = new QueryExecutor(api); + + const results = await executor.execute(query, { + selectResult: { id: 'id-camera.office-42' }, + }); + expect(results?.getSelectedResult()?.getID()).toBe('id-camera.office-42'); + }); + }); + + it('by func', async () => { + const api = createPopulatedAPI(); + const media = generateViewMediaArray({ + cameraIDs: ['camera.office'], + count: 100, + }); + vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media); + + const query = new EventMediaQueries([ + { + type: QueryType.Event as const, + cameraIDs: new Set(['camera.office']), + }, + ]); + const executor = new QueryExecutor(api); + + const results = await executor.execute(query, { + selectResult: { func: (media) => media.getID() === 'id-camera.office-43' }, + }); + expect(results?.getSelectedResult()?.getID()).toBe('id-camera.office-43'); + }); + + it('by time', async () => { + const now = new Date('2024-07-21T19:09:37Z'); + + const api = createPopulatedAPI(); + const media = [ + new TestViewMedia({ + cameraID: 'camera.office', + id: 'id-camera.office-0', + startTime: now, + }), + new TestViewMedia({ + cameraID: 'camera.office', + id: 'id-camera.office-1', + startTime: add(now, { seconds: 1 }), + }), + new TestViewMedia({ + cameraID: 'camera.office', + id: 'id-camera.office-2', + startTime: add(now, { seconds: 2 }), + }), + ]; + vi.mocked(api.getCameraManager().executeMediaQueries).mockResolvedValue(media); + + const query = new EventMediaQueries([ + { + type: QueryType.Event as const, + cameraIDs: new Set(['camera.office']), + }, + ]); + const executor = new QueryExecutor(api); + + const results = await executor.execute(query, { + selectResult: { time: { time: add(now, { seconds: 1 }) } }, + }); + expect(results?.getSelectedResult()?.getID()).toBe('id-camera.office-1'); + }); +}); diff --git a/tests/card-controller/view/test-utils.ts b/tests/card-controller/view/test-utils.ts new file mode 100644 index 00000000..926208a5 --- /dev/null +++ b/tests/card-controller/view/test-utils.ts @@ -0,0 +1,41 @@ +import { vi } from 'vitest'; +import { CardController } from '../../../src/card-controller/controller'; +import { RawFrigateCardConfig } from '../../../src/config/types'; +import { + createCameraManager, + createCapabilities, + createCardAPI, + createConfig, + createStore, +} from '../../test-utils'; + +export const createPopulatedAPI = (config?: RawFrigateCardConfig): CardController => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.office', + capabilities: createCapabilities({ + live: true, + snapshots: true, + clips: true, + recordings: true, + substream: true, + }), + }, + { + cameraID: 'camera.kitchen', + capabilities: createCapabilities({ + live: true, + snapshots: true, + clips: true, + recordings: true, + substream: true, + }), + }, + ]), + ); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue(createConfig(config)); + return api; +}; diff --git a/tests/card-controller/view/view-manager.test.ts b/tests/card-controller/view/view-manager.test.ts new file mode 100644 index 00000000..0f4094a6 --- /dev/null +++ b/tests/card-controller/view/view-manager.test.ts @@ -0,0 +1,363 @@ +import { ViewContext } from 'view'; +import { describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { ViewFactory } from '../../../src/card-controller/view/factory'; +import { ViewManager } from '../../../src/card-controller/view/view-manager'; +import { FrigateCardView } from '../../../src/config/types'; +import { + createCameraManager, + createCapabilities, + createCardAPI, + createStore, + createView, +} from '../../test-utils'; +import { ViewMedia } from '../../../src/view/media'; +import { MediaQueriesResults } from '../../../src/view/media-queries-results'; + +describe('should act correctly when view is set', () => { + it('basic view', () => { + const view = createView({ + view: 'live', + camera: 'camera', + displayMode: 'grid', + }); + + const factory = mock(); + factory.getViewDefault.mockReturnValue(view); + + const api = createCardAPI(); + const manager = new ViewManager(api, factory); + + manager.setViewDefault(); + + expect(manager.getView()).toBe(view); + expect(manager.hasView()).toBeTruthy(); + expect(api.getMediaLoadedInfoManager().clear).toBeCalled(); + expect(api.getCardElementManager().scrollReset).toBeCalled(); + expect(api.getMessageManager().reset).toBeCalled(); + expect(api.getStyleManager().setExpandedMode).toBeCalled(); + expect(api.getConditionsManager()?.setState).toBeCalledWith({ + view: 'live', + camera: 'camera', + displayMode: 'grid', + }); + expect(api.getCardElementManager().update).toBeCalled(); + }); + + it('view with minor changes without media clearing or scroll', () => { + const view_1 = createView({ + view: 'live', + camera: 'camera', + }); + const factory = mock(); + factory.getViewDefault.mockReturnValue(view_1); + + const api = createCardAPI(); + const manager = new ViewManager(api, factory); + + manager.setViewDefault(); + + vi.mocked(api.getMediaLoadedInfoManager().clear).mockClear(); + vi.mocked(api.getCardElementManager().scrollReset).mockClear(); + + const view_2 = createView({ + view: 'live', + camera: 'camera', + displayMode: 'single', + }); + factory.getViewDefault.mockReturnValue(view_2); + + manager.setViewDefault(); + + expect(manager.getView()).toBe(view_2); + + // The new view is neither a major media change, nor a different view name, + // so media clearing and scrolling should not happen. + expect(api.getMediaLoadedInfoManager().clear).not.toBeCalled(); + expect(api.getCardElementManager().scrollReset).not.toBeCalled(); + }); +}); + +it('setViewWithMergedContext', () => { + const api = createCardAPI(); + const factory = mock(); + + const manager = new ViewManager(api, factory); + const context: ViewContext = { timeline: {} }; + + // Setting context with no existing view does nothing. + manager.setViewWithMergedContext(context); + expect(manager.getView()).toBeNull(); + + const view = createView({ + view: 'live', + camera: 'camera', + }); + factory.getViewDefault.mockReturnValue(view); + manager.setViewDefault(); + manager.setViewWithMergedContext(context); + + expect(manager.getView()?.camera).toBe('camera'); + expect(manager.getView()?.view).toBe('live'); + expect(manager.getView()?.context).toEqual(context); +}); + +it('getEpoch', () => { + const factory = mock(); + const manager = new ViewManager(createCardAPI(), factory); + expect(manager.getEpoch()).toBeTruthy(); + expect(manager.getEpoch().manager).toBe(manager); +}); + +it('reset', () => { + const factory = mock(); + const manager = new ViewManager(createCardAPI(), factory); + + manager.reset(); + expect(manager.getView()).toBeNull(); + expect(manager.hasView()).toBeFalsy(); + + factory.getViewDefault.mockReturnValue(createView()); + manager.setViewDefault(); + + expect(manager.getView()).not.toBeNull(); + expect(manager.hasView()).toBeTruthy(); + + manager.reset(); + + expect(manager.getView()).toBeNull(); + expect(manager.hasView()).toBeFalsy(); +}); + +it('setViewDefault', () => { + const factory = mock(); + factory.getViewDefault.mockReturnValue(createView()); + + const manager = new ViewManager(createCardAPI(), factory); + manager.setViewDefault(); + + expect(manager.getView()?.view).toBe('live'); + expect(manager.getView()?.camera).toBe('camera'); +}); + +it('setViewByParameters', () => { + const factory = mock(); + factory.getViewByParameters.mockReturnValue(createView()); + + const manager = new ViewManager(createCardAPI(), factory); + manager.setViewByParameters(); + + expect(manager.getView()?.view).toBe('live'); + expect(manager.getView()?.camera).toBe('camera'); +}); + +it('setViewDefaultWithNewQuery', async () => { + const factory = mock(); + factory.getViewDefaultWithNewQuery.mockResolvedValue(createView()); + + const manager = new ViewManager(createCardAPI(), factory); + await manager.setViewDefaultWithNewQuery(); + + expect(manager.getView()?.view).toBe('live'); + expect(manager.getView()?.camera).toBe('camera'); +}); + +it('setViewByParametersWithNewQuery', async () => { + const factory = mock(); + factory.getViewByParametersWithNewQuery.mockResolvedValue(createView()); + + const manager = new ViewManager(createCardAPI(), factory); + await manager.setViewByParametersWithNewQuery(); + + expect(manager.getView()?.view).toBe('live'); + expect(manager.getView()?.camera).toBe('camera'); +}); + +it('setViewByParametersWithExistingQuery', async () => { + const factory = mock(); + factory.getViewByParametersWithExistingQuery.mockResolvedValue(createView()); + + const manager = new ViewManager(createCardAPI(), factory); + await manager.setViewByParametersWithExistingQuery(); + + expect(manager.getView()?.view).toBe('live'); + expect(manager.getView()?.camera).toBe('camera'); +}); + +describe('should handle exceptions', () => { + it('non-async', () => { + const factory = mock(); + const error = new Error(); + factory.getViewDefault.mockImplementation(() => { + throw error; + }); + + const api = createCardAPI(); + const manager = new ViewManager(api, factory); + manager.setViewDefault(); + + expect(manager.hasView()).toBeFalsy(); + expect(api.getMessageManager().setErrorIfHigherPriority).toBeCalledWith(error); + }); + + it('async', async () => { + const factory = mock(); + const error = new Error(); + factory.getViewByParametersWithNewQuery.mockRejectedValue(error); + + const api = createCardAPI(); + const manager = new ViewManager(api, factory); + await manager.setViewByParametersWithNewQuery(); + + expect(manager.hasView()).toBeFalsy(); + expect(api.getMessageManager().setErrorIfHigherPriority).toBeCalledWith(error); + }); +}); + +describe('isViewSupportedByCamera', () => { + it.each([ + ['live' as const, false], + ['image' as const, true], + ['diagnostics' as const, true], + ['clip' as const, false], + ['clips' as const, false], + ['snapshot' as const, false], + ['snapshots' as const, false], + ['recording' as const, false], + ['recordings' as const, false], + ['timeline' as const, false], + ['media' as const, false], + ])('%s', (viewName: FrigateCardView, expected: boolean) => { + const api = createCardAPI(); + vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); + vi.mocked(api.getCameraManager().getStore).mockReturnValue( + createStore([ + { + cameraID: 'camera.kitchen', + capabilities: createCapabilities({ + live: false, + 'favorite-events': false, + 'favorite-recordings': false, + seek: false, + clips: false, + recordings: false, + snapshots: false, + }), + }, + ]), + ); + const manager = new ViewManager(api); + + expect(manager.isViewSupportedByCamera('camera', viewName)).toBe(expected); + }); +}); + +describe('hasMajorMediaChange', () => { + it('should consider undefined views as major', () => { + const manager = new ViewManager(createCardAPI()); + + expect(manager.hasMajorMediaChange(undefined)).toBeFalsy(); + expect(manager.hasMajorMediaChange(createView())).toBeTruthy(); + expect(manager.hasMajorMediaChange()).toBeFalsy(); + }); + + it('should consider view change as major', () => { + const factory = mock(); + factory.getViewDefault.mockReturnValue(createView({ view: 'live' })); + + const manager = new ViewManager(createCardAPI(), factory); + manager.setViewDefault(); + + expect(manager.hasMajorMediaChange(createView({ view: 'clips' }))).toBeTruthy(); + }); + + it('should consider camera change as major', () => { + const factory = mock(); + factory.getViewDefault.mockReturnValue(createView({ camera: 'camera-1' })); + + const manager = new ViewManager(createCardAPI(), factory); + manager.setViewDefault(); + + expect(manager.hasMajorMediaChange(createView({ camera: 'camera-2' }))).toBeTruthy(); + }); + + it('should consider live substream change as major in live view', () => { + const overrides_1: Map = new Map(); + overrides_1.set('camera', 'camera-2'); + + const overrides_2: Map = new Map(); + overrides_2.set('camera', 'camera-3'); + + const factory = mock(); + factory.getViewDefault.mockReturnValue( + createView({ context: { live: { overrides: overrides_1 } } }), + ); + + const manager = new ViewManager(createCardAPI(), factory); + manager.setViewDefault(); + + expect( + manager.hasMajorMediaChange( + createView({ context: { live: { overrides: overrides_2 } } }), + ), + ).toBeTruthy(); + }); + + it('should not consider live substream change as major in other view', () => { + const overrides_1: Map = new Map(); + overrides_1.set('camera', 'camera-2'); + + const overrides_2: Map = new Map(); + overrides_2.set('camera', 'camera-3'); + + const factory = mock(); + factory.getViewDefault.mockReturnValue( + createView({ view: 'clips', context: { live: { overrides: overrides_1 } } }), + ); + + const manager = new ViewManager(createCardAPI(), factory); + manager.setViewDefault(); + + expect( + manager.hasMajorMediaChange( + createView({ view: 'clips', context: { live: { overrides: overrides_2 } } }), + ), + ).toBeFalsy(); + }); + + it('should consider result change as major in other view', () => { + const media = [new ViewMedia('clip', 'camera-1'), new ViewMedia('clip', 'camera-2')]; + const queryResults_1 = new MediaQueriesResults({ results: media, selectedIndex: 0 }); + const queryResults_2 = new MediaQueriesResults({ results: media, selectedIndex: 1 }); + + const factory = mock(); + factory.getViewDefault.mockReturnValue( + createView({ view: 'media', queryResults: queryResults_1 }), + ); + + const manager = new ViewManager(createCardAPI(), factory); + manager.setViewDefault(); + + expect( + manager.hasMajorMediaChange( + createView({ view: 'media', queryResults: queryResults_2 }), + ), + ).toBeTruthy(); + }); + + it('should not consider selected result change as major in live view', () => { + const media = [new ViewMedia('clip', 'camera-1'), new ViewMedia('clip', 'camera-2')]; + const queryResults_1 = new MediaQueriesResults({ results: media, selectedIndex: 0 }); + const queryResults_2 = new MediaQueriesResults({ results: media, selectedIndex: 1 }); + + const factory = mock(); + factory.getViewDefault.mockReturnValue(createView({ queryResults: queryResults_1 })); + + const manager = new ViewManager(createCardAPI(), factory); + manager.setViewDefault(); + + expect( + manager.hasMajorMediaChange(createView({ queryResults: queryResults_2 })), + ).toBeFalsy(); + }); +}); diff --git a/tests/components-lib/live/live-controller.test.ts b/tests/components-lib/live/live-controller.test.ts index b3dea6c9..85fd3b31 100644 --- a/tests/components-lib/live/live-controller.test.ts +++ b/tests/components-lib/live/live-controller.test.ts @@ -1,26 +1,15 @@ -import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { beforeEach, describe, expect, it, vi } from 'vitest'; import { LiveController } from '../../../src/components-lib/live/live-controller'; import { dispatchMessageEvent } from '../../../src/components/message'; -import { - changeViewToRecentEventsForCameraAndDependents, - changeViewToRecentRecordingForCameraAndDependents, -} from '../../../src/utils/media-to-view'; -import { EventMediaQueries } from '../../../src/view/media-queries'; import { IntersectionObserverMock, callIntersectionHandler, - createCameraManager, - createConfig, createLitElement, createMediaLoadedInfo, createMediaLoadedInfoEvent, createParent, - createView, - createViewChangeEvent, } from '../../test-utils'; -vi.mock('../../../src/utils/media-to-view'); - // @vitest-environment jsdom describe('LiveController', () => { beforeEach(() => { @@ -168,210 +157,4 @@ describe('LiveController', () => { expect(eventListener).toBeCalledTimes(1); expect(controller.getRenderEpoch()).toBe(secondRenderEpoch); }); - - it('should handle view change', () => { - const host = createLitElement(); - const parent = createParent({ children: [host] }); - const eventListener = vi.fn(); - parent.addEventListener('frigate-card:view:change', eventListener); - - const controller = new LiveController(host); - controller.hostConnected(); - const view = createView(); - - callIntersectionHandler(false); - expect(controller.isInBackground()).toBeTruthy(); - host.dispatchEvent(createViewChangeEvent(view)); - - expect(eventListener).toBeCalledTimes(0); - - callIntersectionHandler(true); - expect(controller.isInBackground()).toBeFalsy(); - - host.dispatchEvent(createViewChangeEvent(view)); - - expect(eventListener).toBeCalledTimes(1); - }); - - describe('should fetch media', () => { - it('when in background', async () => { - const controller = new LiveController(createLitElement()); - - callIntersectionHandler(false); - - await controller.fetchMediaInBackgroundIfNecessary( - createView(), - createCameraManager(), - {}, - createConfig().live, - ); - - expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled(); - expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled(); - }); - - it('when has existing query', async () => { - const controller = new LiveController(createLitElement()); - - await controller.fetchMediaInBackgroundIfNecessary( - createView({ query: new EventMediaQueries() }), - createCameraManager(), - {}, - createConfig().live, - ); - - expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled(); - expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled(); - }); - - it('when has no thumbnails', async () => { - const controller = new LiveController(createLitElement()); - - await controller.fetchMediaInBackgroundIfNecessary( - createView(), - createCameraManager(), - {}, - createConfig({ - live: { - controls: { - thumbnails: { - mode: 'none', - }, - }, - }, - }).live, - ); - - expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled(); - expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled(); - }); - - it('when fetch disabled in context', async () => { - const controller = new LiveController(createLitElement()); - - await controller.fetchMediaInBackgroundIfNecessary( - createView({ - context: { - live: { - fetchThumbnails: false, - }, - }, - }), - createCameraManager(), - {}, - createConfig().live, - ); - - expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled(); - expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled(); - }); - - describe('with fetch', () => { - const now = new Date('2024-04-07T19:43'); - beforeAll(() => { - vi.useFakeTimers(); - vi.setSystemTime(now); - }); - - afterAll(() => { - vi.useRealTimers(); - }); - - it('events', async () => { - const host = createLitElement(); - const controller = new LiveController(host); - const view = createView(); - const cameraManager = createCameraManager(); - const cardWideConfig = {}; - - await controller.fetchMediaInBackgroundIfNecessary( - view, - cameraManager, - cardWideConfig, - createConfig({ - live: { - controls: { - thumbnails: { - media_type: 'events', - events_media_type: 'all', - }, - timeline: { - window_seconds: 3600, - }, - }, - }, - }).live, - ); - - expect(changeViewToRecentEventsForCameraAndDependents).toBeCalledWith( - host, - cameraManager, - cardWideConfig, - view, - expect.objectContaining({ - allCameras: false, - targetView: 'live', - eventsMediaType: 'all', - select: 'latest', - viewContext: expect.objectContaining({ - timeline: { - window: { - start: new Date('2024-04-07T18:43'), - end: now, - }, - }, - }), - }), - ); - expect(changeViewToRecentRecordingForCameraAndDependents).not.toBeCalled(); - }); - - it('recordings', async () => { - const host = createLitElement(); - const controller = new LiveController(host); - const view = createView(); - const cameraManager = createCameraManager(); - const cardWideConfig = {}; - - await controller.fetchMediaInBackgroundIfNecessary( - view, - cameraManager, - cardWideConfig, - createConfig({ - live: { - controls: { - thumbnails: { - media_type: 'recordings', - }, - timeline: { - window_seconds: 3600, - }, - }, - }, - }).live, - ); - - expect(changeViewToRecentEventsForCameraAndDependents).not.toBeCalled(); - expect(changeViewToRecentRecordingForCameraAndDependents).toBeCalledWith( - host, - cameraManager, - cardWideConfig, - view, - expect.objectContaining({ - allCameras: false, - targetView: 'live', - select: 'latest', - viewContext: expect.objectContaining({ - timeline: { - window: { - start: new Date('2024-04-07T18:43'), - end: now, - }, - }, - }), - }), - ); - }); - }); - }); }); diff --git a/tests/components-lib/media-filter-controller.test.ts b/tests/components-lib/media-filter-controller.test.ts index cf08281d..da45ef7f 100644 --- a/tests/components-lib/media-filter-controller.test.ts +++ b/tests/components-lib/media-filter-controller.test.ts @@ -1,8 +1,10 @@ import { endOfDay, startOfDay, sub } from 'date-fns'; import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; import { Capabilities } from '../../src/camera-manager/capabilities'; import { CameraManagerStore } from '../../src/camera-manager/store'; import { QueryType } from '../../src/camera-manager/types'; +import { ViewManager } from '../../src/card-controller/view/view-manager'; import { MediaFilterController, MediaFilterCoreDefaults, @@ -10,7 +12,6 @@ import { MediaFilterCoreWhen, MediaFilterMediaType, } from '../../src/components-lib/media-filter-controller'; -import { executeMediaQueryForViewWithErrorDispatching } from '../../src/utils/media-to-view'; import { EventMediaQueries, MediaQueries, @@ -26,8 +27,6 @@ import { createView, } from '../test-utils'; -vi.mock('../../src/utils/media-to-view'); - const createCameraStore = (options?: { capabilities: Capabilities; }): CameraManagerStore => { @@ -295,59 +294,82 @@ describe('MediaFilterController', () => { describe('should get correct controls to show', () => { it('view with events', () => { - const view = createView({ query: new EventMediaQueries() }); + const viewManager = mock(); + viewManager.getView.mockReturnValue( + createView({ query: new EventMediaQueries() }), + ); const cameraManager = createCameraManager(); const controller = new MediaFilterController(createLitElement()); - expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ + controller.setViewManager(viewManager); + expect(controller.getControlsToShow(cameraManager)).toMatchObject({ events: true, recordings: false, }); }); it('view with recordings', () => { - const view = createView({ query: new RecordingMediaQueries() }); + const viewManager = mock(); + viewManager.getView.mockReturnValue( + createView({ query: new RecordingMediaQueries() }), + ); const cameraManager = createCameraManager(); const controller = new MediaFilterController(createLitElement()); - expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ + controller.setViewManager(viewManager); + expect(controller.getControlsToShow(cameraManager)).toMatchObject({ events: false, recordings: true, }); }); it('can favorite events', () => { - const view = createView({ query: new EventMediaQueries() }); + const viewManager = mock(); + viewManager.getView.mockReturnValue( + createView({ query: new EventMediaQueries() }), + ); const cameraManager = createCameraManager(); vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( createCapabilities({ 'favorite-events': true }), ); const controller = new MediaFilterController(createLitElement()); - expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ + controller.setViewManager(viewManager); + + expect(controller.getControlsToShow(cameraManager)).toMatchObject({ favorites: true, }); }); it('can favorite recordings', () => { - const view = createView({ query: new RecordingMediaQueries() }); + const viewManager = mock(); + viewManager.getView.mockReturnValue( + createView({ query: new RecordingMediaQueries() }), + ); + const cameraManager = createCameraManager(); vi.mocked(cameraManager.getAggregateCameraCapabilities).mockReturnValue( createCapabilities({ 'favorite-recordings': true }), ); const controller = new MediaFilterController(createLitElement()); - expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ + controller.setViewManager(viewManager); + + expect(controller.getControlsToShow(cameraManager)).toMatchObject({ favorites: true, }); }); it('can not favorite without a query', () => { - const view = createView(); + const viewManager = mock(); + viewManager.getView.mockReturnValue(createView()); + const cameraManager = createCameraManager(); const controller = new MediaFilterController(createLitElement()); - expect(controller.getControlsToShow(cameraManager, view)).toMatchObject({ + controller.setViewManager(viewManager); + + expect(controller.getControlsToShow(cameraManager)).toMatchObject({ favorites: false, }); }); @@ -355,40 +377,34 @@ describe('MediaFilterController', () => { describe('should handle value change', () => { it('must have visible cameras', async () => { - const host = createLitElement(); - const controller = new MediaFilterController(host); - await controller.valueChangeHandler( - createCameraManager(), - createView(), - {}, - { when: {} }, - ); + const viewManager = mock(); - expect(host.requestUpdate).not.toBeCalled(); + const controller = new MediaFilterController(createLitElement()); + controller.setViewManager(viewManager); + + await controller.valueChangeHandler(createCameraManager(), {}, { when: {} }); + + expect(viewManager.setViewByParametersWithExistingQuery).not.toBeCalled(); }); describe('with events media type', () => { it.each([['clips' as const], ['snapshots' as const]])( '%s', async (viewName: 'clips' | 'snapshots') => { - const eventListener = vi.fn(); const host = createLitElement(); - host.addEventListener('frigate-card:view:change', eventListener); + const viewManager = mock(); + viewManager.getView.mockReturnValue(createView()); const controller = new MediaFilterController(host); - const cameraManager = createCameraManager(); - const view = createView(); - vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); - vi.mocked(executeMediaQueryForViewWithErrorDispatching).mockResolvedValueOnce( - view, - ); + controller.setViewManager(viewManager); + + const cameraManager = createCameraManager(createCameraStore()); const from = new Date('2024-02-06T21:59'); const to = new Date('2024-02-06T22:00'); await controller.valueChangeHandler( cameraManager, - view, { performance: createPerformanceConfig({ features: { @@ -397,6 +413,7 @@ describe('MediaFilterController', () => { }), }, { + camera: 'camera.kitchen', mediaType: viewName === 'clips' ? MediaFilterMediaType.Clips @@ -412,20 +429,14 @@ describe('MediaFilterController', () => { }, ); - expect(vi.mocked(executeMediaQueryForViewWithErrorDispatching)).toBeCalledWith( - host, - cameraManager, - view, - expect.anything(), - { - targetCameraID: 'camera.kitchen', - targetView: viewName, - }, - ); + expect(viewManager.setViewByParametersWithExistingQuery).toBeCalledWith({ + params: expect.objectContaining({ + camera: 'camera.kitchen', + view: viewName, + }), + }); expect( - vi - .mocked(executeMediaQueryForViewWithErrorDispatching) - .mock.calls[0][3].getQueries(), + viewManager.setViewByParametersWithExistingQuery.mock.calls[0][0]?.params?.query?.getQueries(), ).toEqual([ { cameraIDs: new Set(['camera.kitchen']), @@ -442,31 +453,29 @@ describe('MediaFilterController', () => { }, ]); - expect(eventListener).toBeCalled(); expect(host.requestUpdate).toBeCalled(); }, ); }); it('with recordings media type', async () => { - const eventListener = vi.fn(); const host = createLitElement(); - host.addEventListener('frigate-card:view:change', eventListener); + + const cameraManager = createCameraManager(createCameraStore()); + + const viewManager = mock(); + viewManager.getView.mockReturnValue(createView()); + + vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); const controller = new MediaFilterController(host); - const cameraManager = createCameraManager(); - const view = createView(); - vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); - vi.mocked(executeMediaQueryForViewWithErrorDispatching).mockResolvedValueOnce( - view, - ); + controller.setViewManager(viewManager); const from = new Date('2024-02-06T21:59'); const to = new Date('2024-02-06T22:00'); await controller.valueChangeHandler( cameraManager, - view, { performance: createPerformanceConfig({ features: { @@ -484,20 +493,15 @@ describe('MediaFilterController', () => { }, ); - expect(vi.mocked(executeMediaQueryForViewWithErrorDispatching)).toBeCalledWith( - host, - cameraManager, - view, - expect.anything(), - { - targetCameraID: 'camera.kitchen', - targetView: 'recordings', - }, - ); + expect(viewManager.setViewByParametersWithExistingQuery).toBeCalledWith({ + params: expect.objectContaining({ + camera: 'camera.kitchen', + view: 'recordings', + }), + }); + expect( - vi - .mocked(executeMediaQueryForViewWithErrorDispatching) - .mock.calls[0][3].getQueries(), + viewManager.setViewByParametersWithExistingQuery.mock.calls[0][0]?.params?.query?.getQueries(), ).toEqual([ { cameraIDs: new Set(['camera.kitchen']), @@ -509,18 +513,21 @@ describe('MediaFilterController', () => { }, ]); - expect(eventListener).toBeCalled(); expect(host.requestUpdate).toBeCalled(); }); it('without favorites', async () => { - const controller = new MediaFilterController(createLitElement()); const cameraManager = createCameraManager(); vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); + const viewManager = mock(); + viewManager.getView.mockReturnValue(createView()); + + const controller = new MediaFilterController(createLitElement()); + controller.setViewManager(viewManager); + await controller.valueChangeHandler( cameraManager, - createView(), {}, { mediaType: MediaFilterMediaType.Recordings, @@ -528,10 +535,15 @@ describe('MediaFilterController', () => { }, ); + expect(viewManager.setViewByParametersWithExistingQuery).toBeCalledWith({ + params: expect.objectContaining({ + camera: 'camera.kitchen', + view: 'recordings', + }), + }); + expect( - vi - .mocked(executeMediaQueryForViewWithErrorDispatching) - .mock.calls[0][3].getQueries(), + viewManager.setViewByParametersWithExistingQuery.mock.calls[0][0]?.params?.query?.getQueries(), ).toEqual([ { cameraIDs: new Set(['camera.kitchen']), @@ -575,13 +587,17 @@ describe('MediaFilterController', () => { new Date('2024-02-29T23:59:59.999'), ], ])('%s', async (value: MediaFilterCoreWhen | string, from: Date, to: Date) => { - const controller = new MediaFilterController(createLitElement()); const cameraManager = createCameraManager(); vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); + const viewManager = mock(); + viewManager.getView.mockReturnValue(createView()); + + const controller = new MediaFilterController(createLitElement()); + controller.setViewManager(viewManager); + await controller.valueChangeHandler( cameraManager, - createView(), {}, { mediaType: MediaFilterMediaType.Recordings, @@ -590,11 +606,8 @@ describe('MediaFilterController', () => { }, }, ); - expect( - vi - .mocked(executeMediaQueryForViewWithErrorDispatching) - .mock.calls[0][3].getQueries(), + viewManager.setViewByParametersWithExistingQuery.mock.calls[0][0]?.params?.query?.getQueries(), ).toEqual([ { cameraIDs: new Set(['camera.kitchen']), @@ -606,13 +619,17 @@ describe('MediaFilterController', () => { }); it('custom without values', async () => { - const controller = new MediaFilterController(createLitElement()); const cameraManager = createCameraManager(); vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); + const viewManager = mock(); + viewManager.getView.mockReturnValue(createView()); + + const controller = new MediaFilterController(createLitElement()); + controller.setViewManager(viewManager); + await controller.valueChangeHandler( cameraManager, - createView(), {}, { mediaType: MediaFilterMediaType.Recordings, @@ -623,9 +640,7 @@ describe('MediaFilterController', () => { ); expect( - vi - .mocked(executeMediaQueryForViewWithErrorDispatching) - .mock.calls[0][3].getQueries(), + viewManager.setViewByParametersWithExistingQuery.mock.calls[0][0]?.params?.query?.getQueries(), ).toEqual([ { cameraIDs: new Set(['camera.kitchen']), @@ -638,24 +653,25 @@ describe('MediaFilterController', () => { describe('should calculate correct defaults', () => { it('with no queries', () => { - const controller = new MediaFilterController(createLitElement()); + const viewManager = mock(); + viewManager.getView.mockReturnValue(createView()); - controller.computeInitialDefaultsFromView(createCameraManager(), createView()); + const controller = new MediaFilterController(createLitElement()); + controller.setViewManager(viewManager); + + controller.computeInitialDefaultsFromView(createCameraManager()); expect(controller.getDefaults()).toBeNull(); }); it('with no cameras', () => { - const controller = new MediaFilterController(createLitElement()); + const viewManager = mock(); + viewManager.getView.mockReturnValue(createView()); - controller.computeInitialDefaultsFromView( - createCameraManager(), - createView({ - query: new EventMediaQueries([ - { type: QueryType.Event, cameraIDs: new Set(['camera.kitchen']) }, - ]), - }), - ); + const controller = new MediaFilterController(createLitElement()); + controller.setViewManager(viewManager); + + controller.computeInitialDefaultsFromView(createCameraManager()); expect(controller.getDefaults()).toBeNull(); }); @@ -948,17 +964,21 @@ describe('MediaFilterController', () => { mediaQueries: MediaQueries, defaults: MediaFilterCoreDefaults | null, ) => { - const controller = new MediaFilterController(createLitElement()); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); - - controller.computeInitialDefaultsFromView( - cameraManager, + const viewManager = mock(); + viewManager.getView.mockReturnValue( createView({ query: mediaQueries, }), ); + const controller = new MediaFilterController(createLitElement()); + controller.setViewManager(viewManager); + + const cameraManager = createCameraManager(); + vi.mocked(cameraManager.getStore).mockReturnValue(createCameraStore()); + + controller.computeInitialDefaultsFromView(cameraManager); + expect(controller.getDefaults()).toEqual(defaults); }, ); diff --git a/tests/components-lib/menu-button-controller.test.ts b/tests/components-lib/menu-button-controller.test.ts index c55b9c0c..5e7d5c30 100644 --- a/tests/components-lib/menu-button-controller.test.ts +++ b/tests/components-lib/menu-button-controller.test.ts @@ -6,7 +6,7 @@ import { CameraManager } from '../../src/camera-manager/manager'; import { CameraManagerCameraMetadata } from '../../src/camera-manager/types'; import { MediaPlayerManager } from '../../src/card-controller/media-player-manager'; import { MicrophoneManager } from '../../src/card-controller/microphone-manager'; -import { ViewManager } from '../../src/card-controller/view-manager'; +import { ViewManager } from '../../src/card-controller/view/view-manager'; import { MenuButtonController, MenuButtonControllerOptions, diff --git a/tests/components-lib/zoom/zoom-view-context.test.ts b/tests/components-lib/zoom/zoom-view-context.test.ts index 25508b5a..cf2320ba 100644 --- a/tests/components-lib/zoom/zoom-view-context.test.ts +++ b/tests/components-lib/zoom/zoom-view-context.test.ts @@ -1,9 +1,14 @@ import { describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { MergeContextViewModifier } from '../../../src/card-controller/view/modifiers/merge-context'; +import { ViewManager } from '../../../src/card-controller/view/view-manager'; import { generateViewContextForZoom, handleZoomSettingsObservedEvent, } from '../../../src/components-lib/zoom/zoom-view-context'; +vi.mock('../../../src/card-controller/view/modifiers/merge-context'); + describe('generateViewContextForZoom', () => { it('with observed', () => { expect( @@ -53,11 +58,9 @@ describe('generateViewContextForZoom', () => { // @vitest-environment jsdom it('handleZoomSettingsObservedEvent', () => { - const element = document.createElement('div'); - const callback = vi.fn(); - element.addEventListener('frigate-card:view:change-context', callback); + const viewManager = mock(); + handleZoomSettingsObservedEvent( - element, new CustomEvent('frigate-card:zoom:change', { detail: { pan: { x: 1, y: 2 }, @@ -66,18 +69,21 @@ it('handleZoomSettingsObservedEvent', () => { unzoomed: true, }, }), + viewManager, 'target', ); - expect(callback).toBeCalledWith( + expect(viewManager.setViewByParameters).toBeCalledWith( expect.objectContaining({ - detail: { - zoom: { - target: { - observed: { pan: { x: 1, y: 2 }, zoom: 3, isDefault: true, unzoomed: true }, - requested: null, - }, - }, - }, + modifiers: [expect.any(MergeContextViewModifier)], }), ); + + expect(MergeContextViewModifier).toBeCalledWith({ + zoom: { + target: { + observed: { pan: { x: 1, y: 2 }, zoom: 3, isDefault: true, unzoomed: true }, + requested: null, + }, + }, + }); }); diff --git a/tests/test-utils.ts b/tests/test-utils.ts index 2e5defb3..e066e719 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -35,7 +35,7 @@ import { MicrophoneManager } from '../src/card-controller/microphone-manager'; import { QueryStringManager } from '../src/card-controller/query-string-manager'; import { StyleManager } from '../src/card-controller/style-manager'; import { TriggersManager } from '../src/card-controller/triggers-manager'; -import { ViewManager } from '../src/card-controller/view-manager'; +import { ViewManager } from '../src/card-controller/view/view-manager'; import { CameraConfig, FrigateCardCondition, @@ -278,14 +278,6 @@ export const createMediaLoadedInfoEvent = ( }); }; -export const createViewChangeEvent = (view?: View): CustomEvent => { - return new CustomEvent('frigate-card:view:change', { - detail: view ?? createView(), - composed: true, - bubbles: true, - }); -}; - export const createPerformanceConfig = (config: unknown): PerformanceConfig => { return performanceConfigSchema.parse(config); }; @@ -297,7 +289,12 @@ export const generateViewMediaArray = (options?: { const media: ViewMedia[] = []; for (let i = 0; i < (options?.count ?? 100); ++i) { for (const cameraID of options?.cameraIDs ?? ['kitchen', 'office']) { - media.push(new TestViewMedia({ cameraID: cameraID, id: `id-${cameraID}-${i}` })); + media.push( + new TestViewMedia({ + cameraID: cameraID, + id: `id-${cameraID}-${i}`, + }), + ); } } return media; @@ -469,3 +466,10 @@ export const callHASubscribeMessageHandler = ( expect(mock.calls.length).greaterThan(n); mock.calls[n][0](ev); }; + +/** + * Flush resolved promises. + */ +export const flushPromises = async (): Promise => { + await new Promise(process.nextTick); +}; diff --git a/tests/utils/media-to-view.test.ts b/tests/utils/media-to-view.test.ts deleted file mode 100644 index 05493cb3..00000000 --- a/tests/utils/media-to-view.test.ts +++ /dev/null @@ -1,600 +0,0 @@ -import { add, sub } from 'date-fns'; -import { beforeEach, describe, expect, it, Mock, MockedFunction, vi } from 'vitest'; -import { QueryType } from '../../src/camera-manager/types'; -import { - changeViewToRecentEventsForCameraAndDependents, - changeViewToRecentRecordingForCameraAndDependents, - executeMediaQueryForView, - executeMediaQueryForViewWithErrorDispatching, - findBestMediaIndex, -} from '../../src/utils/media-to-view'; -import { ViewMedia } from '../../src/view/media'; -import { EventMediaQueries } from '../../src/view/media-queries'; -import { - createCameraManager, - createCapabilities, - createPerformanceConfig, - createStore, - createView, - TestViewMedia, -} from '../test-utils'; - -const createElementListenForView = (): { - element: HTMLElement; - viewHandler: EventListener; - messageHandler: EventListener; -} => { - const element = document.createElement('div'); - - const viewHandler = vi.fn(); - element.addEventListener('frigate-card:view:change', viewHandler); - - const messageHandler = vi.fn(); - element.addEventListener('frigate-card:message', messageHandler); - - return { - element: element, - viewHandler: viewHandler, - messageHandler: messageHandler, - }; -}; - -const getMediaFromHandlerCall = (handler: Mock): ViewMedia[] | null => { - return handler.mock.calls[0][0].detail.queryResults.getResults(); -}; - -const generateViewMedia = ( - index: number, - base: Date, - durationSeconds: number, - cameraID?: string, -): ViewMedia => { - return new TestViewMedia({ - id: `id-${index}`, - startTime: base, - endTime: add(base, { seconds: durationSeconds }), - ...(cameraID && { cameraID: cameraID }), - }); -}; - -// @vitest-environment jsdom -describe('changeViewToRecentEventsForCameraAndDependents', () => { - beforeEach(() => { - vi.resetAllMocks(); - }); - - it('should do nothing without camera config for selected camera', async () => { - const elementHandler = createElementListenForView(); - - await changeViewToRecentEventsForCameraAndDependents( - elementHandler.element, - createCameraManager(), - {}, - createView(), - ); - expect(elementHandler.viewHandler).not.toBeCalled(); - }); - - it('should do nothing without camera configs for all cameras', async () => { - const elementHandler = createElementListenForView(); - - await changeViewToRecentEventsForCameraAndDependents( - elementHandler.element, - createCameraManager(), - {}, - createView(), - { - allCameras: true, - }, - ); - expect(elementHandler.viewHandler).not.toBeCalled(); - }); - - it('should do nothing unless queries can be created', async () => { - const elementHandler = createElementListenForView(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue(null); - - await changeViewToRecentEventsForCameraAndDependents( - elementHandler.element, - cameraManager, - {}, - createView(), - { - eventsMediaType: 'clips', - }, - ); - expect(elementHandler.viewHandler).not.toBeCalled(); - }); - - it('should dispatch new view on success', async () => { - const elementHandler = createElementListenForView(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera', - capabilities: createCapabilities({ clips: true }), - }, - ]), - ); - vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue([ - { - type: QueryType.Event, - cameraIDs: new Set(['camera']), - }, - ]); - - const mediaArray = [new ViewMedia('clip', 'camera')]; - vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(mediaArray); - - await changeViewToRecentEventsForCameraAndDependents( - elementHandler.element, - cameraManager, - {}, - createView(), - { - targetView: 'clips', - select: 'latest', - }, - ); - expect(elementHandler.viewHandler).toBeCalled(); - expect(getMediaFromHandlerCall(vi.mocked(elementHandler.viewHandler))).toBe( - mediaArray, - ); - }); - - it('should dispatch error message on fail', async () => { - vi.spyOn(global.console, 'warn').mockImplementation(() => true); - - const elementHandler = createElementListenForView(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera', - capabilities: createCapabilities({ clips: true }), - }, - ]), - ); - vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue([ - { - type: QueryType.Event, - cameraIDs: new Set(['camera']), - }, - ]); - vi.mocked(cameraManager.executeMediaQueries).mockRejectedValue(new Error()); - - await changeViewToRecentEventsForCameraAndDependents( - elementHandler.element, - cameraManager, - {}, - createView(), - ); - expect(elementHandler.viewHandler).not.toBeCalled(); - expect(elementHandler.messageHandler).toBeCalled(); - }); - - it('should respect media chunk size', async () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera', - capabilities: createCapabilities({ clips: true }), - }, - ]), - ); - - await changeViewToRecentEventsForCameraAndDependents( - createElementListenForView().element, - cameraManager, - { - performance: createPerformanceConfig({ - features: { - media_chunk_size: 1000, - }, - }), - }, - createView(), - ); - - expect(cameraManager.generateDefaultEventQueries).toBeCalledWith( - expect.anything(), - expect.objectContaining({ - limit: 1000, - }), - ); - }); - - it('should respect useCache', async () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera', - capabilities: createCapabilities({ clips: true }), - }, - ]), - ); - vi.mocked(cameraManager.generateDefaultEventQueries).mockReturnValue([ - { - type: QueryType.Event, - cameraIDs: new Set(['camera']), - }, - ]); - - await changeViewToRecentEventsForCameraAndDependents( - createElementListenForView().element, - cameraManager, - {}, - createView(), - { - useCache: false, - }, - ); - - expect(vi.mocked(cameraManager.executeMediaQueries)).toBeCalledWith( - expect.anything(), - expect.objectContaining({ - useCache: false, - }), - ); - }); - - describe('should respect request for media type', () => { - it.each([ - ['snapshots' as const, 'hasSnapshot'], - ['clips' as const, 'hasClip'], - ])('%s', async (mediaType, queryParameter) => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera', - capabilities: createCapabilities({ [mediaType]: true }), - }, - ]), - ); - - await changeViewToRecentEventsForCameraAndDependents( - createElementListenForView().element, - cameraManager, - {}, - createView(), - { - eventsMediaType: mediaType, - }, - ); - - expect(cameraManager.generateDefaultEventQueries).toBeCalledWith( - expect.anything(), - expect.objectContaining({ - [queryParameter]: true, - }), - ); - }); - }); -}); - -// @vitest-environment jsdom -describe('executeMediaQueryForView', () => { - beforeEach(() => { - vi.resetAllMocks(); - }); - - it('should not execute empty queries', async () => { - expect( - await executeMediaQueryForView( - createCameraManager(), - createView(), - new EventMediaQueries(), - ), - ).toBeNull(); - }); - - it('should throw on failure', async () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.executeMediaQueries).mockRejectedValue(new Error()); - - await expect( - executeMediaQueryForView( - cameraManager, - createView(), - new EventMediaQueries([ - { - type: QueryType.Event, - cameraIDs: new Set('camera'), - }, - ]), - ), - ).rejects.toThrowError(); - }); - - it('should select time-based result', async () => { - const cameraManager = createCameraManager(); - - const now = new Date(); - const mediaArray = [ - generateViewMedia(0, now, 60), - generateViewMedia(1, now, 120), - generateViewMedia(2, now, 10), - ]; - vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(mediaArray); - - const view = await executeMediaQueryForView( - cameraManager, - createView(), - new EventMediaQueries([ - { - type: QueryType.Event, - cameraIDs: new Set('camera'), - }, - ]), - { - select: 'time', - targetTime: add(now, { seconds: 30 }), - }, - ); - - // Should select the longest event. - expect(view?.queryResults?.getSelectedIndex()).toBe(1); - expect(view?.queryResults?.getResults()).toBe(mediaArray); - }); - - it('should select nothing when time-based selection does not match', async () => { - const cameraManager = createCameraManager(); - - const now = new Date(); - const mediaArray = [ - generateViewMedia(0, now, 60), - generateViewMedia(1, now, 120), - generateViewMedia(2, now, 10), - ]; - - vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(mediaArray); - - const view = await executeMediaQueryForView( - cameraManager, - createView(), - new EventMediaQueries([ - { - type: QueryType.Event, - cameraIDs: new Set('camera'), - }, - ]), - { - select: 'time', - targetTime: sub(now, { seconds: 30 }), - }, - ); - - // Should leave selection untouched (last item will remain selected). - expect(view?.queryResults?.getSelectedIndex()).toBe(2); - expect(view?.queryResults?.getResults()).toBe(mediaArray); - }); - - it('should select nothing when query returns null', async () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(null); - - expect( - await executeMediaQueryForView( - cameraManager, - createView(), - new EventMediaQueries([ - { - type: QueryType.Event, - cameraIDs: new Set('camera'), - }, - ]), - ), - ).toBeNull(); - }); -}); - -// @vitest-environment jsdom -describe('changeViewToRecentRecordingForCameraAndDependents', () => { - beforeEach(() => { - vi.resetAllMocks(); - }); - - it('should do nothing without camera config for selected camera', async () => { - const elementHandler = createElementListenForView(); - - await changeViewToRecentRecordingForCameraAndDependents( - elementHandler.element, - createCameraManager(), - {}, - createView(), - ); - expect(elementHandler.viewHandler).not.toBeCalled(); - }); - - it('should do nothing without camera configs for all cameras', async () => { - const elementHandler = createElementListenForView(); - - await changeViewToRecentRecordingForCameraAndDependents( - elementHandler.element, - createCameraManager(), - {}, - createView(), - { - allCameras: true, - }, - ); - expect(elementHandler.viewHandler).not.toBeCalled(); - }); - - it('should do nothing unless queries can be created', async () => { - const elementHandler = createElementListenForView(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.generateDefaultRecordingQueries).mockReturnValue(null); - - await changeViewToRecentRecordingForCameraAndDependents( - elementHandler.element, - cameraManager, - {}, - createView(), - ); - expect(elementHandler.viewHandler).not.toBeCalled(); - }); - - it('should dispatch new view on success', async () => { - const elementHandler = createElementListenForView(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera', - capabilities: createCapabilities({ recordings: true }), - }, - ]), - ); - - const mediaArray = [new ViewMedia('recording', 'camera')]; - vi.mocked(cameraManager.executeMediaQueries).mockResolvedValue(mediaArray); - vi.mocked(cameraManager.generateDefaultRecordingQueries).mockReturnValue([ - { - type: QueryType.Recording, - cameraIDs: new Set(['camera']), - }, - ]); - - await changeViewToRecentRecordingForCameraAndDependents( - elementHandler.element, - cameraManager, - {}, - createView(), - { - targetView: 'recordings', - select: 'latest', - }, - ); - expect(elementHandler.viewHandler).toBeCalled(); - expect(getMediaFromHandlerCall(vi.mocked(elementHandler.viewHandler))).toBe( - mediaArray, - ); - }); - - it('should respect media chunk size', async () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera', - capabilities: createCapabilities({ recordings: true }), - }, - ]), - ); - - await changeViewToRecentRecordingForCameraAndDependents( - createElementListenForView().element, - cameraManager, - { - performance: createPerformanceConfig({ - features: { - media_chunk_size: 1000, - }, - }), - }, - createView(), - ); - - expect(cameraManager.generateDefaultRecordingQueries).toBeCalledWith( - expect.anything(), - expect.objectContaining({ - limit: 1000, - }), - ); - }); - - it('should respect useCache', async () => { - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.getStore).mockReturnValue( - createStore([ - { - cameraID: 'camera', - capabilities: createCapabilities({ recordings: true }), - }, - ]), - ); - vi.mocked(cameraManager.generateDefaultRecordingQueries).mockReturnValue([ - { - type: QueryType.Recording, - cameraIDs: new Set(['camera']), - }, - ]); - - await changeViewToRecentRecordingForCameraAndDependents( - createElementListenForView().element, - cameraManager, - {}, - createView(), - { - targetView: 'recordings', - select: 'latest', - useCache: false, - }, - ); - - expect(vi.mocked(cameraManager.executeMediaQueries)).toBeCalledWith( - expect.anything(), - expect.objectContaining({ - useCache: false, - }), - ); - }); -}); - -// @vitest-environment jsdom -describe('executeMediaQueryForViewWithErrorDispatching', () => { - it('should dispatch error message on fail', async () => { - vi.spyOn(global.console, 'warn').mockImplementation(() => true); - - const elementHandler = createElementListenForView(); - const cameraManager = createCameraManager(); - vi.mocked(cameraManager.executeMediaQueries).mockRejectedValue(new Error()); - - await executeMediaQueryForViewWithErrorDispatching( - elementHandler.element, - cameraManager, - createView(), - new EventMediaQueries([{ type: QueryType.Event, cameraIDs: new Set(['camera']) }]), - ); - - expect(elementHandler.viewHandler).not.toBeCalled(); - expect(elementHandler.messageHandler).toBeCalled(); - }); -}); - -// @vitest-environment jsdom -describe('findBestMediaIndex', () => { - it('should find best media index', async () => { - const now = new Date(); - const mediaArray = [ - generateViewMedia(0, now, 60), - generateViewMedia(1, now, 120), - generateViewMedia(2, now, 10), - ]; - - expect(findBestMediaIndex(mediaArray, add(now, { seconds: 30 }))).toBe(1); - }); - - it('should find best media index respecting favored cameraID', async () => { - const now = new Date(); - const mediaArray = [ - generateViewMedia(0, now, 60, 'less-good-camera'), - generateViewMedia(1, now, 120, 'less-good-camera'), - generateViewMedia(2, now, 10, 'favored-camera'), - generateViewMedia(3, now, 35, 'favored-camera'), - generateViewMedia(4, now, 40, 'favored-camera'), - generateViewMedia(5, now, 30, 'favored-camera'), - generateViewMedia(6, now, 300, 'less-good-camera'), - ]; - - expect( - findBestMediaIndex(mediaArray, add(now, { seconds: 30 }), 'favored-camera'), - ).toBe(4); - }); -}); diff --git a/tests/utils/substream.test.ts b/tests/utils/substream.test.ts index a9d1ea88..c75330b3 100644 --- a/tests/utils/substream.test.ts +++ b/tests/utils/substream.test.ts @@ -1,5 +1,9 @@ import { describe, expect, it } from 'vitest'; -import { getStreamCameraID, hasSubstream } from '../../src/utils/substream'; +import { + getStreamCameraID, + hasSubstream, + removeSubstream, +} from '../../src/utils/substream'; import { View } from '../../src/view/view'; describe('hasSubstream/getStreamCameraID', () => { @@ -54,3 +58,41 @@ describe('hasSubstream/getStreamCameraID', () => { expect(getStreamCameraID(view, 'camera3')).toBe('camera4'); }); }); + +describe('removeSubstream', () => { + it('should remove substream that exists', () => { + const view = new View({ + view: 'live', + camera: 'camera', + context: { + live: { + overrides: new Map([['camera', 'camera2']]), + }, + }, + }); + removeSubstream(view); + expect(view.context).toEqual({ + live: { + overrides: new Map(), + }, + }); + }); + + it('should not remove substream that does not exists', () => { + const view = new View({ + view: 'live', + camera: 'camera-has-no-overrides', + context: { + live: { + overrides: new Map([['camera', 'camera2']]), + }, + }, + }); + removeSubstream(view); + expect(view.context).toEqual({ + live: { + overrides: new Map([['camera', 'camera2']]), + }, + }); + }); +}); diff --git a/tests/view/view-to-cameras.test.ts b/tests/view/view-to-cameras.test.ts index 0d90ad73..723ce232 100644 --- a/tests/view/view-to-cameras.test.ts +++ b/tests/view/view-to-cameras.test.ts @@ -50,6 +50,9 @@ describe('getCameraIDsForViewName', () => { ['media' as const, 'clips' as const], ['media' as const, 'snapshots' as const], ['media' as const, 'recordings' as const], + ['timeline' as const, 'clips' as const], + ['timeline' as const, 'snapshots' as const], + ['timeline' as const, 'recordings' as const], ])('%s', (viewName: FrigateCardView, capabilityKey: CapabilityKey) => { const cameraManager = createCameraManager(); vi.mocked(cameraManager.getStore).mockReturnValue( diff --git a/tests/view/view.test.ts b/tests/view/view.test.ts index bea28a03..ab2ffa29 100644 --- a/tests/view/view.test.ts +++ b/tests/view/view.test.ts @@ -1,12 +1,8 @@ -import { describe, expect, it, vi } from 'vitest'; -import { QueryType } from '../../src/camera-manager/types'; -import { ViewMedia } from '../../src/view/media'; -import { EventMediaQueries, RecordingMediaQueries } from '../../src/view/media-queries'; +import { describe, expect, it } from 'vitest'; +import { EventMediaQueries } from '../../src/view/media-queries'; import { MediaQueriesResults } from '../../src/view/media-queries-results'; -import { View, dispatchViewContextChangeEvent } from '../../src/view/view'; import { createView } from '../test-utils'; -// @vitest-environment jsdom describe('View Basics', () => { it('should construct from parameters', () => { const query = new EventMediaQueries(); @@ -28,21 +24,28 @@ describe('View Basics', () => { expect(view.context).toBe(context); }); - it('should clone', () => { - const query = new EventMediaQueries(); - const queryResults = new MediaQueriesResults(); - const context = {}; + describe('should clone', () => { + it('with query and queryResults', () => { + const view = createView({ + view: 'live', + camera: 'camera', + query: new EventMediaQueries(), + queryResults: new MediaQueriesResults(), + context: {}, + }); - const view = createView({ - view: 'live', - camera: 'camera', - query: query, - queryResults: queryResults, - context: context, + expect(view.clone()).toEqual(view); }); - const clone = view.clone(); - expect(clone).toEqual(view); + it('without query and queryResults', () => { + const view = createView({ + view: 'live', + camera: 'camera', + context: {}, + }); + + expect(view.clone()).toEqual(view); + }); }); it('should evolve with everything set', () => { @@ -201,316 +204,6 @@ describe('View Basics', () => { expect(createView({ view: 'timeline' }).getDefaultMediaType()).toBeNull(); }); - it('should dispatch view', () => { - const element = document.createElement('div'); - const view = createView(); - const handler = vi.fn((ev) => { - expect(ev.detail).toBe(view); - }); - - element.addEventListener('frigate-card:view:change', handler); - view.dispatchChangeEvent(element); - expect(handler).toBeCalled(); - }); -}); - -describe('View.isMajorMediaChange', () => { - it('should consider undefined views as major', () => { - expect(View.isMajorMediaChange(createView(), undefined)).toBeTruthy(); - expect(View.isMajorMediaChange(undefined, createView())).toBeTruthy(); - expect(View.isMajorMediaChange()).toBeTruthy(); - }); - - it('should consider view change as major', () => { - expect( - View.isMajorMediaChange( - createView({ view: 'live' }), - createView({ view: 'snapshots' }), - ), - ).toBeTruthy(); - }); - - it('should consider camera change as major', () => { - expect( - View.isMajorMediaChange( - createView({ camera: 'camera-1' }), - createView({ camera: 'camera-2' }), - ), - ).toBeTruthy(); - }); - - it('should consider live substream change as major in live view', () => { - const overrides_1: Map = new Map(); - overrides_1.set('camera', 'camera-2'); - - const overrides_2: Map = new Map(); - overrides_2.set('camera', 'camera-3'); - - expect( - View.isMajorMediaChange( - createView({ context: { live: { overrides: overrides_1 } } }), - createView({ context: { live: { overrides: overrides_2 } } }), - ), - ).toBeTruthy(); - }); - - it('should not consider live substream change as major in other view', () => { - const overrides_1: Map = new Map(); - overrides_1.set('camera', 'camera-2'); - - const overrides_2: Map = new Map(); - overrides_2.set('camera', 'camera-3'); - - expect( - View.isMajorMediaChange( - createView({ view: 'clips', context: { live: { overrides: overrides_1 } } }), - createView({ view: 'clips', context: { live: { overrides: overrides_2 } } }), - ), - ).toBeFalsy(); - }); - - it('should consider result change as major in other view', () => { - const media = [new ViewMedia('clip', 'camera-1'), new ViewMedia('clip', 'camera-2')]; - const queryResults_1 = new MediaQueriesResults({ results: media, selectedIndex: 0 }); - const queryResults_2 = new MediaQueriesResults({ results: media, selectedIndex: 1 }); - expect( - View.isMajorMediaChange( - createView({ view: 'media', queryResults: queryResults_1 }), - createView({ view: 'media', queryResults: queryResults_2 }), - ), - ).toBeTruthy(); - }); - - it('should not consider selected result change as major in live view', () => { - const media = [new ViewMedia('clip', 'camera-1'), new ViewMedia('clip', 'camera-2')]; - const queryResults_1 = new MediaQueriesResults({ results: media, selectedIndex: 0 }); - const queryResults_2 = new MediaQueriesResults({ results: media, selectedIndex: 1 }); - expect( - View.isMajorMediaChange( - createView({ queryResults: queryResults_1 }), - createView({ queryResults: queryResults_2 }), - ), - ).toBeFalsy(); - }); -}); - -describe('View.adoptFromViewIfAppropriate', () => { - it('should adopt for gallery case', () => { - const query = new EventMediaQueries([ - { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, - ]); - const queryResults = new MediaQueriesResults(); - - const current = createView({ - view: 'clip', - query: query, - queryResults: queryResults, - }); - const next = createView({ view: 'clips' }); - View.adoptFromViewIfAppropriate(next, current); - expect(next.view).toBe('clips'); - expect(next.query).toBe(query); - expect(next.queryResults).toBe(queryResults); - }); - - it('should not adopt for gallery case if neither query nor results in current view', () => { - const current = createView({ - view: 'clip', - query: null, - queryResults: null, - }); - - const nextQuery = new EventMediaQueries([ - { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, - ]); - const nextResults = new MediaQueriesResults(); - const next = createView({ - view: 'clips', - query: nextQuery, - queryResults: nextResults, - }); - View.adoptFromViewIfAppropriate(next, current); - expect(next.view).toBe('clips'); - expect(next.query).toBe(nextQuery); - expect(next.queryResults).toBe(nextResults); - }); - - it.each([ - [ - new EventMediaQueries([ - { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, - ]), - 'clip', - ], - [ - new EventMediaQueries([ - { type: QueryType.Event, cameraIDs: new Set(['camera']), hasSnapshot: true }, - ]), - 'snapshot', - ], - [ - new RecordingMediaQueries([ - { type: QueryType.Recording, cameraIDs: new Set(['camera']) }, - ]), - 'recording', - ], - ])('should adopt in media case', (mediaQueries, expectedView) => { - const current = createView({ - view: 'media', - query: mediaQueries, - queryResults: new MediaQueriesResults(), - }); - const next = createView({ view: 'media' }); - View.adoptFromViewIfAppropriate(next, current); - expect(next.view).toBe(expectedView); - expect(next.query).toBeFalsy(); - expect(next.queryResults).toBeFalsy(); - }); - - it('should not adopt for mixed queries in media case', () => { - const query = new EventMediaQueries([ - { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, - { type: QueryType.Event, cameraIDs: new Set(['camera']), hasSnapshot: true }, - ]); - const results = new MediaQueriesResults(); - const current = createView({ - view: 'media', - query: query, - queryResults: results, - }); - const next = createView({ view: 'media' }); - View.adoptFromViewIfAppropriate(next, current); - - expect(next.view).toBe('media'); - expect(next.query).toBeNull(); - expect(next.queryResults).toBeNull(); - }); - - it('should not adopt when queries and results present in next view in media case', () => { - const currentQuery = new EventMediaQueries([ - { type: QueryType.Event, cameraIDs: new Set(['camera-1']), hasClip: true }, - { type: QueryType.Event, cameraIDs: new Set(['camera-1']), hasSnapshot: true }, - ]); - const currentResults = new MediaQueriesResults(); - const current = createView({ - view: 'media', - query: currentQuery, - queryResults: currentResults, - }); - - const nextQuery = new EventMediaQueries([ - { type: QueryType.Event, cameraIDs: new Set(['camera-2']), hasClip: true }, - { type: QueryType.Event, cameraIDs: new Set(['camera-2']), hasSnapshot: true }, - ]); - const nextResults = new MediaQueriesResults(); - const next = createView({ - view: 'media', - query: nextQuery, - queryResults: nextResults, - }); - View.adoptFromViewIfAppropriate(next, current); - - expect(next.view).toBe('media'); - expect(next.query).toBe(nextQuery); - expect(next.queryResults).toBe(nextResults); - }); - - it('should not adopt for other case', () => { - const query = new EventMediaQueries([ - { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, - ]); - const queryResults = new MediaQueriesResults(); - - const current = createView({ - view: 'media', - query: query, - queryResults: queryResults, - }); - const next = createView({ view: 'live' }); - View.adoptFromViewIfAppropriate(next, current); - expect(next.view).toBe('live'); - expect(next.query).toBeFalsy(); - expect(next.queryResults).toBeFalsy(); - }); - - it('should do nothing with undefined next view', () => { - const view_1 = createView(); - const view_2 = view_1.clone(); - View.adoptFromViewIfAppropriate(view_1); - expect(view_1).toEqual(view_2); - }); - - it('should adopt with query but no queryResults', () => { - const query = new EventMediaQueries([ - { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, - ]); - - const current = createView({ - view: 'media', - query: query, - }); - const next = createView({ - view: 'media', - query: query, - }); - View.adoptFromViewIfAppropriate(next, current); - expect(next.view).toBe('clip'); - }); - - it('should adopt live context overrides for substreams', () => { - const current = createView({ - view: 'live', - context: { - live: { - overrides: new Map([['camera', 'camera2']]), - }, - }, - }); - const next = createView({ - view: 'live', - }); - View.adoptFromViewIfAppropriate(next, current); - expect(next.context?.live).toEqual(current.context?.live); - }); - - it('should not adopt live context overrides if there are new overrides', () => { - const current = createView({ - view: 'live', - context: { - live: { - overrides: new Map([['camera', 'camera2']]), - }, - }, - }); - const next = createView({ - view: 'live', - context: { - live: { - overrides: new Map([['camera', 'camera3']]), - }, - }, - }); - View.adoptFromViewIfAppropriate(next, current); - expect(next.context?.live?.overrides).toEqual(new Map([['camera', 'camera3']])); - }); - - it('should adopt live context overrides even if there is new context', () => { - const current = createView({ - view: 'live', - context: { - live: { - overrides: new Map([['camera', 'camera2']]), - }, - }, - }); - const next = createView({ - view: 'live', - context: {}, - }); - View.adoptFromViewIfAppropriate(next, current); - expect(next.context?.live).toEqual(current.context?.live); - }); - it('should determine if display mode is grid', () => { expect(createView({ displayMode: 'grid' }).isGrid()).toBeTruthy(); expect(createView({ displayMode: 'single' }).isGrid()).toBeFalsy(); @@ -535,19 +228,3 @@ describe('View.adoptFromViewIfAppropriate', () => { expect(createView({ view: 'timeline' }).supportsMultipleDisplayModes()).toBeFalsy(); }); }); - -// @vitest-environment jsdom -describe('dispatchViewContextChangeEvent', () => { - it('should dispatch event', () => { - const context = {}; - const handler = vi.fn((ev) => { - expect(ev.detail).toBe(context); - }); - - const element = document.createElement('div'); - element.addEventListener('frigate-card:view:change-context', handler); - - dispatchViewContextChangeEvent(element, context); - expect(handler).toBeCalled(); - }); -}); diff --git a/vite.config.ts b/vite.config.ts index a35a2154..0808f0ab 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -37,7 +37,6 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'utils/interaction-mode.ts', 'utils/media-info.ts', 'utils/media-layout.ts', - 'utils/media-to-view.ts', 'utils/media.ts', 'utils/ptz.ts', 'utils/screenshot.ts', diff --git a/yarn.lock b/yarn.lock index 4d2adda6..7de17cfc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1833,14 +1833,23 @@ __metadata: languageName: node linkType: hard -"acorn-walk@npm:^8.0.2, acorn-walk@npm:^8.3.2": +"acorn-walk@npm:^8.0.2": version: 8.3.2 resolution: "acorn-walk@npm:8.3.2" checksum: 10c0/7e2a8dad5480df7f872569b9dccff2f3da7e65f5353686b1d6032ab9f4ddf6e3a2cb83a9b52cf50b1497fd522154dda92f0abf7153290cc79cd14721ff121e52 languageName: node linkType: hard -"acorn@npm:^8.1.0, acorn@npm:^8.11.3, acorn@npm:^8.8.2, acorn@npm:^8.9.0": +"acorn-walk@npm:^8.3.2": + version: 8.3.3 + resolution: "acorn-walk@npm:8.3.3" + dependencies: + acorn: "npm:^8.11.0" + checksum: 10c0/4a9e24313e6a0a7b389e712ba69b66b455b4cb25988903506a8d247e7b126f02060b05a8a5b738a9284214e4ca95f383dd93443a4ba84f1af9b528305c7f243b + languageName: node + linkType: hard + +"acorn@npm:^8.1.0, acorn@npm:^8.8.2, acorn@npm:^8.9.0": version: 8.11.3 resolution: "acorn@npm:8.11.3" bin: @@ -1849,6 +1858,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:^8.11.0, acorn@npm:^8.11.3": + version: 8.12.1 + resolution: "acorn@npm:8.12.1" + bin: + acorn: bin/acorn + checksum: 10c0/51fb26cd678f914e13287e886da2d7021f8c2bc0ccc95e03d3e0447ee278dd3b40b9c57dc222acd5881adcf26f3edc40901a4953403232129e3876793cd17386 + languageName: node + linkType: hard + "agent-base@npm:6": version: 6.0.2 resolution: "agent-base@npm:6.0.2" @@ -2621,6 +2639,13 @@ __metadata: languageName: node linkType: hard +"confbox@npm:^0.1.7": + version: 0.1.7 + resolution: "confbox@npm:0.1.7" + checksum: 10c0/18b40c2f652196a833f3f1a5db2326a8a579cd14eacabfe637e4fc8cb9b68d7cf296139a38c5e7c688ce5041bf46f9adce05932d43fde44cf7e012840b5da111 + languageName: node + linkType: hard + "configstore@npm:^5.0.1": version: 5.0.1 resolution: "configstore@npm:5.0.1" @@ -2981,11 +3006,11 @@ __metadata: linkType: hard "deep-eql@npm:^4.1.3": - version: 4.1.3 - resolution: "deep-eql@npm:4.1.3" + version: 4.1.4 + resolution: "deep-eql@npm:4.1.4" dependencies: type-detect: "npm:^4.0.0" - checksum: 10c0/ff34e8605d8253e1bf9fe48056e02c6f347b81d9b5df1c6650a1b0f6f847b4a86453b16dc226b34f853ef14b626e85d04e081b022e20b00cd7d54f079ce9bbdd + checksum: 10c0/264e0613493b43552fc908f4ff87b8b445c0e6e075656649600e1b8a17a57ee03e960156fce7177646e4d2ddaf8e5ee616d76bd79929ff593e5c79e4e5e6c517 languageName: node linkType: hard @@ -5209,10 +5234,10 @@ __metadata: languageName: node linkType: hard -"js-tokens@npm:^8.0.2": - version: 8.0.3 - resolution: "js-tokens@npm:8.0.3" - checksum: 10c0/b50ba7d926b087ad31949d8155c7bc84374e0785019b17bdddeb2c4f98f5dea04ba464651fe23a8be4f7d15f50d06ce8bb536087b24ce3ebfbaea4a1dc5869f0 +"js-tokens@npm:^9.0.0": + version: 9.0.0 + resolution: "js-tokens@npm:9.0.0" + checksum: 10c0/4ad1c12f47b8c8b2a3a99e29ef338c1385c7b7442198a425f3463f3537384dab6032012791bfc2f056ea5ecdb06b1ed4f70e11a3ab3f388d3dcebfe16a52b27d languageName: node linkType: hard @@ -5337,13 +5362,6 @@ __metadata: languageName: node linkType: hard -"jsonc-parser@npm:^3.2.0": - version: 3.2.1 - resolution: "jsonc-parser@npm:3.2.1" - checksum: 10c0/ada66dec143d7f9cb0e2d0d29c69e9ce40d20f3a4cb96b0c6efb745025ac7f9ba647d7ac0990d0adfc37a2d2ae084a12009a9c833dbdbeadf648879a99b9df89 - languageName: node - linkType: hard - "jsonfile@npm:^4.0.0": version: 4.0.0 resolution: "jsonfile@npm:4.0.0" @@ -5659,7 +5677,7 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.3": +"magic-string@npm:^0.30.3, magic-string@npm:^0.30.5": version: 0.30.10 resolution: "magic-string@npm:0.30.10" dependencies: @@ -5668,15 +5686,6 @@ __metadata: languageName: node linkType: hard -"magic-string@npm:^0.30.5": - version: 0.30.7 - resolution: "magic-string@npm:0.30.7" - dependencies: - "@jridgewell/sourcemap-codec": "npm:^1.4.15" - checksum: 10c0/d1d949f7a53c37c6e685f4ea7b2b151c2fe0cc5af8f1f979ecba916f7d60d58f35309aaf4c8b09ce1aef7c160b957be39a38b52b478a91650750931e4ddd5daf - languageName: node - linkType: hard - "magicast@npm:^0.3.3": version: 0.3.3 resolution: "magicast@npm:0.3.3" @@ -6025,15 +6034,15 @@ __metadata: languageName: node linkType: hard -"mlly@npm:^1.2.0, mlly@npm:^1.4.2": - version: 1.6.1 - resolution: "mlly@npm:1.6.1" +"mlly@npm:^1.4.2, mlly@npm:^1.7.1": + version: 1.7.1 + resolution: "mlly@npm:1.7.1" dependencies: acorn: "npm:^8.11.3" pathe: "npm:^1.1.2" - pkg-types: "npm:^1.0.3" - ufo: "npm:^1.3.2" - checksum: 10c0/a7bf26b3d4f83b0f5a5232caa3af44be08b464f562f31c11d885d1bc2d43b7d717137d47b0c06fdc69e1b33ffc09f902b6d2b18de02c577849d40914e8785092 + pkg-types: "npm:^1.1.1" + ufo: "npm:^1.5.3" + checksum: 10c0/d836a7b0adff4d118af41fb93ad4d9e57f80e694a681185280ba220a4607603c19e86c80f9a6c57512b04280567f2599e3386081705c5b5fd74c9ddfd571d0fa languageName: node linkType: hard @@ -6671,7 +6680,7 @@ __metadata: languageName: node linkType: hard -"pathe@npm:^1.1.0, pathe@npm:^1.1.1, pathe@npm:^1.1.2": +"pathe@npm:^1.1.1, pathe@npm:^1.1.2": version: 1.1.2 resolution: "pathe@npm:1.1.2" checksum: 10c0/64ee0a4e587fb0f208d9777a6c56e4f9050039268faaaaecd50e959ef01bf847b7872785c36483fa5cdcdbdfdb31fef2ff222684d4fc21c330ab60395c681897 @@ -6706,14 +6715,14 @@ __metadata: languageName: node linkType: hard -"pkg-types@npm:^1.0.3": - version: 1.0.3 - resolution: "pkg-types@npm:1.0.3" +"pkg-types@npm:^1.0.3, pkg-types@npm:^1.1.1": + version: 1.1.3 + resolution: "pkg-types@npm:1.1.3" dependencies: - jsonc-parser: "npm:^3.2.0" - mlly: "npm:^1.2.0" - pathe: "npm:^1.1.0" - checksum: 10c0/7f692ff2005f51b8721381caf9bdbc7f5461506ba19c34f8631660a215c8de5e6dca268f23a319dd180b8f7c47a0dc6efea14b376c485ff99e98d810b8f786c4 + confbox: "npm:^0.1.7" + mlly: "npm:^1.7.1" + pathe: "npm:^1.1.2" + checksum: 10c0/4cd2c9442dd5e4ae0c61cbd8fdaa92a273939749b081f78150ce9a3f4e625cca0375607386f49f103f0720b239d02369bf181c3ea6c80cf1028a633df03706ad languageName: node linkType: hard @@ -7314,9 +7323,9 @@ __metadata: linkType: hard "react-is@npm:^18.0.0": - version: 18.2.0 - resolution: "react-is@npm:18.2.0" - checksum: 10c0/6eb5e4b28028c23e2bfcf73371e72cd4162e4ac7ab445ddae2afe24e347a37d6dc22fae6e1748632cd43c6d4f9b8f86dcf26bf9275e1874f436d129952528ae0 + version: 18.3.1 + resolution: "react-is@npm:18.3.1" + checksum: 10c0/f2f1e60010c683479e74c63f96b09fb41603527cd131a9959e2aee1e5a8b0caf270b365e5ca77d4a6b18aae659b60a86150bb3979073528877029b35aecd2072 languageName: node linkType: hard @@ -8136,11 +8145,11 @@ __metadata: linkType: hard "strip-literal@npm:^2.0.0": - version: 2.0.0 - resolution: "strip-literal@npm:2.0.0" + version: 2.1.0 + resolution: "strip-literal@npm:2.1.0" dependencies: - js-tokens: "npm:^8.0.2" - checksum: 10c0/63a6e4224ac7088ff93fd19fc0f6882705020da2f0767dbbecb929cbf9d49022e72350420f47be635866823608da9b9a5caf34f518004721895b6031199fc3c8 + js-tokens: "npm:^9.0.0" + checksum: 10c0/bc8b8c8346125ae3c20fcdaf12e10a498ff85baf6f69597b4ab2b5fbf2e58cfd2827f1a44f83606b852da99a5f6c8279770046ddea974c510c17c98934c9cc24 languageName: node linkType: hard @@ -8273,9 +8282,9 @@ __metadata: linkType: hard "tinybench@npm:^2.5.1": - version: 2.6.0 - resolution: "tinybench@npm:2.6.0" - checksum: 10c0/60ea35699bf8bac9bc8cf279fa5877ab5b335b4673dcd07bf0fbbab9d7953a02c0ccded374677213eaa13aa147f54eb75d3230139ddbeec3875829ebe73db310 + version: 2.8.0 + resolution: "tinybench@npm:2.8.0" + checksum: 10c0/5a9a642351fa3e4955e0cbf38f5674be5f3ba6730fd872fd23a5c953ad6c914234d5aba6ea41ef88820180a81829ceece5bd8d3967c490c5171bca1141c2f24d languageName: node linkType: hard @@ -8287,9 +8296,9 @@ __metadata: linkType: hard "tinypool@npm:^0.8.3": - version: 0.8.3 - resolution: "tinypool@npm:0.8.3" - checksum: 10c0/c219d0cfb69de8e3cf17403034a508d773f2fccaad79a13cdbad68600c4fb10186ad814d2320bcaa8f6e774fff5666d2a3d3b241dc8a7ad9d970ee63fe620a32 + version: 0.8.4 + resolution: "tinypool@npm:0.8.4" + checksum: 10c0/779c790adcb0316a45359652f4b025958c1dff5a82460fe49f553c864309b12ad732c8288be52f852973bc76317f5e7b3598878aee0beb8a33322c0e72c4a66c languageName: node linkType: hard @@ -8583,10 +8592,10 @@ __metadata: languageName: node linkType: hard -"ufo@npm:^1.3.2": - version: 1.4.0 - resolution: "ufo@npm:1.4.0" - checksum: 10c0/d9a3cb8c5fd13356e0af661362244fd0a901edcdd08996f42553271007cae01e85dcec29a3303a87ddab6aa705cbd630332aaa8c268d037483536b198fa67a7c +"ufo@npm:^1.5.3": + version: 1.5.4 + resolution: "ufo@npm:1.5.4" + checksum: 10c0/b5dc4dc435c49c9ef8890f1b280a19ee4d0954d1d6f9ab66ce62ce64dd04c7be476781531f952a07c678d51638d02ad4b98e16237be29149295b0f7c09cda765 languageName: node linkType: hard @@ -9049,14 +9058,14 @@ __metadata: linkType: hard "why-is-node-running@npm:^2.2.2": - version: 2.2.2 - resolution: "why-is-node-running@npm:2.2.2" + version: 2.3.0 + resolution: "why-is-node-running@npm:2.3.0" dependencies: siginfo: "npm:^2.0.0" stackback: "npm:0.0.2" bin: why-is-node-running: cli.js - checksum: 10c0/805d57eb5d33f0fb4e36bae5dceda7fd8c6932c2aeb705e30003970488f1a2bc70029ee64be1a0e1531e2268b11e65606e88e5b71d667ea745e6dc48fc9014bd + checksum: 10c0/1cde0b01b827d2cf4cb11db962f3958b9175d5d9e7ac7361d1a7b0e2dc6069a263e69118bd974c4f6d0a890ef4eedfe34cf3d5167ec14203dbc9a18620537054 languageName: node linkType: hard @@ -9289,9 +9298,9 @@ __metadata: linkType: hard "yocto-queue@npm:^1.0.0": - version: 1.0.0 - resolution: "yocto-queue@npm:1.0.0" - checksum: 10c0/856117aa15cf5103d2a2fb173f0ab4acb12b4b4d0ed3ab249fdbbf612e55d1cadfd27a6110940e24746fb0a78cf640b522cc8bca76f30a3b00b66e90cf82abe0 + version: 1.1.1 + resolution: "yocto-queue@npm:1.1.1" + checksum: 10c0/cb287fe5e6acfa82690acb43c283de34e945c571a78a939774f6eaba7c285bacdf6c90fbc16ce530060863984c906d2b4c6ceb069c94d1e0a06d5f2b458e2a92 languageName: node linkType: hard From 73e7e6cf0fb8098031c0b1dbce173933da9597f6 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 29 Jul 2024 09:46:32 -0700 Subject: [PATCH 155/189] Bind to correct object. --- src/card-controller/view/view-manager.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/card-controller/view/view-manager.ts b/src/card-controller/view/view-manager.ts index da6ccde6..a3718a75 100644 --- a/src/card-controller/view/view-manager.ts +++ b/src/card-controller/view/view-manager.ts @@ -42,19 +42,22 @@ export class ViewManager implements ViewManagerInterface { } setViewDefault = (options?: ViewFactoryOptions): void => - this._setViewGeneric(this._factory.getViewDefault, options); + this._setViewGeneric(this._factory.getViewDefault.bind(this._factory), options); setViewByParameters = (options?: ViewFactoryOptions): void => - this._setViewGeneric(this._factory.getViewByParameters, options); + this._setViewGeneric(this._factory.getViewByParameters.bind(this._factory), options); setViewDefaultWithNewQuery = async (options?: ViewFactoryOptions): Promise => - await this._setViewGenericAsync(this._factory.getViewDefaultWithNewQuery, options); + await this._setViewGenericAsync( + this._factory.getViewDefaultWithNewQuery.bind(this._factory), + options, + ); setViewByParametersWithNewQuery = async ( options?: ViewFactoryOptions, ): Promise => await this._setViewGenericAsync( - this._factory.getViewByParametersWithNewQuery, + this._factory.getViewByParametersWithNewQuery.bind(this._factory), options, ); @@ -62,7 +65,7 @@ export class ViewManager implements ViewManagerInterface { options?: ViewFactoryOptions, ): Promise => await this._setViewGenericAsync( - this._factory.getViewByParametersWithExistingQuery, + this._factory.getViewByParametersWithExistingQuery.bind(this._factory), options, ); From d171aac09b14707b16977f5587b9ca20e8f46fce Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 29 Jul 2024 09:54:45 -0700 Subject: [PATCH 156/189] Make description more intuitive. --- src/localize/languages/en.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 72f3ff79..31904859 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -483,7 +483,7 @@ "none": "No action" } }, - "editor_label": "Behavior when a camera is triggered", + "editor_label": "Trigger behavior", "filter_selected_camera": "Only trigger on selected camera", "show_trigger_status": "Show pulsing border when triggered", "untrigger_seconds": "Seconds after inactive state change to untrigger" From f2ca80821e7faa911a22ca629bdf751e5563bdb4 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 29 Jul 2024 10:09:44 -0700 Subject: [PATCH 157/189] Update docs. --- docs/configuration/view.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/view.md b/docs/configuration/view.md index 9e2ad5dd..f97cfc8b 100644 --- a/docs/configuration/view.md +++ b/docs/configuration/view.md @@ -98,7 +98,7 @@ already occupied room will not trigger, but a newly occupied room will). | Option | Default | Description | | ------------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `interaction_mode` | `inactive` | Whether actions should be taken when the card is being interacted with. If `all`, actions will always left be taken regardless. If `inactive` actions will only be taken if the card has _not_ had human interaction recently (as defined by `view.interaction_seconds`). If `active` actions will only be taken if the card _has_ had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed. | -| `trigger` | `default` | If set to `default` the default view of the card will be reloaded. If set to `live` the triggered camera will be selected in `live` view. If set to `media` the appropriate media view (e.g. `clip` or `snapshot`) will be chosen to match a newly available media item (please note that only some [camera engines](cameras/engine.md) support new media detection, e.g. `frigate`). If set to `none` no action is taken. | +| `trigger` | `update` | If set to `update` the current view is updated in place. If set to `default` the default view of the card will be reloaded. If set to `live` the triggered camera will be selected in `live` view. If set to `media` the appropriate media view (e.g. `clip` or `snapshot`) will be chosen to match a newly available media item (please note that only some [camera engines](cameras/engine.md) support new media detection, e.g. `frigate`). If set to `none` no action is taken. | | `untrigger` | `none` | If set to `default` the the default view of the card will be reloaded. If set to `none` no action will be taken. | ## Supported views From 67c90aa577b5f065ad6096400994f6e002008d49 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 30 Jul 2024 02:17:47 -0700 Subject: [PATCH 158/189] Minor docs example updates. --- docs/configuration/view.md | 1 - docs/examples.md | 11 ++++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/configuration/view.md b/docs/configuration/view.md index f97cfc8b..73bb0fde 100644 --- a/docs/configuration/view.md +++ b/docs/configuration/view.md @@ -20,7 +20,6 @@ view: | `reset_after_interaction` | `true` | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | | `triggers` | | How to react when a camera is [triggered](cameras/README.md?id=triggers). | | `default_cycle_camera` | `false` | When set to `true` the selected camera is cycled on each default view change. | -| `update_entities` | | **YAML only**: A card-wide list of entities that should cause the view to reset to the default (if the entity only pertains to a particular camera use [`triggers`](cameras/README.md?id=triggers) for the selected camera instead. | ## `default_reset` diff --git a/docs/examples.md b/docs/examples.md index a6608a72..0bb99c27 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -479,9 +479,9 @@ overrides: This example changes the default card view from `live` to `image` depending on the value of the `binary_sensor.alarm_armed` sensor. The override alone will only change the _default_ when the card next is requested to change to the -default view. By also including the `update_entities` parameter, we ask the card -to trigger a card update based on that entity -- which causes it to use the new -overriden default immediately. +default view. By also including the `view.default_reset.entities` parameter, we +ask the card to trigger a card update based on that entity -- which causes it to +use the new overriden default immediately. ```yaml type: custom:frigate-card @@ -489,8 +489,9 @@ cameras: - camera_entity: camera.office view: default: live - update_entities: - - binary_sensor.alarm_armed + default_reset: + entities: + - binary_sensor.alarm_armed overrides: - conditions: - condition: state From 8823e769a2eefea8f6eecb7b88d4d2fe6b17c08f Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 30 Jul 2024 02:22:50 -0700 Subject: [PATCH 159/189] Remove unnecessary sentence. --- docs/configuration/view.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/configuration/view.md b/docs/configuration/view.md index 73bb0fde..c2003f82 100644 --- a/docs/configuration/view.md +++ b/docs/configuration/view.md @@ -16,7 +16,7 @@ view: | `default_reset` | | The circumstances and behavior that cause the card to reset to the default view. See below. | | `interaction_seconds` | `300` | After a mouse/touch interaction with the card, it will be considered "interacted with" until this number of seconds elapses without further interaction. May be used as part of an [interaction condition](conditions.md?id=interaction) or with `reset_after_interaction` to reset the view after the interaction is complete. `0` means no interactions are reported / acted upon. | | `keyboard_shortcuts` | See [usage](../usage/keyboard-shortcuts.md) for defaults. | Configure keyboard shortcuts. See below. | -| `render_entities` | | **YAML only**: A list of entity ids that should cause the card to re-render 'in-place'. The view/camera is not changed. `update_*` flags do not pertain/relate to the behavior of this flag. This should **very** rarely be needed, but could be useful if the card is both setting and changing HA state of the same object as could be the case for some complex `card_mod` scenarios ([example](https://github.com/dermotduffy/frigate-hass-card/issues/343)). | +| `render_entities` | | **YAML only**: A list of entity ids that should cause the card to re-render 'in-place'. The view/camera is not changed. This should **very** rarely be needed, but could be useful if the card is both setting and changing HA state of the same object as could be the case for some complex `card_mod` scenarios ([example](https://github.com/dermotduffy/frigate-hass-card/issues/343)). | | `reset_after_interaction` | `true` | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | | `triggers` | | How to react when a camera is [triggered](cameras/README.md?id=triggers). | | `default_cycle_camera` | `false` | When set to `true` the selected camera is cycled on each default view change. | From ef7b4b0ddf50c1775c039ae353a781c6e45ccfc5 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Tue, 30 Jul 2024 02:23:51 -0700 Subject: [PATCH 160/189] Formatting pass. --- docs/configuration/view.md | 26 +++++++++---------- rollup.config.js | 2 +- .../actions/actions/camera-select.ts | 2 +- src/card-controller/triggers-manager.ts | 8 +++--- .../view/modifiers/merge-context.ts | 6 ++--- .../view/modifiers/remove-context.ts | 6 ++--- .../view/modifiers/substream-off.ts | 1 - src/components/gallery.ts | 5 +++- src/view/view.ts | 7 +++-- .../card-controller/triggers-manager.test.ts | 2 +- .../view/modifiers/remove-context.test.ts | 1 - .../view/modifiers/substream-on.test.ts | 6 ++++- 12 files changed, 39 insertions(+), 33 deletions(-) diff --git a/docs/configuration/view.md b/docs/configuration/view.md index c2003f82..a33c5c71 100644 --- a/docs/configuration/view.md +++ b/docs/configuration/view.md @@ -7,19 +7,19 @@ view: # [...] ``` -| Option | Default | Description | -| ------------------------- | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `actions` | | [Actions](actions/README.md) to use for all views, individual actions may be overriden by view-specific actions. | -| `camera_select` | `current` | The [view](view.md?id=supported-views) to show when a new camera is selected (e.g. in the camera menu). If `current` the view is unchanged when a new camera is selected. | -| `dark_mode` | `off` | Whether or not to turn dark mode `on`, `off` or `auto` to automatically turn on if the card `interaction_seconds` has expired (i.e. card has been left unattended for that period of time) or if dark mode is enabled in the HA profile theme setting. Dark mode dims the brightness by `25%`. | -| `default` | `live` | The view to show in the card by default. The default camera is the first one listed. See [Supported Views](view.md?id=supported-views) below. | -| `default_reset` | | The circumstances and behavior that cause the card to reset to the default view. See below. | -| `interaction_seconds` | `300` | After a mouse/touch interaction with the card, it will be considered "interacted with" until this number of seconds elapses without further interaction. May be used as part of an [interaction condition](conditions.md?id=interaction) or with `reset_after_interaction` to reset the view after the interaction is complete. `0` means no interactions are reported / acted upon. | -| `keyboard_shortcuts` | See [usage](../usage/keyboard-shortcuts.md) for defaults. | Configure keyboard shortcuts. See below. | +| Option | Default | Description | +| ------------------------- | --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `actions` | | [Actions](actions/README.md) to use for all views, individual actions may be overriden by view-specific actions. | +| `camera_select` | `current` | The [view](view.md?id=supported-views) to show when a new camera is selected (e.g. in the camera menu). If `current` the view is unchanged when a new camera is selected. | +| `dark_mode` | `off` | Whether or not to turn dark mode `on`, `off` or `auto` to automatically turn on if the card `interaction_seconds` has expired (i.e. card has been left unattended for that period of time) or if dark mode is enabled in the HA profile theme setting. Dark mode dims the brightness by `25%`. | +| `default` | `live` | The view to show in the card by default. The default camera is the first one listed. See [Supported Views](view.md?id=supported-views) below. | +| `default_reset` | | The circumstances and behavior that cause the card to reset to the default view. See below. | +| `interaction_seconds` | `300` | After a mouse/touch interaction with the card, it will be considered "interacted with" until this number of seconds elapses without further interaction. May be used as part of an [interaction condition](conditions.md?id=interaction) or with `reset_after_interaction` to reset the view after the interaction is complete. `0` means no interactions are reported / acted upon. | +| `keyboard_shortcuts` | See [usage](../usage/keyboard-shortcuts.md) for defaults. | Configure keyboard shortcuts. See below. | | `render_entities` | | **YAML only**: A list of entity ids that should cause the card to re-render 'in-place'. The view/camera is not changed. This should **very** rarely be needed, but could be useful if the card is both setting and changing HA state of the same object as could be the case for some complex `card_mod` scenarios ([example](https://github.com/dermotduffy/frigate-hass-card/issues/343)). | -| `reset_after_interaction` | `true` | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | -| `triggers` | | How to react when a camera is [triggered](cameras/README.md?id=triggers). | -| `default_cycle_camera` | `false` | When set to `true` the selected camera is cycled on each default view change. | +| `reset_after_interaction` | `true` | If `true` the card will reset to the default configured view (i.e. 'screensaver' functionality) after `interaction_seconds` has elapsed after user interaction. | +| `triggers` | | How to react when a camera is [triggered](cameras/README.md?id=triggers). | +| `default_cycle_camera` | `false` | When set to `true` the selected camera is cycled on each default view change. | ## `default_reset` @@ -97,7 +97,7 @@ already occupied room will not trigger, but a newly occupied room will). | Option | Default | Description | | ------------------ | ---------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `interaction_mode` | `inactive` | Whether actions should be taken when the card is being interacted with. If `all`, actions will always left be taken regardless. If `inactive` actions will only be taken if the card has _not_ had human interaction recently (as defined by `view.interaction_seconds`). If `active` actions will only be taken if the card _has_ had human interaction recently. This does not stop triggering itself (i.e. border will still pulse if `show_trigger_status` is true) but rather just prevents the actions being performed. | -| `trigger` | `update` | If set to `update` the current view is updated in place. If set to `default` the default view of the card will be reloaded. If set to `live` the triggered camera will be selected in `live` view. If set to `media` the appropriate media view (e.g. `clip` or `snapshot`) will be chosen to match a newly available media item (please note that only some [camera engines](cameras/engine.md) support new media detection, e.g. `frigate`). If set to `none` no action is taken. | +| `trigger` | `update` | If set to `update` the current view is updated in place. If set to `default` the default view of the card will be reloaded. If set to `live` the triggered camera will be selected in `live` view. If set to `media` the appropriate media view (e.g. `clip` or `snapshot`) will be chosen to match a newly available media item (please note that only some [camera engines](cameras/engine.md) support new media detection, e.g. `frigate`). If set to `none` no action is taken. | | `untrigger` | `none` | If set to `default` the the default view of the card will be reloaded. If set to `none` no action will be taken. | ## Supported views diff --git a/rollup.config.js b/rollup.config.js index 33ca36e7..be40c43a 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -51,7 +51,7 @@ const plugins = [ typescript({ sourceMap: dev, inlineSources: dev, - exclude: ["tests/**/*.test.ts"], + exclude: ['tests/**/*.test.ts'], }), json({ exclude: 'package.json' }), replace({ diff --git a/src/card-controller/actions/actions/camera-select.ts b/src/card-controller/actions/actions/camera-select.ts index 395b47d3..b492bf0d 100644 --- a/src/card-controller/actions/actions/camera-select.ts +++ b/src/card-controller/actions/actions/camera-select.ts @@ -17,7 +17,7 @@ export class CameraSelectAction extends FrigateCardAction { +export const mergeViewContext = ( + a?: ViewContext | null, + b?: ViewContext | null, +): ViewContext => { return merge({}, a, b); -} +}; export class View { public view: FrigateCardView; diff --git a/tests/card-controller/triggers-manager.test.ts b/tests/card-controller/triggers-manager.test.ts index 88b058e6..0ea09bec 100644 --- a/tests/card-controller/triggers-manager.test.ts +++ b/tests/card-controller/triggers-manager.test.ts @@ -465,7 +465,7 @@ describe('TriggersManager', () => { params: { view: 'live' as const, camera: 'camera_1' as const, - } + }, }); await manager.handleCameraEvent({ diff --git a/tests/card-controller/view/modifiers/remove-context.test.ts b/tests/card-controller/view/modifiers/remove-context.test.ts index 28795272..27ad3fde 100644 --- a/tests/card-controller/view/modifiers/remove-context.test.ts +++ b/tests/card-controller/view/modifiers/remove-context.test.ts @@ -23,4 +23,3 @@ it('should remove context property', () => { expect(view.context).toEqual({}); }); - \ No newline at end of file diff --git a/tests/card-controller/view/modifiers/substream-on.test.ts b/tests/card-controller/view/modifiers/substream-on.test.ts index cbba3e27..ea82b18a 100644 --- a/tests/card-controller/view/modifiers/substream-on.test.ts +++ b/tests/card-controller/view/modifiers/substream-on.test.ts @@ -2,7 +2,11 @@ import { describe, expect, it, vi } from 'vitest'; import { CardController } from '../../../../src/card-controller/controller'; import { SubstreamOnViewModifier } from '../../../../src/card-controller/view/modifiers/substream-on'; import { RawFrigateCardConfig } from '../../../../src/config/types'; -import { getStreamCameraID, hasSubstream, setSubstream } from '../../../../src/utils/substream'; +import { + getStreamCameraID, + hasSubstream, + setSubstream, +} from '../../../../src/utils/substream'; import { createCameraConfig, createCameraManager, From e503f0e429e3ddbc5850f85103de9934276b1426 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Fri, 16 Aug 2024 20:08:21 -0700 Subject: [PATCH 161/189] Initial version of status bar. --- docs/configuration/README.md | 2 +- docs/configuration/_sidebar.md | 3 +- docs/configuration/actions/README.md | 2 +- docs/configuration/actions/_sidebar.md | 4 +- docs/configuration/actions/custom/README.md | 81 +++- docs/configuration/actions/custom/_sidebar.md | 4 +- docs/configuration/actions/stock/_sidebar.md | 4 +- docs/configuration/cameras/_sidebar.md | 4 +- docs/configuration/elements.md | 356 ------------------ docs/configuration/elements/README.md | 24 ++ docs/configuration/elements/_sidebar.md | 29 ++ docs/configuration/elements/custom/README.md | 258 +++++++++++++ .../configuration/elements/custom/_sidebar.md | 29 ++ docs/configuration/elements/stock/README.md | 173 +++++++++ docs/configuration/elements/stock/_sidebar.md | 29 ++ docs/configuration/live.md | 20 - docs/configuration/media-viewer.md | 20 - docs/configuration/status-bar.md | 82 ++++ docs/examples.md | 46 +++ docs/troubleshooting.md | 19 +- .../actions/actions/status-bar.ts | 24 ++ src/card-controller/actions/factory.ts | 5 +- src/card-controller/config/config-manager.ts | 2 + src/card-controller/controller.ts | 6 + .../status-bar-item-manager.ts | 160 ++++++++ src/card-controller/types.ts | 17 +- src/card.ts | 112 +++++- .../utils/get-technology-for-video-rtc.ts | 12 + src/components-lib/menu-controller.ts | 2 +- src/components-lib/status-bar-controller.ts | 119 ++++++ src/components/elements.ts | 159 +++++--- src/components/live/go2rtc/video-rtc.js | 4 + src/components/live/live-jsmpeg.ts | 1 + src/components/live/live-webrtc-card.ts | 15 +- src/components/live/live.ts | 29 -- src/components/overlay.ts | 25 ++ src/components/status-bar.ts | 91 +++++ src/components/submenu.ts | 7 +- src/components/surround-basic.ts | 4 - src/components/title-control.ts | 98 ----- src/components/viewer.ts | 30 +- src/config/management.ts | 41 +- src/config/profiles/low-performance.ts | 7 +- src/config/types.ts | 164 ++++++-- src/const.ts | 16 +- src/editor.ts | 255 ++++++------- src/localize/languages/ca.json | 41 +- src/localize/languages/en.json | 41 +- src/localize/languages/fr.json | 41 +- src/localize/languages/it.json | 41 +- src/localize/languages/pt-BR.json | 41 +- src/localize/languages/pt-PT.json | 41 +- src/patches/ha-camera-stream.ts | 5 +- src/patches/ha-hls-player.ts | 1 + src/patches/ha-web-rtc-player.ts | 1 + src/scss/card.scss | 66 +++- src/scss/menu.scss | 64 +--- src/scss/overlay.scss | 66 ++++ src/scss/status.scss | 82 ++++ src/scss/title-control.scss | 29 -- src/types.ts | 4 + src/utils/media-info.ts | 3 + tests/camera-manager/manager.test.ts | 1 - .../actions/actions/status-bar.test.ts | 67 ++++ tests/card-controller/actions/factory.test.ts | 7 +- .../conditions-manager.test.ts | 27 +- tests/card-controller/controller.test.ts | 8 + .../status-bar-item-manager.test.ts | 243 ++++++++++++ .../get-technology-for-video-rts.test.ts | 24 ++ tests/components-lib/menu-controller.test.ts | 37 +- .../status-bar-controller.test.ts | 330 ++++++++++++++++ tests/config/management.test.ts | 112 +++++- tests/config/profiles/low-performance.test.ts | 3 +- tests/config/types.test.ts | 80 +++- tests/test-utils.ts | 25 +- tsconfig.json | 3 +- vite.config.ts | 5 +- 77 files changed, 3072 insertions(+), 1061 deletions(-) delete mode 100644 docs/configuration/elements.md create mode 100644 docs/configuration/elements/README.md create mode 100644 docs/configuration/elements/_sidebar.md create mode 100644 docs/configuration/elements/custom/README.md create mode 100644 docs/configuration/elements/custom/_sidebar.md create mode 100644 docs/configuration/elements/stock/README.md create mode 100644 docs/configuration/elements/stock/_sidebar.md create mode 100644 docs/configuration/status-bar.md create mode 100644 src/card-controller/actions/actions/status-bar.ts create mode 100644 src/card-controller/status-bar-item-manager.ts create mode 100644 src/components-lib/live/utils/get-technology-for-video-rtc.ts create mode 100644 src/components-lib/status-bar-controller.ts create mode 100644 src/components/overlay.ts create mode 100644 src/components/status-bar.ts delete mode 100644 src/components/title-control.ts create mode 100644 src/scss/overlay.scss create mode 100644 src/scss/status.scss delete mode 100644 src/scss/title-control.scss create mode 100644 tests/card-controller/actions/actions/status-bar.test.ts create mode 100644 tests/card-controller/status-bar-item-manager.test.ts create mode 100644 tests/components-lib/live/utils/get-technology-for-video-rts.test.ts create mode 100644 tests/components-lib/status-bar-controller.test.ts diff --git a/docs/configuration/README.md b/docs/configuration/README.md index b7ac589d..b19be1b1 100644 --- a/docs/configuration/README.md +++ b/docs/configuration/README.md @@ -23,7 +23,7 @@ Only the `cameras` option is required, all other parameters are optional. | [`cameras_global`](cameras/README.md) | Global defaults that apply to all cameras from the `cameras` section. | | `card_id` | An optional ID to uniquely identify this card. For use when actions are being sent to card(s) via [URL actions](../usage/url-actions.md). Must exclusively consist of these characters: `[a-zA-Z0-9_]`. | | [`dimensions`](dimensions.md) | Configures the overall card dimensions. | -| [`elements`](elements.md) | Add custom elements to the card. | +| [`elements`](elements/README.md) | Add custom elements to the card. | | [`image`](image.md) | Configures the `image` view. | | [`live`](live.md) | Configures the `live` view. | | [`media_gallery`](media-gallery.md) | Configures the media gallery. | diff --git a/docs/configuration/_sidebar.md b/docs/configuration/_sidebar.md index 0bc10e8c..1e65dac7 100644 --- a/docs/configuration/_sidebar.md +++ b/docs/configuration/_sidebar.md @@ -5,7 +5,7 @@ - [`cameras`](cameras/README.md) - [`conditions`](conditions.md) - [`dimensions`](dimensions.md) - - [`elements`](elements.md) + - [`elements`](elements/README.md) - [`image`](image.md) - [`live`](live.md) - [`media_gallery`](media-gallery.md) @@ -14,6 +14,7 @@ - [`overrides`](overrides.md) - [`performance`](performance.md) - [`profiles`](profiles.md) + - [`status_bar`](status-bar.md) - [`timeline`](timeline.md) - [`view`](view.md) - [Examples](../examples.md) diff --git a/docs/configuration/actions/README.md b/docs/configuration/actions/README.md index 0990d952..22114ff2 100644 --- a/docs/configuration/actions/README.md +++ b/docs/configuration/actions/README.md @@ -7,7 +7,7 @@ multiple other blocks. Actions are pre-configured activities that can be triggered in response to a variety of circumstances (e.g. tapping on a menu icon, double tapping on an -[element](../elements.md) or holding the mouse/tap down on a particular +[element](../elements/README.md) or holding the mouse/tap down on a particular [view](../view.md?id=supported-views)). ### Differences in actions between Frigate Card and Home Assistant diff --git a/docs/configuration/actions/_sidebar.md b/docs/configuration/actions/_sidebar.md index b9258a61..0da30b6e 100644 --- a/docs/configuration/actions/_sidebar.md +++ b/docs/configuration/actions/_sidebar.md @@ -7,7 +7,7 @@ - [`cameras`](../cameras/README.md) - [`conditions`](../conditions.md) - [`dimensions`](../dimensions.md) - - [`elements`](../elements.md) + - [`elements`](../elements/README.md) - [`image`](../image.md) - [`live`](../live.md) - [`media_gallery`](../media-gallery.md) @@ -16,8 +16,10 @@ - [`overrides`](../overrides.md) - [`performance`](../performance.md) - [`profiles`](../profiles.md) + - [`status_bar`](../status-bar.md) - [`timeline`](../timeline.md) - [`view`](../view.md) +- [Examples](../../examples.md) - [Screenshots](../../screenshots.md) - [Troubleshooting](../../troubleshooting.md) - [Usage](../../usage/README.md) diff --git a/docs/configuration/actions/custom/README.md b/docs/configuration/actions/custom/README.md index 15fb42f4..4f7d1b67 100644 --- a/docs/configuration/actions/custom/README.md +++ b/docs/configuration/actions/custom/README.md @@ -450,15 +450,25 @@ action: custom:frigate-card-action frigate_card_action: snapshot ``` -## `snapshots` +## `status_bar` -Change to the `snapshots` view. +Add or remove items from the status bar. ```yaml action: custom:frigate-card-action -frigate_card_action: snapshots +frigate_card_action: status_bar +# [...] ``` +| Parameter | Default | Description | +| ------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `status_bar_action` | | If `add` adds `items` to the status bar, if `remove` removes items and if `reset` resets the status bar entirely (removes all dynamically added items). | +| `items` | | The items to `add` or `remove`. See below. | + +### `items` + +The items parameter is a list of items to `add` or `remove`. See [`custom:frigate-card-status-bar-icon`](../../elements/custom/README.md?id=status-bar-icon), [`custom:frigate-card-status-bar-image`](../../elements/custom/README.md?id=status-bar-image), [`custom:frigate-card-status-bar-string`](../../elements/custom/README.md?id=status-bar-string) for the allowable items and their parameters. See the [fully expanded reference](./README.md?fully-expanded-reference) below for a complete example. + ## `timeline` Change to the `timeline` view. @@ -732,4 +742,69 @@ elements: tap_action: action: custom:frigate-card-action frigate_card_action: unmute + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-h-circle-outline + title: Add status bar contents + tap_action: + - action: custom:frigate-card-action + frigate_card_action: status_bar + status_bar_action: add + items: + - type: custom:frigate-card-status-bar-string + enabled: true + exclusive: false + expand: false + string: 'Intruder alert!' + priority: 50 + sufficient: false + - type: custom:frigate-card-status-bar-icon + enabled: true + exclusive: false + expand: false + icon: 'mdi:cow' + priority: 50 + sufficient: false + - type: custom:frigate-card-status-bar-image + enabled: true + exclusive: false + expand: false + image: https://my.site.com/status.png + priority: 50 + sufficient: false + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-i-circle-outline + title: Remove status bar contents + tap_action: + - action: custom:frigate-card-action + frigate_card_action: status_bar + status_bar_action: remove + items: + - type: custom:frigate-card-status-bar-string + enabled: true + exclusive: false + expand: false + string: 'Intruder alert!' + priority: 50 + sufficient: false + - type: custom:frigate-card-status-bar-icon + enabled: true + exclusive: false + expand: false + icon: 'mdi:cow' + priority: 50 + sufficient: false + - type: custom:frigate-card-status-bar-image + enabled: true + exclusive: false + expand: false + image: https://my.site.com/status.png + priority: 50 + sufficient: false + - type: custom:frigate-card-menu-icon + icon: mdi:alpha-i-circle-outline + title: Reset status bar contents + tap_action: + - action: custom:frigate-card-action + frigate_card_action: status_bar + status_bar_action: reset ``` diff --git a/docs/configuration/actions/custom/_sidebar.md b/docs/configuration/actions/custom/_sidebar.md index b565bf98..2a59a918 100644 --- a/docs/configuration/actions/custom/_sidebar.md +++ b/docs/configuration/actions/custom/_sidebar.md @@ -7,7 +7,7 @@ - [`cameras`](../../cameras/README.md) - [`conditions`](../../conditions.md) - [`dimensions`](../../dimensions.md) - - [`elements`](../../elements.md) + - [`elements`](../../elements/README.md) - [`image`](../../image.md) - [`live`](../../live.md) - [`media_gallery`](../../media-gallery.md) @@ -16,8 +16,10 @@ - [`overrides`](../../overrides.md) - [`performance`](../../performance.md) - [`profiles`](../../profiles.md) + - [`status_bar`](../../status-bar.md) - [`timeline`](../../timeline.md) - [`view`](../../view.md) +- [Examples](../../../examples.md) - [Screenshots](../../../screenshots.md) - [Troubleshooting](../../../troubleshooting.md) - [Usage](../../../usage/README.md) diff --git a/docs/configuration/actions/stock/_sidebar.md b/docs/configuration/actions/stock/_sidebar.md index f933ffe7..302cfa94 100644 --- a/docs/configuration/actions/stock/_sidebar.md +++ b/docs/configuration/actions/stock/_sidebar.md @@ -7,7 +7,7 @@ - [`cameras`](../../cameras/README.md) - [`conditions`](../../conditions.md) - [`dimensions`](../../dimensions.md) - - [`elements`](../../elements.md) + - [`elements`](../../elements/README.md) - [`image`](../../image.md) - [`live`](../../live.md) - [`media_gallery`](../../media-gallery.md) @@ -16,8 +16,10 @@ - [`overrides`](../../overrides.md) - [`performance`](../../performance.md) - [`profiles`](../../profiles.md) + - [`status_bar`](../../status-bar.md) - [`timeline`](../../timeline.md) - [`view`](../../view.md) +- [Examples](../../../examples.md) - [Screenshots](../../../screenshots.md) - [Troubleshooting](../../../troubleshooting.md) - [Usage](../../../usage/README.md) diff --git a/docs/configuration/cameras/_sidebar.md b/docs/configuration/cameras/_sidebar.md index 050ab8bf..5c901437 100644 --- a/docs/configuration/cameras/_sidebar.md +++ b/docs/configuration/cameras/_sidebar.md @@ -7,7 +7,7 @@ - [`engine`](engine.md) - [`conditions`](../conditions.md) - [`dimensions`](../dimensions.md) - - [`elements`](../elements.md) + - [`elements`](../elements/README.md) - [`image`](../image.md) - [`live`](../live.md) - [`media_gallery`](../media-gallery.md) @@ -16,8 +16,10 @@ - [`overrides`](../overrides.md) - [`performance`](../performance.md) - [`profiles`](../profiles.md) + - [`status_bar`](../status-bar.md) - [`timeline`](../timeline.md) - [`view`](../view.md) +- [Examples](../../examples.md) - [Screenshots](../../screenshots.md) - [Troubleshooting](../../troubleshooting.md) - [Usage](../../usage/README.md) diff --git a/docs/configuration/elements.md b/docs/configuration/elements.md deleted file mode 100644 index a3caf508..00000000 --- a/docs/configuration/elements.md +++ /dev/null @@ -1,356 +0,0 @@ -# `elements` - -This card supports the [Picture Elements configuration -syntax](https://www.home-assistant.io/lovelace/picture-elements/) to seamlessly -allow the user to add custom elements to the card. - -```yaml -elements: - - [element_1] - - [element_2] -``` - -?> The Frigate Card allows either a single [action](actions/README.md) (as in stock Home -Assistant) or list of [actions](actions/README.md) to be defined for each class of user interaction -(e.g. `tap`, `double_tap`, `hold`, etc). See [an example of multiple actions](../examples.md?id=multiple-actions). - -## `conditional` - -This element will let you show its sub-elements based on entity states. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#conditional-element). - -```yaml -elements: - - type: conditional - # [...] -``` - -## `custom` - -Custom elements provided by a card. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#custom-elements). - -```yaml -elements: - - type: custom - # [...] -``` - -## `custom:frigate-card-menu-icon` - -Add an arbitrary icon to the Frigate Card menu. Configuration is ~identical to that of the [Picture Elements Icon](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) except with a type name of `custom:frigate-card-menu-icon`. - -```yaml -elements: - - type: custom:frigate-card-menu-icon - # [...] -``` - -## `custom:frigate-card-menu-state-icon` - -Add a state icon to the Frigate Card menu that represents the state of a Home Assistant entity. Configuration is ~identical to that of the [Picture Elements State Icon](https://www.home-assistant.io/lovelace/picture-elements/#state-icon) except with a type name of `custom:frigate-card-menu-state-icon`. - -```yaml -elements: - - type: custom:frigate-card-menu-icon - # [...] -``` - -## `custom:frigate-card-menu-submenu` - -Add a configurable submenu dropdown. - -```yaml -elements: - - type: custom:frigate-card-menu-submenu - # [...] -``` - -Parameters for this element are identical to the parameters of the [stock Home Assistant Icon Element](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) with the exception of these parameters which differ: - -| Parameter | Description | -| --------- | ------------------------------------------- | -| `type` | Must be `custom:frigate-card-menu-submenu`. | -| `items` | A list of menu items, as described below. | - -### Submenu items - -| Parameter | Default | Description | -| ------------------------------------------------------------------------ | ------- | ------------------------------------------------------------------------------------------------- | -| `enabled` | `true` | Whether or not to show this item as enabled / selectable. | -| `entity` | | An optional Home Assistant entity from which title, icon and style can be automatically computed. | -| `icon` | | An optional item icon to display, e.g. `mdi:car` | -| `selected` | `false` | Whether or not to show this item as selected. | -| `state_color` | `true` | Whether or not the title and icon should be stylized based on state. | -| `style` | | Position and style the element using CSS. | -| `tap_action`, `double_tap_action`, `hold_action`, `start_tap`, `end_tap` | | The [actions](actions/README.md) to take when this item is interacted with. | -| `title` | | An optional title to display. | - -## `custom:frigate-card-menu-submenu-select` - -Add a submenu based on a `select` or `input_select`. This element allows you to convert a [Home Assistant Select Entity](https://www.home-assistant.io/integrations/select/) or [Home Assistant Input Select Entity](https://www.home-assistant.io/integrations/input_select/) (an entity either starting with `select` or `input_select`) into an overridable submenu. This _could_ be done by hand using a regular submenu (above) -- this element is a convenience. - -```yaml -elements: - - type: custom:frigate-card-menu-submenu-select - # [...] -``` - -Parameters for the `custom:frigate-card-menu-submenu-select` element are identical to the parameters of the [stock Home Assistant State Icon Element](https://www.home-assistant.io/dashboards/picture-elements/#state-icon) with the exception of these parameters which differ: - -| Parameter | Description | -| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `type` | Must be `custom:frigate-card-menu-submenu-select`. | -| `options` | An optional dictionary of overrides keyed by the option name that the given select entity supports. These options can be used to set or override submenu item parameters on a per-option basis. The format is as described in [Submenu Items](elements.md?id=submenu-items) above. | - -See the `select` [submenu example](../examples.md?id=select-submenu). - -## `custom:frigate-card-conditional` - -Restrict a set of elements to only render when the card is matches a set of [conditions](conditions.md). This is analogous to [`conditional`](elements.md?id=conditional) element above, except supporting a rich set of Frigate Card [conditions](conditions.md). - -```yaml -elements: - - type: custom:frigate-card-conditional - # [...] -``` - -Parameters for the `custom:frigate-card-conditional` element: - -| Parameter | Description | -| ------------ | ---------------------------------------------------------------------------------------------------------- | -| `type` | Must be `custom:frigate-card-conditional`. | -| `conditions` | A list of [conditions](conditions.md) that must evaluate to true in order for the elements to be rendered. | -| `elements` | The elements to render. Can be any supported element. | - -See the [conditional elements example](../examples.md?id=conditional-elements). - -## `icon` - -This element creates a static icon that is not linked to the state of an entity. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#icon-element). - -```yaml -elements: - - type: icon - # [...] -``` - -## `image` - -This creates an image element that overlays the background image. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#image-element). - -```yaml -elements: - - type: image - # [...] -``` - -## `service-button` - -This entity creates a button (with arbitrary text) that can be used to call a service. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#service-call-button). - -```yaml -elements: - - type: service-button - # [...] -``` - -## `state-badge` - -This element creates a badge representing the state of an entity. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#state-badge). - -```yaml -elements: - - type: state-badge - # [...] -``` - -## `state-icon` - -This element represents an entity state using an icon. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#state-icon). - -```yaml -elements: - - type: state-icon - # [...] -``` - -## `state-label` - -This element represents an entity’s state via text. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#state-label). - -```yaml -elements: - - type: state-label - # [...] -``` - -## Fully expanded reference - -> [Actions](actions/README.md) are omitted for simplicity. - -[](common/expanded-warning.md ':include') - -### Stock Home Assistant elements - -Reference: [Home Assistant Picture Elements](https://www.home-assistant.io/dashboards/picture-elements/) - -```yaml -elements: - - type: state-badge - entity: sensor.kitchen_dining_multisensor_air_temperature - style: - left: 100px - top: 50px - title: 'Temperature' - - type: state-icon - entity: light.office_main_lights - icon: mdi:lamp - state_color: true - style: - left: 100px - top: 100px - - type: state-label - entity: sensor.kitchen_motion_sensor_battery - attribute: battery_voltage - prefix: Volts - title: Battery Voltage - style: - left: 100px - top: 150px - - type: state-label - entity: sensor.kitchen_motion_sensor_battery - attribute: battery_voltage - prefix: 'Volts: ' - title: Battery Voltage - style: - background-color: black - left: 100px - top: 200px - - type: service-button - title: Light on - service: homeassistant.turn_on - service_data: - entity: light.office_main_lights - style: - left: 100px - top: 250px - - type: icon - icon: mdi:cow - title: Moo - style: - left: 100px - top: 300px - - type: image - entity: light.office_main_lights - title: Image - state_image: - on: 'https://picsum.photos/id/1003/1181/1772' - off: 'https://picsum.photos/id/102/4320/3240' - state_filter: - 'on': brightness(110%) saturate(1.2) - 'off': brightness(50%) hue-rotate(45deg) - style: - left: 100px - top: 350px - height: 50px - width: 100px - - type: conditional - conditions: - - condition: state - entity: light.office_main_lights - state: on - state_not: off - - condition: numeric_state - entity: sensor.light_level - above: 20 - below: 100 - - condition: user - users: - - 581fca7fdc014b8b894519cc531f9a04 - elements: - - type: icon - icon: mdi:dog - title: Woof - style: - left: 100px - top: 400px -``` - -### Frigate Card elements - -```yaml -elements: - - type: custom:frigate-card-menu-icon - icon: mdi:car - title: Vroom - - type: custom:frigate-card-menu-state-icon - entity: light.office_main_lights - title: Office lights - icon: mdi:chair-rolling - state_color: true - - type: custom:frigate-card-menu-submenu - icon: mdi:menu - items: - - title: Lights - icon: mdi:lightbulb - entity: light.office_main_lights - tap_action: - action: toggle - - title: Google - icon: mdi:google - enabled: false - tap_action: - action: url - url_path: https://www.google.com - - type: custom:frigate-card-menu-submenu-select - icon: mdi:lamps - entity: input_select.kitchen_scene - options: - scene.kitchen_cooking_scene: - icon: mdi:chef-hat - title: Cooking time! - scene.kitchen_tv_scene: - icon: mdi:television - title: TV! - # Show a pig icon if a variety of conditions are met. - - type: custom:frigate-card-conditional - elements: - - type: icon - icon: mdi:pig - title: Oink - style: - left: 300px - top: 100px - conditions: - - condition: view - views: - - live - - condition: fullscreen - fullscreen: true - - condition: expand - expand: true - - condition: camera - cameras: camera.front_door - - condition: media_loaded - media_loaded: true - - condition: display_mode - display_mode: single - - condition: triggered - triggered: - - camera.front_door - - condition: interaction - interaction: true - - condition: microphone - muted: true - connected: true - - condition: state - entity: light.office_main_lights - state: on - state_not: off - - condition: numeric_state - entity: sensor.light_level - above: 20 - below: 100 - - condition: user - users: - - 581fca7fdc014b8b894519cc531f9a04 -``` diff --git a/docs/configuration/elements/README.md b/docs/configuration/elements/README.md new file mode 100644 index 00000000..5591fb39 --- /dev/null +++ b/docs/configuration/elements/README.md @@ -0,0 +1,24 @@ +# `elements` + +## Introduction to elements + +This card supports the [Picture Elements configuration +syntax](https://www.home-assistant.io/lovelace/picture-elements/) to seamlessly +allow the user to add custom elements to the card. + +```yaml +elements: + - [element_1] + - [element_2] +``` + +?> The Frigate Card allows either a single [action](../actions/README.md) (as in stock Home +Assistant) or list of [actions](../actions/README.md) to be defined for each class of user interaction +(e.g. `tap`, `double_tap`, `hold`, etc). See [an example of multiple actions](../../examples.md?id=multiple-actions). + +## Elements + +| Option | Description | +| ------------------------------------- | --------------------------------- | +| [Custom Elements](./custom/README.md) | Custom elements. | +| [Stock Elements](./stock/README.md) | Standard Home Assistant elements. | diff --git a/docs/configuration/elements/_sidebar.md b/docs/configuration/elements/_sidebar.md new file mode 100644 index 00000000..f570d19b --- /dev/null +++ b/docs/configuration/elements/_sidebar.md @@ -0,0 +1,29 @@ +- [Getting Started](../../README.md) +- [Configuration](../README.md) + - [`actions`](../actions/README.md) + - [`automations`](../automations.md) + - [`cameras`](../cameras/README.md) + - [`conditions`](../conditions.md) + - [`dimensions`](../dimensions.md) + - [`elements`](README.md) + - [Custom Elements](./custom/README.md) + - [Stock Elements](./stock/README.md) + - [`image`](../image.md) + - [`live`](../live.md) + - [`media_gallery`](../media-gallery.md) + - [`media_viewer`](../media-viewer.md) + - [`menu`](../menu.md) + - [`overrides`](../overrides.md) + - [`performance`](../performance.md) + - [`profiles`](../profiles.md) + - [`status_bar`](../status-bar.md) + - [`timeline`](../timeline.md) + - [`view`](../view.md) +- [Examples](../../examples.md) +- [Screenshots](../../screenshots.md) +- [Troubleshooting](../../troubleshooting.md) +- [Usage](../../usage/README.md) + +--- + +- [Developing](../../developing.md) diff --git a/docs/configuration/elements/custom/README.md b/docs/configuration/elements/custom/README.md new file mode 100644 index 00000000..a8200888 --- /dev/null +++ b/docs/configuration/elements/custom/README.md @@ -0,0 +1,258 @@ +# Custom Elements + +## `conditional` + +Restrict a set of elements to only render when the card is matches a set of [conditions](../../conditions.md). This is analogous to the stock [`conditional`](../stock/README.md?id=conditional) element except supporting a rich set of Frigate Card [conditions](../../conditions.md). + +```yaml +elements: + - type: custom:frigate-card-conditional + # [...] +``` + +Parameters for the `custom:frigate-card-conditional` element: + +| Parameter | Description | +| ------------ | ---------------------------------------------------------------------------------------------------------------- | +| `type` | Must be `custom:frigate-card-conditional`. | +| `conditions` | A list of [conditions](../../conditions.md) that must evaluate to true in order for the elements to be rendered. | +| `elements` | The elements to render. Can be any supported element. | + +See the [conditional elements example](../../../examples.md?id=conditional-elements). + +## `menu-icon` + +Add an arbitrary icon to the Frigate Card menu. Configuration is ~identical to that of the [Picture Elements Icon](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) except with a type name of `custom:frigate-card-menu-icon`. + +```yaml +elements: + - type: custom:frigate-card-menu-icon + # [...] +``` + +## `menu-submenu` + +Add a configurable submenu dropdown. + +```yaml +elements: + - type: custom:frigate-card-menu-submenu + # [...] +``` + +Parameters for this element are identical to the parameters of the [stock Home Assistant Icon Element](https://www.home-assistant.io/lovelace/picture-elements/#icon-element) with the exception of these parameters which differ: + +| Parameter | Description | +| --------- | ------------------------------------------- | +| `type` | Must be `custom:frigate-card-menu-submenu`. | +| `items` | A list of menu items, as described below. | + +### Submenu items + +| Parameter | Default | Description | +| ------------------------------------------------------------------------ | ------- | ------------------------------------------------------------------------------------------------- | +| `enabled` | `true` | Whether or not to show this item as enabled / selectable. | +| `entity` | | An optional Home Assistant entity from which title, icon and style can be automatically computed. | +| `icon` | | An optional item icon to display, e.g. `mdi:car` | +| `selected` | `false` | Whether or not to show this item as selected. | +| `state_color` | `true` | Whether or not the title and icon should be stylized based on state. | +| `style` | | Position and style the element using CSS. | +| `tap_action`, `double_tap_action`, `hold_action`, `start_tap`, `end_tap` | | The [actions](../../actions/README.md) to take when this item is interacted with. | +| `title` | | An optional title to display. | + +## `menu-submenu-select` + +Add a submenu based on a `select` or `input_select`. This element allows you to convert a [Home Assistant Select Entity](https://www.home-assistant.io/integrations/select/) or [Home Assistant Input Select Entity](https://www.home-assistant.io/integrations/input_select/) (an entity either starting with `select` or `input_select`) into an overridable submenu. This _could_ be done by hand using a regular submenu (above) -- this element is a convenience. + +```yaml +elements: + - type: custom:frigate-card-menu-submenu-select + # [...] +``` + +Parameters for the `custom:frigate-card-menu-submenu-select` element are identical to the parameters of the [stock Home Assistant State Icon Element](https://www.home-assistant.io/dashboards/picture-elements/#state-icon) with the exception of these parameters which differ: + +| Parameter | Description | +| --------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `type` | Must be `custom:frigate-card-menu-submenu-select`. | +| `options` | An optional dictionary of overrides keyed by the option name that the given select entity supports. These options can be used to set or override submenu item parameters on a per-option basis. The format is as described in [Submenu Items](./README.md?id=submenu-items) above. | + +See the `select` [submenu example](../../../examples.md?id=select-submenu). + +## `state-icon` + +Add a state icon to the Frigate Card menu that represents the state of a Home Assistant entity. Configuration is ~identical to that of the [Picture Elements State Icon](https://www.home-assistant.io/lovelace/picture-elements/#state-icon) except with a type name of `custom:frigate-card-menu-state-icon`. + +```yaml +elements: + - type: custom:frigate-card-menu-icon + # [...] +``` + +## `status-bar-icon` + +Add an arbitrary icon to the status bar. + +```yaml +elements: + - type: custom:frigate-card-status-bar-icon + # [...] +``` + +| Parameter | Default | Description | +| ------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `type` | | Must be `custom:frigate-card-status-bar-icon`. | +| `actions` | | Actions to performs when the status bar item is interacted with. See [actions](../../actions/README.md). | +| `enabled` | `true` | `true` to enable this status bar item, `false` to disable. | +| `exclusive` | `false` | Whether or not this item should evict non-exclusive items from the status bar. | +| `expand` | `false` | If `false` this status bar item will consume the minimum possible space, if `true` will expand to the available space. | +| `icon` | | The icon to show in the status bar, e.g. `mdi:camera-front`. | +| `priority` | `50` | The item priority. Higher priority items are ordered closer to the start of the status bar (i.e. an item with priority `70` will order further to the left than an item with priority `60`). Minimum `0`, maximum `100`. | +| `sufficient` | `false` | Whether or not this item is sufficient to display the status bar if it's otherwise hidden (e.g. with the `popup` [status bar style](../../status-bar.md)). | + +## `status-bar-image` + +Add an arbitrary image to the status bar. + +```yaml +elements: + - type: custom:frigate-card-status-bar-image + # [...] +``` + +| Parameter | Default | Description | +| ------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `type` | | Must be `custom:frigate-card-status-bar-image`. | +| `actions` | | Actions to performs when the status bar item is interacted with. See [actions](../../actions/README.md). | +| `enabled` | `true` | `true` to enable this status bar item, `false` to disable. | +| `exclusive` | `false` | Whether or not this item should evict non-exclusive items from the status bar. | +| `expand` | `false` | If `false` this status bar item will consume the minimum possible space, if `true` will expand to the available space. | +| `image` | | The image to show in the status bar, e.g. `https://my.site.com/status.png`. | +| `priority` | `50` | The item priority. Higher priority items are ordered closer to the start of the status bar (i.e. an item with priority `70` will order further to the left than an item with priority `60`). Minimum `0`, maximum `100`. | +| `sufficient` | `false` | Whether or not this item is sufficient to display the status bar if it's otherwise hidden (e.g. with the `popup` [status bar style](../../status-bar.md)). | + +## `status-bar-string` + +Add an arbitrary string to the status bar. + +```yaml +elements: + - type: custom:frigate-card-status-bar-string + # [...] +``` + +| Parameter | Default | Description | +| ------------ | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `type` | | Must be `custom:frigate-card-status-bar-string`. | +| `actions` | | Actions to performs when the status bar item is interacted with. See [actions](../../actions/README.md). | +| `enabled` | `true` | `true` to enable this status bar item, `false` to disable. | +| `exclusive` | `false` | Whether or not this item should evict non-exclusive items from the status bar. | +| `expand` | `false` | If `false` this status bar item will consume the minimum possible space, if `true` will expand to the available space. | +| `string` | | The string to show in the status bar, e.g. `Intruder detected!` | +| `priority` | `50` | The item priority. Higher priority items are ordered closer to the start of the status bar (i.e. an item with priority `70` will order further to the left than an item with priority `60`). Minimum `0`, maximum `100`. | +| `sufficient` | `false` | Whether or not this item is sufficient to display the status bar if it's otherwise hidden (e.g. with the `popup` [status bar style](../../status-bar.md)). | + +## Fully expanded reference + +> [Actions](../../actions/README.md) are omitted for simplicity. + +[](../../common/expanded-warning.md ':include') + +```yaml +elements: + - type: custom:frigate-card-menu-icon + icon: mdi:car + title: Vroom + - type: custom:frigate-card-menu-state-icon + entity: light.office_main_lights + title: Office lights + icon: mdi:chair-rolling + state_color: true + - type: custom:frigate-card-menu-submenu + icon: mdi:menu + items: + - title: Lights + icon: mdi:lightbulb + entity: light.office_main_lights + tap_action: + action: toggle + - title: Google + icon: mdi:google + enabled: false + tap_action: + action: url + url_path: https://www.google.com + - type: custom:frigate-card-menu-submenu-select + icon: mdi:lamps + entity: input_select.kitchen_scene + options: + scene.kitchen_cooking_scene: + icon: mdi:chef-hat + title: Cooking time! + scene.kitchen_tv_scene: + icon: mdi:television + title: TV! + # Show a pig icon if a variety of conditions are met. + - type: custom:frigate-card-conditional + elements: + - type: icon + icon: mdi:pig + title: Oink + style: + left: 300px + top: 100px + conditions: + - condition: view + views: + - live + - condition: fullscreen + fullscreen: true + - condition: expand + expand: true + - condition: camera + cameras: camera.front_door + - condition: media_loaded + media_loaded: true + - condition: display_mode + display_mode: single + - condition: triggered + triggered: + - camera.front_door + - condition: interaction + interaction: true + - condition: microphone + muted: true + connected: true + - condition: state + entity: light.office_main_lights + state: on + state_not: off + - condition: numeric_state + entity: sensor.light_level + above: 20 + below: 100 + - condition: user + users: + - 581fca7fdc014b8b894519cc531f9a04 + - type: custom:frigate-card-status-bar-string + enabled: true + exclusive: false + expand: false + string: 'Intruder alert!' + priority: 50 + sufficient: false + - type: custom:frigate-card-status-bar-icon + enabled: true + exclusive: false + expand: false + icon: 'mdi:cow' + priority: 50 + sufficient: false + - type: custom:frigate-card-status-bar-image + enabled: true + exclusive: false + expand: false + image: https://my.site.com/status.png + priority: 50 + sufficient: false +``` diff --git a/docs/configuration/elements/custom/_sidebar.md b/docs/configuration/elements/custom/_sidebar.md new file mode 100644 index 00000000..0ea893ea --- /dev/null +++ b/docs/configuration/elements/custom/_sidebar.md @@ -0,0 +1,29 @@ +- [Getting Started](../../../README.md) +- [Configuration](../../README.md) + - [`actions`](../README.md) + - [`automations`](../../automations.md) + - [`cameras`](../../cameras/README.md) + - [`conditions`](../../conditions.md) + - [`dimensions`](../../dimensions.md) + - [`elements`](../../elements/README.md) + - [Custom Actions](README.md) + - [Stock Actions](../stock/README.md) + - [`image`](../../image.md) + - [`live`](../../live.md) + - [`media_gallery`](../../media-gallery.md) + - [`media_viewer`](../../media-viewer.md) + - [`menu`](../../menu.md) + - [`overrides`](../../overrides.md) + - [`performance`](../../performance.md) + - [`profiles`](../../profiles.md) + - [`status_bar`](../../status-bar.md) + - [`timeline`](../../timeline.md) + - [`view`](../../view.md) +- [Examples](../../../examples.md) +- [Screenshots](../../../screenshots.md) +- [Troubleshooting](../../../troubleshooting.md) +- [Usage](../../../usage/README.md) + +--- + +- [Developing](../../../developing.md) diff --git a/docs/configuration/elements/stock/README.md b/docs/configuration/elements/stock/README.md new file mode 100644 index 00000000..620ce56c --- /dev/null +++ b/docs/configuration/elements/stock/README.md @@ -0,0 +1,173 @@ +# Stock Elements + +## `conditional` + +This element will let you show its sub-elements based on entity states. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#conditional-element). + +```yaml +elements: + - type: conditional + # [...] +``` + +## `custom` + +Custom elements provided by a card. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#custom-elements). + +```yaml +elements: + - type: custom + # [...] +``` + +?> See [Frigate Card custom elements](../custom//README.md) for the custom elements offered by _this_ card. + +## `icon` + +This element creates a static icon that is not linked to the state of an entity. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#icon-element). + +```yaml +elements: + - type: icon + # [...] +``` + +## `image` + +This creates an image element that overlays the background image. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#image-element). + +```yaml +elements: + - type: image + # [...] +``` + +## `service-button` + +This entity creates a button (with arbitrary text) that can be used to call a service. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#service-call-button). + +```yaml +elements: + - type: service-button + # [...] +``` + +## `state-badge` + +This element creates a badge representing the state of an entity. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#state-badge). + +```yaml +elements: + - type: state-badge + # [...] +``` + +## `state-icon` + +This element represents an entity state using an icon. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#state-icon). + +```yaml +elements: + - type: state-icon + # [...] +``` + +## `state-label` + +This element represents an entity’s state via text. See [Home Assistant elements documentation](https://www.home-assistant.io/dashboards/picture-elements/#state-label). + +```yaml +elements: + - type: state-label + # [...] +``` + +## Fully expanded reference + +> [Actions](../../actions/README.md) are omitted for simplicity. + +[](../../common/expanded-warning.md ':include') + +Reference: [Home Assistant Picture Elements](https://www.home-assistant.io/dashboards/picture-elements/) + +```yaml +elements: + - type: state-badge + entity: sensor.kitchen_dining_multisensor_air_temperature + style: + left: 100px + top: 50px + title: 'Temperature' + - type: state-icon + entity: light.office_main_lights + icon: mdi:lamp + state_color: true + style: + left: 100px + top: 100px + - type: state-label + entity: sensor.kitchen_motion_sensor_battery + attribute: battery_voltage + prefix: Volts + title: Battery Voltage + style: + left: 100px + top: 150px + - type: state-label + entity: sensor.kitchen_motion_sensor_battery + attribute: battery_voltage + prefix: 'Volts: ' + title: Battery Voltage + style: + background-color: black + left: 100px + top: 200px + - type: service-button + title: Light on + service: homeassistant.turn_on + service_data: + entity: light.office_main_lights + style: + left: 100px + top: 250px + - type: icon + icon: mdi:cow + title: Moo + style: + left: 100px + top: 300px + - type: image + entity: light.office_main_lights + title: Image + state_image: + on: 'https://picsum.photos/id/1003/1181/1772' + off: 'https://picsum.photos/id/102/4320/3240' + state_filter: + 'on': brightness(110%) saturate(1.2) + 'off': brightness(50%) hue-rotate(45deg) + style: + left: 100px + top: 350px + height: 50px + width: 100px + - type: conditional + conditions: + - condition: state + entity: light.office_main_lights + state: on + state_not: off + - condition: numeric_state + entity: sensor.light_level + above: 20 + below: 100 + - condition: user + users: + - 581fca7fdc014b8b894519cc531f9a04 + elements: + - type: icon + icon: mdi:dog + title: Woof + style: + left: 100px + top: 400px +``` diff --git a/docs/configuration/elements/stock/_sidebar.md b/docs/configuration/elements/stock/_sidebar.md new file mode 100644 index 00000000..9edbaf3a --- /dev/null +++ b/docs/configuration/elements/stock/_sidebar.md @@ -0,0 +1,29 @@ +- [Getting Started](../../../README.md) +- [Configuration](../../README.md) + - [`actions`](../README.md) + - [`automations`](../../automations.md) + - [`cameras`](../../cameras/README.md) + - [`conditions`](../../conditions.md) + - [`dimensions`](../../dimensions.md) + - [`elements`](../../elements/README.md) + - [Custom Actions](../custom/README.md) + - [Stock Actions](README.md) + - [`image`](../../image.md) + - [`live`](../../live.md) + - [`media_gallery`](../../media-gallery.md) + - [`media_viewer`](../../media-viewer.md) + - [`menu`](../../menu.md) + - [`overrides`](../../overrides.md) + - [`performance`](../../performance.md) + - [`profiles`](../../profiles.md) + - [`status_bar`](../../status-bar.md) + - [`timeline`](../../timeline.md) + - [`view`](../../view.md) +- [Examples](../../../examples.md) +- [Screenshots](../../../screenshots.md) +- [Troubleshooting](../../../troubleshooting.md) +- [Usage](../../../usage/README.md) + +--- + +- [Developing](../../../developing.md) diff --git a/docs/configuration/live.md b/docs/configuration/live.md index b22e29c2..58d30f97 100644 --- a/docs/configuration/live.md +++ b/docs/configuration/live.md @@ -41,7 +41,6 @@ live: | `next_previous` | | Configures how the "Next & Previous" controls are shown on the `live` view. See below. | | `thumbnails` | | Configures how thumbnails are shown on the `live` view. See below. | | `timeline` | | Configures how the mini-timeline is shown on the `live` view. See below. | -| `title` | | Configures how the camera title is shown on the `live` view. See below. | ### `next_previous` @@ -127,22 +126,6 @@ live: [](common/timeline-seek-info.md ':include') -### `title` - -Configures how the camera title is shown on the live view. - -```yaml -live: - controls: - title: - # [...] -``` - -| Option | Default | Description | -| ------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | -| `duration_seconds` | `2` | The number of seconds to display the title popup. `0` implies forever. | -| `mode` | `popup-bottom-right` | How to display the live camera title. Acceptable values: `none`, `popup-top-left`, `popup-top-right`, `popup-bottom-left`, `popup-bottom-right` . | - ## `display` Controls whether to show a single or grid `live` view. @@ -230,9 +213,6 @@ live: events_media_type: all show_recordings: true window_seconds: 3600 - title: - mode: popup-bottom-right - duration_seconds: 2 microphone: always_connected: false disconnect_seconds: 90 diff --git a/docs/configuration/media-viewer.md b/docs/configuration/media-viewer.md index 049df860..31918b89 100644 --- a/docs/configuration/media-viewer.md +++ b/docs/configuration/media-viewer.md @@ -37,7 +37,6 @@ media_viewer: | `next_previous` | | Configures how the "Next & Previous" controls are shown on the media viewer. See below. | | `thumbnails` | | Configures how thumbnails are shown on the media viewer. See below. | | `timeline` | | Configures how the mini-timeline is shown on the media viewer. See below. | -| `title` | | Configures how the media title is shown on the media viewer. See below. | ### `next_previous` @@ -121,22 +120,6 @@ media_viewer: [](common/timeline-seek-info.md ':include') -### `title` - -Configures how the media title is shown on the media viewer. - -```yaml -media_viewer: - controls: - title: - # [...] -``` - -| Option | Default | Description | -| ------------------ | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `duration_seconds` | `2` | The number of seconds to display the title popup. `0` implies forever. | -| `mode` | `popup-bottom-right` | How to display the Media viewer media title. Acceptable values: `none`, `popup-top-left`, `popup-top-right`, `popup-bottom-left`, `popup-bottom-right` . | - ## `display` Controls whether to show a single media item or grid in the media viewer. @@ -205,9 +188,6 @@ media_viewer: events_media_type: all show_recordings: true window_seconds: 3600 - title: - mode: popup-bottom-right - duration_seconds: 2 display: mode: single grid_selected_width_factor: 2 diff --git a/docs/configuration/status-bar.md b/docs/configuration/status-bar.md new file mode 100644 index 00000000..6d7a0de0 --- /dev/null +++ b/docs/configuration/status-bar.md @@ -0,0 +1,82 @@ +# `status_bar` + +Configures the card status bar. + +```yaml +status_bar: + # [...] +``` + +| Option | Default | Description | +| --------------- | -------- | -------------------------------------------------------------------------------------------------------------------------- | +| `position` | `bottom` | Whether to place the status bar at the `top` or `bottom` of the card. | +| `popup_seconds` | `3` | The number of seconds to display the status bar when using the `popup` style. | +| `height` | `46` | The height of the status bar in pixels. | +| `items` | | Whether to show or hide built-in status bar items. See below. | +| `style` | `popup` | The status bar style to show by default, one of `none`, `hover`, `hover-card`, `overlay`, `outside` or `popup`. See below. | + +## `items` + +All configuration is under: + +```yaml +status_bar: + items: + [item]: + # [...] +``` + +### Available Items + +| Button name | Description | +| ------------ | ------------------------------------------------------ | +| `engine` | The icon of the camera engine for the relevant camera. | +| `resolution` | The detected media resolution (if any). | +| `technology` | The detected media technology (if any). | +| `title` | The media title. | + +### Options for each item + +| Option | Default | Description | +| ---------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `enabled` | `true` | Whether or not to show the item. | +| `priority` | `50` | The item priority. Higher priority items are ordered closer to the start of the status bar (i.e. an item with priority `70` will order further to the left than an item with priority `60`). Minimum `0`, maximum `100`. | + +## `style` + +This card supports several menu styles. + +| Key | Description | +| ------------ | --------------------------------------------------------------------------------------------------------------------- | +| `hover-card` | Overlay the status bar over the card contents when the mouse is over the **card**, otherwise it is not shown. | +| `hover` | Overlay the status bar over the card contents when the mouse is over the **status bar**, otherwise it is not shown. | +| `none` | No status bar is shown. | +| `outside` | Render the status bar outside the card (i.e. above it if `position` is `top`, or below it if `position` is `bottom`). | +| `overlay` | Overlay the status bar over the card contents. | + +## Fully expanded reference + +?> To add custom status bar contents, see [status bar custom elements](elements/custom/README.md?id=status-bar-icon). + +[](common/expanded-warning.md ':include') + +```yaml +status_bar: + position: bottom + popup_seconds: 3 + height: 46 + style: popup + items: + engine: + enabled: true + priority: 50 + resolution: + enabled: true + priority: 50 + technology: + enabled: true + priority: 50 + title: + enabled: true + priority: 50 +``` diff --git a/docs/examples.md b/docs/examples.md index 0bb99c27..654669d3 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -695,6 +695,52 @@ image: refresh_seconds: 10 ``` +## Status bar + +### Disable status bar + +This example disables the status bar. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +status_bar: + style: none +``` + +### Dynamic status bar contents + +This example shows an icon and a message on the status bar when a camera is triggered, replacing the existing contents of the status bar through the use of `exclusive`. + +```yaml +type: custom:frigate-card +cameras: + - camera_entity: camera.office +automations: + - conditions: + - condition: triggered + triggered: + - camera.office + actions: + - action: custom:frigate-card-action + frigate_card_action: status_bar + status_bar_action: add + items: + - type: custom:frigate-card-status-bar-icon + icon: mdi:alarm-light + exclusive: true + - type: custom:frigate-card-status-bar-string + string: Intruder detected! + expand: true + exclusive: true + sufficient: true + actions_not: + - action: custom:frigate-card-action + frigate_card_action: status_bar + status_bar_action: reset +``` + ## Submenus You can add submenus to the menu -- buttons that when pressed reveal a dropdown submenu of configurable options. diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md index e76eee91..a9e8e133 100644 --- a/docs/troubleshooting.md +++ b/docs/troubleshooting.md @@ -78,8 +78,8 @@ The Android video player swallows `double_tap` interactions in order to rewind or fast-forward. Workarounds: - Use `hold` instead of `double_tap` for your card-wide action. -- Use a [Frigate Card Element](configuration/elements.md) or menu icon to trigger - the action instead. +- Use a [Frigate Card Element](configuration/elements/README.md) or menu icon to + trigger the action instead. ### Dragging in carousels broken in Firefox @@ -180,20 +180,13 @@ image to specifically allow `crossorigin` requests (which is typically not the case for an image served from a camera, for example). The stock Home Assistant Picture Glance card has the same limitation, for the same reasons. -### Title "Popups" continually popping up +### Status "popup" continually popping up -Title popups can be disabled for live or media viewer views with this -configuration: +Status popup can be disabled with this configuration: ```yaml -live: - controls: - title: - mode: none -media_viewer: - controls: - title: - mode: none +status_bar: + style: none ``` ### Watermark shown on livestream diff --git a/src/card-controller/actions/actions/status-bar.ts b/src/card-controller/actions/actions/status-bar.ts new file mode 100644 index 00000000..a30e5ad0 --- /dev/null +++ b/src/card-controller/actions/actions/status-bar.ts @@ -0,0 +1,24 @@ +import { StatusBarActionConfig } from '../../../config/types'; +import { CardActionsAPI } from '../../types'; +import { FrigateCardAction } from './base'; + +export class StatusBarAction extends FrigateCardAction { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + public async execute(api: CardActionsAPI): Promise { + switch (this._action.status_bar_action) { + case 'reset': + api.getStatusBarItemManager().removeAllDynamicStatusBarItems(); + break; + case 'add': + this._action.items?.forEach((item) => + api.getStatusBarItemManager().addDynamicStatusBarItem(item), + ); + break; + case 'remove': + this._action.items?.forEach((item) => + api.getStatusBarItemManager().removeDynamicStatusBarItem(item), + ); + break; + } + } +} diff --git a/src/card-controller/actions/factory.ts b/src/card-controller/actions/factory.ts index 0548ab0c..21d36c77 100644 --- a/src/card-controller/actions/factory.ts +++ b/src/card-controller/actions/factory.ts @@ -19,11 +19,12 @@ import { MuteAction } from './actions/mute'; import { PauseAction } from './actions/pause'; import { PlayAction } from './actions/play'; import { PTZAction } from './actions/ptz'; +import { PTZControlsAction } from './actions/ptz-controls'; import { PTZDigitalAction } from './actions/ptz-digital'; import { PTZMultiAction } from './actions/ptz-multi'; import { ScreenshotAction } from './actions/screenshot'; -import { PTZControlsAction } from './actions/ptz-controls'; import { SleepAction } from './actions/sleep'; +import { StatusBarAction } from './actions/status-bar'; import { SubstreamOffAction } from './actions/substream-off'; import { SubstreamOnAction } from './actions/substream-on'; import { SubstreamSelectAction } from './actions/substream-select'; @@ -121,6 +122,8 @@ export class ActionFactory { return new PTZControlsAction(context, frigateCardAction, options?.config); case 'log': return new LogAction(context, frigateCardAction, options?.config); + case 'status_bar': + return new StatusBarAction(context, frigateCardAction, options?.config); } /* istanbul ignore next: this path cannot be reached -- @preserve */ diff --git a/src/card-controller/config/config-manager.ts b/src/card-controller/config/config-manager.ts index 7271ac99..28be50a8 100644 --- a/src/card-controller/config/config-manager.ts +++ b/src/card-controller/config/config-manager.ts @@ -96,6 +96,8 @@ export class ConfigManager { this._api.getMessageManager().reset(); this._api.getStyleManager().setPerformance(); this._api.getCardElementManager().update(); + this._api.getStatusBarItemManager().removeAllDynamicStatusBarItems(); + setKeyboardShortcutsFromConfig(this._api, this); setAutomationsFromConfig(this._api); diff --git a/src/card-controller/controller.ts b/src/card-controller/controller.ts index 758f1f31..cc10b9d1 100644 --- a/src/card-controller/controller.ts +++ b/src/card-controller/controller.ts @@ -28,6 +28,7 @@ import { MediaPlayerManager } from './media-player-manager'; import { MessageManager } from './message-manager'; import { MicrophoneManager } from './microphone-manager'; import { QueryStringManager } from './query-string-manager'; +import { StatusBarItemManager } from './status-bar-item-manager'; import { StyleManager } from './style-manager'; import { TriggersManager } from './triggers-manager'; import { @@ -110,6 +111,7 @@ export class CardController protected _messageManager = new MessageManager(this); protected _microphoneManager = new MicrophoneManager(this); protected _queryStringManager = new QueryStringManager(this); + protected _statusBarItemManager = new StatusBarItemManager(this); protected _styleManager = new StyleManager(this); protected _triggersManager = new TriggersManager(this); protected _viewManager = new ViewManager(this); @@ -228,6 +230,10 @@ export class CardController return this._resolvedMediaCache; } + public getStatusBarItemManager(): StatusBarItemManager { + return this._statusBarItemManager; + } + public static getStubConfig(entities: string[]): FrigateCardConfig { const cameraEntity = entities.find((element) => element.startsWith('camera.')); return { diff --git a/src/card-controller/status-bar-item-manager.ts b/src/card-controller/status-bar-item-manager.ts new file mode 100644 index 00000000..f37bd791 --- /dev/null +++ b/src/card-controller/status-bar-item-manager.ts @@ -0,0 +1,160 @@ +import { isEqual } from 'lodash-es'; +import { CameraManager } from '../camera-manager/manager'; +import { StatusBarConfig, StatusBarItem } from '../config/types'; +import { MediaLoadedInfo } from '../types'; +import { View } from '../view/view'; +import { CardStatusBarAPI } from './types'; + +const RESOLUTION_TOLERANCE_PCT = 0.01; + +export class StatusBarItemManager { + protected _api: CardStatusBarAPI; + + constructor(api: CardStatusBarAPI) { + this._api = api; + } + + protected _items: StatusBarItem[] = []; + protected _dynamicItems: StatusBarItem[] = []; + + public addDynamicStatusBarItem(item: StatusBarItem): void { + if (!this._dynamicItems.includes(item)) { + this._dynamicItems.push(item); + } + this._api.getCardElementManager().update(); + } + + public removeDynamicStatusBarItem(item: StatusBarItem): void { + this._dynamicItems = this._dynamicItems.filter( + (existingItem) => !isEqual(existingItem, item), + ); + this._api.getCardElementManager().update(); + } + + public removeAllDynamicStatusBarItems(): void { + this._dynamicItems = []; + this._api.getCardElementManager().update(); + } + + public calculateItems(options?: { + statusConfig?: StatusBarConfig | null; + cameraManager?: CameraManager | null; + view?: View | null; + mediaLoadedInfo?: MediaLoadedInfo | null; + }): StatusBarItem[] { + const cameraMetadata = options?.view + ? options?.cameraManager?.getCameraMetadata(options?.view?.camera) + : null; + const engineLogoIcon = cameraMetadata?.engineLogo ?? null; + const title = options?.view?.is('live') + ? cameraMetadata?.title ?? null + : options?.view?.isAnyMediaView() + ? options?.view.queryResults?.getSelectedResult()?.getTitle() ?? null + : null; + const resolution = options?.mediaLoadedInfo + ? this._calculateResolution(options?.mediaLoadedInfo) + : null; + const technology = options?.mediaLoadedInfo?.technology?.length + ? options?.mediaLoadedInfo.technology[0] + : null; + + return [ + ...(title + ? [ + { + type: 'custom:frigate-card-status-bar-string' as const, + string: title, + expand: true, + sufficient: true, + ...options?.statusConfig?.items.title, + }, + ] + : []), + + ...(resolution + ? [ + { + type: 'custom:frigate-card-status-bar-string' as const, + string: resolution, + ...options?.statusConfig?.items.resolution, + }, + ] + : []), + + ...(technology && technology === 'webrtc' + ? [ + { + type: 'custom:frigate-card-status-bar-icon' as const, + icon: 'mdi:webrtc', + ...options?.statusConfig?.items.technology, + }, + ] + : !!technology + ? [ + { + type: 'custom:frigate-card-status-bar-string' as const, + string: technology.toUpperCase(), + ...options?.statusConfig?.items.technology, + }, + ] + : []), + + ...(engineLogoIcon + ? [ + { + type: 'custom:frigate-card-status-bar-image' as const, + image: engineLogoIcon, + ...options?.statusConfig?.items.engine, + }, + ] + : []), + ...this._dynamicItems, + ]; + } + + protected _matchesWidthHeight( + mediaLoadedInfo: MediaLoadedInfo | null, + width: number, + height: number, + ): boolean { + const widthMin = width * (1 - RESOLUTION_TOLERANCE_PCT); + const widthMax = width * (1 + RESOLUTION_TOLERANCE_PCT); + const heightMin = height * (1 - RESOLUTION_TOLERANCE_PCT); + const heightMax = height * (1 + RESOLUTION_TOLERANCE_PCT); + + const matchesDimension = (val: number, min: number, max: number): boolean => { + return val >= min && val <= max; + }; + + // Allows matching the resolution width and height in either orientation, + // and within RESOLUTION_TOLERANCE_PCT of the resolution. + return ( + !!mediaLoadedInfo && + ((matchesDimension(mediaLoadedInfo.width, widthMin, widthMax) && + matchesDimension(mediaLoadedInfo.height, heightMin, heightMax)) || + (matchesDimension(mediaLoadedInfo.height, widthMin, widthMax) && + matchesDimension(mediaLoadedInfo.width, heightMin, heightMax))) + ); + } + + protected _calculateResolution(mediaLoadedInfo: MediaLoadedInfo): string { + // Ordered roughly by a guess at most common towards the top. + if (this._matchesWidthHeight(mediaLoadedInfo, 1920, 1080)) { + return '1080p'; + } else if (this._matchesWidthHeight(mediaLoadedInfo, 1280, 720)) { + return '720p'; + } else if (this._matchesWidthHeight(mediaLoadedInfo, 640, 480)) { + return 'VGA'; + } else if (this._matchesWidthHeight(mediaLoadedInfo, 3840, 2160)) { + return '4K'; + } else if (this._matchesWidthHeight(mediaLoadedInfo, 720, 480)) { + return '480p'; + } else if (this._matchesWidthHeight(mediaLoadedInfo, 720, 576)) { + return '576p'; + } else if (this._matchesWidthHeight(mediaLoadedInfo, 7680, 4320)) { + return '8K'; + } else { + return `${mediaLoadedInfo.width}x${mediaLoadedInfo.height}`; + } + } +} diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index cca66b7a..0806cb66 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -1,29 +1,30 @@ import type { CameraManager } from '../camera-manager/manager'; -import type { ConditionsManager } from './conditions-manager'; +import type { Automation } from '../config/types'; import type { EntityRegistryManager } from '../utils/ha/entity-registry'; import type { ResolvedMediaCache } from '../utils/ha/resolved-media'; import type { ActionsManager } from './actions/actions-manager'; -import type { DefaultManager } from './default-manager'; import type { AutomationsManager } from './automations-manager'; import type { CameraURLManager } from './camera-url-manager'; import type { CardElementManager } from './card-element-manager'; +import type { ConditionsManager } from './conditions-manager'; import type { ConfigManager } from './config/config-manager'; +import type { DefaultManager } from './default-manager'; import type { DownloadManager } from './download-manager'; import type { ExpandManager } from './expand-manager'; import type { FullscreenManager } from './fullscreen-manager'; import type { HASSManager } from './hass-manager'; import type { InitializationManager } from './initialization-manager'; import type { InteractionManager } from './interaction-manager'; +import type { KeyboardStateManager } from './keyboard-state-manager'; import type { MediaLoadedInfoManager } from './media-info-manager'; import type { MediaPlayerManager } from './media-player-manager'; import type { MessageManager } from './message-manager'; import type { MicrophoneManager } from './microphone-manager'; +import type { QueryStringManager } from './query-string-manager'; +import type { StatusBarItemManager } from './status-bar-item-manager'; import type { StyleManager } from './style-manager'; import type { TriggersManager } from './triggers-manager'; import type { ViewManager } from './view/view-manager'; -import type { QueryStringManager } from './query-string-manager'; -import { KeyboardStateManager } from './keyboard-state-manager'; -import { Automation } from '../config/types'; // ************************************************************************* // Manager APIs @@ -47,6 +48,7 @@ export interface CardActionsAPI { getMediaPlayerManager(): MediaPlayerManager; getMessageManager(): MessageManager; getMicrophoneManager(): MicrophoneManager; + getStatusBarItemManager(): StatusBarItemManager; getTriggersManager(): TriggersManager; getViewManager(): ViewManager; } @@ -89,6 +91,7 @@ export interface CardConfigAPI { getInitializationManager(): InitializationManager; getMediaLoadedInfoManager(): MediaLoadedInfoManager; getMessageManager(): MessageManager; + getStatusBarItemManager(): StatusBarItemManager; getStyleManager(): StyleManager; getViewManager(): ViewManager; } @@ -218,6 +221,10 @@ export interface CardQueryStringAPI { getViewManager(): ViewManager; } +export interface CardStatusBarAPI { + getCardElementManager(): CardElementManager; +} + export interface CardStyleAPI { getCardElementManager(): CardElementManager; getConfigManager(): ConfigManager; diff --git a/src/card.ts b/src/card.ts index 8f9000c5..39e1db9d 100644 --- a/src/card.ts +++ b/src/card.ts @@ -2,6 +2,7 @@ import { HomeAssistant, LovelaceCardEditor } from '@dermotduffy/custom-card-help import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit'; import { customElement } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; +import { ifDefined } from 'lit/directives/if-defined.js'; import { Ref, createRef, ref } from 'lit/directives/ref.js'; import { styleMap } from 'lit/directives/style-map.js'; import 'web-dialog'; @@ -16,10 +17,18 @@ import './components/menu.js'; import { FrigateCardMenu } from './components/menu.js'; import './components/message.js'; import { renderMessage, renderProgressIndicator } from './components/message.js'; +import './components/overlay.js'; +import { FrigateCardOverlay } from './components/overlay.js'; +import './components/status-bar'; import './components/thumbnail-carousel.js'; import './components/views.js'; import { FrigateCardViews } from './components/views.js'; -import { FrigateCardConfig, MenuItem, RawFrigateCardConfig } from './config/types'; +import { + FrigateCardConfig, + MenuItem, + RawFrigateCardConfig, + StatusBarItem, +} from './config/types'; import { REPO_URL } from './const.js'; import { localize } from './localize/localize.js'; import cardStyle from './scss/card.scss'; @@ -103,6 +112,7 @@ class FrigateCard extends LitElement { protected _menuButtonController = new MenuButtonController(); protected _refMenu: Ref = createRef(); + protected _refOverlay: Ref = createRef(); protected _refMain: Ref = createRef(); protected _refElements: Ref = createRef(); protected _refViews: Ref = createRef(); @@ -185,7 +195,64 @@ class FrigateCard extends LitElement { this._controller.getInitializationManager().initializeBackgroundIfNecessary(); } - protected _renderMenu(): TemplateResult | void { + protected _renderMenuStatusContainer( + position: 'top' | 'bottom' | 'overlay', + ): TemplateResult | void { + if (!this._config) { + return; + } + + const menuStyle = this._config.menu.style; + const menuPosition = this._config.menu.position; + const statusBarStyle = this._config.status_bar.style; + const statusBarPosition = this._config.status_bar.position; + + if ( + // If there's nothing to render... + (menuStyle === 'none' && statusBarStyle === 'none') || + // ... or the position I'm rendering does not contain the menu/status bar + (position !== 'overlay' && + menuPosition !== position && + statusBarPosition !== position) + ) { + // ... then there's nothing to do. + return; + } + + const getContents = (kind: 'overlay' | 'outerlay'): TemplateResult => { + const shouldRenderMenu = + menuStyle !== 'none' && + ((menuStyle === 'outside' && kind === 'outerlay') || + (menuStyle !== 'outside' && kind === 'overlay')); + + const shouldRenderStatusBar = + statusBarStyle !== 'none' && + ((statusBarStyle === 'outside' && kind === 'outerlay') || + (statusBarStyle !== 'outside' && kind === 'overlay')); + + // As an exception, to improve the visual flow, if the menu is being + // rendered on the bottom, render the status bar first. + return html` + ${shouldRenderMenu && menuPosition !== 'bottom' + ? this._renderMenu(menuPosition) + : ''} + ${shouldRenderStatusBar ? this._renderStatusBar(statusBarPosition) : ''} + ${shouldRenderMenu && menuPosition === 'bottom' + ? this._renderMenu(menuPosition) + : ''} + `; + }; + + return html` + ${position === 'overlay' + ? html`${getContents('overlay')}` + : html`
      + ${getContents('outerlay')} +
      `} + `; + } + + protected _renderMenu(slot?: string): TemplateResult | void { const view = this._controller.getViewManager().getView(); if (!this._hass || !this._config || !view) { return; @@ -193,6 +260,7 @@ class FrigateCard extends LitElement { return html` + `; + } + protected firstUpdated(): void { // Execute query string actions after first render is complete. this._controller.getQueryStringManager().executeNonViewRelated(); @@ -250,8 +337,6 @@ class FrigateCard extends LitElement { }; const actions = this._controller.getActionsManager().getMergedActions(); - const renderMenuAbove = - this._config?.menu.style === 'outside' && this._config?.menu.position === 'top'; const cameraManager = this._controller.getCameraManager(); // Caution: Keep the main div and the menu next to one another in order to @@ -281,8 +366,9 @@ class FrigateCard extends LitElement { } @frigate-card:focus=${() => this.focus()} > - ${renderMenuAbove ? this._renderMenu() : ''} + ${this._renderMenuStatusContainer('top')}
      + ${this._renderMenuStatusContainer('overlay')} ${!cameraManager.isInitialized() && !this._controller.getMessageManager().hasMessage() ? renderProgressIndicator({ @@ -320,7 +406,7 @@ class FrigateCard extends LitElement { renderMessage(this._controller.getMessageManager().getMessage()) }
      - ${!renderMenuAbove ? this._renderMenu() : ''} + ${this._renderMenuStatusContainer('bottom')} ${this._config?.elements ? // Elements need to render after the main views so it can render 'on // top'. @@ -331,14 +417,24 @@ class FrigateCard extends LitElement { .conditionsManagerEpoch=${this._controller .getConditionsManager() ?.getEpoch()} - @frigate-card:menu-add=${(ev: CustomEvent) => { + @frigate-card:menu:add=${(ev: CustomEvent) => { this._menuButtonController.addDynamicMenuButton(ev.detail); this.requestUpdate(); }} - @frigate-card:menu-remove=${(ev: CustomEvent) => { + @frigate-card:menu:remove=${(ev: CustomEvent) => { this._menuButtonController.removeDynamicMenuButton(ev.detail); this.requestUpdate(); }} + @frigate-card:status-bar:add=${(ev: CustomEvent) => { + this._controller + .getStatusBarItemManager() + .addDynamicStatusBarItem(ev.detail); + }} + @frigate-card:status-bar:remove=${(ev: CustomEvent) => { + this._controller + .getStatusBarItemManager() + .removeDynamicStatusBarItem(ev.detail); + }} @frigate-card:conditions:evaluate=${( ev: ConditionsEvaluateRequestEvent, ) => { diff --git a/src/components-lib/live/utils/get-technology-for-video-rtc.ts b/src/components-lib/live/utils/get-technology-for-video-rtc.ts new file mode 100644 index 00000000..5d2d8aa8 --- /dev/null +++ b/src/components-lib/live/utils/get-technology-for-video-rtc.ts @@ -0,0 +1,12 @@ +import { MediaTechnology } from '../../../types'; +import { VideoRTC } from '../../../components/live/go2rtc/video-rtc'; + +export const getTechnologyForVideoRTC = ( + element: VideoRTC, +): MediaTechnology[] | undefined => { + const tech = [ + ...(!!element.pc ? ['webrtc'] : []), + ...(!element.pc && element.mseCodecs ? ['mse', 'hls'] : []), + ]; + return tech.length ? tech : undefined; +}; diff --git a/src/components-lib/menu-controller.ts b/src/components-lib/menu-controller.ts index f61e4131..967a1bcc 100644 --- a/src/components-lib/menu-controller.ts +++ b/src/components-lib/menu-controller.ts @@ -165,7 +165,7 @@ export class MenuController { } public getFreshButtonState(hass: HomeAssistant, button: MenuItem): StateParameters { - const stateParameters = { ...button }; + const stateParameters = { ...button } as StateParameters; return hass && button.type === 'custom:frigate-card-menu-state-icon' ? refreshDynamicStateParameters(hass, stateParameters) : stateParameters; diff --git a/src/components-lib/status-bar-controller.ts b/src/components-lib/status-bar-controller.ts new file mode 100644 index 00000000..89e43c02 --- /dev/null +++ b/src/components-lib/status-bar-controller.ts @@ -0,0 +1,119 @@ +import { HASSDomEvent } from '@dermotduffy/custom-card-helpers'; +import { LitElement } from 'lit'; +import { isEqual, orderBy } from 'lodash-es'; +import { dispatchActionExecutionRequest } from '../card-controller/actions/utils/execution-request'; +import { + ActionsConfig, + FRIGATE_STATUS_BAR_PRIORITY_DEFAULT, + StatusBarConfig, + StatusBarItem, +} from '../config/types'; +import { getActionConfigGivenAction } from '../utils/action'; +import { arrayify, setOrRemoveAttribute } from '../utils/basic'; +import { Timer } from '../utils/timer'; + +export class StatusBarController { + protected _host: LitElement; + protected _config: StatusBarConfig | null = null; + + protected _popupTimer = new Timer(); + protected _items: StatusBarItem[] = []; + + constructor(host: LitElement) { + this._host = host; + } + + public getRenderItems(): StatusBarItem[] { + return this._items; + } + + public setItems(items: StatusBarItem[]): void { + const exclusiveItems = items.filter((item) => !!item.exclusive); + + const newItems = orderBy( + exclusiveItems.length ? exclusiveItems : items, + (item) => item.priority ?? FRIGATE_STATUS_BAR_PRIORITY_DEFAULT, + 'desc', + ); + + const sufficientBefore = this._getSufficientValues(this._items); + const sufficientAfter = this._getSufficientValues(newItems); + + this._items = newItems; + + if (this._config?.style === 'popup' && !isEqual(sufficientBefore, sufficientAfter)) { + this._show(); + this._popupTimer.start(this._config.popup_seconds, () => this._hide()); + } + + this._host.requestUpdate(); + } + + public setConfig(config: StatusBarConfig): void { + this._config = config; + this._host.style.setProperty( + '--frigate-card-status-bar-height', + `${config.height}px`, + ); + + this._host.setAttribute('data-style', config.style); + this._host.setAttribute('data-position', config.position); + + if (this._config?.style !== 'popup') { + this._show(); + } + + this._host.requestUpdate(); + } + + public shouldRender(): boolean { + return this._items.some((item) => item.enabled !== false && item.sufficient); + } + + public actionHandler( + ev: HASSDomEvent<{ action: string; config?: ActionsConfig }>, + config?: ActionsConfig, + ): void { + // These interactions should only be handled by the status bar, as nothing + // upstream has the user-provided configuration. + ev.stopPropagation(); + + const interaction: string = ev.detail.action; + const action = getActionConfigGivenAction(interaction, config); + if (!action) { + return; + } + + dispatchActionExecutionRequest(this._host, { + action: arrayify(action), + config: config, + }); + } + + protected _getSufficientValue(item: StatusBarItem): string | null { + /* istanbul ignore else: cannot happen -- @preserve */ + if (item.type === 'custom:frigate-card-status-bar-icon') { + return item.icon; + } else if (item.type === 'custom:frigate-card-status-bar-string') { + return item.string; + } else if (item.type === 'custom:frigate-card-status-bar-image') { + return item.image; + } else { + return null; + } + } + + protected _getSufficientValues(items: StatusBarItem[]): (string | null)[] { + return items + .filter((item) => item.enabled !== false && item.sufficient) + .map((item) => this._getSufficientValue(item)); + } + + protected _show(): void { + setOrRemoveAttribute(this._host, false, 'hide'); + } + + protected _hide(): void { + setOrRemoveAttribute(this._host, true, 'hide'); + } +} diff --git a/src/components/elements.ts b/src/components/elements.ts index 9e3adf1d..5206a1f0 100644 --- a/src/components/elements.ts +++ b/src/components/elements.ts @@ -20,6 +20,10 @@ import { MenuSubmenu, MenuSubmenuSelect, PictureElements, + StatusBarIcon, + StatusBarImage, + StatusBarItem, + StatusBarString, } from '../config/types.js'; import { localize } from '../localize/localize.js'; import elementsStyle from '../scss/elements.scss'; @@ -164,50 +168,66 @@ export class FrigateCardElements extends LitElement { @property({ attribute: false }) public elements: PictureElements; - protected _boundMenuRemoveHandler = this._menuRemoveHandler.bind(this); - - /** - * Handle a picture element to be removed from the menu. - * @param ev The event. - */ - protected _menuRemoveHandler(ev: Event): void { - // Re-dispatch event from this element (instead of the disconnected one, as - // there is no parent of the disconnected element). - dispatchFrigateCardEvent(this, 'menu-remove', (ev as CustomEvent).detail); + protected _addHandler( + target: EventTarget, + eventName: string, + handler: (ev: Event) => void, + ) { + // Ensure listener is only attached 1 time by removing it first. + target.removeEventListener(eventName, handler); + target.addEventListener(eventName, handler); } - /** - * Handle a picture element to be added to the menu. - * @param ev The event. - */ - protected _menuAddHandler(ev: Event): void { + protected _menuRemoveHandler = (ev: Event): void => { + // Re-dispatch event from this element (instead of the disconnected one, as + // there is no parent of the disconnected element). + dispatchFrigateCardEvent(this, 'menu:remove', (ev as CustomEvent).detail); + }; + + protected _statusBarRemoveHandler = (ev: Event): void => { + // Re-dispatch event from this element (instead of the disconnected one, as + // there is no parent of the disconnected element). + dispatchFrigateCardEvent( + this, + 'status-bar:remove', + (ev as CustomEvent).detail, + ); + }; + + protected _menuAddHandler = (ev: Event): void => { ev = ev as CustomEvent; const path = ev.composedPath(); if (!path.length) { return; } + this._addHandler(path[0], 'frigate-card:menu:remove', this._menuRemoveHandler); + }; - // See 'A note on custom elements' above to explain what's going on here. - - // Ensure listener is only attached 1 time by removing it first. - path[0].removeEventListener( - 'frigate-card:menu-remove', - this._boundMenuRemoveHandler, + protected _statusBarAddHandler = (ev: Event): void => { + ev = ev as CustomEvent; + const path = ev.composedPath(); + if (!path.length) { + return; + } + this._addHandler( + path[0], + 'frigate-card:status-bar:add', + this._statusBarRemoveHandler, ); - - path[0].addEventListener('frigate-card:menu-remove', this._boundMenuRemoveHandler); - } + }; connectedCallback(): void { super.connectedCallback(); - // Catch icons being added to the menu (so their removal can be subsequently - // handled). - this.addEventListener('frigate-card:menu-add', this._menuAddHandler); + // Catch icons being added to the menu or status-bar (so their removal can + // be subsequently handled). + this.addEventListener('frigate-card:menu:add', this._menuAddHandler); + this.addEventListener('frigate-card:status-bar:add', this._statusBarAddHandler); } disconnectedCallback(): void { - this.removeEventListener('frigate-card:menu-add', this._menuAddHandler); + this.removeEventListener('frigate-card:menu:add', this._menuAddHandler); + this.addEventListener('frigate-card:status-bar:add', this._statusBarAddHandler); super.disconnectedCallback(); } @@ -286,59 +306,94 @@ export class FrigateCardElementsConditional extends LitElement { } // A base class for rendering menu icons / menu state icons. -export class FrigateCardElementsBaseMenuIcon extends LitElement { - @state() - protected _config: T | null = null; +export class FrigateCardElementsBaseItem extends LitElement { + protected _eventCategory: string; - /** - * Set the card config. - * @param config The configuration. - */ - public setConfig(config: T): void { + constructor(eventCategory: string) { + super(); + this._eventCategory = eventCategory; + } + + @state() + protected _config: ConfigType | null = null; + + public setConfig(config: ConfigType): void { this._config = config; } - /** - * Connected callback. - */ connectedCallback(): void { super.connectedCallback(); if (this._config) { - dispatchFrigateCardEvent(this, 'menu-add', this._config); + dispatchFrigateCardEvent( + this, + `${this._eventCategory}:add`, + this._config, + ); } } - /** - * Disconnected callback. - */ disconnectedCallback(): void { if (this._config) { - dispatchFrigateCardEvent(this, 'menu-remove', this._config); + dispatchFrigateCardEvent( + this, + `${this._eventCategory}:remove`, + this._config, + ); } super.disconnectedCallback(); } } +export class FrigateCardElementsBaseMenuItem< + ConfigType, +> extends FrigateCardElementsBaseItem { + constructor() { + super('menu'); + } +} + @customElement('frigate-card-menu-icon') -export class FrigateCardElementsMenuIcon extends FrigateCardElementsBaseMenuIcon {} +export class FrigateCardElementsMenuIcon extends FrigateCardElementsBaseMenuItem {} @customElement('frigate-card-menu-state-icon') -export class FrigateCardElementsMenuStateIcon extends FrigateCardElementsBaseMenuIcon {} +export class FrigateCardElementsMenuStateIcon extends FrigateCardElementsBaseMenuItem {} @customElement('frigate-card-menu-submenu') -export class FrigateCardElementsMenuSubmenu extends FrigateCardElementsBaseMenuIcon {} +export class FrigateCardElementsMenuSubmenu extends FrigateCardElementsBaseMenuItem {} @customElement('frigate-card-menu-submenu-select') -export class FrigateCardElementsMenuSubmenuSelect extends FrigateCardElementsBaseMenuIcon {} +export class FrigateCardElementsMenuSubmenuSelect extends FrigateCardElementsBaseMenuItem {} + +export class FrigateCardElementsBaseStatusBarItem< + ConfigType, +> extends FrigateCardElementsBaseItem { + constructor() { + super('status-bar'); + } +} + +@customElement('frigate-card-status-bar-icon') +export class FrigateCardElementsStatusBarIcon extends FrigateCardElementsBaseStatusBarItem {} + +@customElement('frigate-card-status-bar-image') +export class FrigateCardElementsStatusBarImage extends FrigateCardElementsBaseStatusBarItem {} + +@customElement('frigate-card-status-bar-string') +export class FrigateCardElementsStatusBarString extends FrigateCardElementsBaseStatusBarItem {} declare global { interface HTMLElementTagNameMap { 'frigate-card-conditional': FrigateCardElementsConditional; 'frigate-card-elements': FrigateCardElements; - 'frigate-card-menu-submenu-select': FrigateCardElementsMenuSubmenuSelect; - 'frigate-card-menu-submenu': FrigateCardElementsMenuSubmenu; - 'frigate-card-menu-state-icon': FrigateCardElementsMenuStateIcon; - 'frigate-card-menu-icon': FrigateCardElementsMenuIcon; 'frigate-card-elements-core': FrigateCardElementsCore; + + 'frigate-card-menu-icon': FrigateCardElementsMenuIcon; + 'frigate-card-menu-state-icon': FrigateCardElementsMenuStateIcon; + 'frigate-card-menu-submenu': FrigateCardElementsMenuSubmenu; + 'frigate-card-menu-submenu-select': FrigateCardElementsMenuSubmenuSelect; + + 'frigate-card-status-bar-icon': FrigateCardElementsStatusBarIcon; + 'frigate-card-status-bar-image': FrigateCardElementsStatusBarImage; + 'frigate-card-status-bar-string': FrigateCardElementsStatusBarString; } } diff --git a/src/components/live/go2rtc/video-rtc.js b/src/components/live/go2rtc/video-rtc.js index 434171b2..406cb3e2 100644 --- a/src/components/live/go2rtc/video-rtc.js +++ b/src/components/live/go2rtc/video-rtc.js @@ -10,6 +10,7 @@ import { dispatchMediaPlayEvent, dispatchMediaVolumeChangeEvent, } from '../../../utils/media-info'; +import { getTechnologyForVideoRTC } from '../../../components-lib/live/utils/get-technology-for-video-rtc.js'; /** * Video player for go2rtc streaming application. @@ -325,6 +326,7 @@ export class VideoRTC extends HTMLElement { supportsPause: true, hasAudio: mayHaveAudio(this.video), }, + technology: getTechnologyForVideoRTC(this), }); }; this.video.onvolumechange = () => dispatchMediaVolumeChangeEvent(this); @@ -641,6 +643,7 @@ export class VideoRTC extends HTMLElement { receivedFirstFrame = true; dispatchMediaLoadedEvent(this, this.video, { player: this.containingPlayer, + technology: ['mjpeg'], }); } }; @@ -668,6 +671,7 @@ export class VideoRTC extends HTMLElement { dispatchMediaLoadedEvent(this, video2, { player: this.containingPlayer, + technology: ['mp4'], }); } diff --git a/src/components/live/live-jsmpeg.ts b/src/components/live/live-jsmpeg.ts index 8d849d2a..1ee169c1 100644 --- a/src/components/live/live-jsmpeg.ts +++ b/src/components/live/live-jsmpeg.ts @@ -141,6 +141,7 @@ export class FrigateCardLiveJSMPEG extends LitElement implements FrigateCardMedi capabilities: { supportsPause: true, }, + technology: ['jsmpeg'], }); } } diff --git a/src/components/live/live-webrtc-card.ts b/src/components/live/live-webrtc-card.ts index 6a8f139d..b0d9f170 100644 --- a/src/components/live/live-webrtc-card.ts +++ b/src/components/live/live-webrtc-card.ts @@ -1,8 +1,9 @@ -import { Task } from '@lit-labs/task'; import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { Task } from '@lit-labs/task'; import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { CameraEndpoints } from '../../camera-manager/types.js'; +import { getTechnologyForVideoRTC } from '../../components-lib/live/utils/get-technology-for-video-rtc.js'; import { CameraConfig, CardWideConfig } from '../../config/types.js'; import { localize } from '../../localize/localize.js'; import liveWebRTCCardStyle from '../../scss/live-webrtc-card.scss'; @@ -22,6 +23,7 @@ import { import { screenshotMedia } from '../../utils/screenshot.js'; import { renderTask } from '../../utils/task.js'; import { dispatchErrorMessageEvent, renderProgressIndicator } from '../message.js'; +import { VideoRTC } from './go2rtc/video-rtc.js'; // Create a wrapper for AlexxIT's WebRTC card // - https://github.com/AlexxIT/WebRTC @@ -104,15 +106,16 @@ export class FrigateCardLiveWebRTCCard this.requestUpdate(); } + protected _getVideoRTC(): VideoRTC | null { + return (this.renderRoot?.querySelector('#webrtc') ?? null) as VideoRTC | null; + } + /** * Get the underlying video player. * @returns The player or `null` if not found. */ protected _getPlayer(): HTMLVideoElement | null { - const root = this.renderRoot?.querySelector('#webrtc') as - | (HTMLElement & { video?: HTMLVideoElement }) - | null; - return root?.video ?? null; + return this._getVideoRTC()?.video ?? null; } protected async _getWebRTCCardElement(): Promise< @@ -192,6 +195,7 @@ export class FrigateCardLiveWebRTCCard // Extract the video component after it has been rendered and generate the // media load event. this.updateComplete.then(() => { + const videoRTC = this._getVideoRTC(); const video = this._getPlayer(); if (video) { setControlsOnVideo(video, this.controls); @@ -205,6 +209,7 @@ export class FrigateCardLiveWebRTCCard supportsPause: true, hasAudio: mayHaveAudio(video), }, + ...(videoRTC && { technology: getTechnologyForVideoRTC(videoRTC) }), }); }; video.onplay = () => dispatchMediaPlayEvent(this); diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 2f440e43..1bc3834b 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -62,11 +62,6 @@ import '../next-prev-control.js'; import '../ptz.js'; import { FrigateCardPTZ } from '../ptz.js'; import '../surround.js'; -import '../title-control.js'; -import { - FrigateCardTitleControl, - getDefaultTitleConfigForView, -} from '../title-control.js'; const FRIGATE_CARD_LIVE_PROVIDER = 'frigate-card-live-provider'; @@ -294,7 +289,6 @@ export class FrigateCardLiveCarousel extends LitElement { // Index between camera name and slide number. protected _cameraToSlide: Record = {}; - protected _refTitleControl: Ref = createRef(); protected _refPTZControl: Ref = createRef(); @state() @@ -540,18 +534,10 @@ export class FrigateCardLiveCarousel extends LitElement { ? this.cameraManager.getCameraMetadata(this._getSubstreamCameraID(prevID, view)) : null; const cameraID = this.viewFilterCameraID ?? view.camera; - const cameraMetadataCurrent = this.cameraManager.getCameraMetadata( - this._getSubstreamCameraID(cameraID, view), - ); const cameraMetadataNext = nextID ? this.cameraManager.getCameraMetadata(this._getSubstreamCameraID(nextID, view)) : null; - const titleConfig = getDefaultTitleConfigForView( - view, - this.overriddenLiveConfig?.controls.title, - ); - // Notes on the below: // - guard() is used to avoid reseting the carousel unless the // options/plugins actually change. @@ -574,9 +560,6 @@ export class FrigateCardLiveCarousel extends LitElement { transitionEffect=${this._getTransitionEffect()} @frigate-card:carousel:select=${this._setViewHandler.bind(this)} @frigate-card:media:loaded=${() => { - if (this._refTitleControl.value) { - this._refTitleControl.value.show(); - } this._mediaHasLoaded = true; }} @frigate-card:media:unloaded=${() => { @@ -620,18 +603,6 @@ export class FrigateCardLiveCarousel extends LitElement { .forceVisibility=${this._mediaHasLoaded && view.context?.ptzControls?.enabled} > - ${cameraMetadataCurrent && titleConfig - ? html` - ` - : ``} `; } diff --git a/src/components/overlay.ts b/src/components/overlay.ts new file mode 100644 index 00000000..2c98d7ba --- /dev/null +++ b/src/components/overlay.ts @@ -0,0 +1,25 @@ +import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit'; +import { customElement } from 'lit/decorators.js'; +import overlayStyle from '../scss/overlay.scss'; + +@customElement('frigate-card-overlay') +export class FrigateCardOverlay extends LitElement { + protected render(): TemplateResult | void { + return html` + + + + + `; + } + + static get styles(): CSSResultGroup { + return unsafeCSS(overlayStyle); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'frigate-card-overlay': FrigateCardOverlay; + } +} diff --git a/src/components/status-bar.ts b/src/components/status-bar.ts new file mode 100644 index 00000000..a54abfe6 --- /dev/null +++ b/src/components/status-bar.ts @@ -0,0 +1,91 @@ +import { CSSResultGroup, LitElement, PropertyValues, TemplateResult, html, unsafeCSS } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; +import { actionHandler } from '../action-handler-directive.js'; +import { StatusBarController } from '../components-lib/status-bar-controller'; +import { StatusBarConfig, StatusBarItem } from '../config/types'; +import statusStyle from '../scss/status.scss'; +import { frigateCardHasAction } from '../utils/action'; + +@customElement('frigate-card-status-bar') +export class FrigateCardStatusBar extends LitElement { + protected _controller = new StatusBarController(this); + + @property({ attribute: false }) + public items?: StatusBarItem[]; + + @property({ attribute: false }) + public config?: StatusBarConfig; + + protected willUpdate(changedProperties: PropertyValues): void { + // Always set config before items. + if (changedProperties.has('config') && this.config) { + this._controller.setConfig(this.config); + } + + if (changedProperties.has('items')) { + this._controller.setItems(this.items ?? []); + } + } + + protected render(): TemplateResult | void { + if (!this._controller.shouldRender()) { + return; + } + + return html` +
      + ${this._controller.getRenderItems().map((item): TemplateResult | void => { + if (item.enabled === false) { + return; + } + + const classes = classMap({ + item: true, + expand: !!item.expand, + action: !!Object.keys(item.actions ?? {}).length, + }); + + const handler = actionHandler({ + hasHold: frigateCardHasAction(item.actions?.hold_action), + hasDoubleClick: frigateCardHasAction(item.actions?.double_tap_action), + }); + + if (item.type === 'custom:frigate-card-status-bar-string') { + return html`
      this._controller.actionHandler(ev, item.actions)} + > + ${item.string} +
      `; + } else if (item.type === 'custom:frigate-card-status-bar-icon') { + return html` this._controller.actionHandler(ev, item.actions)} + >`; + } else if (item.type === 'custom:frigate-card-status-bar-image') { + return html` this._controller.actionHandler(ev, item.actions)} + />`; + } + })} +
      + `; + } + + static get styles(): CSSResultGroup { + return unsafeCSS(statusStyle); + } +} + +declare global { + interface HTMLElementTagNameMap { + 'frigate-card-status-bar': FrigateCardStatusBar; + } +} diff --git a/src/components/submenu.ts b/src/components/submenu.ts index f0e9ad8d..4d36e1e0 100644 --- a/src/components/submenu.ts +++ b/src/components/submenu.ts @@ -81,6 +81,7 @@ export class FrigateCardSubmenu extends LitElement { if (!this.submenu) { return html``; } + const items = this.submenu.items as MenuSubmenuItem[]; return html` - ${this.submenu.items.map(this._renderItem.bind(this))} + ${items.map(this._renderItem.bind(this))} `; } @@ -217,9 +218,11 @@ export class FrigateCardSubmenuSelect extends LitElement { // the items correctly (below). delete submenu['options']; + const items = submenu.items as MenuSubmenuItem[]; + for (const option of options) { const title = this._optionTitles?.[option] ?? option; - submenu.items.push({ + items.push({ state_color: true, selected: stateObj.state === option, enabled: true, diff --git a/src/components/surround-basic.ts b/src/components/surround-basic.ts index a49c5f1d..1975b708 100644 --- a/src/components/surround-basic.ts +++ b/src/components/surround-basic.ts @@ -51,10 +51,6 @@ export class FrigateCardSurroundBasic extends LitElement { } } - /** - * Master render method. - * @returns A rendered template. - */ protected render(): TemplateResult | void { return html` diff --git a/src/components/title-control.ts b/src/components/title-control.ts deleted file mode 100644 index af198c00..00000000 --- a/src/components/title-control.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { CSSResultGroup, html, LitElement, TemplateResult, unsafeCSS } from 'lit'; -import { customElement, property } from 'lit/decorators.js'; -import { createRef, Ref, ref } from 'lit/directives/ref.js'; -import { TitleControlConfig } from '../config/types'; -import titleStyle from '../scss/title-control.scss'; -import { View } from '../view/view.js'; - -type PaperToast = HTMLElement & { - opened: boolean; -}; - -export const getDefaultTitleConfigForView = ( - view?: Readonly | null, - baseConfig?: TitleControlConfig, -): TitleControlConfig | null => { - if (!baseConfig && view?.isGrid()) { - return { mode: 'none', duration_seconds: 2 }; - } - return { - mode: 'popup-bottom-right', - duration_seconds: 2, - ...baseConfig, - }; -}; - -@customElement('frigate-card-title-control') -export class FrigateCardTitleControl extends LitElement { - @property({ attribute: false }) - public config?: TitleControlConfig; - - @property({ attribute: false }) - public text?: string; - - @property({ attribute: false }) - public fitInto?: HTMLElement; - - @property({ attribute: false }) - public logo?: string; - - protected _toastRef: Ref = createRef(); - - protected render(): TemplateResult { - if ( - !this.text || - !this.config || - !this.config.mode || - this.config.duration_seconds === undefined || - this.config.mode === 'none' || - !this.fitInto - ) { - return html``; - } - - const verticalAlign = this.config.mode.match(/-top-/) ? 'top' : 'bottom'; - const horizontalAlign = this.config.mode.match(/-left$/) ? 'left' : 'right'; - - return html` - ${this.logo ? html`` : ''} - `; - } - - public isVisible(): boolean { - return this._toastRef.value?.opened ?? false; - } - - public hide(): void { - if (this._toastRef.value) { - // Set it to false first, to ensure the timer resets. - this._toastRef.value.opened = false; - } - } - - public show(): void { - if (this._toastRef.value) { - // Set it to false first, to ensure the timer resets. - this._toastRef.value.opened = false; - this._toastRef.value.opened = true; - } - } - - static get styles(): CSSResultGroup { - return unsafeCSS(titleStyle); - } -} - -declare global { - interface HTMLElementTagNameMap { - 'frigate-card-title-control': FrigateCardTitleControl; - } -} diff --git a/src/components/viewer.ts b/src/components/viewer.ts index 3c79774b..a18c2ead 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -73,11 +73,6 @@ import type { EmblaCarouselPlugins } from './carousel.js'; import './next-prev-control.js'; import './ptz'; import './surround.js'; -import './title-control.js'; -import { - FrigateCardTitleControl, - getDefaultTitleConfigForView, -} from './title-control.js'; export interface MediaViewerViewContext { seek?: Date; @@ -194,7 +189,6 @@ export class FrigateCardViewerCarousel extends LitElement { protected _selected = 0; protected _media: ViewMedia[] | null = null; - protected _refTitleControl: Ref = createRef(); protected _player: FrigateCardMediaPlayer | null = null; /** @@ -407,15 +401,7 @@ export class FrigateCardViewerCarousel extends LitElement { } }; - const cameraMetadata = this.cameraManager.getCameraMetadata( - selectedMedia.getCameraID(), - ); - const view = this.viewManagerEpoch?.manager.getView(); - const titleConfig = getDefaultTitleConfigForView( - view, - this.viewerConfig?.controls.title, - ); return html` ) => { - if (this._refTitleControl.value) { - this._refTitleControl.value.show(); - } this._player = ev.detail.player ?? null; this._seekHandler(); }} @@ -480,16 +463,6 @@ export class FrigateCardViewerCarousel extends LitElement {
      - ${cameraMetadata && titleConfig - ? html` - ` - : ``} `; } @@ -919,6 +892,7 @@ export class FrigateCardViewerProvider supportsPause: true, hasAudio: mayHaveAudio(ev.target as HTMLVideoElement), }, + technology: ['hls'], }); }} @volumechange=${() => dispatchMediaVolumeChangeEvent(this)} @@ -942,7 +916,7 @@ export class FrigateCardViewerProvider } }} @load=${(ev: Event) => { - dispatchMediaLoadedEvent(this, ev, { player: this }); + dispatchMediaLoadedEvent(this, ev, { player: this, technology: ['jpg'] }); }} />`} `); diff --git a/src/config/management.ts b/src/config/management.ts index 9f7d73ae..9110fa4b 100644 --- a/src/config/management.ts +++ b/src/config/management.ts @@ -3,11 +3,6 @@ import get from 'lodash-es/get'; import isEqual from 'lodash-es/isEqual'; import set from 'lodash-es/set'; import unset from 'lodash-es/unset'; -import { - FrigateCardCondition, - RawFrigateCardConfig, - RawFrigateCardConfigArray, -} from './types'; import { CONF_AUTOMATIONS, CONF_CAMERAS, @@ -24,18 +19,24 @@ import { CONF_MENU_BUTTONS_CAMERA_UI, CONF_OVERRIDES, CONF_PROFILES, + CONF_STATUS_BAR, CONF_TIMELINE_EVENTS_MEDIA_TYPE, CONF_VIEW_DEFAULT_CYCLE_CAMERA, - CONF_VIEW_INTERACTION_SECONDS, - CONF_VIEW_DEFAULT_RESET_EVERY_SECONDS, CONF_VIEW_DEFAULT_RESET_ENTITIES, + CONF_VIEW_DEFAULT_RESET_EVERY_SECONDS, CONF_VIEW_DEFAULT_RESET_INTERACTION_MODE, + CONF_VIEW_INTERACTION_SECONDS, CONF_VIEW_TRIGGERS, CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER, CONF_VIEW_TRIGGERS_ACTIONS_UNTRIGGER, CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA, } from '../const'; import { arrayify } from '../utils/basic'; +import { + FrigateCardCondition, + RawFrigateCardConfig, + RawFrigateCardConfigArray, +} from './types'; // ************************************************************************* // General Config Management Functions @@ -660,6 +661,27 @@ const ptzControlSettingsTransform = (data: unknown): unknown => { }, {}); }; +const titleControlTransform = (data: unknown): unknown => { + if (typeof data !== 'object' || !data || typeof data['mode'] !== 'string') { + return null; + } + if (data['mode'] === 'none') { + return { + style: 'none', + }; + } + if (data['mode'].includes('bottom')) { + return { + position: 'bottom', + }; + } else if (data['mode'].includes('top')) { + return { + position: 'top', + }; + } + return null; +}; + const UPGRADES = [ // v4.0.0 -> v4.1.0 upgradeArrayOfObjects( @@ -822,4 +844,9 @@ const UPGRADES = [ CONF_VIEW_DEFAULT_RESET_EVERY_SECONDS, ), upgradeMoveToWithOverrides('view.update_entities', CONF_VIEW_DEFAULT_RESET_ENTITIES), + upgradeMoveTo('live.controls.title', CONF_STATUS_BAR, { + transform: titleControlTransform, + }), + deleteWithOverrides('live.controls.title'), + deleteWithOverrides('media_viewer.controls.title'), ]; diff --git a/src/config/profiles/low-performance.ts b/src/config/profiles/low-performance.ts index e80e07cc..2ee9d8cf 100644 --- a/src/config/profiles/low-performance.ts +++ b/src/config/profiles/low-performance.ts @@ -9,7 +9,6 @@ import { 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, @@ -28,7 +27,6 @@ import { 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_SNAPSHOT_CLICK_PLAYS_CLIP, CONF_MEDIA_VIEWER_TRANSITION_EFFECT, @@ -40,6 +38,7 @@ import { CONF_PERFORMANCE_FEATURES_MEDIA_CHUNK_SIZE, CONF_PERFORMANCE_STYLE_BORDER_RADIUS, CONF_PERFORMANCE_STYLE_BOX_SHADOW, + CONF_STATUS_BAR_STYLE, CONF_TIMELINE_CONTROLS_THUMBNAILS_MODE, CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_DETAILS, CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_DOWNLOAD_CONTROL, @@ -83,8 +82,8 @@ export const LOW_PERFORMANCE_PROFILE = { // 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, + // Disable the status bar. + [CONF_STATUS_BAR_STYLE]: 'none' as const, // Move the menu to outside to remove the need to interact with it with open. [CONF_MENU_STYLE]: 'outside', diff --git a/src/config/types.ts b/src/config/types.ts index 3eae4a0c..b5875991 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -21,12 +21,15 @@ import { PTZ_ACTIONS } from './ptz'; // Common Configuration Constants // ************************************************************************* -// The min allowed size of buttons. export const BUTTON_SIZE_MIN = 20; +export const STATUS_BAR_HEIGHT_MIN = BUTTON_SIZE_MIN; const FRIGATE_MENU_PRIORITY_DEFAULT = 50; export const FRIGATE_MENU_PRIORITY_MAX = 100; +export const FRIGATE_STATUS_BAR_PRIORITY_DEFAULT = FRIGATE_MENU_PRIORITY_DEFAULT; +export const FRIGATE_STATUS_BAR_PRIORITY_MAX = FRIGATE_MENU_PRIORITY_MAX; + export const FRIGATE_CARD_VIEWS_USER_SPECIFIED = [ 'diagnostics', 'live', @@ -343,6 +346,19 @@ const sleepActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ }); export type SleepActionConfig = z.infer; +const statusBarActionConfigSchema = frigateCardCustomActionsBaseSchema.extend({ + frigate_card_action: z.literal('status_bar'), + status_bar_action: z.enum(['add', 'remove', 'reset']), + + // This needs to be lazily evaluated since statusBarItemSchema may itself + // contain actions. + items: z + .lazy(() => statusBarItemSchema) + .array() + .optional(), +}); +export type StatusBarActionConfig = z.infer; + const LOG_ACTIONS_LEVELS = ['debug', 'info', 'warn', 'error'] as const; export type LogActionLevel = (typeof LOG_ACTIONS_LEVELS)[number]; @@ -366,6 +382,7 @@ export const frigateCardCustomActionSchema = z.union([ viewActionConfigSchema, viewDisplayModeActionConfigSchema, sleepActionConfigSchema, + statusBarActionConfigSchema, ]); export type FrigateCardCustomAction = z.infer; @@ -581,6 +598,52 @@ const menuSubmenuSelectSchema = menuBaseSchema.merge(stateIconSchema).extend({ export type MenuSubmenuSelect = z.infer; export type MenuItem = MenuIcon | MenuStateIcon | MenuSubmenu | MenuSubmenuSelect; +// ************************************************************************* +// Custom Element Configuration: Status bar +// ************************************************************************* + +const statusBarItemBaseSchema = z.object({ + enabled: z.boolean().default(true).optional(), + priority: z + .number() + .min(0) + .max(FRIGATE_STATUS_BAR_PRIORITY_MAX) + .default(FRIGATE_STATUS_BAR_PRIORITY_DEFAULT) + .optional(), +}); + +const statusBarItemElementsBaseSchema = statusBarItemBaseSchema.extend({ + sufficient: z.boolean().default(false).optional(), + exclusive: z.boolean().default(false).optional(), + expand: z.boolean().default(false).optional(), + actions: actionsBaseSchema.optional(), +}); + +const statusBarIconItemSchema = statusBarItemElementsBaseSchema.extend({ + type: z.literal('custom:frigate-card-status-bar-icon'), + icon: z.string(), +}); +export type StatusBarIcon = z.infer; + +const statusBarImageItemSchema = statusBarItemElementsBaseSchema.extend({ + type: z.literal('custom:frigate-card-status-bar-image'), + image: z.string(), +}); +export type StatusBarImage = z.infer; + +const statusBarStringItemSchema = statusBarItemElementsBaseSchema.extend({ + type: z.literal('custom:frigate-card-status-bar-string'), + string: z.string(), +}); +export type StatusBarString = z.infer; + +const statusBarItemSchema = z.union([ + statusBarIconItemSchema, + statusBarImageItemSchema, + statusBarStringItemSchema, +]); +export type StatusBarItem = z.infer; + // ************************************************************************* // Custom Element Configuration: Conditions // ************************************************************************* @@ -680,6 +743,9 @@ const pictureElementSchema = z.union([ stateBadgeIconSchema, stateIconSchema, stateLabelSchema, + statusBarIconItemSchema, + statusBarImageItemSchema, + statusBarStringItemSchema, ]); const pictureElementsSchema = pictureElementSchema.array().optional(); export type PictureElements = z.infer; @@ -1009,24 +1075,6 @@ const nextPreviousControlConfigSchema = z.object({ }); export type NextPreviousControlConfig = z.infer; -// ************************************************************************* -// Title Control Configuration -// ************************************************************************* - -const titleControlConfigSchema = z.object({ - mode: z - .enum([ - 'none', - 'popup-top-right', - 'popup-top-left', - 'popup-bottom-right', - 'popup-bottom-left', - ]) - .optional(), - duration_seconds: z.number().min(0).max(60).optional(), -}); -export type TitleControlConfig = z.infer; - // ************************************************************************* // Carousel Transition Configuration // ************************************************************************* @@ -1188,7 +1236,6 @@ const liveConfigSchema = z liveConfigDefault.controls.thumbnails, ), timeline: miniTimelineConfigSchema.default(liveConfigDefault.controls.timeline), - title: titleControlConfigSchema.optional(), }) .default(liveConfigDefault.controls), display: viewDisplaySchema, @@ -1584,6 +1631,65 @@ export const menuConfigSchema = z .default(menuConfigDefault); export type MenuConfig = z.infer; +// ************************************************************************* +// Status Bar Configuration +// ************************************************************************* + +const STATUS_BAR_STYLES = [ + 'none', + 'overlay', + 'hover', + 'hover-card', + 'outside', + 'popup', +] as const; + +const STATUS_BAR_POSITIONS = ['top', 'bottom'] as const; + +const statusBarItemDefault = { + priority: FRIGATE_STATUS_BAR_PRIORITY_DEFAULT, + enabled: true, +}; + +const statusBarConfigDefault = { + height: 46, + items: { + engine: statusBarItemDefault, + resolution: statusBarItemDefault, + technology: statusBarItemDefault, + title: statusBarItemDefault, + }, + position: 'bottom' as const, + style: 'popup' as const, + popup_seconds: 3, +}; + +export const statusBarConfigSchema = z + .object({ + position: z.enum(STATUS_BAR_POSITIONS).default(statusBarConfigDefault.position), + style: z.enum(STATUS_BAR_STYLES).default(statusBarConfigDefault.style), + popup_seconds: z + .number() + .min(0) + .max(60) + .default(statusBarConfigDefault.popup_seconds), + height: z.number().min(STATUS_BAR_HEIGHT_MIN).default(statusBarConfigDefault.height), + items: z + .object({ + engine: statusBarItemBaseSchema.default(statusBarConfigDefault.items.engine), + technology: statusBarItemBaseSchema.default( + statusBarConfigDefault.items.technology, + ), + resolution: statusBarItemBaseSchema.default( + statusBarConfigDefault.items.resolution, + ), + title: statusBarItemBaseSchema.default(statusBarConfigDefault.items.title), + }) + .default(statusBarConfigDefault.items), + }) + .default(statusBarConfigDefault); +export type StatusBarConfig = z.infer; + // ************************************************************************* // Event Viewer Configuration // ************************************************************************* @@ -1672,7 +1778,6 @@ const viewerConfigSchema = z timeline: miniTimelineConfigSchema.default( viewerConfigDefault.controls.timeline, ), - title: titleControlConfigSchema.optional(), }) .default(viewerConfigDefault.controls), }) @@ -1767,11 +1872,16 @@ export type Overrides = z.infer; const automationActionSchema = actionSchema.array(); export type AutomationActions = z.infer; -const automationSchema = z.object({ - conditions: frigateCardConditionSchema.array(), - actions: automationActionSchema.optional(), - actions_not: automationActionSchema.optional(), -}); +const automationSchema = z + .object({ + conditions: frigateCardConditionSchema.array(), + actions: automationActionSchema.optional(), + actions_not: automationActionSchema.optional(), + }) + .refine( + (data) => data.actions?.length || data.actions_not?.length, + 'Automations must include at least one action', + ); export type Automation = z.infer; const automationsSchema = automationSchema.array(); @@ -1857,6 +1967,7 @@ export const frigateCardConfigSchema = z.object({ view: viewConfigSchema, menu: menuConfigSchema, + status_bar: statusBarConfigSchema, live: liveConfigSchema, media_gallery: galleryConfigSchema, media_viewer: viewerConfigSchema, @@ -1892,6 +2003,7 @@ export const frigateCardConfigDefaults = { cameras: cameraConfigDefault, view: viewConfigDefault, menu: menuConfigDefault, + status_bar: statusBarConfigDefault, live: liveConfigDefault, media_gallery: galleryConfigDefault, media_viewer: viewerConfigDefault, diff --git a/src/const.ts b/src/const.ts index b20219a3..92d4045f 100644 --- a/src/const.ts +++ b/src/const.ts @@ -216,11 +216,6 @@ export const CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_WINDOW_SECONDS = `${CONF_MEDIA_VIEWER}.controls.timeline.window_seconds` as const; export const CONF_MEDIA_VIEWER_ZOOMABLE = `${CONF_MEDIA_VIEWER}.zoomable` as const; -export const CONF_MEDIA_VIEWER_CONTROLS_TITLE_MODE = - `${CONF_MEDIA_VIEWER}.controls.title.mode` as const; -export const CONF_MEDIA_VIEWER_CONTROLS_TITLE_DURATION_SECONDS = - `${CONF_MEDIA_VIEWER}.controls.title.duration_seconds` as const; - const CONF_LIVE = 'live' as const; export const CONF_LIVE_AUTO_PLAY = `${CONF_LIVE}.auto_play` as const; export const CONF_LIVE_AUTO_PAUSE = `${CONF_LIVE}.auto_pause` as const; @@ -272,9 +267,6 @@ export const CONF_LIVE_CONTROLS_TIMELINE_STYLE = `${CONF_LIVE}.controls.timeline.style` as const; export const CONF_LIVE_CONTROLS_TIMELINE_WINDOW_SECONDS = `${CONF_LIVE}.controls.timeline.window_seconds` as const; -export const CONF_LIVE_CONTROLS_TITLE_MODE = `${CONF_LIVE}.controls.title.mode` as const; -export const CONF_LIVE_CONTROLS_TITLE_DURATION_SECONDS = - `${CONF_LIVE}.controls.title.duration_seconds` as const; export const CONF_LIVE_DISPLAY_MODE = `${CONF_LIVE}.display.mode` as const; export const CONF_LIVE_DISPLAY_GRID_COLUMNS = `${CONF_LIVE}.display.grid_columns` as const; @@ -336,6 +328,14 @@ export const CONF_MENU_BUTTONS_MEDIA_PLAYER = `${CONF_MENU}.buttons.media_player` as const; export const CONF_MENU_BUTTONS_TIMELINE = `${CONF_MENU}.buttons.timeline` as const; +export const CONF_STATUS_BAR = 'status_bar' as const; +export const CONF_STATUS_BAR_POSITION = `${CONF_STATUS_BAR}.position` as const; +export const CONF_STATUS_BAR_STYLE = `${CONF_STATUS_BAR}.style` as const; +export const CONF_STATUS_BAR_POPUP_SECONDS = `${CONF_STATUS_BAR}.popup_seconds` as const; +export const CONF_STATUS_BAR_HEIGHT = `${CONF_STATUS_BAR}.height` as const; + +export const CONF_STATUS_BAR_ITEMS = `${CONF_STATUS_BAR}.items` as const; + const CONF_DIMENSIONS = 'dimensions' as const; export const CONF_DIMENSIONS_ASPECT_RATIO = `${CONF_DIMENSIONS}.aspect_ratio` as const; export const CONF_DIMENSIONS_ASPECT_RATIO_MODE = diff --git a/src/editor.ts b/src/editor.ts index 4d6bd9e5..6e0e1059 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -11,6 +11,8 @@ import { MOTIONEYE_ICON_SVG_PATH, MOTIONEYE_ICON_SVG_VIEWBOX, } from './camera-manager/motioneye/icon.js'; +import './components/key-assigner.js'; +import { KeyboardShortcut } from './config/keyboard-shortcuts.js'; import { copyConfig, deleteConfigValue, @@ -23,12 +25,14 @@ import { import { setProfiles } from './config/profiles/index.js'; import { BUTTON_SIZE_MIN, + FRIGATE_MENU_PRIORITY_MAX, + FRIGATE_STATUS_BAR_PRIORITY_MAX, FrigateCardConfig, frigateCardConfigDefaults, - FRIGATE_MENU_PRIORITY_MAX, profilesSchema, RawFrigateCardConfig, RawFrigateCardConfigArray, + STATUS_BAR_HEIGHT_MIN, THUMBNAIL_WIDTH_MAX, THUMBNAIL_WIDTH_MIN, } from './config/types.js'; @@ -112,8 +116,6 @@ import { CONF_LIVE_CONTROLS_TIMELINE_SHOW_RECORDINGS, CONF_LIVE_CONTROLS_TIMELINE_STYLE, CONF_LIVE_CONTROLS_TIMELINE_WINDOW_SECONDS, - CONF_LIVE_CONTROLS_TITLE_DURATION_SECONDS, - CONF_LIVE_CONTROLS_TITLE_MODE, CONF_LIVE_DISPLAY_GRID_COLUMNS, CONF_LIVE_DISPLAY_GRID_MAX_COLUMNS, CONF_LIVE_DISPLAY_GRID_SELECTED_WIDTH_FACTOR, @@ -154,8 +156,6 @@ import { CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_SHOW_RECORDINGS, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_STYLE, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_WINDOW_SECONDS, - CONF_MEDIA_VIEWER_CONTROLS_TITLE_DURATION_SECONDS, - CONF_MEDIA_VIEWER_CONTROLS_TITLE_MODE, CONF_MEDIA_VIEWER_DISPLAY_GRID_COLUMNS, CONF_MEDIA_VIEWER_DISPLAY_GRID_MAX_COLUMNS, CONF_MEDIA_VIEWER_DISPLAY_GRID_SELECTED_WIDTH_FACTOR, @@ -166,8 +166,8 @@ import { CONF_MEDIA_VIEWER_TRANSITION_EFFECT, CONF_MEDIA_VIEWER_ZOOMABLE, CONF_MENU_ALIGNMENT, - CONF_MENU_BUTTONS, CONF_MENU_BUTTON_SIZE, + CONF_MENU_BUTTONS, CONF_MENU_POSITION, CONF_MENU_STYLE, CONF_PERFORMANCE_FEATURES_ANIMATED_PROGRESS_INDICATOR, @@ -176,6 +176,11 @@ import { CONF_PERFORMANCE_STYLE_BORDER_RADIUS, CONF_PERFORMANCE_STYLE_BOX_SHADOW, CONF_PROFILES, + CONF_STATUS_BAR_HEIGHT, + CONF_STATUS_BAR_ITEMS, + CONF_STATUS_BAR_POPUP_SECONDS, + CONF_STATUS_BAR_POSITION, + CONF_STATUS_BAR_STYLE, CONF_TIMELINE_CLUSTERING_THRESHOLD, CONF_TIMELINE_CONTROLS_THUMBNAILS_MODE, CONF_TIMELINE_CONTROLS_THUMBNAILS_SHOW_DETAILS, @@ -190,6 +195,12 @@ import { CONF_VIEW_CAMERA_SELECT, CONF_VIEW_DARK_MODE, CONF_VIEW_DEFAULT, + CONF_VIEW_DEFAULT_CYCLE_CAMERA, + CONF_VIEW_DEFAULT_RESET, + CONF_VIEW_DEFAULT_RESET_AFTER_INTERACTION, + CONF_VIEW_DEFAULT_RESET_ENTITIES, + CONF_VIEW_DEFAULT_RESET_EVERY_SECONDS, + CONF_VIEW_DEFAULT_RESET_INTERACTION_MODE, CONF_VIEW_INTERACTION_SECONDS, CONF_VIEW_KEYBOARD_SHORTCUTS, CONF_VIEW_KEYBOARD_SHORTCUTS_ENABLED, @@ -200,7 +211,6 @@ import { CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_UP, CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_ZOOM_IN, CONF_VIEW_KEYBOARD_SHORTCUTS_PTZ_ZOOM_OUT, - CONF_VIEW_DEFAULT_RESET_AFTER_INTERACTION, CONF_VIEW_TRIGGERS, CONF_VIEW_TRIGGERS_ACTIONS, CONF_VIEW_TRIGGERS_ACTIONS_INTERACTION_MODE, @@ -209,12 +219,7 @@ import { CONF_VIEW_TRIGGERS_FILTER_SELECTED_CAMERA, CONF_VIEW_TRIGGERS_SHOW_TRIGGER_STATUS, CONF_VIEW_TRIGGERS_UNTRIGGER_SECONDS, - CONF_VIEW_DEFAULT_CYCLE_CAMERA, MEDIA_CHUNK_SIZE_MAX, - CONF_VIEW_DEFAULT_RESET, - CONF_VIEW_DEFAULT_RESET_EVERY_SECONDS, - CONF_VIEW_DEFAULT_RESET_INTERACTION_MODE, - CONF_VIEW_DEFAULT_RESET_ENTITIES, } from './const.js'; import { localize } from './localize/localize.js'; import frigate_card_editor_style from './scss/editor.scss'; @@ -225,10 +230,7 @@ import { getEntityTitle, sideLoadHomeAssistantElements, } from './utils/ha'; -import './components/key-assigner.js'; -import { KeyboardShortcut } from './config/keyboard-shortcuts.js'; -const MENU_BUTTONS = 'buttons'; const MENU_CAMERAS = 'cameras'; const MENU_CAMERAS_CAPABILITIES = 'cameras.capabilities'; const MENU_CAMERAS_CAST = 'cameras.cast'; @@ -248,7 +250,6 @@ const MENU_LIVE_CONTROLS_NEXT_PREVIOUS = 'live.controls.next_previous'; const MENU_LIVE_CONTROLS_PTZ = 'live.controls.ptz'; const MENU_LIVE_CONTROLS_THUMBNAILS = 'live.controls.thumbnails'; const MENU_LIVE_CONTROLS_TIMELINE = 'live.controls.timeline'; -const MENU_LIVE_CONTROLS_TITLE = 'live.controls.title'; const MENU_LIVE_DISPLAY = 'live.display'; const MENU_LIVE_MICROPHONE = 'live.microphone'; const MENU_MEDIA_GALLERY_CONTROLS_FILTER = 'media_gallery.controls.filter'; @@ -257,14 +258,15 @@ const MENU_MEDIA_VIEWER_CONTROLS = 'media_viewer.controls'; const MENU_MEDIA_VIEWER_CONTROLS_NEXT_PREVIOUS = 'media_viewer.controls.next_previous'; const MENU_MEDIA_VIEWER_CONTROLS_THUMBNAILS = 'media_viewer.controls.thumbnails'; const MENU_MEDIA_VIEWER_CONTROLS_TIMELINE = 'media_viewer.controls.timeline'; -const MENU_MEDIA_VIEWER_CONTROLS_TITLE = 'media_viewer.controls.title'; const MENU_MEDIA_VIEWER_DISPLAY = 'media_viewer.display'; +const MENU_MENU_BUTTONS = 'menu.buttons'; const MENU_OPTIONS = 'options'; const MENU_PERFORMANCE_FEATURES = 'performance.features'; const MENU_PERFORMANCE_STYLE = 'performance.style'; +const MENU_STATUS_BAR_ITEMS = 'status_bar.items'; const MENU_TIMELINE_CONTROLS_THUMBNAILS = 'timeline.controls.thumbnails'; -const MENU_VIEW_KEYBOARD_SHORTCUTS = 'view.keyboard_shortcuts'; const MENU_VIEW_DEFAULT_RESET = 'view.default_reset'; +const MENU_VIEW_KEYBOARD_SHORTCUTS = 'view.keyboard_shortcuts'; const MENU_VIEW_TRIGGERS = 'view.triggers'; const MENU_VIEW_TRIGGERS_ACTIONS = 'view.triggers.actions'; @@ -303,6 +305,11 @@ const options: EditorOptions = { name: localize('editor.menu'), secondary: localize('editor.menu_secondary'), }, + status_bar: { + icon: 'sign-text', + name: localize('editor.status_bar'), + secondary: localize('editor.status_bar_secondary'), + }, live: { icon: 'cctv', name: localize('editor.live'), @@ -503,27 +510,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor }, ]; - protected _titleModes: EditorSelectOption[] = [ - { value: '', label: '' }, - { value: 'none', label: localize('config.common.controls.title.modes.none') }, - { - value: 'popup-top-left', - label: localize('config.common.controls.title.modes.popup-top-left'), - }, - { - value: 'popup-top-right', - label: localize('config.common.controls.title.modes.popup-top-right'), - }, - { - value: 'popup-bottom-left', - label: localize('config.common.controls.title.modes.popup-bottom-left'), - }, - { - value: 'popup-bottom-right', - label: localize('config.common.controls.title.modes.popup-bottom-right'), - }, - ]; - protected _transitionEffects: EditorSelectOption[] = [ { value: '', label: '' }, { value: 'none', label: localize('config.media_viewer.transition_effects.none') }, @@ -831,6 +817,22 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor }, ]; + protected _statusBarStyles: EditorSelectOption[] = [ + { value: '', label: '' }, + { value: 'hover', label: localize('config.status_bar.styles.hover') }, + { value: 'hover-card', label: localize('config.status_bar.styles.hover-card') }, + { value: 'none', label: localize('config.status_bar.styles.none') }, + { value: 'outside', label: localize('config.status_bar.styles.outside') }, + { value: 'overlay', label: localize('config.status_bar.styles.overlay') }, + { value: 'popup', label: localize('config.status_bar.styles.popup') }, + ]; + + protected _statusBarPositions: EditorSelectOption[] = [ + { value: '', label: '' }, + { value: 'top', label: localize('config.status_bar.positions.top') }, + { value: 'bottom', label: localize('config.status_bar.positions.bottom') }, + ]; + public setConfig(config: RawFrigateCardConfig): void { // Note: This does not use Zod to parse the full configuration, so it may be // partially or completely invalid. It's more useful to have a partially @@ -1230,11 +1232,29 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ); } - /** - * Render an editor menu for the card menu buttons. - * @param button The name of the button. - * @returns A rendered template. - */ + protected _renderStatusBarItem(item: string): TemplateResult { + return html` ${this._putInSubmenu( + MENU_STATUS_BAR_ITEMS, + item, + `config.status_bar.items.${item}`, + { name: 'mdi:feature-search' }, + html` + ${this._renderSwitch( + `${CONF_STATUS_BAR_ITEMS}.${item}.enabled`, + this._defaults.status_bar.items[item]?.enabled ?? true, + { + label: localize('config.status_bar.items.enabled'), + }, + )} + ${this._renderNumberInput(`${CONF_STATUS_BAR_ITEMS}.${item}.priority`, { + max: FRIGATE_STATUS_BAR_PRIORITY_MAX, + default: this._defaults.status_bar.items[item]?.priority, + label: localize('config.status_bar.items.priority'), + })} + `, + )}`; + } + protected _renderMenuButton( button: string, additionalOptions?: TemplateResult, @@ -1244,56 +1264,38 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor { value: 'matching', label: localize('config.menu.buttons.alignments.matching') }, { value: 'opposing', label: localize('config.menu.buttons.alignments.opposing') }, ]; - const submenuClasses = { - submenu: true, - selected: this._expandedMenus[MENU_BUTTONS] === button, - }; - return html` -
      - - - ${this._expandedMenus[MENU_BUTTONS] === button - ? html`
      - ${this._renderSwitch( - `${CONF_MENU_BUTTONS}.${button}.enabled`, - this._defaults.menu.buttons[button]?.enabled ?? true, - { - label: localize('config.menu.buttons.enabled'), - }, - )} - ${this._renderOptionSelector( - `${CONF_MENU_BUTTONS}.${button}.alignment`, - menuButtonAlignments, - { - label: localize('config.menu.buttons.alignment'), - }, - )} - ${this._renderNumberInput(`${CONF_MENU_BUTTONS}.${button}.priority`, { - max: FRIGATE_MENU_PRIORITY_MAX, - default: this._defaults.menu.buttons[button]?.priority, - label: localize('config.menu.buttons.priority'), - })} - ${this._renderIconSelector(`${CONF_MENU_BUTTONS}.${button}.icon`, { - label: localize('config.menu.buttons.icon'), - })} - ${additionalOptions} -
      ` - : ''} -
      - `; + return html` ${this._putInSubmenu( + MENU_MENU_BUTTONS, + button, + `config.menu.buttons.${button}`, + { name: 'mdi:gesture-tap-button' }, + html` + ${this._renderSwitch( + `${CONF_MENU_BUTTONS}.${button}.enabled`, + this._defaults.menu.buttons[button]?.enabled ?? true, + { + label: localize('config.menu.buttons.enabled'), + }, + )} + ${this._renderOptionSelector( + `${CONF_MENU_BUTTONS}.${button}.alignment`, + menuButtonAlignments, + { + label: localize('config.menu.buttons.alignment'), + }, + )} + ${this._renderNumberInput(`${CONF_MENU_BUTTONS}.${button}.priority`, { + max: FRIGATE_MENU_PRIORITY_MAX, + default: this._defaults.menu.buttons[button]?.priority, + label: localize('config.menu.buttons.priority'), + })} + ${this._renderIconSelector(`${CONF_MENU_BUTTONS}.${button}.icon`, { + label: localize('config.menu.buttons.icon'), + })} + ${additionalOptions} + `, + )}`; } /** @@ -1730,34 +1732,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ); } - /** - * Render the titles controls. - * @param domain The submenu domain. - * @param configPathMode Title mode config path. - * @param configPathDurationSeconds Title duration seconds config path. - * @returns A rendered template. - */ - protected _renderTitleControls( - menuDomain: string, - configPathMode: string, - configPathDurationSeconds: string, - ): TemplateResult | void { - return this._putInSubmenu( - menuDomain, - true, - 'config.common.controls.title.editor_label', - { name: 'mdi:subtitles' }, - html` ${this._renderOptionSelector(configPathMode, this._titleModes, { - label: localize('config.common.controls.title.mode'), - })} - ${this._renderNumberInput(configPathDurationSeconds, { - min: 0, - max: 60, - label: localize('config.common.controls.title.duration_seconds'), - })}`, - ); - } - /** * Render a camera section. * @param cameras The full array of cameras. @@ -2427,6 +2401,35 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
      ` : ''} + ${this._renderOptionSetHeader('status_bar')} + ${this._expandedMenus[MENU_OPTIONS] === 'status_bar' + ? html` +
      + ${this._renderOptionSelector( + CONF_STATUS_BAR_STYLE, + this._statusBarStyles, + )} + ${this._renderOptionSelector( + CONF_STATUS_BAR_POSITION, + this._statusBarPositions, + )} + ${this._renderNumberInput(CONF_STATUS_BAR_HEIGHT, { + min: STATUS_BAR_HEIGHT_MIN, + label: localize('config.status_bar.height'), + })} + ${this._renderNumberInput(CONF_STATUS_BAR_POPUP_SECONDS, { + min: 0, + max: 60, + default: this._defaults.status_bar.popup_seconds, + label: localize('config.status_bar.popup_seconds'), + })} + ${this._renderStatusBarItem('title') /* */} + ${this._renderStatusBarItem('resolution') /* */} + ${this._renderStatusBarItem('technology') /* */} + ${this._renderStatusBarItem('engine') /* */} +
      + ` + : ''} ${this._renderOptionSetHeader('live')} ${this._expandedMenus[MENU_OPTIONS] === 'live' ? html` @@ -2521,11 +2524,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor configPathMode: CONF_LIVE_CONTROLS_THUMBNAILS_MODE, }, )} - ${this._renderTitleControls( - MENU_LIVE_CONTROLS_TITLE, - CONF_LIVE_CONTROLS_TITLE_MODE, - CONF_LIVE_CONTROLS_TITLE_DURATION_SECONDS, - )} ${this._renderMiniTimeline( MENU_LIVE_CONTROLS_TIMELINE, CONF_LIVE_CONTROLS_TIMELINE_MODE, @@ -2708,11 +2706,6 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor configPathMode: CONF_MEDIA_VIEWER_CONTROLS_THUMBNAILS_MODE, }, )} - ${this._renderTitleControls( - MENU_MEDIA_VIEWER_CONTROLS_TITLE, - CONF_MEDIA_VIEWER_CONTROLS_TITLE_MODE, - CONF_MEDIA_VIEWER_CONTROLS_TITLE_DURATION_SECONDS, - )} ${this._renderMiniTimeline( MENU_MEDIA_VIEWER_CONTROLS_TIMELINE, CONF_MEDIA_VIEWER_CONTROLS_TIMELINE_MODE, diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json index 9492db6f..cd51cdcb 100644 --- a/src/localize/languages/ca.json +++ b/src/localize/languages/ca.json @@ -210,18 +210,6 @@ "seek-in-camera": "Cerca d'escombratge només a la càmera seleccionada", "seek-in-media": "Cerca d'escombratge només dins de l'element multimèdia seleccionat" } - }, - "title": { - "duration_seconds": "Segons per mostrar el títol emergent (0=per sempre)", - "editor_label": "Controls del títol emergent", - "mode": "Mode de visualització del títol emergent", - "modes": { - "none": "No es mostra el títol", - "popup-bottom-left": "Popup a la part inferior esquerra", - "popup-bottom-right": "Popup a la part inferior dreta", - "popup-top-left": "Popup a la part superior esquerra", - "popup-top-right": "Popup a la part superior dreta" - } } }, "display": { @@ -427,6 +415,33 @@ "low-performance": "", "scrubbing": "" }, + "status_bar": { + "height": "", + "items": { + "enabled": "", + "engine": "", + "live_provider": "", + "priority": "", + "resolution": "", + "technology": "", + "title": "" + }, + "popup_seconds": "", + "position": "", + "positions": { + "bottom": "", + "top": "" + }, + "style": "", + "styles": { + "hover": "", + "hover-card": "", + "none": "", + "outside": "", + "overlay": "", + "popup": "" + } + }, "view": { "camera_select": "Visualitza les càmeres seleccionades recentment", "dark_mode": "Mode fosc", @@ -533,6 +548,8 @@ "performance_secondary": "Opcions de rendiment de la targeta", "profiles": "", "profiles_secondary": "", + "status_bar": "", + "status_bar_secondary": "", "timeline": "Cronologia", "timeline_secondary": "Opcions de la cronologia d'esdeveniments", "upgrade": "Upgrade", diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index 31904859..d4f6b6bc 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -210,18 +210,6 @@ "seek-in-camera": "Pan seeks within selected camera only", "seek-in-media": "Pan seeks within selected media item only" } - }, - "title": { - "duration_seconds": "Seconds to display popup title (0=forever)", - "editor_label": "Popup Title Controls", - "mode": "Popup title display mode", - "modes": { - "none": "No title display", - "popup-bottom-left": "Popup on the bottom left", - "popup-bottom-right": "Popup on the bottom right", - "popup-top-left": "Popup on the top left", - "popup-top-right": "Popup on the top right" - } } }, "display": { @@ -427,6 +415,33 @@ "low-performance": "Low performance", "scrubbing": "Video scrubbing" }, + "status_bar": { + "height": "Status bar height in pixels", + "items": { + "enabled": "Item enabled", + "engine": "Camera engine", + "live_provider": "Live provider", + "priority": "Item priority", + "resolution": "Resolution", + "technology": "Technology", + "title": "Title" + }, + "popup_seconds": "Status bar popup seconds", + "position": "Status bar position", + "positions": { + "bottom": "Positioned on the bottom", + "top": "Positioned on the top" + }, + "style": "Status bar style", + "styles": { + "hover": "Hover status bar", + "hover-card": "Hover status bar (card-wide)", + "none": "No status bar", + "outside": "Outside status bar", + "overlay": "Overlay status bar", + "popup": "Popup status bar" + } + }, "view": { "camera_select": "View for newly selected cameras", "dark_mode": "Dark mode", @@ -533,6 +548,8 @@ "performance_secondary": "Card performance options", "profiles": "Configuration profiles", "profiles_secondary": "Choose pre-configured sets of defaults", + "status_bar": "Status bar", + "status_bar_secondary": "Status bar look & feel options", "timeline": "Timeline", "timeline_secondary": "Event timeline options", "upgrade": "Upgrade", diff --git a/src/localize/languages/fr.json b/src/localize/languages/fr.json index 43acdfe4..f7193c85 100644 --- a/src/localize/languages/fr.json +++ b/src/localize/languages/fr.json @@ -210,18 +210,6 @@ "seek-in-camera": "", "seek-in-media": "" } - }, - "title": { - "duration_seconds": "Secondes pour afficher le titre de la fenêtre contextuelle (0 = toujours)", - "editor_label": "Contrôles de titre contextuel", - "mode": "Mode d'affichage du titre contextuel", - "modes": { - "none": "Pas d'affichage du titre", - "popup-bottom-left": "Popup en bas à gauche", - "popup-bottom-right": "Popup en bas à droite", - "popup-top-left": "Popup en haut à gauche", - "popup-top-right": "Popup en haut à droite" - } } }, "display": { @@ -427,6 +415,33 @@ "low-performance": "", "scrubbing": "" }, + "status_bar": { + "height": "", + "items": { + "enabled": "", + "engine": "", + "live_provider": "", + "priority": "", + "resolution": "", + "technology": "", + "title": "" + }, + "popup_seconds": "", + "position": "", + "positions": { + "bottom": "", + "top": "" + }, + "style": "", + "styles": { + "hover": "", + "hover-card": "", + "none": "", + "outside": "", + "overlay": "", + "popup": "" + } + }, "view": { "camera_select": "Afficher les caméras nouvellement sélectionnées", "dark_mode": "Mode sombre", @@ -533,6 +548,8 @@ "performance_secondary": "Options de performances de la carte", "profiles": "", "profiles_secondary": "", + "status_bar": "", + "status_bar_secondary": "", "timeline": "Chronologie", "timeline_secondary": "Options de chronologie des événements", "upgrade": "Mise à niveau", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 70527221..c9eae16f 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -210,18 +210,6 @@ "seek-in-camera": "", "seek-in-media": "" } - }, - "title": { - "duration_seconds": "Secondi per visualizzare il titolo popup (0 = per sempre)", - "editor_label": "Controlli titolo popup", - "mode": "Modalità di visualizzazione del titolo", - "modes": { - "none": "Nessuna visualizzazione del titolo", - "popup-bottom-left": "Popup in basso a sinistra", - "popup-bottom-right": "Popup in basso a destra", - "popup-top-left": "Popup in alto a sinistra", - "popup-top-right": "Popup in alto a destra" - } } }, "display": { @@ -427,6 +415,33 @@ "low-performance": "", "scrubbing": "" }, + "status_bar": { + "height": "", + "items": { + "enabled": "", + "engine": "", + "live_provider": "", + "priority": "", + "resolution": "", + "technology": "", + "title": "" + }, + "popup_seconds": "", + "position": "", + "positions": { + "bottom": "", + "top": "" + }, + "style": "", + "styles": { + "hover": "", + "hover-card": "", + "none": "", + "outside": "", + "overlay": "", + "popup": "" + } + }, "view": { "camera_select": "Visualizza per le telecamere appena selezionate", "dark_mode": "Tema scuro", @@ -533,6 +548,8 @@ "performance_secondary": "", "profiles": "", "profiles_secondary": "", + "status_bar": "", + "status_bar_secondary": "", "timeline": "Timeline", "timeline_secondary": "Opzioni della timeline degli eventi", "upgrade": "Aggiornamento", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 865334e1..137fba4f 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -210,18 +210,6 @@ "seek-in-camera": "", "seek-in-media": "" } - }, - "title": { - "duration_seconds": "Segundos para exibir o pop-up (0 = para sempre)", - "editor_label": "Controles do pop-up de título", - "mode": "Modo de exibição de título de mídia", - "modes": { - "none": "Sem exibição de título", - "popup-bottom-left": "Pop-up no canto inferior esquerdo", - "popup-bottom-right": "Pop-up no canto inferior direito", - "popup-top-left": "Pop-up no canto superior esquerdo", - "popup-top-right": "Pop-up no canto superior direito" - } } }, "display": { @@ -427,6 +415,33 @@ "low-performance": "", "scrubbing": "" }, + "status_bar": { + "height": "", + "items": { + "enabled": "", + "engine": "", + "live_provider": "", + "priority": "", + "resolution": "", + "technology": "", + "title": "" + }, + "popup_seconds": "", + "position": "", + "positions": { + "bottom": "", + "top": "" + }, + "style": "", + "styles": { + "hover": "", + "hover-card": "", + "none": "", + "outside": "", + "overlay": "", + "popup": "" + } + }, "view": { "camera_select": "Visualização de câmeras recém-selecionadas", "dark_mode": "Modo escuro", @@ -533,6 +548,8 @@ "performance_secondary": "Opções de desempenho do cartão", "profiles": "", "profiles_secondary": "", + "status_bar": "", + "status_bar_secondary": "", "timeline": "Linha do tempo", "timeline_secondary": "Opções do evento da linha do tempo", "upgrade": "Upgrade", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 119c7ada..9771e9f9 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -210,18 +210,6 @@ "seek-in-camera": "", "seek-in-media": "" } - }, - "title": { - "duration_seconds": "Segundos para exibir o pop-up (0 = para sempre)", - "editor_label": "Editor de titulos", - "mode": "Modo de exibição de título de mídia", - "modes": { - "none": "Sem exibição de título", - "popup-bottom-left": "Pop-up no canto inferior esquerdo", - "popup-bottom-right": "Pop-up no canto inferior direito", - "popup-top-left": "Pop-up no canto superior esquerdo", - "popup-top-right": "Pop-up no canto superior direito" - } } }, "display": { @@ -427,6 +415,33 @@ "low-performance": "", "scrubbing": "" }, + "status_bar": { + "height": "", + "items": { + "enabled": "", + "engine": "", + "live_provider": "", + "priority": "", + "resolution": "", + "technology": "", + "title": "" + }, + "popup_seconds": "", + "position": "", + "positions": { + "bottom": "", + "top": "" + }, + "style": "", + "styles": { + "hover": "", + "hover-card": "", + "none": "", + "outside": "", + "overlay": "", + "popup": "" + } + }, "view": { "camera_select": "Visualização de câmeras recém-selecionadas", "dark_mode": "Modo escuro", @@ -533,6 +548,8 @@ "performance_secondary": "", "profiles": "", "profiles_secondary": "", + "status_bar": "", + "status_bar_secondary": "", "timeline": "Linha do tempo", "timeline_secondary": "Opções do evento da linha do tempo", "upgrade": "Actualização", diff --git a/src/patches/ha-camera-stream.ts b/src/patches/ha-camera-stream.ts index 5381aec2..3c5f4a91 100644 --- a/src/patches/ha-camera-stream.ts +++ b/src/patches/ha-camera-stream.ts @@ -98,7 +98,10 @@ customElements.whenDefined('ha-camera-stream').then(() => { return html` { - dispatchMediaLoadedEvent(this, ev, { player: this }); + dispatchMediaLoadedEvent(this, ev, { + player: this, + technology: ['mjpeg'], + }); }} .src=${typeof this._connected == 'undefined' || this._connected ? computeMJPEGStreamUrl(this.stateObj) diff --git a/src/patches/ha-hls-player.ts b/src/patches/ha-hls-player.ts index 50bb7080..a7aae1db 100644 --- a/src/patches/ha-hls-player.ts +++ b/src/patches/ha-hls-player.ts @@ -125,6 +125,7 @@ customElements.whenDefined('ha-hls-player').then(() => { supportsPause: true, hasAudio: mayHaveAudio(this._video), }, + technology: ['hls'], }); }} @volumechange=${() => dispatchMediaVolumeChangeEvent(this)} diff --git a/src/patches/ha-web-rtc-player.ts b/src/patches/ha-web-rtc-player.ts index de30478b..5929167b 100644 --- a/src/patches/ha-web-rtc-player.ts +++ b/src/patches/ha-web-rtc-player.ts @@ -120,6 +120,7 @@ customElements.whenDefined('ha-web-rtc-player').then(() => { supportsPause: true, hasAudio: mayHaveAudio(this._video), }, + technology: ['webrtc'], }); }} @volumechange=${() => dispatchMediaVolumeChangeEvent(this)} diff --git a/src/scss/card.scss b/src/scss/card.scss index 04286562..a26f203a 100644 --- a/src/scss/card.scss +++ b/src/scss/card.scss @@ -80,23 +80,6 @@ div.main.curve-bottom { border-bottom-right-radius: var(--ha-card-border-radius, 4px); } -/* The 'hover' menu mode is styled applied outside of the menu itself */ -frigate-card-menu[data-style*='hover'] { - z-index: 1; - transition: opacity 0.5s ease; -} - -.main + frigate-card-menu[data-style*='hover'] { - opacity: 0; -} -frigate-card-menu[data-style='hover']:hover { - opacity: 1; -} -.main:hover + frigate-card-menu[data-style='hover-card'], -frigate-card-menu[data-style='hover-card']:hover { - opacity: 1; -} - ha-card { display: flex; flex-direction: column; @@ -181,3 +164,52 @@ web-dialog::part(dialog) { border-radius: 0px; background: transparent; } + +/************************************* + * "Outside" style for menu/status bar + *************************************/ + +.outerlay[data-position='top'] { + border-top-left-radius: var(--ha-card-border-radius, 4px); + border-top-right-radius: var(--ha-card-border-radius, 4px); +} + +.outerlay[data-position='bottom'] { + border-bottom-left-radius: var(--ha-card-border-radius, 4px); + border-bottom-right-radius: var(--ha-card-border-radius, 4px); +} + +/**************** + * Overlay styles + ****************/ +frigate-card-overlay { + z-index: 1; +} + +/******************* + * Menu hover styles + *******************/ + +frigate-card-menu[data-style*='hover'] { + z-index: 4; + transition: opacity 0.5s ease; + opacity: 0; +} +frigate-card-menu[data-style*='hover']:hover, +.main:hover > frigate-card-overlay > frigate-card-menu[data-style='hover-card'] { + opacity: 1; +} + +/************************* + * Status bar hover styles + *************************/ + +frigate-card-status-bar[data-style*='hover'] { + z-index: 3; + transition: opacity 0.5s ease; + opacity: 0; +} +frigate-card-status-bar[data-style*='hover']:hover, +.main:hover > frigate-card-overlay > frigate-card-status-bar[data-style='hover-card'] { + opacity: 1; +} diff --git a/src/scss/menu.scss b/src/scss/menu.scss index 9f56c136..60975dd0 100644 --- a/src/scss/menu.scss +++ b/src/scss/menu.scss @@ -5,9 +5,7 @@ --mdc-icon-button-size: var(--frigate-card-menu-button-size); --mdc-icon-size: calc(var(--mdc-icon-button-size) / 2); - // Menu itself does not handle click events. Without this, in overlay mode the - // menu component prevents clicking on gallery items 'behind' the overlay. - pointer-events: none; + pointer-events: auto; display: flex; flex-direction: row; @@ -45,52 +43,6 @@ div.opposing { background: var(--secondary-background-color); } -/************************************ - * Match menu rounded corners to card - ************************************/ - -:host([data-position='top']), -:host([data-position='left']) { - border-top-left-radius: var(--ha-card-border-radius, 4px); -} -:host([data-position='top']), -:host([data-position='right']) { - border-top-right-radius: var(--ha-card-border-radius, 4px); -} -:host([data-position='bottom']), -:host([data-position='left']) { - border-bottom-left-radius: var(--ha-card-border-radius, 4px); -} -:host([data-position='bottom']), -:host([data-position='right']) { - border-bottom-right-radius: var(--ha-card-border-radius, 4px); -} - -/************************************** - * Positioning for absolute menu styles - **************************************/ - -:host(:not([data-style='outside'])[data-position='top']), -:host(:not([data-style='outside'])[data-position='left'][data-alignment='top']), -:host(:not([data-style='outside'])[data-position='right'][data-alignment='top']) { - top: 0px; -} -:host(:not([data-style='outside'])[data-position='bottom']), -:host(:not([data-style='outside'])[data-position='left'][data-alignment='bottom']), -:host(:not([data-style='outside'])[data-position='right'][data-alignment='bottom']) { - bottom: 0px; -} -:host(:not([data-style='outside'])[data-position='left']), -:host(:not([data-style='outside'])[data-position='top'][data-alignment='left']), -:host(:not([data-style='outside'])[data-position='bottom'][data-alignment='left']) { - left: 0px; -} -:host(:not([data-style='outside'])[data-position='right']), -:host(:not([data-style='outside'])[data-position='top'][data-alignment='right']), -:host(:not([data-style='outside'])[data-position='bottom'][data-alignment='right']) { - right: 0px; -} - /******************************************************** * Hack: Ensure host & div expand for column flex layouts ********************************************************/ @@ -156,12 +108,18 @@ div.opposing { :host([data-style='overlay']), :host([data-style*='hover']), :host([data-style='hidden']) { - position: absolute; overflow: hidden; width: calc(var(--frigate-card-menu-button-size) + 6px); height: calc(var(--frigate-card-menu-button-size) + 6px); } +:host([data-style='overlay']), +:host([data-style*='hover']), +:host([data-style='hidden'][expanded]) { + overflow: visible; + background: linear-gradient(90deg, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0)); +} + :host([data-style='overlay'][data-position='top']), :host([data-style='overlay'][data-position='bottom']), :host([data-style*='hover'][data-position='top']), @@ -170,8 +128,6 @@ div.opposing { :host([data-style='hidden'][data-position='bottom'][expanded]) { width: 100%; height: auto; - overflow: visible; - background: linear-gradient(90deg, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0)); } :host([data-style='overlay'][data-position='left']), @@ -180,8 +136,6 @@ div.opposing { :host([data-style*='hover'][data-position='right']), :host([data-style='hidden'][data-position='left'][expanded]), :host([data-style='hidden'][data-position='right'][expanded]) { - height: 100%; width: auto; - overflow: visible; - background: linear-gradient(180deg, rgba(0, 0, 0, 0.3), rgba(0, 0, 0, 0)); + height: 100%; } diff --git a/src/scss/overlay.scss b/src/scss/overlay.scss new file mode 100644 index 00000000..ba952ab1 --- /dev/null +++ b/src/scss/overlay.scss @@ -0,0 +1,66 @@ +@use './button.scss'; + +:host { + position: absolute; + width: 100%; + height: 100%; + + // Overlay itself does not handle click events. + pointer-events: none; +} + +slot { + position: absolute; + display: block; +} + +/*************** + * Slot position + ***************/ + +slot[name='top'] { + top: 0px; +} +slot[name='bottom'] { + bottom: 0px; +} +slot[name='left'] { + left: 0px; +} +slot[name='right'] { + right: 0px; +} + +/*********** + * Slot size + ***********/ + +slot[name='top'], +slot[name='bottom'] { + width: 100%; +} +slot[name='left'], +slot[name='right'] { + height: 100%; +} + +/******************************* + * Match rounded corners to card + *******************************/ + +slot[name='top'], +slot[name='left'] { + border-top-left-radius: var(--ha-card-border-radius, 4px); +} +slot[name='top'], +slot[name='right'] { + border-top-right-radius: var(--ha-card-border-radius, 4px); +} +slot[name='bottom'], +slot[name='left'] { + border-bottom-left-radius: var(--ha-card-border-radius, 4px); +} +slot[name='bottom'], +slot[name='right'] { + border-bottom-right-radius: var(--ha-card-border-radius, 4px); +} diff --git a/src/scss/status.scss b/src/scss/status.scss new file mode 100644 index 00000000..31161fcc --- /dev/null +++ b/src/scss/status.scss @@ -0,0 +1,82 @@ +@use './button.scss'; + +:host { + --mdc-icon-button-size: calc(var(--frigate-card-status-bar-height) - 6px); + --mdc-icon-size: calc(var(--mdc-icon-button-size) / 2); + + display: block; + width: 100%; + + pointer-events: auto; + + opacity: 1; + transition: opacity 1s; +} + +/*************** + * Outside style + ***************/ + +:host([data-style='outside']) { + color: var(--primary-text-color); + background: var(--secondary-background-color); +} + +/******************* + * Non-outside style + *******************/ + +:host(:not([data-style='outside'])) { + color: white; + background: linear-gradient(90deg, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0)); +} +:host([data-style='popup'][hide]) { + opacity: 0; + pointer-events: none; +} + +/********************* + * Status bar contents + *********************/ + +.status { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + + overflow: hidden; + + width: 100%; + height: var(--frigate-card-status-bar-height); +} + +.item { + display: inline-block; + + margin: 3px; + padding: 3px; + + align-content: center; + + opacity: 0.7; +} +.item:first-child { + margin-left: 10px; +} +.item:last-child { + margin-right: 10px; +} + +.item.expand { + flex: 1; +} + +.item.action { + cursor: pointer; +} + +img.item { + width: var(--mdc-icon-size, 24px); + height: var(--mdc-icon-size, 24px); +} diff --git a/src/scss/title-control.scss b/src/scss/title-control.scss deleted file mode 100644 index cf1e798c..00000000 --- a/src/scss/title-control.scss +++ /dev/null @@ -1,29 +0,0 @@ -:host { - --paper-toast-background-color: rgba(0, 0, 0, 0.6); - --paper-toast-color: white; - - pointer-events: none; - position: relative; -} - -paper-toast { - max-width: unset; - min-width: unset; - display: flex; - align-items: center; - - // Without this the paper-toast will consume vertical space before being - // opened, which causes the card to render blank space needlessly. It also - // won't work with 'display: none', it appears to need something with - // width/height properties even before being opened. - position: absolute; -} - -paper-toast.paper-toast-open { - position: relative; -} - -paper-toast img { - max-height: 24px; - padding-left: 10px; -} diff --git a/src/types.ts b/src/types.ts index a512154e..fac43e60 100644 --- a/src/types.ts +++ b/src/types.ts @@ -31,9 +31,13 @@ export interface MediaLoadedCapabilities { hasAudio?: boolean; } +const MEDIA_TECHNOLOGY = ['hls', 'jpg', 'jsmpeg', 'mjpeg', 'mp4', 'mse', 'webrtc']; +export type MediaTechnology = (typeof MEDIA_TECHNOLOGY)[number]; + export interface MediaLoadedInfo { width: number; height: number; + technology?: MediaTechnology[]; player?: FrigateCardMediaPlayer; capabilities?: MediaLoadedCapabilities; } diff --git a/src/utils/media-info.ts b/src/utils/media-info.ts index bdda5e69..41af8cfa 100644 --- a/src/utils/media-info.ts +++ b/src/utils/media-info.ts @@ -2,6 +2,7 @@ import { FrigateCardMediaPlayer, MediaLoadedCapabilities, MediaLoadedInfo, + MediaTechnology, } from '../types.js'; import { dispatchFrigateCardEvent } from './basic.js'; @@ -18,6 +19,7 @@ export function createMediaLoadedInfo( options?: { player?: FrigateCardMediaPlayer; capabilities?: MediaLoadedCapabilities; + technology?: MediaTechnology[]; }, ): MediaLoadedInfo | null { let target: HTMLElement | EventTarget; @@ -61,6 +63,7 @@ export function dispatchMediaLoadedEvent( options?: { player?: FrigateCardMediaPlayer; capabilities?: MediaLoadedCapabilities; + technology?: MediaTechnology[]; }, ): void { const mediaLoadedInfo = createMediaLoadedInfo(source, options); diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts index de95a742..71451bde 100644 --- a/tests/camera-manager/manager.test.ts +++ b/tests/camera-manager/manager.test.ts @@ -11,7 +11,6 @@ import { QueryClassifier, QueryResultClassifier, } from '../../src/camera-manager/manager'; -import { CameraManagerStore } from '../../src/camera-manager/store'; import { CameraEndpoint, CameraEndpoints, diff --git a/tests/card-controller/actions/actions/status-bar.test.ts b/tests/card-controller/actions/actions/status-bar.test.ts new file mode 100644 index 00000000..d4ec5c8c --- /dev/null +++ b/tests/card-controller/actions/actions/status-bar.test.ts @@ -0,0 +1,67 @@ +import { describe, expect, it } from 'vitest'; +import { StatusBarAction } from '../../../../src/card-controller/actions/actions/status-bar'; +import { createCardAPI } from '../../../test-utils'; + +describe('should handle status bar action', () => { + it('reset', async () => { + const api = createCardAPI(); + const action = new StatusBarAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'status_bar', + status_bar_action: 'reset', + }, + ); + + await action.execute(api); + + expect(api.getStatusBarItemManager().removeAllDynamicStatusBarItems).toBeCalled(); + }); + + it('add', async () => { + const api = createCardAPI(); + const item = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item', + }; + + const action = new StatusBarAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'status_bar', + status_bar_action: 'add', + items: [item], + }, + ); + + await action.execute(api); + + expect(api.getStatusBarItemManager().addDynamicStatusBarItem).toBeCalledWith(item); + }); + + it('remove', async () => { + const api = createCardAPI(); + const item = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item', + }; + + const action = new StatusBarAction( + {}, + { + action: 'fire-dom-event', + frigate_card_action: 'status_bar', + status_bar_action: 'remove', + items: [item], + }, + ); + + await action.execute(api); + + expect(api.getStatusBarItemManager().removeDynamicStatusBarItem).toBeCalledWith( + item, + ); + }); +}); diff --git a/tests/card-controller/actions/factory.test.ts b/tests/card-controller/actions/factory.test.ts index 84bb954d..7352cd05 100644 --- a/tests/card-controller/actions/factory.test.ts +++ b/tests/card-controller/actions/factory.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { CameraSelectAction } from '../../../src/card-controller/actions/actions/camera-select'; import { CameraUIAction } from '../../../src/card-controller/actions/actions/camera-ui'; import { DefaultAction } from '../../../src/card-controller/actions/actions/default'; @@ -21,6 +21,7 @@ import { PTZDigitalAction } from '../../../src/card-controller/actions/actions/p import { PTZMultiAction } from '../../../src/card-controller/actions/actions/ptz-multi'; import { ScreenshotAction } from '../../../src/card-controller/actions/actions/screenshot'; import { SleepAction } from '../../../src/card-controller/actions/actions/sleep'; +import { StatusBarAction } from '../../../src/card-controller/actions/actions/status-bar'; import { SubstreamOffAction } from '../../../src/card-controller/actions/actions/substream-off'; import { SubstreamOnAction } from '../../../src/card-controller/actions/actions/substream-on'; import { SubstreamSelectAction } from '../../../src/card-controller/actions/actions/substream-select'; @@ -125,6 +126,10 @@ describe('ActionFactory', () => { [{ frigate_card_action: 'snapshots' as const }, ViewAction], [{ frigate_card_action: 'timeline' as const }, ViewAction], [{ frigate_card_action: 'unmute' as const }, UnmuteAction], + [ + { frigate_card_action: 'status_bar' as const, status_bar_action: 'reset' }, + StatusBarAction, + ], ])( 'frigate_card_action: $frigate_card_action', (action: Partial, classObject: object) => { diff --git a/tests/card-controller/conditions-manager.test.ts b/tests/card-controller/conditions-manager.test.ts index e0327403..1a527259 100644 --- a/tests/card-controller/conditions-manager.test.ts +++ b/tests/card-controller/conditions-manager.test.ts @@ -306,28 +306,6 @@ describe('getOverriddenConfig', () => { }), ).toEqual({}); }); - - // it('with empty value and object', () => { - // const manager = new ConditionsManager(createCardAPI()); - // manager.setState({ fullscreen: true }); - - // expect( - // getOverriddenConfig(manager, config, { - // configOverrides: [ - // { - // delete: [''], - // conditions: [ - // { - // condition: 'fullscreen' as const, - // fullscreen: true, - // }, - // ], - // }, - // ], - // emptyKeyReplaces: true, - // }), - // ).toEqual({}); - // }); }); describe('should validate schema', () => { @@ -538,6 +516,11 @@ describe('ConditionsManager', () => { state: 'on', }, ], + actions: [ + { + action: 'fire-dom-event', + }, + ], }, ], }); diff --git a/tests/card-controller/controller.test.ts b/tests/card-controller/controller.test.ts index 6148cb7e..ff5f0018 100644 --- a/tests/card-controller/controller.test.ts +++ b/tests/card-controller/controller.test.ts @@ -29,6 +29,7 @@ import { ViewManager } from '../../src/card-controller/view/view-manager'; import { FrigateCardEditor } from '../../src/editor'; import { EntityRegistryManager } from '../../src/utils/ha/entity-registry'; import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media'; +import { StatusBarItemManager } from '../../src/card-controller/status-bar-item-manager'; vi.mock('../../src/camera-manager/manager'); vi.mock('../../src/card-controller/actions/actions-manager'); @@ -50,6 +51,7 @@ vi.mock('../../src/card-controller/media-player-manager'); vi.mock('../../src/card-controller/message-manager'); vi.mock('../../src/card-controller/microphone-manager'); vi.mock('../../src/card-controller/query-string-manager'); +vi.mock('../../src/card-controller/status-bar-item-manager'); vi.mock('../../src/card-controller/style-manager'); vi.mock('../../src/card-controller/triggers-manager'); vi.mock('../../src/card-controller/view/view-manager'); @@ -247,6 +249,12 @@ describe('CardController', () => { ); }); + it('getStatusBarItemManager', () => { + expect(createController().getStatusBarItemManager()).toBe( + vi.mocked(StatusBarItemManager).mock.instances[0], + ); + }); + it('getStyleManager', () => { expect(createController().getStyleManager()).toBe( vi.mocked(StyleManager).mock.instances[0], diff --git a/tests/card-controller/status-bar-item-manager.test.ts b/tests/card-controller/status-bar-item-manager.test.ts new file mode 100644 index 00000000..3dc3538f --- /dev/null +++ b/tests/card-controller/status-bar-item-manager.test.ts @@ -0,0 +1,243 @@ +import { describe, expect, it, vi } from 'vitest'; +import { StatusBarItemManager } from '../../src/card-controller/status-bar-item-manager'; +import { StatusBarString } from '../../src/config/types'; +import { MediaQueriesResults } from '../../src/view/media-queries-results'; +import { + TestViewMedia, + createCameraManager, + createCardAPI, + createStore, + createView, +} from '../test-utils'; + +describe('StatusBarItemManager', () => { + const testItem: StatusBarString = { + type: 'custom:frigate-card-status-bar-string' as const, + string: 'test', + }; + + it('should add', () => { + const manager = new StatusBarItemManager(createCardAPI()); + manager.addDynamicStatusBarItem(testItem); + manager.addDynamicStatusBarItem(testItem); + + expect(manager.calculateItems()).toContain(testItem); + expect(manager.calculateItems().find((item) => item === testItem).length === 1); + }); + + it('should remove', () => { + const manager = new StatusBarItemManager(createCardAPI()); + manager.addDynamicStatusBarItem(testItem); + + manager.removeDynamicStatusBarItem({ ...testItem }); + expect(manager.calculateItems()).not.toContain(testItem); + + manager.removeDynamicStatusBarItem({ ...testItem, string: 'not-present' }); + expect(manager.calculateItems()).not.toContain({ + ...testItem, + string: 'not-present', + }); + }); + + it('should remove all', () => { + const manager = new StatusBarItemManager(createCardAPI()); + manager.addDynamicStatusBarItem(testItem); + manager.removeAllDynamicStatusBarItems(); + expect(manager.calculateItems()).not.toContain(testItem); + }); + + describe('should have standard status bar items', () => { + describe('should have title', () => { + describe('live', () => { + it('with metadata', () => { + const manager = new StatusBarItemManager(createCardAPI()); + const store = createStore([ + { + cameraID: 'camera-1', + }, + ]); + const cameraManager = createCameraManager(store); + vi.mocked(cameraManager.getCameraMetadata).mockReturnValue({ + title: 'Camera Title', + icon: 'mdi:camera', + }); + + expect( + manager.calculateItems({ + cameraManager: cameraManager, + view: createView({ view: 'live', camera: 'camera-1' }), + }), + ).toContainEqual({ + type: 'custom:frigate-card-status-bar-string' as const, + string: 'Camera Title', + expand: true, + sufficient: true, + }); + }); + + it('without metadata', () => { + const manager = new StatusBarItemManager(createCardAPI()); + const cameraManager = createCameraManager(); + expect( + manager.calculateItems({ + cameraManager: cameraManager, + view: createView({ view: 'live', camera: 'MISSING-CAMERA' }), + }), + ).not.toContainEqual(expect.objectContaining({ sufficient: true })); + }); + }); + + describe('media', () => { + it('with a title', () => { + const manager = new StatusBarItemManager(createCardAPI()); + const cameraManager = createCameraManager(); + + const media = [new TestViewMedia({ title: 'Media Title' })]; + const queryResults = new MediaQueriesResults({ + results: media, + }); + + const view = createView({ + view: 'media', + queryResults: queryResults, + }); + + expect( + manager.calculateItems({ + cameraManager: cameraManager, + view: view, + }), + ).toContainEqual({ + type: 'custom:frigate-card-status-bar-string' as const, + string: 'Media Title', + expand: true, + sufficient: true, + }); + }); + + it('without a title', () => { + const manager = new StatusBarItemManager(createCardAPI()); + const cameraManager = createCameraManager(); + + const media = [new TestViewMedia()]; + const queryResults = new MediaQueriesResults({ + results: media, + }); + + const view = createView({ + view: 'media', + queryResults: queryResults, + }); + + expect( + manager.calculateItems({ + cameraManager: cameraManager, + view: view, + }), + ).not.toContainEqual(expect.objectContaining({ sufficient: true })); + }); + }); + }); + + describe('should have resolution', () => { + it.each([ + ['1080p landscape', '1080p', 1920, 1080], + ['1080p portrait', '1080p', 1080, 1920], + ['1080p approximate', '1080p', 1922, 1082], + + ['720p landscape', '720p', 1280, 720], + ['720p portrait', '720p', 720, 1280], + ['720p approximate', '720p', 1282, 722], + + ['VGA landscape', 'VGA', 640, 480], + ['VGA portrait', 'VGA', 480, 640], + ['VGA approximate', 'VGA', 642, 482], + + ['4K landscape', '4K', 3840, 2160], + ['4K portrait', '4K', 2160, 3840], + ['4K approximate', '4K', 3842, 2162], + + ['480p landscape', '480p', 720, 480], + ['480p portrait', '480p', 480, 720], + ['480p approximate', '480p', 722, 482], + + ['576p landscape', '576p', 720, 576], + ['576p portrait', '576p', 576, 720], + ['576p approximate', '576p', 722, 578], + + ['8K landscape', '8K', 7680, 4320], + ['8K portrait', '8K', 4320, 7680], + ['8K approximate', '8K', 7682, 4322], + + ['random', '123x456', 123, 456], + ])( + '%s', + (_testName: string, expectedName: string, width: number, height: number) => { + const manager = new StatusBarItemManager(createCardAPI()); + + expect( + manager.calculateItems({ + mediaLoadedInfo: { width, height }, + }), + ).toContainEqual({ + type: 'custom:frigate-card-status-bar-string' as const, + string: expectedName, + }); + }, + ); + }); + + describe('should have technology', () => { + it('webrtc', () => { + const manager = new StatusBarItemManager(createCardAPI()); + + expect( + manager.calculateItems({ + mediaLoadedInfo: { width: 640, height: 480, technology: ['webrtc'] }, + }), + ).toContainEqual({ + type: 'custom:frigate-card-status-bar-icon' as const, + icon: 'mdi:webrtc', + }); + }); + + it('non-webrtc', () => { + const manager = new StatusBarItemManager(createCardAPI()); + + expect( + manager.calculateItems({ + mediaLoadedInfo: { width: 640, height: 480, technology: ['hls'] }, + }), + ).toContainEqual({ + type: 'custom:frigate-card-status-bar-string' as const, + string: 'HLS', + }); + }); + }); + + it('should have engine', () => { + const manager = new StatusBarItemManager(createCardAPI()); + const store = createStore([ + { + cameraID: 'camera-1', + }, + ]); + const cameraManager = createCameraManager(store); + vi.mocked(cameraManager.getCameraMetadata).mockReturnValue({ + title: 'Camera Title', + icon: 'mdi:camera', + engineLogo: 'IMAGE_LOGO', + }); + + expect( + manager.calculateItems({ + cameraManager: cameraManager, + view: createView({ view: 'live', camera: 'camera-1' }), + }), + ).toContainEqual({ + type: 'custom:frigate-card-status-bar-image' as const, + image: 'IMAGE_LOGO', + }); + }); + }); +}); diff --git a/tests/components-lib/live/utils/get-technology-for-video-rts.test.ts b/tests/components-lib/live/utils/get-technology-for-video-rts.test.ts new file mode 100644 index 00000000..d2219841 --- /dev/null +++ b/tests/components-lib/live/utils/get-technology-for-video-rts.test.ts @@ -0,0 +1,24 @@ +import { describe, expect, it } from 'vitest'; +import { getTechnologyForVideoRTC } from '../../../../src/components-lib/live/utils/get-technology-for-video-rtc'; +import { VideoRTC } from '../../../../src/components/live/go2rtc/video-rtc'; +import { createLitElement } from '../../../test-utils'; + +// @vitest-environment jsdom +describe('getTechnologyForVideoRTC', () => { + it('webrtc', () => { + const element = createLitElement() as unknown as VideoRTC; + element.pc = {} as unknown as RTCPeerConnection; + expect(getTechnologyForVideoRTC(element)).toEqual(['webrtc']); + }); + + it('mse', () => { + const element = createLitElement() as unknown as VideoRTC; + element.mseCodecs = 'mp4a'; + expect(getTechnologyForVideoRTC(element)).toEqual(['mse', 'hls']); + }); + + it('other', () => { + const element = createLitElement() as unknown as VideoRTC; + expect(getTechnologyForVideoRTC(element)).toBeUndefined(); + }); +}); diff --git a/tests/components-lib/menu-controller.test.ts b/tests/components-lib/menu-controller.test.ts index 58d26cde..99aee2b0 100644 --- a/tests/components-lib/menu-controller.test.ts +++ b/tests/components-lib/menu-controller.test.ts @@ -1,11 +1,11 @@ -import { HASSDomEvent, handleActionConfig } from '@dermotduffy/custom-card-helpers'; +import { handleActionConfig } from '@dermotduffy/custom-card-helpers'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { FRIGATE_ICON_SVG_PATH } from '../../src/camera-manager/frigate/icon'; import { MenuController } from '../../src/components-lib/menu-controller'; -import { ActionsConfig, MenuConfig, menuConfigSchema } from '../../src/config/types'; +import { MenuConfig, menuConfigSchema } from '../../src/config/types'; import { StateParameters } from '../../src/types'; import { refreshDynamicStateParameters } from '../../src/utils/ha'; -import { createHASS, createLitElement } from '../test-utils'; +import { createInteractionEvent, createHASS, createLitElement } from '../test-utils'; vi.mock('@dermotduffy/custom-card-helpers'); vi.mock('../../src/utils/ha'); @@ -14,18 +14,6 @@ const createMenuConfig = (config: unknown): MenuConfig => { return menuConfigSchema.parse(config); }; -const createEvent = ( - action: string, - config?: ActionsConfig, -): HASSDomEvent<{ action: string; config?: ActionsConfig }> => { - return new CustomEvent<{ action: string; config?: ActionsConfig }>('@action', { - detail: { - action: action, - config: config, - }, - }); -}; - // @vitest-environment jsdom describe('MenuController', () => { const action = { @@ -362,7 +350,7 @@ describe('MenuController', () => { describe('should handle actions', () => { it('should bail without config', () => { const controller = new MenuController(createLitElement()); - controller.actionHandler(createEvent('tap')); + controller.actionHandler(createInteractionEvent('tap')); expect(vi.mocked(handleActionConfig)).not.toBeCalled(); }); @@ -373,7 +361,7 @@ describe('MenuController', () => { const controller = new MenuController(host); - controller.actionHandler(createEvent('tap'), tapActionConfig); + controller.actionHandler(createInteractionEvent('tap'), tapActionConfig); expect(handler).toBeCalledWith( expect.objectContaining({ detail: { action: [action], config: tapActionConfig }, @@ -389,7 +377,7 @@ describe('MenuController', () => { const controller = new MenuController(host); - controller.actionHandler(createEvent('tap', tapActionConfig)); + controller.actionHandler(createInteractionEvent('tap', tapActionConfig)); expect(handler).toBeCalledWith( expect.objectContaining({ detail: { action: [action], config: tapActionConfig }, @@ -404,7 +392,7 @@ describe('MenuController', () => { const controller = new MenuController(host); - controller.actionHandler(createEvent('tap'), tapActionConfigMulti); + controller.actionHandler(createInteractionEvent('tap'), tapActionConfigMulti); expect(handler).toBeCalledWith( expect.objectContaining({ @@ -426,7 +414,7 @@ describe('MenuController', () => { controller.setExpanded(true); expect(controller.isExpanded()).toBeTruthy(); - controller.actionHandler(createEvent('tap'), tapActionConfig); + controller.actionHandler(createInteractionEvent('tap'), tapActionConfig); expect(controller.isExpanded()).toBeFalsy(); }); @@ -442,7 +430,7 @@ describe('MenuController', () => { controller.setExpanded(true); expect(controller.isExpanded()).toBeTruthy(); - controller.actionHandler(createEvent('end_tap'), { + controller.actionHandler(createInteractionEvent('end_tap'), { end_tap_action: action, }); expect(controller.isExpanded()).toBeFalsy(); @@ -462,7 +450,7 @@ describe('MenuController', () => { controller.setExpanded(true); expect(controller.isExpanded()).toBeTruthy(); - controller.actionHandler(createEvent('start_tap'), { + controller.actionHandler(createInteractionEvent('start_tap'), { start_tap_action: action, end_tap_action: action, }); @@ -481,7 +469,7 @@ describe('MenuController', () => { controller.setExpanded(false); expect(controller.isExpanded()).toBeFalsy(); - controller.actionHandler(createEvent('tap'), { + controller.actionHandler(createInteractionEvent('tap'), { camera_entity: 'foo', tap_action: menuToggleAction, }); @@ -490,7 +478,6 @@ describe('MenuController', () => { it('when no action is actually taken', () => { const host = createLitElement(); - const hass = createHASS(); const controller = new MenuController(host); controller.setMenuConfig( createMenuConfig({ @@ -501,7 +488,7 @@ describe('MenuController', () => { controller.setExpanded(true); expect(controller.isExpanded()).toBeTruthy(); - controller.actionHandler(createEvent('end_tap'), tapActionConfig); + controller.actionHandler(createInteractionEvent('end_tap'), tapActionConfig); expect(controller.isExpanded()).toBeTruthy(); }); }); diff --git a/tests/components-lib/status-bar-controller.test.ts b/tests/components-lib/status-bar-controller.test.ts new file mode 100644 index 00000000..9b33f85b --- /dev/null +++ b/tests/components-lib/status-bar-controller.test.ts @@ -0,0 +1,330 @@ +import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; +import { StatusBarController } from '../../src/components-lib/status-bar-controller'; +import { StatusBarConfig, statusBarConfigSchema } from '../../src/config/types'; +import { setOrRemoveAttribute } from '../../src/utils/basic'; +import { createInteractionEvent, createLitElement } from '../test-utils'; + +const createConfig = (config?: unknown): StatusBarConfig => { + return statusBarConfigSchema.parse(config); +}; + +// @vitest-environment jsdom +describe('StatusBarController', () => { + describe('should set config', () => { + it('should set config', () => { + const host = createLitElement(); + const controller = new StatusBarController(host); + + controller.setConfig( + createConfig({ + position: 'top', + style: 'hover', + height: 50, + }), + ); + expect(host.style.getPropertyValue('--frigate-card-status-bar-height')).toBe( + '50px', + ); + expect(host.getAttribute('data-style')).toBe('hover'); + expect(host.getAttribute('data-position')).toBe('top'); + expect(host.requestUpdate).toHaveBeenCalled(); + }); + + it('should not hide when not in popup style', () => { + const host = createLitElement(); + setOrRemoveAttribute(host, true, 'hide'); + + const controller = new StatusBarController(host); + + controller.setConfig( + createConfig({ + position: 'top', + style: 'hover', + height: 50, + }), + ); + + expect(host.getAttribute('hide')).toBe(null); + }); + + it('should not show when in popup style', () => { + const host = createLitElement(); + setOrRemoveAttribute(host, true, 'hide'); + + const controller = new StatusBarController(host); + + controller.setConfig( + createConfig({ + position: 'top', + style: 'popup', + height: 50, + }), + ); + + expect(host.getAttribute('hide')).not.toBe(null); + }); + }); + + describe('should set items', () => { + beforeAll(() => { + vi.useFakeTimers(); + }); + + afterAll(() => { + vi.useRealTimers(); + }); + + it('set/get basic items', () => { + const host = createLitElement(); + const controller = new StatusBarController(host); + const items = [ + { + type: 'custom:frigate-card-status-bar-string', + string: 'Test', + }, + ]; + + controller.setItems(items); + expect(controller.getRenderItems()).toEqual(items); + }); + + it('should order items', () => { + const host = createLitElement(); + const controller = new StatusBarController(host); + const item1 = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 1', + priority: 40, + }; + const item2 = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 2', + priority: 10, + }; + const item3 = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 3', + priority: 60, + }; + const item4 = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 4', + priority: undefined, + }; + + controller.setItems([item1, item2, item3, item4]); + expect(controller.getRenderItems()).toEqual([item3, item4, item1, item2]); + }); + + it('should treat exclusive items exclusively', () => { + const host = createLitElement(); + const controller = new StatusBarController(host); + const item1 = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 1', + priority: 100, + }; + const exclusiveItem = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 2', + priority: 1, + exclusive: true, + }; + + controller.setItems([item1, exclusiveItem]); + expect(controller.getRenderItems()).toEqual([exclusiveItem]); + }); + + describe('should recognize sufficient items', () => { + it('with sufficient item', () => { + const host = createLitElement(); + const controller = new StatusBarController(host); + const insufficientItem = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 1', + sufficient: false, + }; + const sufficientItem = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 2', + sufficient: true, + }; + + controller.setItems([insufficientItem, sufficientItem]); + expect(controller.getRenderItems()).toEqual([insufficientItem, sufficientItem]); + expect(controller.shouldRender()).toBeTruthy(); + }); + + it('without sufficient item', () => { + const host = createLitElement(); + const controller = new StatusBarController(host); + const insufficientItem = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 1', + sufficient: false, + }; + const sufficientItem = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 2', + sufficient: false, + }; + + controller.setItems([insufficientItem, sufficientItem]); + expect(controller.getRenderItems()).toEqual([insufficientItem, sufficientItem]); + expect(controller.shouldRender()).toBeFalsy(); + }); + }); + + describe('should deal with popup styles correctly', () => { + it('should show from empty to sufficient', () => { + const host = createLitElement(); + setOrRemoveAttribute(host, true, 'hide'); + + const controller = new StatusBarController(host); + controller.setConfig( + createConfig({ + style: 'popup', + }), + ); + + const sufficientItem = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 1', + priority: 100, + sufficient: true, + }; + + controller.setItems([sufficientItem]); + expect(host.getAttribute('hide')).toBe(null); + }); + + it('should not show from empty to insufficient', () => { + const host = createLitElement(); + setOrRemoveAttribute(host, true, 'hide'); + + const controller = new StatusBarController(host); + controller.setConfig( + createConfig({ + style: 'popup', + }), + ); + + const insufficientItem = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 1', + priority: 100, + sufficient: false, + }; + + controller.setItems([insufficientItem]); + expect(host.getAttribute('hide')).not.toBeNull(); + }); + + it('should show from sufficient to different sufficient', () => { + const host = createLitElement(); + + const controller = new StatusBarController(host); + controller.setConfig( + createConfig({ + style: 'popup', + }), + ); + + const sufficientString = { + type: 'custom:frigate-card-status-bar-string', + string: 'String', + priority: 100, + sufficient: true, + }; + const sufficientIcon = { + type: 'custom:frigate-card-status-bar-icon', + icon: 'Icon', + priority: 100, + sufficient: true, + }; + const sufficientImage = { + type: 'custom:frigate-card-status-bar-image', + image: 'Image', + priority: 100, + sufficient: true, + }; + + controller.setItems([sufficientString]); + + // Emulate the popup being hidden. + setOrRemoveAttribute(host, true, 'hide'); + controller.setItems([sufficientIcon]); + + expect(host.getAttribute('hide')).toBe(null); + + // Emulate the popup being hidden. + setOrRemoveAttribute(host, true, 'hide'); + controller.setItems([sufficientImage]); + + expect(host.getAttribute('hide')).toBe(null); + }); + + it('should hide popup after expiry', () => { + const host = createLitElement(); + + const controller = new StatusBarController(host); + controller.setConfig( + createConfig({ + style: 'popup', + }), + ); + + const sufficientItem = { + type: 'custom:frigate-card-status-bar-string', + string: 'Item 1', + priority: 100, + sufficient: true, + }; + + controller.setItems([sufficientItem]); + expect(host.getAttribute('hide')).toBe(null); + + vi.advanceTimersByTime(1000); + expect(host.getAttribute('hide')).toBe(null); + + vi.advanceTimersByTime(2000); + expect(host.getAttribute('hide')).not.toBe(null); + }); + }); + }); + + describe('should handle actions', () => { + it('should bail without action', () => { + const host = createLitElement(); + const handler = vi.fn(); + host.addEventListener('frigate-card:action:execution-request', handler); + + const controller = new StatusBarController(host); + controller.actionHandler(createInteractionEvent('tap')); + expect(handler).not.toBeCalled(); + }); + + it('should request action execution', () => { + const host = createLitElement(); + const handler = vi.fn(); + host.addEventListener('frigate-card:action:execution-request', handler); + + const controller = new StatusBarController(host); + + const action = { + action: 'fire-dom-event' as const, + }; + const tapActionConfig = { + tap_action: action, + }; + + controller.actionHandler(createInteractionEvent('tap'), tapActionConfig); + + expect(handler).toBeCalledWith( + expect.objectContaining({ + detail: { action: [action], config: tapActionConfig }, + }), + ); + }); + }); +}); diff --git a/tests/config/management.test.ts b/tests/config/management.test.ts index 1ba51ed9..be8da942 100644 --- a/tests/config/management.test.ts +++ b/tests/config/management.test.ts @@ -25,7 +25,6 @@ import { frigateCardConfigSchema, } from '../../src/config/types'; import { getParseErrorPaths } from '../../src/utils/zod'; -import { update } from 'lodash-es'; describe('general functions', () => { it('should set value', () => { @@ -3193,5 +3192,116 @@ describe('should handle version specific upgrades', () => { }); postUpgradeChecks(config); }); + + describe('title controls to status bar', () => { + it('when mode is none', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + live: { + controls: { + title: { + mode: 'none', + }, + }, + }, + media_viewer: { + controls: { + title: { + mode: 'none', + }, + }, + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], + live: { controls: {} }, + media_viewer: { controls: {} }, + status_bar: { + style: 'none', + }, + }); + + postUpgradeChecks(config); + }); + + describe('when mode is invalid type', () => { + it.each([[{ mode: { should_not_be: 'an object' } }], ['sideways']])( + '%s', + (mode: unknown) => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + live: { + controls: { + title: { + mode, + }, + }, + }, + media_viewer: { + controls: { + title: { + mode, + }, + }, + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], + live: { controls: {} }, + media_viewer: { controls: {} }, + }); + + postUpgradeChecks(config); + }, + ); + }); + + describe.each([['bottom'], ['top']])('on the %s', (position: string) => { + it.each([ + [`popup-${position}-left` as const], + [`popup-${position}-right` as const], + ])('%s', (mode: string) => { + const config = { + type: 'custom:frigate-card', + cameras: [{}], + live: { + controls: { + title: { + mode, + }, + }, + }, + media_viewer: { + controls: { + title: { + mode, + }, + }, + }, + }; + + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{}], + live: { controls: {} }, + media_viewer: { controls: {} }, + status_bar: { + position, + }, + }); + + postUpgradeChecks(config); + }); + }); + }); }); }); diff --git a/tests/config/profiles/low-performance.test.ts b/tests/config/profiles/low-performance.test.ts index 30832789..61c7f709 100644 --- a/tests/config/profiles/low-performance.test.ts +++ b/tests/config/profiles/low-performance.test.ts @@ -13,7 +13,6 @@ it('low performance profile', () => { 'live.controls.thumbnails.show_favorite_control': false, 'live.controls.thumbnails.show_timeline_control': false, 'live.controls.timeline.show_recordings': false, - 'live.controls.title.mode': 'none', 'live.draggable': false, 'live.lazy_unload': 'all', 'live.show_image_during_load': false, @@ -32,7 +31,6 @@ it('low performance profile', () => { 'media_viewer.controls.thumbnails.show_favorite_control': false, 'media_viewer.controls.thumbnails.show_timeline_control': false, 'media_viewer.controls.timeline.show_recordings': false, - 'media_viewer.controls.title.mode': 'none', 'media_viewer.draggable': false, 'media_viewer.snapshot_click_plays_clip': false, 'media_viewer.transition_effect': 'none', @@ -44,6 +42,7 @@ it('low performance profile', () => { 'performance.features.media_chunk_size': 10, 'performance.style.border_radius': false, 'performance.style.box_shadow': false, + 'status_bar.style': 'none', 'timeline.controls.thumbnails.mode': 'none', 'timeline.controls.thumbnails.show_details': false, 'timeline.controls.thumbnails.show_download_control': false, diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index 5b926078..cd313042 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -5,6 +5,7 @@ import { customSchema, dimensionsConfigSchema, frigateCardCustomActionsBaseSchema, + frigateCardCustomActionSchema, } from '../../src/config/types'; import { createConfig } from '../test-utils'; @@ -273,6 +274,30 @@ describe('config defaults', () => { box_shadow: true, }, }, + status_bar: { + height: 46, + items: { + engine: { + enabled: true, + priority: 50, + }, + resolution: { + enabled: true, + priority: 50, + }, + technology: { + enabled: true, + priority: 50, + }, + title: { + enabled: true, + priority: 50, + }, + }, + popup_seconds: 3, + position: 'bottom', + style: 'popup', + }, timeline: { clustering_threshold: 3, controls: { @@ -507,7 +532,7 @@ describe('should convert webrtc card PTZ to Frigate card PTZ', () => { }); }); -describe('should lazy evaluate', () => { +describe('should lazy evaluate schemas', () => { it('conditional picture element', () => { expect( conditionalSchema.parse({ @@ -555,6 +580,21 @@ describe('should lazy evaluate', () => { type: 'conditional', }); }); + + it('status bar actions', () => { + const input = { + action: 'fire-dom-event', + frigate_card_action: 'status_bar', + status_bar_action: 'reset', + items: [ + { + type: 'custom:frigate-card-status-bar-string', + string: 'Item', + }, + ], + }; + expect(frigateCardCustomActionSchema.parse(input)).toEqual(input); + }); }); describe('should handle custom frigate elements', () => { @@ -621,3 +661,41 @@ it('media viewer should not support microphone based conditions', () => { }), ).toThrowError(); }); + +describe('automations should require at least one action', () => { + it('no action', () => { + expect(() => + createConfig({ + cameras: [{}], + automations: [{ conditions: [] }], + }), + ).toThrowError(/Automations must include at least one action/); + }); + + it('empty actions', () => { + expect(() => + createConfig({ + cameras: [{}], + automations: [{ conditions: [], actions: [], actions_not: [] }], + }), + ).toThrowError(/Automations must include at least one action/); + }); + + it('at least one action', () => { + expect(() => + createConfig({ + cameras: [{}], + automations: [ + { + conditions: [], + actions: [ + { + action: 'fire-dom-event', + }, + ], + }, + ], + }), + ).not.toThrowError(); + }); +}); diff --git a/tests/test-utils.ts b/tests/test-utils.ts index e066e719..e5d017aa 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -1,4 +1,8 @@ -import { CurrentUser, HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { + CurrentUser, + HASSDomEvent, + HomeAssistant, +} from '@dermotduffy/custom-card-helpers'; import { HassEntities, HassEntity } from 'home-assistant-js-websocket'; import { LitElement } from 'lit'; import { expect, vi } from 'vitest'; @@ -15,28 +19,31 @@ import { CameraManagerMediaCapabilities, } from '../src/camera-manager/types'; import { ActionsManager } from '../src/card-controller/actions/actions-manager'; -import { DefaultManager } from '../src/card-controller/default-manager'; import { AutomationsManager } from '../src/card-controller/automations-manager'; import { CameraURLManager } from '../src/card-controller/camera-url-manager'; import { CardElementManager } from '../src/card-controller/card-element-manager'; import { ConditionsManager } from '../src/card-controller/conditions-manager'; import { ConfigManager } from '../src/card-controller/config/config-manager'; import { CardController } from '../src/card-controller/controller'; +import { DefaultManager } from '../src/card-controller/default-manager'; import { DownloadManager } from '../src/card-controller/download-manager'; import { ExpandManager } from '../src/card-controller/expand-manager'; import { FullscreenManager } from '../src/card-controller/fullscreen-manager'; import { HASSManager } from '../src/card-controller/hass-manager'; import { InitializationManager } from '../src/card-controller/initialization-manager'; import { InteractionManager } from '../src/card-controller/interaction-manager'; +import { KeyboardStateManager } from '../src/card-controller/keyboard-state-manager'; import { MediaLoadedInfoManager } from '../src/card-controller/media-info-manager'; import { MediaPlayerManager } from '../src/card-controller/media-player-manager'; import { MessageManager } from '../src/card-controller/message-manager'; import { MicrophoneManager } from '../src/card-controller/microphone-manager'; import { QueryStringManager } from '../src/card-controller/query-string-manager'; +import { StatusBarItemManager } from '../src/card-controller/status-bar-item-manager'; import { StyleManager } from '../src/card-controller/style-manager'; import { TriggersManager } from '../src/card-controller/triggers-manager'; import { ViewManager } from '../src/card-controller/view/view-manager'; import { + ActionsConfig, CameraConfig, FrigateCardCondition, FrigateCardConfig, @@ -55,7 +62,6 @@ import { Entity } from '../src/utils/ha/entity-registry/types'; import { ViewMedia, ViewMediaType } from '../src/view/media'; import { MediaQueriesResults } from '../src/view/media-queries-results'; import { View, ViewParameters } from '../src/view/view'; -import { KeyboardStateManager } from '../src/card-controller/keyboard-state-manager'; export const createAction = ( action: Record, @@ -450,6 +456,7 @@ export const createCardAPI = (): CardController => { api.getMessageManager.mockReturnValue(mock()); api.getMicrophoneManager.mockReturnValue(mock()); api.getQueryStringManager.mockReturnValue(mock()); + api.getStatusBarItemManager.mockReturnValue(mock()); api.getStyleManager.mockReturnValue(mock()); api.getTriggersManager.mockReturnValue(mock()); api.getViewManager.mockReturnValue(mock()); @@ -473,3 +480,15 @@ export const callHASubscribeMessageHandler = ( export const flushPromises = async (): Promise => { await new Promise(process.nextTick); }; + +export const createInteractionEvent = ( + action: string, + config?: ActionsConfig, +): HASSDomEvent<{ action: string; config?: ActionsConfig }> => { + return new CustomEvent<{ action: string; config?: ActionsConfig }>('@action', { + detail: { + action: action, + config: config, + }, + }); +}; diff --git a/tsconfig.json b/tsconfig.json index 9218fb69..879e97ef 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -33,8 +33,7 @@ "ha-selector", "ha-svg-icon", "mwc-button", - "mwc-list-item", - "paper-toast" + "mwc-list-item" ], "rules": { "no-unknown-tag-name": "error", diff --git a/vite.config.ts b/vite.config.ts index 0808f0ab..0369ec03 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -14,10 +14,11 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'card-controller/**/*.ts', 'components-lib/cached-value-controller.ts', 'components-lib/key-assigner-controller.ts', - 'components-lib/live/live-controller.ts', + 'components-lib/live/**/*.ts', 'components-lib/media-filter-controller.ts', 'components-lib/menu-button-controller.ts', 'components-lib/menu-controller.ts', + 'components-lib/status-bar-controller.ts', 'components-lib/ptz/*.ts', 'components-lib/zoom/*.ts', 'config/**/*.ts', @@ -74,6 +75,8 @@ export default defineConfig({ test: { include: ['tests/**/*.test.ts'], coverage: { + exclude: ['docs/**', 'tests/**', '.eslintrc.cjs'], + // Favor istanbul for coverage over v8 due to better accuracy. provider: 'istanbul', thresholds: { From 869c2f9049b98652a8ba7c80be1ebd1130426f97 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 17 Aug 2024 11:40:33 -0700 Subject: [PATCH 162/189] Minor pointer fixes. --- src/card.ts | 25 +++++++++++++++---------- src/components/viewer.ts | 9 +++------ src/scss/status.scss | 9 ++++++++- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/card.ts b/src/card.ts index 39e1db9d..699c1699 100644 --- a/src/card.ts +++ b/src/card.ts @@ -211,9 +211,12 @@ class FrigateCard extends LitElement { // If there's nothing to render... (menuStyle === 'none' && statusBarStyle === 'none') || // ... or the position I'm rendering does not contain the menu/status bar + (position === 'overlay' && + menuStyle === 'outside' && + statusBarStyle === 'outside') || (position !== 'overlay' && - menuPosition !== position && - statusBarPosition !== position) + (menuStyle !== 'outside' || menuPosition !== position) && + (statusBarStyle !== 'outside' || statusBarPosition !== position)) ) { // ... then there's nothing to do. return; @@ -230,16 +233,18 @@ class FrigateCard extends LitElement { ((statusBarStyle === 'outside' && kind === 'outerlay') || (statusBarStyle !== 'outside' && kind === 'overlay')); - // As an exception, to improve the visual flow, if the menu is being - // rendered on the bottom, render the status bar first. + + // Complex logic to try to always put the menu in the right-looking place. + const renderMenuFirst = + menuPosition === 'left' || + menuPosition === 'right' || + (menuPosition === 'bottom' && menuStyle === 'hidden' && statusBarStyle !== 'popup') || + (menuPosition === 'top' && (menuStyle !== 'hidden' || statusBarStyle === 'popup')); + return html` - ${shouldRenderMenu && menuPosition !== 'bottom' - ? this._renderMenu(menuPosition) - : ''} + ${shouldRenderMenu && renderMenuFirst ? this._renderMenu(menuPosition) : ''} ${shouldRenderStatusBar ? this._renderStatusBar(statusBarPosition) : ''} - ${shouldRenderMenu && menuPosition === 'bottom' - ? this._renderMenu(menuPosition) - : ''} + ${shouldRenderMenu && !renderMenuFirst ? this._renderMenu(menuPosition) : ''} `; }; diff --git a/src/components/viewer.ts b/src/components/viewer.ts index a18c2ead..5ed93cc5 100644 --- a/src/components/viewer.ts +++ b/src/components/viewer.ts @@ -505,7 +505,7 @@ export class FrigateCardViewerCarousel extends LitElement { return html`
      { + protected async _switchToRelatedClipView(): Promise { const view = this.viewManagerEpoch?.manager.getView(); if ( !this.hass || @@ -912,7 +909,7 @@ export class FrigateCardViewerProvider title="${this.media.getTitle() ?? ''}" @click=${() => { if (this.viewerConfig?.snapshot_click_plays_clip) { - this._dispatchRelatedClipView(); + this._switchToRelatedClipView(); } }} @load=${(ev: Event) => { diff --git a/src/scss/status.scss b/src/scss/status.scss index 31161fcc..ad740e96 100644 --- a/src/scss/status.scss +++ b/src/scss/status.scss @@ -13,6 +13,14 @@ transition: opacity 1s; } +/******************************************************* + * Non-hover styles should not interact with the pointer + *******************************************************/ + +:host(:not([data-style*='hover'])) { + pointer-events: none; +} + /*************** * Outside style ***************/ @@ -32,7 +40,6 @@ } :host([data-style='popup'][hide]) { opacity: 0; - pointer-events: none; } /********************* From dc3ff6260363c61c7c879633288b538cbbf2e1f1 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 17 Aug 2024 11:48:41 -0700 Subject: [PATCH 163/189] Formatting fixes. --- src/card.ts | 8 +++++--- src/components/status-bar.ts | 9 ++++++++- src/scss/status.scss | 2 +- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/card.ts b/src/card.ts index 699c1699..756f75a5 100644 --- a/src/card.ts +++ b/src/card.ts @@ -233,13 +233,15 @@ class FrigateCard extends LitElement { ((statusBarStyle === 'outside' && kind === 'outerlay') || (statusBarStyle !== 'outside' && kind === 'overlay')); - // Complex logic to try to always put the menu in the right-looking place. const renderMenuFirst = menuPosition === 'left' || menuPosition === 'right' || - (menuPosition === 'bottom' && menuStyle === 'hidden' && statusBarStyle !== 'popup') || - (menuPosition === 'top' && (menuStyle !== 'hidden' || statusBarStyle === 'popup')); + (menuPosition === 'bottom' && + menuStyle === 'hidden' && + statusBarStyle !== 'popup') || + (menuPosition === 'top' && + (menuStyle !== 'hidden' || statusBarStyle === 'popup')); return html` ${shouldRenderMenu && renderMenuFirst ? this._renderMenu(menuPosition) : ''} diff --git a/src/components/status-bar.ts b/src/components/status-bar.ts index a54abfe6..7cfcc988 100644 --- a/src/components/status-bar.ts +++ b/src/components/status-bar.ts @@ -1,4 +1,11 @@ -import { CSSResultGroup, LitElement, PropertyValues, TemplateResult, html, unsafeCSS } from 'lit'; +import { + CSSResultGroup, + LitElement, + PropertyValues, + TemplateResult, + html, + unsafeCSS, +} from 'lit'; import { customElement, property } from 'lit/decorators.js'; import { classMap } from 'lit/directives/class-map.js'; import { actionHandler } from '../action-handler-directive.js'; diff --git a/src/scss/status.scss b/src/scss/status.scss index ad740e96..d68e5de4 100644 --- a/src/scss/status.scss +++ b/src/scss/status.scss @@ -16,7 +16,7 @@ /******************************************************* * Non-hover styles should not interact with the pointer *******************************************************/ - + :host(:not([data-style*='hover'])) { pointer-events: none; } From 429dd9097232565924d07af3e1eecbba31ca8924 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 24 Aug 2024 20:00:00 -0700 Subject: [PATCH 164/189] Use custom websocket to avoid needing admin privileges. --- src/camera-manager/browse-media/camera.ts | 12 +- .../browse-media/engine-browse-media.ts | 16 +- src/camera-manager/camera.ts | 71 +-- src/camera-manager/engine-factory.ts | 36 +- src/camera-manager/engine.ts | 11 +- src/camera-manager/frigate/camera.ts | 99 ++-- src/camera-manager/frigate/engine-frigate.ts | 28 +- src/camera-manager/frigate/event-watcher.ts | 76 +++ src/camera-manager/frigate/types.ts | 25 +- src/camera-manager/generic/engine-generic.ts | 18 +- src/camera-manager/manager.ts | 24 +- src/card-controller/card-element-manager.ts | 16 +- src/card-controller/controller.ts | 2 +- src/card-controller/default-manager.ts | 29 +- .../{ => hass}/hass-manager.ts | 28 +- src/card-controller/hass/state-watcher.ts | 51 ++ src/card-controller/message-manager.ts | 9 +- src/card-controller/style-manager.ts | 4 +- src/card-controller/types.ts | 5 +- src/config/ptz.ts | 4 +- src/localize/languages/ca.json | 1 + src/localize/languages/en.json | 1 + src/localize/languages/fr.json | 1 + src/localize/languages/it.json | 1 + src/localize/languages/pt-BR.json | 1 + src/localize/languages/pt-PT.json | 1 + src/types.ts | 2 +- src/utils/basic.ts | 9 +- src/utils/ha/index.ts | 66 +-- src/utils/ha/types.ts | 21 - .../browse-media/camera.test.ts | 16 +- tests/camera-manager/camera.test.ts | 124 ++--- tests/camera-manager/engine-factory.test.ts | 31 +- tests/camera-manager/frigate/camera.test.ts | 485 ++++++++++-------- .../frigate/event-watcher.test.ts | 201 ++++++++ .../generic/engine-generic.test.ts | 10 +- tests/camera-manager/manager.test.ts | 14 +- tests/camera-manager/store.test.ts | 16 +- .../card-element-manager.test.ts | 71 ++- tests/card-controller/controller.test.ts | 6 +- tests/card-controller/default-manager.test.ts | 102 ++-- .../{ => hass}/hass-manager.test.ts | 73 +-- .../hass/state-watcher.test.ts | 101 ++++ tests/card-controller/message-manager.test.ts | 16 + tests/test-utils.ts | 26 +- tests/utils/basic.test.ts | 27 +- tests/utils/ha/index.test.ts | 106 +--- 47 files changed, 1219 insertions(+), 874 deletions(-) create mode 100644 src/camera-manager/frigate/event-watcher.ts rename src/card-controller/{ => hass}/hass-manager.ts (64%) create mode 100644 src/card-controller/hass/state-watcher.ts delete mode 100644 src/utils/ha/types.ts create mode 100644 tests/camera-manager/frigate/event-watcher.test.ts rename tests/card-controller/{ => hass}/hass-manager.test.ts (74%) create mode 100644 tests/card-controller/hass/state-watcher.test.ts diff --git a/src/camera-manager/browse-media/camera.ts b/src/camera-manager/browse-media/camera.ts index 030707d4..031ef5c2 100644 --- a/src/camera-manager/browse-media/camera.ts +++ b/src/camera-manager/browse-media/camera.ts @@ -2,19 +2,23 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import { localize } from '../../localize/localize'; import { EntityRegistryManager } from '../../utils/ha/entity-registry'; import { Entity } from '../../utils/ha/entity-registry/types'; -import { Camera } from '../camera'; +import { Camera, CameraInitializationOptions } from '../camera'; import { CameraInitializationError } from '../error'; +interface BrowseMediaCameraInitializationOptions extends CameraInitializationOptions { + entityRegistryManager: EntityRegistryManager; + hass: HomeAssistant; +} + export class BrowseMediaCamera extends Camera { protected _entity: Entity | null = null; public async initialize( - hass: HomeAssistant, - entityRegistryManager: EntityRegistryManager, + options: BrowseMediaCameraInitializationOptions, ): Promise { const config = this.getConfig(); const entity = config.camera_entity - ? await entityRegistryManager.getEntity(hass, config.camera_entity) + ? await options.entityRegistryManager.getEntity(options.hass, config.camera_entity) : null; if (!entity || !config.camera_entity) { diff --git a/src/camera-manager/browse-media/engine-browse-media.ts b/src/camera-manager/browse-media/engine-browse-media.ts index 1463d8f9..997cf9d3 100644 --- a/src/camera-manager/browse-media/engine-browse-media.ts +++ b/src/camera-manager/browse-media/engine-browse-media.ts @@ -1,4 +1,5 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { StateWatcherSubscriptionInterface } from '../../card-controller/hass/state-watcher'; import { CameraConfig } from '../../config/types'; import { ExtendedHomeAssistant } from '../../types'; import { canonicalizeHAURL } from '../../utils/ha'; @@ -28,10 +29,10 @@ import { PartialEventQuery, QueryType, } from '../types'; +import { getPTZCapabilitiesFromCameraConfig } from '../utils/ptz'; import { BrowseMediaCamera } from './camera'; import { BrowseMediaViewMediaFactory } from './media'; import { BrowseMediaMetadata } from './types'; -import { getPTZCapabilitiesFromCameraConfig } from '../utils/ptz'; /** * A utility method to determine if a browse media object matches against a @@ -123,16 +124,20 @@ export class BrowseMediaCameraManagerEngine implements CameraManagerEngine { protected _browseMediaManager: BrowseMediaManager; + protected _entityRegistryManager: EntityRegistryManager; protected _resolvedMediaCache: ResolvedMediaCache; protected _requestCache: RequestCache; public constructor( + entityRegistryManager: EntityRegistryManager, + stateWatcher: StateWatcherSubscriptionInterface, browseMediaManager: BrowseMediaManager, resolvedMediaCache: ResolvedMediaCache, requestCache: RequestCache, eventCallback?: CameraEventCallback, ) { - super(eventCallback); + super(stateWatcher, eventCallback); + this._entityRegistryManager = entityRegistryManager; this._browseMediaManager = browseMediaManager; this._resolvedMediaCache = resolvedMediaCache; this._requestCache = requestCache; @@ -140,7 +145,6 @@ export class BrowseMediaCameraManagerEngine public async createCamera( hass: HomeAssistant, - entityRegistryManager: EntityRegistryManager, cameraConfig: CameraConfig, ): Promise { const camera = new BrowseMediaCamera(cameraConfig, this, { @@ -164,7 +168,11 @@ export class BrowseMediaCameraManagerEngine ), eventCallback: this._eventCallback, }); - return await camera.initialize(hass, entityRegistryManager); + return await camera.initialize({ + entityRegistryManager: this._entityRegistryManager, + hass, + stateWatcher: this._stateWatcher, + }); } public generateDefaultEventQuery( diff --git a/src/camera-manager/camera.ts b/src/camera-manager/camera.ts index 9e83e5d9..c22b731a 100644 --- a/src/camera-manager/camera.ts +++ b/src/camera-manager/camera.ts @@ -1,19 +1,17 @@ -import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { StateWatcherSubscriptionInterface } from '../card-controller/hass/state-watcher'; import { CameraConfig } from '../config/types'; import { localize } from '../localize/localize'; -import { allPromises } from '../utils/basic'; -import { - DestroyCallback, - isTriggeredState, - parseStateChangeTrigger, - subscribeToTrigger, -} from '../utils/ha'; -import { EntityRegistryManager } from '../utils/ha/entity-registry'; +import { HassStateDifference, isTriggeredState } from '../utils/ha'; import { Capabilities } from './capabilities'; import { CameraManagerEngine } from './engine'; import { CameraNoIDError } from './error'; import { CameraEventCallback } from './types'; +export interface CameraInitializationOptions { + stateWatcher: StateWatcherSubscriptionInterface; +} +type DestroyCallback = () => void | Promise; + export class Camera { protected _config: CameraConfig; protected _engine: CameraManagerEngine; @@ -35,47 +33,17 @@ export class Camera { this._eventCallback = options?.eventCallback; } - protected async _convertStateChangeToCameraEvent(data: unknown): Promise { - const stateChange = parseStateChangeTrigger(data); - if (!stateChange) { - return; - } - - this._eventCallback?.({ - cameraID: this.getID(), - type: isTriggeredState(stateChange.to_state.state) ? 'new' : 'end', - }); - } - - protected async _subscribeToTriggerEntities(hass: HomeAssistant): Promise { - if (!this._config.triggers.entities.length) { - return; - } - - this._destroyCallbacks.push( - await subscribeToTrigger( - hass, - (data) => this._convertStateChangeToCameraEvent(data), - { - entityID: this._config.triggers.entities, - platform: 'state', - stateOnly: true, - }, - ), + async initialize(options: CameraInitializationOptions): Promise { + options.stateWatcher.subscribe( + this._stateChangeHandler, + this._config.triggers.entities, ); - } - - async initialize( - hass: HomeAssistant, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - _entityRegistryManager: EntityRegistryManager, - ): Promise { - await this._subscribeToTriggerEntities(hass); + this._onDestroy(() => options.stateWatcher.unsubscribe(this._stateChangeHandler)); return this; } - async destroy(): Promise { - await allPromises(this._destroyCallbacks, (cb) => cb()); + public async destroy(): Promise { + this._destroyCallbacks.forEach((callback) => callback()); } public getConfig(): CameraConfig { @@ -100,4 +68,15 @@ export class Camera { public getCapabilities(): Capabilities | null { return this._capabilities ?? null; } + + protected _stateChangeHandler = (difference: HassStateDifference): void => { + this._eventCallback?.({ + cameraID: this.getID(), + type: isTriggeredState(difference.newState.state) ? 'new' : 'end', + }); + }; + + protected _onDestroy(callback: DestroyCallback): void { + this._destroyCallbacks.push(callback); + } } diff --git a/src/camera-manager/engine-factory.ts b/src/camera-manager/engine-factory.ts index 39b7384c..00ac031b 100644 --- a/src/camera-manager/engine-factory.ts +++ b/src/camera-manager/engine-factory.ts @@ -1,4 +1,5 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { StateWatcherSubscriptionInterface } from '../card-controller/hass/state-watcher'; import { CameraConfig } from '../config/types'; import { localize } from '../localize/localize'; import { BrowseMediaManager } from '../utils/ha/browse-media/browse-media-manager'; @@ -12,34 +13,41 @@ import { CameraInitializationError } from './error'; import { CameraEventCallback, Engine } from './types'; import { getCameraEntityFromConfig } from './utils/camera-entity-from-config'; -export class CameraManagerEngineFactory { - protected _entityRegistryManager: EntityRegistryManager; - protected _resolvedMediaCache: ResolvedMediaCache; +interface CameraManagerEngineFactoryOptions { + stateWatcher: StateWatcherSubscriptionInterface; + resolvedMediaCache: ResolvedMediaCache; + eventCallback?: CameraEventCallback; +} - constructor( - entityRegistryManager: EntityRegistryManager, - resolvedMediaCache: ResolvedMediaCache, - ) { +export class CameraManagerEngineFactory { + // Entity registry manager is required for the actual function of the factory. + protected _entityRegistryManager: EntityRegistryManager; + + constructor(entityRegistryManager: EntityRegistryManager) { this._entityRegistryManager = entityRegistryManager; - this._resolvedMediaCache = resolvedMediaCache; } public async createEngine( engine: Engine, - eventCallback?: CameraEventCallback, + options: CameraManagerEngineFactoryOptions, ): Promise { let cameraManagerEngine: CameraManagerEngine; switch (engine) { case Engine.Generic: const { GenericCameraManagerEngine } = await import('./generic/engine-generic'); - cameraManagerEngine = new GenericCameraManagerEngine(eventCallback); + cameraManagerEngine = new GenericCameraManagerEngine( + options.stateWatcher, + options.eventCallback, + ); break; case Engine.Frigate: const { FrigateCameraManagerEngine } = await import('./frigate/engine-frigate'); cameraManagerEngine = new FrigateCameraManagerEngine( + this._entityRegistryManager, + options.stateWatcher, new RecordingSegmentsCache(), new RequestCache(), - eventCallback, + options.eventCallback, ); break; case Engine.MotionEye: @@ -47,10 +55,12 @@ export class CameraManagerEngineFactory { './motioneye/engine-motioneye' ); cameraManagerEngine = new MotionEyeCameraManagerEngine( + this._entityRegistryManager, + options.stateWatcher, new BrowseMediaManager(new MemoryRequestCache()), - this._resolvedMediaCache, + options.resolvedMediaCache, new RequestCache(), - eventCallback, + options.eventCallback, ); } return cameraManagerEngine; diff --git a/src/camera-manager/engine.ts b/src/camera-manager/engine.ts index a17c0110..e9fa6b0b 100644 --- a/src/camera-manager/engine.ts +++ b/src/camera-manager/engine.ts @@ -1,7 +1,7 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { CameraConfig, ActionPhase } from '../config/types'; +import { PTZAction } from '../config/ptz'; +import { ActionPhase, CameraConfig } from '../config/types'; import { ExtendedHomeAssistant } from '../types'; -import { EntityRegistryManager } from '../utils/ha/entity-registry'; import { ViewMedia } from '../view/media'; import { Camera } from './camera'; import { CameraManagerReadOnlyConfigStore } from './store'; @@ -27,18 +27,13 @@ import { RecordingSegmentsQuery, RecordingSegmentsQueryResultsMap, } from './types'; -import { PTZAction } from '../config/ptz'; export const CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT = 10000; export interface CameraManagerEngine { getEngineType(): Engine; - createCamera( - hass: HomeAssistant, - entityRegistryManager: EntityRegistryManager, - cameraConfig: CameraConfig, - ): Promise; + createCamera(hass: HomeAssistant, cameraConfig: CameraConfig): Promise; generateDefaultEventQuery( store: CameraManagerReadOnlyConfigStore, diff --git a/src/camera-manager/frigate/camera.ts b/src/camera-manager/frigate/camera.ts index f00d1117..3dd992d6 100644 --- a/src/camera-manager/frigate/camera.ts +++ b/src/camera-manager/frigate/camera.ts @@ -1,5 +1,6 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; import uniq from 'lodash-es/uniq'; +import { StateWatcherSubscriptionInterface } from '../../card-controller/hass/state-watcher'; import { CameraConfig } from '../../config/types'; import { localize } from '../../localize/localize'; import { PTZCapabilities, PTZMovementType } from '../../types'; @@ -7,32 +8,52 @@ import { errorToConsole, recursivelyMergeObjectsConcatenatingArraysUniquely, } from '../../utils/basic'; -import { subscribeToTrigger } from '../../utils/ha'; import { EntityRegistryManager } from '../../utils/ha/entity-registry'; import { Entity } from '../../utils/ha/entity-registry/types'; -import { Camera } from '../camera'; +import { Camera, CameraInitializationOptions } from '../camera'; import { Capabilities } from '../capabilities'; +import { CameraManagerEngine } from '../engine'; import { CameraInitializationError } from '../error'; +import { CameraEventCallback } from '../types'; import { getCameraEntityFromConfig } from '../utils/camera-entity-from-config'; -import { getPTZInfo } from './requests'; -import { PTZInfo, frigateEventChangeTriggerResponseSchema } from './types'; import { getPTZCapabilitiesFromCameraConfig } from '../utils/ptz'; +import { + FrigateEventWatcherRequest, + FrigateEventWatcherSubscriptionInterface, +} from './event-watcher'; +import { getPTZInfo } from './requests'; +import { FrigateEventChange, PTZInfo } from './types'; const CAMERA_BIRDSEYE = 'birdseye' as const; +interface FrigateCameraInitializationOptions extends CameraInitializationOptions { + entityRegistryManager: EntityRegistryManager; + frigateEventWatcher: FrigateEventWatcherSubscriptionInterface; + hass: HomeAssistant; + stateWatcher: StateWatcherSubscriptionInterface; +} + export const isBirdseye = (cameraConfig: CameraConfig): boolean => { return cameraConfig.frigate.camera_name === CAMERA_BIRDSEYE; }; export class FrigateCamera extends Camera { - public async initialize( - hass: HomeAssistant, - entityRegistryManager: EntityRegistryManager, - ): Promise { - await this._initializeConfig(hass, entityRegistryManager); - await this._initializeCapabilities(hass); - await this._subscribeToEvents(hass); - return await super.initialize(hass, entityRegistryManager); + constructor( + config: CameraConfig, + engine: CameraManagerEngine, + options?: { + capabilities?: Capabilities; + eventCallback?: CameraEventCallback; + }, + ) { + super(config, engine, options); + } + + public async initialize(options: FrigateCameraInitializationOptions): Promise { + await this._initializeConfig(options.hass, options.entityRegistryManager); + await this._initializeCapabilities(options.hass); + await this._subscribeToEvents(options.hass, options.frigateEventWatcher); + return await super.initialize(options); } protected async _initializeConfig( @@ -266,49 +287,39 @@ export class FrigateCamera extends Camera { return null; } - protected async _subscribeToEvents(hass: HomeAssistant): Promise { + protected async _subscribeToEvents( + hass: HomeAssistant, + frigateEventWatcher: FrigateEventWatcherSubscriptionInterface, + ): Promise { const config = this.getConfig(); if (!config.triggers.events.length || !config.frigate.camera_name) { return; } - this._destroyCallbacks.push( - await subscribeToTrigger(hass, (ev) => this._handleEventChange(ev), { - platform: 'mqtt', - topic: `${config.frigate.client_id}/events`, + /* istanbul ignore next -- exercising the matcher is not possible when the + test uses an event watcher -- @preserve */ + const request: FrigateEventWatcherRequest = { + instanceID: config.frigate.client_id, + callback: (event: FrigateEventChange) => this._frigateEventHandler(event), + matcher: (event: FrigateEventChange): boolean => + event.after.camera === config.frigate.camera_name, + }; - // Only trigger for events pertaining to this camera. - payload: config.frigate.camera_name, - valueTemplate: '{{ value_json.after.camera }}', - }), - ); + await frigateEventWatcher.subscribe(hass, request); + this._onDestroy(() => frigateEventWatcher.unsubscribe(request)); } - protected _handleEventChange(ev: unknown): void { - const parseResult = frigateEventChangeTriggerResponseSchema.safeParse(ev); - if (!parseResult.success) { - console.warn('Ignoring unparseable Frigate event', ev); - return; - } - - const change = parseResult.data.variables.trigger.payload_json; + protected _frigateEventHandler = (ev: FrigateEventChange): void => { const snapshotChange = - (!change.before.has_snapshot && change.after.has_snapshot) || - change.before.snapshot?.frame_time !== change.after.snapshot?.frame_time; - const clipChange = !change.before.has_clip && change.after.has_clip; + (!ev.before.has_snapshot && ev.after.has_snapshot) || + ev.before.snapshot?.frame_time !== ev.after.snapshot?.frame_time; + const clipChange = !ev.before.has_clip && ev.after.has_clip; const config = this.getConfig(); - if (config.frigate.camera_name !== change.after.camera) { - return; - } - if ( (config.frigate.zones?.length && - !config.frigate.zones.some((zone) => - change.after.current_zones.includes(zone), - )) || - (config.frigate.labels?.length && - !config.frigate.labels.includes(change.after.label)) + !config.frigate.zones.some((zone) => ev.after.current_zones.includes(zone))) || + (config.frigate.labels?.length && !config.frigate.labels.includes(ev.after.label)) ) { return; } @@ -327,11 +338,11 @@ export class FrigateCamera extends Camera { this._eventCallback?.({ fidelity: 'high', cameraID: this.getID(), - type: change.type, + type: ev.type, // In cases where there are both clip and snapshot media, ensure to only // trigger on the media type that is allowed by the configuration. clip: clipChange && eventsToTriggerOn.includes('clips'), snapshot: snapshotChange && eventsToTriggerOn.includes('snapshots'), }); - } + }; } diff --git a/src/camera-manager/frigate/engine-frigate.ts b/src/camera-manager/frigate/engine-frigate.ts index bc2a837e..d8d871e5 100644 --- a/src/camera-manager/frigate/engine-frigate.ts +++ b/src/camera-manager/frigate/engine-frigate.ts @@ -4,6 +4,7 @@ import isEqual from 'lodash-es/isEqual'; import orderBy from 'lodash-es/orderBy'; import throttle from 'lodash-es/throttle'; import uniqWith from 'lodash-es/uniqWith'; +import { StateWatcherSubscriptionInterface } from '../../card-controller/hass/state-watcher'; import { PTZAction } from '../../config/ptz'; import { ActionPhase, CameraConfig } from '../../config/types'; import { ExtendedHomeAssistant } from '../../types'; @@ -20,8 +21,8 @@ import { ViewMediaClassifier } from '../../view/media-classifier'; import { RecordingSegmentsCache, RequestCache } from '../cache'; import { Camera } from '../camera'; import { - CameraManagerEngine, CAMERA_MANAGER_ENGINE_EVENT_LIMIT_DEFAULT, + CameraManagerEngine, } from '../engine'; import { GenericCameraManagerEngine } from '../generic/engine-generic'; import { DateRange } from '../range'; @@ -59,15 +60,16 @@ import { import { getDefaultGo2RTCEndpoint } from '../utils/go2rtc-endpoint'; import frigateLogo from './assets/frigate-logo-dark.svg'; import { FrigateCamera, isBirdseye } from './camera'; +import { FrigateEventWatcher } from './event-watcher'; import { FrigateViewMediaFactory } from './media'; import { FrigateViewMediaClassifier } from './media-classifier'; import { - getEvents, - getEventSummary, - getRecordingSegments, - getRecordingsSummary, NativeFrigateEventQuery, NativeFrigateRecordingSegmentsQuery, + getEventSummary, + getEvents, + getRecordingSegments, + getRecordingsSummary, retainEvent, } from './requests'; import { @@ -110,6 +112,8 @@ export class FrigateCameraManagerEngine extends GenericCameraManagerEngine implements CameraManagerEngine { + protected _entityRegistryManager: EntityRegistryManager; + protected _frigateEventWatcher: FrigateEventWatcher; protected _recordingSegmentsCache: RecordingSegmentsCache; protected _requestCache: RequestCache; @@ -121,11 +125,15 @@ export class FrigateCameraManagerEngine ); constructor( + entityRegistryManager: EntityRegistryManager, + stateWatcher: StateWatcherSubscriptionInterface, recordingSegmentsCache: RecordingSegmentsCache, requestCache: RequestCache, eventCallback?: CameraEventCallback, ) { - super(eventCallback); + super(stateWatcher, eventCallback); + this._entityRegistryManager = entityRegistryManager; + this._frigateEventWatcher = new FrigateEventWatcher(); this._recordingSegmentsCache = recordingSegmentsCache; this._requestCache = requestCache; } @@ -136,13 +144,17 @@ export class FrigateCameraManagerEngine public async createCamera( hass: HomeAssistant, - entityRegistryManager: EntityRegistryManager, cameraConfig: CameraConfig, ): Promise { const camera = new FrigateCamera(cameraConfig, this, { eventCallback: this._eventCallback, }); - return await camera.initialize(hass, entityRegistryManager); + return await camera.initialize({ + hass, + entityRegistryManager: this._entityRegistryManager, + stateWatcher: this._stateWatcher, + frigateEventWatcher: this._frigateEventWatcher, + }); } public async getMediaDownloadPath( diff --git a/src/camera-manager/frigate/event-watcher.ts b/src/camera-manager/frigate/event-watcher.ts new file mode 100644 index 00000000..6aee9002 --- /dev/null +++ b/src/camera-manager/frigate/event-watcher.ts @@ -0,0 +1,76 @@ +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { FrigateEventChange, frigateEventChangeSchema } from './types'; + +export interface FrigateEventWatcherRequest { + instanceID: string; + matcher?(event: FrigateEventChange): boolean; + callback(event: FrigateEventChange): void; +} + +export interface FrigateEventWatcherSubscriptionInterface { + subscribe(hass: HomeAssistant, request: FrigateEventWatcherRequest): Promise; + unsubscribe(callback: FrigateEventWatcherRequest): void; +} + +type SubscriptionUnsubscribe = () => Promise; + +export class FrigateEventWatcher implements FrigateEventWatcherSubscriptionInterface { + protected _requests: FrigateEventWatcherRequest[] = []; + protected _unsubscribeCallback: Record = {}; + + public async subscribe( + hass: HomeAssistant, + request: FrigateEventWatcherRequest, + ): Promise { + const shouldSubscribe = !this._hasSubscribers(request.instanceID); + this._requests.push(request); + if (shouldSubscribe) { + this._unsubscribeCallback[request.instanceID] = + await hass.connection.subscribeMessage( + (data) => this._receiveHandler(request.instanceID, data), + { type: 'frigate/events/subscribe', instance_id: request.instanceID }, + ); + } + } + + public async unsubscribe(request: FrigateEventWatcherRequest): Promise { + this._requests = this._requests.filter( + (existingRequest) => existingRequest !== request, + ); + + if (!this._hasSubscribers(request.instanceID)) { + await this._unsubscribeCallback[request.instanceID](); + delete this._unsubscribeCallback[request.instanceID]; + } + } + + protected _hasSubscribers(instanceID: string): boolean { + return !!this._requests.filter((request) => request.instanceID === instanceID) + .length; + } + + protected _receiveHandler(instanceID: string, data: string): void { + let json: unknown; + try { + json = JSON.parse(data); + } catch (e) { + console.warn('Received non-JSON payload as Frigate event', data); + return; + } + + const parsedEvent = frigateEventChangeSchema.safeParse(json); + if (!parsedEvent.success) { + console.warn('Received malformed Frigate event from Home Assistant', data); + return; + } + + for (const request of this._requests) { + if ( + request.instanceID === instanceID && + (!request.matcher || request.matcher(parsedEvent.data)) + ) { + request.callback(parsedEvent.data); + } + } + } +} diff --git a/src/camera-manager/frigate/types.ts b/src/camera-manager/frigate/types.ts index 7cc7559b..77515ff4 100644 --- a/src/camera-manager/frigate/types.ts +++ b/src/camera-manager/frigate/types.ts @@ -83,8 +83,7 @@ export const ptzInfoSchema = z.object({ }); export type PTZInfo = z.infer; -// Frigate events as stored in MQTT updates. -const frigateEventChangeSchema = z.object({ +const frigateEventChangeBeforeAfterSchema = z.object({ camera: z.string(), snapshot: z .object({ @@ -96,25 +95,13 @@ const frigateEventChangeSchema = z.object({ label: z.string(), current_zones: z.string().array(), }); -export type FrigateEventChange = z.infer; -const frigateEventChangeType = z.enum(['new', 'update', 'end']); -export type FrigateEventChangeType = z.infer; - -export const frigateEventChangeTriggerResponseSchema = z.object({ - variables: z.object({ - trigger: z.object({ - payload_json: z.object({ - before: frigateEventChangeSchema, - after: frigateEventChangeSchema, - type: frigateEventChangeType, - }), - }), - }), +export const frigateEventChangeSchema = z.object({ + before: frigateEventChangeBeforeAfterSchema, + after: frigateEventChangeBeforeAfterSchema, + type: z.enum(['new', 'update', 'end']), }); -export type FrigateEventChangeTriggerResponse = z.infer< - typeof frigateEventChangeTriggerResponseSchema ->; +export type FrigateEventChange = z.infer; // ============================== // Frigate concrete query results diff --git a/src/camera-manager/generic/engine-generic.ts b/src/camera-manager/generic/engine-generic.ts index dc69f35e..f201c852 100644 --- a/src/camera-manager/generic/engine-generic.ts +++ b/src/camera-manager/generic/engine-generic.ts @@ -1,11 +1,11 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { PTZAction, PTZ_PAN_TILT_ACTIONS, PTZ_ZOOM_ACTIONS } from '../../config/ptz'; +import { StateWatcherSubscriptionInterface } from '../../card-controller/hass/state-watcher'; +import { PTZAction } from '../../config/ptz'; import { ActionPhase, CameraConfig } from '../../config/types'; -import { ExtendedHomeAssistant, PTZCapabilities, PTZMovementType } from '../../types'; +import { ExtendedHomeAssistant } from '../../types'; import { getEntityIcon, getEntityTitle } from '../../utils/ha'; -import { EntityRegistryManager } from '../../utils/ha/entity-registry'; import { ViewMedia } from '../../view/media'; import { Camera } from '../camera'; import { Capabilities } from '../capabilities'; @@ -40,8 +40,13 @@ import { getPTZCapabilitiesFromCameraConfig } from '../utils/ptz'; export class GenericCameraManagerEngine implements CameraManagerEngine { protected _eventCallback?: CameraEventCallback; + protected _stateWatcher: StateWatcherSubscriptionInterface; - constructor(eventCallback?: CameraEventCallback) { + constructor( + stateWatcher: StateWatcherSubscriptionInterface, + eventCallback?: CameraEventCallback, + ) { + this._stateWatcher = stateWatcher; this._eventCallback = eventCallback; } @@ -50,8 +55,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { } public async createCamera( - hass: HomeAssistant, - entityRegistryManager: EntityRegistryManager, + _hass: HomeAssistant, cameraConfig: CameraConfig, ): Promise { return await new Camera(cameraConfig, this, { @@ -74,7 +78,7 @@ export class GenericCameraManagerEngine implements CameraManagerEngine { }, ), eventCallback: this._eventCallback, - }).initialize(hass, entityRegistryManager); + }).initialize({ stateWatcher: this._stateWatcher }); } public generateDefaultEventQuery( diff --git a/src/camera-manager/manager.ts b/src/camera-manager/manager.ts index 9bae0252..71ba9d4f 100644 --- a/src/camera-manager/manager.ts +++ b/src/camera-manager/manager.ts @@ -123,10 +123,7 @@ export class CameraManager { this._api = api; this._engineFactory = options?.factory ?? - new CameraManagerEngineFactory( - this._api.getEntityRegistryManager(), - this._api.getResolvedMediaCache(), - ); + new CameraManagerEngineFactory(this._api.getEntityRegistryManager()); this._store = options?.store ?? new CameraManagerStore(); } @@ -157,7 +154,9 @@ export class CameraManager { // rapidly in the config editor). await this._initializationLimit.add(resetAndInitialize); } catch (e: unknown) { - this._api.getMessageManager().setErrorIfHigherPriority(e); + this._api + .getMessageManager() + .setErrorIfHigherPriority(e, localize('error.camera_initialization')); return false; } return true; @@ -190,9 +189,11 @@ export class CameraManager { const engineType = engineTypes[index]; const engine = engineType ? engines.get(engineType) ?? - (await this._engineFactory.createEngine(engineType, (ev) => - this._api.getTriggersManager().handleCameraEvent(ev), - )) + (await this._engineFactory.createEngine(engineType, { + eventCallback: (ev) => this._api.getTriggersManager().handleCameraEvent(ev), + stateWatcher: this._api.getHASSManager().getStateWatcher(), + resolvedMediaCache: this._api.getResolvedMediaCache(), + })) : null; if (!engine || !engineType) { throw new CameraInitializationError( @@ -238,12 +239,7 @@ export class CameraManager { // Configuration is initialized in parallel. const cameras = await allPromises( engineByConfig.entries(), - async ([cameraConfig, engine]) => - await engine.createCamera( - hass, - this._api.getEntityRegistryManager(), - cameraConfig, - ), + async ([cameraConfig, engine]) => await engine.createCamera(hass, cameraConfig), ); // Do the additions based off the result-order, to ensure the map order is diff --git a/src/card-controller/card-element-manager.ts b/src/card-controller/card-element-manager.ts index f8587919..1590b556 100644 --- a/src/card-controller/card-element-manager.ts +++ b/src/card-controller/card-element-manager.ts @@ -46,9 +46,9 @@ export class CardElementManager { this._menuToggleCallback(); } - public update(): void { + public update = (): void => { this._element.requestUpdate(); - } + }; public hasUpdated(): boolean { return this._element.hasUpdated; @@ -69,6 +69,17 @@ export class CardElementManager { this._api.getKeyboardStateManager().initialize(); this._api.getDefaultManager().initialize(); + this._api + .getHASSManager() + .getStateWatcher() + ?.subscribe(this.update, [ + ...(this._api.getConfigManager().getConfig()?.view.render_entities ?? []), + + // Refresh the card if media player state changes: + // https://github.com/dermotduffy/frigate-hass-card/issues/881 + ...(this._api.getMediaPlayerManager().getMediaPlayers() ?? []), + ]); + // Whether or not the card is in panel mode on the dashboard. setOrRemoveAttribute(this._element, isCardInPanel(this._element), 'panel'); setOrRemoveAttribute(this._element, true, 'tabindex', '0'); @@ -129,6 +140,7 @@ export class CardElementManager { this._api.getKeyboardStateManager().uninitialize(); this._api.getActionsManager().uninitialize(); this._api.getDefaultManager().uninitialize(); + this._api.getHASSManager().getStateWatcher()?.unsubscribe(this.update); // Uninitialize cameras to cause them to reinitialize on // reconnection, to ensure the state subscription/unsubscription works diff --git a/src/card-controller/controller.ts b/src/card-controller/controller.ts index cc10b9d1..859f42ab 100644 --- a/src/card-controller/controller.ts +++ b/src/card-controller/controller.ts @@ -20,7 +20,7 @@ import { ConfigManager } from './config/config-manager'; import { DownloadManager } from './download-manager'; import { ExpandManager } from './expand-manager'; import { FullscreenManager } from './fullscreen-manager'; -import { HASSManager } from './hass-manager'; +import { HASSManager } from './hass/hass-manager'; import { InitializationManager } from './initialization-manager'; import { InteractionManager } from './interaction-manager'; import { MediaLoadedInfoManager } from './media-info-manager'; diff --git a/src/card-controller/default-manager.ts b/src/card-controller/default-manager.ts index 88d10027..60eb7383 100644 --- a/src/card-controller/default-manager.ts +++ b/src/card-controller/default-manager.ts @@ -1,9 +1,8 @@ import PQueue from 'p-queue'; -import { DestroyCallback, subscribeToTrigger } from '../utils/ha'; +import { createGeneralAction } from '../utils/action'; import { isActionAllowedBasedOnInteractionState } from '../utils/interaction-mode'; import { Timer } from '../utils/timer'; import { CardDefaultManagerAPI } from './types'; -import { createGeneralAction } from '../utils/action'; /** * Manages automated resetting to the default view. @@ -11,7 +10,6 @@ import { createGeneralAction } from '../utils/action'; export class DefaultManager { protected _timer = new Timer(); protected _api: CardDefaultManagerAPI; - protected _unsubscribeCallback: DestroyCallback | null = null; protected _initializationLimit = new PQueue({ concurrency: 1 }); constructor(api: CardDefaultManagerAPI) { @@ -47,8 +45,7 @@ export class DefaultManager { public uninitialize(): void { this._timer.stop(); - this._unsubscribeCallback?.(); - this._unsubscribeCallback = null; + this._api.getHASSManager().getStateWatcher().unsubscribe(this._stateChangeHandler); this._api.getAutomationsManager().deleteAutomations(this); } @@ -59,19 +56,11 @@ export class DefaultManager { return false; } - if (this._unsubscribeCallback) { - await this._unsubscribeCallback(); - } - - this._unsubscribeCallback = await subscribeToTrigger( - hass, - () => this._setToDefaultIfAllowed(), - { - entityID: config.entities, - platform: 'state', - stateOnly: true, - }, - ); + this._api.getHASSManager().getStateWatcher().unsubscribe(this._stateChangeHandler); + this._api + .getHASSManager() + .getStateWatcher() + .subscribe(this._stateChangeHandler, config.entities); // If the timer is running, restart it with the newly configured timer. if (this._timer.isRunning()) { @@ -82,6 +71,10 @@ export class DefaultManager { return true; } + protected _stateChangeHandler = (): void => { + this._setToDefaultIfAllowed(); + }; + protected _setToDefaultIfAllowed(): void { if (this._isAutomatedUpdateAllowed()) { this._api.getViewManager().setViewDefault(); diff --git a/src/card-controller/hass-manager.ts b/src/card-controller/hass/hass-manager.ts similarity index 64% rename from src/card-controller/hass-manager.ts rename to src/card-controller/hass/hass-manager.ts index 34c35e7d..a0ea929f 100644 --- a/src/card-controller/hass-manager.ts +++ b/src/card-controller/hass/hass-manager.ts @@ -1,11 +1,13 @@ -import { localize } from '../localize/localize'; -import { ExtendedHomeAssistant } from '../types'; -import { hasHAConnectionStateChanged, isHassDifferent } from '../utils/ha'; -import { CardHASSAPI } from './types'; +import { localize } from '../../localize/localize'; +import { ExtendedHomeAssistant } from '../../types'; +import { hasHAConnectionStateChanged } from '../../utils/ha'; +import { CardHASSAPI } from '../types'; +import { StateWatcher, StateWatcherSubscriptionInterface } from './state-watcher'; export class HASSManager { protected _hass: ExtendedHomeAssistant | null = null; protected _api: CardHASSAPI; + protected _stateWatcher: StateWatcher = new StateWatcher(); constructor(api: CardHASSAPI) { this._api = api; @@ -15,6 +17,10 @@ export class HASSManager { return this._hass; } + public getStateWatcher(): StateWatcherSubscriptionInterface { + return this._stateWatcher; + } + public setHASS(hass?: ExtendedHomeAssistant | null): void { if (hasHAConnectionStateChanged(this._hass, hass)) { if (!hass?.connected) { @@ -36,18 +42,6 @@ export class HASSManager { const oldHass = this._hass; this._hass = hass; - if ( - isHassDifferent(this._hass, oldHass, [ - ...(this._api.getConfigManager().getConfig()?.view.render_entities ?? []), - - // Refresh the card if media player state changes: - // https://github.com/dermotduffy/frigate-hass-card/issues/881 - ...this._api.getMediaPlayerManager().getMediaPlayers(), - ]) - ) { - this._api.getCardElementManager().update(); - } - if (this._api.getConditionsManager().hasHAStateConditions()) { this._api.getConditionsManager().setState({ state: this._hass.states, @@ -57,5 +51,7 @@ export class HASSManager { // Dark mode may depend on HASS. this._api.getStyleManager().setLightOrDarkMode(); + + this._stateWatcher.setHASS(oldHass, hass); } } diff --git a/src/card-controller/hass/state-watcher.ts b/src/card-controller/hass/state-watcher.ts new file mode 100644 index 00000000..08e42250 --- /dev/null +++ b/src/card-controller/hass/state-watcher.ts @@ -0,0 +1,51 @@ +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { getHassDifferences, HassStateDifference } from '../../utils/ha'; + +type StateWatcherCallback = (difference: HassStateDifference) => void; + +export interface StateWatcherSubscriptionInterface { + subscribe(callback: StateWatcherCallback, entityIDs: string[]): void; + unsubscribe(callback: StateWatcherCallback): void; +} + +export class StateWatcher implements StateWatcherSubscriptionInterface { + protected _watcherCallbacks = new Map(); + + public setHASS(oldHass: HomeAssistant | null, hass: HomeAssistant): void { + if (!oldHass) { + return; + } + + for (const [callback, entityIDs] of this._watcherCallbacks.entries()) { + const differences = getHassDifferences(hass, oldHass, entityIDs, { + stateOnly: true, + firstOnly: true, + }); + if (differences.length) { + callback(differences[0]); + } + } + } + + /** + * Calls callback when the state of any of the entities changes. The callback is + * called with the state difference of the first entity that changed. + * @param callback The callback. + * @param entityIDs An array of entity IDs to watch. + */ + public subscribe(callback: StateWatcherCallback, entityIDs: string[]): boolean { + if (!entityIDs.length) { + return false; + } + if (this._watcherCallbacks.has(callback)) { + this._watcherCallbacks.get(callback)?.push(...entityIDs); + } else { + this._watcherCallbacks.set(callback, entityIDs); + } + return true; + } + + public unsubscribe(callback: StateWatcherCallback): void { + this._watcherCallbacks.delete(callback); + } +} diff --git a/src/card-controller/message-manager.ts b/src/card-controller/message-manager.ts index 22afbdf6..940f56e7 100644 --- a/src/card-controller/message-manager.ts +++ b/src/card-controller/message-manager.ts @@ -42,16 +42,17 @@ export class MessageManager { } } - public setErrorIfHigherPriority(error: unknown): void { + public setErrorIfHigherPriority(error: unknown, prefix?: string): void { // This object should accept unknown objects to be able to seamlessly - // process arguments to catch() which can only be unknown/any. - if (!(error instanceof Error)) { + // process arguments to catch() which can only be unknown/any. HA may throw + // non Error() based errors. + if (!error || typeof error !== 'object' || !('message' in error)) { return; } errorToConsole(error); this.setMessageIfHigherPriority({ - message: error.message, + message: prefix ? `${prefix}: ${error.message}` : error.message, type: 'error', ...(error instanceof FrigateCardError && { context: error.context }), }); diff --git a/src/card-controller/style-manager.ts b/src/card-controller/style-manager.ts index 02a95115..ff3245fd 100644 --- a/src/card-controller/style-manager.ts +++ b/src/card-controller/style-manager.ts @@ -11,7 +11,7 @@ export class StyleManager { this._api = api; } - public setLightOrDarkMode(): void { + public setLightOrDarkMode = (): void => { const config = this._api.getConfigManager().getConfig(); const isDarkMode = config?.view.dark_mode === 'on' || @@ -24,7 +24,7 @@ export class StyleManager { isDarkMode, 'dark', ); - } + }; public setExpandedMode(): void { const card = this._api.getCardElementManager().getElement(); diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index 0806cb66..5dd754d6 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -12,7 +12,7 @@ import type { DefaultManager } from './default-manager'; import type { DownloadManager } from './download-manager'; import type { ExpandManager } from './expand-manager'; import type { FullscreenManager } from './fullscreen-manager'; -import type { HASSManager } from './hass-manager'; +import type { HASSManager } from './hass/hass-manager'; import type { InitializationManager } from './initialization-manager'; import type { InteractionManager } from './interaction-manager'; import type { KeyboardStateManager } from './keyboard-state-manager'; @@ -121,13 +121,16 @@ export interface CardDownloadAPI { export interface CardElementAPI { getActionsManager(): ActionsManager; getCameraManager(): CameraManager; + getConfigManager(): ConfigManager; getDefaultManager(): DefaultManager; getExpandManager(): ExpandManager; getFullscreenManager(): FullscreenManager; getInitializationManager(): InitializationManager; getInteractionManager(): InteractionManager; + getHASSManager(): HASSManager; getKeyboardStateManager(): KeyboardStateManager; getMediaLoadedInfoManager(): MediaLoadedInfoManager; + getMediaPlayerManager(): MediaPlayerManager; getMicrophoneManager(): MicrophoneManager; getQueryStringManager(): QueryStringManager; } diff --git a/src/config/ptz.ts b/src/config/ptz.ts index 3dd77e98..4507e2bf 100644 --- a/src/config/ptz.ts +++ b/src/config/ptz.ts @@ -1,5 +1,5 @@ -export const PTZ_PAN_TILT_ACTIONS = ['left', 'right', 'up', 'down'] as const; -export const PTZ_ZOOM_ACTIONS = ['zoom_in', 'zoom_out'] as const; +const PTZ_PAN_TILT_ACTIONS = ['left', 'right', 'up', 'down'] as const; +const PTZ_ZOOM_ACTIONS = ['zoom_in', 'zoom_out'] as const; const PTZ_BASE_ACTIONS = [...PTZ_PAN_TILT_ACTIONS, ...PTZ_ZOOM_ACTIONS] as const; export type PTZBaseAction = (typeof PTZ_BASE_ACTIONS)[number]; diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json index cd51cdcb..efb70f05 100644 --- a/src/localize/languages/ca.json +++ b/src/localize/languages/ca.json @@ -570,6 +570,7 @@ }, "error": { "awaiting_live": "S'està esperant que es carregui la transmissió en directe ...", + "camera_initialization": "", "could_not_render_elements": "No s'han pogut representar els elements de la imatge", "could_not_resolve": "No s'ha pogut resoldre l'URL multimèdia", "diagnostics": "Diagnòstic de targetes. Reviseu la informació confidencial abans de compartir-la", diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index d4f6b6bc..dbb6703c 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -570,6 +570,7 @@ }, "error": { "awaiting_live": "Waiting for live stream to load ...", + "camera_initialization": "Camera initialization failed", "could_not_render_elements": "Could not render picture elements", "could_not_resolve": "Could not resolve media URL", "diagnostics": "Card diagnostics. Please review for confidential information prior to sharing", diff --git a/src/localize/languages/fr.json b/src/localize/languages/fr.json index f7193c85..567e431b 100644 --- a/src/localize/languages/fr.json +++ b/src/localize/languages/fr.json @@ -570,6 +570,7 @@ }, "error": { "awaiting_live": "", + "camera_initialization": "", "could_not_render_elements": "Impossible de restituer les éléments de l'image", "could_not_resolve": "", "diagnostics": "Diagnostic de la carte. Veuillez enlever les informations confidentielles avant de les partager", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index c9eae16f..7876a92f 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -570,6 +570,7 @@ }, "error": { "awaiting_live": "", + "camera_initialization": "", "could_not_render_elements": "Impossibile renderizzare gli elementi dell'immagine", "could_not_resolve": "Impossibile risolvere l'URL dei media", "diagnostics": "Diagnostica delle carte.Si prega di rivedere per informazioni riservate prima di condividere", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 137fba4f..bd16f26b 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -570,6 +570,7 @@ }, "error": { "awaiting_live": "", + "camera_initialization": "", "could_not_render_elements": "Não foi possível renderizar os elementos da imagem", "could_not_resolve": "Não foi possível resolver o URL de mídia", "diagnostics": "Diagnósticos do cartão. Revise as informações confidenciais antes de compartilhar", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 9771e9f9..ad342dea 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -570,6 +570,7 @@ }, "error": { "awaiting_live": "", + "camera_initialization": "", "could_not_render_elements": "Não foi possível renderizar os elementos da imagem", "could_not_resolve": "Não foi possível resolver o URL de mídia", "diagnostics": "Diagnósticos do cartão. Reveja as informações confidenciais antes de partilhar", diff --git a/src/types.ts b/src/types.ts index fac43e60..990deea5 100644 --- a/src/types.ts +++ b/src/types.ts @@ -56,7 +56,7 @@ export const MESSAGE_TYPE_PRIORITIES: MessagePriority = { }; export interface Message { - message: string; + message: unknown; type: MessageType; icon?: string; context?: unknown; diff --git a/src/utils/basic.ts b/src/utils/basic.ts index b3f4ee6e..36d5342e 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -101,14 +101,17 @@ export function contentsChanged( /** * Log an error as a warning to the console. - * @param e The Error object. + * @param e The Error-like object. * @param func The Console func to call. */ -export function errorToConsole(e: Error, func: CallableFunction = console.warn): void { +export function errorToConsole( + e: Error | { message: unknown }, + func: CallableFunction = console.warn, +): void { if (e instanceof FrigateCardError && e.context) { func(e, e.context); } else { - func(e); + func(e.message); } } diff --git a/src/utils/ha/index.ts b/src/utils/ha/index.ts index 1a85e69a..bd0d5ec2 100644 --- a/src/utils/ha/index.ts +++ b/src/utils/ha/index.ts @@ -17,14 +17,6 @@ import { } from '../../types.js'; import { domainIcon } from '../icons/domain-icon.js'; import { getParseErrorKeys } from '../zod.js'; -import { - HAStateChangeFromTo, - haStateChangeTriggerResponseSchema, - SubscriptionCallback, - SubscriptionUnsubscribe, -} from './types.js'; - -export type DestroyCallback = () => Promise; /** * Make a HomeAssistant websocket request. May throw. @@ -100,8 +92,8 @@ export async function homeAssistantSignPath( return hass.hassUrl(response.path); } -interface HassStateDifference { - entity: string; +export interface HassStateDifference { + entityID: string; oldState?: HassEntity; newState: HassEntity; } @@ -115,7 +107,7 @@ interface HassStateDifference { * strings only, firstOnly: whether or not to get the first difference only. * @returns An array of HassStateDifference objects. */ -function getHassDifferences( +export function getHassDifferences( newHass: HomeAssistant | undefined | null, oldHass: HomeAssistant | undefined | null, entities: string[] | null, @@ -137,7 +129,7 @@ function getHassDifferences( (!options?.stateOnly && oldState !== newState) ) { differences.push({ - entity: entity, + entityID: entity, oldState: oldState, newState: newState, }); @@ -403,53 +395,3 @@ export const hasHAConnectionStateChanged = ( ): boolean => { return oldHass?.connected !== newHass?.connected; }; - -/** - * Subscribe to a HA trigger - * @param hass The HA object. - * @param callback The callback to call with the data. - * @param options Parameters to the trigger, see: - * https://www.home-assistant.io/docs/automation/trigger/#state-trigger - * @returns A callback to unsubscribe. - */ -export const subscribeToTrigger = async ( - hass: HomeAssistant, - callback: SubscriptionCallback, - options?: { - entityID?: string | string[]; - platform?: string; - topic?: string; - payload?: string; - valueTemplate?: string; - stateOnly?: boolean; - }, -): Promise => { - return await hass.connection.subscribeMessage(callback, { - type: 'subscribe_trigger', - trigger: { - ...(options?.platform && { platform: options.platform }), - ...(options?.entityID && { entity_id: options.entityID }), - ...(options?.topic && { topic: options.topic }), - ...(options?.payload && { payload: options.payload }), - ...(options?.valueTemplate && { value_template: options.valueTemplate }), - ...(options?.stateOnly && { - from: null, - to: null, - }), - }, - }); -}; - -/** - * Parse a state change trigger response. - * @param data The raw data. - * @returns A HAStateChangeFromTo object. - */ -export const parseStateChangeTrigger = (data: unknown): HAStateChangeFromTo | null => { - const parseResult = haStateChangeTriggerResponseSchema.safeParse(data); - if (!parseResult.success) { - console.warn('Ignoring unparseable HA state change', data); - return null; - } - return parseResult.data.variables.trigger; -}; diff --git a/src/utils/ha/types.ts b/src/utils/ha/types.ts deleted file mode 100644 index d1c54943..00000000 --- a/src/utils/ha/types.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { z } from 'zod'; - -export type SubscriptionUnsubscribe = () => Promise; -export type SubscriptionCallback = (data: unknown) => void; - -const haStateChangeSchema = z.object({ - entity_id: z.string(), - state: z.string(), -}); - -const haStateChangeFromToSchema = z.object({ - from_state: haStateChangeSchema, - to_state: haStateChangeSchema, -}); -export type HAStateChangeFromTo = z.infer; - -export const haStateChangeTriggerResponseSchema = z.object({ - variables: z.object({ - trigger: haStateChangeFromToSchema, - }), -}); diff --git a/tests/camera-manager/browse-media/camera.test.ts b/tests/camera-manager/browse-media/camera.test.ts index c7905f24..eaf96699 100644 --- a/tests/camera-manager/browse-media/camera.test.ts +++ b/tests/camera-manager/browse-media/camera.test.ts @@ -5,6 +5,7 @@ import { CameraManagerEngine } from '../../../src/camera-manager/engine'; import { EntityRegistryManager } from '../../../src/utils/ha/entity-registry'; import { Entity } from '../../../src/utils/ha/entity-registry/types'; import { createCameraConfig, createHASS } from '../../test-utils'; +import { StateWatcherSubscriptionInterface } from '../../../src/card-controller/hass/state-watcher'; describe('BrowseMediaCamera', () => { describe('should initialize', () => { @@ -15,7 +16,12 @@ describe('BrowseMediaCamera', () => { ); expect( - async () => await camera.initialize(createHASS(), mock()), + async () => + await camera.initialize({ + hass: createHASS(), + stateWatcher: mock(), + entityRegistryManager: mock(), + }), ).rejects.toThrowError(/Could not find camera entity/); }); @@ -30,7 +36,13 @@ describe('BrowseMediaCamera', () => { const entity = mock(); entityRegistryManager.getEntity.mockResolvedValue(entity); - expect(await camera.initialize(createHASS(), entityRegistryManager)).toBe(camera); + expect( + await camera.initialize({ + hass: createHASS(), + stateWatcher: mock(), + entityRegistryManager: entityRegistryManager, + }), + ).toBe(camera); expect(camera.getEntity()).toBe(entity); }); }); diff --git a/tests/camera-manager/camera.test.ts b/tests/camera-manager/camera.test.ts index 46e5196b..6d08f403 100644 --- a/tests/camera-manager/camera.test.ts +++ b/tests/camera-manager/camera.test.ts @@ -2,51 +2,69 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { Camera } from '../../src/camera-manager/camera.js'; import { GenericCameraManagerEngine } from '../../src/camera-manager/generic/engine-generic.js'; -import { EntityRegistryManager } from '../../src/utils/ha/entity-registry/index.js'; +import { StateWatcherSubscriptionInterface } from '../../src/card-controller/hass/state-watcher.js'; import { - callHASubscribeMessageHandler, + callStateWatcherCallback, createCameraConfig, createCapabilities, - createHASS, + createStateEntity, } from '../test-utils.js'; describe('Camera', () => { it('should get config', async () => { const config = createCameraConfig(); - const camera = new Camera(config, new GenericCameraManagerEngine()); + const camera = new Camera( + config, + new GenericCameraManagerEngine(mock()), + ); expect(camera.getConfig()).toBe(config); }); describe('should get capabilities', async () => { it('when populated', async () => { const capabilities = createCapabilities(); - const camera = new Camera(createCameraConfig(), new GenericCameraManagerEngine(), { - capabilities: capabilities, - }); + const camera = new Camera( + createCameraConfig(), + new GenericCameraManagerEngine(mock()), + { + capabilities: capabilities, + }, + ); expect(camera.getCapabilities()).toBe(capabilities); }); it('when unpopulated', async () => { - const camera = new Camera(createCameraConfig(), new GenericCameraManagerEngine()); + const camera = new Camera( + createCameraConfig(), + new GenericCameraManagerEngine(mock()), + ); expect(camera.getCapabilities()).toBeNull(); }); }); it('should get engine', async () => { - const engine = new GenericCameraManagerEngine(); + const engine = new GenericCameraManagerEngine( + mock(), + ); const camera = new Camera(createCameraConfig(), engine); expect(camera.getEngine()).toBe(engine); }); it('should set and get id', async () => { - const camera = new Camera(createCameraConfig(), new GenericCameraManagerEngine()); + const camera = new Camera( + createCameraConfig(), + new GenericCameraManagerEngine(mock()), + ); camera.setID('foo'); expect(camera.getID()).toBe('foo'); expect(camera.getConfig().id).toBe('foo'); }); it('should throw without id', async () => { - const camera = new Camera(createCameraConfig(), new GenericCameraManagerEngine()); + const camera = new Camera( + createCameraConfig(), + new GenericCameraManagerEngine(mock()), + ); expect(() => camera.getID()).toThrowError( 'Could not determine camera id for the following ' + "camera, may need to set 'id' parameter manually", @@ -60,39 +78,19 @@ describe('Camera', () => { entities: ['camera.foo'], }, }), - new GenericCameraManagerEngine(), + new GenericCameraManagerEngine(mock()), ); - const hass = createHASS(); - const unsubcribeCallback = vi.fn(); - vi.mocked(hass.connection.subscribeMessage).mockResolvedValue(unsubcribeCallback); + const stateWatcher = mock(); + await camera.initialize({ + stateWatcher: stateWatcher, + }); - await camera.initialize(hass, mock()); - - expect(hass.connection.subscribeMessage).toBeCalledWith( - expect.anything(), - expect.objectContaining({ - type: 'subscribe_trigger', - trigger: { - entity_id: ['camera.foo'], - platform: 'state', - from: null, - to: null, - }, - }), - ); - expect(unsubcribeCallback).not.toBeCalled(); + expect(stateWatcher.subscribe).toBeCalledWith(expect.any(Function), ['camera.foo']); await camera.destroy(); - expect(unsubcribeCallback).toBeCalled(); - }); - it('should not subscribe without trigger entities', async () => { - const camera = new Camera(createCameraConfig(), new GenericCameraManagerEngine()); - const hass = createHASS(); - - await camera.initialize(hass, mock()); - expect(hass.connection.subscribeMessage).not.toBeCalled(); + expect(stateWatcher.unsubscribe).toBeCalled(); }); describe('should handle trigger state changes', () => { @@ -100,28 +98,6 @@ describe('Camera', () => { vi.restoreAllMocks(); }); - it('when malformed', async () => { - vi.spyOn(global.console, 'warn').mockReturnValue(undefined); - - const eventCallback = vi.fn(); - const camera = new Camera( - createCameraConfig({ - triggers: { - entities: ['camera.foo'], - }, - }), - new GenericCameraManagerEngine(), - { eventCallback: eventCallback }, - ); - - const hass = createHASS(); - await camera.initialize(hass, mock()); - - callHASubscribeMessageHandler(hass, 'MALFORMED_DATA'); - - expect(eventCallback).not.toBeCalled(); - }); - it.each([ ['off' as const, 'on' as const, 'new' as const], ['on' as const, 'off' as const, 'end' as const], @@ -138,28 +114,22 @@ describe('Camera', () => { entities: ['binary_sensor.foo'], }, }), - new GenericCameraManagerEngine(), + new GenericCameraManagerEngine(mock()), { eventCallback: eventCallback }, ); - const hass = createHASS(); - await camera.initialize(hass, mock()); - - callHASubscribeMessageHandler(hass, { - variables: { - trigger: { - from_state: { - entity_id: 'binary_sensor.foo', - state: stateFrom, - }, - to_state: { - entity_id: 'binary_sensor.foo', - state: stateTo, - }, - }, - }, + const stateWatcher = mock(); + await camera.initialize({ + stateWatcher: stateWatcher, }); + const diff = { + entityID: 'sensor.force_update', + oldState: createStateEntity({ state: stateFrom }), + newState: createStateEntity({ state: stateTo }), + }; + callStateWatcherCallback(stateWatcher, diff); + expect(eventCallback).toBeCalledWith({ cameraID: 'camera_1', type: eventType, diff --git a/tests/camera-manager/engine-factory.test.ts b/tests/camera-manager/engine-factory.test.ts index 647352f9..fe0e9ac1 100644 --- a/tests/camera-manager/engine-factory.test.ts +++ b/tests/camera-manager/engine-factory.test.ts @@ -1,9 +1,11 @@ import { describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; import { CameraManagerEngineFactory } from '../../src/camera-manager/engine-factory.js'; import { FrigateCameraManagerEngine } from '../../src/camera-manager/frigate/engine-frigate'; import { GenericCameraManagerEngine } from '../../src/camera-manager/generic/engine-generic'; import { MotionEyeCameraManagerEngine } from '../../src/camera-manager/motioneye/engine-motioneye'; import { Engine } from '../../src/camera-manager/types.js'; +import { StateWatcherSubscriptionInterface } from '../../src/card-controller/hass/state-watcher.js'; import { CardWideConfig } from '../../src/config/types.js'; import { EntityRegistryManager } from '../../src/utils/ha/entity-registry'; import { EntityCache } from '../../src/utils/ha/entity-registry/cache'; @@ -20,12 +22,10 @@ vi.mock('../../src/utils/ha/entity-registry/cache'); const createFactory = (options?: { entityRegistryManager?: EntityRegistryManager; - resolvedMediaCache?: ResolvedMediaCache; cardWideConfig?: CardWideConfig; }): CameraManagerEngineFactory => { return new CameraManagerEngineFactory( options?.entityRegistryManager ?? new EntityRegistryManager(new EntityCache()), - options?.resolvedMediaCache ?? new ResolvedMediaCache(), ); }; @@ -181,18 +181,27 @@ describe('getEngineForCamera()', () => { describe('createEngine()', () => { it('should create generic engine', async () => { - expect(await createFactory().createEngine(Engine.Generic)).toBeInstanceOf( - GenericCameraManagerEngine, - ); + expect( + await createFactory().createEngine(Engine.Generic, { + stateWatcher: mock(), + resolvedMediaCache: mock(), + }), + ).toBeInstanceOf(GenericCameraManagerEngine); }); it('should create frigate engine', async () => { - expect(await createFactory().createEngine(Engine.Frigate)).toBeInstanceOf( - FrigateCameraManagerEngine, - ); + expect( + await createFactory().createEngine(Engine.Frigate, { + stateWatcher: mock(), + resolvedMediaCache: mock(), + }), + ).toBeInstanceOf(FrigateCameraManagerEngine); }); it('should create motioneye engine', async () => { - expect(await createFactory().createEngine(Engine.MotionEye)).toBeInstanceOf( - MotionEyeCameraManagerEngine, - ); + expect( + await createFactory().createEngine(Engine.MotionEye, { + stateWatcher: mock(), + resolvedMediaCache: mock(), + }), + ).toBeInstanceOf(MotionEyeCameraManagerEngine); }); }); diff --git a/tests/camera-manager/frigate/camera.test.ts b/tests/camera-manager/frigate/camera.test.ts index 15ed29e8..3ec504aa 100644 --- a/tests/camera-manager/frigate/camera.test.ts +++ b/tests/camera-manager/frigate/camera.test.ts @@ -2,40 +2,25 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { CameraManagerEngine } from '../../../src/camera-manager/engine'; import { FrigateCamera } from '../../../src/camera-manager/frigate/camera'; +import { FrigateEventWatcher } from '../../../src/camera-manager/frigate/event-watcher'; import { getPTZInfo } from '../../../src/camera-manager/frigate/requests'; -import { - FrigateEventChange, - FrigateEventChangeTriggerResponse, - FrigateEventChangeType, -} from '../../../src/camera-manager/frigate/types'; +import { FrigateEventChange } from '../../../src/camera-manager/frigate/types'; +import { StateWatcher } from '../../../src/card-controller/hass/state-watcher'; import { CameraTriggerEventType } from '../../../src/config/types'; import { EntityRegistryManager } from '../../../src/utils/ha/entity-registry'; import { Entity } from '../../../src/utils/ha/entity-registry/types'; -import { - callHASubscribeMessageHandler, - createCameraConfig, - createHASS, - createRegistryEntity, -} from '../../test-utils'; +import { createCameraConfig, createHASS, createRegistryEntity } from '../../test-utils'; vi.mock('../../../src/camera-manager/frigate/requests'); -const createFrigateEventChangeTrigger = ( - type: FrigateEventChangeType, - before: FrigateEventChange, - after: FrigateEventChange, -): FrigateEventChangeTriggerResponse => { - return { - variables: { - trigger: { - payload_json: { - before: before, - after: after, - type: type, - }, - }, - }, - }; +const callEventWatcherCallback = ( + eventWatcher: FrigateEventWatcher, + event: FrigateEventChange, + n = 0, +): void => { + const mock = vi.mocked(eventWatcher.subscribe).mock; + expect(mock.calls.length).greaterThan(n); + mock.calls[n][1].callback(event); }; describe('FrigateCamera', () => { @@ -51,7 +36,12 @@ describe('FrigateCamera', () => { const camera = new FrigateCamera(config, mock()); const beforeConfig = { ...config }; - await camera.initialize(createHASS(), mock()); + await camera.initialize({ + hass: createHASS(), + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: mock(), + }); expect(beforeConfig).toEqual(camera.getConfig()); }); @@ -67,7 +57,13 @@ describe('FrigateCamera', () => { entityRegistryManager.getEntity.mockRejectedValue(null); expect( - async () => await camera.initialize(createHASS(), entityRegistryManager), + async () => + await camera.initialize({ + hass: createHASS(), + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }), ).rejects.toThrowError(/Could not find camera entity/); }); @@ -85,9 +81,13 @@ describe('FrigateCamera', () => { }); entityRegistryManager.getEntity.mockResolvedValue(entity); - await camera.initialize(createHASS(), entityRegistryManager); - - expect(camera.getConfig().frigate.camera_name).toBe('fnt_dr'); + await camera.initialize({ + hass: createHASS(), + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }), + expect(camera.getConfig().frigate.camera_name).toBe('fnt_dr'); }); it('with a camera_entity without camera_name match', async () => { @@ -104,9 +104,13 @@ describe('FrigateCamera', () => { }); entityRegistryManager.getEntity.mockResolvedValue(entity); - await camera.initialize(createHASS(), entityRegistryManager); - - expect(camera.getConfig().frigate.camera_name).toBeUndefined(); + await camera.initialize({ + hass: createHASS(), + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }), + expect(camera.getConfig().frigate.camera_name).toBeUndefined(); }); it('with a camera_entity without platform match', async () => { @@ -123,9 +127,13 @@ describe('FrigateCamera', () => { }); entityRegistryManager.getEntity.mockResolvedValue(entity); - await camera.initialize(createHASS(), entityRegistryManager); - - expect(camera.getConfig().frigate.camera_name).toBeUndefined(); + await camera.initialize({ + hass: createHASS(), + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }), + expect(camera.getConfig().frigate.camera_name).toBeUndefined(); }); }); }); @@ -141,9 +149,13 @@ describe('FrigateCamera', () => { mock(), ); - await camera.initialize(createHASS(), mock()); - - expect(camera.getCapabilities()?.has('favorite-events')).toBeTruthy(); + await camera.initialize({ + hass: createHASS(), + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: mock(), + }), + expect(camera.getCapabilities()?.has('favorite-events')).toBeTruthy(); expect(camera.getCapabilities()?.has('favorite-recordings')).toBeFalsy(); expect(camera.getCapabilities()?.has('seek')).toBeTruthy(); expect(camera.getCapabilities()?.has('clips')).toBeTruthy(); @@ -163,9 +175,13 @@ describe('FrigateCamera', () => { mock(), ); - await camera.initialize(createHASS(), mock()); - - expect(camera.getCapabilities()?.has('favorite-events')).toBeFalsy(); + await camera.initialize({ + hass: createHASS(), + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: mock(), + }), + expect(camera.getCapabilities()?.has('favorite-events')).toBeFalsy(); expect(camera.getCapabilities()?.has('favorite-recordings')).toBeFalsy(); expect(camera.getCapabilities()?.has('seek')).toBeFalsy(); expect(camera.getCapabilities()?.has('clips')).toBeFalsy(); @@ -188,9 +204,14 @@ describe('FrigateCamera', () => { mock(), ); vi.mocked(getPTZInfo).mockRejectedValue(new Error()); - await camera.initialize(createHASS(), mock()); - expect(camera.getCapabilities()?.has('ptz')).toBeFalsy(); + await camera.initialize({ + hass: createHASS(), + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: mock(), + }), + expect(camera.getCapabilities()?.has('ptz')).toBeFalsy(); expect(camera.getCapabilities()?.hasPTZCapability()).toBeFalsy(); expect(consoleSpy).toBeCalled(); }); @@ -211,9 +232,14 @@ describe('FrigateCamera', () => { name: 'front_door', presets: ['preset01'], }); - await camera.initialize(createHASS(), mock()); - expect(camera.getCapabilities()?.has('ptz')).toBeTruthy(); + await camera.initialize({ + hass: createHASS(), + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: mock(), + }), + expect(camera.getCapabilities()?.has('ptz')).toBeTruthy(); expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({ left: ['continuous'], right: ['continuous'], @@ -242,9 +268,14 @@ describe('FrigateCamera', () => { name: 'front_door', presets: ['preset01'], }); - await camera.initialize(createHASS(), mock()); - expect(camera.getCapabilities()?.has('ptz')).toBeTruthy(); + await camera.initialize({ + hass: createHASS(), + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: mock(), + }), + expect(camera.getCapabilities()?.has('ptz')).toBeTruthy(); expect(camera.getCapabilities()?.getPTZCapabilities()).toEqual({ left: [], right: [], @@ -272,17 +303,19 @@ describe('FrigateCamera', () => { ); const hass = createHASS(); - await camera.initialize(hass, mock()); - - expect(hass.connection.subscribeMessage).toBeCalledWith(expect.anything(), { - type: 'subscribe_trigger', - trigger: { - platform: 'mqtt', - topic: `CLIENT_ID/events`, - payload: 'CAMERA', - value_template: '{{ value_json.after.camera }}', - }, - }); + const eventWatcher = mock(); + await camera.initialize({ + hass: hass, + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: eventWatcher, + }), + expect(eventWatcher.subscribe).toBeCalledWith( + hass, + expect.objectContaining({ + instanceID: 'CLIENT_ID', + }), + ); }); it('should not subscribe with no trigger events', async () => { @@ -300,9 +333,14 @@ describe('FrigateCamera', () => { ); const hass = createHASS(); - await camera.initialize(hass, mock()); - - expect(hass.connection.subscribeMessage).not.toBeCalled(); + const eventWatcher = mock(); + await camera.initialize({ + hass: hass, + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: eventWatcher, + }), + expect(eventWatcher.subscribe).not.toBeCalled(); }); it('should not subscribe with no camera name', async () => { @@ -316,9 +354,14 @@ describe('FrigateCamera', () => { ); const hass = createHASS(); - await camera.initialize(hass, mock()); - - expect(hass.connection.subscribeMessage).not.toBeCalled(); + const eventWatcher = mock(); + await camera.initialize({ + hass: hass, + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: eventWatcher, + }), + expect(eventWatcher.subscribe).not.toBeCalled(); }); it('should unsubscribe on destroy', async () => { @@ -332,79 +375,20 @@ describe('FrigateCamera', () => { const unsubscribeCallback = vi.fn(); vi.mocked(hass.connection.subscribeMessage).mockResolvedValue(unsubscribeCallback); - await camera.initialize(hass, mock()); - expect(unsubscribeCallback).not.toBeCalled(); + const eventWatcher = mock(); + await camera.initialize({ + hass: hass, + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: eventWatcher, + }), + expect(eventWatcher.unsubscribe).not.toBeCalled(); await camera.destroy(); - expect(unsubscribeCallback).toBeCalled(); + expect(eventWatcher.unsubscribe).toBeCalled(); }); describe('should call handler correctly', () => { - it('with malformed Frigate event', async () => { - const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined); - - const camera = new FrigateCamera( - createCameraConfig({ - frigate: { camera_name: 'front_door' }, - }), - mock(), - ); - - const hass = createHASS(); - await camera.initialize(hass, mock()); - - callHASubscribeMessageHandler(hass, 'GARBAGE'); - - expect(consoleSpy).toBeCalledWith( - 'Ignoring unparseable Frigate event', - 'GARBAGE', - ); - }); - - it('with wrong camera', async () => { - const eventCallback = vi.fn(); - const camera = new FrigateCamera( - createCameraConfig({ - id: 'CAMERA_1', - frigate: { - camera_name: 'camera.front_door', - }, - }), - mock(), - { - eventCallback: eventCallback, - }, - ); - - const hass = createHASS(); - await camera.initialize(hass, mock()); - - callHASubscribeMessageHandler( - hass, - createFrigateEventChangeTrigger( - 'new', - { - camera: 'camera.back_door', - snapshot: null, - has_clip: false, - has_snapshot: false, - label: 'person', - current_zones: [], - }, - { - camera: 'camera.back_door', - snapshot: null, - has_clip: false, - has_snapshot: true, - label: 'person', - current_zones: [], - }, - ), - ); - - expect(eventCallback).not.toBeCalled(); - }); - describe('should handle event type correctly', () => { it.each([ [ @@ -487,30 +471,33 @@ describe('FrigateCamera', () => { ); const hass = createHASS(); - await camera.initialize(hass, mock()); + const eventWatcher = mock(); + await camera.initialize({ + hass: hass, + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: eventWatcher, + }); - callHASubscribeMessageHandler( - hass, - createFrigateEventChangeTrigger( - 'new', - { - camera: 'camera.front_door', - snapshot: null, - has_clip: false, - has_snapshot: false, - label: 'person', - current_zones: [], - }, - { - camera: 'camera.front_door', - snapshot: null, - has_clip: hasClip, - has_snapshot: hasSnapshot, - label: 'person', - current_zones: [], - }, - ), - ); + callEventWatcherCallback(eventWatcher, { + type: 'new', + before: { + camera: 'camera.front_door', + snapshot: null, + has_clip: false, + has_snapshot: false, + label: 'person', + current_zones: [], + }, + after: { + camera: 'camera.front_door', + snapshot: null, + has_clip: hasClip, + has_snapshot: hasSnapshot, + label: 'person', + current_zones: [], + }, + }); if (call) { expect(eventCallback).toBeCalledWith({ @@ -549,30 +536,33 @@ describe('FrigateCamera', () => { ); const hass = createHASS(); - await camera.initialize(hass, mock()); + const eventWatcher = mock(); + await camera.initialize({ + hass: hass, + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: eventWatcher, + }); - callHASubscribeMessageHandler( - hass, - createFrigateEventChangeTrigger( - 'new', - { - camera: 'camera.front_door', - snapshot: null, - has_clip: false, - has_snapshot: false, - label: 'person', - current_zones: [], - }, - { - camera: 'camera.front_door', - snapshot: null, - has_clip: false, - has_snapshot: true, - label: 'person', - current_zones: zones, - }, - ), - ); + callEventWatcherCallback(eventWatcher, { + type: 'new', + before: { + camera: 'camera.front_door', + snapshot: null, + has_clip: false, + has_snapshot: false, + label: 'person', + current_zones: [], + }, + after: { + camera: 'camera.front_door', + snapshot: null, + has_clip: false, + has_snapshot: true, + label: 'person', + current_zones: zones, + }, + }); expect(eventCallback).toHaveBeenCalledTimes(call ? 1 : 0); }); @@ -599,32 +589,35 @@ describe('FrigateCamera', () => { ); const hass = createHASS(); - await camera.initialize(hass, mock()); + const eventWatcher = mock(); + await camera.initialize({ + hass: hass, + entityRegistryManager: mock(), + stateWatcher: mock(), + frigateEventWatcher: eventWatcher, + }); - callHASubscribeMessageHandler( - hass, - createFrigateEventChangeTrigger( - 'new', - { - camera: 'camera.front_door', - snapshot: null, - has_clip: false, - has_snapshot: false, - // Even new events appear to have the event label in the - // 'before' dictionary. - label: label, - current_zones: [], - }, - { - camera: 'camera.front_door', - snapshot: null, - has_clip: false, - has_snapshot: true, - label: label, - current_zones: [], - }, - ), - ); + callEventWatcherCallback(eventWatcher, { + type: 'new', + before: { + camera: 'camera.front_door', + snapshot: null, + has_clip: false, + has_snapshot: false, + // Even new events appear to have the event label in the + // 'before' dictionary. + label: label, + current_zones: [], + }, + after: { + camera: 'camera.front_door', + snapshot: null, + has_clip: false, + has_snapshot: true, + label: label, + current_zones: [], + }, + }); expect(eventCallback).toHaveBeenCalledTimes(call ? 1 : 0); }); @@ -668,8 +661,14 @@ describe('FrigateCamera', () => { }), mock(), ); + const hass = createHASS(); - await camera.initialize(hass, entityRegistryManager); + await camera.initialize({ + hass: hass, + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }); expect(camera.getConfig().triggers.entities).toEqual([]); }); @@ -694,8 +693,14 @@ describe('FrigateCamera', () => { }), mock(), ); + const hass = createHASS(); - await camera.initialize(hass, entityRegistryManager); + await camera.initialize({ + hass: hass, + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }); expect(camera.getConfig().triggers.entities).toEqual(['binary_sensor.foo']); }); @@ -719,8 +724,14 @@ describe('FrigateCamera', () => { }), mock(), ); + const hass = createHASS(); - await camera.initialize(hass, entityRegistryManager); + await camera.initialize({ + hass: hass, + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }); expect(camera.getConfig().triggers.entities).toEqual(['binary_sensor.foo']); }); @@ -743,7 +754,12 @@ describe('FrigateCamera', () => { mock(), ); const hass = createHASS(); - await camera.initialize(hass, entityRegistryManager); + await camera.initialize({ + hass: hass, + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }); expect(camera.getConfig().triggers.entities).toEqual([]); }); @@ -767,7 +783,12 @@ describe('FrigateCamera', () => { mock(), ); const hass = createHASS(); - await camera.initialize(hass, entityRegistryManager); + await camera.initialize({ + hass: hass, + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }); expect(camera.getConfig().triggers.entities).toEqual([]); }); @@ -789,7 +810,12 @@ describe('FrigateCamera', () => { mock(), ); const hass = createHASS(); - await camera.initialize(hass, entityRegistryManager); + await camera.initialize({ + hass: hass, + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }); expect(camera.getConfig().triggers.entities).toEqual([]); }); @@ -814,7 +840,12 @@ describe('FrigateCamera', () => { mock(), ); const hass = createHASS(); - await camera.initialize(hass, entityRegistryManager); + await camera.initialize({ + hass: hass, + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }); expect(camera.getConfig().triggers.entities).toEqual(['binary_sensor.foo']); }); @@ -837,7 +868,12 @@ describe('FrigateCamera', () => { mock(), ); const hass = createHASS(); - await camera.initialize(hass, entityRegistryManager); + await camera.initialize({ + hass: hass, + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }); expect(camera.getConfig().triggers.entities).toEqual([]); }); @@ -866,7 +902,12 @@ describe('FrigateCamera', () => { mock(), ); const hass = createHASS(); - await camera.initialize(hass, entityRegistryManager); + await camera.initialize({ + hass: hass, + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }); expect(camera.getConfig().triggers.entities).toEqual(['binary_sensor.foo']); }); @@ -896,7 +937,12 @@ describe('FrigateCamera', () => { mock(), ); const hass = createHASS(); - await camera.initialize(hass, entityRegistryManager); + await camera.initialize({ + hass: hass, + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }); expect(camera.getConfig().triggers.entities).toEqual(['binary_sensor.foo']); }); @@ -922,7 +968,12 @@ describe('FrigateCamera', () => { mock(), ); const hass = createHASS(); - await camera.initialize(hass, entityRegistryManager); + await camera.initialize({ + hass: hass, + entityRegistryManager: entityRegistryManager, + stateWatcher: mock(), + frigateEventWatcher: mock(), + }); const filterFunc = entityRegistryManager.getMatchingEntities.mock.calls[0][1]; diff --git a/tests/camera-manager/frigate/event-watcher.test.ts b/tests/camera-manager/frigate/event-watcher.test.ts new file mode 100644 index 00000000..36219baf --- /dev/null +++ b/tests/camera-manager/frigate/event-watcher.test.ts @@ -0,0 +1,201 @@ +import { afterEach, describe, expect, it, vi } from 'vitest'; +import { FrigateEventWatcher } from '../../../src/camera-manager/frigate/event-watcher'; +import { createHASS } from '../../test-utils'; +import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; +import { FrigateEventChange } from '../../../src/camera-manager/frigate/types'; + +const createEventChange = (): FrigateEventChange => { + return { + type: 'new', + before: { + camera: 'front_door', + snapshot: null, + has_clip: false, + has_snapshot: false, + label: 'person', + current_zones: [], + }, + after: { + camera: 'front_door', + snapshot: null, + has_clip: true, + has_snapshot: true, + label: 'person', + current_zones: [], + }, + }; +}; + +const callHASubscribeMessageCallback = ( + hass: HomeAssistant, + data: unknown, + n = 0, +): void => { + const mock = vi.mocked(hass.connection.subscribeMessage).mock; + expect(mock.calls.length).greaterThan(n); + mock.calls[n][0](data); +}; + +describe('FrigateEventWatcher', () => { + it('should subscribe to a given topic once', async () => { + const stateWatcher = new FrigateEventWatcher(); + const hass = createHASS(); + + await stateWatcher.subscribe(hass, { + instanceID: 'frigate', + callback: vi.fn(), + }); + + await stateWatcher.subscribe(hass, { + instanceID: 'frigate', + callback: vi.fn(), + }); + + expect(hass.connection.subscribeMessage).toBeCalledTimes(1); + }); + + it('should only subscribe from a given topic once', async () => { + const stateWatcher = new FrigateEventWatcher(); + const hass = createHASS(); + + const unsubscribeCallback = vi.fn(); + vi.mocked(hass.connection.subscribeMessage).mockResolvedValue(unsubscribeCallback); + + const request_1 = { + instanceID: 'frigate', + callback: vi.fn(), + }; + const request_2 = { ...request_1 }; + + await stateWatcher.subscribe(hass, request_1); + await stateWatcher.subscribe(hass, request_2); + + await stateWatcher.unsubscribe(request_1); + expect(unsubscribeCallback).not.toBeCalled(); + + await stateWatcher.unsubscribe(request_2); + expect(unsubscribeCallback).toBeCalledTimes(1); + }); + + describe('should call handler', () => { + afterEach(() => { + vi.resetAllMocks(); + }); + + it('with invalid JSON', async () => { + const spy = vi.spyOn(global.console, 'warn').mockImplementation(() => true); + + const stateWatcher = new FrigateEventWatcher(); + const hass = createHASS(); + + const callback = vi.fn(); + const request = { + instanceID: 'frigate', + callback: callback, + }; + + await stateWatcher.subscribe(hass, request); + callHASubscribeMessageCallback(hass, 'NOT_JSON'); + + expect(callback).not.toBeCalled(); + expect(spy).toBeCalledWith( + 'Received non-JSON payload as Frigate event', + 'NOT_JSON', + ); + }); + + it('with malformed event', async () => { + const spy = vi.spyOn(global.console, 'warn').mockImplementation(() => true); + + const stateWatcher = new FrigateEventWatcher(); + const hass = createHASS(); + + const callback = vi.fn(); + const request = { + instanceID: 'frigate', + callback: callback, + }; + + await stateWatcher.subscribe(hass, request); + const data = JSON.stringify({}); + callHASubscribeMessageCallback(hass, data); + + expect(callback).not.toBeCalled(); + expect(spy).toBeCalledWith( + 'Received malformed Frigate event from Home Assistant', + data, + ); + }); + + it('without a matcher', async () => { + const stateWatcher = new FrigateEventWatcher(); + const hass = createHASS(); + + const callback = vi.fn(); + const request = { + instanceID: 'frigate', + callback: callback, + }; + + await stateWatcher.subscribe(hass, request); + const eventChange = createEventChange(); + callHASubscribeMessageCallback(hass, JSON.stringify(eventChange)); + + expect(callback).toBeCalledWith(eventChange); + }); + + it('with a non-matching instance_id', async () => { + const stateWatcher = new FrigateEventWatcher(); + const hass = createHASS(); + + const callback_1 = vi.fn(); + const request_1 = { + instanceID: 'frigate_1', + callback: callback_1, + }; + + const callback_2 = vi.fn(); + const request_2 = { + instanceID: 'frigate_2', + callback: callback_2, + }; + + await stateWatcher.subscribe(hass, request_1); + await stateWatcher.subscribe(hass, request_2); + + const eventChange = createEventChange(); + callHASubscribeMessageCallback(hass, JSON.stringify(eventChange), 1); + + expect(callback_1).not.toBeCalledWith(eventChange); + expect(callback_2).toBeCalledWith(eventChange); + }); + + it('with a matcher', async () => { + const stateWatcher = new FrigateEventWatcher(); + const hass = createHASS(); + + const matching_callback = vi.fn(); + const matching_request = { + instanceID: 'frigate', + callback: matching_callback, + matcher: (event: FrigateEventChange) => event.after.camera === 'front_door', + }; + + const non_matching_callback = vi.fn(); + const non_matching_request = { + instanceID: 'frigate', + callback: non_matching_callback, + matcher: (event: FrigateEventChange) => event.after.camera === 'back_door', + }; + + await stateWatcher.subscribe(hass, matching_request); + await stateWatcher.subscribe(hass, non_matching_request); + + const eventChange = createEventChange(); + callHASubscribeMessageCallback(hass, JSON.stringify(eventChange)); + + expect(non_matching_callback).not.toBeCalledWith(eventChange); + expect(matching_callback).toBeCalledWith(eventChange); + }); + }); +}); diff --git a/tests/camera-manager/generic/engine-generic.test.ts b/tests/camera-manager/generic/engine-generic.test.ts index 1acf663b..da678641 100644 --- a/tests/camera-manager/generic/engine-generic.test.ts +++ b/tests/camera-manager/generic/engine-generic.test.ts @@ -2,8 +2,8 @@ import { describe, expect, it } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { GenericCameraManagerEngine } from '../../../src/camera-manager/generic/engine-generic'; import { Engine, QueryResultsType, QueryType } from '../../../src/camera-manager/types'; +import { StateWatcherSubscriptionInterface } from '../../../src/card-controller/hass/state-watcher'; import { CameraConfig, RawFrigateCardConfig } from '../../../src/config/types'; -import { EntityRegistryManager } from '../../../src/utils/ha/entity-registry'; import { TestViewMedia, createCameraConfig, @@ -13,7 +13,7 @@ import { } from '../../test-utils'; const createEngine = (): GenericCameraManagerEngine => { - return new GenericCameraManagerEngine(); + return new GenericCameraManagerEngine(mock()); }; const createGenericCameraConfig = (config?: RawFrigateCardConfig): CameraConfig => { @@ -27,11 +27,7 @@ describe('GenericCameraManagerEngine', () => { it('should initialize camera', async () => { const config = createGenericCameraConfig(); - const camera = await createEngine().createCamera( - createHASS(), - mock(), - config, - ); + const camera = await createEngine().createCamera(createHASS(), config); expect(camera.getConfig()).toEqual(config); expect(camera.getCapabilities()).toBeTruthy(); diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts index 71451bde..69a609c2 100644 --- a/tests/camera-manager/manager.test.ts +++ b/tests/camera-manager/manager.test.ts @@ -29,7 +29,6 @@ import { import { sortMedia } from '../../src/camera-manager/utils/sort-media'; import { CardController } from '../../src/card-controller/controller'; import { CameraConfig } from '../../src/config/types'; -import { EntityRegistryManager } from '../../src/utils/ha/entity-registry'; import { ViewMedia } from '../../src/view/media'; import { TestViewMedia, @@ -240,11 +239,7 @@ describe('CameraManager', async () => { camera.engineType === undefined ? Engine.Generic : camera.engineType; if (engineType) { vi.mocked(mockEngine.createCamera).mockImplementationOnce( - async ( - _hass: HomeAssistant, - _entityRegistryManager: EntityRegistryManager, - cameraConfig: CameraConfig, - ): Promise => + async (_hass: HomeAssistant, cameraConfig: CameraConfig): Promise => createCamera( cameraConfig, mockEngine, @@ -313,6 +308,7 @@ describe('CameraManager', async () => { 'Could not determine camera id for the following camera, ' + "may need to set 'id' parameter manually", ), + 'Camera initialization failed', ); }); @@ -338,6 +334,7 @@ describe('CameraManager', async () => { 'Duplicate Frigate camera id for the following camera, ' + "use the 'id' parameter to uniquely identify cameras", ), + 'Camera initialization failed', ); }); @@ -356,6 +353,7 @@ describe('CameraManager', async () => { expect(await manager.initializeCamerasFromConfig()).toBeFalsy(); expect(api.getMessageManager().setErrorIfHigherPriority).toBeCalledWith( new Error('Could not determine suitable engine for camera'), + 'Camera initialization failed', ); }); @@ -371,13 +369,13 @@ describe('CameraManager', async () => { factory, ); expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); - const triggerCallback = factory.createEngine.mock.calls[0][1]; + const eventCallback = factory.createEngine.mock.calls[0][1].eventCallback; const cameraEvent: CameraEvent = { cameraID: 'camera', type: 'new', }; - triggerCallback?.(cameraEvent); + eventCallback?.(cameraEvent); expect(api.getTriggersManager().handleCameraEvent).toBeCalledWith(cameraEvent); }); diff --git a/tests/camera-manager/store.test.ts b/tests/camera-manager/store.test.ts index 5c218ffb..13daec36 100644 --- a/tests/camera-manager/store.test.ts +++ b/tests/camera-manager/store.test.ts @@ -8,6 +8,7 @@ import { Engine } from '../../src/camera-manager/types.js'; import { EntityRegistryManager } from '../../src/utils/ha/entity-registry/index.js'; import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media.js'; import { TestViewMedia, createCameraConfig } from '../test-utils.js'; +import { StateWatcherSubscriptionInterface } from '../../src/card-controller/hass/state-watcher.js'; describe('CameraManagerStore', async () => { const configVisible = createCameraConfig({ @@ -18,13 +19,16 @@ describe('CameraManagerStore', async () => { hide: true, }); - const engineFactory = new CameraManagerEngineFactory( - mock(), - mock(), - ); + const engineFactory = new CameraManagerEngineFactory(mock()); - const engineGeneric = await engineFactory.createEngine(Engine.Generic); - const engineFrigate = await engineFactory.createEngine(Engine.Frigate); + const engineGeneric = await engineFactory.createEngine(Engine.Generic, { + stateWatcher: mock(), + resolvedMediaCache: mock(), + }); + const engineFrigate = await engineFactory.createEngine(Engine.Frigate, { + stateWatcher: mock(), + resolvedMediaCache: mock(), + }); const setupStore = (): CameraManagerStore => { const store = new CameraManagerStore(); diff --git a/tests/card-controller/card-element-manager.test.ts b/tests/card-controller/card-element-manager.test.ts index 12fced9c..0ac1d74f 100644 --- a/tests/card-controller/card-element-manager.test.ts +++ b/tests/card-controller/card-element-manager.test.ts @@ -1,7 +1,14 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; import { CardElementManager } from '../../src/card-controller/card-element-manager'; -import { createCardAPI, createLitElement } from '../test-utils'; +import { StateWatcher } from '../../src/card-controller/hass/state-watcher'; +import { + callStateWatcherCallback, + createCardAPI, + createConfig, + createLitElement, + createStateEntity, +} from '../test-utils'; // @vitest-environment jsdom describe('CardElementManager', () => { @@ -191,4 +198,66 @@ describe('CardElementManager', () => { expect(api.getActionsManager().uninitialize).toBeCalled(); expect(api.getInitializationManager().uninitialize).toBeCalledWith('cameras'); }); + + describe('should update card when', () => { + it('render entity changes', () => { + const api = createCardAPI(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + render_entities: ['sensor.force_update'], + }, + }), + ); + + const stateWatcher = mock(); + vi.mocked(api.getHASSManager().getStateWatcher).mockReturnValue(stateWatcher); + + const element = createLitElement(); + const manager = new CardElementManager( + api, + element, + () => undefined, + () => undefined, + ); + + manager.elementConnected(); + + const diff = { + entityID: 'sensor.force_update', + newState: createStateEntity({ state: 'off' }), + }; + callStateWatcherCallback(stateWatcher, diff); + + expect(element.requestUpdate).toBeCalled(); + }); + + it('media player entity changes', () => { + const api = createCardAPI(); + vi.mocked(api.getMediaPlayerManager().getMediaPlayers).mockReturnValue([ + 'media_player.foo', + ]); + + const stateWatcher = mock(); + vi.mocked(api.getHASSManager().getStateWatcher).mockReturnValue(stateWatcher); + + const element = createLitElement(); + const manager = new CardElementManager( + api, + element, + () => undefined, + () => undefined, + ); + + manager.elementConnected(); + + const diff = { + entityID: 'sensor.force_update', + newState: createStateEntity({ state: 'off' }), + }; + callStateWatcherCallback(stateWatcher, diff); + + expect(element.requestUpdate).toBeCalled(); + }); + }); }); diff --git a/tests/card-controller/controller.test.ts b/tests/card-controller/controller.test.ts index ff5f0018..a211175e 100644 --- a/tests/card-controller/controller.test.ts +++ b/tests/card-controller/controller.test.ts @@ -14,7 +14,7 @@ import { DefaultManager } from '../../src/card-controller/default-manager'; import { DownloadManager } from '../../src/card-controller/download-manager'; import { ExpandManager } from '../../src/card-controller/expand-manager'; import { FullscreenManager } from '../../src/card-controller/fullscreen-manager'; -import { HASSManager } from '../../src/card-controller/hass-manager'; +import { HASSManager } from '../../src/card-controller/hass/hass-manager'; import { InitializationManager } from '../../src/card-controller/initialization-manager'; import { InteractionManager } from '../../src/card-controller/interaction-manager'; import { KeyboardStateManager } from '../../src/card-controller/keyboard-state-manager'; @@ -23,13 +23,13 @@ import { MediaPlayerManager } from '../../src/card-controller/media-player-manag import { MessageManager } from '../../src/card-controller/message-manager'; import { MicrophoneManager } from '../../src/card-controller/microphone-manager'; import { QueryStringManager } from '../../src/card-controller/query-string-manager'; +import { StatusBarItemManager } from '../../src/card-controller/status-bar-item-manager'; import { StyleManager } from '../../src/card-controller/style-manager'; import { TriggersManager } from '../../src/card-controller/triggers-manager'; import { ViewManager } from '../../src/card-controller/view/view-manager'; import { FrigateCardEditor } from '../../src/editor'; import { EntityRegistryManager } from '../../src/utils/ha/entity-registry'; import { ResolvedMediaCache } from '../../src/utils/ha/resolved-media'; -import { StatusBarItemManager } from '../../src/card-controller/status-bar-item-manager'; vi.mock('../../src/camera-manager/manager'); vi.mock('../../src/card-controller/actions/actions-manager'); @@ -42,7 +42,7 @@ vi.mock('../../src/card-controller/default-manager'); vi.mock('../../src/card-controller/download-manager'); vi.mock('../../src/card-controller/expand-manager'); vi.mock('../../src/card-controller/fullscreen-manager'); -vi.mock('../../src/card-controller/hass-manager'); +vi.mock('../../src/card-controller/hass/hass-manager'); vi.mock('../../src/card-controller/initialization-manager'); vi.mock('../../src/card-controller/interaction-manager'); vi.mock('../../src/card-controller/keyboard-state-manager'); diff --git a/tests/card-controller/default-manager.test.ts b/tests/card-controller/default-manager.test.ts index 5f3be314..e266f66f 100644 --- a/tests/card-controller/default-manager.test.ts +++ b/tests/card-controller/default-manager.test.ts @@ -1,12 +1,24 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; +import { mock } from 'vitest-mock-extended'; +import { CardController } from '../../src/card-controller/controller'; import { DefaultManager } from '../../src/card-controller/default-manager'; +import { StateWatcherSubscriptionInterface } from '../../src/card-controller/hass/state-watcher'; import { - callHASubscribeMessageHandler, + callStateWatcherCallback, createCardAPI, createConfig, createHASS, + createStateEntity, } from '../test-utils'; +const createCardAPIWithStateWatcher = (): CardController => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().getStateWatcher).mockReturnValue( + mock(), + ); + return api; +}; + // @vitest-environment jsdom describe('DefaultManager', () => { afterEach(() => { @@ -15,7 +27,7 @@ describe('DefaultManager', () => { describe('time based', () => { it('should set default view when allowed', async () => { - const api = createCardAPI(); + const api = createCardAPIWithStateWatcher(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { @@ -75,7 +87,7 @@ describe('DefaultManager', () => { }); it('should restart timer when reconfigured', async () => { - const api = createCardAPI(); + const api = createCardAPIWithStateWatcher(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { @@ -88,8 +100,6 @@ describe('DefaultManager', () => { vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(false); const hass = createHASS(); - const unsubcribeCallback = vi.fn(); - vi.mocked(hass.connection.subscribeMessage).mockResolvedValue(unsubcribeCallback); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); vi.useFakeTimers(); @@ -99,71 +109,47 @@ describe('DefaultManager', () => { await manager.initialize(); expect(api.getViewManager().setViewDefault).not.toBeCalled(); + await manager.initialize(); + expect(api.getViewManager().setViewDefault).not.toBeCalled(); + vi.runOnlyPendingTimers(); expect(api.getViewManager().setViewDefault).toBeCalled(); }); }); - describe('state based', () => { - it('should set default view when state changed', async () => { - const api = createCardAPI(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - view: { - default_reset: { - every_seconds: 10, - }, - }, - }), - ); - vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(false); - - const hass = createHASS(); - const unsubcribeCallback = vi.fn(); - vi.mocked(hass.connection.subscribeMessage).mockResolvedValue(unsubcribeCallback); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); - - const manager = new DefaultManager(api); - await manager.initialize(); - - callHASubscribeMessageHandler(hass, { - variables: { - trigger: { - from_state: { - entity_id: 'binary_sensor.foo', - state: 'off', - }, - to_state: { - entity_id: 'binary_sensor.foo', - state: 'on', - }, + it('should set default view when state changed', async () => { + const api = createCardAPIWithStateWatcher(); + vi.mocked(api.getConfigManager().getConfig).mockReturnValue( + createConfig({ + view: { + default_reset: { + entities: ['binary_sensor.foo'], + every_seconds: 10, }, }, - }); + }), + ); + vi.mocked(api.getInteractionManager().hasInteraction).mockReturnValue(false); - await manager.initialize(); - expect(unsubcribeCallback).toBeCalledTimes(1); + const hass = createHASS(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); - expect(api.getViewManager().setViewDefault).toBeCalledTimes(1); + const manager = new DefaultManager(api); + await manager.initialize(); + + callStateWatcherCallback(api.getHASSManager().getStateWatcher(), { + entityID: 'binary_sensor.foo', + oldState: createStateEntity({ state: 'off' }), + newState: createStateEntity({ state: 'on' }), }); - it('should not monitor state without config', async () => { - const api = createCardAPI(); - const hass = createHASS(); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); - - const manager = new DefaultManager(api); - await manager.initialize(); - - const mock = vi.mocked(hass.connection.subscribeMessage).mock; - expect(mock.calls.length).toBe(0); - }); + expect(api.getViewManager().setViewDefault).toBeCalled(); }); describe('interaction based', () => { it('should not register automation on initialization', async () => { - const api = createCardAPI(); + const api = createCardAPIWithStateWatcher(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ @@ -182,7 +168,7 @@ describe('DefaultManager', () => { }); it('should register automation on initialization', async () => { - const api = createCardAPI(); + const api = createCardAPIWithStateWatcher(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ @@ -216,10 +202,10 @@ describe('DefaultManager', () => { ]); }); - it('should remove automation on uninitalize', async () => { - const api = createCardAPI(); + it('should remove automation on uninitalize', () => { + const api = createCardAPIWithStateWatcher(); const manager = new DefaultManager(api); - await manager.uninitialize(); + manager.uninitialize(); expect(api.getAutomationsManager().deleteAutomations).toBeCalledWith(manager); }); diff --git a/tests/card-controller/hass-manager.test.ts b/tests/card-controller/hass/hass-manager.test.ts similarity index 74% rename from tests/card-controller/hass-manager.test.ts rename to tests/card-controller/hass/hass-manager.test.ts index 6bf3bf5a..f4051d31 100644 --- a/tests/card-controller/hass-manager.test.ts +++ b/tests/card-controller/hass/hass-manager.test.ts @@ -1,6 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { CardController } from '../../src/card-controller/controller'; -import { HASSManager } from '../../src/card-controller/hass-manager'; +import { HASSManager } from '../../../src/card-controller/hass/hass-manager'; +import { StateWatcher } from '../../../src/card-controller/hass/state-watcher'; import { createCameraConfig, createCameraManager, @@ -11,13 +11,7 @@ import { createStore, createUser, createView, -} from '../test-utils'; - -const createAPIWithoutMediaPlayers = (): CardController => { - const api = createCardAPI(); - vi.mocked(api.getMediaPlayerManager().getMediaPlayers).mockReturnValue([]); - return api; -}; +} from '../../test-utils'; describe('HASSManager', () => { beforeEach(() => { @@ -29,8 +23,13 @@ describe('HASSManager', () => { expect(manager.getHASS()).toBeNull(); }); + it('should get state watcher', () => { + const manager = new HASSManager(createCardAPI()); + expect(manager.getStateWatcher()).toEqual(expect.any(StateWatcher)); + }); + it('should set light or dark mode upon setting hass', () => { - const api = createAPIWithoutMediaPlayers(); + const api = createCardAPI(); const manager = new HASSManager(api); manager.setHASS(createHASS()); @@ -40,7 +39,7 @@ describe('HASSManager', () => { describe('should set condition manager state', () => { it('positively', () => { - const api = createAPIWithoutMediaPlayers(); + const api = createCardAPI(); const manager = new HASSManager(api); vi.mocked(api.getConditionsManager().hasHAStateConditions).mockReturnValue(true); @@ -59,7 +58,7 @@ describe('HASSManager', () => { }); it('negatively', () => { - const api = createAPIWithoutMediaPlayers(); + const api = createCardAPI(); const manager = new HASSManager(api); vi.mocked(api.getConditionsManager().hasHAStateConditions).mockReturnValue(false); @@ -71,7 +70,7 @@ describe('HASSManager', () => { describe('should handle connection state change when', () => { it('initially disconnected', () => { - const api = createAPIWithoutMediaPlayers(); + const api = createCardAPI(); const manager = new HASSManager(api); const disconnectedHASS = createHASS(); @@ -90,7 +89,7 @@ describe('HASSManager', () => { }); it('disconnected', () => { - const api = createAPIWithoutMediaPlayers(); + const api = createCardAPI(); const manager = new HASSManager(api); manager.setHASS(createHASS()); @@ -110,7 +109,7 @@ describe('HASSManager', () => { }); it('reconnected', () => { - const api = createAPIWithoutMediaPlayers(); + const api = createCardAPI(); const manager = new HASSManager(api); const disconnectedHASS = createHASS(); @@ -124,7 +123,7 @@ describe('HASSManager', () => { }); it('hass is null', () => { - const api = createAPIWithoutMediaPlayers(); + const api = createCardAPI(); const manager = new HASSManager(api); const connectedHASS = createHASS(); connectedHASS.connected = true; @@ -148,7 +147,7 @@ describe('HASSManager', () => { describe('should not set default view when', () => { it('selected camera is unknown', () => { - const api = createAPIWithoutMediaPlayers(); + const api = createCardAPI(); vi.mocked(api.getCameraManager).mockReturnValue(createCameraManager()); vi.mocked(api.getCameraManager().getStore).mockReturnValue( createStore([ @@ -179,7 +178,7 @@ describe('HASSManager', () => { }); it('when there is card interaction', () => { - const api = createAPIWithoutMediaPlayers(); + const api = createCardAPI(); vi.mocked(api.getConfigManager().getConfig).mockReturnValue( createConfig({ view: { @@ -201,42 +200,4 @@ describe('HASSManager', () => { expect(api.getViewManager().setViewDefault).not.toBeCalled(); }); }); - - describe('should update card when', () => { - it('render entity changes', () => { - const api = createAPIWithoutMediaPlayers(); - vi.mocked(api.getConfigManager().getConfig).mockReturnValue( - createConfig({ - view: { - render_entities: ['sensor.force_update'], - }, - }), - ); - - const manager = new HASSManager(api); - const hass = createHASS({ - 'sensor.force_update': createStateEntity(), - }); - - manager.setHASS(hass); - - expect(api.getCardElementManager().update).toBeCalled(); - }); - - it('media player entity changes', () => { - const api = createCardAPI(); - vi.mocked(api.getMediaPlayerManager().getMediaPlayers).mockReturnValue([ - 'media_player.foo', - ]); - - const manager = new HASSManager(api); - const hass = createHASS({ - 'media_player.foo': createStateEntity(), - }); - - manager.setHASS(hass); - - expect(api.getCardElementManager().update).toBeCalled(); - }); - }); }); diff --git a/tests/card-controller/hass/state-watcher.test.ts b/tests/card-controller/hass/state-watcher.test.ts new file mode 100644 index 00000000..2e6ff4e4 --- /dev/null +++ b/tests/card-controller/hass/state-watcher.test.ts @@ -0,0 +1,101 @@ +import { describe, expect, it, vi } from 'vitest'; +import { StateWatcher } from '../../../src/card-controller/hass/state-watcher'; +import { createHASS, createStateEntity } from '../../test-utils'; + +describe('StateWatcher', () => { + it('should not subscribe with no entities', () => { + const stateWatcher = new StateWatcher(); + const callback = vi.fn(); + expect(stateWatcher.subscribe(callback, [])).toBeFalsy(); + }); + + it('should call back with state change', () => { + const stateWatcher = new StateWatcher(); + const callback = vi.fn(); + expect(stateWatcher.subscribe(callback, ['binary_sensor.foo'])).toBeTruthy(); + expect(stateWatcher.subscribe(callback, ['binary_sensor.bar'])).toBeTruthy(); + + stateWatcher.setHASS( + null, + createHASS({ + 'binary_sensor.foo': createStateEntity({ state: 'on' }), + 'binary_sensor.bar': createStateEntity({ state: 'off' }), + }), + ); + + expect(callback).not.toBeCalled(); + + stateWatcher.setHASS( + createHASS({ + 'binary_sensor.foo': createStateEntity({ state: 'on' }), + 'binary_sensor.bar': createStateEntity({ state: 'off' }), + }), + createHASS({ + 'binary_sensor.foo': createStateEntity({ state: 'on' }), + 'binary_sensor.bar': createStateEntity({ state: 'on' }), + }), + ); + + expect(callback).toBeCalledTimes(1); + expect(callback).toBeCalledWith( + expect.objectContaining({ + entityID: 'binary_sensor.bar', + oldState: createStateEntity({ state: 'off' }), + newState: createStateEntity({ state: 'on' }), + }), + ); + }); + + it('should not call back without state change', () => { + const stateWatcher = new StateWatcher(); + const callback = vi.fn(); + expect(stateWatcher.subscribe(callback, ['binary_sensor.foo'])).toBeTruthy(); + + stateWatcher.setHASS( + null, + createHASS({ + 'binary_sensor.foo': createStateEntity({ state: 'on' }), + }), + ); + + expect(callback).not.toBeCalled(); + + stateWatcher.setHASS( + createHASS({ + 'binary_sensor.foo': createStateEntity({ state: 'on' }), + }), + createHASS({ + 'binary_sensor.foo': createStateEntity({ state: 'on' }), + }), + ); + + expect(callback).not.toBeCalled(); + }); + + it('should not call back when unsubscribed', () => { + const stateWatcher = new StateWatcher(); + const callback = vi.fn(); + expect(stateWatcher.subscribe(callback, ['binary_sensor.foo'])).toBeTruthy(); + expect(stateWatcher.unsubscribe(callback)); + + stateWatcher.setHASS( + null, + createHASS({ + 'binary_sensor.foo': createStateEntity({ state: 'on' }), + }), + ); + + expect(callback).not.toBeCalled(); + + stateWatcher.setHASS( + createHASS({ + 'binary_sensor.foo': createStateEntity({ state: 'on' }), + }), + createHASS({ + 'binary_sensor.foo': createStateEntity({ state: 'off' }), + }), + ); + + expect(callback).not.toBeCalled(); + }); +}); diff --git a/tests/card-controller/message-manager.test.ts b/tests/card-controller/message-manager.test.ts index 658943d7..38283cae 100644 --- a/tests/card-controller/message-manager.test.ts +++ b/tests/card-controller/message-manager.test.ts @@ -144,6 +144,22 @@ describe('MessageManager', () => { expect(consoleSpy).toBeCalled(); }); + it('should set error with prefix', () => { + const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined); + + const api = createCardAPI(); + const manager = new MessageManager(api); + + manager.setErrorIfHigherPriority(new Error('generic error message'), 'PREFIX'); + expect(manager.hasMessage()).toBeTruthy(); + expect(manager.getMessage()).toEqual({ + message: 'PREFIX: generic error message', + type: 'error', + }); + + expect(consoleSpy).toBeCalled(); + }); + it('should not set unknown error type', () => { const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined); diff --git a/tests/test-utils.ts b/tests/test-utils.ts index e5d017aa..31d705af 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -1,8 +1,4 @@ -import { - CurrentUser, - HASSDomEvent, - HomeAssistant, -} from '@dermotduffy/custom-card-helpers'; +import { CurrentUser, HASSDomEvent } from '@dermotduffy/custom-card-helpers'; import { HassEntities, HassEntity } from 'home-assistant-js-websocket'; import { LitElement } from 'lit'; import { expect, vi } from 'vitest'; @@ -29,7 +25,8 @@ import { DefaultManager } from '../src/card-controller/default-manager'; import { DownloadManager } from '../src/card-controller/download-manager'; import { ExpandManager } from '../src/card-controller/expand-manager'; import { FullscreenManager } from '../src/card-controller/fullscreen-manager'; -import { HASSManager } from '../src/card-controller/hass-manager'; +import { HASSManager } from '../src/card-controller/hass/hass-manager'; +import { StateWatcherSubscriptionInterface } from '../src/card-controller/hass/state-watcher'; import { InitializationManager } from '../src/card-controller/initialization-manager'; import { InteractionManager } from '../src/card-controller/interaction-manager'; import { KeyboardStateManager } from '../src/card-controller/keyboard-state-manager'; @@ -57,6 +54,7 @@ import { performanceConfigSchema, } from '../src/config/types'; import { CapabilitiesRaw, ExtendedHomeAssistant, MediaLoadedInfo } from '../src/types'; +import { HassStateDifference } from '../src/utils/ha'; import { EntityRegistryManager } from '../src/utils/ha/entity-registry'; import { Entity } from '../src/utils/ha/entity-registry/types'; import { ViewMedia, ViewMediaType } from '../src/view/media'; @@ -213,7 +211,11 @@ export const createStore = ( const eventCallback = cameraProps.eventCallback ?? vi.fn(); const camera = new Camera( cameraProps.config ?? createCameraConfig(), - cameraProps.engine ?? new GenericCameraManagerEngine(eventCallback), + cameraProps.engine ?? + new GenericCameraManagerEngine( + mock(), + eventCallback, + ), { capabilities: cameraProps.capabilities === undefined @@ -464,14 +466,14 @@ export const createCardAPI = (): CardController => { return api; }; -export const callHASubscribeMessageHandler = ( - hass: HomeAssistant, - ev: unknown, +export const callStateWatcherCallback = ( + stateWatcher: StateWatcherSubscriptionInterface, + diff: HassStateDifference, n = 0, ): void => { - const mock = vi.mocked(hass.connection.subscribeMessage).mock; + const mock = vi.mocked(stateWatcher.subscribe).mock; expect(mock.calls.length).greaterThan(n); - mock.calls[n][0](ev); + mock.calls[n][0](diff); }; /** diff --git a/tests/utils/basic.test.ts b/tests/utils/basic.test.ts index 79188997..81f6ff39 100644 --- a/tests/utils/basic.test.ts +++ b/tests/utils/basic.test.ts @@ -103,36 +103,40 @@ describe('contentsChanged', () => { describe('errorToConsole', () => { const spy = vi.spyOn(global.console, 'warn').mockImplementation(() => true); + afterAll(() => { + vi.restoreAllMocks(); + }); + it('should log given error', () => { - const error = new Error(); + const error = new Error('ERROR'); errorToConsole(error); - expect(spy).toHaveBeenCalledWith(error); + expect(spy).toHaveBeenCalledWith('ERROR'); }); it('should log with context given frigate card error', () => { const data = { foo: 2 }; - const error = new FrigateCardError('foo', { foo: 2 }); + const error = new FrigateCardError('ERROR', { foo: 2 }); errorToConsole(error); expect(spy).toHaveBeenCalledWith(error, data); }); it('should log with custom function', () => { const func = vi.fn(); - const error = new Error(); + const error = new Error('ERROR'); errorToConsole(error, func); - expect(func).toHaveBeenCalledWith(error); + expect(func).toHaveBeenCalledWith('ERROR'); }); }); describe('isHoverableDevice', () => { + afterAll(() => { + vi.restoreAllMocks(); + }); + it('should return hoverable', () => { - const spy = vi - .spyOn(window, 'matchMedia') - .mockReturnValue({ matches: true }); + vi.spyOn(window, 'matchMedia').mockReturnValue({ matches: true }); expect(isHoverableDevice()).toBeTruthy(); }); it('should return not hoverable', () => { - const spy = vi - .spyOn(window, 'matchMedia') - .mockReturnValue({ matches: false }); + vi.spyOn(window, 'matchMedia').mockReturnValue({ matches: false }); expect(isHoverableDevice()).toBeFalsy(); }); }); @@ -225,6 +229,7 @@ describe('sleep', () => { it('should sleep', async () => { const spy = vi .spyOn(global, 'setTimeout') + // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-explicit-any .mockImplementation((func: () => unknown, _time?: number): any => { func(); }); diff --git a/tests/utils/ha/index.test.ts b/tests/utils/ha/index.test.ts index 8c25a4f8..823f7ead 100644 --- a/tests/utils/ha/index.test.ts +++ b/tests/utils/ha/index.test.ts @@ -1,10 +1,8 @@ import { HomeAssistant } from '@dermotduffy/custom-card-helpers'; -import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { getEntityIcon, hasHAConnectionStateChanged, - parseStateChangeTrigger, - subscribeToTrigger, } from '../../../src/utils/ha/index.js'; import { createHASS, createStateEntity } from '../../test-utils.js'; @@ -69,105 +67,3 @@ describe('getEntityIcon', () => { expect(getEntityIcon(createHASS(), 'camera.test')).toBe('mdi:video'); }); }); - -describe('should subscribe to trigger', () => { - it('mqtt', async () => { - const hass = createHASS(); - const callback = vi.fn(); - - await subscribeToTrigger(hass, callback, { - platform: 'mqtt', - topic: 'topic', - payload: 'payload', - valueTemplate: 'value_template', - }); - - expect(hass.connection.subscribeMessage).toBeCalledWith(callback, { - type: 'subscribe_trigger', - trigger: { - platform: 'mqtt', - topic: 'topic', - payload: 'payload', - value_template: 'value_template', - }, - }); - }); - - it('state and attributes', async () => { - const hass = createHASS(); - const callback = vi.fn(); - - await subscribeToTrigger(hass, callback, { - platform: 'state', - entityID: 'camera.foo', - }); - - expect(hass.connection.subscribeMessage).toBeCalledWith(callback, { - type: 'subscribe_trigger', - trigger: { - platform: 'state', - entity_id: 'camera.foo', - }, - }); - }); - - it('state only', async () => { - const hass = createHASS(); - const callback = vi.fn(); - - await subscribeToTrigger(hass, callback, { - platform: 'state', - entityID: 'camera.foo', - stateOnly: true, - }); - - expect(hass.connection.subscribeMessage).toBeCalledWith(callback, { - type: 'subscribe_trigger', - trigger: { - platform: 'state', - entity_id: 'camera.foo', - from: null, - to: null, - }, - }); - }); -}); - -describe('should parse state change response', () => { - beforeEach(() => { - vi.restoreAllMocks(); - }); - - it('malformed response', async () => { - const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined); - - expect(parseStateChangeTrigger('INVALID')).toBeNull(); - - expect(consoleSpy).toBeCalledWith('Ignoring unparseable HA state change', 'INVALID'); - }); - - it('valid response', async () => { - const consoleSpy = vi.spyOn(global.console, 'warn').mockReturnValue(undefined); - - const stateChange = { - from_state: { - entity_id: 'camera.foo', - state: 'off', - }, - to_state: { - entity_id: 'camera.foo', - state: 'on', - }, - }; - - expect( - parseStateChangeTrigger({ - variables: { - trigger: stateChange, - }, - }), - ).toEqual(stateChange); - - expect(consoleSpy).not.toBeCalled(); - }); -}); From ca405e9e3ead3b398b1cd1a7627e1b422fc5b8ef Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 26 Aug 2024 12:40:29 -0700 Subject: [PATCH 165/189] Fix query adopt bug. --- src/card-controller/view/factory.ts | 11 ++- src/view/media-queries-classifier.ts | 26 ++++++ src/view/view-to-cameras.ts | 21 +++-- tests/card-controller/view/factory.test.ts | 9 +- tests/view/media-queries-classifier.test.ts | 91 +++++++++++++++++++++ 5 files changed, 147 insertions(+), 11 deletions(-) diff --git a/src/card-controller/view/factory.ts b/src/card-controller/view/factory.ts index 9f43d5f3..5a0f6b8e 100644 --- a/src/card-controller/view/factory.ts +++ b/src/card-controller/view/factory.ts @@ -7,6 +7,7 @@ import { } from '../../config/types'; import { localize } from '../../localize/localize'; import { ClipsOrSnapshotsOrAll } from '../../types'; +import { MediaQueriesClassifier } from '../../view/media-queries-classifier'; import { View, ViewParameters } from '../../view/view'; import { getCameraIDsForViewName } from '../../view/view-to-cameras'; import { CardViewAPI } from '../types'; @@ -221,7 +222,15 @@ export class ViewFactory { const switchingToGalleryFromViewer = baseView?.isViewerView() && view.isGalleryView(); - if (switchingToGalleryFromViewer && baseView?.query && baseView?.queryResults) { + const alreadyHasMatchingQuery = + mediaType === MediaQueriesClassifier.getMediaType(baseView?.query); + + if ( + switchingToGalleryFromViewer && + alreadyHasMatchingQuery && + baseView?.query && + baseView?.queryResults + ) { // If the user is currently using the viewer, and then switches to the // gallery we make an attempt to keep the query/queryResults the same so // the gallery can be used to click back and forth to the viewer, and the diff --git a/src/view/media-queries-classifier.ts b/src/view/media-queries-classifier.ts index 9c35cb23..4a6dd0b4 100644 --- a/src/view/media-queries-classifier.ts +++ b/src/view/media-queries-classifier.ts @@ -1,6 +1,8 @@ import { EventMediaQueries, MediaQueries, RecordingMediaQueries } from './media-queries'; export type MediaQueriesType = 'event' | 'recording'; +type MediaType = 'clips' | 'snapshots' | 'recordings'; + export class MediaQueriesClassifier { public static areEventQueries( queries?: MediaQueries | null, @@ -14,6 +16,20 @@ export class MediaQueriesClassifier { return queries instanceof RecordingMediaQueries; } + public static areClipsQueries(queries?: MediaQueries | null): boolean { + return ( + this.areEventQueries(queries) && + !!queries?.getQueries()?.every((query) => query.hasClip) + ); + } + + public static areSnapshotQueries(queries?: MediaQueries | null): boolean { + return ( + this.areEventQueries(queries) && + !!queries?.getQueries()?.every((query) => query.hasSnapshot) + ); + } + public static getQueriesType(queries?: MediaQueries | null): MediaQueriesType | null { return this.areEventQueries(queries) ? 'event' @@ -21,4 +37,14 @@ export class MediaQueriesClassifier { ? 'recording' : null; } + + public static getMediaType(queries?: MediaQueries | null): MediaType | null { + return this.areClipsQueries(queries) + ? 'clips' + : this.areSnapshotQueries(queries) + ? 'snapshots' + : this.areRecordingQueries(queries) + ? 'recordings' + : null; + } } diff --git a/src/view/view-to-cameras.ts b/src/view/view-to-cameras.ts index 449f13f7..2efbf40b 100644 --- a/src/view/view-to-cameras.ts +++ b/src/view/view-to-cameras.ts @@ -1,4 +1,5 @@ import { CameraManager } from '../camera-manager/manager'; +import { CapabilitySearchOptions } from '../camera-manager/types'; import { FrigateCardView } from '../config/types'; /** @@ -10,6 +11,10 @@ export const getCameraIDsForViewName = ( viewName: FrigateCardView, cameraID?: string, ): Set => { + const capabilityMatchAnyMedia: CapabilitySearchOptions = { + anyCapabilities: ['clips', 'snapshots', 'recordings'], + }; + switch (viewName) { case 'image': case 'diagnostics': @@ -35,17 +40,15 @@ export const getCameraIDsForViewName = ( : cameraManager.getStore().getCameraIDsWithCapability(capability); case 'timeline': - return cameraManager.getStore().getCameraIDsWithCapability({ - anyCapabilities: ['clips', 'snapshots', 'recordings'], - }); + return cameraManager + .getStore() + .getCameraIDsWithCapability(capabilityMatchAnyMedia); case 'media': return cameraID - ? cameraManager.getStore().getAllDependentCameras(cameraID, { - anyCapabilities: ['clips', 'snapshots', 'recordings'], - }) - : cameraManager.getStore().getCameraIDsWithCapability({ - anyCapabilities: ['clips', 'snapshots', 'recordings'], - }); + ? cameraManager + .getStore() + .getAllDependentCameras(cameraID, capabilityMatchAnyMedia) + : cameraManager.getStore().getCameraIDsWithCapability(capabilityMatchAnyMedia); } }; diff --git a/tests/card-controller/view/factory.test.ts b/tests/card-controller/view/factory.test.ts index 7e84115c..b837e39b 100644 --- a/tests/card-controller/view/factory.test.ts +++ b/tests/card-controller/view/factory.test.ts @@ -1,5 +1,6 @@ import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest'; import { mock } from 'vitest-mock-extended'; +import { QueryType } from '../../../src/camera-manager/types'; import { ViewFactory } from '../../../src/card-controller/view/factory'; import { QueryExecutor } from '../../../src/card-controller/view/query-executor'; import { ViewModifier } from '../../../src/card-controller/view/types'; @@ -618,7 +619,13 @@ describe('getViewByParametersWithNewQuery', () => { const baseView = new View({ view: 'media', camera: 'camera.office', - query: new EventMediaQueries(), + query: new EventMediaQueries([ + { + type: QueryType.Event, + cameraIDs: new Set(['camera.office']), + hasClip: true, + }, + ]), queryResults: new MediaQueriesResults(), }); diff --git a/tests/view/media-queries-classifier.test.ts b/tests/view/media-queries-classifier.test.ts index 0b96608b..0b2fe4ba 100644 --- a/tests/view/media-queries-classifier.test.ts +++ b/tests/view/media-queries-classifier.test.ts @@ -1,6 +1,7 @@ import { describe, expect, it } from 'vitest'; import { EventMediaQueries, RecordingMediaQueries } from '../../src/view/media-queries'; import { MediaQueriesClassifier } from '../../src/view/media-queries-classifier'; +import { QueryType } from '../../src/camera-manager/types'; describe('MediaQueriesClassifier', () => { it('areEventQueries', () => { @@ -26,4 +27,94 @@ describe('MediaQueriesClassifier', () => { ); expect(MediaQueriesClassifier.getQueriesType()).toBeNull(); }); + + it('areClipsQueries', () => { + expect( + MediaQueriesClassifier.areClipsQueries( + new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, + ]), + ), + ).toBeTruthy(); + expect( + MediaQueriesClassifier.areClipsQueries( + new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: false }, + ]), + ), + ).toBeFalsy(); + expect( + MediaQueriesClassifier.areClipsQueries( + new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, + { type: QueryType.Event, cameraIDs: new Set(['camera']) }, + ]), + ), + ).toBeFalsy(); + }); + + it('areSnapshotQueries', () => { + expect( + MediaQueriesClassifier.areSnapshotQueries( + new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasSnapshot: true }, + ]), + ), + ).toBeTruthy(); + expect( + MediaQueriesClassifier.areSnapshotQueries( + new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasSnapshot: true }, + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasSnapshot: false }, + ]), + ), + ).toBeFalsy(); + expect( + MediaQueriesClassifier.areSnapshotQueries( + new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasSnapshot: true }, + { type: QueryType.Event, cameraIDs: new Set(['camera']) }, + ]), + ), + ).toBeFalsy(); + }); + + it('getMediaType', () => { + expect( + MediaQueriesClassifier.getMediaType( + new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasSnapshot: true }, + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasSnapshot: true }, + ]), + ), + ).toBe('snapshots'); + + expect( + MediaQueriesClassifier.getMediaType( + new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasClip: true }, + ]), + ), + ).toBe('clips'); + + expect( + MediaQueriesClassifier.getMediaType( + new RecordingMediaQueries([ + { type: QueryType.Recording, cameraIDs: new Set(['camera']) }, + { type: QueryType.Recording, cameraIDs: new Set(['camera']) }, + ]), + ), + ).toBe('recordings'); + + expect( + MediaQueriesClassifier.getMediaType( + new EventMediaQueries([ + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasSnapshot: true }, + { type: QueryType.Event, cameraIDs: new Set(['camera']), hasSnapshot: false }, + ]), + ), + ).toBeNull(); + }); }); From 09a15ab785d6865cb96ba367540f59a9d44c8b37 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 26 Aug 2024 13:10:19 -0700 Subject: [PATCH 166/189] Fix recording timezone issue. --- src/camera-manager/frigate/requests.ts | 10 ++++++++-- tests/camera-manager/frigate/requests.test.ts | 8 ++++++-- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/camera-manager/frigate/requests.ts b/src/camera-manager/frigate/requests.ts index c019f934..c378c5e4 100644 --- a/src/camera-manager/frigate/requests.ts +++ b/src/camera-manager/frigate/requests.ts @@ -36,7 +36,10 @@ export const getRecordingsSummary = async ( type: 'frigate/recordings/summary', instance_id: clientID, camera: camera_name, - timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + + // Ask for the summary relative to HA timezone + // See: https://github.com/dermotduffy/frigate-hass-card/issues/1267 + timezone: hass.config.time_zone, }, true, // See: https://github.com/colinhacks/zod/pull/1752 @@ -148,7 +151,10 @@ export const getEventSummary = async ( { type: 'frigate/events/summary', instance_id: clientID, - timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + + // Ask for the summary relative to HA timezone + // See: https://github.com/dermotduffy/frigate-hass-card/issues/1267 + timezone: hass.config.time_zone, }, true, ); diff --git a/tests/camera-manager/frigate/requests.test.ts b/tests/camera-manager/frigate/requests.test.ts index 461c1df2..89873775 100644 --- a/tests/camera-manager/frigate/requests.test.ts +++ b/tests/camera-manager/frigate/requests.test.ts @@ -34,6 +34,8 @@ describe('frigate requests', () => { day: new Date(), }; const hass = createHASS(); + hass.config.time_zone = 'Europe/Dublin'; + vi.mocked(homeAssistantWSRequest).mockResolvedValue(recordingSummary); expect(await getRecordingsSummary(hass, 'clientID', 'camera.office')).toBe( recordingSummary, @@ -45,7 +47,7 @@ describe('frigate requests', () => { type: 'frigate/recordings/summary', instance_id: 'clientID', camera: 'camera.office', - timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + timezone: 'Europe/Dublin', }), true, ); @@ -179,6 +181,8 @@ describe('frigate requests', () => { }, ]; const hass = createHASS(); + hass.config.time_zone = 'Europe/Dublin'; + vi.mocked(homeAssistantWSRequest).mockResolvedValue(eventSummary); expect(await getEventSummary(hass, 'clientID')).toBe(eventSummary); expect(homeAssistantWSRequest).toBeCalledWith( @@ -187,7 +191,7 @@ describe('frigate requests', () => { expect.objectContaining({ type: 'frigate/events/summary', instance_id: 'clientID', - timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + timezone: 'Europe/Dublin', }), true, ); From 91ffe0656bb0316d3940d26f912b96a68eecaaea Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 26 Aug 2024 14:35:16 -0700 Subject: [PATCH 167/189] Don't run automations prior to initialization . --- src/card-controller/automations-manager.ts | 15 ++++--- src/card-controller/hass/hass-manager.ts | 4 ++ src/card-controller/types.ts | 1 + .../automations-manager.test.ts | 41 ++++++++++++++++--- .../card-controller/hass/hass-manager.test.ts | 10 +++++ 5 files changed, 60 insertions(+), 11 deletions(-) diff --git a/src/card-controller/automations-manager.ts b/src/card-controller/automations-manager.ts index dbc38abb..367a7f5c 100644 --- a/src/card-controller/automations-manager.ts +++ b/src/card-controller/automations-manager.ts @@ -27,11 +27,16 @@ export class AutomationsManager { } public execute(): void { - const hass = this._api.getHASSManager().getHASS(); - - // Never execute automations if there's an error (as our automation loop - // avoidance -- which shows as an error -- would not work!). - if (!hass || this._api.getMessageManager().hasErrorMessage()) { + if ( + !this._api.getHASSManager().hasHASS() || + // Never execute automations if the card hasn't finished initializing, as + // it could cause a view change when camera loads are not finished. + // See: https://github.com/dermotduffy/frigate-hass-card/issues/1407 + !this._api.getInitializationManager().isInitializedMandatory() || + // Never execute automations if there's an error (as our automation loop + // avoidance -- which shows as an error -- would not work!). + this._api.getMessageManager().hasErrorMessage() + ) { return; } diff --git a/src/card-controller/hass/hass-manager.ts b/src/card-controller/hass/hass-manager.ts index a0ea929f..86ce88eb 100644 --- a/src/card-controller/hass/hass-manager.ts +++ b/src/card-controller/hass/hass-manager.ts @@ -17,6 +17,10 @@ export class HASSManager { return this._hass; } + public hasHASS(): boolean { + return !!this._hass; + } + public getStateWatcher(): StateWatcherSubscriptionInterface { return this._stateWatcher; } diff --git a/src/card-controller/types.ts b/src/card-controller/types.ts index 5dd754d6..834d7f8a 100644 --- a/src/card-controller/types.ts +++ b/src/card-controller/types.ts @@ -59,6 +59,7 @@ export interface CardAutomationsAPI { getCardElementManager(): CardElementManager; getConditionsManager(): ConditionsManager; getHASSManager(): HASSManager; + getInitializationManager(): InitializationManager; getMessageManager(): MessageManager; } diff --git a/tests/card-controller/automations-manager.test.ts b/tests/card-controller/automations-manager.test.ts index a60fa696..2f9d6d41 100644 --- a/tests/card-controller/automations-manager.test.ts +++ b/tests/card-controller/automations-manager.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; import { AutomationsManager } from '../../src/card-controller/automations-manager.js'; -import { createCardAPI, createHASS } from '../test-utils.js'; +import { createCardAPI } from '../test-utils.js'; import { ActionType } from '../../src/config/types.js'; import { AuxillaryActionConfig } from '../../src/card-controller/actions/types.js'; @@ -34,9 +34,25 @@ describe('AutomationsManager', () => { expect(api.getActionsManager().executeActions).not.toBeCalled(); }); + it('should do nothing without being initialized', () => { + const api = createCardAPI(); + vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(true); + vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue( + false, + ); + + const automationsManager = new AutomationsManager(api); + automationsManager.execute(); + + expect(api.getActionsManager().executeActions).not.toBeCalled(); + }); + it('should do nothing without automations', () => { const api = createCardAPI(); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(true); + vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue( + true, + ); const automationsManager = new AutomationsManager(api); automationsManager.execute(); @@ -46,7 +62,10 @@ describe('AutomationsManager', () => { it('should execute actions', () => { const api = createCardAPI(); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(true); + vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue( + true, + ); const automationsManager = new AutomationsManager(api); automationsManager.addAutomations([automation]); @@ -77,7 +96,11 @@ describe('AutomationsManager', () => { it('should execute actions_not', () => { const api = createCardAPI(); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(true); + vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue( + true, + ); + vi.mocked(api.getConditionsManager().evaluateConditions).mockReturnValue(false); const automationsManager = new AutomationsManager(api); @@ -90,7 +113,10 @@ describe('AutomationsManager', () => { it('should prevent automation loops', () => { const api = createCardAPI(); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(true); + vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue( + true, + ); const automationsManager = new AutomationsManager(api); automationsManager.addAutomations([automation, not_automation]); @@ -130,7 +156,10 @@ describe('AutomationsManager', () => { it('should delete automations', () => { const api = createCardAPI(); - vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + vi.mocked(api.getHASSManager().hasHASS).mockReturnValue(true); + vi.mocked(api.getInitializationManager().isInitializedMandatory).mockReturnValue( + true, + ); const automationsManager = new AutomationsManager(api); automationsManager.addAutomations([automation]); diff --git a/tests/card-controller/hass/hass-manager.test.ts b/tests/card-controller/hass/hass-manager.test.ts index f4051d31..181a2799 100644 --- a/tests/card-controller/hass/hass-manager.test.ts +++ b/tests/card-controller/hass/hass-manager.test.ts @@ -21,6 +21,7 @@ describe('HASSManager', () => { it('should have null hass on construction', () => { const manager = new HASSManager(createCardAPI()); expect(manager.getHASS()).toBeNull(); + expect(manager.hasHASS()).toBeFalsy(); }); it('should get state watcher', () => { @@ -28,6 +29,15 @@ describe('HASSManager', () => { expect(manager.getStateWatcher()).toEqual(expect.any(StateWatcher)); }); + it('should get hass after set', () => { + const manager = new HASSManager(createCardAPI()); + const hass = createHASS(); + manager.setHASS(hass); + + expect(manager.getHASS()).toBe(hass); + expect(manager.hasHASS()).toBeTruthy(); + }); + it('should set light or dark mode upon setting hass', () => { const api = createCardAPI(); const manager = new HASSManager(api); From 4712a320b8c263b03a1d01969365bad6adbe5469 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 26 Aug 2024 16:36:44 -0700 Subject: [PATCH 168/189] Fix auto media action problem . --- src/components-lib/live/live-controller.ts | 3 +++ .../plugins/auto-media-actions/auto-media-actions.ts | 12 ++++++------ tests/components-lib/live/live-controller.test.ts | 1 + 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/components-lib/live/live-controller.ts b/src/components-lib/live/live-controller.ts index e7037feb..b7fa45c6 100644 --- a/src/components-lib/live/live-controller.ts +++ b/src/components-lib/live/live-controller.ts @@ -50,6 +50,9 @@ export class LiveController implements ReactiveController { constructor(host: LiveControllerHost) { this._host = host; + + host.addController(this); + this._intersectionObserver = new IntersectionObserver( this._intersectionHandler.bind(this), ); diff --git a/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts b/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts index 9086cf62..2ed70429 100644 --- a/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts +++ b/src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts @@ -50,7 +50,7 @@ export function AutoMediaActions( let options: OptionsType; let emblaApi: EmblaCarouselType; let slides: HTMLElement[]; - let containerIntersecting: boolean | null = null; + let viewportIntersecting: boolean | null = null; const microphoneMuteTimer = new Timer(); const intersectionObserver: IntersectionObserver = new IntersectionObserver( @@ -92,7 +92,7 @@ export function AutoMediaActions( emblaApi.on('destroy', mute); document.addEventListener('visibilitychange', visibilityHandler); - intersectionObserver.observe(emblaApi.containerNode()); + intersectionObserver.observe(emblaApi.rootNode()); if ( options.autoUnmuteConditions?.includes('microphone') || @@ -184,14 +184,14 @@ export function AutoMediaActions( } function intersectionHandler(entries: IntersectionObserverEntry[]): void { - const wasIntersecting = containerIntersecting; - containerIntersecting = entries.some((entry) => entry.isIntersecting); + const wasIntersecting = viewportIntersecting; + viewportIntersecting = entries.some((entry) => entry.isIntersecting); - if (wasIntersecting !== null && wasIntersecting !== containerIntersecting) { + if (wasIntersecting !== null && wasIntersecting !== viewportIntersecting) { // If the live view is preloaded (i.e. in the background) we may need to // take media actions, e.g. muting a live stream that is now running in // the background, so we act even if the new state is hidden. - actOnVisibilityChange(containerIntersecting); + actOnVisibilityChange(viewportIntersecting); } } diff --git a/tests/components-lib/live/live-controller.test.ts b/tests/components-lib/live/live-controller.test.ts index 85fd3b31..c942b786 100644 --- a/tests/components-lib/live/live-controller.test.ts +++ b/tests/components-lib/live/live-controller.test.ts @@ -29,6 +29,7 @@ describe('LiveController', () => { parent.addEventListener('frigate-card:message', eventListener); const controller = new LiveController(host); + expect(host.addController).toBeCalled(); controller.hostConnected(); From 0403441e079658779d4883ae82223eaa9ee40a23 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 26 Aug 2024 19:57:55 -0700 Subject: [PATCH 169/189] Add max_simultaneous_engine_requests parameter --- docs/configuration/performance.md | 10 ++++++---- src/camera-manager/manager.ts | 23 +++++++++++++++++++---- src/config/profiles/low-performance.ts | 4 ++++ src/config/types.ts | 1 + src/const.ts | 1 + src/editor.ts | 7 +++++++ src/localize/languages/ca.json | 1 + src/localize/languages/en.json | 1 + src/localize/languages/fr.json | 1 + src/localize/languages/it.json | 1 + src/localize/languages/pt-BR.json | 1 + src/localize/languages/pt-PT.json | 1 + 12 files changed, 44 insertions(+), 8 deletions(-) diff --git a/docs/configuration/performance.md b/docs/configuration/performance.md index 9590a07c..f0597905 100644 --- a/docs/configuration/performance.md +++ b/docs/configuration/performance.md @@ -22,10 +22,11 @@ performance: # [...] ``` -| Option | Default | Description | -| ----------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `animated_progress_indicator` | `true` | Will show the animated progress indicator 'spinner' when `true` or a simple loading icon when `false`. | -| `media_chunk_size` | `50` | How many media items to fetch and render at a time (e.g. thumbnails under a live view, or number of snapshots to load in the media viewer). This may only make partial sense in some contexts (e.g. the 'infinite gallery' is still infinite, it just loads thumbnails this many items at a time) or not at all (e.g. the timeline will show the number of events dictated by the time span the user navigates to). | +| Option | Default | Description | +| ---------------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `animated_progress_indicator` | `true` | Will show the animated progress indicator 'spinner' when `true` or a simple loading icon when `false`. | +| `media_chunk_size` | `50` | How many media items to fetch and render at a time (e.g. thumbnails under a live view, or number of snapshots to load in the media viewer). This may only make partial sense in some contexts (e.g. the 'infinite gallery' is still infinite, it just loads thumbnails this many items at a time) or not at all (e.g. the timeline will show the number of events dictated by the time span the user navigates to). | +| `max_simultaneous_engine_requests` | _Infinity_ | How many camera engine requests to allow occur in parallel. Setting lower values will slow the card down since more requests will run in sequence, but it will increase the chances of positive cache hit rates and reduce the chances of overwhelming the backend. | ### `style` @@ -59,6 +60,7 @@ performance: features: animated_progress_indicator: true media_chunk_size: 50 + max_simultaneous_engine_requests: 100 style: border_radius: true box_shadow: true diff --git a/src/camera-manager/manager.ts b/src/camera-manager/manager.ts index 71ba9d4f..93dd9a3b 100644 --- a/src/camera-manager/manager.ts +++ b/src/camera-manager/manager.ts @@ -112,6 +112,7 @@ export class CameraManager { protected _engineFactory: CameraManagerEngineFactory; protected _store: CameraManagerStore; protected _initializationLimit = new PQueue({ concurrency: 1 }); + protected _requestLimit = new PQueue(); constructor( api: CardCameraAPI, @@ -135,6 +136,9 @@ export class CameraManager { return false; } + this._requestLimit.concurrency = + config.performance.features.max_simultaneous_engine_requests ?? Infinity; + // For each camera merge the config (which has no defaults) into the camera // global config (which does have defaults). The merging must happen in this // order, to ensure that the defaults in the cameras global config do not @@ -535,7 +539,10 @@ export class CameraManager { } const queryStartTime = new Date(); - await engine.favoriteMedia(hass, cameraConfig, media, favorite); + + await this._requestLimit.add(() => + engine.favoriteMedia(hass, cameraConfig, media, favorite), + ); log( this._api.getConfigManager().getCardWideConfig(), @@ -590,7 +597,11 @@ export class CameraManager { return null; } - return await engine.getMediaSeekTime(hass, this._store, media, target); + return ( + (await this._requestLimit.add(() => + engine.getMediaSeekTime(hass, this._store, media, target), + )) ?? null + ); } protected async _handleQuery( @@ -653,7 +664,9 @@ export class CameraManager { } await Promise.all( Array.from(engines.keys()).map((engine) => - processEngineQuery(engine, { ...query, cameraIDs: engines.get(engine) }), + this._requestLimit.add(() => + processEngineQuery(engine, { ...query, cameraIDs: engines.get(engine) }), + ), ), ); }; @@ -789,6 +802,8 @@ export class CameraManager { if (!engine || !hass) { return; } - return await engine.executePTZAction(hass, cameraConfig, action, options); + return await this._requestLimit.add(() => + engine.executePTZAction(hass, cameraConfig, action, options), + ); } } diff --git a/src/config/profiles/low-performance.ts b/src/config/profiles/low-performance.ts index 2ee9d8cf..6bd8a49e 100644 --- a/src/config/profiles/low-performance.ts +++ b/src/config/profiles/low-performance.ts @@ -35,6 +35,7 @@ import { CONF_MENU_BUTTONS_TIMELINE, CONF_MENU_STYLE, CONF_PERFORMANCE_FEATURES_ANIMATED_PROGRESS_INDICATOR, + CONF_PERFORMANCE_FEATURES_MAX_SIMULTANEOUS_ENGINE_REQUESTS, CONF_PERFORMANCE_FEATURES_MEDIA_CHUNK_SIZE, CONF_PERFORMANCE_STYLE_BORDER_RADIUS, CONF_PERFORMANCE_STYLE_BOX_SHADOW, @@ -137,4 +138,7 @@ export const LOW_PERFORMANCE_PROFILE = { // No trigger actions. [CONF_VIEW_TRIGGERS_ACTIONS_TRIGGER]: 'none', + + // One engine request at a time. + [CONF_PERFORMANCE_FEATURES_MAX_SIMULTANEOUS_ENGINE_REQUESTS]: 1, }; diff --git a/src/config/types.ts b/src/config/types.ts index b5875991..2989e1ec 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -1913,6 +1913,7 @@ export const performanceConfigSchema = z .min(0) .max(MEDIA_CHUNK_SIZE_MAX) .default(performanceConfigDefault.features.media_chunk_size), + max_simultaneous_engine_requests: z.number().min(1).optional(), }) .default(performanceConfigDefault.features), style: z diff --git a/src/const.ts b/src/const.ts index 92d4045f..08783be4 100644 --- a/src/const.ts +++ b/src/const.ts @@ -348,6 +348,7 @@ export const CONF_OVERRIDES = 'overrides' as const; const CONF_PERFORMANCE = 'performance' as const; export const CONF_PERFORMANCE_FEATURES_ANIMATED_PROGRESS_INDICATOR = `${CONF_PERFORMANCE}.features.animated_progress_indicator`; export const CONF_PERFORMANCE_FEATURES_MEDIA_CHUNK_SIZE = `${CONF_PERFORMANCE}.features.media_chunk_size`; +export const CONF_PERFORMANCE_FEATURES_MAX_SIMULTANEOUS_ENGINE_REQUESTS = `${CONF_PERFORMANCE}.features.max_simultaneous_engine_requests`; export const CONF_PERFORMANCE_PROFILE = `${CONF_PERFORMANCE}.profile`; export const CONF_PERFORMANCE_STYLE_BOX_SHADOW = `${CONF_PERFORMANCE}.style.box_shadow`; export const CONF_PERFORMANCE_STYLE_BORDER_RADIUS = `${CONF_PERFORMANCE}.style.border_radius`; diff --git a/src/editor.ts b/src/editor.ts index 6e0e1059..cc2e8318 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -171,6 +171,7 @@ import { CONF_MENU_POSITION, CONF_MENU_STYLE, CONF_PERFORMANCE_FEATURES_ANIMATED_PROGRESS_INDICATOR, + CONF_PERFORMANCE_FEATURES_MAX_SIMULTANEOUS_ENGINE_REQUESTS, CONF_PERFORMANCE_FEATURES_MEDIA_CHUNK_SIZE, CONF_PERFORMANCE_PROFILE, CONF_PERFORMANCE_STYLE_BORDER_RADIUS, @@ -2790,6 +2791,12 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderNumberInput(CONF_PERFORMANCE_FEATURES_MEDIA_CHUNK_SIZE, { max: MEDIA_CHUNK_SIZE_MAX, })} + ${this._renderNumberInput( + CONF_PERFORMANCE_FEATURES_MAX_SIMULTANEOUS_ENGINE_REQUESTS, + { + min: 1, + }, + )} `, )} ${this._putInSubmenu( diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json index efb70f05..27a008ef 100644 --- a/src/localize/languages/ca.json +++ b/src/localize/languages/ca.json @@ -401,6 +401,7 @@ "features": { "animated_progress_indicator": "Indicador animat del progrés", "editor_label": "Opcions de característiques", + "max_simultaneous_engine_requests": "", "media_chunk_size": "Mida del fragment multimèdia" }, "style": { diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index dbb6703c..f2279649 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -401,6 +401,7 @@ "features": { "animated_progress_indicator": "Animated Progress Indicator", "editor_label": "Feature Options", + "max_simultaneous_engine_requests": "Max simultaneous camera engine requests", "media_chunk_size": "Media chunk size" }, "style": { diff --git a/src/localize/languages/fr.json b/src/localize/languages/fr.json index 567e431b..b41ebeaa 100644 --- a/src/localize/languages/fr.json +++ b/src/localize/languages/fr.json @@ -401,6 +401,7 @@ "features": { "animated_progress_indicator": "Indicateur de progression animé", "editor_label": "Options de fonctionnalités", + "max_simultaneous_engine_requests": "", "media_chunk_size": "Taille du morceau de média" }, "style": { diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 7876a92f..a87f9b75 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -401,6 +401,7 @@ "features": { "animated_progress_indicator": "Indicatore di avanzamento animato", "editor_label": "Opzioni funzionalità", + "max_simultaneous_engine_requests": "", "media_chunk_size": "Dimensione del blocco multimediale" }, "style": { diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index bd16f26b..2fac32db 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -401,6 +401,7 @@ "features": { "animated_progress_indicator": "Indicador de Carregamento Animado", "editor_label": "Opções de recursos", + "max_simultaneous_engine_requests": "", "media_chunk_size": "Tamanho do bloco de mídia" }, "style": { diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index ad342dea..7fdb3de5 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -401,6 +401,7 @@ "features": { "animated_progress_indicator": "Animação na barra de progresso", "editor_label": "Editor de etiquetas", + "max_simultaneous_engine_requests": "", "media_chunk_size": "Tamanho do ficheiro" }, "style": { From 76a750ff734aa669970e41927d4ed9454d3e084d Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 26 Aug 2024 20:08:59 -0700 Subject: [PATCH 170/189] Small test fixes. --- tests/camera-manager/manager.test.ts | 17 +++++++++++++++++ tests/config/profiles/low-performance.test.ts | 1 + 2 files changed, 18 insertions(+) diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts index 69a609c2..545235b3 100644 --- a/tests/camera-manager/manager.test.ts +++ b/tests/camera-manager/manager.test.ts @@ -1271,5 +1271,22 @@ describe('CameraManager', async () => { middleTime, ); }); + + it('handles null return value', async () => { + const api = createCardAPI(); + const engine = mock(); + vi.mocked(api.getHASSManager().getHASS).mockReturnValue(createHASS()); + const manager = createCameraManager(api, engine); + + expect(await manager.initializeCamerasFromConfig()).toBeTruthy(); + engine.getMediaSeekTime.mockResolvedValue(null); + + const media = new TestViewMedia({ + cameraID: 'id', + startTime: startTime, + endTime: endTime, + }); + expect(await manager.getMediaSeekTime(media, middleTime)).toBeNull(); + }); }); }); diff --git a/tests/config/profiles/low-performance.test.ts b/tests/config/profiles/low-performance.test.ts index 61c7f709..b491e186 100644 --- a/tests/config/profiles/low-performance.test.ts +++ b/tests/config/profiles/low-performance.test.ts @@ -39,6 +39,7 @@ it('low performance profile', () => { 'menu.buttons.timeline.enabled': false, 'menu.style': 'outside', 'performance.features.animated_progress_indicator': false, + 'performance.features.max_simultaneous_engine_requests': 1, 'performance.features.media_chunk_size': 10, 'performance.style.border_radius': false, 'performance.style.box_shadow': false, From 8344734e2b4b7873b8596ac7e611279aa76ae37b Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 26 Aug 2024 20:55:02 -0700 Subject: [PATCH 171/189] Remove optimization that caused scrubbing misbehavior --- src/components/timeline-core.ts | 7 ------- src/utils/basic.ts | 6 ++++-- tests/utils/basic.test.ts | 4 ++++ 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/components/timeline-core.ts b/src/components/timeline-core.ts index 502ac0cc..d204c58d 100644 --- a/src/components/timeline-core.ts +++ b/src/components/timeline-core.ts @@ -678,13 +678,6 @@ export class FrigateCardTimelineCore extends LitElement { query: mediaQuery, }, queryExecutorOptions: { - // Reject the new results unless there is something to be gained (i.e. they - // are not a subset of the existing results). Example usecase: On initial - // view load in mini timeline mode, the first 50 events are fetched -- the - // first drag of the timeline should not dispatch new results unless - // something is actually useful (as otherwise it creates a visible 'flicker' - // for the user as the viewer reloads all the media). - rejectResults: (results) => !!view.queryResults?.isSupersetOf(results), selectResult: { id: this.viewManagerEpoch?.manager diff --git a/src/utils/basic.ts b/src/utils/basic.ts index 36d5342e..e530849b 100644 --- a/src/utils/basic.ts +++ b/src/utils/basic.ts @@ -105,13 +105,15 @@ export function contentsChanged( * @param func The Console func to call. */ export function errorToConsole( - e: Error | { message: unknown }, + e: Error | { message: unknown } | string, func: CallableFunction = console.warn, ): void { if (e instanceof FrigateCardError && e.context) { func(e, e.context); - } else { + } else if (typeof e === 'object' && 'message' in e) { func(e.message); + } else { + func(e); } } diff --git a/tests/utils/basic.test.ts b/tests/utils/basic.test.ts index 81f6ff39..257bbe3c 100644 --- a/tests/utils/basic.test.ts +++ b/tests/utils/basic.test.ts @@ -124,6 +124,10 @@ describe('errorToConsole', () => { errorToConsole(error, func); expect(func).toHaveBeenCalledWith('ERROR'); }); + it('should log string', () => { + errorToConsole('string message'); + expect(spy).toHaveBeenCalledWith('string message'); + }); }); describe('isHoverableDevice', () => { From 1a0e219c61ac91f74858d2c86d06030f6172b828 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 7 Sep 2024 15:04:23 -0700 Subject: [PATCH 172/189] Move automatic media actions out of carousels --- rollup.config.js | 2 +- .../media-actions-controller.ts | 269 ++++++++ src/components/live/live.ts | 79 ++- src/components/viewer.ts | 64 +- src/config/types.ts | 6 +- src/scss/menu.scss | 8 + .../auto-media-actions/auto-media-actions.ts | 247 -------- .../auto-media-loaded-info.ts | 7 +- .../media-actions-controller.test.ts | 573 ++++++++++++++++++ tests/test-utils.ts | 29 +- tests/utils/embla/carousel-controller.test.ts | 2 +- .../auto-media-actions.test.ts | 455 -------------- tests/utils/embla/test-utils.ts | 20 +- ...get-state-obj.ts => get-state-obj.test.ts} | 0 vite.config.ts | 10 +- 15 files changed, 994 insertions(+), 777 deletions(-) create mode 100644 src/components-lib/media-actions-controller.ts delete mode 100644 src/utils/embla/plugins/auto-media-actions/auto-media-actions.ts create mode 100644 tests/components-lib/media-actions-controller.test.ts delete mode 100644 tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts rename tests/utils/{get-state-obj.ts => get-state-obj.test.ts} (100%) diff --git a/rollup.config.js b/rollup.config.js index be40c43a..faa6e37a 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -51,7 +51,7 @@ const plugins = [ typescript({ sourceMap: dev, inlineSources: dev, - exclude: ['tests/**/*.test.ts'], + exclude: ['dist/**', 'tests/**/*.test.ts'], }), json({ exclude: 'package.json' }), replace({ diff --git a/src/components-lib/media-actions-controller.ts b/src/components-lib/media-actions-controller.ts new file mode 100644 index 00000000..af998eb9 --- /dev/null +++ b/src/components-lib/media-actions-controller.ts @@ -0,0 +1,269 @@ +import { + MicrophoneManagerListenerChange, + ReadonlyMicrophoneManager, +} from '../card-controller/microphone-manager.js'; +import { + AutoMuteCondition, + AutoPauseCondition, + AutoPlayCondition, + AutoUnmuteCondition, +} from '../config/types.js'; +import { FrigateCardMediaPlayer } from '../types.js'; +import { FrigateCardMediaLoadedEventTarget } from '../utils/media-info.js'; +import { Timer } from '../utils/timer.js'; + +export interface MediaActionsControllerOptions { + playerSelector: string; + + autoPlayConditions?: readonly AutoPlayCondition[]; + autoUnmuteConditions?: readonly AutoUnmuteCondition[]; + autoPauseConditions?: readonly AutoPauseCondition[]; + autoMuteConditions?: readonly AutoMuteCondition[]; + + microphoneManager?: ReadonlyMicrophoneManager; + microphoneMuteSeconds?: number; +} + +type RenderRoot = HTMLElement & FrigateCardMediaLoadedEventTarget; +type PlayerElement = HTMLElement & FrigateCardMediaPlayer; + +/** + * General note: Always unmute before playing, since Chrome may pause a piece of + * media if the page hasn't been interacted with first, after unmute. By unmuting + * first, even if the unmute call fails a subsequent call to play will still + * start the video. + */ + +export class MediaActionsController { + protected _options: MediaActionsControllerOptions | null = null; + protected _viewportIntersecting: boolean | null = null; + protected _microphoneMuteTimer = new Timer(); + protected _root: RenderRoot | null = null; + + protected _eventListeners = new Map void>(); + protected _children: PlayerElement[] = []; + protected _selected: number | null = null; + protected _mutationObserver = new MutationObserver(this._mutationHandler.bind(this)); + protected _intersectionObserver = new IntersectionObserver( + this._intersectionHandler.bind(this), + ); + + public setOptions(options: MediaActionsControllerOptions): void { + this._options = options; + + if (this._options?.microphoneManager) { + this._options.microphoneManager.removeListener(this._microphoneChangeHandler); + this._options.microphoneManager.addListener(this._microphoneChangeHandler); + } + } + + public hasRoot(): boolean { + return !!this._root; + } + + public destroy(): void { + this._viewportIntersecting = null; + this._microphoneMuteTimer.stop(); + this._root = null; + this._removeChildHandlers(); + this._children = []; + this._selected = null; + this._mutationObserver.disconnect(); + this._intersectionObserver.disconnect(); + this._options?.microphoneManager?.removeListener(this._microphoneChangeHandler); + document.removeEventListener('visibilitychange', this._visibilityHandler); + } + + public async select(index: number): Promise { + if (this._selected === index) { + return; + } + if (this._selected !== null) { + await this.unselect(); + } + this._selected = index; + await this._unmuteSelectedIfConfigured('selected'); + await this._playSelectedIfConfigured('selected'); + } + + public async unselect(): Promise { + await this._pauseSelectedIfConfigured('unselected'); + await this._muteSelectedIfConfigured('unselected'); + this._microphoneMuteTimer.stop(); + this._selected = null; + } + + public async unselectAll(): Promise { + this._selected = null; + await this._pauseAllIfConfigured('unselected'); + await this._muteAllIfConfigured('unselected'); + } + + protected async _playSelectedIfConfigured( + condition: AutoPlayCondition, + ): Promise { + if ( + this._selected !== null && + this._options?.autoPlayConditions?.includes(condition) + ) { + await this._play(this._selected); + } + } + protected async _play(index: number): Promise { + await this._children[index]?.play(); + } + protected async _unmuteSelectedIfConfigured( + condition: AutoUnmuteCondition, + ): Promise { + if ( + this._selected !== null && + this._options?.autoUnmuteConditions?.includes(condition) + ) { + await this._unmute(this._selected); + } + } + protected async _unmute(index: number): Promise { + await this._children[index]?.unmute(); + } + + protected async _pauseAllIfConfigured(condition: AutoPauseCondition): Promise { + if (this._options?.autoPauseConditions?.includes(condition)) { + for (const index of this._children.keys()) { + await this._pause(index); + } + } + } + protected async _pauseSelectedIfConfigured( + condition: AutoPauseCondition, + ): Promise { + if ( + this._selected !== null && + this._options?.autoPauseConditions?.includes(condition) + ) { + await this._pause(this._selected); + } + } + protected async _pause(index: number): Promise { + await this._children[index]?.pause(); + } + + protected async _muteAllIfConfigured(condition: AutoMuteCondition): Promise { + if (this._options?.autoMuteConditions?.includes(condition)) { + for (const index of this._children.keys()) { + await this._mute(index); + } + } + } + protected async _muteSelectedIfConfigured( + condition: AutoMuteCondition, + ): Promise { + if ( + this._selected !== null && + this._options?.autoMuteConditions?.includes(condition) + ) { + await this._mute(this._selected); + } + } + protected async _mute(index: number): Promise { + await this._children[index]?.mute(); + } + + protected _mutationHandler( + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _mutations: MutationRecord[], + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _observer: MutationObserver, + ): void { + this._initializeRoot(); + } + + protected _mediaLoadedHandler = async (index: number): Promise => { + if (this._selected !== index) { + return; + } + await this._unmuteSelectedIfConfigured('selected'); + await this._playSelectedIfConfigured('selected'); + }; + + protected _removeChildHandlers(): void { + for (const [child, callback] of this._eventListeners.entries()) { + child.removeEventListener('frigate-card:media:loaded', callback); + } + this._eventListeners.clear(); + } + + public initialize(root: RenderRoot): void { + this._root = root; + this._initializeRoot(); + + document.addEventListener('visibilitychange', this._visibilityHandler); + + this._intersectionObserver.disconnect(); + this._intersectionObserver.observe(root); + + this._mutationObserver.disconnect(); + this._mutationObserver.observe(this._root, { childList: true, subtree: true }); + } + + protected _initializeRoot(): void { + if (!this._options || !this._root) { + return; + } + + this._removeChildHandlers(); + + this._children = [ + ...this._root.querySelectorAll(this._options.playerSelector), + ]; + + for (const [index, child] of this._children.entries()) { + const eventListener = () => this._mediaLoadedHandler(index); + this._eventListeners.set(child, eventListener); + child.addEventListener('frigate-card:media:loaded', eventListener); + } + } + protected async _intersectionHandler( + entries: IntersectionObserverEntry[], + ): Promise { + const wasIntersecting = this._viewportIntersecting; + this._viewportIntersecting = entries.some((entry) => entry.isIntersecting); + + if (wasIntersecting !== null && wasIntersecting !== this._viewportIntersecting) { + // If the live view is preloaded (i.e. in the background) we may need to + // take media actions, e.g. muting a live stream that is now running in + // the background, so we act even if the new state is hidden. + await this._changeVisibility(this._viewportIntersecting); + } + } + + protected _visibilityHandler = async (): Promise => { + await this._changeVisibility(document.visibilityState === 'visible'); + }; + + protected _changeVisibility = async (visible: boolean): Promise => { + if (visible) { + await this._unmuteSelectedIfConfigured('visible'); + await this._playSelectedIfConfigured('visible'); + } else { + await this._pauseAllIfConfigured('hidden'); + await this._muteAllIfConfigured('hidden'); + } + }; + protected _microphoneChangeHandler = async ( + change: MicrophoneManagerListenerChange, + ): Promise => { + if (change === 'unmuted') { + await this._unmuteSelectedIfConfigured('microphone'); + } else if ( + change === 'muted' && + this._options?.autoMuteConditions?.includes('microphone') + ) { + this._microphoneMuteTimer.start( + this._options.microphoneMuteSeconds ?? 60, + async () => { + await this._muteSelectedIfConfigured('microphone'); + }, + ); + } + }; +} diff --git a/src/components/live/live.ts b/src/components/live/live.ts index 1bc3834b..cb6abbf2 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -47,7 +47,6 @@ import { stopEventFromActivatingCardWideActions } from '../../utils/action.js'; import { aspectRatioToString, contentsChanged } from '../../utils/basic.js'; import { CarouselSelected } from '../../utils/embla/carousel-controller.js'; import { AutoLazyLoad } from '../../utils/embla/plugins/auto-lazy-load/auto-lazy-load.js'; -import { AutoMediaActions } from '../../utils/embla/plugins/auto-media-actions/auto-media-actions.js'; import AutoMediaLoadedInfo from '../../utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.js'; import AutoSize from '../../utils/embla/plugins/auto-size/auto-size.js'; import { getStateObjOrDispatchError } from '../../utils/get-state-obj.js'; @@ -62,6 +61,7 @@ import '../next-prev-control.js'; import '../ptz.js'; import { FrigateCardPTZ } from '../ptz.js'; import '../surround.js'; +import { MediaActionsController } from '../../components-lib/media-actions-controller.js'; const FRIGATE_CARD_LIVE_PROVIDER = 'frigate-card-live-provider'; @@ -290,10 +290,33 @@ export class FrigateCardLiveCarousel extends LitElement { // Index between camera name and slide number. protected _cameraToSlide: Record = {}; protected _refPTZControl: Ref = createRef(); + protected _refCarousel: Ref = createRef(); + + protected _mediaActionsController = new MediaActionsController(); @state() protected _mediaHasLoaded = false; + public connectedCallback(): void { + super.connectedCallback(); + + // Request update in order to reinitialize the media action controller. + this.requestUpdate(); + } + + public disconnectedCallback(): void { + this._mediaActionsController.destroy(); + super.disconnectedCallback(); + } + + updated(changedProperties: PropertyValues): void { + super.updated(changedProperties); + + if (!this._mediaActionsController.hasRoot() && this._refCarousel.value) { + this._mediaActionsController.initialize(this._refCarousel.value); + } + } + protected _getTransitionEffect(): TransitionEffect { return ( this.overriddenLiveConfig?.transition_effect ?? @@ -312,19 +335,12 @@ export class FrigateCardLiveCarousel extends LitElement { return Math.max(0, Array.from(cameraIDs).indexOf(view.camera)); } - protected _getPlugins(): EmblaCarouselPlugins { - return [ - AutoLazyLoad({ - ...(this.overriddenLiveConfig?.lazy_load && { - lazyLoadCallback: (index, slide) => - this._lazyloadOrUnloadSlide('load', index, slide), - }), - lazyUnloadConditions: this.overriddenLiveConfig?.lazy_unload, - lazyUnloadCallback: (index, slide) => - this._lazyloadOrUnloadSlide('unload', index, slide), - }), - AutoMediaLoadedInfo(), - AutoMediaActions({ + protected willUpdate(changedProps: PropertyValues): void { + if ( + changedProps.has('microphoneManager') || + changedProps.has('overriddenLiveConfig') + ) { + this._mediaActionsController.setOptions({ playerSelector: FRIGATE_CARD_LIVE_PROVIDER, ...(this.overriddenLiveConfig?.auto_play && { autoPlayConditions: this.overriddenLiveConfig.auto_play, @@ -344,7 +360,33 @@ export class FrigateCardLiveCarousel extends LitElement { microphoneMuteSeconds: this.overriddenLiveConfig.microphone.mute_after_microphone_mute_seconds, }), + }); + } + + if (changedProps.has('viewManagerEpoch')) { + if ( + this.viewFilterCameraID && + this.viewManagerEpoch?.manager.getView()?.camera !== this.viewFilterCameraID + ) { + this._mediaActionsController.unselectAll(); + } else { + this._mediaActionsController.select(this._getSelectedCameraIndex()); + } + } + } + + protected _getPlugins(): EmblaCarouselPlugins { + return [ + AutoLazyLoad({ + ...(this.overriddenLiveConfig?.lazy_load && { + lazyLoadCallback: (index, slide) => + this._lazyloadOrUnloadSlide('load', index, slide), + }), + lazyUnloadConditions: this.overriddenLiveConfig?.lazy_unload, + lazyUnloadCallback: (index, slide) => + this._lazyloadOrUnloadSlide('unload', index, slide), }), + AutoMediaLoadedInfo(), AutoSize(), ]; } @@ -541,15 +583,10 @@ export class FrigateCardLiveCarousel extends LitElement { // Notes on the below: // - guard() is used to avoid reseting the carousel unless the // options/plugins actually change. - // - the 'carousel:settle' event is listened for (instead of - // 'carousel:select') to only trigger the view change (which subsequently - // fetches thumbnails) after the carousel has stopped moving. This gives a - // much smoother carousel experience since network fetches are not at the - // same time as carousel movement (at a cost of fetching thumbnails a - // little later). return html` = createRef(); - /** - * The updated lifecycle callback for this element. - * @param changedProperties The properties that were changed in this render. - */ updated(changedProperties: PropertyValues): void { super.updated(changedProperties); @@ -209,6 +207,22 @@ export class FrigateCardViewerCarousel extends LitElement { this._seekHandler(); } } + + if (!this._mediaActionsController.hasRoot() && this._refCarousel.value) { + this._mediaActionsController.initialize(this._refCarousel.value); + } + } + + public connectedCallback(): void { + super.connectedCallback(); + + // Request update in order to reinitialize the media action controller. + this.requestUpdate(); + } + + public disconnectedCallback(): void { + this._mediaActionsController.destroy(); + super.disconnectedCallback(); } /** @@ -234,21 +248,6 @@ export class FrigateCardViewerCarousel extends LitElement { }), }), AutoMediaLoadedInfo(), - AutoMediaActions({ - playerSelector: FRIGATE_CARD_VIEWER_PROVIDER, - ...(this.viewerConfig?.auto_play && { - autoPlayConditions: this.viewerConfig.auto_play, - }), - ...(this.viewerConfig?.auto_pause && { - autoPauseConditions: this.viewerConfig.auto_pause, - }), - ...(this.viewerConfig?.auto_mute && { - autoMuteConditions: this.viewerConfig.auto_mute, - }), - ...(this.viewerConfig?.auto_unmute && { - autoUnmuteConditions: this.viewerConfig.auto_unmute, - }), - }), AutoSize(), ]; } @@ -356,6 +355,24 @@ export class FrigateCardViewerCarousel extends LitElement { } protected willUpdate(changedProps: PropertyValues): void { + if (changedProps.has('viewerConfig')) { + this._mediaActionsController.setOptions({ + playerSelector: FRIGATE_CARD_VIEWER_PROVIDER, + ...(this.viewerConfig?.auto_play && { + autoPlayConditions: this.viewerConfig.auto_play, + }), + ...(this.viewerConfig?.auto_pause && { + autoPauseConditions: this.viewerConfig.auto_pause, + }), + ...(this.viewerConfig?.auto_mute && { + autoMuteConditions: this.viewerConfig.auto_mute, + }), + ...(this.viewerConfig?.auto_unmute && { + autoUnmuteConditions: this.viewerConfig.auto_unmute, + }), + }); + } + if (changedProps.has('viewManagerEpoch')) { const view = this.viewManagerEpoch?.manager.getView(); const newMedia = view?.queryResults?.getResults(this.viewFilterCameraID) ?? null; @@ -368,6 +385,12 @@ export class FrigateCardViewerCarousel extends LitElement { this._media = newMedia; this._selected = newSelected; } + + if (!newMedia) { + this._mediaActionsController.unselectAll(); + } else { + this._mediaActionsController.select(newSelected); + } } } @@ -405,6 +428,7 @@ export class FrigateCardViewerCarousel extends LitElement { return html` ; -export type AutoMediaActionsOptionsType = Partial; - -const defaultOptions: OptionsType = { - active: true, - breakpoints: {}, -}; - -export type AutoMediaActionsType = CreatePluginType< - LoosePluginType, - AutoMediaActionsOptionsType ->; - -export function AutoMediaActions( - userOptions: AutoMediaActionsOptionsType = {}, -): AutoMediaActionsType { - let options: OptionsType; - let emblaApi: EmblaCarouselType; - let slides: HTMLElement[]; - let viewportIntersecting: boolean | null = null; - const microphoneMuteTimer = new Timer(); - - const intersectionObserver: IntersectionObserver = new IntersectionObserver( - intersectionHandler, - ); - - function init( - emblaApiInstance: EmblaCarouselType, - optionsHandler: OptionsHandlerType, - ): void { - emblaApi = emblaApiInstance; - - const { mergeOptions, optionsAtMedia } = optionsHandler; - options = optionsAtMedia(mergeOptions(defaultOptions, userOptions)); - - slides = emblaApi.slideNodes(); - - if (options.autoPlayConditions?.includes('selected')) { - // Auto play when the media loads not necessarily when the slide is - // selected (to allow for lazyloading). - emblaApi.containerNode().addEventListener('frigate-card:media:loaded', play); - } - - if (options.autoUnmuteConditions?.includes('selected')) { - // Auto unmute when the media loads not necessarily when the slide is - // selected (to allow for lazyloading). - emblaApi.containerNode().addEventListener('frigate-card:media:loaded', unmute); - } - - if (options.autoPauseConditions?.includes('unselected')) { - emblaApi.on('select', pausePrevious); - } - - if (options.autoMuteConditions?.includes('unselected')) { - emblaApi.on('select', mutePrevious); - } - - emblaApi.on('destroy', pause); - emblaApi.on('destroy', mute); - - document.addEventListener('visibilitychange', visibilityHandler); - intersectionObserver.observe(emblaApi.rootNode()); - - if ( - options.autoUnmuteConditions?.includes('microphone') || - options.autoMuteConditions?.includes('microphone') - ) { - // For some reason mergeOptions() appears to break mock objects passed in, - // so unittesting doesn't work when using options (vs userOptions where it - // does). - userOptions.microphoneManager?.addListener(microphoneChangeHandler); - - // Stop the microphone mute timer if the media changes. - emblaApi - .containerNode() - .addEventListener('frigate-card:media:loaded', stopMicrophoneTimer); - } - } - - function stopMicrophoneTimer(): void { - microphoneMuteTimer.stop(); - } - - function microphoneChangeHandler(change: MicrophoneManagerListenerChange): void { - if (change === 'unmuted' && options.autoUnmuteConditions?.includes('microphone')) { - unmute(); - } else if ( - change === 'muted' && - options.autoMuteConditions?.includes('microphone') - ) { - microphoneMuteTimer.start(options.microphoneMuteSeconds ?? 60, () => { - mute(); - }); - } - } - - function destroy(): void { - if (options.autoPlayConditions?.includes('selected')) { - emblaApi.containerNode().removeEventListener('frigate-card:media:loaded', play); - } - - if (options.autoUnmuteConditions?.includes('selected')) { - emblaApi.containerNode().removeEventListener('frigate-card:media:loaded', unmute); - } - - if (options.autoPauseConditions?.includes('unselected')) { - emblaApi.off('select', pausePrevious); - } - - if (options.autoMuteConditions?.includes('unselected')) { - emblaApi.off('select', mutePrevious); - } - - emblaApi.off('destroy', pause); - emblaApi.off('destroy', mute); - - document.removeEventListener('visibilitychange', visibilityHandler); - intersectionObserver.disconnect(); - - if ( - options.autoUnmuteConditions?.includes('microphone') || - options.autoMuteConditions?.includes('microphone') - ) { - userOptions.microphoneManager?.removeListener(microphoneChangeHandler); - emblaApi - .containerNode() - .removeEventListener('frigate-card:media:loaded', stopMicrophoneTimer); - } - } - - function actOnVisibilityChange(visible: boolean): void { - if (visible) { - if (options.autoPlayConditions?.includes('visible')) { - play(); - } - if (options.autoUnmuteConditions?.includes('visible')) { - unmute(); - } - } else { - if (options.autoPauseConditions?.includes('hidden')) { - pauseAll(); - } - if (options.autoMuteConditions?.includes('hidden')) { - muteAll(); - } - } - } - - function visibilityHandler(): void { - actOnVisibilityChange(document.visibilityState === 'visible'); - } - - function intersectionHandler(entries: IntersectionObserverEntry[]): void { - const wasIntersecting = viewportIntersecting; - viewportIntersecting = entries.some((entry) => entry.isIntersecting); - - if (wasIntersecting !== null && wasIntersecting !== viewportIntersecting) { - // If the live view is preloaded (i.e. in the background) we may need to - // take media actions, e.g. muting a live stream that is now running in - // the background, so we act even if the new state is hidden. - actOnVisibilityChange(viewportIntersecting); - } - } - - function getPlayer(slide: HTMLElement | undefined): FrigateCardMediaPlayer | null { - return options.playerSelector - ? (slide?.querySelector(options.playerSelector) as FrigateCardMediaPlayer | null) - : null; - } - - function play(): void { - getPlayer(slides[emblaApi.selectedScrollSnap()])?.play(); - } - - function pause(): void { - getPlayer(slides[emblaApi.selectedScrollSnap()])?.pause(); - } - - function pausePrevious(): void { - getPlayer(slides[emblaApi.previousScrollSnap()])?.pause(); - } - - function pauseAll(): void { - for (const slide of slides) { - getPlayer(slide)?.pause(); - } - } - - function unmute(): void { - getPlayer(slides[emblaApi.selectedScrollSnap()])?.unmute(); - } - - function mute(): void { - getPlayer(slides[emblaApi.selectedScrollSnap()])?.mute(); - } - - function mutePrevious(): void { - getPlayer(slides[emblaApi.previousScrollSnap()])?.mute(); - } - - function muteAll(): void { - for (const slide of slides) { - getPlayer(slide)?.mute(); - } - } - - const self: AutoMediaActionsType = { - name: 'autoMediaActions', - options: userOptions, - init, - destroy, - }; - return self; -} diff --git a/src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.ts b/src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.ts index bc104ed7..db65a86c 100644 --- a/src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.ts +++ b/src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info.ts @@ -46,7 +46,9 @@ function AutoMediaLoadedInfo(): AutoMediaLoadedInfoType { function mediaLoadedInfoHandler(ev: CustomEvent): void { const eventPath = ev.composedPath(); - for (const [index, slide] of slides.entries()) { + // As an optimization, the most recent slide is the one at the end. That's + // where most users are spending time, so start the search there. + for (const [index, slide] of [...slides.entries()].reverse()) { if (eventPath.includes(slide)) { mediaLoadedInfo[index] = ev.detail; if (index !== emblaApi.selectedScrollSnap()) { @@ -76,7 +78,8 @@ function AutoMediaLoadedInfo(): AutoMediaLoadedInfoType { const savedMediaLoadedInfo: MediaLoadedInfo | undefined = mediaLoadedInfo[index]; if (savedMediaLoadedInfo) { dispatchExistingMediaLoadedInfoAsEvent( - emblaApi.containerNode(), + // Event is redispatched from source element. + slides[index], savedMediaLoadedInfo, ); } diff --git a/tests/components-lib/media-actions-controller.test.ts b/tests/components-lib/media-actions-controller.test.ts new file mode 100644 index 00000000..df551761 --- /dev/null +++ b/tests/components-lib/media-actions-controller.test.ts @@ -0,0 +1,573 @@ +import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; +import { + MicrophoneManagerListenerChange, + ReadonlyMicrophoneManager, +} from '../../src/card-controller/microphone-manager'; +import { + MediaActionsController, + MediaActionsControllerOptions, +} from '../../src/components-lib/media-actions-controller'; +import { FrigateCardMediaPlayer } from '../../src/types'; +import { + IntersectionObserverMock, + MutationObserverMock, + callIntersectionHandler, + callMutationHandler, + createParent, + flushPromises, +} from '../test-utils'; +import { callVisibilityHandler, createTestSlideNodes } from '../utils/embla/test-utils'; +import { mock } from 'vitest-mock-extended'; + +const getPlayer = ( + element: HTMLElement, + selector: string, +): (HTMLElement & FrigateCardMediaPlayer) | null => { + return element.querySelector(selector); +}; + +const createPlayer = (): HTMLElement & FrigateCardMediaPlayer => { + const player = document.createElement('video'); + + player['play'] = vi.fn(); + player['pause'] = vi.fn(); + player['mute'] = vi.fn(); + player['unmute'] = vi.fn(); + player['isMuted'] = vi.fn().mockReturnValue(true); + player['seek'] = vi.fn(); + player['getScreenshotURL'] = vi.fn(); + player['setControls'] = vi.fn(); + player['isPaused'] = vi.fn(); + + return player as unknown as HTMLElement & FrigateCardMediaPlayer; +}; + +const createPlayerSlideNodes = (n = 10): HTMLElement[] => { + const divs = createTestSlideNodes({ n: n }); + for (const div of divs) { + div.appendChild(createPlayer()); + } + return divs; +}; + +const callMicrophoneListener = ( + microphoneManager: ReadonlyMicrophoneManager, + action: MicrophoneManagerListenerChange, + n = 0, +): void => { + const mock = vi.mocked(microphoneManager.addListener).mock; + mock.calls[n][0](action); +}; + +// @vitest-environment jsdom +describe('MediaActionsController', () => { + beforeAll(() => { + vi.stubGlobal('IntersectionObserver', IntersectionObserverMock); + vi.stubGlobal('MutationObserver', MutationObserverMock); + }); + + afterAll(() => { + vi.restoreAllMocks(); + }); + + beforeEach(() => { + vi.clearAllMocks(); + }); + + describe('should initialize', () => { + it('should have root', async () => { + const controller = new MediaActionsController(); + + controller.initialize(createParent()); + + expect(controller.hasRoot()).toBeTruthy(); + }); + + it('should do nothing without options', async () => { + const controller = new MediaActionsController(); + + const children = createPlayerSlideNodes(); + const parent = createParent({ children: children }); + + controller.initialize(parent); + await controller.select(0); + + expect(getPlayer(children[0], 'video')?.play).not.toBeCalled(); + }); + + it('should re-initialize after mutation', async () => { + const controller = new MediaActionsController(); + controller.setOptions({ + playerSelector: 'video', + autoPlayConditions: ['selected' as const], + }); + + const parent = createParent({ children: createPlayerSlideNodes(1) }); + controller.initialize(parent); + + const newPlayer = createPlayer(); + const newChild = document.createElement('div'); + newChild.appendChild(newPlayer); + parent.append(newChild); + + await callMutationHandler(); + + await controller.select(1); + + expect(newPlayer.play).toBeCalled(); + }); + }); + + describe('should destroy', () => { + it('should do nothing after destroy', async () => { + const controller = new MediaActionsController(); + controller.setOptions({ + playerSelector: 'video', + autoPlayConditions: ['selected' as const], + }); + + const children = createPlayerSlideNodes(); + const parent = createParent({ children: children }); + controller.initialize(parent); + + controller.destroy(); + + await controller.select(0); + + expect(getPlayer(children[0], 'video')?.play).not.toBeCalled(); + }); + }); + + describe('should respond to select', () => { + it.each([ + ['should play', { autoPlayConditions: ['selected' as const] }, 'play', true], + ['should not play', { autoPlayConditions: [] }, 'play', false], + ['should unmute', { autoUnmuteConditions: ['selected' as const] }, 'unmute', true], + ['should not unmute', { autoUnmuteConditions: [] }, 'unmute', false], + ])( + '%s', + async ( + _: string, + options: Partial, + func: string, + called: boolean, + ) => { + const controller = new MediaActionsController(); + controller.setOptions({ + playerSelector: 'video', + ...options, + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + + await controller.select(0); + + expect(getPlayer(children[0], 'video')?.[func]).toBeCalledTimes(called ? 1 : 0); + }, + ); + + it('should not re-select', async () => { + const controller = new MediaActionsController(); + controller.setOptions({ + autoPlayConditions: ['selected' as const], + playerSelector: 'video', + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + + await controller.select(0); + expect(getPlayer(children[0], 'video')?.play).toBeCalledTimes(1); + + await controller.select(0); + expect(getPlayer(children[0], 'video')?.play).toBeCalledTimes(1); + }); + + it('should unselect first', async () => { + const controller = new MediaActionsController(); + controller.setOptions({ + autoPauseConditions: ['unselected' as const], + autoMuteConditions: ['unselected' as const], + playerSelector: 'video', + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + + await controller.select(0); + await controller.select(1); + + expect(getPlayer(children[0], 'video')?.pause).toBeCalled(); + expect(getPlayer(children[0], 'video')?.mute).toBeCalled(); + }); + }); + + describe('should respond to media loaded', () => { + it('should play', async () => { + const controller = new MediaActionsController(); + controller.setOptions({ + autoPlayConditions: ['selected' as const], + playerSelector: 'video', + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + + await controller.select(0); + expect(getPlayer(children[0], 'video')?.play).toBeCalledTimes(1); + + getPlayer(children[0], 'video')?.dispatchEvent( + new Event('frigate-card:media:loaded'), + ); + + await flushPromises(); + + expect(getPlayer(children[0], 'video')?.play).toBeCalledTimes(2); + }); + + it('should unmute', async () => { + const controller = new MediaActionsController(); + controller.setOptions({ + autoUnmuteConditions: ['selected' as const], + playerSelector: 'video', + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + + await controller.select(0); + expect(getPlayer(children[0], 'video')?.unmute).toBeCalledTimes(1); + + getPlayer(children[0], 'video')?.dispatchEvent( + new Event('frigate-card:media:loaded'), + ); + + await flushPromises(); + + expect(getPlayer(children[0], 'video')?.unmute).toBeCalledTimes(2); + }); + + it('should take no action on unselected media load', async () => { + const controller = new MediaActionsController(); + controller.setOptions({ + autoPlayConditions: ['selected' as const], + autoUnmuteConditions: ['selected' as const], + playerSelector: 'video', + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + + await controller.select(0); + + getPlayer(children[9], 'video')?.dispatchEvent( + new Event('frigate-card:media:loaded'), + ); + + await flushPromises(); + + expect(getPlayer(children[9], 'video')?.play).not.toBeCalled(); + expect(getPlayer(children[9], 'video')?.unmute).not.toBeCalled(); + }); + }); + + describe('should respond to unselect', () => { + it.each([ + ['should pause', { autoPauseConditions: ['unselected' as const] }, 'pause', true], + ['should not pause', { autoPauseConditions: [] }, 'pause', false], + ['should mute', { autoMuteConditions: ['unselected' as const] }, 'mute', true], + ['should not mute', { autoMuteConditions: [] }, 'mute', false], + ])( + '%s', + async ( + _: string, + options: Partial, + func: string, + called: boolean, + ) => { + const controller = new MediaActionsController(); + controller.setOptions({ + playerSelector: 'video', + ...options, + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + + await controller.select(0); + await controller.unselect(); + + expect(getPlayer(children[0], 'video')?.[func]).toBeCalledTimes(called ? 1 : 0); + }, + ); + }); + + describe('should respond to unselect all', () => { + it.each([ + ['should pause', { autoPauseConditions: ['unselected' as const] }, 'pause', true], + ['should not pause', { autoPauseConditions: [] }, 'pause', false], + ['should mute', { autoMuteConditions: ['unselected' as const] }, 'mute', true], + ['should not mute', { autoMuteConditions: [] }, 'mute', false], + ])( + '%s', + async ( + _: string, + options: Partial, + func: string, + called: boolean, + ) => { + const controller = new MediaActionsController(); + controller.setOptions({ + playerSelector: 'video', + ...options, + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + + await controller.unselectAll(); + + children.forEach((child) => { + expect(getPlayer(child, 'video')?.[func]).toBeCalledTimes(called ? 1 : 0); + }); + }, + ); + }); + + describe('should respond to page being visible', () => { + it.each([ + ['should play', { autoPlayConditions: ['visible' as const] }, 'play', true], + ['should not play', { autoPlayConditions: [] }, 'play', false], + ['should unmute', { autoUnmuteConditions: ['visible' as const] }, 'unmute', true], + ['should not unmute', { autoUnmuteConditions: [] }, 'unmute', false], + ])( + '%s', + async ( + _: string, + options: Partial, + func: string, + called: boolean, + ) => { + vi.spyOn(global.document, 'addEventListener'); + + const controller = new MediaActionsController(); + controller.setOptions({ + playerSelector: 'video', + ...options, + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + await controller.select(0); + + // Not configured to take action on selection. + expect(getPlayer(children[0], 'video')?.[func]).not.toBeCalled(); + + Object.defineProperty(document, 'visibilityState', { + value: 'visible', + writable: true, + }); + await callVisibilityHandler(); + + // Not configured to take action on selection. + expect(getPlayer(children[0], 'video')?.[func]).toBeCalledTimes(called ? 1 : 0); + }, + ); + }); + + describe('should respond to page being hiddne', () => { + beforeAll(() => { + vi.spyOn(global.document, 'addEventListener'); + }); + + it.each([ + ['should pause', { autoPauseConditions: ['hidden' as const] }, 'pause', true], + ['should not pause', { autoPauseConditions: [] }, 'pause', false], + ['should mute', { autoMuteConditions: ['hidden' as const] }, 'mute', true], + ['should not mute', { autoMuteConditions: [] }, 'mute', false], + ])( + '%s', + async ( + _: string, + options: Partial, + func: string, + called: boolean, + ) => { + const controller = new MediaActionsController(); + controller.setOptions({ + playerSelector: 'video', + ...options, + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + await controller.select(0); + + // Not configured to take action on selection. + expect(getPlayer(children[0], 'video')?.[func]).not.toBeCalled(); + + Object.defineProperty(document, 'visibilityState', { + value: 'hidden', + writable: true, + }); + await callVisibilityHandler(); + + // Not configured to take action on selection. + expect(getPlayer(children[0], 'video')?.[func]).toBeCalledTimes(called ? 1 : 0); + }, + ); + }); + + describe('should respond to page intersecting with viewport', () => { + it.each([ + ['should play', { autoPlayConditions: ['visible' as const] }, 'play', true], + ['should not play', { autoPlayConditions: [] }, 'play', false], + ['should unmute', { autoUnmuteConditions: ['visible' as const] }, 'unmute', true], + ['should not unmute', { autoUnmuteConditions: [] }, 'unmute', false], + ])( + '%s', + async ( + _: string, + options: Partial, + func: string, + called: boolean, + ) => { + const controller = new MediaActionsController(); + controller.setOptions({ + playerSelector: 'video', + ...options, + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + await controller.select(0); + + // Not configured to take action on selection. + expect(getPlayer(children[0], 'video')?.[func]).not.toBeCalled(); + + // There's always a first call to an intersection observer handler. In + // this case the MediaActionsController ignores it. + await callIntersectionHandler(false); + + await callIntersectionHandler(true); + + // Not configured to take action on selection. + expect(getPlayer(children[0], 'video')?.[func]).toBeCalledTimes(called ? 1 : 0); + }, + ); + }); + + describe('should respond to page not intersecting with viewport', () => { + it.each([ + ['should play', { autoPlayConditions: ['visible' as const] }, 'play', true], + ['should not play', { autoPlayConditions: [] }, 'play', false], + ['should unmute', { autoUnmuteConditions: ['visible' as const] }, 'unmute', true], + ['should not unmute', { autoUnmuteConditions: [] }, 'unmute', false], + ])( + '%s', + async ( + _: string, + options: Partial, + func: string, + called: boolean, + ) => { + const controller = new MediaActionsController(); + controller.setOptions({ + playerSelector: 'video', + ...options, + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + await controller.select(0); + + // Not configured to take action on selection. + expect(getPlayer(children[0], 'video')?.[func]).not.toBeCalled(); + + // There's always a first call to an intersection observer handler. In + // this case the MediaActionsController ignores it. + await callIntersectionHandler(false); + + await callIntersectionHandler(true); + + // Not configured to take action on selection. + expect(getPlayer(children[0], 'video')?.[func]).toBeCalledTimes(called ? 1 : 0); + }, + ); + }); + + describe('should respond to microphone changes', () => { + beforeAll(() => { + vi.useFakeTimers(); + }); + + afterAll(() => { + vi.useRealTimers(); + }); + + it('should unmute when microphone unmuted', async () => { + const microphoneManager = mock(); + const controller = new MediaActionsController(); + + controller.setOptions({ + autoUnmuteConditions: ['microphone' as const], + playerSelector: 'video', + microphoneManager: microphoneManager, + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + + await controller.select(0); + + callMicrophoneListener(microphoneManager, 'unmuted'); + + expect(getPlayer(children[0], 'video')?.unmute).toBeCalled(); + }); + + it('should re-mute after delay after microphone unmuted', async () => { + const microphoneManager = mock(); + const controller = new MediaActionsController(); + + controller.setOptions({ + autoMuteConditions: ['microphone' as const], + playerSelector: 'video', + microphoneManager: microphoneManager, + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + + await controller.select(0); + + callMicrophoneListener(microphoneManager, 'muted'); + + vi.runOnlyPendingTimers(); + + expect(getPlayer(children[0], 'video')?.mute).toBeCalled(); + }); + + it('should not re-mute after delay after microphone unmuted', async () => { + const microphoneManager = mock(); + const controller = new MediaActionsController(); + + controller.setOptions({ + autoMuteConditions: [], + playerSelector: 'video', + microphoneManager: microphoneManager, + }); + + const children = createPlayerSlideNodes(); + controller.initialize(createParent({ children: children })); + + await controller.select(0); + + callMicrophoneListener(microphoneManager, 'muted'); + + vi.runOnlyPendingTimers(); + + expect(getPlayer(children[0], 'video')?.mute).not.toBeCalled(); + }); + }); +}); diff --git a/tests/test-utils.ts b/tests/test-utils.ts index 31d705af..cbe59207 100644 --- a/tests/test-utils.ts +++ b/tests/test-utils.ts @@ -385,13 +385,20 @@ export const requestAnimationFrameMock = (callback: FrameRequestCallback) => { return 1; }; -export const callIntersectionHandler = (intersecting = true, n = 0): void => { +export const callIntersectionHandler = async ( + intersecting = true, + n = 0, +): Promise => { const mockResult = vi.mocked(IntersectionObserver).mock.results[n]; if (mockResult.type !== 'return') { return; } const observer = mockResult.value; - vi.mocked(IntersectionObserver).mock.calls[n][0]( + await ( + vi.mocked(IntersectionObserver).mock.calls[n][0] as + | IntersectionObserverCallback + | ((_: unknown) => Promise) + )( // Note this is a very incomplete / invalid IntersectionObserverEntry that // just provides the bare basics current implementation uses. intersecting ? [{ isIntersecting: true } as IntersectionObserverEntry] : [], @@ -399,6 +406,24 @@ export const callIntersectionHandler = (intersecting = true, n = 0): void => { ); }; +export const callMutationHandler = async (n = 0): Promise => { + const mockResult = vi.mocked(MutationObserver).mock.results[n]; + if (mockResult.type !== 'return') { + return; + } + const observer = mockResult.value; + await ( + vi.mocked(MutationObserver).mock.calls[n][0] as + | MutationCallback + | ((_: unknown) => Promise) + )( + // Note this is a very incomplete / invalid IntersectionObserverEntry that + // just provides the bare basics current implementation uses. + [], + observer, + ); +}; + export const createSlotHost = (options?: { slot?: HTMLSlotElement; children?: HTMLElement[]; diff --git a/tests/utils/embla/carousel-controller.test.ts b/tests/utils/embla/carousel-controller.test.ts index 8eef025f..8b3352bf 100644 --- a/tests/utils/embla/carousel-controller.test.ts +++ b/tests/utils/embla/carousel-controller.test.ts @@ -4,13 +4,13 @@ import { CarouselController } from '../../../src/utils/embla/carousel-controller import AutoMediaLoadedInfo from '../../../src/utils/embla/plugins/auto-media-loaded-info/auto-media-loaded-info'; import { MutationObserverMock, + callMutationHandler, createParent, createSlot, createSlotHost, } from '../../test-utils'; import { callEmblaHandler, - callMutationHandler, createEmblaApiInstance, createTestSlideNodes, } from './test-utils'; diff --git a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts b/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts deleted file mode 100644 index d508772e..00000000 --- a/tests/utils/embla/plugins/auto-media-actions/auto-media-actions.test.ts +++ /dev/null @@ -1,455 +0,0 @@ -import { add } from 'date-fns'; -import { afterAll, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; -import { mock } from 'vitest-mock-extended'; -import { - MicrophoneManagerListenerChange, - ReadonlyMicrophoneManager, -} from '../../../../../src/card-controller/microphone-manager'; -import { - MEDIA_ACTION_NEGATIVE_CONDITIONS, - MEDIA_ACTION_POSITIVE_CONDITIONS, - MEDIA_MUTE_CONDITIONS, - MEDIA_UNMUTE_CONDITIONS, -} from '../../../../../src/config/types'; -import { FrigateCardMediaPlayer } from '../../../../../src/types'; -import { - AutoMediaActions, - AutoMediaActionsOptionsType, - AutoMediaActionsType, -} from '../../../../../src/utils/embla/plugins/auto-media-actions/auto-media-actions'; -import { dispatchExistingMediaLoadedInfoAsEvent } from '../../../../../src/utils/media-info'; -import { - IntersectionObserverMock, - callIntersectionHandler, - createMediaLoadedInfo, - createParent, -} from '../../../../test-utils'; -import { - callEmblaHandler, - callVisibilityHandler, - createEmblaApiInstance, - createTestEmblaOptionHandler, - createTestSlideNodes, -} from '../../test-utils'; - -const getPlayer = ( - element: HTMLElement, - selector: string, -): (HTMLElement & FrigateCardMediaPlayer) | null => { - return element.querySelector(selector); -}; - -const createPlayerSlideNodes = (n = 10): HTMLElement[] => { - const slides = createTestSlideNodes({ n: n }); - for (const slide of slides) { - const player = document.createElement('video'); - - player['play'] = vi.fn(); - player['pause'] = vi.fn(); - player['mute'] = vi.fn(); - player['unmute'] = vi.fn(); - player['isMuted'] = vi.fn().mockReturnValue(true); - player['seek'] = vi.fn(); - player['getScreenshotURL'] = vi.fn(); - player['setControls'] = vi.fn(); - player['isPaused'] = vi.fn(); - - slide.appendChild(player); - } - return slides; -}; - -const createPlugin = (options?: AutoMediaActionsOptionsType): AutoMediaActionsType => { - return AutoMediaActions({ - playerSelector: 'video', - autoPlayConditions: MEDIA_ACTION_POSITIVE_CONDITIONS, - autoUnmuteConditions: MEDIA_UNMUTE_CONDITIONS, - autoPauseConditions: MEDIA_ACTION_NEGATIVE_CONDITIONS, - autoMuteConditions: MEDIA_MUTE_CONDITIONS, - microphoneManager: mock(), - ...options, - }); -}; - -const callMicrophoneListener = ( - microphoneManager: ReadonlyMicrophoneManager, - action: MicrophoneManagerListenerChange, - n = 0, -): void => { - const mock = vi.mocked(microphoneManager.addListener).mock; - mock.calls[n][0](action); -}; - -// @vitest-environment jsdom -describe('AutoMediaActions', () => { - beforeAll(() => { - vi.stubGlobal('IntersectionObserver', IntersectionObserverMock); - vi.useFakeTimers(); - }); - - afterAll(() => { - vi.useRealTimers(); - }); - - beforeEach(() => { - vi.clearAllMocks(); - }); - - it('should construct', () => { - const plugin = AutoMediaActions(); - expect(plugin.name).toBe('autoMediaActions'); - }); - - it('should init without any conditions', () => { - const microphoneManager = mock(); - const plugin = createPlugin({ - autoPlayConditions: [], - autoUnmuteConditions: [], - autoPauseConditions: [], - autoMuteConditions: [], - microphoneManager: microphoneManager, - }); - const parent = createParent(); - const addEventListener = vi.fn(); - parent.addEventListener = addEventListener; - const emblaApi = createEmblaApiInstance({ containerNode: parent }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - expect(emblaApi.on).toBeCalledWith('destroy', expect.anything()); - expect(emblaApi.on).not.toBeCalledWith('select', expect.anything()); - expect(addEventListener).not.toBeCalled(); - expect(microphoneManager.addListener).not.toBeCalled(); - }); - - it('should destroy', () => { - const plugin = createPlugin(); - const parent = createParent(); - const removeEventListener = vi.fn(); - parent.removeEventListener = removeEventListener; - const emblaApi = createEmblaApiInstance({ containerNode: parent }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - plugin.destroy(); - - expect(emblaApi.off).toBeCalledWith('destroy', expect.anything()); - expect(emblaApi.off).toBeCalledWith('select', expect.anything()); - expect(removeEventListener).toBeCalled(); - }); - - it('should destroy without any conditions', () => { - const microphoneManager = mock(); - const plugin = createPlugin({ - autoPlayConditions: [], - autoUnmuteConditions: [], - autoPauseConditions: [], - autoMuteConditions: [], - microphoneManager: microphoneManager, - }); - const parent = createParent(); - const removeEventListener = vi.fn(); - parent.removeEventListener = removeEventListener; - const emblaApi = createEmblaApiInstance({ containerNode: parent }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - plugin.destroy(); - - expect(emblaApi.off).toBeCalledWith('destroy', expect.anything()); - expect(emblaApi.off).not.toBeCalledWith('select', expect.anything()); - expect(removeEventListener).not.toBeCalled(); - expect(microphoneManager.removeListener).not.toBeCalled(); - }); - - it('should mute and pause on destroy', () => { - const plugin = createPlugin(); - const children = createPlayerSlideNodes(); - const parent = createParent({ children: children }); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - containerNode: parent, - selectedScrollSnap: 5, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - callEmblaHandler(emblaApi, 'destroy'); - - expect(getPlayer(children[5], 'video')?.pause).toBeCalled(); - expect(getPlayer(children[5], 'video')?.mute).toBeCalled(); - }); - - it('should play and unmute on media load', () => { - const plugin = createPlugin(); - const children = createPlayerSlideNodes(); - const parent = createParent({ children: children }); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - containerNode: parent, - selectedScrollSnap: 5, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - dispatchExistingMediaLoadedInfoAsEvent(parent, createMediaLoadedInfo()); - - expect(getPlayer(children[5], 'video')?.play).toBeCalled(); - expect(getPlayer(children[5], 'video')?.unmute).toBeCalled(); - }); - - it('should not play or unmute on media load when player selecter not provided', () => { - const plugin = createPlugin({ playerSelector: undefined }); - const children = createPlayerSlideNodes(); - const parent = createParent({ children: children }); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - containerNode: parent, - selectedScrollSnap: 5, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - dispatchExistingMediaLoadedInfoAsEvent(parent, createMediaLoadedInfo()); - - expect(getPlayer(children[5], 'video')?.play).not.toBeCalled(); - expect(getPlayer(children[5], 'video')?.unmute).not.toBeCalled(); - }); - - it('should pause and mute previous on select', () => { - const plugin = createPlugin(); - const children = createPlayerSlideNodes(); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - previousScrollSnap: 4, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - callEmblaHandler(emblaApi, 'select'); - - expect(getPlayer(children[4], 'video')?.pause).toBeCalled(); - expect(getPlayer(children[4], 'video')?.mute).toBeCalled(); - }); - - it('should play and unmute on visibility change to visible', () => { - vi.spyOn(global.document, 'addEventListener'); - - const plugin = createPlugin(); - const children = createPlayerSlideNodes(); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - selectedScrollSnap: 5, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - Object.defineProperty(document, 'visibilityState', { - value: 'visible', - writable: true, - }); - callVisibilityHandler(); - - expect(getPlayer(children[5], 'video')?.play).toBeCalled(); - expect(getPlayer(children[5], 'video')?.unmute).toBeCalled(); - }); - - it('should pause and unmute on visibility change to hidden', () => { - vi.spyOn(global.document, 'addEventListener'); - - const plugin = createPlugin(); - const children = createPlayerSlideNodes(); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - Object.defineProperty(document, 'visibilityState', { - value: 'hidden', - writable: true, - }); - callVisibilityHandler(); - - for (const child of children) { - expect(getPlayer(child, 'video')?.pause).toBeCalled(); - expect(getPlayer(child, 'video')?.mute).toBeCalled(); - } - }); - - describe('should take no action on visibility change without callbacks', () => { - it.each([['visible' as const], ['hidden' as const]])( - '%s', - (visibilityState: 'visible' | 'hidden') => { - vi.spyOn(global.document, 'addEventListener'); - - const plugin = AutoMediaActions(); - const children = createPlayerSlideNodes(); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - Object.defineProperty(document, 'visibilityState', { - value: visibilityState, - writable: true, - }); - callVisibilityHandler(); - - for (const child of children) { - expect(getPlayer(child, 'video')?.play).not.toBeCalled(); - expect(getPlayer(child, 'video')?.pause).not.toBeCalled(); - expect(getPlayer(child, 'video')?.mute).not.toBeCalled(); - expect(getPlayer(child, 'video')?.unmute).not.toBeCalled(); - } - }, - ); - }); - - it('should play and unmute on intersection', () => { - const plugin = createPlugin(); - const children = createPlayerSlideNodes(); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - selectedScrollSnap: 5, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - // Intersection observer always calls handler on creation (and we ignore - // these first calls). - callIntersectionHandler(false); - callIntersectionHandler(true); - - expect(getPlayer(children[5], 'video')?.play).toBeCalled(); - expect(getPlayer(children[5], 'video')?.unmute).toBeCalled(); - }); - - it('should pause and mute on intersection', () => { - vi.spyOn(global.document, 'addEventListener'); - - const plugin = createPlugin(); - const children = createPlayerSlideNodes(); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - // Intersection observer always calls handler on creation (and we ignore - // these first calls). - callIntersectionHandler(true); - callIntersectionHandler(false); - - for (const child of children) { - expect(getPlayer(child, 'video')?.pause).toBeCalled(); - expect(getPlayer(child, 'video')?.mute).toBeCalled(); - } - }); - - describe('should handle microphone triggers', () => { - it('should unmute on microphone unmute', () => { - const microphoneManager = mock(); - const plugin = createPlugin({ microphoneManager: microphoneManager }); - const children = createPlayerSlideNodes(); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - selectedScrollSnap: 5, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - callMicrophoneListener(microphoneManager, 'unmuted'); - - expect(getPlayer(children[5], 'video')?.unmute).toBeCalled(); - }); - - it('should not unmute on microphone unmute when not configured', () => { - const microphoneManager = mock(); - const plugin = createPlugin({ - microphoneManager: microphoneManager, - autoUnmuteConditions: [], - }); - const children = createPlayerSlideNodes(); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - selectedScrollSnap: 5, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - callMicrophoneListener(microphoneManager, 'unmuted'); - - expect(getPlayer(children[5], 'video')?.unmute).not.toBeCalled(); - }); - - it('should mute on microphone mute after default delay', () => { - const start = new Date('2024-01-28T14:42'); - - const microphoneManager = mock(); - const plugin = createPlugin({ microphoneManager: microphoneManager }); - const children = createPlayerSlideNodes(); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - selectedScrollSnap: 5, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - vi.setSystemTime(start); - callMicrophoneListener(microphoneManager, 'muted'); - - expect(getPlayer(children[5], 'video')?.mute).not.toBeCalled(); - vi.setSystemTime(add(start, { seconds: 60 })); - vi.runOnlyPendingTimers(); - expect(getPlayer(children[5], 'video')?.mute).toBeCalled(); - }); - - it('should mute on microphone mute after configured delay', () => { - const start = new Date('2024-01-28T14:42'); - - const microphoneManager = mock(); - const plugin = createPlugin({ - microphoneManager: microphoneManager, - microphoneMuteSeconds: 30, - }); - const children = createPlayerSlideNodes(); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - selectedScrollSnap: 5, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - vi.setSystemTime(start); - callMicrophoneListener(microphoneManager, 'muted'); - - expect(getPlayer(children[5], 'video')?.mute).not.toBeCalled(); - vi.setSystemTime(add(start, { seconds: 30 })); - vi.runOnlyPendingTimers(); - expect(getPlayer(children[5], 'video')?.mute).toBeCalled(); - }); - - it('should not mute on microphone mute after delay when not configured', () => { - const start = new Date('2024-01-28T14:42'); - - const microphoneManager = mock(); - const plugin = createPlugin({ - microphoneManager: microphoneManager, - autoMuteConditions: [], - }); - const children = createPlayerSlideNodes(); - const emblaApi = createEmblaApiInstance({ - slideNodes: children, - selectedScrollSnap: 5, - }); - - plugin.init(emblaApi, createTestEmblaOptionHandler()); - - vi.setSystemTime(start); - callMicrophoneListener(microphoneManager, 'muted'); - - expect(getPlayer(children[5], 'video')?.mute).not.toBeCalled(); - vi.setSystemTime(add(start, { seconds: 60 })); - vi.runOnlyPendingTimers(); - expect(getPlayer(children[5], 'video')?.mute).not.toBeCalled(); - }); - }); -}); diff --git a/tests/utils/embla/test-utils.ts b/tests/utils/embla/test-utils.ts index 4aad2d0f..66779fe6 100644 --- a/tests/utils/embla/test-utils.ts +++ b/tests/utils/embla/test-utils.ts @@ -16,6 +16,7 @@ export const createTestEmblaOptionHandler = (): OptionsHandlerType => ({ optionsAtMedia: (options: Type): Type => { return options; }, + // eslint-disable-next-line @typescript-eslint/no-unused-vars optionsMediaQueries: (_optionsList: LooseOptionsType[]): MediaQueryList[] => [], }); @@ -34,29 +35,15 @@ export const callEmblaHandler = ( } }; -export const callVisibilityHandler = (): void => { +export const callVisibilityHandler = async (): Promise => { const mock = vi.mocked(global.document.addEventListener).mock; for (const [evt, cb] of mock.calls) { if (evt === 'visibilitychange' && typeof cb === 'function') { - cb(new Event('foo')); + await (cb as EventListener | ((_: unknown) => Promise))(new Event('foo')); } } }; -export const callMutationHandler = (n = 0): void => { - const mockResult = vi.mocked(MutationObserver).mock.results[n]; - if (mockResult.type !== 'return') { - return; - } - const observer = mockResult.value; - vi.mocked(MutationObserver).mock.calls[n][0]( - // Note this is a very incomplete / invalid IntersectionObserverEntry that - // just provides the bare basics current implementation uses. - [], - observer, - ); -}; - export const callResizeHandler = ( entries: { target: HTMLElement; @@ -110,5 +97,6 @@ export const createEmblaApiInstance = (options?: { }; export const createTestSlideNodes = (options?: { n?: number }): HTMLElement[] => { + // eslint-disable-next-line @typescript-eslint/no-unused-vars return [...Array(options?.n ?? 10).keys()].map((_) => document.createElement('div')); }; diff --git a/tests/utils/get-state-obj.ts b/tests/utils/get-state-obj.test.ts similarity index 100% rename from tests/utils/get-state-obj.ts rename to tests/utils/get-state-obj.test.ts diff --git a/vite.config.ts b/vite.config.ts index 0369ec03..bbc3c8e5 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -12,15 +12,7 @@ const FULL_COVERAGE_FILES_RELATIVE = [ 'camera-manager/motioneye/icon.ts', 'camera-manager/utils/*.ts', 'card-controller/**/*.ts', - 'components-lib/cached-value-controller.ts', - 'components-lib/key-assigner-controller.ts', - 'components-lib/live/**/*.ts', - 'components-lib/media-filter-controller.ts', - 'components-lib/menu-button-controller.ts', - 'components-lib/menu-controller.ts', - 'components-lib/status-bar-controller.ts', - 'components-lib/ptz/*.ts', - 'components-lib/zoom/*.ts', + 'components-lib/**/!(timeline-source.ts)', 'config/**/*.ts', 'const.ts', 'types.ts', From e0dda84295fa7e764a24bb1dd138762d973ba9da Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 7 Sep 2024 15:07:57 -0700 Subject: [PATCH 173/189] Small formatting fix. --- src/components/live/live.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/live/live.ts b/src/components/live/live.ts index cb6abbf2..df5f2144 100644 --- a/src/components/live/live.ts +++ b/src/components/live/live.ts @@ -300,7 +300,7 @@ export class FrigateCardLiveCarousel extends LitElement { public connectedCallback(): void { super.connectedCallback(); - // Request update in order to reinitialize the media action controller. + // Request update in order to reinitialize the media action controller. this.requestUpdate(); } From c7359188e7f01aa430f182f64f1bab203a3bea6d Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 7 Sep 2024 15:33:54 -0700 Subject: [PATCH 174/189] Fix overlay z-index for menu . --- src/scss/card.scss | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/scss/card.scss b/src/scss/card.scss index a26f203a..dc37e1fb 100644 --- a/src/scss/card.scss +++ b/src/scss/card.scss @@ -183,7 +183,7 @@ web-dialog::part(dialog) { * Overlay styles ****************/ frigate-card-overlay { - z-index: 1; + z-index: 10; } /******************* @@ -191,7 +191,7 @@ frigate-card-overlay { *******************/ frigate-card-menu[data-style*='hover'] { - z-index: 4; + z-index: 20; transition: opacity 0.5s ease; opacity: 0; } @@ -205,7 +205,6 @@ frigate-card-menu[data-style*='hover']:hover, *************************/ frigate-card-status-bar[data-style*='hover'] { - z-index: 3; transition: opacity 0.5s ease; opacity: 0; } From 9141cec0fe5e9662e24259ea245558587f5f077d Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 7 Sep 2024 16:16:13 -0700 Subject: [PATCH 175/189] Add status bar screenshot --- docs/examples.md | 2 ++ docs/images/dynamic-status.gif | Bin 0 -> 2836004 bytes docs/screenshots.md | 6 ++++++ 3 files changed, 8 insertions(+) create mode 100644 docs/images/dynamic-status.gif diff --git a/docs/examples.md b/docs/examples.md index 654669d3..fb23a028 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -713,6 +713,8 @@ status_bar: This example shows an icon and a message on the status bar when a camera is triggered, replacing the existing contents of the status bar through the use of `exclusive`. +![](images/dynamic-status.gif 'Dynamic Status Messages :size=400') + ```yaml type: custom:frigate-card cameras: diff --git a/docs/images/dynamic-status.gif b/docs/images/dynamic-status.gif new file mode 100644 index 0000000000000000000000000000000000000000..0021b8d097e60cc79d7a45bd9b0eb6aa5855b934 GIT binary patch literal 2836004 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
      xb6cg8eH<22{7ViVFx}46C1xy3+$`>4 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 $k!^&Q^ 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

      ntpzeufrD{UO-#AJA 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Ƅ*c1J9$uUMY-_q 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

      X?#OJ#N4CSw_V`BZgok%j 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

      i+sVU$)D=wb&(YFLIUMC$+no6wW4XWC^ECTXu$ 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 A=O4-+H;5t)%ZJ5 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

      }T_cjOuP&5#H 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 z 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

      *3kkb! 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⪙S5a&eK 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

      H<8g2;c^DUt41!Z_ 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 z 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 z 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

      VH<*Fs2C0(zQ29>Tp}EU-?;@X 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

      +oJ2hP(QvfS!Qo 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

      lNQYj`vG@YH>bER|2bo4 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

      nxbz8k}R$H;93NAnQ0=8r!azuF8|^^C zh4;U*3dBivv+>>nBG{hecQRqI<5C~!q`j>7P3lYCV6EOSjtu5LQ zxsL07Vx_&IT#zR$#;ZFMFeOF!Q3X-1W#20cO7{OKdwPSLQVmEm-I|_x)d}<}8K3?G zyZg1NV(37{koIfpp^FgUywN`XNsBu?HDTa2+cRfe`_t~563~lFy&>NTu`C$V7wlHb z75<@a$VT}tp=;L8Q+(jg_DVF@a(gL|zT8hOYnFx@H(VbZ=^%z#s9aJvAMc`D7rsZTPAb#2@|fF7fdJX%1TZ=hVy@q~FUE43rz{dzDPQWYA3C_yvh>Q+VS--3h zYgXD6his<)dfs(MIAy6c zr7>S%?TU;@a#Lym?dI;VWzB8dZYr*1?D)-OwWm%(#zRWuu^Ka9tPpHCf`FYr?bDx{ zFUN&^-#?*O+sHSwWu`CtAgh&@e6xecRRyWwIj#LXQM)QM%j z*jP=9t>9r9x1C;~{d|xOJ#XnTQXI`Qej`x0x z@mTHKR0K!M2!wL>*l0f6#H3~w+87{3gXlJ9dL%Y?n5~vB*0!lrct(5Ll>gL4j7-^s zkdIaypB&mj_bw8!U1|8h|E36Eet%!+%`FnU=B?FX4R7a>i0Q+n4%nuHbcG4JFRlwR zzdkNF|U7Qw^N#aIbh`T-qJxyB$*1my3SUS1bf(PCS2e zTH`bCJt-PzdECI0m!wL|B7k+rwRNYrF){*7NE+iwf!dtl{MF%Li8Re=?xV~Ws+xjX z>0w@eNf*A-g|dZCnGMj5vkAi9@p#Cq%!5C(Fl-TAv}ZYl3i?#g!jU#rV-K>#4qtJY zxn|2~bp7wtZ4wE|1J>P{8|*T6M4G!Hu1uuiHL#;y=Da4JS&Zg1jkUD&7MdR9E<@iB zZ*-VXi|k)dF11w+j~u# zzUvp;9WN1NoNbR3*EVxkH%f=y)tvJx1(q>$6PHIY#58gPk-+8mp%T=^J3OY9?&TBO z+fi%FS+IQG1#xFjy;5bHnpE!>cYVIyJD+ZxBNlcIWmaFhRoLnq^X@@~Ttf)2MQzVx zGB;F1=ykieX5di5NSbQw*3Il{?ubV8Okqq``r6v7xzvzL*0lohnD)CpLl|43*VDM^ z(FfO{VeP19`LWFmA5PD!cL$Vg*LVf9aj+RJ*ws9AB7B+>K{tcY|GX6@~sTDRt*-0ow0o2Jo14Rqo&Ai@gT;wPvEPnLDv|qTm=Y z@3q62>@mkYH_H)&d|G*~;wF}u-HM5(%LrU)X;o%V0%`%NNg7pl!Qj>k$HJX4Tpl&? zea|JMUcjWb2mbvcrkkgjsmIuEBV?z3`f@NUN2|SmnT1i$kv^9EHSdPN>!{{~!JMUw z(tC+)2x3ocDJy$%bL%30FR`_pia(>#s238{UZEwtu67vx;aD5f2Yz>)Pi{wBz07B? z_Qk~J-W`?egB+4gQHJ&8PzjNtLag%*S;$7YZT{nbY>o)&X4)A@sNRH0Kck{v?sYsz znXmfhs~QYVt1~vhm(<-cv8ZKtB3h-{to9anTMclzZPRopOR8~PtkU<4(3?C#|2F2? zoLKvp8PgikFVtY*ZKV(ml=4O+46qBKeAshcM0=dh{0+BC0YS|0rw(J%&}$hYC|7uGG>CLHC}9! zfLo z%Mc%w>LjU~O2-mp`P95)&!~Kh5#}~$f2VHw8ehmG{<(L1EJRaJ)fPL|ZgEj1-{viK zmDwT;H8{G)s8>&tVnhu)FOv#b)V~+cOUCq~OvZ1)Ip-)aGMg=ERB4)x#~MozXd!RkM68UceStR_);XE)nv(h|)Dg-eZl>lbD-a4~_Bgg0Owe=SnA_WY9YNL*@&{4+BV13m&3u!)t8{fxB=b~n9r+$}M1u}&%lmqeGw-{DDLlPuP zrPz~ZhAfAbNrnyi-sj;5<4?~ZrVsbHD|DBxr16#V>8-RgHi4UG zl8pejXG`X}d~1%2Vj8M@Z~={!?@Hb=8a<=QrKTj2Tn9h8>}yiln0otZNGWDF-wPHB zbO0AWvDLY`N9va<4D19uLgDo8iH!apl;k-dT-$)m9xQGccl zdT+yJ;G9lz*M=>FFmTOmaXQ^G&qn0Ak5L}IAWFbJ3;FuxGwQ0~QJ;`HJgucvc7~O~ zMGErh8}t>?SrEkp0_GNxv3^HakPA43f^10nne7OFGE~RZK_a>P)PTY#U)xr6k+EZ# z%|=JtcF$|tUZz6XhXl%c8CrT(9NU$jr<<0$T4a_)rv0pRFrQ`@ulIPNR{?ud zb&fDXSNZyEX1*2Axf*{Lk63X!BO$nG`W>h%86=N-gi*xsjvU+de7> zWG1Yfl}m}t<5qG_`gZ3}TICygp}AK;xX9xZg`OaD?(~d~K1S2iY&j%#n_rb6)s(^P z99`-NVN5-xWw4gf%ANxLaX-MES8!|AQ~;(r-Me8@Sb<@~50zxGR-b811Z@U5sM<3ctF?L;>esb7U-A74 zBu^4|?LfT-1?KSirBKwi4SJyF9_sN0Ri-Lko}|K`e*Ej>eBx7``7$BJ&u{FGiCgWEuy8|lk`OHYJFA2v3WFUTaCX`sgqo1i#rp0$#uM-5Ekc$>M!o%*G1zSTm4eh?hWDp$9EWvv6N8o%zx&!ikx(KpZh7 zG>;P2z>MoYIvzd*+M`4RU|!Yb|AfGqu@tBDFgNhKbwsFG>?PHBotFd7&`8102>cbP z?@H-~nDI$+4q_?%)%lqo!m3s6WLp51g&DR?yDTyWgWZ_-u9PF>30gQmD4{{u>uuQL3j2DdzOf+~8x?YZyL8~qBaGlOHeypr94+QMQMComtPu-H6*Wsc z0ZBi>M@NZWBm<4lF-+c}>G&bd<&Y}8II&4WlA`7uCO^eim@GBbqK?+A8aI6$X`Dih zmYKlzy})k3$s;;9nhxsV|AAYdM>gGW-%#56_GQF#4To__FS)a;TRP=LB05-ae? zQm!rW)(P}_8A|-X&T2ZH%uOYr z3IFjjm;Tkvm?Jz%7A?MpsrjxivLp)w7pjl&2Obm6w8Lz`;Pos4=kRvbFkZn>h$k5$ zA8|xBzS6M+hSXP{5TWcfLGoP}s)UUfmXy|hDE?Yf+{7tj^NBhb@pavJ`pBuC5A``{ zSpmGx^8-NGslNg%|E5cJi$D0syUSX5pkvxwV%dSAl70@jCq!ieCFyX+G0RAOu>}C8S%)3LN z2jyWl1o3Ch>4N)bZlXLr(8LuPz!Ax2 zhSW&GAu+wCqlQBYiy&ie2m&^XTAy0MFG&X4$FhrL;aj1CRCc`A_se;*X??0(78!Ov zGb7&GK%z{%st7eZ&YEaKZfDP+Gr~ zs~37K^!UrjX1?G|4Gr5TbJpT`inla4^D7yXz=T?|JPv{-<<>FUDsgHUaUqbJ$+eU6 zzm%FooOa7miXbF*MIojW^Q-EB=OXlSwWn~%X)Z`$3KbyZh}m-VzrLDivvuEf79+GI zEQwcZYzp)_7Pzn|KQWc8(%gQ(HCQ(kmV5#OIgR!t^Mx|=-=0FJT|o&@gq>3~A9q1- zNf{lAPxIph*xpGN%0yoPPkeASqfNx$yhkV{!bWY?WdBniN$~`#yOLhKBFruAlytAnCAI= zt6c)WMAK+isqRY`Zmtnn7M(h{g;`P)7?MrcRN_>kmVMl3^^+0JB9m1IepM^PC1d#3 zG4lG9Qw4uwhav&It812sU^w|5)$=h*-&tZ%*ASz!E}^V?1~Y>>b+Q(-y@a{H zs4t1+x4U#OJ((yOsxTTt%wCd8yA2mYi&Zt#0ur!w`*-yeb$M0F|7&6vMY4`rVTutf z205AG-6g%MwJ|cF~M&U%A zpXNNkYn~uC3gQ*6p!kHB^}+tCSK6Vy-WbzGhVbhsSZLGON%VUj;dxK%>(5b+-%4Q3 z@waTJ2Fp-AprLTAX?hF5;epjN&t1NQ;&!ug?>b}Xa~-$vpLci?wU>p|BLW+0P?oGC zb`kl1Fj)FerPRE_%S~4em94~^8f2PNDSvJD(1M%RLEf+6mubq<_|$rn`!q_S^WVp} z^pRCd$X50n09+!CcenbX)Kgc~H&7(mTrG^L)oJ!OrYas-mLXTy!SKI1iznA32-#Am z=lAzuL3tSppMUQELv-t$W3lV;9E>#tDq%~!SXqT|tF+My?_7NxukZ|MwOxt)f#+omYpHudpFU-61O{_F0MW%%DC zH){U~zGrFw#RVB`w0s&6u{@384q3ZR{#5cm#NK<2vdc_6VjgqLU0Lc3TGt&yS`_cZ zD+*w)etm)(2NI`Nl}2$302MCOB%#+o#UWe9zN%-0f??Dz7_do#v~nG*a&gV)5&F1s zv;F}Vn10f$zC?9)1{Lk6JfMCOL1Ah8C`{WPF&YTMimdN}VD|}%n{}ue6zu%miBrf^ z2$8#5%k&cDl~_!k%Ft*_y)sF8qB&L`^9Ey~(JvfA>nNE*;009^fI6P1V)H0d7Ox!- zujwK*a@^7}1ZJK0F1^V@-u1R*^KEJHxPzz^}RG1AqOw!2{iK_2t;>R<&6x31e@#Ex;^!6#J5;t^Rf3|9Da70jC}tGQ5>jD zP&71Z=Zj>u!v4AbcS+cDQNF+EY*mv*Pc3S$2Bm8~t1_gjX7`#e_^nXeWCwQq7mMe2 zf0E`{rw;xqS8`dt9<(Hk53bO9)3l@Hp{3lf&4)04BPgpJ!#vlC@>o$2n_3jSj{<1q zl<39hzrih9RK2-3M~^;%Z;+t}+=PNd`1mMZrY-_^#+(f29-jRmIxiZ`OJ%Hl*nc1mB0hcKbZBU17-Jp2|ll4?~PjEf_ki5a1@j` z`xFo6t<_EIqhbEHF=%iAOs40X}N(ZN;~>xA9cW@KUK<~9`s?q z5dNR;!i-}^M^r8E3nbAz(L3sL$c2waf8SaiBmSQ4h{GPK&UUpn`@8u^w5f!>wB9uH z^jLLvxAF`qY$}>~#n0_5F>OWta89HWXT1e0i7He^E|~KsthPtu`=X#PcGl3v?+H3) zQ!@rD*Eh%g)Ak);T&i|`;*zo8hN6-_w2TtMh%?I94EBDCWG_C3tAkMP$kg7tuVpG= zo7H~e==N4&@DnykbI((kT3Nu5BU0;!zK4@tF_ZYj%lPHq7h(dlFls&c8RPKNj1cT} z8r9$BH-~`n*s<{4hw*=uPjZ@dPeRn?`C)C3+f7DqT;31`8_R&<`6IdTC~il5RKM4I zm&P8giHepUyQ;i>qEnIjyXLe4j1a18@nmESI}Wqa{^urj_Tm#!wtaYaBSUX7$IY$k z@NWSJt{Lz|6TUU%y<~#%)6?iN78+o&ZP?4)%dL1X#^Tb#ceE+|ndU}Db8b*n)lMt3 zqzeyo5g6LuHIMRZ>xzL_3~p|z@fmW>(0;;Tlyb||Gl$g#Dv@{=|1oGL71mo77EnL{U;B?LQj^UCU} zys5*AITA5;KIVQ7!m0l^D=E_FY(B9LjsLRG_p%?UYVG62n%2dSC%_2*RBj(xn66@e z&y?R|aO=MPEgl*;Yr8l7`2QsH#ym{ z+02cUp?{t#iL=rY%xQdCQxDv%PGmvo!8}pGe%B^r)&KCr4V=Vy0UOI`YRDova*<3o zy50zA3ydj>!+xvTtvvJ~a>QD6>)KJem^N#WR;qm(+iI`E7oe=E>!!^1EdjN91xUmG~3$m;xN`2XR4w%#E-4uredXK0uVWk z3vmtbNr}R&RT4X0@@Z#sjKJCjK#y&>5#Oh0FlxH^_{WE~kYRiFHmi{!MiI2xEGy>3 zW>TkCkX+#B#gxLsct{oqg5i!C^aSJ+fuAz(5F5301+Si#|?qi8dZxh8DC zV)arhX=Nzb)h?AMEOPh1HE!Z+*5i9btLu{CLY|?Ke~WAU2a=@WJ9d2fxYWiU8PtTW9581Q8Te~D@#%$1clLcJoGi?D zXUWkYJ<+yid5c)e#?3c}T<|Rqublc~kUJyDGK~Q`2hlcF{_O zGzXj!>Xo1K1q$RtKGS^KG$q5G1Ti##!S>fk_NenW3uvy`>8k}I^%Ae5rRCVNDQso> zwUHxdpOVC>urp(xZxc`Jj0Da$s^^a7#GZ*qyzG}$WrstKQNEL&s-Q@noU!7{U%p%u zugk~Zsob-_bQMvzFYIfH?+GoK?bCz&Gp;2tdjc7CbdAE~S&1NBYpR=w`?Lv1VG)ej zoM?Ah)EC_paik0ie4x8&m=M{~cRuw^Er|>oNMC?31Ta{@I0CP2=6VPMt5R9;n~fkFoyir)RO2bUW&mM5Pcv{#yRtLcO<6ZC^BB8&>j>>>4XP(QdCoxF1f>!{nvecEl!u=KUyoZz z5l|u6JT~l}dWo2>AHTgWhUl7)jf0oRPfR|@j8dgM7y8|wB$C11s_Agl!a+;%2((=D zkAr(RSpBH;HLB*G?dEIE9Pc?dW>{CPRqjBhB?9Aw*z1HXp7tg00t`72eVL|~NTYQYDJm&VSisw7)gHru0 zE#PuAH96Sa-#V*jK(~{yc7Xf0 zM2vD)C2KcwNPz7r&cypG1@vFZ@H8#$jzEWYKAeJ=lOo4UNW|nh<8~YHIa(7 zo59*NFe2@sUZZfB0JfXwADFc0pHPW|WNo1062QK{f2ki?Q!qe){a%wz9Cyu_vOtQlnHmKkA&rsqnjgJCgP`;WRtGuwy+ zwUaC1N>HA^tYk|V_I)Te)Gl=N6rN!3b-m7=4nAUFjHC#W_e}zNa}C5?gFi95ZGUgE z+05#eWHe7ciiCf`REW)V>_r-PO#%{$% z%3yDSyhk>KS3kUlG%6lk(@T57f;UBpIY*v2niWpPZzM}q!8*smfyfw5eR<%Yy(=q= zEBAsCN54UR2X?I32i6?m+beLFgOd%!$p_smo8I{x#AYFIhsedyfzp!1G$niqu@ceZ z`bfjs7VlD;b5xlM6mpR0-|AHZM}14Sk~Ss8 zRC`ZVn~Co71a@zWo+CHgxH$a=d4K1Fyh2!wV75GD=!k((4^G83eXGG=F@4+-`0hpE zabE4e^4eN5(KNppKNw>W13rExLyJ>ZPi=%32chXF4ot3v7ptsvRXI4vTrXHoUCIpW zU^M|+$g}t?lG9iUs~4 zKi`JV`xslmsf%IL$fDAeH2tS``0Jas-zT3*X~|YH@(?Z677z43Dnje*@Z+YuU3)bH z&gz7NoAoCuJ?inb$z{7B`INNA*KrPgS1gi1%OLIZ1U=vC1K4P`Hqz-dQ4gO#t5>i* z)BmR~)@@QsFMMNbTp%@>oI}LR_bQtu91vnWPYXGF&MKd!pM)I+(lw;4EiZQ>TIy?@ z_6th3>9ky-=>q7`~>pQz`qZJq6 z{!Kt#E4c-M?`YB=YC{%pM$~QAWtWX+mg&fE^b_{4JcuoRkgXi^`cL62Gi$J_s6jAL zw{j5abO(D-;MrAIH{A?0q4O%?&F!VN>LwBRjsW$51De)Qmjtl$qnKLOHRNDWx#N{p zvDhv&{@y<978xFB*5b>rD?wiSr1~ogwDz5oQOGDR$wl;0=W8mqXZ8ZoUzoNJdrK&x z{Zda#z1RZ2QdNK@kgl+eLLZq@-9IVoKPy7p(u_;!sBJCbN)l=@1`v;Flwe6=F}IS* zNyJ&Oniv~$>?+aU1F+W7Ys}SRgH7~L+&-J3jk@hM*u2STmy)ESq@z#ENJjqk%4Vn$ z7)itxEce=XCEbS4!K1K8Q_>K+=R8lknPtohN+%ClL-#4M-S(zTSic+%vx75{g zupTbR!~$R2l%ZUAMMgqZ&;fQX&YuK78Ph`a&ngrE{IUG?pA8-{kSC^O2hqSDtdJCg zUUf@rnj}HufHIQuWC6At>3=t*my9Rj{^{LMkYHbjYA18b=_HsV8)CtR+%`E%YPtWG zkKLYvZLX68{twn6@fGg1Q(KqU5>MI`X3*SmXMcQkn^uLfJ;5PdMm}MWi_mt=SI6e$ zTLi)RfKb{~6|`qh8uAbqS1r*u96u4&iAWrC&0vS-=ikA3>lBPJ^KKq3IETmVXbti~ z6wQ&e>@MSZcjNrkki{C+PQk}hz&f+-N)^Z|ImCk26Sp50$AHqg^-7Mwfz#Wxxgq`YczQlD66px*{f!b&)jTy4HK8ZKoxz&(GqIq&x@a z9;zhKxXlvypv!@v%fTRoML7PWObxI$7tjdR&a@Ms?k=6noesrD-Y!u}hv=!W%xjk8Ls|Q+4>w=G)!^aVsY{Zsa9BUi)wCd_6O0#^_MDt zdZxs(gSb$a5RHwI*rbeQxem`alYHKYzhsIlAf1GRfz{K*A_ii+9Fg=x8A?gRkc$V2 zJRmEz2W$q?k%N{BZmg0*X!IAzx)<7j>uo-C@5=;>DYWQErZAHU+YkF9l3ep|T)IY2lB{|JdWgV&sr?ey(_ zQgPIH&S;UO{&Us{=onCvP8O$NV`y%nW2-aRP!6}sKH~E42(JthYRwPzJ`mo`4Ua$9 z((|$f%gI&BbIW(UfTxWgzg@QC&G-=nlum0H`DPwC@UpI0X?w8{XCke<_F9VRxoD{{ z*4bMuj06w-J11HIJ^vA&cs9uU-Bbz~b7RcnZjyFn5w4~PS3ah*kJfVjr}{y5`tb!g z33_MZ(}(FVA2?AOo+lCi`F7*~4rHvrk2+~*TH@AuJ%1Np*Rq`yN;BNfHVLQ0xSa?q zCUzUn4qk-&z{RdQI<}AgVKb+T+_DbS3~tXV(p7_%-+ZBzLu$c$IQ#z+H5t^w}c>hMP zn8rUZrk(KD5T4dRUZ zkYGOYFDu=eUT)j!w7(7xK8cKxY~75_UR2NB^4m6bnFIjeJ?nLM-1Zsh10_bKj)W>< z13msd$e6CXzu?mex3A8t>)#!&xm|Ly5L>=!BTWj~0M*-c4nM27uVasA(`=$-lue)_ z6RX@0xwk^0c6`Wu(s(qi%0BAr!f$S3E(#lizCx>OlFO9( z)I+nIz&U(m<^~aam;pQGd{wLW=dNdWgU^xnmSmifhB4QbEqqU(I#GH-^vy`k-in{}uh!d}Pzu`X21s9e=MU4*J<_hvi!} zoqFg(3t#HPQIX#|{e<%b!S{E2m`Td^p9{|^h6On`THjb5hFxE3mSsE(+jnnGi{X!D zxXQii6p}gYuvA1gM5t&xMK;luTR3nP2lAGmA8gM(lIf9#EQmpFT`1qG`%h_CWDCL) zGX-z4{NFZm0IcMcY-8^Mru52?nPD^kB=?-mFf;VxMd2^ksY~mY@FJC37_Ru5Enp}S zXIFC49BV;;P8YeM&(7ID(xRByiXgaT)ph5AxK$QfPG3&gjyUAli@jqK&aqdz3XZI+ ze1$R+Q&4al-4Iy^poQl1gal5h$cdN~p$5aSW-pR33+B|*Xxa>&q#TN%^3TE2Ii?jh z^PU6$C^uKHy72WD2MUJ1`o4y<^x@-Gm~qUs0n_Ra(v>%0G1ED|=5yRd;cUrFkrn>? zr>8GrpJIoFTLd#`CAktifwoY#TtL6?2SIzXM=Env?a61|JSxI@KDB9?geJ`d!}QoX zBiJ{n%Fvc|iR3+RwtDCv$n-X^?|@N07s%(w>ZRF6;;y5jTCapv+TK)=!#HfHv(RB_ z{CTu3*}T5N>ML~;GgXxH9rB+Q{R*ja!R->{JS4GBo=p!`nEbHmBs#)Zvbk$7G`}#e zhjw_U*7?&8!7i=;n;Iv{_K8wlU>6$(H-ChEoV<7o9SbSiyrVq%;T2cOx#eZda~)o_ zJ%>8#I3rc4uiMu9_p;EZM^Rn#>Q5u7pK`#5WK+V1+Bp5ii=uex=1n!(Lp@DLvlFWd z@0qhCGr>y1>z$j6SE;zZGl+!YJQc z{&FyRfKQ;Wr|8=as0p*#L(2tn%DPQ0jo%6$@uYpFM(;#uajH2x>LsIPt;6TZ^p_;> zH&(?B9_LBa%BI?o(`WXfVmK<_?j59q=5kVaOkC6Fc$jX)w`{%zRdQ9^TvWJPPA6hM zzz-;VruW_CcgC7h@G4&2wo5VeSXNh-%3vk^TQI^h(+us%iH>}jiu}qj%5g5%V6H4* ziQRjiq?v*~;WNMTG++c->HuTW6A-b*Hi)f6@kO*8VDVt$qr$p3v&iMy7Bk7$2eC@^ zRFfN?L8Iai#9<6Ui)!L=Y)cdl$&l3q10IrN*`qGnBir0(=|Wr zJfCpONN5z9e#2&9J7$Y4Y;MCsqMl2vEI zMQ33Xo?Z(v+-05~SZQ5|ZUv!B=RLJer~)su4hp1aIQ=F&cQs4HtG85yv>F5ZS*CD=O zaf4k0-UcPWu~kJd%AY4&HrF*3TkK3bj03wlCjB@vy8;rnE-Wej<=IN_g?s2chf%+0 z`9{MQu$}NT9xjG>Qyz<7wC&;9r`wMX3t5mYRty9a?y6`Ds@Dmeq1PGV;U=7GCE(=& z*EqdyeW@VbNXV+D4?Mx$Y}j;e#~He}BWarSA$V+It4H{OK;_w4#2$wqA2w&)$ge~A zlg`p%lwThM#q2V)Qum+8`yVg<4w{KKQxnE7p0hlb@FXO{qr|>4inn8T@VhC4|CdaFJKc_C9=6S zk>@_eDL5hGATZ`GUy(K$;J|wY-Wg4!?g2j$CVf-Jr>WdP@RTv{N6%9TSDN8W>b&}P z8*-KRa&tzF#|+iZa&U7ct=@QItvHK!1v1D*ZchiRj&xBy7!SV&RN$We=`30yR1euc z<6Y81r0^%a5F`>0F>CZpg$qDnt|_pQzXous+>a#RfC7x5KVt0Rg7s7oYRa$NQUs>N zey(xm`u`XN?J{nC_0GEsp$v8PXdTGSo*{E=*&Tol1v0V~WBe%Lg_80cycSk)BCpjvS7j~@t&V{eD zQsvm^&)I%H=>{`Xa(|`Ft90N1sj$M2~h%c1&^X=hvZZZc{<(R(?Pgq1Bm zj=m#>+mXO)emj2Mv!ouiT0U|;8kkf0wr%o1=8UgFTZ_4TL9(3-!6q+?_ql4Q2K_Rg z+$y7=-SP_;6a`-`Qi|@vhhWz6MvK>VZlUg5Vb$Bcpa!WLs0~~QVW28fHzQH|j{Ia{ zW?Ocu^Mxi&DgdE2L57q0LQtDa=-rxBRa@HKLNnlFYK~%mVfF+n%pb=p5asa7*0u3h zJLCY=(qS+A?wR(Q04@ych~RKX;ySdrd{f0aTou3XtkhJ-Jq4g2{mVObbUnHHHl=;N zEJ9@T>V|O4kvC%>rEycjaz$0%`4Hz++va+Kw5GOsjj4r*Q_p>whEkOt`A0mm1mdaB za_uD|Z7ffhbXVBMyFh~xt-+!(Pz4?Qm3_QeGL;eh85%xui~!bKh+3+6 zL@ow_S=(Kp;<%8vl_1&~Pg1Ay@TolaZREFO)DKjsWAbrKBtV+KH;RS8o@(3tLpJBg zMFXBZ1;mz-T;0zzv;V^kO z8$cJRxSpPIE{QB68#&&0JGu`;DE{mYgmxNbT)Qx1e}Zy{^UpP*6jZJ36*Wxuygw?c zid1`a6I4iks6KPg69;I@+OiAm z4v)YB;~l`YoLfVaH?spVj>d@Y zZ!S4}3~EOwCT=sW{MbfbXdfvk=y?ih!RI*BmVZ&uUOVTf-X5o*PO{54B&n{iHf~6W z-S9O21bU`NIHJD%2%r|!nmN$XzsQkdK%@D7Hj%&6{H_Rlea9=5X4`#jBG|d~raBg^ z*5=!)A-ZBNIv#M_be3>;v@ttWg#?1=IEY#?y!KDtyh`3xC9{yfkk>gWw#a-GV+!!9 z9~}zw;-$i(4~W>I$0Q;FyPDA`(sqv`g(^$Yn+B3@HLQ~n@#2fti z%bzTOqZ*PZvk+ygO`D6b#IVH#^cZ>4`zcf0k#@_`mCFuOC3bj z%#p!=1QB}%7Lv)jn*=@oYED$kL-XW;Z#^&A02cD0)lik#y4qRtr5Tfu7 z-{B#j%F}PI(3f|oYKQ`9up8h(35y%5+#OUw^7ZHwnPKi}l1tMP~m?urZOjT|FgIpkpSeba`$46rQ?lp@c6(T}NDBN2vz*luW z9|`O$Ktmir8~OkPPNk5_+o1o{NE7f|zIQzwiq1b;9mK1@ji&h52mp;TN3EO&$xFtvwHd4KZErb^YoI3Hy;Wvql49C!;)t0k*(m1S(FJoUMX-V61W?L zNlR$i+ZQOBc_MM(c~ayD52?9j!rkAg7K2ABN(X9WJ)@akoF_eep(y$vyQc?aNf70H z39@OZkt|2QIT~xkfJP?oe9Caa;>ajAM`9_`WAn6WKXmZ zV7A_4(FA@O{$*7`sBZfTTAy0f1|aq7sGG;NgpqfEhiN>h?E+b~`TUc!z72#STr#+O zF>g-!$(Kip6pwk{6Q0hV;W^p`^FkweRPg$&277^6QMg>E9d@we#d8i=hqRFw%F`T) zyg+@NoeWuq{z+&86B+XzyC`7=tEjDuncA}Z>a)}*(B>!+TZF&RQLQ#&I38+!r- zaKX}iZGs3!*|Kp;ggDcc#Kzv4FQSIedNc>+DQX zo(PuzvSegMcLMRbC=U+1+1>sznUbD^T1DB!o@^$;QO%Y9hHjux|Cy-_%+fdVuXzC70T zQoiWwsMvG{f|pYpadte;I^IkPXHVq1kaY$iF_|=l=94mWH;F>y+dsp6xbdQq5Zh(O z>wyyczNCPWke;xqnP$IQ*4;nB5(~xiz%k~Xsd2(b_Xw5P3Kj@9bM=nvG65F!&i+0> z6l9!>dH*{9#;H@92aSJiC9Y+Jr4phGETg5}?v2~|77Bi?vJhCUCDNk>)vS4Xw9LuF z=Ak4^6jtKt9RZ}aYJRW~xl=@%B#lgGAn0YI%FlJMegNJN2yo{TqsIP30zTN}<|U+h ztwK1ziRX~Z>VVm%0^HX=+!y&;vVpN3GeRuVEj2+)WkS4!Ea(TIGxl4X?F;WX#z;iR zp!X+7^Et~&yATu8#1plUVd22URP`W#zVA>kkW?f}@ri8FTQ_Y1sEhi)fcVQDwCP2F zcDfoU!{O@g>$JhiTZSAlU9PfYc{lO#d!fjbPBa-tw=<=S`@_A~IJf>95)KHlhwt+n61O;QQLjSe3a z0JT4Jynj4s4^TrPFvHv=9u4YZCQ`MB<+r}iTDe7p9nWrhy@i>x0oWN|GMBA@u2n#J zqA+o@+j<#5&v~NO9WJ6Hx68ajM>bs``F{7?#moHsoNIrf`Hji%uc#4FOMhRi6)=0% z!$|_x?;hM)|KYq9-(&_%LxhPP-n|n5*qMl_<}$C&6894Dc=N4nlBl))`vdqCzlpB{ zg1%AHvX()S(`&`4MfFjDvyxNjFpzUwcc-n4Dgr(&=k0cAih>8?Bc!Yr7L8Z0a)Fzs znBH0ww;|)_*X! z%q!+`1WbbAwh41MVJcutZQJ@=rgwx=E`~Z1U2A5xgrrsgae99w(saLI`){^u zXUl+JecKR0(MOcVuWVL6ZgKM?mx&GrVvIqM)U##TAV?_(*B>S73kDFsCnfS1(KuDa zj~A?)xeyDAR5*tSmFibp~YotSrR8`Ia#*+9&(k*U<5 zImTO+SwO6CZab^{yTWtE;4(+Bk*eYaf-jniz)t!Jo%3N8!1Gu2oKZ+cc1LdrCe5Y=kCEk9T+qU5G7>>&z{<5 z{HbFB*`<6;?mYbI>da5!7(|jGo&m0@ejZpij5cN$2D6C~zKi~+Jp6^gr6;`n8@qHZ z0q)G)E>Z_y8QV*on-HQjp#DTjD8E}Sc1R}t0Cl?qc$l?r!#IV~Bk~cH>W{?B%FDv! z@z%DqX&1}HE6imvGMb=cl&~~8Ieof=>0n*V^fn`OoXT}tyvNKh(RVAtEE+PKv1B)K z0N>cLQPQzC2KnnlVB?VvPuOcM=8yk|=w26%7UTXtent;cvd5jw+elzoj=JH>_EWFu zz^wpR?%yM>j0`M3FJbm^pEcm4M{ASpmm!8=_L=jvzi*}4?m_s-8}Y^+dT`v5GR2y` zwgXQ=@Y$;R+r>OrE-Z#&eg5&VvU1^I>t&f1ZTLld@3$kW{l|l^G~aN1|CV3}+q2{r zw{+r|jT`EIv4+-ahSz~@_hWt@c}l+xE%r{78b&V$igq8Yw)ZfIlY<}d56S1$BXBo( z07XOV$Ck+5WLFZSW;O|Hb_PQrdUY+tp{>n!e%oYrOps6s?jNiSKq&1_!^Nx;_a*P3GCQOTE2_knvp}ZhG#+2waKuF>Szov7P`fK1};j+Qk$v+lz zw9Ny%>fpvuFN9`5b!>W>VML*cNROYImKP4QcDPT3-Zrb_CoXEl2nb7YF%h`iX4+?r z#jb`{w534Qauk702g5Y!^04;=v{r&M#z-iIt`8ZILbvYebRjd>g|C6`A%#-)N@?4e z2F)o_^y;qJPKNQ|ujAV}uVtO8TJ4TG)i6eBs0?aKCc4v}0`82!(BF@Dg=amO*=vF8 zdf+0`wd*FXbLSoP`Gm_bh%F(yo*`!vI|(K=8L@zI72jQymvo4%aM_m}8X$;kpYzB$ z)ZQW!B;zv14G+nUD=+Qza^1{4wV<)F*_d2^(ll6k$$?$aZDoUns1UU-j^M!lSUb2q z4ZB9!&^HN*^E3jF8Zp?uI>%3K?r_n0wOmfKaVhX+H8hO`L1J#p^^QYd(4}gK8b>J| z(T9arMRfjYETh2m2W!l+rK^f6d0W^YV#-zw5;o0)tnVc?TT6-XKWyxM22kftfY*&D zA9&jBFYTjXV7bHy4)zm>|qE23&z%&0e=6f*iZ&%p^KSYe+?BeS-6QC;(= zaWHl04V)=pFI_F5^ADJdwd~l(P4_Fu461flw6jVY%No2$ZpnpJL!~Bb7UK|WiQws_ zL9AMaU$&9sib5G}#mC5AlFhNA2BTo?kLE6C$D@~EAmb~Sd2r#xAsjTPUh$}nC7;LH&?d_j5V_4a7$KS4Tj>BYHed|s$iUu>ePr> z=VPEcJuZpYH7rX{8!3xkdg&NxI+yo;Ho#|`TnVeobEstC#d2>3YtGb-14%?M?&+Y( zCb8F4M{{94@w>s?Q@yv7mW_BocVw{9<@w3O$v2!-))1u#2_l@2A&8_KNpd1xp_6vwUDUk z%gf%w34%(URSu^cS0aOLX{LzJWx=U-{K-rV-rNR##bSrRZJ<><6oZRj?^wVhujB!L zohi(^0p*cZ>}7?rR6)|R7m2mV=)YwRASjWwQ2Hn;yz@3HHkb7_3&BK7r<7vfsAKyVPt|I!vfIy#E)-GbrT1B z@sHXP=M2~bD9$Z*Zed|}q4OYL@0DzGi2|%HCJ9zLPcg4A#qD?ZU$yS%^T*j4F__I` z{OCUXxwX=S!r_D1LaaZ4bSXDFjJp5y&2_QMQj5_suD?*}kL+sZc&_t);PS9o?SAA? z3fo?>?ULqDX+z<)?YDZ9J&%HNSoCYLfvVNvvykzn$p@D4eUrH|$je?o9~Wc5Rmox9 z6Tx^lPns*NEm{1hWva%9RBD#8Xz*@c0y-SDnsJ3&Vmgm)#_^tJ^v?R)HtZo~wjIfu zk|9lXyXb#>ndE1Go?Y$Vte&PdsyRT_S}heEeE-5H(o7JV!|Lo1f`o2{B`B9Il_&o* z7kS*e2Dly0w0ETvJ2GQmYwAteSgI9B5}dEYil#wMpSfi|Qr-868|hK}qrQj!woT`6 zZG-RM%s8yGsv|=H>-RyaLb@Tk0+6ARgMA@u_8u*z?$*%1&fQPXTfa39Q9(WHT&qGc zm~iZ*3#q3akO2UyR&N+)O$*h(QVz6qs~$Q1`_ zpaiw-+(}W&P8cZYmDvOkSg2FDC{K?tv>cn{^FTZFX45vSOy7r{u}rMA_ zd>Xa?>B8Id7FtDO9_NHgkaSEO^##NL#M!7r^ykN!BpC$&#gg5+r=Be76CaAP;5i)$7=M6si93 z{WGn}sJHwqGxIPUjQlrhXVC8POZ_@%{$J4geHumwVE%%Y>mp0$cg!1{6lEHMz%Sj3 zzRZfAKZ9^0MiGiu2R%}`GOm|n(Ijl1TyF!Pj#hNmtY6pWXu+DvVsX2V2(S_PxkzJu@E~D*wFq! zrYazHZPriiK7={mn>9%1NcvK76Su+Iq?ax?{C{E)`ky;4EV$j(^gX4?G!}H9;&r!_ zG9L)t?-#?g`yO%v3J4gc2KJ$V{%%&4G#9+5<$&A6r&b5xX9vf>p-G z{dpxw(b!h{icqeaO52+=d*rQT5A487f-@r{ndkZHjSCFS?R(Q{fjRJ{HW+7cuvFmF z)v!U_fvA8LfZ zyZ|M(#+*fYC~k+JbKfE{o!rKtD~#om20`Ljp>jXL0KcLcg;9!aTi0NukZ4 zIwF`sl6*AI-3fGjZt3@vy~v>UK3jAPURI zuEwrogd&fFWCi;bSXa*A8zXo+T}naMNsC;e+gC8(xzcTG-Ri#+_f!R5Hx*BVTn&4V zye@`;OP?(g>a}-Px1SkL?h3Vut!L2aJ$-KhMGr6^`hE{8RL)LO3_R|u+X z1*gQQN<25`Zk!rqz!Hmt7;QXxQkG2Qlm?8mxZ?|XYBN$lW<*PX{3({ zV?@H^@L%umWSu>c6zrOGJU(gXw2K8~qZ*Ue`Lyf+z&5mXMGsKbvpZ}xO;VB z-T-4$1MFnhYkFIU&Up&kA>LFArj2r48LwbEAyst48S&BHnH?2H;FF9PCP#5cvugzj z!Y4sq4ZAB(wM})!n7mPC^3}Rldqg(tyZ$5JrzJL}XmPxydc zQynE{Wl}~v{Z8)y=1(Lhiav?$Qdu@!rlQ#25Nf6$W0J?{Pv6j+i#q3}nXlu97u|-- zHiovCjn;MS*X;_o*&40Mj0j0o^B7<2RkvRht<(GQ{L1^B`|ovQ;t8ae2k`=JERlE2 z9q-ZQQMA=n6-EL0t{z=gS_PU*CpDd#y!~Fa-8s`86U-#uZ-s5!7Lx4yP)}UaH9GsY zE_YjOCLMkJ%{c6Z3!T$%AGY#YGA7NeT0)-&88fov8N(^wWAu;AF4MA)>z~E#JLPAr z22&E~d1tqM=A`N|rh3hEVVqod9l-oTF8uO+v^GI<1uuxX!#m*UX|SC1XSo_N1yucN zY7oC)t&0-G?>Yt33+iym_`GrH9_>IMEuda)&Y;}`Cc<~wdVJ|znF~(_)#nc&2}ONh zQkV;$c2PKm>2ZB8uxJ_R{TOPv1g176ccBjN4myc-KFJ8(-W5_a6Uo@;-tqNI*8zGy zV+vC{zRe3TA3OZIxx8Zq;cJOjmuCEDJxryxgm?AIc3s8$cTS&Nt`26Y5h6s}y#f<((SbiH7v)> zsE4H>6>a5R0*@{Y z7z{-I1B0VMN{|I;`T79HgF%22q(tennq?h1fQDJ5qPgx~9=6OnWB60Forq|=Qj+-j zt+6k}CHHB@hZ80&6J;IjMnHl$i?sgXl+h=HzQC(~TVM5DKK=LvJqNwQ`%2SbJ^Ff- zbJMPp^@mwPE8`~dlfknW(GSmRUOo5x66aq2ii6EUiN4)ZPclP`>>z0Uu|v-o`_d&5 zKk6s>v-;DfQd8~p*0a}}$L}!>&K&shA=-d{V%yR>d!S_yYqOmAE1rxlGPM~B*COuZ zJloOxcQGfo;>F$AdR6?IrhJXJ*%{}4U0t7Q%;C{^dJX5$`#w)9j%ec@&dl9iyR|*j z>u?aTN4Q|Je&RRvKgRR&s5#{Y-{;r<_+Q&|%hhWiY5XX}K6njLgT~n$vMc)S+N>48d$6k zDJ*!DYjJHp@F2wZee5RV1vfVopgXUw=Gc5n+u><@@W7g}-tJ9ygWOfv?L9RU+N&=* z>}RK$7PC(5zX?vFaF+WiBD^reL;j2bi|^|8N>A6NeCp`7xy|6ruE`CehN*h_cm@)=)JK)1qW z%VFKK^vXLFsr60z%hUe*$CL~){ei{q-gAgQ6C15>06|aU;B$P_i%8APvBEl>nG}2S z%f4c3@8vUhdWpB0G}>v=Q0MHA7X-?ojt--pSxQ=LPgA|qQ=BE_gX?y7CWfh?-+N`| zYyUeor%!U9I(hcmXd`F1`9G~LS2R>d;aX^~RSH$hMTN1iw9~w#(Rsm-3M`(4oU_~< zQPcUzboB4b=X6rdLvp3bA)}#PR*t2tYjC8yqFw3m?TF>Qb`^>B9nkHRD@r-r)`PG1 zcaw^1@-vxw2uO3d*9xf;sF45~rlmQe(?DKsT0uLvl_$HP25cDaM0LzBOtcZJ=-(qrk; zqPjkf*!Oo7P-!?uKeqnuXP4t(23DgqC%A#$WNLc#+R(+rJBG)T)IxltaM>KQ9Tu+-4^>9N))dK?5*6V9`wbGMFf79@}_0_RLlYUrr0U!yqU zl@bxMO<}y|-5TNiW0J)uLD|Sp7Zz4Z3bm-TJ}|E0w-l$H>8&t~zRJT(W&59Q)cv8m zSK6c6RTxNg)jH0F^Iwf2T#AWqK|D&13>#9AcC}K7MG&ZuMfx zDGv%>M)EIEnk)W8yQ17?$T(Qn3&}~UbPH~(=!IbA&+60tJi8rR>HdZu`aiKwCv6QU z{`J`Ic2zcq2PKoPN>5y4g|KRX4C%dXi6nF5b-@yEQPp4HB}6A+Q{qq3T<`wXVZ2dU z*0s~gR?xo$?$4e9tLI8%X$?5cc87Yseuc-H`8dDXQ{PFNL8o-xV@{^a8!XZ88F|zL2QPZsJ$UfW&6dRw-9` zC)Yf(g~*^M-dy1~oswu-{a0}A!pKE?;}3jPLM~w9A!#LvKyYI#-YsQe2C0G6?d5wM za0I%vhT4SmHnOxb+)!_VdOjfwjNw?UF_hd>5VXF5`<&I$S7v!IL~CKw&Rwj%cD^2> z-J5dTe&JX3J~S3NRx$ZsuEWL+RSU)+hm&@bdI!GLBKR8o38VNsA1{O?@70qwV!s&u9UCr<4$_Tq_4wTuWIB*15*q4dX+o4#_nP*yP)xAObE`8e0ZRt^8~x~iO{ z887+?oAB6&ze?IT(BZO;EyYibK{s`Yl7l-`Y_vUHPIUHBpE*l4;+RTJj#DZl|7cms za6?{nRAaYYd$Bby&%87U_^b9iqGiifQpLPz_mfl7wiUiNi$D^?iz&d`9sZa%|6}Mp z{GtBiIPToJWqt4LefHK_8IiklI3t7i*t=Fnvy1uTU<)h#dWM(t9zfMCfi_Y z=j$*aZ)W3(?2(5%2WTrRG^yNPIo=9BWPIQuXtC|fYijoQpdboFA&v`s8TzL8m@zqF zCb$uTsqKcDDA7bd0+kCxEP}OEA%ldSyQMYW-aecf-S!g$pD%|?(>m`P%gH4*f433e zow#@Plie|Qby0`^A!7s_9Qs!wA zP`$fmgQrDXr|BKuiSIwFK!lcrNru1t_|q7c14~?6bsa%<&SFb^MqkMqcVLlJvo8@1 zc~snKbwK+=B{V7!R7xRysxVMd$)%v?eM`{YVlkwGxw_Tlk~z`BUxFK3JyYB&eYH zI}Cy))+;A3qinj;{;j1+MGc^%uxVnzt*M_03}wi1xu?c9^2!pu^{YWU^tO}?ndeO$ zd|@qL=tw7K6encxgHGekYgv=yxw<+YI4L~Rc z#xMY4N9gT}xM3XX;cp(EQb){464;rWrU01=mN~j%&6x-DzZHp}AX`=;ikl*3e#<|7 zeCb08keDxjH&{KW_c$Vu&!L(x8O8sp|1vaCEK-5rtS$b#O`5r`+%FKq_iBtdJrN|X zS~w3c#33rW&Zl+(_Ky!$-u8b_zEE+S4?iGOWq_!$=6|#$s2S@zoMy+@j4u!(+(1!} zF?kY=0R0i{u#f=yH{kp;(jQN~u?5ElsYc#LT-!j58(nJMG@UbwUsVdK=WInC|EV^} zr9E{!&2&2LRJ96{#Lv5<*6zeRb6cpg9+m4R;a3gV?PwH*!JVfOu5DJ}{0I&iS~-Ha zK6O@n^THSg_4ct)0|pZkr1{zj-@-fw#Q=RzfY`T`*YTkoCwt5J(@zR7n&}#51R}_=&S8mc5H7|*V+O!o;?mmW;`cUlX8ue-vp538_e763#Zwb_7cS7Y+s&Uda=V0bCCnA6SZD z6`yJuiVir~FZgr1ki9#H56n{2*0FhpK&%nqsshM}^OPt;j^ex$jUeDn?ub#Wm~xmR zBR41zku#c`y9vL(SUMf9nzyEY6N{XM=aCijdL9R;c^F?+&?7Q{LK4u&rH!A?Jmmt+ z;`nEqyiSdwj8=f+ZiH(ll!>`~$vxGuzypFuKE?r|#-g~#$YWurIk8-#UI65PT-%%k zSxDzF^SMVMLCk~F>D3{1;01sTvNmLJHsJ+WM4@`w%ZMAvi_+N!$`BAzoSGM8<-@ay zB#xs}0#j^FfTo#iVAS>fH9$F7WCMXLiOu3+!80o>Yp#~^j2}Cw6G57hE(X9GTu8KY z&Y1uRycssHUcx6|0UhPOyjH@!kTXp3;*JAbOky7Z$kte-{=o_l%JBEN_-{x~Kp^7N zOpV}ZZq5cGQ!FYgBS139n+Jsa1kOyXRtpXi``P9-(sZZ^aec|kUoiiQ1nb}m5qXga znv-)I0qNxhq&S_qU#7Aav8$Rd3*jF=^5ZVD02t{&*M%A?iK1pD%kF|offbXWj(JbKV zOKE%FoU0K!-t*9ud1z@@-g!J341yw>c`uL~KZmr~B>>J?aDhEAi>NmOsF`4-qk*PW z7vSVBj&Z&Z&5x^$fX4oUP7tAyQ&(_X3T=$WZ&=NB+JQefT8gI}?Ni@pZ&L!`=np1>Eu@S~!e3 zTo?S~r(n>Apd}YIze8v+fB<@Ufh{GcT8g4G%J`k{UmK}ewb!V#zX7W%TM0r~8R*2~ zg({ia<-Y|R#&{co(yq9qB#maT*Qqp?0kb3gXD$G)DMym8>pVgtk~gG^4dCaoEG9tr zPC4&tB#E{YH*-yYgWJl1&v3C4%PEU>;163Z-%9sB2q3%Vc;lX@9TxKpM0qP*&;)q3)W6y2 zKOn2OI`O4{_D?`x;bC=vS=T(*ff!2!Ps6alS9l3#G;gF5k>7`MV7+7^F+TjOvEm7_ zntfR#YeX)|F7ByOvzOBtC~JTRU)lya-ZAM&;NXYhRYPF~Qmawu%gKO)8DJqZEN)oF zEnl{p{k+%cS!68cmvcjheOs;S(~ARUp<>Xrt?or_XhU)z;By)8I*tx3j8oZSd3ce28MLYF`slRm1{a^2|r zDdAb7H|u|B%hgL~1wxf2N}5dn;)&=MLyJa`O2A>z`njq5S?s$<`<_ zf353K`M#iC!8RjaE)(FG=afKn#H1CF1V$*H4f?QstOAD=eySg~*2W1Q=Z+hA-!1`F z1yj25;ATAWtVv1a>6;hFBR-`UD&i6`csx>)(@p$YTs5AFk6aS+@g)f8Sct_yN7mH8m3EUeC*Vn+G z9N-bI>JesHAZ8gnnw=7;a+(^D*LU(kI z$jE6fm|h!ss2CVTK^5HceQF&AJdc>K*-N;wwFZ@cBIK6h{r>wyU$MK*d>CGS-#h^7 z03=@8;QKGC1s$vwc=l29r%W6oUQ@I;M&e)mRqjKrocY0tP2L9X8xQ^oD*FPdLx9Pn z7F;C;c@=!2J%5U_%FWq?OtirAxH37r8jEw|ZdGx-jsW7Q21=QTah|vEn=kj*xvsG7 za9m{PzIH8!_wNl}H^*f!e!dxg{)?{B;hCs*K9qCLD>jcA@VzkpbxbgRg;V*9dsBe* z_7|&PASl21g%ipvL%L^vP|=+W(ga+}1DHqDOqeB-qzqnA`J)Y_IL`ko#VsqRYM|oe$NL*@R!lsf^~~!uSmZD!cXX)gvSDdreD+kdWPZw=lL-z zi#Pq73P_JS971p58%%cq4jveezTt>9o26w+T zrw990-ZJi)IcK;1W-*YgowMB86_#}U(!#4$L(UH?t-2xV>P zR!^zREi3fh%6l{k*RWS7A6(wkheXKJQu#4EyD-WrCn!G}P+~3KbP-h&<^H2etDGp~ z)B?4?1m_+%_&vK^@yB+&zOZE9Z;S}I%sz^gxE0zuf@Za)E$*j)+v|s%W3W`6?6cfl=&OAGRcLhQD{Y)}40Ox+uQc^dMVIe;-!SccPn5h{lH|={FH( z@-UN-za-3AyQ?|fsjo7lj*LPSSX7u~&R4Mjh+d-tIOg@&o9`iZ&XqOrY6@mLp0RmT z+8YQ;|CqF^+MYTK)EM4Eqr#ulA3n{~1WIypwJ7DgD;-4!`2vTE20Fs;XD#a6tG47g ztQDpD>wdbaSA-&63k_Sptr6nBg2t-(d5?YJ z+|EX0<`0V~ud3J61w7UJ{;Rxt8mgA_Be2qf%lW>7*M3~@Q>A80gUS1~yRcXEv4&N& z$1rv2s&}Lae5!2Dhk>eKXz5MUPd6uE*l=%^yG3n(RLf%rQhvQC+h|-Zbmtq>zZDG6 za>WGXnWR@wlCEtGC+-V}KfLOwp<0n7p;?EIb1(WTVzV#7MWHCoBU~u58&5PavBC@u z>OP>xOF`>K9fiQE!>)f`y(O;VF1i&{>D;$C{nELi)uqzs(5AcUw~evSH`^D-^vp{; zAqk$rS438o51+DAJvHf%=&g)Fpc@}&=?2+UBp|Li`Q^Nlz;*=Gwuc_fg{Zw8h4)Hu zuBrPoxuBlWP_Rp5$Cc*P9o70|rB4>nP|MtqtL#6Kx;xE(k zZMfu=1SwE2MByKt#Ol!pO`}k)LXB#rLU+;~NxY}O*RA!(FqaIOi6N_qtwLF$Ipt{bqO`f;SY&PNWgeub`TGzj|s(%vM~mr%+93+4prsuL4aP8 z(Jk^VHc`&)}P zzP*H>S#!lUE#$<6q!}z?-dJtyeP1Y2|S=GJ=cg)Gjqn=Ok_f*0w4*{Ba97wTx=f@Sl24|_r zr5Y=TC;4HA!$ljh4maBZ2Pw1~zw;qs)`MrSK7KhY+LX3p$6iXmch4HCREY;-X^J*F zkaN2DN}K{rz)e@Nb|#;$%Cm^9Q2CUs892$~6K03WiaV|RH$!h^yXYjkRx!etpX32L z;yrNOmnA;1w2BhUu1wck#MrFsJQQy}ZIdzcbd5lRA_*Z^F#oX!rU;e7QvCh-`3`&@ zK)s{GShkqhzsLa4k?9xvmQ7&wr~sCph6na>-L3XhoV#NWn|;mC=+v=EAv}ccuOsRz zPNC}&o&~(E-!d_im^Vk->;UP*j~a6`i;edc^ZF|l{oe&Tc_ZS5bSt{`c&9y#LKh3~ zy=Q1>^NV;Y^yPjg28VyIl{!>?H;c_Z)ihD0dPnv%l6AP)O+YIu*q*0T1w|B*=}^8~ z`MbEYDe4f{v8n+{2+}FQ{t0A;=L?B~pomkCbAU)Q1DBqOU9casd4L>q-TjQOn(|6h zx?zY*zVYWHM8X4gQxAuPSo8rzY$ zym-Wv{DNMIRT?7NkX_Z6{1Iq0w5C2IPAt1J@O98H`9}Q z#iLiEU%VeMi*nHU73?2tbi~x%D)(-+zcM&p1d4{s3p^?fS8Z2Jz z5gJk}@*n*W*;&DSIdJGhR7-4Rg$2i$H)NW36otRYJXMPe>9un?Wu;c3aU*12?lttA zg(HR;JuTe4)!CdF3i>GF`mf`NxydVaQGLmTpy1;9q$e|dCkeZX!aV_WI)ymO;Nlm-}>{2Y69iJ-qGTD+?@|YGZkDilKX{h(+<*qc4CRra1{ql-x7?S znqAb)x0>bEWUha6dz$AMwbfdKbR=G@JE>Zv46Vv?&drKTJSDAW&B`p*zjT_$uv8QE z%}vo>^5V^pcO4#$p$0r!+1j@;;GplbGv*vFb_T43GdUFn?# zxiJPQu6kBa#ni`W9GDukbm_Fzjby`fI~F(}RJb+p)|^^nWF z4{on3GeOf*49QYZ=NLC{J=y#RmKx3#hcL(s*3GODzl=bVP}K|I?B_upS2}dQd{qB> zRVVx%ZXWfZumlDVJN0;@xTIP@1wtp3r0rh2h5oQa#&xE`92tiFjznX=IqYwj%g$>3} zi^S6{B;lTLwuMp$k}PaXB&ZC^snwh2sC7~5pGm}W@vdf-9*~|#j%JOLQxEd34Kg38 zSHKg2j3wU}@5t)P%lBbC>S46LyHozOCrccoSSBLd#PFfAt5}d>amEk46IMFvs0%C z*(#0N0z^WMlV|?75qvpV&`nYU7{g;`6l=8a()QYxccd<=7D#M@qc0C2T87}RpquV zrK?}S^Em(X%T(Z1>ii&`alFXbiktK*JJu%K=b646!oTy?JG1Vwe1INQ!i$HU!N3qg zu(+o5-?q08+p1Lm%Qzjxc-G3}?Ii4j1wUY?{Rc1oR!&AtJ0b(P3;=5yctn##cI^E-CcW-Uw$ zHT;xQZsmmP&n`90TG;V^mM^BHAC>})*GW&-|&6OaA8 zHTLT(ZM17ya*f^|tT4GGXX&9%HeW>xG%{fwfy;r)AC)7OmTF{_% zc0C!jmmyfj^^n)&Ql{wFspT;eWFV%d<2rG5A1e^;K##~|;v_Pe&)P)E2_L>R~S z-fsJXZo0V?9k|#$DSx6|zD~atmBx5YyH5qQ+fN&F+|`Q@Q4}g#?(xldLVB6J5{1cC zIX5huC_u(xUB{n7jA&<}2*79${E|8=WKL$Is+#PiJ%}uN9IU8n(^L@#<mwS%}gct6Lc92W!V|-N9t+TRJDxcc5NMf-+4F1Y_pbc(#w=FFxL&HlDaMVJY zqgM3xXV%@`S@;GS4uGiQ)06=Z33mjiYR)fB#wXYQU6!~HUB;!&d!lfp$OQrbYm94NZt)wCt4wgGxX|D zAH^tAeX>NMMa1m{A;#x>qp_~SrE?GKJTA%X*l&>ir#_b0mBR3o z$mfhXzmT#GE~{^&bWac}_V`U-kgz96Z2DAAz2|w^KvX)#{_w#~x3J)cNMq8K$MWzv z;072GS#X7O`UfuwdsX!##1eb;f-OYaaXFO)QCy>$>}NbZhIj?xO(fN4jikpiZbvyS zs;R(v_h6|`u#}CAlY6jwDfk!ZQKc_Khw@%xMo@C{+%xkJZhA4|bs`czJ@D;;J2*kC z+U#?%AvtPG6sNJddn+orE2;CR#5|{k?=wU^-BFJjl%vyy#;aoi2hEb~8L##ymwcX% z(;Brj{&>RatKk7&rFLfro*!ObbD!gH_Rr=P)}!Cc4v>$~Hmw$V=2IF}@faR}u{Bq} zM;Vxjot!J%c|xhDM!eL%rNVHWel`B-P{Ka=j^imS=IQJ2%|VrkcYLu3C$ zqH?Cal*+kcr8i1RSr57(X0|I?Oh~6YV=b4KC_w*xZzENW2dT`MIRR?=wt?zer*GJz zHUb2bK*CO3Xbw#9{(Jhya1osH$6-1P_igaBbisdl_zl>V4u-U5?sc_vkAT$=nF~)u zME{T>_5Sdn-3+t(iEG({MQR@w2Rman+PCBxJI@)Le_+w#s8dX%#`yG4l~F~jCpb9_ zGI4U|0h3_q)v)&$*&P;~9Y7D+hasVx2Vej*4opLwG56^QzZ_ijWE^#VWo+YRYK)8R zH!gZb+exV9cjHizXL?v{RhlIHuL?Y#E8~~c z-C!oRQ~-MIzwdgmY-GR+QDoggem$E>IV@HZM)Fn@f}0#i*kO|#4#)=#$n+-7l#^jG z#&zxl=$s0-NLLcYiGpg17CZ-fCy-bs9+SgG`8)Sk;>#uhN83}Q;(Wu5sMI}g?F|Bu7q8I?+z zs+_M-cB>ZY7Y*eqz4+%eIo*%~4WG|B_XTN3KJDPNrRw_2i81$UvdSeq-3JbJ2L76P zP-7{SLDy^E@+(7&lksYMB@6v=g6ME#vj$*Bi%Dcc3`D->5ka1l#zw80mHYV z@Ke7bA)mRE{FBRKA2|IVL4+P_aOLL$CzW5DHH;rQkKsL|N zE$J|R4Kw-8MT?7&4}o7+H>;0c=4@Y5@*MK$_GlG&u1DOMyyF2esaPyz0=0Q@!g_WF zBcr#n``|9`4g+(zcu3Jcub5-tldCRuF85APuBTB%(I<9RD%m(S{e6T4!%E|D#01>s zuh{l_uLZ|f1Nrk1`mW23?P9mhE2IOEiTk{hJb}*3c>(sz!L0^u_VhzN#7#(x7|Sel zpc2FUI{lFD@hSwlsv%u!R9q{?G0Thwgk1>x6#^itHYMKmKr}p}CN}~3vt|^(K>9J9 zF>{`X?uXM`UTMU$Ne2v8y=Tc{ zWqigl=W?7Lv>$U(#6J=J_eyh+FVw++!}n~~g`-v!*9Xqj{AtnJ8KnK)-ev>$M1*XZ z2F&jXIZSf`%5wEbj@;xwte_cmSS7ywvuzoqips?1@)M!>xR3vCzavg>co34FrfyhV z$+T!nO_AId7vb=#wswa?CGLBLicVnpNg6KTQ5;mD8{y%`XCSx0O&H7Xn78FgP;W;N zNR&+M-V!Elpa*8LiZ|lpmNx;>V^41)gZY$`V75cJt7*csXNeIC*^*kfe;)DPU{bCB zPFW~mZ>0s;DlDG9VK5tynDknS3SO7RPpOD#1<0Q?Cky@Crx=;e+`(R1@ZJ;tb!AsQ zPafk5LXLPcQ^Uz|nfjFkUlzh1R~=CoTkdv37jSkzC5x{aG7Dz_c3s`7FaMMhik(}Y z%&V!ksW0G0VohnW3aaO%Nd}%fSKjQUNkvLX8WqMLk+Zwy-LxaDes}y{n(@5c@v981 z4*D6V$?!WmSkq+|y(N3xpjx=79x3|N08j`($tNeA6cd^<0`(2&g6vs1K2=n>3R@p= zWvGZ#`tM-$#HKcbQyj-pHY33pYt7M5Y#!msH3~*yw_j;LA2zX9Q-LUx#``jWcr%`K z2VDi8Q~2!2d)1=tz^X;(+8ejWpL_%cW-T?FifEoaQpi8E7G3H0EX2G0#7$gncJrAE z%vsrh%9N#YwC=d2 z;2@pL+RA>%6n5|o<8Obj)X(K)F0*L%^@>*&WS6v}$0+-H&dLb^6rk)`~!b8=gmTE|I~OaIiReApG+GWru8q9g>0EO%{hMec(n4qajJ<(hP$($^d2Qz75Pd%NX9-`d{~A3+LG?-RKnRQL9d2 zoATxqu_c(oyITW=+^ILZk^eER@M9z?SagOa(zxzmgwEK3kzfi)YWQ2l3^*7+Aoj%g zmK#=WZ`h)AUQAnR;82zj#XzW=Mv-9Qbm|AK)FveTzH}?@x#yE$gz8jWn&~f$ZS)um zHA1b{ezBQLc!gt1;t4F4i9u8oxPt{7Sj~(l^v#KX9;)0y7joO+x@Of3MIl-(LOm>K#lV5aGLYw| zeixaQvN*bz#sfbONXb3+Iu>4}k)v~+@QF{%%%i`)B!IJF(NLj(@A7qYYYH71Y{cgh z(N=Kb7$YNfTR6_(P?4JTCN6%nPoqY6elF+#9PeqWtlOP z^p*X%oUH)Gs4T53=D&PQ?+VW@{FWg_qN;7h1n#NBGS7Jmx}0$l?f(EC4bH@e-4o?> zR8*fBv(Uj1sR8qHr!nbkFty?- z($?C^K;eUBYm#Ym@HhTxNb2s+Y|Ful`r!-CaX$sd1xfP1ZuyLI|p1P}k#naMmM+zp~>y{$&r zF#I{ALLz6~7CU~ybsXYyLlPk(mjuD+eN?&viTx3lBDVlCD5Z3A!47pD{4WAc|2Ffa zmj_Ph992cdm~sDV^s-V|{oroQt%UPv+XFl9LZf|MY#f*w64Q8+jo}x8NF}h&JVB!s z`urvByEL0nMGMcT%I;Z8;ZW9U+F-dJgS^ zSJa6LQ9{+u4R-PoyRMKx=du^UATw*@3o2$4BmT8I`TVX&SJoNZvBrE z1HJ=99qH=tdtiQ9nz}FBkdGaIr_##m1FjT5v}@VrUR?|jrB?B(VJtT_ZcO4^s}Kxc zspp3uO=dSuWH(KShDYa|6mcI#uXdr`B;K=e-E+3K^Iam+#0V5bsIugkA3Ic;>Hb9? zKLEz>jGCzR!Uc#vN;1|v+;3&r!;}8DkoV(WHq=W9&{5yjMxk+l80YKhW=KyE&wZT9 zr{n8!c7Ppo%qnh&;}l@a<_Yq+zt^MaUD#lF(k2{ay+M&{b(M-8u}Ktrkiu3x&sJz; zN$y$#0uVGHkDpU0x-(HELo1ed2)Y>3tjj93l^2-Dm1#3z7)Qd+1diDicZ}!g2w4B} zv_+?ce>>%HdY;ZIOH9^YpO5AM=YC_$Hf#Mzc|T^Q)a`W8{M+SL4K3}kWiv><6U|VJ zR)~VEZRbUz#@0uCBZfd$z?V`)nYSbu%5n_6IX~@SoTCb{w9!(qZY9`;a9cC+DDe|^ zhyuGm_Wy*T0;TqV8Ow?>zH1JJC*y(?Xm)5el>E+ZF74<6RLV&u^eNcbWLU3>uF*cED^-G9Ywm^iB&AaK6II8D*&-qp&3M2pWy11OoEtCSXu+LvALe3SVi+f*CX|_ z=IazpC*&wY$b8kY_MHhj)J(Hg&gI1?>hNPQb8QAwR|FaTveIIK-4*} z4?T3U`AJICj|B(HtMc$HS|lzTI`k+$^~*!kWCu?QWR<=a38^F2;=9;ah_weG2prK32bx7I0^HHW zkNAN;i-De_J1e+(uvu)5X?>dEbhl}j3SKMxvA77~qWiZZ;&)|Yxb`Ue4e7lf+wS7R zqs{T^Vv=cRUnIji%MFYkRa3vEpqF?nZ#~?G8A=$Th#xc-ni`bcc+`WI6&T$LzP*OD zQ#MiMwxP~^Q6Vhh^a~ALr95H9<}5K`Zfjo__C(c!nf3B5RIC3uV@&1^9A?W-6Fu#J zngkXTppg~WW~&$i<6|N%*I*EA!I;(<49==m#ETaxVo^%d92tCKcgaA+nQIO<$)&Ef zYLN!V4T)Cn)P@O2kmbH*Lc7enV`(d)nS9qmy)<5wC#cjAr%hV|6F zPu?<5w$Veww?LVOL$7&-Rf`J~q#R1z62;DG%;2!66z#0KO(F{O++IF?^FB(cYhy83 zSc+9@FXE(dkveBFUl=^1b*zdDaS>NN2x*s96Fba_vKd^$b4hH+cJ=>5pL{i$@5}{i8jnwjmJ0<^lz`{xNN3%QFMJ?!|YL2 zJOd>Ag~k*hdZ8gQd}|iM)c1D1eFBjC`)TToMw{tyqIE4ne4%iyL0871Lg{{2EPp`L z0az%DcU~CL*0pyVx2!k5EO2!@|E~KN@aVoJMS(cBC2+Jgt)8pr#8Z;OG*7lK&Ab_| zGU2aUdj0UHtfsbJe9rtKrG{}^_UR=q!W?;vkEl=T(bei1D!RLMdyIATq=)|sZjj{| zPLb-=R*@wp#+nKFWqH)Mii zo`5(9yrw}kostN7YD*x0(qPze-KSIVDwQ4;jZ3p!LyhF_HVuBKgoOdIbMpw>tL|A;erOh3K@QEKg#ydP<< z0U@K<{E2Kq0HR>nqutu1VDSUzo3?Xp{oP)V$`A0-SJ@bh zuoii`g1rP1S0hNs5p~A}uN84E8bd5TY7y$?39%|?bJ9Lubs1SmGiUdhv3vGVG^nj2 zLHfHz0urIZZ&X7#s5L^>V_4YTQKOH(o!o?mIm-{ zT7-1-?^`;bW0SK_5o!o)8_v9qiZ| z0aU*LZj11$&DkE|2L~q8-t8F|lOS5}34%;cb?-h%qmlo?9oCKvQU8cO!55tG1nY=T z&WhsPY?)q-H>{O5i)RiQ+`UHORwFukyu}@~>>624LXd=gOOv}K)HWIQ^o_N~RKQN} zKet|y?KheoTeyn{l=80Y9pvkZZ1ZY<&4JKQ_rN#WX^Ljk>EjXkT<2|xSmknHUSzR{QO33T9F*l;aeH;3jutR{l@8Ol^usD z)e0)i$0XGdl;_S7fGY7h0``lq-8*iXciqV){e}(a&nj8|px*LMf=JaX%Se+Y>&x?} zK>T6S#Y?~aqzPq-j|n5oMi*CXDjyRnTMoVggmq{=2u)3xB9e|Dzkh1CaHP12W7v);>?AvzWSQZM> zB-IoyyS5WIynlzKkc}2m9{tJ1Hwj%Y7c}}P1BdZsmX{D)#Hk~-jr^vAqvx4QyW^Un z2q~5asM1c<@~bXaY&TP7jqv4ZPaj;cE$@b_v`l_9(0ojhVJ_a&UVEDXn&$KXiI=-d z_NL|7=1X~ULB#duOOa7G2}I{q!%Lyc*O+Z8fq2Cz~aJtf@Q zoaP%+b(;(j-~qc@3Ryz}qSQ3{0t?PC*d#LD)qPaX6lGb(N}Hu03hXO1DF{1uowwk< zTex+lgdvo(3l_fPe21b5la&lV6>!@S92c#(^Yx}h1u}noz}tz_Z=qoNT)+*#^ubd) zqztaKwXFOi^$f$wc~dZh7o~ImlY8m$`KQU8RzPoiIR6Gkds`(>g8ty>bLi$CuL|I* zMyWLQ8{!ixzE6pUA704T=^nt^JJmQ5C5s6m8yYPn{8#QaTWkG|s)C^mjfU zdDlV-TiQ^n-<7*g&GOGet2qSJR!K`~|9zt7I-Yu4)SEwMq|c%$KtfOA$S))c%lGFw zit+I#ZzsoLPA>J)Nqi4CefoG;gZP$G74>k-T8)x|^D8wfmvdI7rJImiHpR|l14lhk zeGC&7dpE2LW$O@SOuwy5$}xeCb@S=Bij#7*h&vILrX-FOTm&xVYiB@@RnM=wA7wmj zmiEaTZdCfIdRV8^0f&bO@1qvvG>&!QNNKGkBF221X;~@$r1oVsMY`tY!&K9muMJx4 z`uZcakOrlzZlb3ZGgXAoJ7Fv&ydMtY5znAy>}hP;0a8oxV|%K=CehTiAZr6SqTxmC zpnLzxXwc3!xB{0NP+%Nw>6B#LD@kf!M5?Sx!4GxTcDg`>jIj&g(n|1?R?AX{`HXLuKmQ|a9Fx6T#h}=^t3g{B;`Z7Pp4SIG zEcHze4Bq2g?3#{S{bPf2c&?>XA9P6vK0_hy*ZHTd%ZG=~U&UDWlbdA*s!t6fG;*}E zDvJ$HSa1CrzB7wz{XR^Q`sP&qb?+4PljyZHfdktU*LuJOLz1|uphR>BWok7Kvw<8l zHB!o2ovmy_C`6k7gq%KJ`Env~6)6(L5m`Oa`R&@+E8pC`&o=|`8MZTBxgsCsf`mC4 z>r|%*rTSqSM=k73f)3;TH@r=M7scg|hiMu~H9e8Ot*mlmBM`H9Ev-5^2&C5yB28iA$sEi)*PH2blYs>SCw7AH%jl8hVeT;Qm+XD0LJ=BtMw5FDU!S!t z@{o;*I;QYiK62;ECv_$M&>Bv+#avj)->AkD6KOt~Q_X@V#{EF*&aenCm04z7Bdql= zqZK=faPK1;2JTp5_VH|a$q?z(e>UjzU8-pTF$u^jn^c_bi)#xAby-PCJn1)|?sGK( zv(b`+u$yURn}E4&eC!Lvr6scBr4V;Zu*1a?se9qQ7-?zuJ3-i+6v%>{hxkCc@D_cA zU&*eZ)w4)R-InS^K-2!z`tR30bZJ@@tT-sXJJ?!SCRfvRXZrQAZ+qBIQPAdEN5vp~ zg&W|2dHm<(G7^nEj*GMTxFKw`pPv^nh81ldAZf)0c2EFt&aIBOxJKQ+WdnT^$Wn~bYhS=)QjpQ zpaJB|E_siMkc_f49jI=EFx~v9wZW0WR7~`Ae}*@u$ki@Hfk%KH1CJXwhCNq`X#r=?C&So z0T}}jDL#sBR*iKCl~|3A9$B`~81xVm`;E^qre(O`gDJ*orbCs5;$s)2O)%O6C8i1 zf2$#xS6ZE6Y(wUVxr$QFkt-Ea>9o%bBgb5&LYph3q9k;gB%!`bD&0t>8>v*XuYck5!~1i+ zUXN#0jELsIgwU@mdBtO%nZ9MgL5KTUrB_Z{s`aWo4SC8YT6esj>{5ELcZPsP#qx=< zdLgx|?c7OJzXpWuIS^gm?R8ev{l3cWXJnNv|p6#~GkIVG^hxWVP zgV?#)Sw$r!_iuG+nI>_}?@!WtjvYOgWecoM+qbe`jl^0%fn_zG7^0hccmA#Wv39I`c#=U_xWT>f0d_Co$sN7MMDT*i~F8XHSymKdLubY6eaiR23Rm-yPn<3Y!edQe?}kbAH35Bs=&;HU z>iRlr%7I43ImGH)W9N;Vr9Y?Z-{2Gr&PTl;*a?k0|y@^N5fNmnyHn5n7BmP`&w6jogFX>-pOrmJ`eTvbf1i3 zv=6ELF;kfv0}d{mJs&wUB%<~<5!4ifk%oFnw`@_npsBC(mAy&Y?jbu>5VWQ3-+f+oOM4@K%L_NeMa zDoitcAGhj6vD_1-2(2EQx%$&&`1qRp>aSYndqr1^W0c*jovglSC5`|0Vv6*Up<>Rg zADGm%pE3yl3Sz6j2iN@*MC(w8cJk1ZrY!~))IrsZpQ$K?TFL!IiB7)+szB;td-N2m z1wA75_9UC!UC^;w9d~!dIY^Z*c{ev>aFS^fCbcKBROZC*0Gr(tNzl@*^~g8@8<}6; z2k9;|eSBxhyNB3#zZY>-RI+>V*meQFTQ$o_!w`5E`On*f<}(Q>xsj%EyX1>py-4_8 z+=SMl2gJ=NgS>mj9mUiU$y1D>ZjVG~Dc%NsH^%myJ2|d-z8K=clm#oIQi^8nf6(aQ zIfrTF@f2t;(>Ub|DYTbFqyAvCs63?pzFSH|-Ac-F`9lp;xmLzp97W-h(nz5{4{uAQojW1 zklK8*KwPp}e)eov>bOQ~EA$m<&>le5G*#u!sAl+6;tSL^oB@Z~)P?)dURYh(M=|Nr zozU7#eL@Xx|XkEO3r1m#3h^jB5rJ3~g{M-JO0) z=Xb68FUUl<#CMUZ+mF1~1M58dZqUNiJ{h6aG^m~$xYB1zkx*^WQvzXvjSn#2&HrcX z22-Z|{#)Rg(BOlbJ?iUsuUyTXQs=W=-N<Zv~9(hPuXeE2VaFm`!16>}CGSqEe@ds4=O| z4n>^x-v@?9Ab$6yF+a1dD9(v`aK28dIj33wo5AdR?HZfeVy-28%hKB4c=!TtYR+*x z4>Dg%Y@8&0&s>C^i;>$t!6`RsfVTM%3;&|Y<@5b+#P=f?Ikm@OyxVW`L z$0D=}QYjlAsvAeyQCQlm_L%L1DSN3JmQnUj7EuWjskl*CuJV(IW#a#T@@(&*0fUXDnOD>fwKH!H^ie#y#=gBA43B~U}zM#6+k zP&+yKf!+=(Wsg)N;gT_55|P=fA#d;1+i}bWVF}y}q;lGzfyc(H6u17s$;c5Gx|X-q zOZ_zrLqB^nQp%P)4`;kffl`tp2z8+9r29{!uo9U;(s(OS-LrFijcdp*JW8*ds^@nM z>POm~&kSDzh7O1wUdgWg&Bi2WsrXF4?&=B5;<^r)8<3t@E%xw zeaU``kw)iPHS^|JIcy@AF_eQt?zf-YC*@qlpp=5w8WTrI>QA0TcK8j?y(hOD(|2iR zxZznIP-HhQxEmJ<{R>9q1T6y&iE&wF%C7IV$0LsT7aoc4QEMZtB%s22rU#T2)ty7B z+zq^k>miJ$Zo-BglxkRM!i!S95#O>)KTU&??3}Plqf9kE(mh0pysNe@X8TWQaXq9w zW}wb6A=3749D**2bz3I>HglD#SoGKlFx%nZ#(NRC2}igrjkSvdFjY<44NRZr#zrcT zBW?O%HR8B>&*jW`)JCNVEj%h;Ni%x;L|Nmy_$QX?#%h6Avol~LkzA^=c#PcqlgHIe z`eSBWWkZ#x1W;}*rOldV7MVNAhU(4maY+YxwsZm4^TCuoIa|Fl%b|o|m=ilD{IciZ z$y9gu`h;b}r4%>)KTOS?<60f#3Uv`lqt?`@$50bx?^C4iN3`;ggXHOMczgBBKB`vl zPHl5|qq{WJKWo<+M{9(Z?0{liM78bed59QdtnH7SSnHE$$O;HE@ebQyd&Q#9_}_3N zZe&9!cEV+$d(W?$1nYt-Y_Aq=A65C6!DIoXTn?SI#NhZU7*xK`&*O5YwiwnPonN-N zHrY49Y!SYRsRp7i$Clbzr%+4z-xxNxRFW?cn0ui6CFG$oAeJAgTC;Ucr*Gc;vSN3v zyjW0Q`4BJczAzJb=1zvHMO4+{jVu1tY}pCx+@~FhKe-i6t}t*2G7M=hxh3hgCg)Q!8on_E3KriX=|Na7f_o}Lzi2mTmroN1wC=x>c6UX|Hw z87K2EC>p5cTW-3j)MKqzvh=M^hqda)ab%lH8$>qo`@BOTKs~YxPFx=U0s*RMnmzNPkIB zwM6mhs*6g041iIn!s$|Sn0Cx@s#V!l4pXx}LboCE$Rkz7iMGvse>NTe1+CH~?~7=D z628I|xr-LzuNN%1&rrrNp#y)M-|kgcMVaeWEQx<%>o$_Wn*R3IWT0nvKx|h;q~5E} zim{9Ju@#Z)r?{2h3Eta)QN(R*FShIar)jP~{uUUC*^};Uo!Cgu8vms)E6t*6tB!8O zJ6$Ytmndz#bWXQ?+r*Lh0O_)Xp7Tq%#h z^sR+nWC1(J2>inwZ>~Ru-{HS`#r!}EJ&h<}}-eC(h*<`s1D>KJ@$@TZj`(TIe&0&!g)YecFh zMqGMMFlbsC(MY4Jc2aOQ&o5Z#ZbvDhpCH3 zAODG;e<*}%-8B0u$7ge)`(e~#261SEaVmG{0>8fO)rEbHyG}A*Hf~wrN1Y{7Nxo~# zYDcbV7~*TOk@(2EOC7(`F+O&Fu7?JT5AdNPSRP8MJBP9N3}krS$%KH?!J7jBHY_C$EiDo64zp~N}hc3u9`XjzQepj+Ke$%&zfjxmIA)I zB_VDfNehS)-_Q6luX0#nWz$Gw@L3zX+V>;N-7xMrRJFa+LzMyWOf6Z;NPVzsrb^0SQoY58Z~&9Sl;V^EcH%^ zY4lY4^V=lH_3p~j+dQ29l!z+3&eAkFr$mo&-?5x!gmmpzNO_S9WQNC{*fnO2$5!gNNC?eCDI@h(6b# z$=xMNE+4oYb+2%(EDD-XE>rbb;L4POmi;JHU~+_<94mdnXbLXBJ*I;9mfA;N6F2_I zb@1u%J%&Zq6&Yw@9@x)#?7X(m^$PpakoDlmTSeB2AqI%IOq%x3P1)HbOL18Y>I=^7 zm5jPF7Bf6`$5eu+Tr@zU}HWCC(_fUid>k z!T#{0Dz?JU=L@fBvdBZ3q#rGxWPVvHa=4}1&Fo-yV&6Md1n8a`K#1;jEa!y0Ub!?~6f39zuZAEKl$7;Sa=1Z6FzP$fMu}2C1?FmuK z*T+xt?&088fgyM0Mh*J=Ywtna^hO?x#XZnTP1%Wi*Qcv7qk}Q#BSZZqBt-yL6N4j?{%hioxo(UIy1{ zHTc$DNkg#3N^S18YpRTT_fv1-n}P%VXuDsdcU**?=bZD-L2Ejmv;OQA)hl8Aa4H#H zTw9Q9DnNs}{nLx%mjP&+kwG9f3W8U?lYF7Yt?r**WiR4{7eeoovYu2ijN;FogZhg} zEx1U0R-42w=8xyUgru7)i*729ZdIv8H1x(_&QU8jm09jRQrnyKX<99>Q|wx_Alt(+T@gYI9lOyp|%BNy{wx1Z4c=Z0kj2hiq3R*`ezo42%n&_Vm_OkOQyWkD`{6Ct;vi}V zBG^)KnY$@!4)5F{7(}jo(4d{v7-1iBT6=%olc%b;TMh4a0Cfc z7wSneOwtINzoQo&eaA`NU4m07Tza_rFI|=k5z~Ol#3Z!N(zc3UL&kVkN`H2RwR{D( z@wIEQ;W<7hWuq;*VMueXa6<)u%kSk>W^aUHMq0HpzLmEFHw**_d!XgRvCLwDX#Dr3 z(}rZp6IKoLc;H)`t1l!>{(kV&wR=!iXAeV=D*Cs?@?h?=JpVo@lrSzqMjYlQl}Oz` z0he%(ea%*#S*iJ*)>|wW-tl}xeT0tBBx9*2ti9Il9GbbW+N0%$**#3VpF#Q3PtUO< znxjKYzsSqerl_IggiX$Usf4Fnn3Ee$>CoGo<7Sw@WxfY=l-I(4tyPIKr@G1&$B-KAOFV2}9vqLcw#C$&1}`Bdg1a<45;O z#)2ZM3axolqJL-PpCIJ64{EGH-tDL%O)>tE=54 zAyV}Csw52Si;sK=f2LBKmkakN%?x>e*`5Da00nCGMBsLrHwktq@7Jr&&bT+dqiVDw zN`)m%wR6X}d$Bave|r2!-5ry7SPDcdM)yDBvHZI^^B*7K4*h#WitgvPToh*=%MG=) zJ)G}jl`P7o^*Vq4hqtQUB+}s??>TOmi#41cF}vEJEsyIKE+%Vclbh%V$i__lnk!a1 zwc$}?-E8acByAlUdVHZKcJ(Gc(Xp;`*%rC+%f@%Z71e5zC1+5i zCiB(lS8t=|gLAhvooRgPSdqKhr|`29b$7NeaDKNY|KiVoQLWKpw+k9)w`azA-yz)n zcBIg9Q}F=}H6V?}WJ`K2g+oColi(@uP zQ`O9EW=V@bZocpkXZCTOXTf8rVw;LDHGHOG|Cv%a1Yq?fwAJoD0v7$~27!PmpMt$0IxE6jf>{8k51 zD`U6<#3N3p=IrXnx^q+cEv6m~CT#zmN!I*On^D7+KzC~asG)fn^TxRU zL^(rX*}nyQ>5OIi6S9i}Qh$I(M>AueZ&-3BV(ojGhvd_H%X^qbnPzSvfyd!yb6|`# z$fIQqDgb4`J!E`o^MW08iOUB}BesT63^4GMJz!}DdgU}Wm4^=YB=7k}T2l)vM4%fe zd;V@q))yI$dxD0D^THHWc;L$UniukZ;C`Any>(AsXU(pB-1nm%ePsf1q zDg>z*K&czM@~{!$9{asqUOA{~yxFmSk2CJbaG9BVLk>o|m2wQU8bd9IP*w;Oewa`z z%Ut;Byi=x&rNk!3$Tj6j(U3iQ1sBy33R2WzIWKE}EXb4LBItQxEd=}wa(39BI!{8r z&BG!&Y4c?2G)Yf{s+S-XAE-^wA}zSVn)cwdAj4IR_M(IMU~plK{F^~koKbrEI4|)B zNqi-W7?4}l0M>+d3Y+jGn%I8_$5tIRaBou39!q?wO0TPG;{%YJ(zVBNEkFOppSEWV!mb zH<>u=ErbA3Q>6L5Te;8^-fd)Vuq5kUhcy5rX-Q$JX@@azj6!m@$~1zMR7_|s4hu6+ zhr<+^y0$VKyWb(PjJ^2QeexDy?-<5ShIYLSmT~Y+m%&fpN!fIiB&JkZ<;bF@mN(%* zt*}&|k(=fY>OmsZZ_=41a4!kFk3n8zPiZVRXY^=>nMS4$^OEotK`K7FW;pep{b&`` z2T8GL}#$Ehb^RPqgbj~@tIkzsGCCqo7#Z9n*ZMLKd{LJnv2P6FDkvvJevKqxYAku=4RR z-Xi*#oB^n4^C$zS0=Mbv(huv;?^On}0|P90=;Os9`Q1^-dv}A|=lp3}`O4hlhbZCz z7@}CDh@RzQtRoJ#;DvPj!ReYdFEWjRwq$JbD05e|PPIw~(l&s1MipL*i1-JjYuhNd z`RYERq^2+sbwDgn%B+|#!oZ~q4JVh6AxGFKDg(tkUMA-tAF+677~j}u^pbhzL6C&( zbjCXxwTy#$s8JP*DRxgz@{wUapQ*U@y3bYJ*v&x~xw=z@ z;UOg)ZU&*X-1$)zP(=7apcwohotp-+o^mjB4F9dQ9KSU9#1S{0IQzZ74xOCYv801) zq2f1!=e{Z6s+q4R9fn!Iru+y_}sJI z+RaS_)V7Ua{y>EmXT@?m@MW^ydcQY3jaDazLrqK_GfE*4`AOa3xj4~(I;$|Z< zPl7k+Nhpp**V+>p=4Soi3$7XA?D?4IchKW617` z5j%rNNHRzcd+}n^4W=W+JJ`vh6d`uU8FmHPc?kE>KfTv)~ z9C0dI`t+0BXYCjEgL<5EW9F?mRO=_4XS5bQ4MF>wX^uf&PgCrWw$XHjHZ5zDe=x)YDWvkrj1+rfiL_{u*T z?{mP*U2@~5Kcq}|Faq>Zw#Eit1$X=*>$HG(PU&L3z#GxWkZ!FHo^R1GcXc^~;X+xBS|5J)kA^R= z938-6MXKYFo;g#i)*S$rf@o@t>h{8GUZS+hzUKeL@srztrMoli*_?ILd z1a-vK+9D)62f|_z|Ls0?ugPf8oPOX>s|nTRY7TyWxV3@5#YBaNbAXE8@-)F~ue42r zBuLA~>eRbEa_H8ntDTZ@#hb}HW%M+sYsQj;xW)RLa(cwVUs8R=ih!b8T&sF+sGQD& z2tQJRqx3<F zH@|;W;xgOHZ@$+UbG?8Qn*$Z4KUl2{Xl4gjUCTI}t6SV_E8ZS?iZ1SN$k(|Z#7cf$Jn{$G;k1rml=6m@g zo+qnnZUH(JOM?S!F|D_8*ADFgae(ewyzvwN8Ra=Hi32wey#LDEZ`(K7CfYu(EX>^ryzIF#C zBfIiaQg|g8ara>*Ns2a^CPj6(CCTu>_^w4~FjDe}kc{ONh{rvA zw4v_Aw(G_`E_mUJp4is>42cL~r za;^(2C0EMLEa|AZd<`cTa$J8uaXegwkfxOnlEm`kG)HhY5oG!3VI<7@dt-j*n4K+( zbI-xEN#PeE!f_6eCjuCU9=RjYXI^-%x4zI24qp6CVlc2)ZrIB>OduRmmwS2Vr4y1F zr9&a$3Hk&4AuyCz0>dQEc;8DsJ3T+}%{lOzS7`PIaDqu#?gM)71&(Kl)HL)d!~B}o&raCZ|O1oM@iJ195v0 zLl2ccu8$ziFi4{=;Y$ecmw^X6b>&Dc*~f(Sxb_pE(J62waqSUU<6B@%xoXwjP?Ym# z(CQTUcL(xmoEbhK{olxaN)qzR0>XbKa@rYbtx&Vnr;Ppj4vQp~Y$Up0edl`}tmVXJ zP6IT3%9f;o-v^&7!&BR)->*&>_;aeumx1NlgO>Ufe16CtUWk9i8?*{gKh`9t*P&m7 z%?WRCk|qN*P_+egSp#a$VyxeEVGe=cr%7{&aGNY}PaB?l8x^#-SFu&W@BAo<3WDXI z^!|{B`k7wC%+NKTH6d2_Vytc#s0Mx+T!T!`9T_??;#CR8+yLLVe|c8Le7Z;~Up`)Y zUD4l_T#QiAI5Hq9lDA=0y0FRkeTen3j8m=&TN->H{i?d)fWTbNnhI9&t^Z@)=KSDk z-=Li9MN)d85O5U}fj3aY9TAz{Xy1-O;)3xSTa)$z@Jn=&vcn!Q^?dT37srQfdqicl zm#e{2`Sphb5z>d*e_cT8O@A~e00Sd!URNyFeMUmwe17ib(zIIB=`R({a|#7u0QM^( znQ%Y=WM2Fl9PyP`W$3Y9^_&ucG zW6GNAz+*>1nG2Wz`s5U==ddtA2wc}GQL5|=)|&K%M|ytAPZ5dV3Yu@_$c^lNqEY&H zNuV4fS6=wVR%W1_Oyt zZf>@M35QO!#Q2ueuz{+kK#@58aH{gMrs?}PZ85(Vc7NaXf#I<4U0N>_1k|X$=gFB< zXYRXt$d#26=T`|ta2Tkb^5R}q@${wrWG_I?!ne*fM;YgIJBKN0wrplKO0 zBpVL`KHrRz?=%}aCR=X`XM&Z#XR&_Amv8PUFjh*Y)cMu93`t zSmsNd6irhfDC%Ny@;d=(0jem9__Kqw2LsENJQi-z+q-WG8}#SzxQq|ME2L_eRq{0v z=R@QvW|*=+s>{|AcF4c0dR*>alk|$1X+$@xSW)mNR@oj?k-#{EF|WBPD~C*luwWj4 z_Aln_t+N-%s&x%V{-{h@!Y{n~OVim4vH2^tTlvsROm!5rstJr!paaAF{Pd|L-{SPd z-=4bsQ57~DHuU*s;9jpfy~g-dYTy|w@%(#*J27gJXN}~^)K1j{Z+1Y$lWh>+8rw7l z!%aazZMqGoA5~CscC6FkVcu9*x=hf2^+E4oqj6!3W1uWd)zCvcvN&T#T~To;idc>L ze1RzZnG~h$uIlYBImiB(+NSZh3lzcXW@WVfoVU5e8<-x$U^t29E0${~tFiNJd$b#D z_E;pmJI!%26Oi0T9lYC2N`|Q=fii0@fCisL)R*FPBx~?G|@_CeZn3^GfeRWF#N~oXF)yYWQNFB z4!_A;>;mseVY)FpYIxydT(e|I3+Qdf6q`I!LH{-pT_mf1KHZ(vi>fwD%3H6hFDGO< z!>?fA{Zg8f4u^8@z-fL{IEumx!h49P|lW{&7aoAOd!V}{8aNEH#zJi z60g3&0kW631+G^j&N%&Ot{yc6w2CMvKb@w?lMN;6o6jYS%_3cH#lW@y?v&_LbKl<) z1ipzXbi`caAAOy#ej`pCtY|ApkOm7KgzqX!Abfkl81mzZ?N<@V#YP4?8T)L^K*?t8 zMu*bclVbk&hu@Bf6`fkde8<;UrV=arGGdNh-EN+Gyn<4^O&soA4Hhzbg9J9BwM-vK z=+m#v?&&~(q?v_7Ic?^~j(!9|ly*kX86gWFx_Qc=Hc;5;y}NL`I1#!_4`6NlQAl6P z3ny@I4J8FGCV{vc?sI<^SFa8W282Xs(xpP;!Pj?_KX#rDc|`&USoFBe$YeJ?~B-c?F6 zb*sTtcf(K~9&}`)r`%3=tJIPXyzmcLqvjA}EKuA%U6Ww9ckr>wWO61#!blClGeik0 zmTJ|M&s?n6KoZna?MAsF=hWDKPJ+tY*xN9w3Jii^Yh83){NvD4dh0o(b+nw5)%_Ih z;7r=|rmbD3GR{?{-YwY!n{;v}hK!&g*yM1At-SSgqEmdn5V4Kr?4V=JkTMw}St4#0 zW9o~{a1>M?#T8Q-x_p60K&^*1p~!o5HXQ|bSRmqkwLmE8hw;nsA2Jd67M$Tddgak{R(O>@6iD{exIXy{`nPNlQ6mzJG4PtGV` zzr|mu0iB`~u4zp3{QBl}O)vHy*eXJ5Czyj5*47$5GX%UMs_J$RQ%8Y8| z5w0m)G}X!vX4Zr=RY#m|1?-IP94O0DI_svFr92)1C;5dmS+`PVXM4;Spy8Gh6~->i zwo1Wo>7qm(OPGky{=)P;(k(d8DN=}_HAK7oO(>t2BAZLiaK>tt&5I5Z#?M{J)Mz@9MAT!*rVj8 zWgRdO*rlT2t`s3mttHq@tx$7UUDMR+xuvIuWl`FR`n~x~Zok_;g$+tUbXbZh=HPd0cyRqs>!!gh!h^1Bd=S0$ZXW&Jz1-70Ogtl+Lv+6C_~b zrNt#>SX*ahr4FrYIz!zQb(#QcGw(Ser)FGsqltVuC^hl9$7WyNEABi{?ZLQ_oH-vZ zG`ZiClBhe^szZLwW0Y>)PI4!pBA5!F z&zDf#^;v|*0QC`BR{F>|>4W~b!NM*T+kXDD77AaO0gsmco~C~6wtERL@bY>o64n&<+y{Z22+GZb_IOL}*;7z;!AO4FN{ zPaeCXCR`yySh%%MU1St?biU3&Bt2m8J35caZ4qFwW2OVsTOdS%LM57``Vd1?*HOJf zy7_shpkJyp=|~+RxGhPqby0xn~@S|S!aT@1&0Oedcz=tdd? zC{qBHv+1JQsJ*r+{pzLFllyPNY~{XBX4U&Io*V8=hM2E)aTHT*q;Fhsi>6bSK#&U*$z_HQ=G4TU}VpQvf^y z7l6449i_PC6K;ke9Z=~w8A=vvH^2gMZ9&|vRs9~7aW_=hz|yOLibH{7d4GC0tZItX z?Kh1iHbLeYwnDU-Bd8z`5~=|(C|X-60-v&lAAN-X2KzSo0=6w>ZqB{cGCP+A{O0MR z#1>p?IjltY$aDbh*tuB&#kHfyE*0IO=2~rvP^z4F9{+tEj_WOeq$r?&*uk+RD8G=8 zc!pkcjmFN5V}B`PzI^Ci2;7F_&bB{g8PbFrW9$P0p@pe;_#rnw+uJO!=K*8c9W)Bq zkHR`-*f7vWe3ULD<8TIW8dIA-4Oa%|S4X35*$S4X8Ka*8Pddi48*`12IoGcv1Z9c1h&!tm0-?x@m`eqQG zX9(pEY#8!2DPjs4|9zhuRDzBxmjmYLQ)k0&nCHPd^VvFatjccJBAU=p>l^jX}^ z>|m>iZTRd{ilOiyvatUz{%NV~h_od(SJbor+HkomJoaC8T8~2o`n|5R_ld$RD&RIo z;7T!p<$gk$+xl*zizaT9FmH1!;L}NS9?Ni;8pyfoxse7C?xJBj#*ckjtRvhU#rsGW zVnBU>jrelN$Ar-T_<8TwW*5E)p%Jxvpyp6Dh*2qfY01 ze2n*8FXRq~*J+p?9#;O`jZGUi`EjS3$^-!R4B5r%Uv|uO&&nwTwU=ip0E{prg`a^< zJNOn;NTCpk{sNr2R2`oPw^<8&2bbo>&)AgnH~hnYnP7QeUo8#>uB-BWF5h|}yyXyl z-sB<5t{ioSEDTS@c!Gd0H{iu*f$c}&!URqDL+JMr0~$Vq1F6zufQA^|g9AXjz9it4k6s1}^Z+-9%$xaGgJ48ezVg;Ry<`if z2}Nk;^mv``uM3teAwS>pFWU1-R9_2d(e=()ITWoaC!7_IL=Lv2YlAKy43s@ za5yk<6Tfcc{NdnYF4Ftl>PIrvPQCowxt_jEDkkY6;DB$l5%L zy?#AZkjA+?j~A^Jup#03-}s(w!(R{cBA1<1mIn)c1%OX*_#Hi=QYqpm_V%moYBO!Z z@EU~FPCMl(O9@c>8YDD-;bBArrZ(Na>kBwp@;~SZHOr9{4wpZM$Vft3w5ijcJ%fc_ z)G^L5&$-?Q`63fpUCuwW&h3%-T;1>B_wEm1Ho0)gH3Tv>LjbpiRzXwc#LMS5JObR< zuY$zDUZz?J;y7M}xX{Q8-{I~|%`dy&Tg`Yq?&wI2-g-2Y34o6GHZPe~uZKma)1e!U zNS&>Au$hI|;6nC8z5M!htf}R17JRwNLU_fNhv}gY&xQqcNMKbl46G9le+IN#R%>#X z^7P31D5Q205*sW$^bf!C#Y>5tJ)ov9+>5>EPXQbufx9Wjn;r1NIaJs!V0Q~REss7w zvU8cvOxMJ5bG(ZxGSzpCR(GTMs#Q9Rqk_?hE1w^s<1|e2kN3NH7{|MeDsBx-Kv)#K zC`^(1rMeGoR{wd81VYElYS&Mq`$EIH6lgOH1ZJ|I*<}f<^EbY=MXHSS*E};BrpW%#M;92w^4wt zcW4|}B`#2md1tBMnf5$A?s;{qXJJc7VcKy~2(WTL;^Jo^26%0(KgWkG}PA+>PoV zTa$mP5;bpLuntz8zELpRY1>k`DR8we7ygNkR-fhqnb&50)@=`uu4Zra+wvqK$l)&q7` zF5NG?c5M-&DZp}to9C9n>cFPT7E;{c8@POf#(Y%$c4sT!?T6nggg$M09#{EWxQ_RT zUr$FT`vMgC?Ry-=+p(@kA84KrW%uB23}rpw4aM!R`Lv3au|~Y>nWchDKbn{I{M^}y zOb(*>u&S3XFzWUJ#o+n2t;U!L9~()H<9S~bw?^%GY#uYAUi*UR(0|tt`1x|>gTD=z zl1pCd7|@?ZioaZK(2FY6-1Or9y8__J=fAuX+J@_jo1FC(sMex#Cvmh`Hsa2T&4t|LudzfBV*Su zKa8IrK*xUz?IYQ7>lb<7hghviDvD+|H46D;qsM}!wh-IVdPYKHi% z{gv)8YH46vU)YQdXt(CJ?7O05C)*9jJ$LUv?jzGU>}6Xe+T@Rzt9DG{o#~t{b4leW z4L)Z0*v+&5yKYt$DRgioY3OgC?ZhQX@ku3x1Bgwps|Drk(?7qQZM~Cc(L)=FDNIZz z{doLrF}wO7Uh-4*^bJIcN0lWJxs*&Hwgb8i8-&0lbMcu(q~h_IPldXJ&rk@rTaFx) z@%ErCyU}AG|M)qeZIdwi)`A-W!qC3F5N>8eh2N{svvz|iFntu3s|wvk$ELD{Hd7fF z4Kil8t~$>UFf|39{b=`wU+Kca_Vj}xB7u)c@bd=^uElJhlR+KU-V(q-k7a-%%~n z9@rIxs9p&?ys+N`H+=3 zuAlnR^|X=Z&*}fbb;KeLOrQjCNEp;x8PWXOG$~kjat>ZE7bE!lu@A%%tO!f;Lsv5a z!VTC;kP6&(J*s=WNggL%tDbnm`ncA{@`xw#tVt25y|GsU>hHEAM>Dh7)p)n^Jr_A8 z1eeYe)PjW|b|k@3Rok7vaBG=cQU&gvCP5nTPV;bFw7%hmWwid2*hfD}ro_$-BGaBk zARviA5p$f*E}*w0Tft{ySxU8+rEU}QI1{8T;jK*-=4IT5S83c%L4(`zcPBu!5*;z* zrX>^Kca5XhPPwYnFesdIqf7?c>jLBef_B3(mK$QvEhTyHv)8WvX1&ZK#QjOtZielm ziB@@U?<MC823}cpCug#&pwJv2-u>oP_Mwz;wf#b=wbN`+CxGK2s#4fTRxoVgB9Gl6f z7XwCwFMT4@R+=EstA1?O-?*_hu|oN_bT<>4=>{=R zT}FJ}91cE-cUQ1R1SEf!FSrRUDbXA_N{yVVM$qW^h{UOXoCD8U1Hc1Sxm|-y$>@c+ zM`?vaoh%(2#wklML`h#^d|R?Ja*3_oZifR`j7+Ez;3ALB+-nZ!;}ZW(WvNep9Te&3 zOi7l-DCor~lK%$Av+phoIB}WFoOs|=q3~sfbU;yRy;ei}OubA~v+(I(R*%M<@g2qd zh5!1CoriN`r&hT~buv)(IK2X*X8r-4Xgsh_Pr-0G{b-nK%FWF1G25OW(ll@v5+bpfawTUNW z^!m)a4@yy8<*6@YYuIXrO8t$jQjY05vq{Vy@Q!io3@QG+Z8mm4 zP7p_){}gB&L-xeSyKBCyt!OcLZDPrNhi)=_2@ZvLDRnEM&k-r zMTYvtyC7ult{A`uwrEaR9l9?)<@GN+c0#22(s{-p2SkzA#uiJhCQomem*cOIFJ9%V zwn4Fw{~H{ji&Q?ZKmoY-Hj| zleJyDs9m5tI)!Ijg(Ms1MFNhx<83%LgD|WKjpz@%oBm#lI;kyoD~Kpo_GP${7_j1@ z@2AmNzzmxp17pfSQqveyHJ8KmhWM&uV`$nu0$7^IP|8y^WK8DCmb1N6 zW(B&B-r5}-+|HEo-0w-3D|0x7x&VxKTv$mxB+H3N`IygjnPdK*fMCv{Z0 z$ncH$-FN z_zIb+89P&$>^2VpjzG_&rVsqD9pW&%su`ujQ=eHIGMa=of~ZW9yXP`#?$k1jsKWzS zDyawzuWf_M;xN$Ov!dni>2Yg=l&>ffRmR@s1l2pA+#5uItylDxQXO`)OzB8%XCC#! z?5S7k6OS^dxC}QTQ%yKqs58pA|H~=|Si_T}7C+ikvrkF(D=&x;8wZ~&NzbxIXA8Yn z^!Ch{<>;eoYW=QSS#y>s&sK7mY(Fj)OEuEcxcE`HGMcor1Fe0v8++=kb=1wj_`Z}Y zpH5Xbk#=(9+~)S@q_Yk0p8pr+7Ok@_(tXoJp|cN8tE3F`+hv2*x&DdeX+0q=f268B$H_}k(G zNC?*YXAQ2>R-!P)MHKh-MBgX!oL!B46aZ;E0yLVo;S)4-0?sb^U#lbWh9gm zn%@=7cXh$R^6-=r6b7v9uCg+pW28h{l^xNB$cc8B#n^Ml5$}IhgMW_(5iTuTxOdCT zfU)k=ej5r06^3jf8M=HUuYRI-LvW%hO!1Txf<-3?!=twuMQ|mW(`d;IIgL0vy5|3^C`0Uw#?p%Yh z1YmTW>t6pH1J|evH4-PGnr-ni%HDcug!r3WA`=8JtRzH%%m~jdI+^^EJp4G-));Hs zT5DpA9dS6g*WumTTg5}!H5kdvQ>9duUzPzZ5&1Q=oRXJsqbg};-XanI;*aFZP}e?| z)ipy%p!mxRvM80+0#!O;^X(wI!(O90CCZc}A`Y=FCWX0v4A%ikTv6G+7KZN>Es0&Q zCj*%OYUmynZY;D>M2zzuV$1;&UeG-D{muy zeo#we*BFy7yHA|0rJ%HO;*P3`ns(rtHab&!_-<+v}|Vs z+`flLAZFZ^kGH=Qer%L zthP^fjYokU5F`$1E?X1M0uQN>LK-6Q%;i_(xo0-)N6a7&vcbI3!cdkpDT>V(t_ew^ zr(rdS?Ehe=Z#K_Rpp$B}ZDAOP?M{xo>@(1{o4y=t&Af+mTwpGOqn_z|5`d|RVvY=} zO9lXQr*;Nvw6z?>ILaN`^lsTp4OW-F`Vrr*7dImMYqeCG7p<~VRJFRBby6xMqkljA zWHCui(J10EQ6qvzM5KaWmX7~-lomH%U(y?~Y{r2E=xC~wAYvrizybG3w#6jn-=LS< z#&Hxa8qdZgH|lsu&crIrS%i~8n>zgVw~nck;ElnyQuTyw5Z0Do#1Ef!sTadSGRl#M zo_G^t++<=VWJ|kbn`01~(RekggeXK}D#m8`q}tbJqWPo+TqPCVZ6+We>JFxW>&UK7 z&EllrSs_GSHE{hm0w_Dpn3SeL8f|NGw3Lg32<+M(h|~4(ZM#lbU7L>m0y9zMIteSg zL9W7#dI_aCRHNpXUyW(oZ}`*LzMIjL(UF(QZgK{W^GYOu-oUHDnbP1aG=r#_eHP4( z`bo|RSILFHNm||;H>$NC? z{j`OlTzNiT5W^O|d1lF&B$i*B7I%F(%x5^dg>(AEisR~tK4;|fL1KLL%sPp?t2Din zAq}=8wu0Ul6*=l~d`(aD89;8$jnbfk2=o9$_93oD1S2WXR2|u2i^)hTlMQ zWlsj6Xj@Khsp`EdX%IOx&~me%TCkV4L%vr%SfJ+C;5T@$#;!#1#8A1-{o0Z1CTBlu znW%>hSKv~SBZIf6MsJdj{Q9HRoQpeXbJMoMH?QD!GSlS1&QB-ItEK>aEyC_$l#K`1 zDq+$PD17_K)#J$D9|NDf+Y+}N-D`{#r&CJ)itp6i{-Phw6+Afcd`dnjQrKcQ%D(+O z&LLTwa1WA+_IwzvFR}LgL5W^dv71C8pToOn!TsWzS}JxA)`!aXB85?T=<4L+ONY!o znl~)&K2kqa@Q{&Y@Rt89#^EVI$9>_Zz}*Q)K6>01H`?WjS8TW*qvmu>Uzuwz{gLd* z9Rv~^e%1RvI=iE|DfIX+t8=F(Q)@n3l|?8k{rysTS$_F#c;QZovuqOZ-6<{UQtu4{ zTlfCHyK-l1KoOk46hFvOzD2!)-BF|g!j2&)DEB5^r!9DVNlO--K>|y&eWefU*-+hv zC8g@>58$Z1rA$SR51E`+$ks=l<+>|67$0u`^^U-{&mhym>)6rk*|E`X+|f=rl;NmD zlRNleRNXG;{Oe-H9RAIe4;I_A+p5flonIJBCMu}zBr`-(6`w9e%aG@7e{GL{OD|9_ z(Ldh7)O)JCm9Evkv*a17wL|Q|DGysS6Vw5&5=4ZHTUfk#c@egXH+mhW$T}}uc=N8Q zl+AxyePH7(X1R9tYJQtkHB2cJsLsH}?GWp={rR?X4ZuDV*$#EoOt>%D1&=}0-~B5D zzbmYidWYL+3Y7CY=#fNxcJ6a5LRNv36<78eG+7sAPc3ypUa0|D$$NvhaR}F8@iSvb z3uQea%5kUh{V1A)(c756xwVTs1)ug2P7T0!bH#&4K#Q#jApQ!Fwi0&VUZ2IC`8%H~ zz9ar4RS2^*u+funqrDZ!xpA!-|Lg5ZrmxMZ>I}s~;d`6?$k=PyMmP-7sNuUTgwtR; z->e~sMrb)BxbmkCHM4b&+q*mv<=&5PI`WIIkj;UHhp=vKW40|C{DKgkUAtQnstm*J zQO$?=eE$oXCfx}%n)|UkxQDbgMhQ1w@hh&Z_O8A|`ws$BBY#IkK_+Qr)2ZRHV&PW9 z?RQrX;@x&8Ab2j)@I-?$8^5vlcw8W6H#G_&-*0yz@2cNgx7yK; z3JEjz)xhO6Xp0&B31u{;{Lh-d3(of$B+lG(H#NF*0vubb$~+zZP5Ukucy+@Vcq&Fq zNBQ{PyAZEJr4Ym|cCt@$Wq%7)czg7s!wr6xvb?Ns{VfrW>>^Fu+w&p%5D%6VcUIP$NNSKl_O5yvP zhkxNmYQijoBKiyl1Vk5k;UwyXnD#6Uze;kNZljgkKT!k0ly)!5ORRd_RQJ1EgMT~q z6%$!Z(0y;NuwK4W77VFebN4|@GRR#}PO;Y_rrs{u4}^27o3Eqqlb4h2+~Q&IPjRc9WqB*G9F=hWEG2%g2+Pj&8%apSkicy zHDy!D))^^W_^w=D4V_g#gh#!V8qn`l26&}Lu_~uBC0Kz2$&+`X;RANa)mmV_UGwCN z>s=O45w1t~=H;f9$PHmQetUo>eNdafGDJhtXX*zwqo7x7T%DOf$0axkKV>!l%Weo1F1s!^Omi;B+QSvOqaqWd{}h(j?}FWkc0VLY?(b-kHIr} zGl(R9d+OEQx%S)AZzm#6Jm_lNmg-%BYTsLNqS^}jX?pkDN@aOg_r=Y#tC9T0Vb}r9 zXgx-7GdSVZDxYb$=3L@j6IpY z{h{hu;*;ipJHrqiy6R+%LA z%uxi@(y}#X);c5AZULKMjS7rN&1##~+{?h|yMGHN-;{z3S|urGWp7+r=>`L7-SFSX|(!r@3^PhI9DhZK#c_2!C7x-H?|7$CR)QJmy-2me)S1S${9E z$UE1gFX*cVe-t;EK%OSOikj`!3R&d;CA$oA`atJW{wYG*7Rs<=u=+(v$+Ts%-6^f6M9dQL($fne??@@zo(8 z*-(u~4Y-=WK5xE%%8e>284Zbb;$7e?W(MCB@nff56huqQr`jos#Gt5xwI8fLZdiT9 z35PNx8UcN93yM}J(ho{CtmLOr-JfvZpxyVMmON`nWg@9rC4NHVp{@snCmqZqNT-RO zl~;(D2dv2wKT2r4m2r?->@P33&ER9XhUtQ}n!UOgs^5qmzJ)qQ1_TCzwR#13sgb?S zM^D0$oXx1(ZfP5Za2hs4fGTsf%j;DMuxJD*sR7{`=gur!eP#=OW(s}=q5Zam;z&Ts zZ$Ex$h^dPimvz_xFWG_PH}et}ivcE-GzG@49L4e=TxhO=h_iZ#VnEogR6Li3D8>b7 zoDW+Kl4XrX35Z z1o*N~Pk93}nRzHRpd0Sw0U_OD9&?khuvjL#v;moHxVS5c&V>0q0`66w=XwgfaE_UB z)(<)htgy4+dZUk@4TkDP`P>BNB%rFJXiNxTq6nM@$C}D6S~eFw~Gbnpt@o z1EjWUy zrnUI0Mpc1liGY!M8qX`>_YXR}5|+fed2|xtH&#BW>hgr9&o_3B3siGs1n0TiLfL^SYOXVU(_8X~31A*0@<|mS#_%2;#h)4nvmOD%Y~K?umAsoKjYG6tN^QwU zbgMJ!i8HDdTLo^hual1#`V0io1kRSZnj>!>4QX`$4ZP~U1=iEP076y(@)fKbnX%_V z*803%Iq%e}f0+Vn8$yTcffpx%-Yojd2mGH+Vz1UltLr&@Q})R{1nkD~dguaw!hz(s zu8Da`sm@G00#mRH-r{S@`xuyRuQ+6cu603Gc6&bk47{6ndN(Q{@)$@Smte8dnK*cm zrM5Ib;({*xmHrJ;;d^10>JNMY=>2tPAWddJrO?49m;nK{SVS1S*U**tS(l z`;y=b#rmP>hh_)*M&-o^0rX*DmMvfuQ5Eg-2uwiS8oG!*47>r~Qxd;-VN^o>A2N0I zj6$M5SpFRSF_3G9eipz#5ZhLx4pi3*e|1f4u>n4w2X1#G5+VTas}iZs#R&P@0=?$q z(WVkTC1$g<48H6sXg|iG89eq-AypvJ>lU)bc2+%@MR}AHgIH>Bl<9f&Z0yksUv2cF zk7XI~&Nk&xJGynWe2Rs8|G92nBj=5@_JAJnSoO+XuKo$ZSo7fK^= z<&@p8hsQ7U0~fvT&n2QOJ@;>~VBWi~!+-89m{sRi-4dZ1Fg(Dwzn?mq*rc0cm^{i? z+Up4CDLx1(P7GAzPukZ^S$x)fRxsN1{$eF`42!4|pWh_jDhvLKb{F_pgOC>($HjAx z^|t-Hhv12Mb__7jdIY2LEqyXAyWf~DZ1-kSyb{+2xCquhytD+*nU}1OW1ttzfKSa& z3NE5=3xn6c+aFZ}dbWh}#RlMd7vk@`7Rk%Xa3?yVx-k6LXg(gK0tz3V5&i90?dCDk zqw^O913i#kcfkw%Z1!1xmw2~M=OCq9PsuGyjx0 z6VG`KJ*-{>qjudG`T88QdU)V{@TOIm#FN3XC(`&+qm$sN7LC2wL<8&tWM$xAsp4T! z$(cYkVvuarKIwbCL&$Zo{yJv2qjG(1;O9R~Cg${g-2*L;&pw`dI7yMbWsi$H-1w+9 z9FDToR|&e`C>Hipx*TYmump7bOy7)m3Xf&*$@jniD+p8yu2cGDqWZb4OIcZH@1QE2 zOMA{a^cuLPTIvL^9`E+|dM?FK=MK+PZmQtsZ$jH3f5Tt#J5$(^Dq6!diKqp9ZS>gv zEByigg189WrpW!=k>v(RCB6mjZ8k&Dg3n5uz|`}95O-V*ORcJG`PWGh^qr6jSJ}<% z&p^F2I!BQq_>tuqZf*b49xzRH71g`a5Cq`nyC3s4>;ps2JqVZ^IDWR~9q)@UdD+M= z@vSwW{y7OI|1gRt+vW#=d~jLNMF-x09?mlg#oNET0C>9?Qh@PJzPJN&WULGwH z`ZbTk8~ngNx*g^E)G`pI8ld2H3~)wCT%%g#2dgEc)sq*V=J}O}4D|>v*dU?&4>l&h zx}aW$qIv?1KUYXX^J4fbad_J|T+mQ|SvtJMG}&yQ;zbrZuW(s!CA#VkeYqo(@WDhNj1atxTl~NatYA+N9}ka6r3y6bM5i%;&GGfPaOB2RjRHQo0JO@` zdzp1fDeKa+JKSTYCqH54?_>!rVmiD?#5;gGL1vzpf93S;B*X}EOrXOKSY~;y0-rYu zfu@lCCHINlj9lsHyVCX~@zN7n)V#v*Yr=&(!&B&c^3w9U{QhJ7qNXA}#s3M!EMUF@ zw-GajphKvZ6Hm8tp_LD?^6Md8Nm?)TvKSWEsk6|$!C$=EMFyWBv5131iUW1dXWvdr z@Vw`hf0sG^l@CwJJOw5640GoB>uu~mURZfih42aT08u-pCCIO3c>qx>^rOhpv-aA;OC$Zs9X-v)U zqktO;!QtWm{Q5tR@)&>YIn*~R?#4U8JVDd?zkFBFqxf;$So!zxGj0@6Opa?LR|wVo zODgAt%Uf_$#EFl$SfK58uYWURBmAjn07|a-fAc#d+~4**+XwIOs8l91wrKFK?~z=W zu%#Jn(USC=Iq3t}&<#;Qol0bnp*_wP_{0?G!67TyKgdRbt{wpT9*pUo-zH8^Dv&fEH<*0K?(SZ-BBMnCXR0XQ7@|7L(cZ!(frC=zaPXSS> zv}8jkg{aLYD3IbDwha(QnFL=*=%6e7tK0+HG~bmDL=mgO$=zf3w%JC5XZ@ikbM8i; z->Wr1DkBx@A_{#Uat$lR{s{@cqn1b>&$lbdt8Hh@=-*rZbt2#y1Sa+x{z=Z?G4WX> zr_V6B?K%o}&yB31sO8(d7vZ1qdDABTqisppz>7GWgxj#%!*$G=o-rw|g)zU%y65RR z|BM>i1LREz+&?rVDvy_(BTgveiYx~AJ(EZ3sV&pc<*tm-Cz_qUo`Igz^&X5Kqva>E~rO|99 z;q>wt>_7&UVd$#prT?x^JuUH?#_d}(w~-BZ^)ConYxi7z{-mvgv})JSH@+<5poIy& zL)F6bA9UawynV12Fw@#EyX|kE4{u4T30ZyRjP)hMhvCxEsP!-|HqKwk#%S2~o^zY@ z;}$Do>;QUIK3-#}?!jyQAUG#0eB!&@Ni(T>caP*Qpb`SVSFa>xX!cc3jdfif&JvAO zys3;1Ldrz4W8<)4jzdEl`FGuan%^5BtUfs?k|I9r#Hq4tWW#Sh7bXj)((+72zE4;j zg{2fY9o`Hf%}8heQLSOL<$aJly=ST`ABRhDSA6Li;o%XhqoH0Q>S0*Qv3`YDtr9;o z+=t15cl25vE7Sg2NaBlRQIivC4@?&6(sVv?@~B!}`GpP}!?g6{$jWf?U%}w(Xa0(r z>*gIGJ2ZCo(sj(ZoC2pKTvEr&>tgv<_bxoJDP&#d+H7!@&eiUn6!%Vf{Kxgw0Q#0p zidc|!#XUU(J<{dtMJAFdIe$JDR~3JC7+tW<$EEN|PVI*plab&KY)Z#ZO*xoCF>AfN z%v3S#Q@XkNZ@8PDYx}y=Ip=c8=|iMWA=m;3Wl!V`a|&CvS9E- z$-d|Yv{4GM78oWCr@JpdeXGt9uZ)qSe0M&Q&l%z>DZ{hoA7(IB0+b+3-B}BTrRqRa zb*bJC^xwN+WsiXkxz*=be4NVFUl9>k@Y2KA9OER%77&g!-Q4HG`j3)Pyi&@6lU{S1 zx$d)dYH$>vaXB@+KvydRj_8X9y0em*n^#Ya_2NugT4iUzFKIu(!DHx-GI;}gGp!pl7Ay$I*WOA`v{sQWjyj;ZK z34DEi35l+(`lqz5j-b7X=~ZSMK5M64#Zu(yL4sTVp-j_-%bopoUm9HX*>5B?)=B6f z7V9&9=0rz7hR*N>@f&o5Q;|n(q+t2xo$3WxrP3mTH*>rka+iE)YRN(tpqhs-$URUP zlymrQ!YB`bjr{A^L!|UXTYX6{ppBczU2|k?bc@{$IH6pTRcJ>@z!ncPRo3do?z}kY z@Ov2UD>`9XFpS9Tyf&dcReFG#^C74)d=>X&G%p=hO~hcPF_|a%liuFDqgt8PsUI|6 z#t?1>)r1!l)EN0Zw|b5unMf*EHo-yB-{?ON|w`4i`DIm|M7D;pEGpWri zh>{wQ<5}GbU~ftF5SuO&!nVq1Z|E(W@({jT0iz#Iw;E;o^Zhjj#%et)KKU)%i26*w zRaky#^=G3X<@(d4e5I4hI+-WF>NB%1e^p{)H!P;I{F~MmZx-!lXy>>H=sdMjoZqz; zeHMPzE55K#3d5(Z!~O7#ffMSM)k4T3;&|n@L2Nh%$tQdv|Fp~(O;=l8E0UEAGfy0> zMEqc(zajKtcj*>4pwGByh`*Y3KkmG7Lq-uqxzW)v_2AO=zBEY6H#PCbyPtP`EDrRKD#)m zs!5AY{%|f!*~OmWFd}X4EiOO8wmNj79FYGQgXstTJQ(FtNXfpAeOxN7efKsKS;~2; zKhR}i3v6)5NNfRLZ$78eLOep35^S8uE<@*2S6y(6NSoT`Uc|JORNRzwv}(rNq+>@j zOxg+yHa)73=dUrm`^x4?N1X_U1xnpIdnmQI^~=I%&p=Mh7WwKf@I^ZR15-l^CtrvN zdm*{Rr`**?6LPG)9i;iZf%m=uvOKL$X!#Yyl--e+wn(#|(v*Nj67*SLx*Ps{a&odY z&wTfEBV_8qr7+_&d5dv(0*+}G-8Vi5*I$adW%=K9-@qfIpsj2@-%tKyD8e}^vo3)+ z02m(oP-3N);uj^cbh(po&gI*x2SsJ~E}K_P_h&K+H?K8-Z}j@$nl?Por`*iOnPW5C z1-X!~Bl;KXWsbgsI?XPsn&M%5dVv~B->+|7(s0pE5-o2(**7LTY=NVS%GSBcKO1`Z z9C_xlM+i*Y;KMDI;^`Sm^qR1)XZ)%|)mU=Oa*?vB^fFM2`BTFAA-es{IOquV9}I;x z$#1(i7a$Whe>lICwqnrOGztfv<$eLPJ=*WDO zbe;Kf)gq-7>N)x!6{kJ%IFoXU+Smi1zRoky0RnJv;&b@1rE1v=xpzj{1xynzGQLM} z17xxT6WE6FE5Q%{FajZ-Cc_QTH!G=A&BU^&Vn4)abW@tM^0(*kFyC6tSs`+OX6YBq zLr_8cMlRV7ZoQvQg?=oZ$H$sD!21{G)4@nhDio@hlA#{5{|B9vPt(}PK^2YcH;`(N zDZX7iI_3J)&!6zKDLyt3ytA0h=d2?%He;278l|B285BP%lF^gw&0_}P5det%T@WCyOb?!B3<4mY8yq-K z%#r*=8`|piyVCGCMC3s`JgDBdfMx01iLf^0Y~JR_5aGsSaLdUdJ1k)f4o!{{f37Pz zJJ`9CN>7IuIsD1EjA-gu&{Sne(44FGt{*ZeyKP)hUw54Xs{h{M5Le9$Uev?Ll>hH`DsKGKOUNzLz78U0rOy15508q zK-22|!hadQ%rxJPp)H(+(RigO$$}GX>VnkcUYz0NPsw52#gy&ov+bx95L(&ZvPB&h zw_Vnh`Mh5(>jW!Ji3ndp9r49g97SX;mQs=>oxbm|Va@7TM9Qw2O*Wfy)Lm-8y^Kl2~}9?_oaa#v8DsDX0G`sEP90==h~AWB zbknA!Pzp4!ddlV{$}{(&+)vj(hEuWOJZtjwLVNmeCHmwr7D*!x?_|K)uCx5kr#lCE zcAcQFo@z+H@(%)qx#qk3!~wcVLE6tXri>6_xXk54q~ zTX0T^tS`}m>e3kInU&6TFL;_)-J!WQxa0_YSqc7}mF$s4d4!8hngJ6NiHmy!paQU(R74 z^Yr5Q{S34dJhdx`<($E*_i+X_eS0z!k(SQTBO_G6O(bX{`m$RZ?vDTCOeFlNf2jj) zE2cKZkxmgdUY!R@b($ap`Gin>u$;5+JdT1e_7E(un)6LjgPU9LpQi+1A8%-=p zd0GJV3y!{*GW?G9`20vu`Pwjig92v{!bd@{QIPfnP}Hj@Wy8a#hvCtU#8Jb{i4eCG z_!|K3RpCzOb@n_yLHRc<|IJQ*T~Q^e2LI5tYE$~z>0_oH+wz?;Uep8h%S*J%y6KK= z{MTiHOkvmtGNYd7`ZMKHn`|tNG8Sh7?=4| zpbb>>%1TemL1@*p-UHrvc|wfhlwJ4ESW18(&2VEmobQ!<1_&gGAyZgh>jf=Rq5|KZ z=is*rI>*otyH`2kFb%F`ci~(c0j#%(}m~CBO@v)Pd~3 zvub+ZX~NxpgVJGKE0IPbS1y{$AeucHz`L4W`2K*f zs5lR;nNmISLi%X717O| zb`f;J7RF3chEw1n8aw?$9wX_wz)4EQ!0Z@}4)JXqgTAKodHZ}{J5;nz@Jkv;6Rx55 z%xIMKFjhLx-E2otnnE${Oa2>k(YdCLSq42Y1xKagc$N;VL>rBW1gtPjcqEh>aCi6djeAzMP z+Q4Ci(==S?^E8c~agGjiH572g&@Y+-@mBOGcn0!shO6#PZyYpf4`vBi5>*g~>L^|= zA%$skG)WoN-OS{~6z>?SFr0dF2+m_FZ7gY*R}Hiu~1!o%7v>8q}A*?;fVr9M6=WL=+Ec>YC)sZ957OY`2& zu#lu*k<7Tn{@B0zh@|q8!MvADr%ITp`@Nw5nUs?_KKVrF3(Yx@-*15d@JL|kY)^QP zBi-$nrw}NDDITGSjmrJ1e%nD;`tF*y?3>%K)_l)>YAVHGUoej*G7RHTD-p~JEBKdJ zjnfXM4_CbM1Kg`s-~@UL3Fy|9&33-?jMnVVogl;FS(7xDgpv~cn9d_rmzjiwXF62T9w* zOH)bhK=(b%$a^yMSROk?&N^dsoknKP@4=ki;fu0xBK&4DobQnfJXtN%!8h?n!&yZ~EUM263@8Ngf)&v!C;)c__Eb z3f^rzBDjWas(UwbbdE7k+cAN1>uWzHtEG>{@W!lWtV6H?Na&L*(DT|KQ1WEjKmLr40OAnY|Je#nFwqgtV8r%OMAXOv zjoj=b_@>B;E{Hq#h;`NaqtfgGY_9Y~uY7M9TKz=CB4hPPbGa$Qk zZb0V699#mMl05(2>semz)9{$0*O^O$Kxt@%dw8f9-Hzp7 zkO&h#+3q^{=|>#R#hQNg5~0iOrhMzVxf9$R=u4h2Fd0a_aTsw#1s=&t|94FKlIh3) zZZZh6^b6Y=7askd8|4*_X}hvD{47MPbY$PtOE0vA2j2-91f@A{FT2^&-I`{|+c4CH zxaPSrGcsIkU_05F$M3(m?x#OBCDyY0;p}hW*W!KCBwv=ao{IIj8Finw7IQAY6b8B_ z9gW+}Z~j9Y{Zhz9R&p~;SX!WKnCO74OM_Z*pbSgBn5fkj5`xc(l@TzWcIsQ&sY6Em zCgTdd@Q-Xdmv6Lpnr;u4PrH9e=&O68yHFZgSJ9~%x?-I+OD+;q0c)^-K7Io~#)Zk~ zMs?5qq+vf9U3P;Q`KL@#0v~;mk$nTve0J$F|0~BAu{|)F40Ah;2lQ`&w;sUJ2DG=^^~^f9Ck#jUMwvTn!-sq9QRHxsP) zS;?g8*Nn2(6xN<;)sGehWnzxj-k+1J0cxo=QAK~x^9Q38G_-`(>%jfvSUZ7+7`^UD zyad|Mefh%ud8AMPmkQrZNb3^R-)mp2MhaVB=6iej&OevvS&t^vQ?pm~0q@zj_9_+) zx8;<$)=XhN4Kf{l!zDq43X>n$hnEB5r<2 z>6P95;n zMGLXXX^UjZD!5ACep+BGS2T%VqpNz6q03cE5E0~C&`q)Q&)jw@6w7SxF6OockUY8E zMqD>ODD#gK-$_{r5ijq3vKaq56x5A?wZ}PYOV(@!gz?qi8w)(J84MiV+8C6#qI$*; z1<3Agd0A$<8)IZ8#3ZfpsrIkYMq_@WH!ha7dpU~&v|&oX5B(6N2^akayCcw@0;vce%7;XCsAGSxTbkL-%L=ZVb< z+v#@0@4v9{2(Ko%akXj+U3~~E-L7sJQca0}f>AMkwkX2&>GrvRab%1*2@eNzmx_;n zIu7xoaYtWkL^WV&h-wjuc%=G>Yn+Wj4F0vGRkWzmJqq2YFS`z$M+CyS!s#k6@NUcGci zLfMCDz^MkO3x=e+qzSIn9!H~XDsOkY4<)U9brX;E0ZRFjEGrWDu0@1d|IN1&40{qz za!hHyWI1-}kTmIqX5}(^(qd~Z!CUPXEniOs^TreK!&K%)gkJS1{D|+9BxU1rE$05# zN%$<8tQ&b@sdTj>@;C&&v*QGGNEMEZ!b}x&3~J4y0A-f~&pVc-JCy@J@CnDAUBnOu z|L{j-NDtc`F<(O5zh^lW@gGd|S($_W%x;=LfMK8&%Z54V!`uuh2ueXLzxc(-Mwdyd zT8{3`i@h#_anF*ODb}p3;sg4N>G+*sAc@YxJ5oE6Nj+|25v6$FL(JmdyXRCoF^w8H zVKGMv>70wdRkXW=jp%cQ^lcZ*js&1s6k>|`#Iya{3L?Fu$OnxWnx0BajlXly)(=g6 zvWJJ}l3<6wJ(no;8|BfvmS%Q$=J*a-%+rH*#N2HoO{9@QQ5^L_ssa$-6@;MOMG}w`Nzo=J;fpZ zY@-lG+bJb*(Us<6Jf#(Vpie=OQU?d9b-W6)W9p}Sl+moJ6l@(oY-2HtpM)D$O}9ME zm-*taj(&yc)Vkc(W4f04Z?X8jRB+^g~T6^+0ZvVVht3sr%_;Vc%_1a0Qu zStWjThHL^S*idDwL-~%JIvzDHX;grAuTSMF7%lB&?XgL4+H zo4HQsXs9D>f>1mwwRS3?Md?WW_JwxQx&RxyfItSY!t;8uk z;JZcu?=3u@`cr_skMgFXG zi^Z?u*l1f=m&*HD^1dc+RGR<0Wo;^mQHrUTvsQ@&oR{<3F_mzWDf#~Km=xhhmBWg2 zrd_FirMghP^v@=x*vJ^g3NFw7FCVAU4|ZQtRlEfUjXST*0DfV0-R8!07U)tg>xK0{ z@?QVCfOc}P5?$A(>(X1$fm2-y3x~ZrN`Xf;7*g$pB{<->@qXmPBvxr-&Enyis zB6~_)H)=CiyuMxGKy(ZKyASS4)~I3$a2MaPk;@}6a6`Nvs(5pOOe6EsTG#0&A-o?g zPeK@IHpr@T6Lp4@aBi-~CR=jpza~+FQ1XW1>%Bn#RMs1jY+ZdJZe>Ugs7g@$6VJPH zrT3|ln{>M$p?2KBl}qb?vGxPwB>@fSE3;7&5|y08!hzRQbc5V5zpTw3qJyl?kot4l zRITscL5pyE+D@o*J&Xd#>nr{yU=38>i=*AgOAl06a7}CEE-hw6VQ7blzfN7Wlh1OC zB?(_`qyHA{=3FgpiiQp5-#wg?%H4aTU?R3x~{-nkTawF zv2z}#pxHOjz1NC74_=8bl%m|264ObyvN?-zXn`uMK(?R%=T&xT7V*4on4wYMVf zq;)7<(H?omtpL(<42xSxs|h;Pl8w{>(FHz?sMU?sx4C{}`uB~<7bXMq^d%S9TTeAu zjkheOVm%b6j+R=Ylpc&8pCBqV(Y=3O`JKG#)C+ZKem@ooH;}Aek=cg9eEsu044!UE z|8c6(a8q~WE>yJ-(gnW=Gc0%h$(21Cc$c$1SHnN^1Lh*(^UnA>TfAf*h`}bv&smJl80pHM-|Z2|VHuD{hVrbW!v%maPTpI~0>f(u!exb( z@OTJ!#uAn1%Arg*qkH4+N{$E$>HCp%YZ*_Xof@Qj!qi9bRE3URZQiSeCOhW@kzEDb`AZGjL5F zq;F!7{lG-72L$osjRj;1&ykT0vtL=Suo~?#FRirf#AI+@q(<>R`Y9i=(<>b${nGLV z6j}07$@SyDJ(HXtAiS@IwWiPMy>(3oPR&R*`Zl{*90 z2RI6?UMkfD6@XWNhgZL`r{OeBY>Fyo!ebRc71W{%n!mMRP|&a5U3zjANymA(r~MV> zh{cdR+#!x)5Co(6X(NbZ%C{8)IWpf99x`t+(Bm4Kj#;Ix%Ma=NNLl>hWZlUtolkJa z4W%|OSca$WE0L#{G!$g>AeJRLl(i>0jvfwOP zkb;!rIA`{E#(%oxc38^393W0Xr!)n(*K>%OE-X$$YvF~osAG8oyRY8sc)YgIascK* zb}gb-QyEqiP`KE>my+E+-zENy(U;b7Z_v zXYcC@AiVmoX0)9TYx6-cH0T_kGGtyK=lb^YwDJg8iw*Wn57rc;{l-A_{D_u*L_y(O z_&VOv%`Qvl|GfQa4--=aL!ayJ^~i@*;kCf3o+N!G;&E@PniNDMi2817d>R#IXPJ5V zRT}^HdrB`NcyP={Q}L6jU-rwhGpUr09@jg(W&=Ib%H7+$a}n_= z`ip!Ay*a56XsVu&s#sw93McWR-G@DC;*1(h2-RxGN=cH73AjvBK~?(AkyJ!UY8oN<8D;-k zg?9kj(vxP{@uYlX&+n3rhbs6fu57daP!twXDJ#( z5)ye2slJw$hWIan#T#{i)F)Zt0g6%i-1#uoV`Mo(Vb2IB0B04f zz1B_NnAK%Q_YuCDN>v`Ptutv z+hzQ)emF#G9Pk65HJ7QZBi7aY=4T?x_^J zVD6i4iZs`dfs3(lR$Emn2WYhw|c*-LYTWSrPBz~#$RwgVPiGh(uxC+czd(z+N)6UW;G44GG- zr}0i*32?Dc*-cwOZR_0Sill4K5NB8*{c6_y2J1x>_~q6yyM*RuIn3x!-XL4}kwR*`qE-Vl|HHK)oj5qH9AKO;62ouP4f=WQyCYlv4-u^~SlFM&YBKdp{mKKd~=F z7q${C9vas#cZ>k(;F7MK*2vD{Xu&@?;n>4~;rDAJ|HfPnXo{N>;|`2`c52x5a5~g= zUFhU(SWr9@Bb<(PxJnX}+xwdVisFZlQIbJL4&u{Z7d5On=ee#Ntj3Kigu=ei z(pjsi;9gD6jYo$7n`})6yLfX*a1|tkSQUNrLl#V5HS4WauXrd7*uVpZ_S{{ko-zjg> z*WH;txC5*%%M)f-xa7}w0*Cq%z(a# zqhCc*l3e6)Em!_Y8DtOH!+#`V#m1a;#;G0|d5hGnOM}+uTa?mhdLP_)jeE5VbvJ0X z;s0~$z`Iql1`}WeiL>y$*H(=q21{ICc~1uH8N^h|8Q?jqJNaIUoKI%~ux68h@_5&U zf?BM(cYh;;W&C!;F8QE)&rraHA5OE*!zo}*{w|h8 ziug)N^K}z#IgMt?G!0MWt8#RwnZZH77~wbHaz(mCXP;QHRa;Mc-KPi4cdjl*8ekKv z<6v@9n?`ctR&Q$89u%tpPEsda4+_l?-*Na-#QlQsY>UpmYzu{xMUf#Ks^~Y?FgMk`Q~uEuQRJ$eGqI2w2Z0Bf!tf4)VP$0ufY>un1Qy}6eI5{6}^ z91)`dba#o=+ayl*@nYjwbie6=@q=9BC3O>In``nfSCyZ%N??d%V!b*zBy;LF?XMe- z?x>keTb8u`w>hM_dwT)kNA~fach=JA#)koVSKPLi<{hMud+ppyGzz;*G9Kg6$xF>9|hBCQX~kH=$uFH=5O5s}8i$)}-KPB4%@>Bj-c{ zi8EiBQ!5#=#eR4l)UEyg@R0Q}rSKfweSI+>nLv%TS(NGGS~Tq%j7=_zgeHzo2? zr6LDc%16)TKv86uURUWdrpyk#)0GqahC*dCgN9!|7jLrTHdXEQ3MTFbn*TWv&{y&9 zZU*#Wr|c8++N(L0aZzn6*BI)$e8AqsX}t=uwMYJ%ivOoec6T#rq~wtMe6qQnqA&i&JsYN!Jl7mY8ft)Q2iog zp-P^2y=O^a;YX(}8llG6)2fpv{)$YL94nXRdvY`_rsfG2$U3Q8)dRQMZ&~$vHBDg9*PA8&{ai&K1<8ev zr*~$Sv|}zT>CxdUB-D~U6+4hLz~M1QF<~`-KD6jbT0F6NH!2V##(hhsic!fPdShKC zQF3>0ER3>*zz-Kb3yj3G!gBVK{{nuSuKxm(IAW2%n2QTmek_@>`n zSH433yt#F?UtuAEG6c+o z8tBx=nLheGPuZo4G3K;;d{&ig9*-$2Suk&z$IpQA;Q-4*RY9`S4=e zJpLNuQ{=u8^c2vKg)Ob^a+eI!x>*$aN9C3ZYAP0a{?1%>p?0k{>e=#wuE+^1(zd;5 z(KSL2f=5ah<#30ZYuL%@?S>T@9&s@%<_R2qktDvMl(HEwqH~gZhB4Kst!K=M36(zk z>~6yO#)G_-!)gGar4*v%?AiKw&ggpV&a-M@aT!~wui00nN>b9tUDSzM6R5Q1EaJ(V zEp_1~uc@#CWu!TCXwp_^{fAM|HU^@)MzEKZ1vm}U$k;q;R=e;uS_l2G@4IZ+1}RLk zH8di>Um-pJYUQ|qG zd}IYhO+XZ*N_S(WG5mE6uMOWT5C6SYUa>n%4~S`FcevX@{r1c1GiW7a(Bh2KFoP)K zbwy2%5ou|E@H(Kq=>SoyKre5)^}URAVBJx)heVnabiJ~0X11WhkAc?6Kz^P(OiGt4 z{cr4<{?vlJv{o|kH@en>->{4i6q6*@nMku3?XA;rTiSy zgP?u85+ft|=UldZ$lp%vSC-?Fc44Z4Z1p9}%&!^FmzmU{yJex0c4*6`!GfnA4Ud6i z>d?>VqpK!v)*6*x%$$~M5vJ_g8&(OITmw9|Yeymr92#6uE7QMi^H|&x0%>n5bo&T# z*r`%BJrj)7P0_w5o@`Bq5v9p`oevA)&cs6i&h(=?9zz_Z2Q|BA2zI`~b|GPHzvJ6l zMgDnW=bYy~`!(yE%sFC`w-`1@lav*q(lt2&i*42~a^JM78;ut(H}ymrj3_D(DlJPpS@b7@dsjbCeI{ zwm8J@+jE7!mLCis*p9wVS}qTOWnc;dVZ@dcq*>Ng8QGS2ZSyeMrnS6-pPL~XgXYDd zga+lFMOTw!bGxoB`C(7+Us!CeBP1bjRR{jLH$c87o#1jjw5A zkn=a6j2{bs4x;agU?DiE0jlRe55s}|cVoK!2UXm6#Gb!fJk9PK0}_IZjtF+Z*c4F+ zx_WaWUxz<*fMWfc*{*E-ZNaQh-m;gNe#53qOoFLEf&O7PolZS@gUQ z=X6Bm(V-+~A3NTF8tKfQFty>$&S2auJqY`k zEq4VUSUV6_`@e)(esM6a;rgye9{N$tSbeKH^bIY@iT_!m4%#}yQ$kJ^%%P#Z8~d{` z-3e~KgBr^1lVLDsgZyWy8`mDm^&9-wLP z;e_M%0$)TbLREryi4K0$HH;J;_#+4*+9uFrb?PRKuhtFr>5U|Od37eh=%eWgH-@Jq zW$umakm`C%V*%9i701#lPh2xy7_83hc8=k^d=(RuoL5ZF8)YiIZxPp9&_~%3 zM44#rtkY6N-n&pB#d3f#5M1Z1rnQTOPu7@JYrk`2Kl^`s%Hc)s@{EFD1=2BLNeDs4sJYBx)U62{MVI7q zmzqBlAav>859X~tIwE%h?1AA{zuKI|^*21l!B;JJk~X9?n?x9gM~+iKq6-}nWsFW5 z&ebNN;d9A}`KkF#PfJ7MnAG)NkWvg#De5yJf~gdx09f^D{3Ou(IgigjkhjN__zG|l zE5Eo&Q!pqxgQfAsU}9G;TpSU+S$pnIlZR(=V2z2Eo(E~oBfS3u{tn=ycAacHVCy>r zOBRA1Ty^ez!v`EV+1s!>Hu1+LZX^0*vcLGDwg}n3sF*aT>^Ubq zix-gvRBs(DxkGxi`3)~hR*V}Ar$i}d)85}%mWy0a37MNGgG~4BRF>S*`MF7(Z0Ap6 zMFE7B7l{S%E`VH3%r7hnEFmH(#<3@t|DD@iI@`bmRIpjCn(g$ikC;lxIf zV}fB&a*7*v`7KkSE^E|`IOcbd1eR6=`6bRms}Emo=;GdiYAwdxL)ViwnMf+i@SXd| z?5kSw^Egqhes%q7RH=IA3jRW^>eP4q(^TU_gT}l3i4#=q_ft`KnpMr|Y}^%ma zgUBFg44P$%B2mT@?GlOcKM4vWg^1of1s#yjS~3MKvO?75HMM=V^thBsnx>a>`|s_b z)X7#xaL06?%$R5ev5~O36ZxLIL%Pf8b1=-jOnjYs15;@q5sv_2iC0YPDHme5zHvS03n1mIgj2L|nlFG@%tQ@-h!0o5>5(c-Jd3cE;U z?()84J3ERDN)lk=T;4{9LVCIBzRR#rLDMpqA3O z3U#wV^uV98Pmy&eJCdk2qu9G7Lj^i+221qqq?^qz#1U2Ir^Yvd>{O8J>LcYu(Y+~C z)3t~?he$&S0Fx-|KIKeIoKsFG-tOr%4)Z6Dx{?BXNMa!s;75AD<0M(TtL7U%LFh+u z^?d725}Fg;;6x)on*kBhljV&esXW5&Fm>A@f0{h?75_TjTEbK}kPdl^RY?>naeolZ zKPY*4QgotBh93u+&fk`VFwv~HFde4+4RpqI&vvznuVj#VXe!BCQA^a)Ix5@=`_Q3a zR@HHNFTN47PXMX=hM$kM)S*8hgS^w~Tx)+sjeWuQMBo^anMIRPaVBQ##klP2>ixhF z2~DjvQni6eFH}^~Tf^rL8f$c6^H)g?gFD5-o%7f*;ExB620zz@R*M2;mbsDKDn70@ z+N^G}XC;1l!k+I*R9oHIZ1I8{fkKe>u?djOwk30x!q-^~t{`yL;?@8NF^a`ZUk$(I zqN^iP>Jfkw=M?uGP$XP8d_*P2oQiCuh2U@4=tkwLO)19DA3T(yoCtJ1>_>imu#Pf_ z_$eDc^qnM`y%8Y+YE$U1)+5~U*jQ7MNv12Rjky*j&@+qHb;$_0ykgYyUxx(fZNV>Poe%Ia8jgO7!D7XZpdz!hv2@xIIv*m%Qv$Xaj zEf7#m$fMhigeB47y}*p>Q;MufM_i`i{2IYjiRe8NolaC)M`$I^#a9zgJUpkv-KijK zw2~b}4s_`!r0M&&>onkdyT(U+N8=qjTEcw-}`xVyKa>3PAfV|R7j~q zN?^73JwN2!($1+OVPj?q-Xnn~(^1j)$mYd{F{ji;kp;Ja>b=0I3=A=sMpu2JT-{w7 zGOx5}zgnlcmQIv%$Y7L;@sNlczpm)0OdJK`W|;iR zIewrhxD%*8kQn{$Nb!lmj6S;BSx(_(x^i^p^4Vo;N*$(}t>}v_ioACSL(d}95hE(s zu(icAMvA^P>bC~@u82ShQ{gA^=FAULLjY+e*U@xd_OwzVr_J!aNw&qaa*0+0o-_Dg z_G6_OQM4?2|Ha|A@6rDhK)ClnoCvNV{#~W4s&(3e=v_`fH0YBy7!^pzWuw%qBULu9 zdqrRNDzhSnsA?%Fsl^TkzM3tHo7a(XM`MY$(G?di=T4v0sR{tZVL+(}(n%ozo^_P; znu`9YvdjB^_L`y=4!Ct=3Bw0m+>A`AwKEF|CUyMAZ%jv&s}O}u+`3!^UKKaRysI4v zQULwKo(+Edt3bETh8d}x%Tz?8iEXs~Xp!1?fIC8zllDI9MD1XDt%_o=&7Ytm3G;Lx z>9o7Z5cVN!DcU0jO^op+)d=wwUWw6O(n(ZlLhwGe5Nf&qsw6PVPmk}cDKc9eAToT0YL+E z0md#B*`9~UBv{R9vLi=k^aI{oD7erJ2J9yJw=_sRueq9a-WB~zzPg|PgTVD8iHIi# zfz7`SWtdmP6Z)^?e@1$&;Tfmt7QgZ7K!ej-N;Nd<wsQm3Sv|l!*B$6bldBta@FE94%$O3t$Bn~tRT=SDm z2N41O1Gh=|uY;;lkrSFX8bj%0iGTQqUclfiNX0}GhQ6>lmmfUe*!_jj9*J|~s`w7p z_zs$Q%NCnM-3Vvy+b-STq#W8uVzdqB-D%^BIfTKSeS3ZB-h1Mu=0Q~lGZV|xn51j4XxWJf*&E+)AV5V@_JVFB1>asr z79y+l)ONlAW|9`B{bw8@vb;4fNB)JE?4!ESkLkc(+C4p%@))EUvM~|JvQY|FtFGN_ zs4WUfF-H8v*AaU{S=CH6oQS5Ly-u*!P*b_+cVd;m0Xj7i_bt>awh>tV378SuOC4O$ z2cbN29?oDPTtJvI-;$tW#RtOO@EY=xNa2`1+*d;@TbT8ndf1f2QlNbj1czw`OYf_M zE%(dDLN*rf2t*e9~J4V|AIdSMxBh`L%cJmNnv?p#B6o!w9GlWWU%ma{qp9Z zyeL!lK`!Ek`Aw;bv5Z@e$S@+(qj6V%t*&UFPMwq_64!Oxi=h0juq$2om-H2YGB|cV zMIeoKMn~r$)bHBtWH#)x$G)&pW5|Bg-TqM*G;(Qk>hY0J=LdAY+kE?S-=fn-OA}{Q zg!tF^Wf4FOxxOw9DuWqd(gv5KpnV7Dn z!+v(h^>&ffm8Vxj!w+RE76n``9jg0RKf=e^B`?}Tj<)Ow+tbz)QE^{12|=-~Hh+xE z%8{Ox_Q`(ub0n+dsYMpLY)9`y!cb^iNJdYb?<1!%I~{#l#gCVC{m3?sosf5z9+a6S zs-z#H6e_YKMS7ZhoTYuP9$BnDT3A24i*2%5s0Xxat$jIGwe7>PPeIydkQT{t?@XkrSZmo{kc_-~P1i=%P05A|&LI9K?&J#Y#O zi5>}p{li?)Ej^ttIU{d25FmE)*kcXO~ z{>aMY0Aqh?s4HoQlFS{>#n4!to~L1wjv;3~jnWk#Rf!-)or@dy9Xe*3!c#QvSpa!O zSsTP?>*U*3AWu1%sHl2ZzT&@eD}C2+55KA3Mc8>*^>hr~Y_Y=+<*L2nlP8(Eq2q1l z(#Q9KC_Z`aboX5VYu9~!<+z557Y*+2m01UnfM6d@i`=kzgFWGN}1-kacW14$8E@Nx=InVwnOGi^o5}Gt%ZA^NcD7-3@LlLIjAxF zuaD7{KCk6NH`CWVwX3zG7bv)Q{GlX`PCuTEPh83;w=mABC;3{!hd7t+X+`}?)8BQ) zXM>sX-z&T`Q3>=3Pqi@jrx8NF#oo9`q~nfR@nvsmN&Rm3xrD&sKFHj}WXfMPZTelC z@!m;$$cgSUJLkg}1J#dtr+8r{1O7`+a)`7Jg!2OK#S6*of&2{I0o1horw#AYp^%p3 z!|miss!nkCg84%e_RC%`lkfL`{m&#QHRFxj0V+R?Ube1#en&%ZXB=)@Oyj7No7&o! z;ztd=5DDFRhSu$x%@22I$2rE`Ht_Nv*oOAf9oN?J>QISch z)Wh{12g0pZcO+pY2nR7uAv@%;o2=P2U+_DE)k`jAGg5x~$wT>|x9;I#7DTosQAS-X zhu$)Sx8D{(d?3~A3?}R8i&JjUOCXKj|DPl1RGPL+f!@kU@g@-tGxiCY zo^);$^9uIw7&JT;Iwo_sGaThQ+KXN z+UQ67JEV=X{hZofxm$QWka1>R=evlF6iVl`G#!5-(Epqfd9w^DuPOfib%5;POemdt zdN60!W3PF<6d_-wrY_r0&&T&dk#*O#=6`H`y=G!i(@Oc<=VFcbx$cGqwmm7s;9cf3 zr)jpG)xNJpYSuFOG}+&X3|O9mS5}n!_h+b|7x`N814R*MW1aQ_uB6yKzeIZ=Xm~Ie zO$2p$&|1&%=rA<7W*KY%c#6UY)CUyI3$YS2Ovs%DnLt=DO;#1rzStfg#=p06$E^JA zeP{glb*Q6kKRv+677t?vgask}fLZO|lY`#Es$ z5RO~5RgdSLtojX(zaVE1iCFyNy@qlH2B?N43zuLXXpxr^8QdV#Cv=LU5MM6GYwhf9 zaJr$yQ3FSs)+Fi~Tr-nDy|%1vdvw>-WgHTbIFw6IAtd{@N|42SF zM-HZ7z)CX<78-u;6!7O@s;3#zb%t&2EnMtXHLiUGS4Ue~&)%y;t{~%N)D@W(Vos&dT(tu8N~)(>4S! zk1P_}==~@*BqdL`4MRS)L^HD^&0a0#X>mobcF0DO*kifzt1AZHNmUNkcJsA!RxqbO zowI|vV+6Oldv1&O_>l~@x_S${0`vV`m*W(afY!3xOnGr7gaBgug*x}C6Gqfr4)C4X zm7ByHWm{Sn*|{W1ov7{Hda$KkAKmvQG5i^P&}z8nu!P>Rhq9UE;&Re=+3S5^o}r31 z%#s3>*KV{rvQUq|KK{KSWW~Z_U3k{U%>No%WN`ir9o7DlYtyts{im7nPy#sLbbWqH zvD}ob6;xwf{lxZtjLy!I)q??QY^Z%IIIRf4v$OdQsA_(+v)r43_*(4Cx~dENtQs7c z*42D-R;X{JR&%R;WvFU#uBH9Gtfo(A5hzb?8$=)4eiKx?d*v%07l)mNPw5SV&poo$ z$IU6k`lD@>%CA&P>qi-2vBj4!+hYGCCM5EtX0&hMCI`zUkspsQ?+&qT1}fNFUbaP8 z+?T*WrzAvYwG;bq+}!Jah!o5cyCDi{H3M?)UKVZbqD>-^DJ-#X#rhV<9D~2(Ofd4&^1FToX&Vsltm1xLxS@(6DNN}7FQm0kFvlUlzz*eC1Mg{z_j|$L zz1m>4L8=KuizDZehjKB4v*CWa$M@7qP#K-@?hdzWfYfI|Ojbm$9aC;+3`S`p^X|LJ+;_JHqG)CYF%k_zYx{i(9RQg4PjNE<>UKN5gx-S+$S^Wb|AkG(RGjGhq%@ zQA`tnVXG++T^UT4qKE)@(uUVjw$%w0WucgZ1=-lk*`_FbcwTH64Myh!yhIi`O@}Rd zQMJN-6=$-nR}`LsG1jyHA28^ow`b!3b2I-$BsB7fj0CUe2yStClM2hjox^o}$J`>^&o)Bql?hh^$jm zFd9@)A3W)@s^)9~GVv`nm<1V7a>6FLkU_AcZooWBw%%etHx>yVAwWWa{IZ(j z$fjmV^B`#&Me1;;&&73>L{X zD8Rfy?>9S(T+)*rTy~}{OXmr}lI55T^L=I%S4JNAV11A}Q#u-%v!<-sTA?VXtNHdG zYE;jnmdS+y^B|Fsg%#;tzS4JVrF+x#Tn3@(ywm9mRmk_nw3oRl7 z=s;7Vz5*u>$&Z$@p76Fu7M|+Wc@l^72OpD3v2=xD0;ph<<;q8M5Scoyun0)+Gt@=> zaEDXm7y^lfEkAY3sDB=5@mUb_eW4# z1RBmyH)&Tmq*EqzLTX1YxVHmlO9N|CirJB+38BtfLd)+TluMxJ!>I!G70FTNyxkwZ z>R~Ntj6fAu0aZwV92KHskWiUVry!l=Ru5Q&O zn#K=MhbE+KW_3TbcxTOICS0zT2&*5VjGh#py9m+22|;+R`sT6Elqod+#mD>TCM41tyCmz7({+p3*Ge-k-A)vn~;J1VPZ^?y8azx z%xi)$GjozX`cX0k$*|qMV9{Bm{5{mr8RUfYUhmdKR+IVd4vDQ~Le4eeBI_q>tpZ7) z05QIeIR}t^EZ~r8lommU<}00-+h~gNP^ZB`KczmL4arT7zkKb$(>r%D-ARSCNyA>gi0f$nBt^e@!pcEm+Ihgbmj z;wX^^exV=f7!CW9yC2xf#>2mxUF-_G*md~?gl1s%1A*aTln5aPilw(lER6wR-2_aL zD*e>7Zc!g<(-u#nfU=Ka`YPHqXwqJ%kS4jHU21w!E4jdhb_tK{=?{5q&K)toMyX9( zGteO~gYN#=ZR%U?w}L_m!ZRXbBoh#iiR0fm5}(qZfwks00t5$jk z0ck^#wn^@>B^s)ywDcWBu6rJq|J4)h2i@Ls7Pk_VsE@_oYmKf-Oew~!5b>xgg21~ZeWhhr7m7*%?;<2n>#Hi(r0hE?_@c{Y4^g&q>Gzo+v%lyPFRkBZ z&?g6xk1LSp<1nlUlvFed;sV?DLxRYo2&;ArIT1pi-w4A+*!IAz@-XWrLz9C;G5?#x z-n3IWgdB)Wz8*DkGi-1`A{bDg1L$tx`g708)WRhI_=AZX;jRXDe30EFb4Wd`I2su) zgrv7-Ld}Gf}tteygcT4+;th1uhJC zUKZpWqh7v+il~6aGx{%YJFu@8N8V+mRHAu(n~JJK=1o3$nh&lhs!lzK#Ms1c??-LL z1Kdu)oZ!Y5u`$jUE{5hq8d$LGT-fn=%;mF4Bi|wMXYAd-Xa@`FyJka>IhoyY$RF{@ zgF><4J0OYopy;@wAy4uEy4YMrq^gBA=WwCr3DldfcFQ^-Ynu8kR5ISbICcwFIGlMa z?ifag&=C;TD!!r^>I)8?0DA$B{`VL7QauDRch=PG#(wp^?4=tOUC`rw&?6LR*)If@ zI&{0+hp-BMn`&8{3aR;x*hoOu%3|(ED83PRhVo@HJ7Ak3&`4fhG!^0%!P)3R8P0YM z)<0++Lk+zJ5(vk^)vD(!4`m4^Zw?IKOhm#qCLt?*#?Jkbqo{MMh}EnyN1kh_Sn>1Q zTeyrN8{qgvVkV9`?l(C;=11oIKu@Ygx=;L;; z4sg;CFf%SdSpc+?->c#!;+x;5{X@9?L!9TrE>%Brzd9|Moqlt$$1NV|=>cs&gvmt0 z8mf_gnTl710WxM2fxEp!C}!3~ki}Ij1m#fj8AzOc)z=>ZNJL6Ept5|aSGEfef@WU0 z!JtMXd6X$X-TqcN@4Ic7F0g5H(HJh-Ft^@OebRC4;-w1Nw5oqnrst{?p99I+1F9ei z99Feg*iqd4PsJ$Z(T%GOR3W(YB9gXTYIg%g>qBKv#7hLHHT<5KcFN!)73XOa%QsPh z6OB426_anHzN$N9?d_4~ACj3=8Jl{BixlGJy)l)r0SCsVzb45|(L4QH&V(f{eZbxX zJvNGJ9dA?A`DO9)7I?H2sJ6&d>S$H(tYdnQviTRyN?w#_LyrTXtLtcQsuUGzMwFR@ ztbq3tki~VUFTRJW-0=v|n1G;QO%WLLd#F>t5X7=45}r&@2L$jB5qR*apP%%a_kiXy zum$JvGX|-V4Ac++)d=~iLe=g8a>T3VZBP27R-O^V7@8N6b64{zgEk3v5~;hc*}rGT zE>yn@nFKpg!0x*Yl?9y+$AId97s|&6-uFF*%r)#rsSfAznonTLH%1}MN2YVLu}MfO z0DKQ39i9wXeT7;jl}IM$L_g!_!8?G74{tp#tazC(K|5q(*2y|{aoKLBg8*Zx zffGh4M7FR9q35vfUh51)E4Y?v$Mbw}O!$tG!BgKa;b@e1NRe~gdv6v8VlP_rnR23s zLD~~6-nzW$__Eh){9>TLEw_4_2m^)x%+a8n|nic&xtr} zl#4y@v*60mULpL?3oHNUdxgwfUs0n65Rop>^YCc8&Zv`tZKaV();kYnW~|GfTCI*U z60=6Z82!rXe9I0A$T-ZRV`rs3xN~C&6yq^u5sp6VxEMJLE>bey!||ek4=-r@ZF#rM z%c|c=z^aKYyJr8FQ_1+3#<}cUw{yFOA}LPNBbd5uTxUPvnS9XshO!a3%#YV9qp&LJ z`;XGW%9HTA4ecVnKlqFfXMFmMzg>~m(Xj0SVd;{1^ZDDde6{0=1j6Rv9AQlM!hWK? z>`Fb--WD@jK0`e|Q5&>Vi)+bT%DPIh27{bSbA)<}a{L#ax;3}74fJ}8O#ZmnL+uy0 zbYFO}R=MqWz2?UE{!t!{EF7QHbPKIIx|RFt|Lv0bbGa*=jt+B})D2P8L2bAvG7iGr zr^oPV+T=;cUShprKDr(&Pb=BFHv&{lHubQgG)Lw^jFd@iA zn9imhouDI-j(Tx0Z5GJI;TF0C1{zZyV@!K9F8YfL=@|j@;>#-j$mGK8f2^6dZtZ`# zE&{8g#-7VYFP_+fio#4rfzlA2Y3l8@2YC~0>hIWFp^Wp=eQt7pp;G~uz3xwm+I#5) z1BgMWK*8g}eiu7m&R#_)!!bp`}Lqf!Wy5OiM84(ra} z`07)rv7@Y~5v6YGLs@|WyeDYC_^>=FRgflYu$S=cp=}m{tTQ28ij^1rJdtGA__9_{ zcIrY>Ye(1PaLdMof$iH4y_3o`7@Y_0!u^vM??^(A-Z7#8p-S3mh_zGijE*3s2}X8z zBJ%5GIRs()JX+!75Uqh?%vd30P-cMeIu1ncOQb?~)qhU2RNip9p82TRnU?8UD0Lc$ z6vT@qRC6<4pgj1PLc*CVTSNk@72gh~Pos7(My z>wiwxw`KH{39s5X7D3D_-_*hUV0PH~vZpDd1??cJG@4>qDCPZLE$XuE!W9CJGJ6=V z-`B34c=DoQVV|rSoj+YpNc-#l$zPY}KJ90(6$)1<=^zqdgS*asqJQIB7wo=RM96^E zP?b>K!dGwc|9I}()1RMlotZ0ikR75fQmWViG(8DY)>(G0j+Jeuxi(Akcm#kFA}w6N zkwT|x7gh{P95(sssrs$!#+nm^i=P8@<#UBn)^6^nbtYw;dlq?iy;K9h{#hDDB4p-l zo+6}te~|sYVHEnMSbOL~afHfK9>T3hTfpEDRA{yAtU0`$Z7mgNWz23XLmjUCplq_h zd*zoeLkEZy1r(lPuen_VYM6TVoKe6Jo(YO5>;%((ycoOMw-0kGJ-*Tf1o^v(3!vqzuUn z5K#v3S3bsUuwEKcS#(n|e+{$<9>*4J);?f+(=2o%QOM7^UXmb<1$EoBf=8Pvh#VN_ zGH9iRp%f`yE89>h5s;J?0T8?u_-yL>J^V3IQN+gE1PKGG++ACi6J4)%WKL8*b_8Nc zY1pk@_-15L53STo*(Ra5?3T`B5eVTybu5$o$-e&xs!X1v4=4O{xyV zJoSa*5rCV#hcGZLBLG>u9v3ieJi6=oB=1YvH-GcIkIMbCQS7*;w)hHsf&U_s(Ws(V zE8v_6cL9Oa%91(7ILNCmyacTsp8gxkmaoX&FE42zL66R6!T24=K?diO7#jA1%eVoM)_U8i3^tyay9ip@@jdXJtwG#6Iddl)$_B5G=~4XN6kN8 zj)S@dJsJj~gvqYB6#1u8`uEJibqdW^frPx-A&wxC_oPf)S=*=k?Ty3y<_G}a0T+DSdMuK;sCVUKoY=-8-zdS0M)v@F&0h0}ZFf2`^6 z_*~&t%~f!_RAYUM1`3qPj^@2MrDk)@yuTF2*+$-IP6!X2uZGb=`b1+2;XIl0q-)& z*BO(ak5`qjN31otqw1vcl*$1^S0noAYW~5@0I3j2AHL(^@pCQjH%xRUK9F}s9I@GW zTa){IdE$)=sQ#Kx3ak`BpDcB3mi!{^(Rc2`HonYaOiFpSq@T5Y??cmyl z9Bdu3T#r-#A7wE|e1{-8DZ&0{_mEA4MfV(5ks6fDE&kGtnLHAa9)TPzxchdQKwpPq z6C8Qr-L_499Tu$a)u$r$gWT5!+$wumm>I0(R`H5IFHop(X7-k$?Utsv@Q*q70vf^; z=Cw!E_tDrh7POV_?XQ;s@Qz!r{>pC7+e<3T$By0<0$7C6+(Q;zdB9fI2cQ=~X9^tG zeiztQUH-z$yVMKz$O3h`*fryl$ zN({)@%gj@%0*2)pwn}+$J1aY-d@=BSe{7jB4z+{zl)#PpG~iEU8)Q*A>!3zj*<}M* z+HX+~jQU!_m5y33@W{?*Q>6=%m0}E}dRZWYT{PjWEZkP1V)3@q(VNY0Vf`VlVl^a` zQN90ffkp}U-8QalM01Cs3?u?TvgFF9!9ocLy@fmNLL+^O6PqE$CUhEd*zSu`lm?!< z>`(=RCP#E2vsq_S^~n@xH38gm!HJ#hP{1`SlPlqGgN<8otr#Zn!`gE~K=$j*kWVPb z2)5}2%Odv*6DGZTy&wiq@)yJ17Ga*93ft4+g0zJBG;=BzbG!aPRTq_1VKO_G?rtM+ zOhT%1xC~#Mo^1+jPU?>J!ERWx#ZYQD6X{-VWTS2=DkE^OR_S8YVeS@q1q))dWI)c< zkQi6(Hk`&a)7BcZWp7)o%F$!o`CDLubjPJWVD`d&w~7U4h`r2dUp5~9+xTF=P+$+E zE%9|Cq>gTwb@%idM&%Ws7v{qlEIlxfDdlN+?MiBwX|5DQ+YU-(0tj3*m-VLzq=y9Q za2Z4)65eu2Eam!hQkgHtok_G9BEjG&kZ#q3kdoqaJ=a1zY?#a5>|8oaFtW0(_J3;J ziw#v4gaJN5OFkQ=*IT0Be31{+EbV4HC%dy5RAzEPwWoW<`jC$WSEob18!WZgj@>Y) zc?rp#!W8Db%DdX{1n+CQHGo}O0^NS-RZt0uR^i6$!S*EQ=SaAD5khf3vX_r!=|!-9 zZZMdP>Jc#9x~l(H$oMT45B7{V^tY>yHY{-F`mMzdR*1&;gRoyx@Lvy`K4W1hE$-v} z;|+?V*7w^ZFMr{-<8x@9d^L8V-st59XbNvbc?g<~AbRvB8klwzD z4YxY}CuDTKX5L^E%1Q+Q<_tH72Y^rjrn{tFcwm=YuZJQJq3wt;OA6%bi>!CM^LXcY z2>gjTSEf&jdI+Yr&bqFuD%a?H?t-nY6}gVz7$yPLO;X)iu*vAS8Y@Pr6|W{Vm5bQU zovxb9K^C|=z^)G7wTs{y_7Vw4cbI0IGr0;LTrewy5yi+)q2`k=ido2fEk&-s(35Oj z$Q@&zLBoD6ISmG|3<7ELDs2nAhM|5re8^aSFM)u4%(ew6jsavw0WcNrVJoimga|w# zVp4N+sL#@G7ef|hb^OkQH85Q0I3sLOLknNI4KsAU2MfwSK)3sP4k~%_{#tk5~iohJsaR;YRQFIJuTaS zDupnagkgSGNsAGz*b3$<>6me%z$}Cz##5~0Qy>*|n1#^VbAsJ;44|~w+U`%gJ>^po zVsz+Bk!~)icH*A-GV=xdf6TaGc3f_zRWRE(xB$7EiQL_F2zITs;<^s(*qQ3%w~KS$ zk*^D%R!ro|5sdP5xco!6|EO@udfe_fR&8g9S#KyCwuh;r*0~NSeJtXp5qIyN(|yK|Zy3Xj_vC)m;7aQSv-JSX z|6}M(+@Wg2I6O0E%$bd2Ut{cJ$xf1GHv2YY-x_O_%34~@jKL5ZJEcN)Dx^ZHu@$0_ ziWXT5ZD{#aGN1DooO3wH*oQLCy}QtP z{mr@;W}fzJsHQ2+3n~HeV@0uexIhE?TPANR4?<^2Lj|_`Q|P2L8>TRX*@Z^!bhhMq zJ=#-Xw+^t>kF6KS%61I$Re*kpS!TzTs3$PxFoDDJz@Ab|X1xvzKzK_F9+n0c6a3uG zhYAwGD6eKXjiKNQ;n66m9X6@0Z(?>{U^fncyg%+GdGqp&h63uF<*US;U}Q8T`SvTp ziuZY(fYd?8+1vBErO$4RLBI|Op=^Lv&rAnXZ-I07mZ3a)MbE{8CrO+Vw8-}m*3=t+ z7VS={<)sv^U#fJIvv%gE>1pPefB}Db8mk5v6Z~2Fa6K0(=~{$$MH)+5u$~EElW*F@ zL2&i*Z2|d%Iyn5%7UVvTd?{1Dltmz%Paz6aM$NDow^C*Y2+SS)BO_So{h9N zRW7hRCk|ANqU8hvU@V*!g*D6QP?oXUz)8fkTOS){*9;SHNI7E-|3*EK<PLr%xi z%g>LzbNN;r99Yeaq8t8YG!TSYW6YzvILHI09F6&h`&NXG7p7;icj0ks3=A!dGE+-A z%8{pO$oQ__SYzUJ?J_EK%}ei3&r_Macg)#qpOc@m7->Q}QURNf1ERQLEr|CYa*}d) zq@m0qQ;z5$Q~Vh7XvoeN3$o|cKYXo4&T_tNe@TscbIjybtj&jX-q+lYIQef`d81i> zHs2sMS-&2=&zsFswv!jf<3*?LgkeN>^9l`1N4Mhum9c(td{C|W!I=&}F-d{Fc!{&& zwSF&QuHj8pYH+eW+_C~5k2>tpp@`vUOr)lzK;o`@G1qvg-ZDr~w8ILricv9Y8oU z=Kgld#ymUD!+*P1`e0>YAW!k@oaEOO;`2%hB+jSD+3r6n)T<()>@vQNx!&ndEc>4x zC4rF89wxnK-*!g+W%@qN!Z9fZVwww=HQAdOwWhUbZ_aja= zR;m4W{BPJ&YQ@2s*~g8hA1i8?mez#GgNGdT*|wiI&y8$KZLek>)CvelD_4>7=CQp7 zzgOol+^p7l+?l=n^Ft?xyHb`(w}##@ z@zqRw^aZb&aYLR!_PR z=FUl9u1oRWNc5q+sIeT|)XU`P{zZL{9vYrMPX2wY^g1hj`^%pUP4NcT%koJh4G9N( zEOt5B$Bb9eRVj7byLJx}RRj>C67u?+Jm&r@-Zw*&fXW_gfZq{mV&9{LK!xl;Ga24t z%oZW-<`;~g1Av6e_CV~X7CTo7esI**+A}JulV!OT#+-jYpJG;sUCM01=cejrcj!m4 z`>mxBDAN&l8b>&F|Hbea!iSLJl%^A|q-!kAPDKdDZdn zU1#)fQ^$?4LK6SJE&WKTaFuMn_?-w7L>6la-;C?=fzO{HuN}IBM*v@5eQM^4b(1!I z=X!Tfh4dnDc>UO4V}M@i+6DBp%X`>3;deBUj(B&w6kx>(7P=bJz5FP~(uFXLW;3rB zttrh`$`C{;^;^4brM~t`>`r$lwMR1_#kc(v%aD;zivZ$fcbK1~JKTv&q-t9Hm4Jwf zp1d53KjEOPyLn=-cAfN3E*u75^Yo-?%0yD=AqeP6@1mMKAHIETZSrA9I8-3o|27j5 z|4*P7p-Nx73J5_>D-O)zDpN`6R@G#T7GHdj37FAmp`knOYmyz2T3aHblN{M^t<>8B z!#mKK$+L7W_S(gKP*B?z#?wN#hR5I-+GpYHi$|%?2 z@yG?+qaAZ%7oPqK=gK3d8<9nPn)1+XerZp7>4IZ;u=lTbrZ0ULW#Kadr}C7qkvRWU zq!aaY%qhV}Z^tSET(BYBhsi5V-{^vIV<4b97E1!~iEN4xiR-H+COpnvx4u*hQN|W9 zKa7RTMneUq8_Ww4at4RQ--t(y6#LsI2eKbqr-`>`DVZivFOw>_mbo_`q8cty@>Mgv z?jq)NW~9T+sA?DXsm+VE?&7cbj~Vs1$X&S<^pX9w!zr(`iGojtun-F3QQxf3_g)VS zcG^my2qRwZN`1f><@E$vc%6|DBbRdwqN-($l`*9bs&H{(uW@B**)q~&algRA0ht!r za5-CND=J69RB91WR5Qsbif!U~jA^R{No1%vh@H=Dt=V%wBls9^j;4s1wtr(SZ}aI9 z-qY5>o|0|f%dx%7*j3wkH}kASS8P@E3lFEtCg@r3lNC_G98_^EDOvCJSj8DXuYT(^ z^B?6i;0O4+S1n8lE_Okx-CBqUUsfzf1!hoh!(<05VsS&x6lqwKdf-$1yq3MB{ztBt zB|P%z*f<5NgfbrC_ka%h>rH0}+0h>?lW2iSl z5z*?NlASS|!e)g~p{S`4p}!2^N+4OZM-`!El8*|Ug~`<7(>1qyoNt(j$?&5-SbOB5 z)Vrdg{J<52_l;x;vkGlF!8j_qQR-1jy#U3$ReZ{saaUG;L@8DWs7jm=*i3>SJpo6f zE!Lp&$qYDQ5Q6@ER}9xeVC+MY(5^&YF4h%rWArwePq0zj*NiPHi%IRX>Gr1VL>#n1 zHMp&lJ_HwAuX1o<-Olovaot;Y4=10z0_K{A9}+#u#w+9jAA-m#^_v+Q9^+gWi|{f& zan(9jDUYJRu0&i8EuC%GO>G`3m))E0je|8S$xxH`wGL=4ei!b9*sG{WlWMoU?_vzjUu~lt5Ah_wxk|>-6@omog_v9l|`OR2t4(8(;hLprbJhjQcm>e9(a96i9>*^ zpyM*h4CPur!G=W3%ThBp(wI;c+<#LOeTDGL^mPn?Q=DKl-B8n+SO$EDi^Vj8lQe|a zj{0EQpdM_Po7AQqaNHwR%6RZb?9W#g17nXo*K2b2M1^66#8b_GeNjr@%0Rw8UxY9H ziQjZ`CWX`4Sq8=$t7q(Op3M@|2eA<{W%ANmWj!o?YV*8-l6GyywbuilH8n|tFU&*b zq-;$z_MKtdo+|_1OOi{4*V%;hL!MFUMx7IrfUaTO=w&QX@4(+-AAZMBK~l&wtzpV% z)Nn*mhGVz@D$1wuMCePeChEIz7B1pXSa$~id+Ll zk<^*ipSjYTNI_{|8g$#MS5QVi>}NhqOyVV8>@19;qr+b@;$Q@FbveSW!<|Ne5>Q$^ z@x+idofA`>HTf^&y8OCmxC`pzt)hA^@yz!r@qqKyQ4->4dRZrh6r7_k|(LI zIiEuR6;bwL@b22|obPufp}OZgTddsI>C#SX&rt(+Ei?m_XLNp4e$#oGGV~?o?Uu-e z4!E-FI^fX$0Bj@x(Ux%-PYzkU!`?>AlzHA|2Mj(n(x0YT-i11BRiXh9h~~q2xheWV z4l`%xts6;RR~WCg<~b$hN57xB+v0^-lkk1@(GTpB2+tEZe=SAP7$($C{DK%7LE7tU zrui?Wh&td;_o={f5uTLI%Osuhnvnhl5~(&sGIE+@$Ha6bUsM^~$$CMR`kD57;hG`m z!?d?-HD`lcOsH$5 z0wa_Cd4333sa=~Fg+lKWQMVItmb#@DbTaLgmp-FBQN}x*c-$`y^>zSLz2jx43Xd>^ zvLW(4?v}SjSkl;6w|RiY2 z==~(Y()kfcNQP-AlS$G=)XiCAnfG~_y~v6pRXGAFv4)=7Wn zO|X+#O*<35bJKbwDcN7KIPj&b~Na=;VQa5~cYa#LCM^K0M5o zP9r7uER1qEaqN%w@K%tuTv4IY!F^nmtE37eW{JAeX1vy*^=ehvm0XO!jYt_6X9X9Q zW$zHw*Jb*3%;9|eA{A|XfJA)r-SYj`Ji=& zgz33=*2|E<(E!TY`QKxUZnf_eMh_@N^D6eT&CRI{E^*h5#rL}e*-dI<1xp#$)93fy&qZcu*247<( z$W|Lr{?5M4N)r2nC0tP_+|RUs2XKkK6HHNcArU3wEU9@0uf9pJk4sY37pq7=l-;;? zP@Mz5rI?djORmO{5dRWVvX21AT|z6;(}j1=41RwzoU%2VkQnr54w1S{d<9KE5F1j_ ztr(Eh|3-rCejLDH*#VwqBx;oR2n5^=@g9jJCBL@r#%7qJY-bB?L9!AJ|9CHT#1iiF zVbGdeL$c4Kyj4%w?u$>)(0K!cuatg6il0v#WyH*C~yO&tGoEyS01A zd|`hbTP|4RR2haVn$>lD?b)?8;XE*7oyfwhJ5s7yghj$P8Mwz%Xux)=t)WJq7278k z(I^RV>>bKCiT2@!Q7`Vi%Q7jYcf7l$ZYyq!YW1#0q5Uk=Ec_M3$wQVpjb z0aOxu5M55UlW!t%Aru_#RZDcOM5s8&OA2_l&yhVFl1~YA(h%u&u8i8T4a5fzOnzp% zW=hD%GRJMz#HKw-Iv<@!^X&;_k|$YH^=eLUlL>0h+QMgJH_Y>2-vwJ)Z`DhQD~L1O zeP!Y?28JOIm20O@`G}b|n5sbx%%hWMQDMQ5K6CiZZ5zANOF<57+309WRC9Qw4Lc+o z6T=W;b2!P41B;ib*u#|i&#o;%k7e$gMXHpA5QXM0L#Pl~D)u__B=&VSe##j$lP;&T zNG|RfgB>C1f1<>aev~#*bixy5sgtHuHPx#pW}^53=RQ(qn*uIB(CiYU*AJju`_{Yo!Un61Bbe>`_cFJ|}O@=spq2pWK z7-atjyY<&qNM(%cCeg;S*sFe}vdmUI8yenelRuVzBsO1ut*87c4dH>;^iNCJafIG( zpo|>#oTuTY?K$ZeZ)=e!OP^~_b0O`pZRU#;6?-oMrU z2K&~gcR7CRHtx-rji{rG*44zwYDi?Vz08RfS9s6%uenMWQnbZOajeadBo#v?iLX6N z9}c6$#F9p!fDBx5ge2cVdM2weW#K}C7~;eH@dsil_9VfK3_S^U=ToS%j)s~nRV6W= z60`AAJrRAFx)?aH-qo^!Q|BA`e|yzZSEk?aBX`JPI~7WG6AunSWTyqvLnu)Uq`X05 zRDY3oWJ*_cCkp7zhR{l%A%P{aFhmp^UA)pScQCC#!lwwN}u3T-At*?Tcxq{6atwb5A#1COF5&V{(brWACjIc zSRI5AX?t?oAMvaC<11{l<}-hBbQq#zwcD3?-`H`hpD4?`hF-?auCjyTcnPZ6Zt>rc zQ|I48Z&TW(uyorN^{3YDk#^FDYqBHJ;m0X(riWBN?F3vLd`Ss^ZA}}GG5(oh`qR4k zyMxlleUFc3+iLUgC6dIGnbcUQQUX&d`Dd)gkspO1R^$c6H-6*yjhEZ0YWI?MP1OWl z9I+1UDL8K9T5+)c+(4qiH`lF}1NR05nvwqHiB7Wpmzzs;`F%1&S8a`d1r6S1fJQE% z47ZCra~uYsW2<`*@$Zx%i9L)@)*oU`w1co_s0P6@aBRE=rkpDYWu z`CjPp4MQkH+7nh?Z{$Rg2rSe<=r{9rlIMo<&KP~)Nj=sVsWZ%s0w=m)gSPO8jg8yX zj-fhJmFm-_izjYAKJ^h^Hi{8ELp-+~E_*#s_8sq{3|mhQ{$NncC5tCl%%E2gAxS*? z$9|N4#I6rPY-R77cBx<6sWn_v=PYN6K9d&Uk0&!1%!JYp_t$;9K;bo0^oL}qO$A$h zGFuHfQ=iEj&OGQsAAf^>K*b>r%CvUH> zd~B&2I4^B<=q-mU_V@yxk|poZRy|Ze*e@Ag)mHPQL_cg;l_Qu>Bxgsiz8!iVaXv+7 zdx^L#VDFYOkjt9v&un;J>r&*XR;F=*XJJ}*=-u$otJ#u<;#Mn;zpmN2T-=V6t?@3h zV@E$n7v7`ozuu;+L~0ubG-e($+{gx6sWzz8ZHRQ5p{YJ8I2SdX(^XvQ;^L?B-(vsJ z_{=ji%Y!?U?)J#SPS>VtsAtsq%9|;T3WMj%4%NnBx?~4`9QZbqpj0Dq#b_?z_AP6V zjpe=L*0$Mrkv|zPDqbuq9tqncQ}}3(WqXjqpV>ZEsO{Q_uJQro6M}x03?5@IM&Z55 zzTftj+;pF|J}~e({~{@DOXW$>mL^r;aI=hR04sM$c}(+0c}Cvp9>hV1$dc(vyEC9+ zKT54)Df(vVa~b(*wQggV1h6fqS~H525bDeEKLyIPRL?9 zsyECW>qZrpsh0o;Yly}DQ4Vodx``+?J_GiFSXe&w>fCb|yRkAKT(w;$f2wW7x+j*R zpbua21+h-YPtwrAX%gZj3Ur($I<(iXn0;0#u_6!d$9Y?gfcgZVk^d7t&WROGR6egG zR0v$!p+YSY6Y>vY^&eq9vyUT&_!ITDFq}WxSKwbEEGBQg?Go|fJfe(!8$6BHYa7m@ zwWP|6EBf=pZ9mymvmKN(5tU}3l8&L_A?0)bj8x7UZ6LE#9<-yK4LBC8K@AR&*lWGw z;sl~}u;yceWMjaFo+Z>Sr}y)anvz}}cqzOUK4ci&jA)1-B9vh5O72VMrRL^`%T`|} zO=KRXxhAW6yf=Je|NVmT3s12!!@k+y7YrWg-#SnF4*UBoh)2BEfW=An%ie(f!`M*y zXaj_81OVSb6AgLX)Nb?q(xUw!a<^EUpkd(WSHnX4KDQ$I-(%}g%&M$lX${q<){D-` zV;t>Mzuc7lNL7#TJpaP~C#-aipD;3v@Ds~5o9=#Blmh!5f2(fesWw9O=1BA8fDDwr z6LlM__{RE|t`R^*n&crUlxPDQOxY3})6?T|7JT{ej~4fns?zCK%pmQU*_KE}XQcw1 zhK|gK{!5-$iCxRe;KKfae{OppiLjMtl0WrSCBRnP54_iJOdgr#@A#2SVG*h4eEQnW z!DjdoCisIgn)ue9bO1j7P}9N)INB%su=-1GPgV6 zt(d*MpvMh%;)3E!Uqzo&bLUf*36{|ny(Err|9;Q09pg=e{g0o*(-5Xfdg$PatY{k3 zvjQs$lFiKG748;lSYD$cq*Z9rVE%em-bK?F z6nxr9%?YIzo5t^Q|3boFX6|1~R2Dk>H8u?X`vcqjkFfskI%h&W9P{5VvLoM9JC@H) zRR|8ju%;T$aGm9SyiK@|^Ner-l{REi2IImYBN1_u8)(F0R-CZ|hSdO*I|ljgXOxxj zZ8a3#saKozU%DU8vvs~6v``!RVK6|fomRL6Ms_U6|oKD38^MC z)={lhl-UV;FtLBMU19Ijc%gFg7nv%nJO472Vzs&S$(Hmz;u`bGX58x4=k2;Hf+jR? zuFzEf*<=!fB(gfjg`<2hFxW@*#BfS@2nrLz1bw*z0aPXw27PQ@C6fQ`=*vCuA)NFl z>8nAq{Ur~oOZ>s6VCIi@httgi%?gO;sZ)=n*Tn3bCVaW;@=pAk-!9T=L}(QkOLlqt zX;Ryl1iBVeuO2H<@DRzLt!o61{EVYk;o?Bcz@o6bn=QDwWqXGQY~&Ov)gLkOwvcTH z%qiJlSm|<1A0Y}~E+q?Wld`^Kg^L1E70zn8li0Yn)t&0ne)#cBorHOd9{*=?uEVWJ z+n4zNY;GBr&RK;K`lj`*2EU$C{m^)wEZH>G(EK1UZ$GZu&nq*JWZ!BLMA#GAC;iAU z-JruW4nAP_bCpQ@D@;jfG2*XXxwLuD2DAjm zqR6OT^Fj-IeD$@%l-IH%wtUKS)su#l<`GHl|B6EI@{5yt#!{~YW1N*v7zFQ*JPN*1 zO`9Iq7c97Z9UJxItApe2L7y|UxBMxtx^!hGiGB+|b4QYdAV2l{96G!B2KeLX zBvhjy!4=R%-v3w|b>`zGvFyl1f~;uvN$=g{pFLsZb7mE`ChLs){XRdU0$5eV8U5)t^{HyJi z)Z+1!U4yO6AA{1N5x;EuwLZM=GkA07=AH77_V%N){VVPo951sxK;YK#<_iIP>;|FV zu5E{X7CNb=h9#lw%GWlnYzGaG8n~G|gr)O&kN9)hj{n6ZF62!tZ#xx3w^Kg*YAdul zLV>a9686U^^zRcbFp+9b{y>qU$WgHM9;rI~TB+sm9|LN-`2TTVD4!!$_5?roK=sbK3 z)UFGk7vGIC!1M4%UyqB_6yY%GLV;;Q^g2*}F^*3^dt(56$UDk!K^rX^PH}PZd(Hus zhU`>P?c$`{EGZ||WcfUS-wSwKCHR&RIHm?t)`ZRRV4H}zBGLS(2yFju3(r&HsVDEjeS_68_WZWf7QOrSg|QAjifMZcYL&9IpJxoyuvglR{vqs4 zZ-ePcpu3O!-quu!9)}{fh^?2u+8wrR9{o^HRN<^ACPeV^##w}t>qiyvUB$V%|17K$ zM4gXgKi`G%^^v=2(Bw*Y)p73{xPri(0C_A7<1Vl}HVy{GxDr5g2?LcZuKXW^zXm8q zxGYtoia&-U*4@R#E(kD#uWM+BelWKTRgs=EBGemB5OJ#|n9w^$)iey%#&6$}ZSEjS z-Wcfl2-20+`TG7v>})Bf)jPZppm9t_Derm&pk7Fy%mDo%@y2YCQLf=O)Ka}C6h4<7 z=&l$x7C4p+HmfA#_^}Y-CH!6x&gZ2cD+TxPa$w^p1jaM=x#tRmpsrRFt|oiC8=^1F zGU5#k5~+H!Q%u?tSUd<$@-CG5X0xxcU}ZfqB5uM4(bFeXJeHShQyvGK70K0YVgL9)r4#^)9kMyF#$j8(^A zL{P*k6ZDO>L9CyHK~;8fwca9x(0jyMBEgHiLU;&jS^AR45b)mXl2bIwZv#a;i7M7N z_#CC&SYi6`7YCII-lRq1l#0)kW+E$buu9yOC@zdyYypcDoY2hOWFZUyCst|(8#K#9 zzT;EDdo%~b1aXZ?e>hZKP92P&6;x|5kDE^um@|~B#8P}kdGv4;xlEu3QoI62*%u1N znG;PxBZw+;9b#8@F}(GnZ$5Ylak#~_h_MNjFmj_pPF}ssY_N;LFe9(WXPRf6(B!a& ze+xg&WKA&&q3SyYMB5u);}?P^>%wNzDo^vo4A|EM^R7tb!J2Es0A%0YBJbzx>+67ZV*a zE`g4mF+)&Fy8LKJ;*g;;pmh4qoZ?pjoMvN?b|Y?*SpW2QfYEadG7hcAuR1lo_dKwvlYN2eqn{vuy#NhitWkxaFcBtOyzB-LX>JeKGO+Q10ibBHr}jhj$d@$W5p!S6{uH29qQTMVN~^MuQ!lelpr% zw`?;2y#zBrU7%GK&|76MC0?jNNgqN*DO~`11R`2UXwrc!E$^Lc$GKC5R?p92=gLnF z9jegRw*4p)kO{u}F3$p!xZurw<3hmtPR&gsX9Z8Tpxa}wB*$U@PD@x#T2vrRU?d2N z2SL(mZU)3bPJ=oOy-g3Wx*9wJ$++bxz}jHnT*IVu1*)PWqb1`*F%hx`txl+-dtGYX z%-k1?-7qDDPAr3uN8CD5&R@Ix^;*3EU+KCKvmRD??);nUPUKsH^Btc9z)V#w)Ah@O zOysHW9lAY2-)LkQ6BWin+U^4{%1Pg0Xk5K5VO1DZtPS35D!}RAmU|`3sM2dY1;U&% zY7$%Oh?r|HpfD0{fl#|osYql~B<9JT!-qj^hnh!2Z})Fu77cIR0QYqyX?S5&{|cLi zs@z|zlY3#Cmhjh+-Ly+x z=BQNqh@t`glEfW}o^GMaOV3)>{N}jN|8-^)h%j>*Sr^8Pahh zLY1{2>+h(9iP$~{Z}MZMX0^e6Z|kh2>S3g-OK&oAvPDgqV#z#U>Y&)`0_3TR$^8R| zTJRcteTvm?(bB`u_*|h2eu_RtKn3^6euCNl%kB8N_P?#>?IY%p^WnF3#ykEB@1k|n z!gD--6krU*3+bvyYQi6GJ<+}n-Z=@1nf1miF;%+3$(w7<+ELggrFS}e^JXTT8IPoXBSRn*e)yLWwwfW=`2c8jiZ9|{@>7gxX0Gr-1mU!Ed>xDj*SyRm}K zXaUk&()cdi#t!xQ_Tg^hdrjkeW($N_#pu>o-xe|+pxTO5yIs@{EP=f zbU`0^nF)QX_I#gqXE2Bhf?n3U*V2d2f>!k8xAN)&GU9K+TtU*iQ$K@d5D|VJ3kBIS z-l9@uer_UKWaiNbpp*kDUH5bT_|8;G-YU7NyrNEEeDppIYqEdmH#;WtZI2d!<0r3b z#_f(ZRHj#1zE%my{Ka0WK6dFS=2A?DoXCe&{SQ+;=lI;K5p#-NjGGsqf>15vST(TH zw27?&R``MBwXtszV8V!me3!_cnJFZ+^3uRWp2Cbno!@)i73omrXr+D(Q^hRaDEiTJ z&CSISOVJG5^J={)?yQLS*ZnViz{?=Ix&=KgDeAo?wD|^X8ZTA$jBk0VHkgiaSb({Yg!@0g`wG?gf2>TY1;>fBNH6_Ka=)e0Pt{)S)o{HOz}Rz(S}=lpl?6Y>D) zb@o~5`L#R)Y;W+KP~``#NDq-DaFh9HFC<8$^(`z;fInLh6DZQi*uVjYH4gkID#uK` zuyN|@M)LdrB-WdX<{8C8KdxyUjt{X@d7g+b_NMjl}9^ zs}w(h;4WVkb*WKxYPRg_%qNJ|2i!1Iei=SOv*`g8t)&IsB+CF^{pwL<1R@D^$%`569x&LFo1$$JB=1 zE{1OZHIALM-syk_$pS-lPe^-q8+18vMMi1_WN@Lz#!C$;p8TFaJ{a%ofdgHC485JF zt;70)uMBK9R(LVX>mRtF&|jV;@F#0-JrTM#(|PvaHljQ}=20r_g@Q3VZ@!Nspx0Ii zRjuK21^DHKMR~FvDQ|d3R0a>v)|Kr=TofAFcutsXaC4L({J2W1xX5Rd=Ve}qeoaX& ze?&cHxcRwOohfSJb>8!(*FfaS-7lZ~eD5mlHgsfqWimeKIbzS$Z_?5*-sx?W167aZjUXzLg33(1d=!M-#;oAgXQtGalJI_q zMCv8S^*6F_u{<60sIR=8R?JG$oi2#Fn)Te!k}3#5P?~?7uGuHzmv4)2Z11}vMr&7z zc)Xtw{pk^t*XOj0_4M>d#p9)kZ4N3Q|5T;H>nskpWPkp9P+AW2NADU`Q??$iHpU_Y zijmUuSFIr-nQ0L7H-g4Oe0Ky@=RfhhyM^HeM;c1Ej8R&Y%RAsQGg`P3LL56SyIj=r z!6^M%%0$m$yt8Xhzp6c7DZauhcxXxS08AUXi`6T4v*NfR`PoDv`F9-~CC`1Ks_W*(`q$_8QG+u3e3OLs+>gfSeESD=rNYtSgN7SQ4{D zYTXUA7*%@}$RdVI1v4k^=iR=n&l**G^XvYR`dPrmf%~I+K}^pJp=@XOg^@Vkl6}ru z@5Oz1sGY;{AFMX~al=swwcYz9m%|Fz`ZzFv8^KcwFOvB6P&+~&l_Aflj}# z*{R`bYUE)}D`w*Fc(>fkpC1*c^Zi^Od)50#;5!>r)sDRy-20KvdZbbwniU`+9A3c6 zt1Xk4kcxU$psEqo%H-|>uW9p{C*R0dA*#}tlg-{0PtboRirnsw*WP0F4m__(sI>YM zebLJJ$gipUa!ZGpw&VT(WuF@M!Mo^YX4Rc@bI#;WotuYm6u?t1iQj&nrT1-V^_On! zv9UR`^(>d(Pe)do_C{K+P`++dr@Gc4nwZigpXEGu+SgqCrB9#D;g z?S-mkxu18Z4M0ik#@wR@vK%|H`es$7_GY*Zb%(K==Vyo*VrXtlrCcnf2d= zd2ub3?7`GyfxT6%$@%>&4y8`VThWf}P>E_@mKS|J%Zmroes$WxL_ahqg>y}wPkj6z zOiH0p)d7FP-D6(&C)KLvo8oGK;u7#(IG}z>;?%MmbX!EHShWI{KP`V6txV)jwz|OA zd&KcQHON11c!g8%1g=Wzy=HP!5$hEvgiaQp{_V32&l~shDhvrl&>Udpg$^YZ`#kyOMQ`cUVZ%h?_AH^ zMEjVtk1bI8XF@RlwvdNeAplD``jw>a#0Zi82UKG*_B_heaw(legy|+_n%<7SRqUyy zE%O_@hbUlwvD~Pd>7J(j;|EW;Xf0^>T)5@cHu3j7Q0?F)(LEg`ZY&;~)obkLg_yYO zH~3BOmi;nudzzM6OsPW5`8GWepyj^qmBjyRaH>}>F(k0n)We7Z#&l81LI|?5uXYr@ zDJl)JWks6B4$|$wx=c)cl{X@`jI9;1TU1pHO#;}D~Kzv{dvtx=hu9hCRI zPgzrbpowaX;P=ejvY^#>RvpBk$it^4sp%+@*h7=^cMGEgU(;2$`VcUOes^mS0xi=9w&&ZgM@57Ksk;H}@NpKzbD?En zG1|89xa=kx-uClFK{$nPq-QZLH6$RCqpiMA@9!{KqHR`>WY{-3q!neOo#uE=cDi0r7ZZBHCt7FMveIK+1k%tvK}JpOA5uZT zZG!200*@b=3;n)c(G%(tO3 zJ!`vd(=X-4_s5@YH%YXe?_=o?`QmdQ0VcNxSY{K%MA-NTzmb4k#baScb20v>3bXTu zp1vC5*S0;xWv=pnM|R?W75%in^BJ9*K}fc8ICM1M5Uj9B+Y@mGbIh!=>dV*{HPGrq z7C!_CTK=tgR)Ld$W4W5dUnrTtAUgVT@@!p5$`h)CNu$@VXFI>15GZ?zGn{822^Uph znlDcBMT}9b@^TrAA;IIZER){k6Sk&?NR;k$0xIbfPI$8!u|d?(wlMOYDY$Z_tY9=$ zUghf6lQ?|k*RosTlCdsW|ITFn+g;uGnWqv)pSDH)3ll+2{BzlF2ZIt9-V){FyoDmy zzNTb{3tE9)L>(HFRdHP4^4{kA{PnW24ylLViimua=eV`Z})ri|uysmU?CfQFMeuWsm;u7m<5i$nWmC8!p+zqiR$Pzb#O8 zZkh)&D0xF!WFN&OKG;bdIs0zlmbHo^y$2aS`!(w134H0*mqdMHmKnBR#1PMT4YM>y zwcP@5rwl?$WjXNh`*1d7D)qj}pKklt<{k@r@6PLiLpqc{+<&rw=KcsH1+KeP!Mb1)=RR+=-S%@HMDXL9jTn`9;@9b03OtJ(FCt-0=kO~$o-ndJ@LDIKjTr3@w>VicPi zR>6c4kWpjUN&{Y@{e2d`KrmU8IS8?J8pKvW(sz;?LzLBMKf`T&Z!t5{{Qbd3 zijMXp5o}KhK*j7eVu93$_!iN<)DQd7t(CU2s%*3R+~WHF4lS%o^Su^ja+5tp<}?Jo zIfSeSN~H1oyUE!d5F<|N{t$@TFh^IX?IBPM>$HK8h$wKlAZm~`2x)u*9Md+j_`z#^ zbJM)NPq_TH|Nah{-h#v7dJW07m&araX{0PCb{2&iqXP(vagOP5VmIs9GCK(j=RxMx zAJ3n>op%Z{zFPqwP62oilpQO-Lx;tHy;1FQ(YTx4A}^i#n$JKEi~x(OQg+P48& z&$!w=d=Ld24iNL4v|#EpH;iYsAJJNs6-TQiXk-S_U|)9nB&1*hOj!^wABDa zi((1Ktpq|!m%BIf-M-4vNpGn-6eH2uGRkL7nH2<9W_+S7^yJJLqg<06WSi4J?4+6v z%KK#GnGgf;l4t<;hU5V7c?+o|!9g<^NrBx+x-k~dNfzVC67XC17%4o4kUrDWcR&e& z1<9!2fkcfj5S-bIf6X3S%^t#=NFM}~Ii(G*F?mk46lLxe^pyVi7L0@b}|1CQZbSbHyo^y)VMx2&7y45OOhJw3j3-7NAQw zR8?|GC|(@+qCd&Rll}2&u4A@8jZk*~GBo9Z@n~lB&_m{+XQ8i~%1O&?{EL5+ZdyrR z@G~zo|78fZcrhVNP@2Qf%<%$!UvO+PgC>WWQw%|xiVq|sYKqbxpeO2#dL54X`a8ou z9Ca{lx=A}<=Cc$-gxVPk7e4!HeMo$r@T!Z5%$!zBauN2fKpYC2K4F=OYH^plKQ8w# z1KDE!#MqI=gE$qr9TOR6U$7&*iXlu1A}Zh=0_y8JAZByG z1eHDlndUU3rHbrSPV>nQZ<}hjpIJ*(3s8-1*@|?ycF`;1w%f#15?G0kl zjeX|DA1aTZ_7CI#4>>mqWYzep(BBl!`p!i7cAd>U_}UO{lE0s$uzFvqe@TiX#tGgm zOR2bLk|tkenYlr1%?4hRp1d9Xi81hayJ06DF<8QL{&=>u-wx83}UW_@yA_^Sc4HD0FXf;mA@Y0e9f0nHla zsJrC+Fi)FLu&vq<>$k*|OBfv$0cgp!%dIZB=KazC-Yn;(Iq9eGPeyo|*Rn+pv>(ch z2g)_#l@Aj$j{Z0w0a0O2k!x-v=*hYd8?w>$3>5u!Qn!0Ww*9z>-eFW`bOUpwkKs_@ z$=^*!I1`{y`n+7Ho2JQZ%2boUoiIL?ZvJxNZ}!3;IP|?5fD#NYkPc`0GC{LNiYZFO z75960dP;|alUdpbH~8T!yw?WRNEf-Ad^>V0fVCrd)48%AUl{XGGb6wLyNg6vFHmJ! zdh67Z`X3ETT($@2%@_IXAn69`&l%=eXx+Qef>KF+g^JLZlPQ}FZ5fv93h;{8{C=I- zwY0$Uokip_v`53t)n71UU$o&CeTsaAeW7u|Q^MOw8wEhbHMn5R_t=$O|0%6pfdOO%BV(nF;#y8uQAQ*9G}?{hSbb z`T62>`k0abxawCYLOpV%+S{LX^1O=kC|0v`osjc=G!pPsKUu48ei~92hO~ z;+9+C;KKbjMmES~g3!39oXbyvd9~Hc!EXwDnZB0Hq#IL2*Toe2;%{e^ONC4FQ%;&K z20ugF$(r8J3)xjh>#Ue*r1@n}joz89cBOf*R7MmIru%wGtaT99^;<(diZmu_m@P)o z!t(6nx0nP3^M8iU{2!|JkHd^Hi)G9V#u&@&b~W}T#TjGYg@kG>*$GidF$;#okV+-l zLljcc_Ao|N6hc~_vPM#0JSr9D>o2(PAI|HX`@BE*`?|EUwLRZuisb||KkfA9Asa89TpqJtS3NkP01NCE7hgH+fu;dG34jUqo}5>#gtb#YvJ)2QKeMXNFj<|S zuWv)8TjS0%19vddqD067D=WGnb?F9%*Yp&2Hg2gtK5x6Bs%y0{0)3BFmdh@4x~~qq znR-@sWFdaU%|m@pME0~m&EkX5Z|@X%Z`MvhdXH`8!!h%mr%|fnWBX$_o@51-%v=dt zpunQan)-iB2J#^huoWh9g-L_^ZE%>KIl}KHhwSqnoqMNO@k!^d@|7lmN!wTi5{5Qs z$#uVTlHyja;`|`pW!2fo^ z5I+tBvHuet-X%1WlVPTY?2(2Zk}~!MZlOYNvdVNmmpAQB&WWe3uv#TOkT4&fB!K6g z8pus#Cfso}x;QYC{$YlHCM!KGPi3W5wx6f8vwNj(gG`|(LDJ(!m;0iEZRI^7Hsv)6 zW~a!j3Qxgj!l(LH-#>+Y+!t}+khoH3%8nG5MH^yIij$!yE^k9`b6E`guqOM3^Dyz? zW8c>s=2(*-v>K%Td0VXb&v%)$?C;bUTLJse?LTh2QU9pCuvG^ZI{^7aw7Ovjnrk(SeDbugM9=P7;)P zqNTDs9t%gK&O(V*g!j$Zk9Fv!L@h%MiYm)%2|gNVrpVFVcKZ%j;7oxD3z# zGB?Kl@rMNciTV5a&w1vr%&DAC3@pMtr?c*t_hMw7$=Rpw@Jvk@grB@p?Q_1f1U;3N zDaK(Xr2Z()Iq)bozi318#=TG~`cm9m_vuu&CpZ9*^jLYd;}wQgPl1Hv0Zf~~^nT&FJz!&#s_i^WBtK1HD7b;Zvo%t#6kN_5? zf0oybpKn3rR-5I0R$b17r?C6|yi6+W1li6My8~u` zb!l}xxO|`hdMM^`YQe_FMPINh59}A2S%77g;(0?w8Ktmjxyj9;O!zU(&?_iUQFAB% z@K4C@;X+KJNd7m^?@X4c-uaV7Z-sej4b3wMTaXwj(#exB%M%XC;`P3pL~6=9g`m_YFHrvWN^Jdo&Wm)5~iDl zM8U2()%IAcF~AZLDoOXe6U+Ta16{v(nm7h2e+fleE`6yAq~GSPdl-ny*PQj`qXckD zp~7Wek}{kP1rinJ!rZ(Q$BuYUr~WEBc`)F&huMeZ*)fJ_E67~q^3v%aMUr4&n)rbg zl)^>i+SY42ouJ6j1co*_enw-pKRgP+DRj7oqLbkTB0M>H?qWfe!kNBxnZ6?S0KQ5Bz`a(Uo9N2FYnf{;(2aYK*nS@x{+W<2?G zf7W`fTNuc&-qyO{l1FetCdu~|_p2WbIHiB@t#cS4d24%CcWU>Dkj+koguJ%@DZKZB?78OgUewejT#O|)R7pM zBMHg0n}Ei)Ex;(dMj$1MCIeIoMU}lT_lUObzFgl6845)j{aRX;)3>+&ioa~a-c!I4Xp0`S0n>=+#Zl*jOmqvRP* zmHtk2r)oI$!7(7M%{yPSZu7Ww-T!bDEQ-DLI6;Uqb3`^^u4G~TRHCO6>3oOpEr9y= zagdx=(}1`AM#ITxgnjL1WNXQ^isCYGF}t})sIxAm`M@IS*(>gf5JogJh~l50)bZt~ zPA6JejrXaDY$pEKb-?q@`sr)KhAR7toK4P%I78R#&sqGk&iSC|OKDD}d$JpNYA>t> zoARB&Rh?#jHp_OI9kMPmYU&kv=iQ?>!G08Z_tlT`xmlX3w}HIdXEaeuj$!I1CC*>A z6D=DbeKu)4>lDvCfV_y!L-HHo#GHD*Ri}8ApCvPueE^y0PbRK4^h=)8?ES%*7K1pw zww_S9ju~8#oYfuJP4PY#?I@u#D)#iKAQIESSljA!N z$Vw{$R@6?VtVR6pZeW{2y3*gM<4Y(BqMK$R?|3Dd8@N!sKjk^iq>m+=tk_6Ys`!@W622R zs{>X!G4sK?!tR2Iu9}|*Ar9kbAg%bNIB)3R{@rH2+1aQnsmxx5UImB_bjQQ8aa{bN zr=iYBLp~w4Sqe5~j*5=tkVV}*I@cFjH~1OPT>HFeqpWE2be?MWhd^Fy-IHBeBHH1 z9-IC6eNx_R29=aS=F#ejQrYWMcuQJ1Fsamed3!cN5(qt_x6W>4=78bBGIV2`p)ziz zM7(nkL~~S{o%JlsN{441@>9+_hvV#9yaax0R20{6L%zzq&(gp^rA$nkN)!`tT62 zwb21I1!CY|#^E323oHr_nPwk}w4|VrwNh8XT{XJSKZ`R7#e^=Jqva-6J#@21&gJnr zbGL|ryg^s{omsArkzoNhfuvAHuyYat59ee+=$N{NTWd7f7i=x&R*k-;ViMJ*9in}$ zRyXyIFAKJaq%I`dn+|`KVf)k&KGq8FnCENt;wbrGLq`fWP|A1NDZExS2stD!6?h?~u}=)*P`cxdV9c>Zh6PM}wr)?e z^PK9UW534Vk%xbuwmX`$xXJ%ZdzFq3Lq-h2J$yj<=l$Pc?KR+ld9}@j;AcV+EZ1Ck zURE*Z0I8CB=)!m@a&6l-2nElfZ9DU0{mHFtYOJrS7wnG)rA^Y%k&I?P=?@1>OOA-6 zVuzpf9K8sG`-wla&*r?UPbA@VDYedn{5>6smZF z1T(8Gew?`xrVI&wwx^1EXbBy5KzRDQbpcQ^z0JY7oM|833BV=R{+QTRwbyg>i@{bM zg!F3z>2T6#LlIf!8+E`XmIB|qS%thGrf>$H1ly`VM#?P{6P-+T@>RQfn4y@i+A_8HMPpq3omZj7KyU#NQH@l(tDFr z%F!>!1rG){`gZd-<>Ecb=Ou}`{f+D=8S)IJ`z?m9?HF-r^M@DmRd;}aM~9brh@k@p zVErwm9Y6h8Eqs+x-nJnZ#HbyesgLcXlK%N|aNtZ;l;uO&8IV%t6kf}}#{?w+?f2S6 z?$hS!iA5og3{MdDlDd3q)4yJ{`2FmX=>Su@I-zR5N``|43-hjCiA&0uownH-PbJwT zs;Yj=$puL~8J~xncj%(MuA5Z^%NmGgAKC>InngFgVGpKNYs;9&0bI{Fp9YVeWEz$! z%U%$BPk>}>Lmvd=pDJcxsK&g{*8VgdG((N5Hv*zlo{g|lRgR#D=491>~(+w)1DL<7~7uuMo$7>q{rI6Ep{55ly^?#@tKfGz_}qatN5zVhbBB+Rcu z=JG)jit+xCr>(i8eQ;!8N7>BHnfY;C>2f5omYQcRix-8m8~k^L-hKJM_WzVdXRHAR9Wj zC)AB&79?>51D@aeo;rshQfBqGu0L@F4{zD-t^@f^vg92lQAn1{c5hZ<{&lZ1pK^6; zSdhJs=+OV%7;Z?arW3;o%hY?^0mwU6s&u&))B6r!Y{!P~hzS zGu7yXCpo?$R8|k!NzlFR&Veh^B5`_;1bTCVm?8Et#P!FLDu=dviM38gm|}K^oq_eb zXiGoFnD96)j}X-75KdmqJ`C{KwrB~%0^6PPgz9#$Qx1Tp04^T6zYU*Rjb11F_g$qg$Lu890Xo4fO zaG{k69PgQpUj$6gDBRNqi-!w_FM|v>Z4E2IfArXjSO#`;=MIq&ZR1zrHSk9ahr;HB z2S^4ZA)IXv)V#sIoX*|0jSsJm*ydQ)ayAti(c8TW!cfO42!9&`Fgb>Up9w#Dzi4yw zFx-7oe%CSJe-y!5$skQn5Ht~#RH}Hhg+U_D(DZD*bs}1aK-v%d9EJ0R>yfRG2~KFC zMi`yYF=-vt8?B?Vnb({C%^e=aQi%l4JB9&^fC}wq`>wC}j-HoPE=i0I(&1`_(RFIs z+Cj6{1-6%}g{L(bsNrB2eL!wgtiHLTbGl-yyOA-6*#UQp8>c;O$mq7_V_?p9Zu}!w zgB(i*#xzxEHQZ}K)2x0fJmw76@V?w~`d<$X#yQFXt;I@47I%`RLmjjK@Ypr|9d@C! zFMgeEU?btstm8|&K^Fs!cnt}3gezTztv!OozH^}(4BE$LV5i?``sE0YabjDdJshk? z({=pjqQwYx#4tc-0vTbtBbPxyMz0Evd$AgfS?@->PJDVK_g72)23Dy4lu@ZH&Iy4? z#SV=7GF@qO&Gkygl*Hbt>YW-8*e!Ct3(z$7qU$ZCZ?Ja{=s6GCS|&)4nn7LgAx{vUZ+>-}f$ZtfqQ@SKQt+XlvDMYiZtV=wJNUhtXIM z)r)OL;uvOSS9T}(ym$mTAnEia$u|$puuSj;I{a?XRT^-4#RI}+J`M@-Vl>2BS`E)! z{LB!7J__kCM#p(lDp7tdFPrMm{nP`>ZO?~;+t=dh9X+Glwk9849Rt2vBd18%+d#6m zVMeddvJSuq4?{E1d_b;T)VO}D$n3#k*ESb7Hd*L6rDz4vt*+9iy157ceF7RE-;qmT zzypKs0_R0bp@h|@#NM&q>-8(vAA0uGdyckXg-ZjD~k^DP4~R=R+(ZkC?kPHzjROBqnNd8|z*y#}Tsrm}&E1n)xG>DI1ji=518HN~ z83(0jAl@V^k@kL+u)!_cn~=S4PyX-hE+BW1fbG+5|dWdeEZbNY@%7X3n~D#dvec`h#n!j_|uZqcmqOaa4$ZLY;FvYU-Yae2Ej+5Dc3ojQm6wGp7k#| zAkQ^$&Mxy`B?c?gM?kuS1AtIqGzBtfZ3iZ`0NT&LtJKifJ=SxH^u>7k3Ja^yvf?Mo ze*F%h`h;pUk7;Dke8m#&DFCo8hV2ad+NS`PLcF%%fp5K1N>K6Hvc+MA6M%_NjhGJ^ zL1+AERMyzn-TPs}7MSB$&2fOKxZ}DiA5=#VM+gHhohOj{OuIwK5N~v2K(JwJ;NnwS zt>p8k+&&#{qro}@B{Y7e$c({7Ie-l}jxvI5m9{xpS38X3J*?{&Yg#D%!_xD2;^OVO zZr4vZ-z$xNKW!K~;YQ41g2m;_Wu42fN)LDMugN-A(><1LFL|c>i3XJF2~Fy&iBka| zUyw+W=UQ$ysj0|a9CtKj_8Kr%Up~^&NM;Y6tAgVgH`<3{!+e|-zyl{l0_|q@RDhkv zI`_g`k_#!M&hiR3lg!*++mj9%_QgeM$WH$J2Z?Z zIB-J_QkyBz;f;lF+wS{d3v}8h1PeOc+^m;-3xuwFRIdZ(T}v>jj#@)qJt(Fhnnb>O_R1@JC=D5-vOL*W>CcFou5`@Zv#}?ZXis+I^vS4aoqKws6K0NCx?exMv2S&0E$8j z+}~cc4?dNvC&mx*A~VFQhg7ur_&oP)b06FGc?s>0rjgVbqU*=_*4DmFONtcVo2`l7A4Vgz7DsHWgOq9VtbE1$YKl{ zstxpfId+0#uCG%m=+P1!3i{fqR8&FkG5AC@I^Z|iBo^HLQ{KGNCzkM@V^b?Hdh$-; zFpdf!+4hxL`F+o; zNH&N!#z~!RVsOqg2 zF-9`+j+J6*&qjc~vf4|fONl`ixo-2W<2n~a6?@a6vua~MUlJdu{U=}>kF9*Lj*=a! zmp<7X+~6*9{K91n5UG!#QE~si3*(LjB8E=?Eo-^L>@Ol_%2??p9S!Nkg?uzeyzPt; z@lQ`g4-Z;%RQhP8xMhN{=qzs6b01~Hl1w{Sb?|>4xzBTUt2Oa|zq;Xi)%Tv^Ti#6X za3+>#`N@Aqf@)hz*_w5ESY@3FT}@OvvP*v;9`WgJN~h`Albk;*^Edy#TC(>ptJMfe z{(`4^o|FRt5B^oPWIQ?-`&;v3W<_y+n*?zVaS>KW&o0ZXPh7t9s{Z$~s=>DQkO4^U z&n(`C6jfX5j7X{{+L6SC-I=(y+3O~TBGx%UV}9#5e94(jUR_Q>4L$qP;Se@&_qLO# z?tBmu(AF;c#XmL89EuDh4SD7l*) zGHH;$R=hx_SNzG%run+}>t1{L>?zSwbTGSOr8Zh~*prYET=Vvw*gFH0WWH)oZ$^r8 z?LpA%%}UR`#~OS?E^ZAN$;hFp1_#qzt7gX53+rfYetF zLx3AEfOdK)^2(9+MdBaZwyT=L8k(Vwi$Hub@?IkikTfr=2rbLvFyIhL4W`nEZ5I64 zxQo@+AD-$xqi#;+|L`9py?hWQ?VPa%vZI2BG$M(U6C{+%N-Ygdr-3!MJa{1R_zny6 z&aU{d2*l+alpG0y+OlP%!Z^wwVI6~as}T40@bVc|1f@elGPNc^!?aj$=<+aE_RBk< z@|Vi|R(Q?cffa$}RI%bi)5&M12;83K+vllrXugUH~*Zr)f z8L+lBqR^5-#?{@-RAm>beCd(7BFqnLB>{DlGk{K;%LNO8cNdn>z@Rd&I{jxrpnnF! ze#pJJu*lGUP-hzgMyb3FMqTjd*cw*p@CV$i_6lVAs_jGP8f+{CZO^QmY^ob~=#O(9 z(>^xmC&9+Gto#6#kh*t8Jey6{JGz}eKhW2%az6TB~<839fXR-kctW^*RHsV zt^%L{xgB@+KnFQL?R8<6@xjv67V7992bp>$`QMh|N)czPY&(*DdOD;tiUqam8wAnr zjB7~+pGF+4r+}iwPFS9i|8-Q}qM=P|WJ|Fas`biGevZs9ym#%veZet)AM`H?JKpN= za$iRIG~VLv2Q*aYSG?*@*S1P7ee-cO5UAw|9Yh3*J4;?aRy{2J<$0%f>RqTan-VD3 zKMujT5+D64X2<@vLgJsmnO*5FA)+#Y_4k7zAs6W6_8+VERwyZtIr*-D6Gq(ful!N9 zTHjZ#Ida=xhxlbI1f+_iI<_LG2UeoQ#JSm8E_x%+fMXUEi{ufbHS#k))a8G}U7vqG ze<{mFH!5;KT6lq~6GcTyEbp$Ej~dS`uW=PI`>LJy7oI5P+|_XrB&)FV&x_P+0Znu~ ziubkHJ8NU8uW+#1p!7{fK%6zL56*1U?#)K3332#P=gg%<6!UCZO z+f8j#Oyldt+nwfn8P{l0()we0rL|VOl$bCtnSP?yQhf&Z=0o;!^a5v~O7y_6LQ&;20ooD} z$WeJ#9)9KL(8X}j`?ckF>Aszht`@auIQ?|ow>cH1=!pJjHoqh?CKah-iP&>SJH^)j zwQXv%?YOxDZTHYZM`FWe#mwOw3#Ezt5;frgme|Ely2QYP>Xb=nS|5;b(%UQY-*0`# z28?2Vb{nQyy;5(y(6Vg>DmtX1_|Q(W&B~xghP)^F9xF|1KU%--@qLZKP%Bc3x13YP z^uJygUjo%!kWy>hqA-d_QALfLkL3KO8ZuO5Slv$@$G3_4{^F!}%S|*gI)RAM36>`T z^+EIa?kb{S%G8vE)}mjR`G#)-)Cz8Ilz-c32EK@u@Q7|~7 z>1?yjNrf zhj8q;?Vg-i*q&`7YF$h|R&!`r_07?PF7n{`A8 zo^AKwy>H{eg#%izB=<2ts#bqIBOt31Q8XeNJs0Hzi61R)xkX&ZRpYG*eAvMIskmD6v_5HCI{-B_u>8r2tztk`CAT&G?QLVNi4vt}Ku*J4j z1@d?4-TrcT?YZ^*mhoXvo?x2Xx`sdFp=&RNlp&&J&>Mr%Wb6Pm+Qw^bL2pkZ$_h}Z zHzfI!F+q%*+dZ;Z{zs1PGZVR?mKVvLXJy8i@WF4pL_JdBa+Ibdog`!|1#vZpvAPdr z9+oX8S8edIQiG@S(N#>rjMR}n)1W#XVywBRyM5Am`Ukz=&6K1zz%scviu8OzexgT> z4{fFs(T4#El^I2M4T>2lNj>{vYo#n5pj>5{LK_Ys=vWE~8~;E3%<~Vd=!gv++zp;R zLR?YmRT4zsOjJGv5;yWDv`|{Tp!dJ1T*@^!{e~}_J8Z>X@L?Lxt}e{ExuAQHANxv! zo-!%~7?(jzWW92#W5sY4@jKo6O{fmo$L2rneS51EK%sB;%_ymWq&{RBQ5D>7Mc!wO z_N^CupRyrs4p?K{~$uWC-7w#~wOaV`h~ErhnPq{vK?!BpDy!x9p8Bqku+>I?9vJkzP#SpA1NN#=EZ+)4pFuhlk+wS%uFSAeVB@ZQS7F^{_gIi`A5Ctk;o~V5d*ZRaZ(b zsV|Ysr)lv&u(8va*y*f^A4>i`k*~%iZuT4os(n{ebWTi=v+g=2MIDi6M2cf}xp3sl z+%(O2FG993xu^|KdZ}|35M_`|mIR~q#8YrX_$ zu#Hb@Tr$PYVT3-%O*D;D=yK*gQJp7F=h%BTXa5TwzC_8lQ1WaSM~bYlA%;YVMHWW?>AkF!q=2n0UcDMqq=Gi zYFQYjmIm^&0_#aBDj}@9)yOL|+U)hfkvZ*^pJzwroJ8X3&!+L6;^}g45{iPc?GwZ^ zJxco|x%e7fq$XOS$7L_Q=*J{^CO-KXuwe_gp#IXuI-4Fx`5(O*XHK z^F=_+s>+7%F~n*r$N=5dZj3+D@=M@6tdx!p2eH#qt02`XGJ;d+Ml*kG;-B*gVTLT* zYf+))9qirZ&YTP*Z>Ho0@?V2Vakb%Kl~{!)Gqy_88|AUPM8V0bJsbFBR&xhU#V7HI zhoTBy4(X^uFFn|`*wo>ZfY4|_u79gGkfg8|b7SX~tE4F2;)?Zv(XodUvA6M(S`RFWLXNGSLmNl-tXe5b+gn4h`8imgzn(V z(_XlyU-(D<%1=&`tuF0px4AFsBct?moOV+cbPS)0A)3b0F^6~SEJ_(l5j%F=O8?w# zIdsEa)Pm31$V?&Kh3ybQOpFhrD}r?7Qy)MT$Bhjkq(pmo* z%yr8d{v{GZ?6Ue=P702+#x)~CWCtCEsOx_}1U& zXHYI-#XH?+ez}D$8C_1?!@RUShSdFaG)lC zHUMaGfU8nkNx8}7G`p>)?w@Ay;L+Y4PJIgqUB!Vi$`OEO2?ls#iJmK(=HL}xp6*=sgW)oGllzbi0{B|x}V z`91{GBcu;r-wd*51F{9019h<6H`%Kb$n@PGwS}ruRKpMpK~K-V{ym*vx5%9t%7uG= zZi_RE|5a+ZjB)==RwJo7?!~Z)D%)8qkw4EGd@OZ#5p8bb+ev%O_rL6aLNu*3Bux=2 zLv?Er@=5d{(cPJmuF&~B?m*WT`OkZUj);F#NV;0AL=b*4uVT;Ve=n$5AJQ7WAZ_W< zQC*5X&}B^ulZu(v>^y!Dc%@SPz09jc`UWwztCV5lGZLUn6MIey&E-svM25}>o=F?L zypxdT(?5^isFq4Cy`9MP`tPejt<`Q`jN014RVYv8$)hp1tsqnS_+C1$0l-xPI+2r@ zGvcRnB|A;4p8%kj$B7UBEx2Uo3%k<`cbmmOXTIseO%emMk_2);HPO+T^+KnbN7l!YwK!? z$(w(wAQ6dmQa@|;1Da2?8Ake+keh&q6|xV#hOBLZG1K0!ZNbkp;R_oE%Ac<*+W0MV z_ePR)oE4!lNQ!ss=W9B?72rk|nV6fY*ckA`^xM?^6wwo9ZUpY*^mudNrHrF1Z*F_{ zZa*`AcJ9Ma=G1nTk@ENJ#&K44`hQP;n7MUCDsL+$bpDG*kgNXFrmiJI%k5haH9y>y z(yix|tdxzg!<{c@W~>Bdy!}ZS$~-(R-KIs~mBB3GQ4cG)I6(hxuLbUdIY%3+w>kN7b&mw-D<)f!o=N23{pVejb|8L1 zzMCs@C|nbFyrCxGM-hcP$jSkh+9De5!Zqd~SL2fxo>^CK&Yr9H_31s(0hde{d10hh z50)SxUkFve2X*5}dTvuCy|Qq8MR-g5U!dRGck{R;U85tb7phUpN2`-?qj|)GK}PQ0 zPQ@LC(Y3#&5@X6YkH65Z3u;1|K)(6CF0{jehper&jr}eu9phyKzi^abSsXgR`!=dq ztJWz)OPGK8UK!Ph9=?onI2CM?wB~fg^RGw9tooc!Me3;3E~hgZ`thU4Bp2c!tdYR4 z?%ICMy{ggHlT!nq7MuA;Yf~O2rNO6_kVyd#FwS1D3VsD^OpLt;92XMf9Y^)vurC&OjAKTe#C2=?%a;<08F_vJ=2!jrFr&P;*xmlvyBhYq5yc_y zLo2(&?dd!sfh(Jwu>Wzw&V(-#xB@k>HFFp20q)vJzL%*t(+{ze*I*#cBrYDbAMGg# zdPR8d>Zm0%ljnVb5u4c#%Pk?;wq~?@lBe-8-xo|cooHhG->k#iEH+0SjOGq-==CMY z*PEegpHs0;o;`Bl9Ukm=)|8p;1@lBhzDPcY_F2F1IA_4hg)N#K-+FXc`)qk{;LaaD zE;q3tQ_R-aWS}1SIB+ksAWH)Ed(liS9d)<%8A-l2L=^$P=qTfXReF|_`~AYuX%g5Y zH|@jOr8-{01jPt)Ss`K{tufzIr;2RI`vDt)4;}4Mg;w44jt=qq^5p_^mtk}aGn%i* zdu=Kj?iCjNE@FabA-6&crEczcRL5M14XxQEL^aGZjCcd4{M231kfSun1WTBRLm^U_ zX7Eu=*W%?PG3}$f3g^lxBcQ7dB?LRInQO3-QaXD?QeQX=|GN=9`h1+Drx4t=zt;DN zK3ftO|AO=_L{@ESyr2|J^oELn7)E&nQjRB<2dO%2i=q#55=IF(Ig8fyhLusqtN1pa zBvm$qcW%2E^(CX_VewCHf;Q{+;I zXtDsH4ddSYxkO2MsIDOjcH}PW31C$Vj^05f_LbF<_Z~?q)DIWbs4+4F{^l;13_~<+ zq9`x6`sFS%CE(g|fqU)qa=U47d&|V)?i$0=&aHqjB!yIE8Wde zf!WNzHnDtfqw#Y6pZSAeVnu%>D?CD`#YknqF2`Ae$? zf=Fk5n1i}@NKoJ3g-Ko11abT{Ft&3Zcd$0uGr;EvV-p12u^4Y)}`yytIvXK@~(`InZFbtN$fm8^t2cVKz@PAPxs=* z9rC0^qGAaSx88WsE>C1W#o{z{TOU*IKe+2FoYwi^&b^gvAUYvF8~X>3ZS9uSW3pNa zxL!90mvPzAY|fEY{p4e9Dp`<@(%3ocPZu@m>-|nfLWz^2#h$T{4LQxpo-QL}Ue3j4 z-&U+y#@ItuMY~W`>W3P2+kJVLyB^EczxkJB_qYEee@VM3i0};-1%cfFe9x-(f5e!= zv>ir&N^g=uiBOka-#gQPYccM5wGQaS_DIo>2)Vz+ad@U4_hk?`MN`EgTZAgj*s?{e zW1ZylRUuf*MN-n2!a3$oHsR3}d|&w|;E9@n18pW<#z#2i#+EV)PZcF3PSr!xY(%u2 zVL9cx^k@Ap4a3wXHoQCwevlTeg_8OAJaXx??CeyaRL?2RzJrkBqgxYd0}EL&7BrF& zxWd6Jdxk!3k%pG{zpRR_@ui&}+~nhwnIgyq%5`L4<}USc=rA}L&dNSjpX zfVUDLYdhj2q9LDzA%D#q{yC4NFwn97PEZ@I;;&^ZxQJbp<{E%x^XO1^r}17Gx&u^q*o>QmcE<8g%alUaUGwsppX8 zMAD@QR8}QPdzGsRI7cb%U4`y0_OeggA6vlGMul1WwC(+Mx6mgT7T~D@U6tZVLMR|9 z@`&sNQ(AB24Ajdw$4p=OM1VdL)zEj0egTQHLFbgAA0|*a=Oa}bkw+rY@yx(=ZXSeH zgy}iEQkr<^X!IdFv{DjLvE5|t%^quG{|m?A++k5RGK>_wA@`Y<3>!gwZA}GL!@?Vm zqz}Wxr}Ay`2;ofW9ay1HuwzniP|JZx^&IgSvqG47$Sf>GY50WJh|%dcIoE2Ce$xR` z5y*Re?3gvVi5qOCgD{apR&fGG&mL{I{}M0pjN6oE2qEly#CdtTb4RL{c_qjknYsGQ z?Mdohm&@o@-dc~2~m2@!;%+INF6Li6X*~T0pvF2@@g0*7)CW#vYyNe@wi!GsuH zYFcaO*~LSQJj}s%pVhD-=L?FDn%juZHm9LGly$xzhyQVa&pvcw(F)@J!Z0U4x28!%=1AU~%&_bYQ#m!DQ;kx5>`K z8J$jWsdOagKfN^`I=$6-??B*nnEazsF%ivPYV|T^1nh*wwh%9X(vfG;04^t3LmG4%@sIGuiSE`|?nt8{X6Jf~k1C6|{^c@QHSKtO^L`;;WKC@mcl!%8; z@2lvRszBz$Sx#YfNbHK})a}<2ZZ>Dd5v10z0NJ1JJAg%5R}=LKAn6JQ)an;Z(#9r1ZR~^;*}I^!wk< zm=QaYVRIdaP&S_fPc-HF+gD}HdHfQjB7NpH$`g|pzrt*s9_ zZjp)QQhB!5|{13hs z|I0_FE9*BSMeyf;R9Vy}j|7NDGUOuWP6)WwW7xuI7&NmXSM&#IS97U1%B7KC7vRjZ z&^`%N-RCW~AH9mK&B|mF;ro9b=Khr%*$;D0K$+NRRWK}ANjvK)9;`vSyRb{DL8MC1 zE*j|Jb7g2Ltbh;WCzLX)Bo})0nvW9>e%ax1LOkp4fvANjFHm6GZ%u7Dw3(D(Io_0O)Vljkz(Yuza!kMY(A|d;o%+9pxZbnpdt<0@ zgIlM+ws)^c>kX=Y#ewB%8KXCm<1vpZWk-#0he`aS3#M9TNQs#e$;(WniGpnyQ;88< z_3MGHe*k+s9eL#|h&0^w1gArwp$}=%Fu`}J;yoAFDl|gEvk4^C3wUueNjE0_TXNg( zVNl-MQfa?XRKnw=H%5I-jeua8rFRdYZQ`gE zv8iZ5CcMTnwtfF^Euf&h-8eVdT+Dj2R+BWDozB{ z>pIg>lyymuW~6&7VL419Ht5NR3^a1aw?sY`pxH2?`R2biVyZ4lfpxa2~yYeQ9nn z!JL+!fBs0cB3)3PK^d-DH$cRpj@)TTxxEg;FCnf^n#HMWF(9>Jk`j6xI?#)KN7)D~7YnYoH ziCvhZj3^|HkZvSV$}Y@^DV2)ca^)zAQVnxPp-ZKHNKsVMrNVyxg3ssi{yaX9$NT+y zzu(W7dZs1M>Clym$I$kc2<2nLhzIuwZt`VaXTZ3LBj>!8r<}SF+;cw%*JM|W#m@Bu zAo-w`;PrTL?jdEe7znHz(^1R+lSQyyaHBTHqLhxJN>C|-Tc^U2Uw2(bQ$41_p;4!m z!Y1&{I@SfRZavHYE}lFp7d!Cp&`eJo)zG|Q=! zP0B^5fQWX_3ehV!cVcb%ZoKyE?3;VA^4W)zJ?rC1YbyHNWyNO>$|0$M%~c?|UiPM9 zwNH(j+>{MWB;Q-do}*~1QFAfWNsOczBjfO{{v1DTi!e+;M(Lt1&Qf#)~!}m6f-kSwf`sbkK-jgHW}fQ5lWC7qfTEl@Q?6 z*QU16g43Btw4RnT{22j|%Ja$w7X3~9O$j?cZD0ec6W5Ih{jK*k^Die~6Hg$UijbDb zlQGC+`(}-}(ETSpoflviw(Ass+AEtta#)-VR{-u>yp%5NPEcGKmJtn@Yvv( zZmv}z3l_wp8#i{KI~Mgz-l;2nM_SI4!V>PR&Rx&Ua6e~GS);mjz?KdGEY^=-$}N&} zoQA3UZx`zPVc-DakGvuvTa|rOA~g;_Ftc9$!wMYkeXt(B zdobE}xKyI1WxV>1&7)^zYptG|SO7zj@;c~Hl913@lnL**QEC-@c%US+U`Mx&@={aO zEkL)T3A|J}8Bt2cO>+5}ck{Pa1pm~rsOxDAe*fy(+z#%^FCh_-X&t}-KGY-Msn>Vj zkOf01RlV0)?+kw#QuqDw6M~N=bk{OsJKHLg2}^6*)70x?W!c1fKM_`gRFaW*!kcJ# zRE@^j6RD8YjE^b4cP@M!FkGk2je|`p>An8t>LiGJ*i`j8yp$%{pl{3+vx$=(nC{pr zi_-24nL&2+w^H~q6#bI9l9bivf#HLt+Me)ksjc*r675WaOW)1c6g}e`kr?6tLhn0l;-NNs{+?mndUi;}KmK$+P zS0w~a`&+a)K##34e$+Ssud0ZuiT%}xG&wdBD^SRJk-zCmFCI>0WPk54eLerf{8Ipa zuKXtRP0C{B1AI>Ylt=kFN$KxWf>XM&i&0LA2I>26`}j1NOuJ~vKt-Ks66$zXlx&lm2Gm|^grC?ho;Ve$vJbtcTt9ui!R@YVn$=9d&XD|0#vFbr1bS5c+~ zo&UStbF<4Bk`Ww1hQwkC2u(F^UYNkUkrlMsAxN8=AbST@QN%bEzbzF?2CBQP82fWe zf?RjxCe=~Od$D`-pia+g(eT67TwvbHz;7wi;wXMli@Y6wKnZqKs8T9(k`iu*1Q~pU zL7t`9)09W$&-zy{n&wAWpLY0jmI5*aEW77)^k;X=$i%BRtv>AvQ$?{>ySFn|)9cm3 z(xAQn&Ih3c*jjP73o};EBZLQJ37--=zCVU{M+mOf4rosR)%&>QMkQl1{UZ_Z^m9E2 zxdhdTHblyAfdlLR_7bB=o|!+)7}9_423BF|uGr5y9A;>JBL$fk43mG~CiFVr&FNCr zgUSG$*(M6)nKAboJma&{>AyKzTGU9VMzq2_?Yw(W#BKXe(jD;(;l|{d)9g>L#d(gKC0pUXpy|rEw|zshfVdMjtdiBIKACm2$C)>n z{mGdxo-Xrmu{EU67trY`3%4=CtD;lYqk%%_A3DhGjvpTH3QKd=%pN$Mh=|cf?_?MdZ*jR zIi@y=6~k#z_nBM9w<|>WM;GUgKl_^U=N?l!Q8Nh7TIHwWZ+9|`Wx|@)v;=0Bcbofm)eYA3#qf{(h zD=pV+FXrg3c6Gz$+-zgw(>AqIdOSPco4V)%+R}~r*HsN}z(?mJ)fotb2qADh`k zsd^-D#iRCmVudTJ_JJYq8ur)>?|2dj)omG_NFuv$fumlpz{^YXMT1IuCMFBr#xCl8 z*!j4{eCZzTZ;9?stGVkM@(47z5(R-{2WuVy!9q=b4S2U2-CB^$Sv8^*11DZLWFFSl z&aKzD7QU-C1Qh$`r%1yXVAa-L`j_A-LnmG%e$6CJfYd&YZ(r0+1ltZ;i0l&k$JyT~ z^aA5e6CLYX{gNs<{KuLY(Sh>nR_H})V^@tH8jSH-$qcJQok$Xm4p%1-8hCsCiKzzEkjE)@N4TJHCWGwuFAZ1X(?+2VO#=meScC zrnvk&>`xVAf2(y)w#<6bD(&sMSet$e<)l>nw=0Hwd_kXMZ^m7zC=bNdPIN*)>Q<7R zA}M*D*7E;dZl|2%>9V?b_#62snioitPwC?I*=JfvY62}hXpNrqOjv{n@sa#q3FWd- zC1IoU%g_^lkSVQ57@-L#^Ru+z*qV+xSg$ccSprrxqK2JbKg)Y_Q)o6!=i}ZXX|@abrwshBw{2DTK0I2Etrw z`ci+yxpAPF=fVtKi$lonpWnA(?mEhB3$qhkS7Y&2qPd;>pGpW6t; zHv=6vP@Wv#I`N%%CM{u8;2DfZCd)K%UK`6XiyU!ohKS0BFW#E!o@?U(3m1RoD}_wm z4~e&Hm)%9-wt;M~h<^S9YGLgtC@@gX0^#_Z z8UhiUC$FUl-Rju`nXLj^D{TK=VLHa9n(TZCE3`}GA5P|fsm|lI@~^b<&1FlF!7|7V zHa2^p?L@P?JQj62g25H1x0Z_(^>RXz$ZAh`ym>um5)6G)7(ZN`n%v8%MPmrvnK6hH z3u#cwgB=lIU9oq6GwOq`85gvEYym1Lt$>hfq?dhBkL$4^f2eENDevX(ZDpX$P)4J za1Yi%be=${q@h=_mAb7VR~Y)lBf>e~1+1 z>czuy3jO+yVtS!SOX6QI6kD?u+>N|40r2RZ`mQ9yW8c-a14K@_hHAEtlu?{tcrdnV zI5WCHf#mY`;Ij)qZHLD^!V5s$Zyx6UY9C~J_FNo1F3joQoEtCPkNWUY_!Sse_#A4A zV(hVL*UWToRDIS;M?*!kU6B`t4TDP zT&{N@H)TO{3AmjZm_wEZz-!L&f^bM2$Mz^j3wJ>^28^}v{T-bX_j=2o63dX!`Is9b zUp${avf*!G-4fap z+s^5M^K-qw8b3fwwrIpUYW_qQk+(MX*>T5i?ove^AXXVypoJy|rM6jil(+DY{NnRn z=FGR5Bz}M7&Q$mlY;Z|?1iA%VXdfx^Y~(%Nrk$jUvcRvw3z?b4P-y&4s+D5{v(LJ! z-K6hz$1?w(DJpDfX9#MI2n(+r11Y1pJC>1}W2loT@FKb7|u|?(h{9iG(V?!o0<)X7xzB7)mc^?(IYkLioFZ-A7E^aOVN$zTe zG9G5S)i}A_FGr}kLT?GRi970rPmV{5j{Ow#fZaPiw5>?I#Xz1ho^O&sF3!~6Xm7Q3 z@nL#_Xiuv!Hx|&6SFI;le6NeLc`D76{0DlwyB>wu+bTpeLFaun)HsmpPrN`inuyOP zu^Th$M0T7E3z{%W3CO79G}#ojj!(}N1nlx_^H7dg(_-IBIxp&Xkl7+ zKz^!Mi-8|rd6_OSRt@EXDi7B6Yyd@80^v2Y(|ok5R+f1Gslo;S_i{aX2^+n*OFJ55 z_UDt@QKKgJGA)oP$zFe_MTOO>HF)ZpC)noh+~_Fy0pcZuL!p+%bTlKk`vDcHfo;kU7@co&Z(f8yBe#9l&>5F$ zxymTfRTp^g@$cJz{TDinlDhLB(%$(%CBEkv7WItXn<;#6afV%qduREKTVe3M5%S*E^-QK#K)p-qERWc| zI#3CKRq=o7?XMAvFm) z7N^luwW3}7!MBAO_xd2ViGMbN1RJBFuHwHbOZu?Twh=ec>l z6DVHeJotA_G4~dS2YtdbDE{StQy3*{NQj;}ojD8{9<0n{dF}+#A-i%mSAwOU7g}7Z zMhdonlsm%s*RA@7y)bby$pyr*m*Ba)6a;2fmmNdsN?WJk98H=m5eOB{!^=@zupni_ zrV|HSCy2aMxK(Kg%IdufTALbG3?djjOi|T}8e=!o(k>&cqZ6x2XsjzT$7N{AB#o|! zC|vEbghZ-Y%5K;n55qn#$|uh!Me~)d3_7u zs&XeoP62PzcYpCeCLg1j_aHxX)4wkm!>IU6i&4pWKXl$65rU;~0LQ}VLFnd1!Atq)`$F927OefdZx>BhRtNO7sNEh<*tRb-F~r2dEUwZkKJ1xk?d-mPf=q z%uuXvyh0eQ-z8fxh1iQpU3|PxekJ^&MT@=4I0X4>F1@0Ijw?4i z;I2s%9Y~C9b2JNP-1nh^x}7k_;**tTpJBE-L_T-%GKJBC5Ec4T+Tne^2+c@)Y`2T| z@;N@;C@bIhpsep%h}+pP!TEqoFRN15%YV%6i;}UY`dmtcZUZJowy>8jEyLkn`&#s9 zhP7Q9{!s}%s=ptD<(}Gn0Z-AMj$?!C{^j73*sgU{eO;nD&aX^jIx$4JO=1`&spt@kD@06)@}Wn!#Sh* z1B_B`XyNUmN-M)Pw&gXM(tY#)66j>fu=;KdrC*Qb<+v>Kri1ZC}hGw0OVvc1xcBrkIz8BKC&V9j+awJvg@WecQTAUS@8m zO~jJ7iXUrgs}UNV8QPC1Qt`2Mn-9k%DA3G~Ryy(egPWF@PUuFFTe0J}sjy1bZnht(r%mAu+-9|B^h$eItUt-Ds)M{uhg zjZs%@=uexXrSJOT{$x$JS#+sBo8uO#5Q))yp$^Y@C+;mCI(tagx1y+hw8Szs6YW<1jUADq6GAkXLY$J=&jL5+7fJOInG*jG)4 z6SWsN3{^<=kB_qHtU$a)Dg~;E&!aBu)}%L6_K2qnJ1(>Drb_XVIHeA-OsQnOqh7j< zok>0HW?N7_yB+aIEFaBkPU)*NpxGDrbWWJ%T29N)tS`DS_&diQc&N1hsV3bqS1Ayu zcY5JU*}>CKFIYzjzKf)T5LFDx<{m~lf~FMw#a&8S>_h~3cw5h+ zqQ0hptS1hjZ)_&smX?_P`-lAbg~nGEkfJLNK=7-Ro70vD@Uo!d;Aew7dMq^sK%lks z?+*&vt|f<%8?9q-|CgfYSf|>@r(2&7M}VlSxdgZrg>dHFbKNXZktMq7DNM@CGrpWt z@6bZ2<2%#ZfOuo4_s2+gsF(BnHmQtJjP##N(xzGPhAgn+_kg=;G2TM*llMq7(E0Q= zcuzWAHGTFyV5HfB4|aG+y$y6k>M8a>NeE%v<+MB=Ax$WtY`Dfj`p;Z{_HEilTMXL#$#ScbE5}gD z!tg<1d6>Sx2g6c%AjJmc1Bf$R*AsOvvlz}x`(=G@eh`Dw;TXa{xnX)J(4O{3Y|?yC z9~svV=KNZ$82pE%_<{zrm|qF}m(}|E75HyWV8?eSQJM;VLY)<6kZhRlM(aSovx-nf ze3V+Y-T^=$3MgfsecK8`p5MHnqfWU_4LymLYD~E+QJK^m-#H?3Ib>$VJ!xexH|vHT z`05X>Hi(yYdTBX`zhzq(JhM`0F^KkPQ#%>rv3{|R zIYXT+g`G(eAZg28{fEEH#hP19r4AOuqL%7k>a~d{Y@{ieKmYBNO>zVS25ivDKArU} zkbM|^qb@9m+PdYc<2C8lw4ZAu{X`PQG@?ib+)mh79Jzv;CFqJbTvoP*jo)L-$zSSF z2#;wVUny%gwniQBw2(Pn?C?kVh3M1Q?Fh%Lbcr4p#D_+>l>&dtuc<3Rx6ew>9^1Ds zu)+YQz44up;G(BIhjA6-pWJ`PGq{Q#QX|CQ18OUzSsu&pX@mRK!f*D5o+JZpOMfe2 zF^f9h+Wog=1O*3ML4VPA)CUTWo!6K2h7feSa6bO0g@d3;b5OC$ViBSOM8j5B-Fpwm z@C`Uw`mLBt>pb_1Py77QX;9%_b1n{kZU%$zXfLJTnIM?;d>VGpzpBK{<6-A*%>4$N z4-U>C{MPH8!gPGgR`1;Nh!I|E?zkKX^!$r=9n<`dhwFxe9r_Q=GV^iwU9Qd9Qzf^CaLmSrd|lUewHfbM8hZlhB3km@~E&$dSjLh z6$8TYC>Y6q!`?n~TCZF{-0Iog^hQw63g5<*fhKFak%K+gFm#C_biE;kPlGghuOs~m zvA&QxSB#hqY37_!TIJX2@93JiOr7WAi{EbeLDgw|>(U;okp(unfz~Vz*GcT43k%St zFuie2h3DJoi4f1`PM2ny6`t-X?4(;<+Fi)-DBw`55N-v?Bn#;`OX-V!g&h-e$*i&j zZ&(}UwTm|h-YP8$nM7DT3@PZMC4#y%q?ktC*Qbi8(n6{Yczf}r%k28Eu(0(5SIjIK zb7UWsJGH3k`fn{tEsKpEY5C!PzfwQfy+To5a`~nuU1|Q^m{6_iYp{# z&QriVTd?6QX9F6kVxw8@q(TQFrZ6cgOq5j%%@cv2qtR?0I^^ zt1)#Dt$oEWW3EzJG^8Vq5HaNW1?6eQAda~aETpmxtsPrd>2tOtv5)lV_?h)M>Dun)A4+xWqLqpq-7KgLSnE9oTs(| z#Qpa)aVeJM@lir`XMt^*B~%NV1IgdEkwJ==oXYDmE0&f@O6E|#73^-Oni48Ae`J2A zJWA6I7Ih%+k!skhI#4*BQtso=y_ippc9afHKOS--Vw}&c06eV;O@j$4L5~+hTz9>x z*BI81Uah1jUwauLjcgs-AaUJFG@QFf)tS~iYF14B(b4#$Ll-BFU*+SSco)*9bnSWP z(eB3O5X*d8Kq%vqBSXKDC3Mr3g%|do$PY-vc^`zoJO;W%Wgt}=C6;wL)R>WBF$V$r zz>j$`(p*HHef=iYRr9j<=D$08{l`i+3NYRhbd?%f{tPBYHKX0Fj0(m&br61`8)4_E zgWwMu=jr)AM=Ygc4M?^oqd~6sxd8Gao~OSGC17cX4LYGWU`B7#KAE!T+NN;!Msb=m zbo@1XGCp5ZaGnU!#dkJa@qE>IWE`XDLZ@jSO<&p>peZn#pm`qbY+dD_e8s(jWtx#; zhWZ=m#luQKRm>p6vKe4b_lF!VG+L9&v)M`38YLE0K-F$oD2*ptnA!$4BR>o&oYvyBj%}b{ri*$j5Vb7l5u<3FNa#)+=2q zV|mnQFpfiwZ0@5q_hD^HpGH&9ME65zxkEQ}OZbJT~n2+xS?N8?Oi zXzx8|VB#hCypzlzIMI+NW)O~ow$(MopMFBQjEO6YX&pAuUt^1vB~Uo#IDwUo6lX)R z78B(QC~vR6bRkh4C=$qE1>~AwheCKKjzKyoQKb$>t)$N_U+Gf&;JO49AIhOG43{pB z7gI0WouG8z%6{l9P;R8a^Kf*j4$X6c7H?1|sG&Dfk1l}M*LjUjlb-=czHT3CXMh)Z z=c+EeqB9ysX%Fo;WPZPJoi4Bc^8?BK0$9^F!}nelRqx~aEbdWf!y9HZu~*mp->b|$ zwcoqMD7-4A8IvOEb=RrohL^U#H|TTwFN!fk*^oru^^wT|T|_eDq3Nv})m1(3m%FSg z#cKt7|7BJIIVUjQY`*Ui#;FFd{NRcO_gNS$;1m{OIH{kN(J?Pdht=dH7MF)TX`zh0 zyieF+@;za0uO-}#wIy;1q&c6HS!w);EKt)k%~g7_5|K$Dc@ZWme>yS}(a62Cq*DbS1Qxl>2BUjBB@OsZKXh*695y%XE=9CqnL)AEJt6RXg1-rTtHo6RZ` z(75%t2_`2n|e_^b4GggoUfHANXWjQP`?Sv#@M@{*!>fO^pNnO5H!)r(qg2Nmek z66`E98_kR9{6U-09I}+U-5ByRm^m7HJ=SsNnd8TEmz!eE4mj+F>9T*4?7x%90=+zh zN%=FE3omJp$=)2S#@E9d4BhMjmA*3~J^UkAFqT2B5nO)4m|7iI z?C+WZwhPxze6pmsnwl+Gx>dafjj5lC zVz}u12bq6y#gCAfERe9Jr=H8fFFtygT)6|5z=egSo+(Pb#6h=b%h~*L6@awSDtk9d zzlXqnNhs@F1XmpeiuSRV=8RF03bxVf;Gs-WpSE_f(!jH^jNg~P`!&2osqbz65O7Z= z*9xYCG9*rL)j%ev2Nbj?xQBkU(#$iA&o*gzeSGd%{mhZ^sRBl1Le8a3=(8FUa%}14 zyw=j{nQNrod0$O z%3XS`Ah7UU*y>Inm}vnip87Aab#RY*A3H=UxW+)EeoR{UdZK78BSOmWEp!%r`>@iY$r8Ied zf53v?URXw*L}Cup+YKvw(9;kWQGQb-1IqhE%lwLKHIHyAbSXFEcFmDXiQDA%Zi@^( z-~tmrZpANjtgx;>62z*rq^4#yJ1>hyP_55stB-y8vw5N<0w^Dm0P{tf>fuJ4^>9Kri`<@n+rhAvs4!|X=8yY&dch6CIH@8l}4QUhad zcZ|2;zuvb^KHK>~9wIZ;TIaAwDlc!j>YHu3r(e7t>ptJ^tuZN7(^@^2@QsR>yG&SZ zTD{%b^a|Jz{3LtB;)DyS4YSH0gNtYd@^G|Lz7j!OIeYa|3CUetkTMFN$~AM>e@H{g zg((L{e>fyKIVDtl`F-etC0*8$1f7X_lCt=3AvVO5UE?2mbL#Jm%egI9O`=lzI$r_V zWzbrlD+Y!!*WidUqk1`|vn>2wz*t^Sjywo-!WC;lvAs zQ@7rb+rv6E1eVDz2beKDkBHoLsw&bzYB zz$7&Hvt9`a>jNuA6MU^o@*bqrLl%k}fkl2DQSm^GVGHwft!W$U=Ufrer)Idm?bBbD zzmhtppV1qd7$#6(Z3DZmKbCkP?eXe90%F6aceyqytW8;c!PMZzqII-DD*^UKz-Lq5 zRacTQr81i8CBA`0iHvxcNobodsQxy)TSDDRyM5@ddh-CWU%_(dyO3xPIaP+?$-Y6Z z{d}%sOtSBZF*jNgmVSJ5u6$q{-j(*}nzE0vT)%OhRkdfaD`Q`|5*HLZ@2|A8Qnrr^ z7%iGuU}idFqU4Tc->SbKeJh9tq3p*u$!in`nBE77BQ0_^RUGN5iWyc%Jewkt<< zi_=(OAR&04k>^?B;Wxysp2knk&~6*mEgPbb(P?|GEy8YmFUnuwoOA42aGuw_qZIdU z*YSs(vJkPsX|IX$R|g))UjDmwMc3DP+mr-O9zl6IvZnaa71Dt8=y_GGpG6SB9s@3c zpKyq}7149x!w&Pog`x*BXKy74rY>&=2ZR5mbMN9T%wJTg{+r>2T!fXt6zzcy*yt+Z z&5_Y6`~hJDWOGnKTCT}7rC-AlEC>}n{Wd1=Pu`@?al97smpE^8 zvffr%;!~G)T{VyMrAPhS`~&L4s~d$=0Lno+@Rn%v>{8@0RJ0h_m3|Ic=xT2M@Xb7| zlkgu^l5yYKhdpujqS(TcE=L*-w}~;CS}C){4oeVbAmxv~Qm|dkWeP=C{HRe$?~wc% zN=+1G1Azh4S-JrEFRpxls`S*tYY!k%Lq=#C#45GB-D!#^ z?I#Ys?XEc2c%7&sFW1?Q_v9un=vCE?`@MB-+nCBwy4n|ZjnO0%j&9i>k^jkm07lGU zai_`G(NVQP=^Y5_y6^}W5FCDv?|7;&f{Z-;8hu<{P9aS+(jFch^E(H|0`2R49S*kw zZgqQecD8&2(VX!R(b6X!^I>h~_GY5m8_*h@0Q}6Ym}j-I_QVV5=%GO9l^5-br%o>; zZ&9Y4Z!O_b&WSvtVkeWVF_Vq8eB?&;GXr|cL!<4x^b6l9-R%bNKGM&Bu@hBQ+H?~;P;>MfyvMA~Q zPrA*#H-2qc3%Ujhk-(iNVdtB=J-XH2H!xT*l_r>%Y0^%)bEmfA&)C;c<^knrz5>u* z0tLwZ=Xm&nCxd{l#hMEUE%N385KE5oNzL&!QU?pZZs?7Jsf^g zZ*@nlR@ygh|q)VC%czADB}H1XKv-e`VL!826p{9xUxzRn9L$NK3rxph8IT6 zyCc>ej_Fd*=8NqIC%Xt=K5h-s==2nkWSdoC?>&r{47uZ20`p^W5-gWyw~u^OMsn3p zAfuOKvivduv#nzsu}RF54oxN8avu+LGe7-q!;R9<;!5L!uvl8y&-#FzYp#d)s~BeZ zUZpUx`XYwM14xrL;w@829wohM_y@eUlV3L%%NZ(nhzQxd0A8tlX)(t?qZF!g9a})z z2%*~id!ByoZz@KQ%HaV5>jwy3X~%47pNI>komr-1h^hrg#e0h6XQa))20SvT%5Arc z39)kYK*8~;R8#DGA2S1ykajnSLQ{#Vh*MzY$@9Z;pqpN*dDRWrX*T_MEE$OdwfyXO;>Y}n6PeD zLbjKYhsPPg#v=)ywoEgJ+nWjk52`LBS*@JL%ioQJyAj<}o?FJqRx?CG zhCQ0AM#`Ayj05_-@FX{{%{5t`w`!i%2Hw=ngJipJyN>f}1VLKrUfzs;;+A)Io2j%K zn(`sW>vsK{yB3Gm9sG+vLQ{+BZONaz-8k7LRDCsl%-E9J1lw7@gnZHT{$c);wIw-w zc;?#wTpjej)4Z?T=x?|IfmJs!d~MIetEOk&JBFHOAdd)wgzZ~QkSp(|cM`5Tb=$Q% z{(Khum9Ob0JGt(C(zo(rM4aX^IeWc{f>)k0f!^|+POrkKE+*mq?yZl~f@J4>F5zFM zP=c2+L>4OVql_}iPqOas%;d^iiQ0yel`=U!tOD(=OIDtHags$md*`}(d&CZwz7#I? z|NZSaOKnSFvpZwZ#_&oa)b`g^veW@KNu8z!0EUN`k9rUbC`>uSg*7uHLE3DtQ2SaT zo^>*Ka$&cN$MOPzkXydF#r5TiwaEBVTjIHs z2vhexd_-(`hFd}TOy8Lb(|x3 zo3Lt~Utyq~H%0N17wFTXDWKGiYOzyj!1@#f8ILZ#l(_j4uW%o9iZ{ zZBTU>h48R_V*9vqO2)kBaEbbb$esu}Zi3E5=n%V*TDYz}>Hx+T-@kFVRqhev-PujU z)$fTLb&sm_Lqy~yM`jqmZ^Z~GfqYzge7~94(_f$c_g_vKL?iA%_}M<5uyj54yO(dH zMFa)nWjAE=1hvbHRS^^LqO%LK<=f+CuL6x1$uj>}AS`_OTA|_Yahbg4N+_=qbMjO8kJs!0o0h-SY3DlaGS#UTePcoAUXU>F{`( z3-0Da6-y#YFIL{JJlI8Xrti8Fa@>TP{TiM{K8uRy4R+PI<$_bF+lT!r4x7Y^zNks( zkCEXcT@<^gF~j8$-*+F}_F<%dDMl)N`mJ4sb*yZS9tz%C5GfA*kxjTE8KP|GUdx## zC<;K`KZnm2Zq>^sh*g9*d1d*7Bv~YEZrWlFqIx{fa?V=Tk@jK|ogM8dIzS^v$w)8;?=$&zA$>b=Cc0X-`g?F$KR{hcyknHDmd~to3POwbZ4^F_JpUp9aLBOW1 z)fWK5yJ~}PiifSrIgQ5nd1p6Q-qUr2vZ@gZWfGmR`Yyu0L+;JEHD=SwJI(=r{Q5U2 znL^|b>p-N(vkl)-y66GZtK2$OL%&~!CybPpRWzBYD1u4VG@(1?9+$KcAX@Shezf|ahU%%4(7?v=4 zbG1ueChq#Fc@(p6&<{V9ZxnF(TaJ1uMIR7)en+r48(ky#Z0o*TTdmH6Wh+R6*Af^o zimK2Ws0A9Rks*l6Xbo$aGqM%UU}DbM@+2vc8AB#1HM@a8fCb@ zT1?HyX+T!klN|e(wQn@{+@=^{8vw}eTzQB+Pkw6mM+Ys^VOI=Se$VBjn>|k>X>#Xi zW&;0!KGRu8VARd^%n;6K`#>5e6Q5~i1InT-s^BfI`&2`GpGcW@z@K(vhpag5lV04j z%;-+#qL^LVZK>lvl=msle)aa>r?CO~^S!9g8}{Bg0F2)nIT)9krl}AYx<6S>vrU|; zq=PHN-LlP5brP;W3_IVUz_906X;3L)4A1dT*t?A(OuFYNkI^FAD_f#d7uks5pTBWM zs!V%!Qr`EdNRWE2;)O=W>qfZe)UW>g8d<)_^&rOBJ~6 z8}dT!tH2|1qd(qibNhUjJ$hC#6Z7@!reSvC*k9oQQ{uBbfBbzS#Sn5)mvUp!m8StU(W6RM(yFZ1LJ6;aY3X~?|w&0;~ z$efd+Ky$p*&HM|Bx#@%HR+paj37AgdJjbW>r~!i(73&33Pc1`ubIl>04Q&RF4eala#|#y0%7ltgnhm$7yi$ z__d8{eG$>@Z7E^yL@K*vNBh-q@e~-|37<-H$+(2a?h=MwUmLB$@upC*3ocdH^Y)Bw z-iTWNiIyf#6)Ff&!j1pAEOMf+CmvP)aT+FDvMovy1csKDC7zER@&G(rOA9F%{!&5- zFOo&K&&0j?O9?Rt4oS4<*)LMY8-YWyCt=5|wuS|v!K!h`)gujn6U9jEUNVZHFu9=k zrWo5IN%o>*a`b`g=dpAP*#03LN)`& zO-3|fS|U_?W4w-2R99?)mm2|04AyqW-vH(9_*+rT0dKGXOcGSD?BGMFr~9C%CoU%a zuC%+bfO0IAE9?n?Jq5<4JJ7P&NEs_7-LuVQebsL3oGiI0#|FN%`vG4m%m<2;(tVxnRq@q+>nT;8tv4*IzFG+~9 z)jPvj+YqHvAqs7jN`-lSe?C3exz2gcdCvX28G`8u@OYdsn)${*-{={+qz+DG#hI!D zZd_sBIxsUOH^9jmoJG3mB#yCJ9#d&!q7|wChN8||rOnK;-f+Z9NI=<`A39fbJEhDm4|Y65Htn~>vmcZoADBC(M8>BW z)dKiN#ESZ4X|gQANx}qYyDGsr*b-b0Zx!psur_~4jMM;?%fN-<{EIf`seSp3;!6v$ zOotLrL5mJBu6%p7091+`Xo(l5T>JCvoKDUFj=SmPREi#mmHtK+2lEO& zB`*u*tGJ((iPiyn(vsrBi>GxJ{qum6NuIk4gdI&VN5^ytiNcNrKody(?;WBD57p?b zoj>N3ZvrEDl)}d&n#=>mC$5WEEeu?Nfm~=T6bz2W0Fo z79^H8TLOAMnoR;8Ses(7{Jz+cV+rwrT6+NgrvVQ-;2IBKoNF-t74b`}F`_Ww!v--f zzxrDjU@VWeWdUA#=uRJG<66PpZr6Y7IWg}KLnvbFFm!*{A-=A&bS2|g1Q1tJ1PO<6 z64@229OX4}!EEhBqd4$Kq6U(F+Zlr!78 z^}aY6s9Jo^XBjD)WYud2SpB>vx#r*`wcBwX23o#S1u@rss8MABi?iKbJjMX?D2ljS zUj#yR&;Cj%t`vdC(`qb_&_$a?dF=PynIhrkqU>OBZnJnrxFI)u3#)a1uJQ`}EDS5W z)KUVkxIX9y>B4A+FO3N^m+{Z9R*nJgY(x6ozfe4=GQOQVTwxF>!?t)P5O~}NrjK7lnqst<00%p7H*8C@dW&s}y0zL} zFO7l*_?eP3qzn!7;hXUHHaS3q17uvKI`H1-_VexMYM_559*|KxmO&HbPJtjzYz!mz zmnIfEWXNq`y=v(^R-{s9ue@vBJaQBcdS+~I4#@oVs&Gcs^U*7-;-7`M6Mt)k$HkB8 z0`pdx zTk-INyhZ5(lcrj$f!+P^5xb%%3avSuuDV1vmx~y3z9Y5Pb^Rt+Weqw1SK_uw?dMlQ z5((ut9ZpnbPS3Zwbp z+*Fq!$^koI9acLhG=NOfS3UzU-|LHnUrvRLD4@CZS%Zq>hbGUquQaxM{F7)60essE z&>+2%N)Tjj2%MYYIC>qYSZx7{M20&I=9_`4`}b-DS#D-ndEWTfR{HQ?uYFU$R4Zb@ zWG9Irp?cjSpd*te4`NPsdZB6sEh9DoHlO@8E}sOHY7(COF&_&?ugrD{HI2%eqUP;T zL3V(6Z+GHMH+WnK!%ESNiPbRibgFNC-vwCcdydc zxU%7+H|yg7c0z2egIv*Hm8kBXX`G~=vyVX=K0=xn*gW$a?M=Mwpmza|J`Z#_<8+7O zk5{)Q1hVejMP2m-G9QY)TD>V2K7gz{kC?N$vGCx@AGhs?;wW_8Mj7BnE4gI=P)h*% zenRse9=P?WVwv!7Q(@Dqz!?VxxnetPRz{U8p!N8=WbO;M6(`AY+PHq;&&uJ%YiHlB zsq72rPyC(O_@~b}1lU~;5NaRe9-(@;C@%ZdsPjIBAMx7I!>tFuTcvUKQV2tqihjU(9iYNlxxiyD&GsQGx4eK7`+FRWI(XEm4)~@I zaN9b{6r~`adXQ+^uk@MZ4dT<+b0Yu9j}8E00rNlH(f!@~lJ_I?41mEgm*<2T$ix7clI9m9?ZRj8$#6@3$L}*O;@i0eD?R z*Nwp|Ql!pbLb$HGAAv9JO4>=u?*)ReCE?sraMRRp&xPWKr*Xw9eU`=GqW~bZ7^nux zj@R@h^suxbrhg@J*;z=_xs>9bHgq5ibU)%}ukqe_J>h#lqj#(~9G}vn!AbYUAny@# zH_L`OayUfF&_{ctmjWT=wUf7`DdP6mN}NIgT=P3(^Hb>fV6-zx_+tGX6bM+|Ngtp{ zLq$J7zzGX6S|MEZ0POH(pfSlC9K_m_>)*Y!*Tm!F{J#C!mHhpyq_P)Kr*>a_yhS$G zELmwTApyOA1pRAz^#>!-%>F4b_gQ58)w9Ma!9R(H5MY@z)u`;-O#*zzwDPqdN;(&} zhI|){?FnhC&+iMrKMs}<9P@OHS`i(`o~>Fj9RK#~$;y`Fw}lhmnl7QMOg?OP??tZ7 zDS>1XM$wZ%nNsV=9d2UXm|V!8epw&!rCBi%p19N3HC*V^Terkz-%Xi?iU_9(9qkhW zOwLM<{mM8u3*kvU!wG9GpZMgJ=2`ng4yXNh*ZR4~-#)tmJAxsBIGS)}W+wcxPZNv8`e_2%62DbWt>@rW%G&zjR+2mm+Py(vX+FA3PaaaT6i79)(XB_K}JUajU*OpVI9(vxbIxT$OeCwo-v; z<78cc={7B<8QpsnLVhhD;qk~d902K!8oc9$efbvRsYR_<<(`to+*^6#s+4z+BH z2?v<)!0-S~A5R|>Q85Nuy=~KPY|JULIiwY$JE3lqDn_6ny z%<)6S4`brFpk>u7_!D{-Ka4Jn7T&m|wxab)=P#t8HaS0@J?F_c=}0cP87~_YwjWA3 za`*3$;t51!j@q~F@Q=5sPb!uMr86{6V14D!d4S=HVPV2F5{5~q#m0g}l@SQM8c0{?Gxlt^X zRK2BrhkAG1wfbn~pDA7ONHyJ{0LOnH+rr&^U5c{I(_hpz=dDOJ_M}Nkzb&Fqq7P&m zxU6;s1mV6FrB)}^YMz^~&`~+vBJ->nOBZ{RWV%-Vk06@F3VHl_VIt!3)T zLB^$B5B}D9Emxz??X_H5@{`FsQ6Wv*dCjN)Dqj*&ZONHcy>%l{XXdu5XNp#F*{HKt z4Dm>LghkvLse$-9tC)bMGf8>SFDXOzp&0V940Gh zq;TTsJEy!LK*5(D(Rxy8AOzH;+ueLRVExbly^ss>8ow+SlJ6>BoGV%xqa$6-Oq?8s z{cg$47RYE?fj zaBp2*LgU9H_9bw>l?4s?cyQtjiGu;|mUfVqQ9{Fl2bdIk7WLid=^=LP1W63l9 z`J>co|8jF%N$fT{GrXnJ&cKXhHH;+{O)l2RTI3iZz)0U!kqT(dh^WEgtK>iz^YTB_ zo-r@e`uNW{$dR->6m^msWLYE<=O?}IgaT{3EkRZ+jK~Wz&0KCSe$WQdK5+)&H9RH5 z=|pLlxkxz=tm$fRHTccM0S>cssy4S=D`TU)k{sP)yxk8AaOpg`2avm(52m4N;T5DF zAgZAoE#!47fIlS@C2A2TWVkH#6!pj#D?Kcf5WXk>+g25;Jn4u)E70X>SuG_PqEF;4 z4M5vEB92);)5&Ydw26mE4_}OpPkSbFHTaiSfjQG+dt7WBCmK2wJ7`+8b|qRlvQ4BF zs&*^-O{!28=1!2y`z8-G!hv(Qp_L1joew?dLvQ!la!Zx#o1%`HbzG_P4m>RRnvpPj zQ~IUqtLfy2uUnU|{`dF|=<+om27TSaWkhMuLOdHSd`72KUU$#tO2Hm-{(ZB!kUg3E z@Po1%e%4x-E!!$0W!i`_L(C?88ZVRgAPC#DF=T&jhtU0Th654Q3yC25MAed(c#GlA zN0txFijMK!wK*_3hKx_!+X?eSGlt2m4#}>;>cG0OgJC+7bx}sc{oM<6y@eG6XB=MY zSaRH{?6T5C#cJQ(dKPX)+R;!lrW9jSap zjpYg}*mQ^>Dups_I6L8P=^~v#sBOnk`vYGmhX`?8Qw${x^NaF8O8b@0vHO_@2B z-6W}zvkrfs_`$k@ielw@A74V~d!ZvyQyk2n9Yp$et{Wra+%vM~fq;nJ`QlMRkb2is zq7GveUwyuCTi`G#=+?2)GONz}4O-7ln_2(k;{B$Fb?4yx$bTWA# z_6vLRj`@IkVvaT)yD*w1M&+z-_xD0^;sbJEq+GZ?8D)wn-bke#y(>6giMOBbd5 zhW@>U?x!^3R zXP=1AveloJR2aPRV~_4P_UgS~Kp)VlDPKC9VfccDv~%9(Nf^EI*|k3E)F+cw0wwey z<0_I8TCb-jo*#R_f$E3i;Ej*!z_-)C3+pAmOATv-de^eI*@YFu|Ava|Xb#-wPi6639CXtsZShEf@=5%V@(TXUst3gRobzow(Tx zQdgBAiO{Pot@Xxzv)#Lm-*zRvk^5e>mtkTUht0?i%F90HU$rGz#aK0lZ=}xP6>-}c zMj`cr!Gnhu-SlV>PGjnrLs7jDJWNP67T9956zV}^Rb8pY6sWD_+$Y5hQ?cIRw9|Vm z8Dm0XCJ%~&x{HE9Gg3Ti7!*uqmMaOBk}AKkYBb|_+oH7=`@0<;GJ{(#d$H+WHa*#D zvY%h;eEH$nCNFU>h`FXC`hy^PoGHFsZ%QKO+3S`kWRXVoTDc;SEmph~pG9T2y^x}R9z{$(69fD$H9a~c9PG|Nym3C?`rI=i zsSBCa_I3n+*v$Lgj21mbvnx@J@;!PmmCZi<9Kmb`6eDSg zc6wRuYEm}gL;+3mHz$U9Xw2S{fBnLtQ7gv_P3)Z({KXPIpVL;KZ^>!Zadom2*JHINy&M$ricdsa?_qB`I0_HiHe)Zouo)U^axaI|ELx z1Z7t8QoL)-y44oqMrthhfQ@}zC!r)vEIxtt&AoE-W&g1#k7Mhu!3ds{0rQn#_bCfz zqbI+IImqZ7>X}YMETw(ZEiHoG{YuFG$)T%OGr8=WtyTKne?{$&4EK<8l9|XGzDOE( z54It_-;Wv1PLB=}IWRjAnV249(mUh}^NzI&*%Upn3YGJPi7d4tQqrDa2S+w{CY?7J zVS}ml6z{*HsEssT9j2Eav+M`k)}H0?hwiQeOR%t%m`=NKL{)5cFm=^cl)IOv<5o%@ z5;R%Z-L!z6>$!IxMQL8xeXfADkic&q77}CD)cL`PWLOoO5eyrioPI(TV%#}NkF{;~Hjf@XYWIBTP`Ev-0WT;m+Z6Rs zdc2m~Mg;&G`EiMjmS{99DWN+R7(!RWB!WOy57Wp9w}ud6)u+*GVP5BFJc?jGJ)C=D z-23)-=ze3o{E^FF4Pd)D^p^eyo>>o5b?#=*GuXcNKQ3HnwmFcC}6k_Lv%5I=+yWI!t|>376Q+Y$Cj6UpAN`?bKHBKnw3PAvy&0z%t%)@-n4)fpq_7A1V&oI28H|tLVlQY)G!l}?9xax$y5v+oVi3_ z@q=BxmbKzXr!paE)Fie3#W|=yuH)Y6YUX+VXsR=aW6nIy09`EiXQb_@&Zm3ibAJw3 zPId+{((Gxm%zdzcWqsJ-Khdr)ChXCh7JAGpdHRG|dZw77bZN%vmV)p4(>b#ummj8g zM6-f~CQ^6Wdgcg&BsA%udJ&hWfT7Bz7)UY|r8a2VK$V1{`x5OQ@yea{qy3JA{~*Q>2&?=4Ex!)T^(TE}RQLT`8Py<}F0IFY_2VBy(0oH*22SlAgDfQFC;rhbeqc|2ef-=<%oMB3NWI zCq0hgH~EIwJT^-uy-by-%v_9-*$|Z@gY?Lt`tlFxM9|T+E$xMUQY~o9Uj@B(^z7K)9L3gUA<;{Z&;?w;> zYRjpd6@mOQ{=3WiK~~J*3g+3A`4W;9EyZfGcwvX-cd-~n?0#3c`LV4Q?&Yl8aZI-~ zZHe*ta_lNBel|Uz5|-Fs85AfMkv!}n6`WPa(Ig0<8PMe zL?%;=JQ=3q%Bp`^6wB0Cu*F!z7?DeL^*(N}PpQl-M$iY)Z~6fpXbHC0Uk5g&MNK7B z1ZKxs`r(P9#<1O|6DtNmqFj(;%w*yR56w}sR6rExq!;49lQa@@kxE|(gPIqacy zpil{XE50zSC19f}ox5=S4Kqt$kg>HT8aO?*Q_KBf>7{WQ=KElAfk!jLR;gjsQ~(rT z`yn9^CYAU-&Nck>Da!ealIM{=D9!FdE2db`$7?MR{0;bGvFNv!g3HHPz{AVi(aFtA zhl;}X4Bq^janzKAp&#y};n;o-oJ@nq6Fp;VY|J-m7do-{F!@Dh(x}LP|1ty*j82uN zX#Wj`UDa^Dl*>(zr6_V2_aBGHu~my7Ad}1?`d717{t3Ge$34CKz9>;7go~6(TrK_h z-u7PF(d$3r4^N)I({-L6EZI3!PWy5T`dVr#Z87R2kVg50ayeftnmo4Rvy{vb%J&1> zi&{j_b9NCp#cFj-RWK^I|YvRSnOS#2zaJR6cjdc3;xv!Wn+WTQ7$o_ug3DdH7pk`?t(fkU@Fs zi*t`IAty0r)5)S5vKUzKm_n(mkD$58whfj@+{{9qs3OO#a1RZk(L5dmIqxIWu~eHGB?~7-|cXs z_d86K4O@Z4P-6>c~!FCHAV~c1g*kD-)`J5sFqEy97)2~ zmgp-~wiee%7)CzYc2P%sRqd!kj%*2An?-dd%mcx%<9_NrZwkI=l+}{hM`xIC!~e)t zM_3+4-r4f&0bb+XLI~Tr)x+cg5={LpVt+@(6}>RuK@6452p1^BlIpoWEftrk5cqX| z&^T?eOW@ql7W-MX(ptZ8OMlScd?npDvhhNIh-L%X?o9W7o8iY8I(-`#AB3E{oywD= znzPuiooZ)?%e}<&!aF7>>imX+=Z?6jMhZHdmt?W8^Cy7N6YD)}LhvdfUi8 zsHDh{6K2%V$#c_K=Rlre;B>=?yEF==q@I85f*Q~b?X8esX})Z%qvJugL4 z^Y-TC-cnhyd`T=#sB26kc3}|EaC!cH^thY2)ZV;3m!!o{y6Fa}-NsO)Lu&=x?@tYQ zikE%8W$065!eUcog31#ZEzkULpUd0QlI|DeL)irpx#A6zQoa%iOD}GOZ~xghO+i5^ z#dxE7jBy3bXKnh%zFX`*gh^TpD8AjoLWJo<_Aw`YJCovWNK#{Xdv)U z0ducw+pF)dxCBX40C_v14ewO3);$qs$TJsuTEB-}^s-S9>r<2d0SWwCsw z7N^X2&s~_p`#r{YQr4foF|7MlPKsJ3?wuswJy6K{+77diLuBD2qI>)#jG~>1(6Ob zbbjnbbkE`+zzr9`)Am@!KCdDR;+oUVodx4;nNxX3jkHNaS^TNx{$RUhgLd2ak6Y>~ zB$w@zQsy@vd+46Hd_YFCrN*xg`BCs^U-H2qS&V-_zBW30Y^zGIQvHn+A0$WK>_=Ox z6V)26ul}4})Og#-zsDt_3a2U9pe0<`v5X#hhojEWKFW2)%HoV!OsKdI768ByOs9}2 z%`B8;kyZ*AMk(Cg5H)!#MNDr2V{MOclIO1~*37}P(`!a!x+9&Dmp_!?!+A;OxH4<6Lw8; z{?7I2M6A+gMn4|RWJps`yVG8&>wj0JuX;hj5uP_TCfTi~5K&KNxVGhfH1Tn?ji7~5 z;?;(v)A5<{=iJnkc`gFi$tAR4)y?kiS_y++b>2V3J=33hMazt?(39q({k*d<@L&@5 zHjiMA?t{BYyO+RxLI}>MWONM|6wdt_+TBdNtj>!F+K7y7aroFJSFaJ{XBue^s9kle z{2*}&S$*xnvfYgUu*@5OmYTSaXrhbR!EIeEz8Hgf_cIQg^G8%$t{>vvxT~8Djo~a&4mkgQoFt1KR6(+n_ee(>Vd#+8Uxbb!k>@4K(q<>Hh z$}OB60kiXxdO5xqUSD);0&21RMKe9UDSc=JcpR3`yNL6}h$^_b<_b8cnIQJO!^ zG>Qc%TTufP_5nN5T%#Dz!uXr9x)%BhOB9J}m^p4{khx}FbW+MA|97cbzaF^0g*(Xl za`Mvx+jVmL3q}4uX7mAM5V3gcE%dOt)HbF^bn6ZIMo z% zAVR=u%}7@OqHMCRaiCaE9F3>KDVWNT5;uoSXCgao%N(WC*adY`T zH064ZO?9is@<33k{R4=`#;{(O=bav;=^}pDzHc`zB8LU_X8+|sVUL41Rkyc?Y%@P+ zAF(LGMvyECUKdvkim}KO9D>sNSi03F5AX{d;rX=j0zX$jlY#dK9N)U4xx|S(;~RTJ zv5Fdgg8}y@yNemxSpfwX>@X~^5O2K1xkpthAD0FVpVuGkk`6NOUUg{|022(VJK?pq zuIq_v0xM4P?{UI8Yi;Mblj%WvOS-KV$&Kg<2B%M|#u?gQc#$|@t~)0; z<}|9U2rnK3b+_}kuJ3~{IR$64Jq+fjV5S2BVDu3>vFz@>y?FGwRh-J?#hci!>bDtN zSF}UIHN|~VNX~)sQ~XGksavAE2Y;f|XM_b`V>j(KX%1xYL7AZNqfp(=Nhdb-kB!f% z8h&+CpKep%P$J&DoUfLokYGyx)*#?pMBy<8bg4~(bUHtb zgCuy0T@TCNceG+37V_^8rQgEGR%1fOgn~q6B3rohC}{+n+jcAMPV~U;_5R(TX%3%- zO%3_;0|a~WxP&3yIE<>k@pzP7?6L%|2^h%{O8Bw_ycn+U5>p@tO z!7CGXC_lCszI7ALepR^qe%N-{OQ&k^&SXwZkGFUN{4+K`Wuw97KDei#TG|h2RptNH`q0{NRh^1$rs*JfXd~jK$x=>V` z4A$u_j9k}P1731!9#w16|Nm~qOmS$Lppz<-_cW(&_c7b zfM6jDqr;0aoBiI&U|}P^(O91mz0VO5oNIx>r}aGya1T}KCk8{U)#&WCMHVC`c1sf< zwf}UcxIC;(nNMk$a&=*A5T>O9+l!t$C=;Uk3STZHhsa2-E*#z^eS9kl4;$_c$wssv zlBtIH8V&kdMf*Jf2p62^_KNbSD;zuf=Ph@Vab2rPXv+F~eAMN0%k*9A#evdZyUN_o z8DbJ0KH_&|Bi+}#D)^s$sy#xG4}3nd3h;W6ch3y5t5`x<%wYpH{+?0|9(tx83;7|_ z7x9&NGpVE>tKts|L#=$G!ZtO#r;e!A1IOCyl3ppJnudqDUNfy{_0=?mXT> zg@9SXch2uba&{wK+=xDHNz@>zdI(W#)ad6#s0kxEX1;D{{zv?ykAEr@WVn0e%%tVh ziThqXENpXzn-H5Ggh#Q}1A_=h)9J4Sf2acokVjt>=)mFd#G-3YF zO2QJwf-g1ELQFdf_4UawZIaMsd%LtdpNUNmJ#nNK+ka@{(*$VRVs+N3Y=OHatb|cj zDdxS9(K>IT^(AR+=hpFI9|IB&5uAgH-we4Yl-;zVhjHlcBV)8EY2>OL{6ZS9)^)Iv zZpZiBReIzh7rGnB-`!itGNr%cXKz%;1`acx;B*Y4t{3_r=}@C1MdB}4CKS&0VaJy& zHTo?fF{>|UC%3{$k9ZBOpn_Xb5mpdP*}(%C;(M#FcucsK0p5JOzfR;beOdALn&6dJ z2v25KNax_7QS(@VlR^LMSOYlI>)UsFg z!T6157M=a>D808IzN9W28nqY@#>B|jC-(qFUAzXVS*1N# zy@}EvaExGcd^#%nD9aMXJw)S$q`^;8mjWZ&gPnBb%I_8QSK z_Qi#(Q6z`Q(Y2THWqPF-DFK@|ryZ`+3)0~Ju{XU$9cF3%R*;{eaQm<|_v-%Qo#r^q zG%%RxFd1{Ck$-F{Xulf&X2A(kNWf8w@tEwbqqiUzqY_mQd)!Tjs2W2w-_@TE{Kl;@ z!PoN&zB2Ar6LZywTEJ1g&cot+-0FXE$Egp~qCVhz_y5a{F9;P-z7-V0CRZXkMl0Ri z_--NO4Vb-_!cIAb2Gp-_%6x1mn9ooXHifBcG@O87wRA{_`!zY_4KJVs*yiz~ad!Lo zh6Q~cRzLb?t_L_Dhnv%tQ{G_z#WqeEJPtkRk$jwF)4aIr^6xJi`1Q17SYk=xO2gj_ z?K-+P?R#NS+pXv31ahCQ_mG}C8oz`~GI~T147imid;=ejPsnhIwIC=*-i!vBM!LMo zY;R?@j9CS_FvY*0J=_>~@NsvtOVbeBis;NZzE7Rlw7U$m&rSN3zWU-T{IvFeBCv=M z%EffP62NOM3~153=E6xcu^#iSbA=ewW%-W{5qsctf$6DjHuxL;oQgY&$&++$mhsoa zz`m)gtE*)2jnw&W#(Zn`&(^VVn0Yw%2t`@B&81ASVd}GUIODxqxW?`IP;WQ>7mWv@ z-^2AqBGYDMU?LjE5c@um6u`s5h*7bRPiN5a{$y#H$9)eNajQBasB^YPPep>Np z!S}`t=%>&>+D*mZAgUai0%o{QEmXs4ya*_TP(WQX%KA8d+8&yX{dU)=GP!#GnNzIs z@0_1J5MF(_deNv)YP(-6fqLEwa`-q@GCBFd_G-9X5?Zvwr5CcKCz9ckj)a{&V@-@Y zv$&(fpU}WV7b_)#WSxZrF74CvR(W5bBEajTu)orAcIT zLTvh{79*-lagXCcR@VGIcj0uUaM6PsP7u6i;>yu$G<*6+K+2(dqd3y0iAVLA&#%J) z7MA#?6Z>sl&pg~uGB{k=#KQVZD00uXBpe-havq>Tlk)N0NwF*VugW==@VVklW4{xE%VzoxXn}dmcRf{rbcC|1LL?4$-n} zf0{pX-qq6X!3KEnT+9$vB7DWt1ga7s85?|kL`6(>W?{fPm*o@caSjJ z{(7?TGc3CtPk^T2{XSWZTjHP5TAj_+7Sn)5z!jZ}v3V1aJ_E?i&@e(MK+<$7o8#~2aI<<`AQSq%}{f5$_0slpl3y7GDx zUf%Bn`@Jm>o;~~Hqi*GndzQ?bTMaX*Gd*%O3XU-g3)^lPEuKD1mo;KDY52f`st*jG zD7EgT2ZmE%6BVNA;@`8d>7G?OFf}c(SXRM=&{4Gx*OWQcmmbs+>t3BqzO2=@sh7lV zlW-P~VI(c5z3Q6C)4815$%8e1sqfQs@a}BOsZ5x_ z9hVK>K3j7&WI}DiGc%7*YPO)Q+{D^NzW#+L zy7wt3+Je^wF-#+2-NsC7!XjFz(6~xg^76bAFAv&)%P^+65ZJ(wS|= zE7f+}x|O;&p9G_7;$ibYd-tEf>c}1Rx6Hrk->3)UZFsiD7@vZDx{dkIQSx(|Cf|-; zIk?@h(Aovr5>;R$zC7kp+xwa3Pq$ksOy+DrczUwNubp;Lx}d8rqwR6McDRK#w1>Lm^zGTLkmYiqL`fGKmqkC@iMi*rVl3|X_dP9#cerg2 zD$6vuD$g0Sr{TtZu_@0xrwu=&)R|`d;iA-aTUP&sg$obzsyh<8TYj%*+4q7$LDGk_ z`ENm)dR|$PZ`cQpjZAB>EvLU(46mk08F)f(trk50RhlAtnlx}ME@ zlcrSL`k%F_El)HO)L?frozpd>`Qm{s{Z37Q)T`DSm`ql%zhj<#=4uY63N-S<^91zy zESLCKkNI+1(s7a02c*XeuS{p;mGf6szhIaamwxBY7vNJde+WrxlunExiVRigLm_-c z!4q0R)oBA~wT2u&L16A{EXH;jI?G_25O`taWf)0L{$c%`YGxlECre_B_-ceeOJ;+w zyXH1fAl_)KSg!*kSNS5uQti>C6Ojx~9bZ*XWkXQ#Kj;HXne2JCAYI!loY{AgFY3r7 z`}eUSSIcTJ&tJNWe;P70t*2!9jZjrXi0HWbMV26T@vMz|7fC2W|L1#UG!oyq9S$)$ z0aI7yI~PBME@p+-6S}u4bd#3M0O_;hG#PY^lTNc63i9z~{$NyVvuL@!7~=Caig5loD$THFlC z;}KYPMSWPG3#rY&m5<{Hvy?X7ipRt0;t<|PNpF0*QQK{52cFe41C>-xTveThT*D^< z5br`Rbm&gjcNiG|ZnmJ(e1FCtox|BNWPYN*?y$bV1O0HPNr|#;hZ-hO{B|4@jAge( zM^@AP@}N*zE>(F{?e`VdFRh}2NR8y}@%!!RnqGp-G~*i0!Thp9wW#4fg%SDu!<9pE z(5^S0m_D4ulLh2Hc>`B+aUXSB^6b**26u>Fbzw!nwluCByE5Y5kuDk?r2C1Ge@>a& z0#~|k2iK+JFE=|{cuFr1=!LF%bc|7@QPHtDc@Npqqj%2_O&j3e+8K8G(!~csbXCVn z!$E4b_^A|(iyE`hW;Cjl$fT&~_UTM=&FTG8*B)3|4tJzAIn12;>_q+-)O+?=^m4s| z7t-3s6M~Mq**jpi9d3FMRVCfeUH+zJEy%jlM#I$X9SMw{K$<+J=HH)P(7oUT1l50T z-J#qVrla@IQiyu-L;O$0S(Qsc2fpargv9l!m)yZ8N=6ZuC4XCb#%+A@qG)9`$B zu)6IF8#;W>^mm#!AaA!i`$@&CX&^cdz0XXrj-`dFdQmMhoqj~)%IWG0FBrQ zj(s3hwfp;;x@Ew%lsfIKb2-NcZzN&%7`;kKkSJn3qm>;NyPs3%#6<$8L?+^LrW z!>w|vj(QBo1<`hWZ??wTZe1zJc(3~2=y%uCgV`~3=#2%zkw0QN5pF zJQu2^DmvRx@5Cenxzt{15Jp~bOWADpnWoqt^<3rkgvOBtsO3h+3*5;h+Y$(Rc(;XA zqBGs0`A0wQcH-4}=bY4*Ucn;S%-S+#Dl1w@cNJ4wYpS>A?P)}X0>OMQTH*M zK0Zi6n9X7ZN^c(75@%Q!l>c8r%+xN){ zXvFolh1D3LxZ~$OD_IVEpr03KetfLK-ZgV9{$$h||43M+{A3y|!dndII{D?(H`R?a ztfOm7_++t!=Jl-a#aWo@48gG|IlWtl*SV-h?p4&XYEXog&No$^r+>Yu67xb5t6_$A z66%|2s4P5M4J&WAqAF+>->ocOB616pAmqKe@M-Bb9T7p$8mNiDt1-E+^&SC2F+Ze% za57D~vKrGlH`BbLS{hzR{vr=E{%;$*nnOF!pND0T4Nw_g3u$82E|Mpxn(~Q;u5RKG zkUFA5Ok706H@vHJ_^Bh+C~(YS7o=q7n|cJt!XZLLx02qzcW|=rHIbVF!$a^n#~Leu zC;G^7VHGY#WtZv3u2#$w?$@Q}nHG>zHDzD>XVrp=XO0naY6>X zuAog5<&rOB3=E&>tx5PpIs(H{1M|Y~R!~rygy+z2j=D@QWpo;Y^ku7sLO&VlXl|Hj zt$6z;CteevvN8N-zwJ3;A{Tl$_hQq>)sS(Av2bOq&&D8HrFc$NFDZgcQC`YXvOqtF zMJW7wA{+liE&(SePZo}*^80dkT$yAFGNc#aUJ!y40w-TclR)6a!z!zSb1}785E6`R z@KGd^HidF|M)nO@fyuE`-)-=Cs&-Z3z~h*lyM2&8c#+D%|j0yU@ymYnpIz zcy^0YWp%q^`oFQR~sV*3*2i5|g1CdfXyrl)8- z)G=5eAe~7_HK4}EA8>sCZhmbjt zOh2WEA2hZn%#E{^WdEn=T>P2-zc{{|ZRWDi80Naob%f?p%_X*(`~6O#xm0osNtCi1 z=DtZ$x{ONbMyXJJ+mMj@j>=c1noFfSQmJG=zklKL_&nb4bI$v`p3lSN)Un-5U-3yH zU*ql$F-7py=krlje1+-H*7pk;Eat~9yEd{ z%;zr`5nzhO%WB3)?VPhdo1A-$301|T63B^=yJSOxUD{@ccbXT8hJ7}@O|~9KA1g~` zc(3g$|Mr8CobO4!`}ccvx!-*;h|{b+p5N0#VS#UdwQD*jzuO)y#aq~S}9BT0Wc-6R&eUDSLqU- zO8tccn{u&Ao+>(>Y2LIZ+cPM-VuHHyTl_z4!g0{wEn{CZeHy6>CYl%%aYt14nSj;C z&-Q&Z__WdTS?2^MJRB79?#jpgGfE%6eq7{l>sc@w8Gw0--MpJTj?4N|-s-S=UF7!R zdg?}LW2S7ZQOFk)xmKud=ag3+TjwlT2e)KoI5LE!<9KXbGf|r~%`Ov_Y>e0IwIe{Y z4`M$IAF3oUA?wPmO%j4hSKr}3iM#nk<)c);V7mK+*vZHxGJiOsce zouiUq{PpX49@~@*WBsQmR)v~7;t3}+R41uQ!%Wm88B__pP9CozS~SjvkjW`%q~Yax z!sQjr>Ea<3nxXa^l8bq7zonbMz9E`MSMUI(`x~v2=$~$HG!24AZWFFE zBx2;s#5>~>eKI}%pJx1*c>F98k8MsWHMV&nB*4Gv4Sd+{I-PWmt&=it?14FdioI^& zjjr`|LUUlOdpxGoS}%HP9My|K#;ZzY%EMHB`4lveXCgH#$))v?zvB6tT`(|u|EAnG zRJ3%!b)+9P0FDlxR(%`>_vfVjkTRav5;8zWURMZTK$wdQC~H+jS{Y?0T}^F`9{}3D z2V$Y)fwNyU;!MSB{I_ZLvcAR>b#uc*a+)rguH&*`yg1s2yHR0ka_;$0eA&3lw5CbM zPx@0E)k&u6aymNc=30K*B#Ca_HLa8K7Jo{t-3)?0YdXfVFtLXcpPUOWp2o`uo4;TE zXmtFG(OZzmKUBn4F>DJ+!9}#*6~gS@S6~iS&k2iFY6_u23`W2PG8zRE<ofk`qXcs>ITUOeDl@njzyBNGDluC9 zahB_}{;I^F;@@RUg{?=HvM*F;dT2Z&HI;kMD1)gM!pf*F0ca34 z5FBlPZMQim$?9nd(ILED;6qI~a&H+wEV?Qp7Dm?_7BKfKP1nv`DG#JDpi!!wqGTmQ zD%WtI&G74a5tJB(-tjAJoj)eKDH)jMTpHDZE0LR723?vaD@(>lWml|cwb7b^fM%dq zeu5ImKF~1iJr*&inf}AXA(3N@?IwsF&LimtlfQNkR!%C|FJE}z3EP;`HV!dwU)BtwifyTx&8 zF7v&STG0LsaL&Zd=EPR@McF@8LmwYW%~hH51Zyovpt{rt>kqKDiquXU-!!9L>bGq4 zL3?tb%y3EAJ8pQnnd$b6z{#>V2?%Amy)$mMiEjR2e3ka;13PSyXElyBj<|(>w$bEb zpL3WE33Q&!cUwNFc zCIaipwCc2m$%-ufnc{9T6Sae?7t~;Q@si(z4W>s$NNkaz?AXRx6P?%CZa-_D>PKG6 zh(e35LcbETUDpJO;+xYGmZrDf`(rG=CZ^K$HkKpj#M&1n4R4-0@){4cv%;!qI#u!7 zy%2n0(?OOadB-olcEVVO@!J+2&wCV z@rn3jPIn$x_YK?h4)xhIo!V_WrerKyi`+2Lu)g(>-)zNRG|-Bf_r_EV7-!IsotG}8 z!=WGQ36H`^Pe8|tso%Y#OrSpfqBweSJ+V;~cvf*- zqL*}>P;i+5*k>&e4UiXoCq1w_GkQx1X8&(|@x|sNmG|dZ85##v1a%_lWkx z@$g;w!u7`6gNaS|^l17^#}i5F1(?@+|)76)m8a@T*>6ED;?t0kub7o+eQJVc0C}6nP+}N)Zg?f6e@R4#{{^GUS zyEjq5kK~$Jl3MpB<+e`+kHu>CuGd#Spd|E*ekAvsH+vQ{7jVdPy=!InTPMTq+8 zeYQ7T4vT;4y2&~C9`#UK*J;MKZsWksi;SP+IrUh@H!&9ojA7SyTv$D|F29LiwqXQ# zN_~aQ8H|vRWCF)S6nSp-eh%}3+-^p+aQzME9p%>98j$hBdK-RB&@x1g?rh_|rh;Uf zAtIn(v@(O(U;1>HmmYEn5(a$d1KByKv*RW_GN;BUA;)ZV zgZi_wG7^AkLYN?4UQ1~Q_Wo4J{)f(c==y9j!8bbksg&buicF#_s`;l1+z19qa)}$7 z*c`>`jhj7v3i{C2B=mktGn0|5+^?PNXWo06VW?wIq&pTopLUJsjRwXLM{%RbjgCdY zjS%;HGwLpYjeCT=VAExziljU(lV~J#wEis;TkX8CaxK95V~(ZN`>;s@Uk{=*`|svI z6}M7)pnH408CG&Tcg;qD&3{N7vR@(vv{i(3%^1OJS1&t%yV`wk^WRy|UC!2`8xeCN zd*qkalu$+E{m0TELqZ~>o-}sS>{NTmI8~y@6jZ&FVn$Wm?MM4uyNbYroBd6T+a*|{ zrLavBXDAic>m87eKo<`G>jd3k7fecTuek4BOV$bA{Dq;i{YdsbmK=;r(B}ENTTk%X)!EAud zS(bZGT)g07bbo|gFiHy{0?0>2P}E^$7hLT;_``io@f=}Yzlo4Uk`SsgVYAPR=)C%P z)f3(?XsE`kg|+bg5SxFga~q5FZHkyfHhK&O2&1kC# zB0;C{(c1m2qI1l6LIRR|to;naZDhBhs@`F^*0-`y`H5+~Xu0GVEMa3QrBAyzub6DS zjCKw%<|22|6n8`lGh*i}{$R@7;oq%E1~8l+m`H!+UZXU$F1>aw2@F>&du;y^uXmxC z`VT>{uFIGrkD_C4-`DC_;T0e-2``K5jnO{H+EK} zyaiwwF3&&Wvzh_XFYfd>TsW>gs|+OuyL;_|YMK-mAg-Z-uQQPF9%@M_J4&NdaK(_# zT3Zz3LX5I?(okoyqvbpmIi~cw)i*hBYO-3F>HtulF!KLh@$58IvpUt^q$bn#@<%|d z6IPN4YyyrD3wcy?+|KFZJlcpYV6(kg899$%+c=M6#wH%0l2iQeP$BUYdgk82r;%Z4x+6;`i{<|Q8-HK5YTmr?{n<0+e`$_06_)JT& zh3Yx)f!htHbyDW<^PUD0dXxKi)r6F=Ct1)(e|Lp`Qi}g4>8pt#tt}=+{Yl}-7ZiON zp<<~d#D7vDCXnwL&LtSJv9WRfkoAw2I2-b>uu z%m*(kykO6r-%!v=kU!m^;4PoP5!PXZxl%CNw^g4j{OTdy+d<3de20;-EF2Sh@66ZIb<-y`0x!exSxEpb6m+WcnoghF52tY@3RFrW%KP+Oow8uy1f5k6-rG zW#$M#y0aHNbkE-KiTwaD=kfb;6%kdN)3~DbhTAGbrr?m5?^J&iY*+6`zp(EoPq7p& zm=M*=59+?mM-gg=fHfYsM?j#*_J4XvrfQ9dwN5u^3n6S?)|JG>pH+ybe|N=3SjD1~ zl36R)8p&5Sig2O=Ex3Mp`ZRYCE^@eCOb%mV)!bonV$w zS7eAy%aR03s*6^&sJqz1>){3ijFwES5Jr9-W10fEuO@0V2ALjljCagi+prHNeHE?B z*-aG3+lJ>eBnSKbZZ+LG4z*ftm8d|FcW?7=vX&N8c}Rp7ZVQY=S=nQB_oR!m);BpBd%&bO zysV$5YNxn=jEDo7GEjM7^g=MwZ9VT^eb2nrhWI1tJjYu!^^V}2Qm+71Q$VV zit9`;c{k(W!3f0xlh;sAsz6aLMO^|ge>2hR6EV3=MEpD(LWBEKE7lH=O?(KS0&q!? zqC9@t+(CnO2=ynLDBu!p=)q!`Ceq}i7UD3>QH!4Owit1Y544(v#cZ)ChAH=&282?c38M5vkxO%`xiN`edf<8NJ^>pIEze=&gatp9cl(p>gcNujpx6^sJO!7$*V5i~#7jgJZI^o?Sy^inXdYDv-7VMS?oS zl;V+u9SEWF5VPb$h=R428i|=)Ou-Oj;7`j{l`SxLZOda3m^Ye{*Fx9GmSqXgw1RE6 zFbS-6)ACILp-vHb;G|>tJ_kVj6P@}Kgvs2gdH)20sF3aetR);Cn``X>)jbFM%x;e= zk|CB5xl;~6E}`E38mzzzgRxWaT>>k6@{37)ilT|A6{k-KM09W=MD?0@;y2T?XMP^K z^j?j0Tn~2aNR+o0v%TTM*%TG9Q_0j}9RU2gCJjy7iA6Q^(p9qBW_GlocbAU!|AOCLHwMM76AsN ze;h|k0m^EKFFr7i+&F7*cUmJ@WLXna-gpA*lXl~*a)rHC6&2||pkXEjSCbFrj3VHT z#~ST{7jO(+45KqIoHho2B{cat0=w-`!NHYs!bNw;8I0s4G#KfKQC`IsoV>5)`9u3^ zW2xxc@utXKlPSPO(b>xy7H^K{-UtQn%0CLnHSg?H5(|{XBIQ^NBEMa)?wwkq41N%V zXgeN41gr03A%7YA+_V7hAz=5;Z*b;b0HzT6rJ9bT$dY!Xq7vqex;&uDQ1J%K;b|g( zpzfS%!~0~yAU1R===e^j3r7daXEaK&w9?aTXKjd%+wn_nidTO-6wc@J_QmTL1zjl^ z*d1XO<^ot4PDAa2piw1&QVKX}Eo%gB8>lq_JRLL1G22)t3;p0(bgGp^`5Lq319288tPK%SB|?d*s9g5dusV$xHh9ZY{@Q*U8mxNJ22gI--=%x!NdvT_t#MSz z^Zfn0er!a3<~2=P=_?DjDi%+jrd^$Yys!ykD&GJ3V~E^b%kqUMBEH{LWQvHtD^u&% zB%jbEgLg%DXPvv-JJ!9keFIT=2s7mq#*BWdYv|>B^X0E*-6+J7gzNJ5TlS$Bt&kXu z(QS?3-rj7Owcj02;DT)?%pSD%YLT*`f{hXO?WKiK3pPT)cje=IGt};uf}J#dtfDrR zVM}ou-B;J$N>TDDSMRwesVg6nbYo&Le6bJ-mM6Sw?ty|OM&_79Oo<)|i2PU#jYmlm z&b#ga&|52*KvaKy@hO%A6odX2)cX~5V@n9Kh&-^Dcqiq+jrAv>&LEgA3!nmhZoEPJ zJ{B-qT|0$5KU{4eVcASCcbI>Oi9oi#rYu5n*Z&67(X zK!wUPi|yecIQ42A>1y*sQ6M}XeL$#c<_y%&_Z0|lh!kP0f*Y7dA(RN6wA3o4D$eMc z9IKCRH!qfNbc*qCn!m08Sx>$LD=a$g49+ROhwV6Vd9Py4Jo0i15W+nDC%y-om45)} z*>Mo?eE?I^dvMhmv)cl=@hMtA`T7yt`xddrW=Q)Smcq62MDKq114qolylUOFHzeLM z^P$$k6*MjO+3N~`=L}eip&^kN=Mzq#fxWBdcQGH-w8)@cKg*C>Cw6M9CH~&hwuqEV z5sn`fWMvHyd6M9#?!15oUr}CIHg{6}Chl(eYwC2+?|bG&TAeeKSB6L+vwP|Ezpc zFok?j>$GHf;Jc-qy=5QZWyg-(55)gPH;01JES!%rM*D0p^Di1Dl9geu?V%xw`*+JT zUpNpHJOxtQn6{ygHMqp)J@e!6ju*&Av9ceg?|N+BzC(=OI$+_y3r%nvb0Ay{XM*6E zL_psPajn4sDOCBu1a1IQ$N_}~E3KoK8h@m}UQU1GocY8cLhF?NhOi-CV9VYh(mf@1 z=uPg4dS~En@>F~JQHbzfH10&Q3y^wQUrH{JgR(9Nl&*o4_gQ23C)Pr+Pf8c=DNIf( zK-51K!G~Weq>RA!s$fV8w=iJ)z3oIDXTa>_7<@`qr9uA?6`t1aUg`kYWx{bzz~BnH z{;*utrwaIRl98PyRcmaFdi3nX!-pOOpjbJr?YXmcP*GSVz=BQTg1}e4S#71Hp*!wr z0pR;z&RjYfCZ7i-|3S%x}-%F-iSyB{H}>6lZ2oxS?5OVQ6MnH zW-9Sm7@XpzE&^{$VX0?MU5vGxb1AF{LRRbnzS_e5H%)*3^5u6H;Aqem~vPQLqZ_&yai!?ByeT&O}@Pv!jp??VP zAOx^Ks)jsX9fWj_=;_=Hr02hYX2Co~LX*q*lNSb%w4Oa;*bWt+n_tzoW!51Z7a+k1 z79rI;{-xwMdP}P6BB1q``J;eX#3YPtng5ZN3BMEN_GW$pVuP*-&cPb0MT!+>T`?J= zzt-_EYXa0#x@sx?p{|m5mQy0Ea6bOcoi2udF+jE{jKbWzw1(u7>AsVp|2~R8*^nG zP_0^6Twhk#Dvu37c?;hpoR zBD>%nEJ^mfvhJt7&FF$kLkJzX0M&bv?aQFPc{=QF9OW>NUcFQCj&oXW(VfS0T zr+o-6j;`0A*|>C9Nk90^<;=$KsZSC5j7-7{QQuK@d1KTRz4!59vVyhqgycGdXMuJJ z`b7mVJlu%BY)krh+Bh7J_ogp>eROy8LDe7HiEAgRu+Tv&cgjw>|NGIxY1H46@YTEK z+w9GbZaM$yaYWPNJD0k-C`d)27&KFHX;qS{%3Bt|t_C?C1Fn8mwP0ZUoPV9ihOH{v zSmUC|5IabyF~EK5XV)Tnl5n7dGZ|r8S=(b zN_D@I%l1D1@#4B!;TKl+8D+|C(iPH`fQcy{T$D59LK()rFWdZlcK5?aIxFukb5*~s zVb&ixdR;1ntlZbDo6LGJQux8K1=Y5C%xIKr&ES*ijS1&!g{LG6#6Xh9g3cA`#QKmR zZ@Y*0xFJr193;xI^^D%GRK@!`@~lA*IWLnks4(Rck}X06O;>>7q8DjLqP?PvhPl8{ zz!A$v&hE4N^dqP$r%6i7b0IF=CfJe4@VZi`>Ck^JqK55#>Lzu2pVUGB1U-OjopevM zcD2KZ57+I+w~VK#|f^hm^~Kd*CSVobFY@7Rn#2SP+QiuJre zM51yN*mQ4=+vUi&`-`G1yp!9iI_P?zXH*x4Nmtr-MjkSM$CXi_sp-6oK0V3_PzmhcmfjbIwHrxTZX3JpSnS*Mi-IqQn#;=9^>jhn`gGh{u)(X~ z`uf6Vp~ca!Di@qtKJX@ZZKpH54!i&R)AJiQ&Yk$mTW(V7GHuUuIC;9M zre^?%S8h~R>G?%4w|#B7B>W+o6kYmc*Rl>Gai0sQQ|&OapklJk_Hie@Z`zSn3*M*H zxs>?mZN1tW>B9x4W}L3Y{(GY>j7NmmrH)*(sE^`kW1dJNf5;%b^?4Rgktri85yjRe zKJdIo+t(&XU5<;v@&5Z1g^CSD-l+9njX4YXeXe3`>(`(!an`>Ail_GhB=Quh-AJGl zV%$Ql?2lnn26dK_isX8;i14W1&@Z-#-3~q$x7v$ns-eg=h2r{sBGeeu5YaWEq8+{~ zK1|SgjD)0Rq95bs2|M}(Eh8UHrVc2Ys*b6>AuzV1lf~dNKClWlaUX5-(OC@^2Q{je zyX=Y8iuhTh_zJOpUx=IjN+R$=KMB)7MxKrvJ6gw-5_D%}t`_lv7tb0kla@X8Jt)2O z{qAa;^%S?oHK|{H2*&K}@;P|XP{U=JrdBA^3Cqn>xmC%)b%ejFZHt+8tIHInVy(FNXB`l}0+kk5p9lBMKYbUI5eZ_B@_9)@Bf` zvZxD>88uN`uA~uyOpz;zU=`eXid@K2a5g#l9INW*IA4v={bquts@2RYYNPXH_}?cg zlv?B>ju0TiH&VUS<7$dplE94!?OxXmG8cCnBr;mQuSA)zF0W$145(n&(JpO*-&?%$ zA5Wx*I!8lf?^2iyy}K&nZxr_{C&;R`Pc>cP2GP-Q;s`W^I#xHxQYiR?P~ks+zzrj8 zH=n8>SllOoj##vLAbr?mOgG~78JS1cwpeIB8!j19Oxkq`>=lnKx05xlh|_0{XGno{7Qyl^ttn73R) zR30l8PGC*l^c8{RU)U{bRyi?w!7!IGwWHFtwTzA?NK?wa7kd4~$b-YLo2iT|Np^;k zp7W1Je%DkBzY&y}>-@%^u@((yZyT|x1x81}-G)1%SQa(5k@Mfmz`ZkYj071Y;y}wY zjo})7Ote~PORcmK!Jc#VSR=O8Ghy2LrErVXv%-ntYtMRmBZjF*1ct_EsYS}z<75RZ z+!CRE13%@0Va!E$6HGXy}TBH@1K!_`2#w4EJXF^rt#@Z4_UE?^>ULYG?iGk;5)KHl&73X*0WmWcLG) zv0nKo_yMc|LYJCE1TGg4CuJt(;TLyLsX-qVh`cOGV3kZUk3gMLyuDI#T$SE!`^l`J zz$qmxSxnYL5+6tV0~y3LU~S{sHNAboHQ55e8~$QW(Ni?dQA0(wb2K{1{0YJvwHY1W zV>x+d)*~BnkM!ZOf%e;aEskrniJgmLP}5$GAdVU%9!_-fQsPk*h{&nXOb0Q&x#Dd$ zefvXs{ZHD5hXJj!pZF(Fe$qZQ=(VO1hJ!u$+uaFs=O@LI;P@r494Sm++~0va*WwkZ z09lL&!3;n*l`PZW6SU7Ng(CNAcT({!70Nbp8mHG*rKSj1{RVG&@E2`K3Xf@^b%np@ zosnY@o-02H34ahB>5b)@JNk6y>Lu_GX#gchQVhqGN!zBoUc~&@Bj{-JrP?XHjJS7@ z`SNmAHA|9hr0I z+grTwk}jI%0YMmoXt#&%rY)7#+*Jg3uG<0L6-w4=L8zLqiv_f`=bY<=;Zcti#lTp6>BTnqHF} z)6@a~IrA-}^B_Qci#y1+UT$kcYU_X?=fxEO71JtkewYjy zv*Z8wyMz;M3F_SN>^Sr`Na^r5to?)oPq6vsKbjyrZq!XK3+AbGfr~t9cdPlUo71A3awg6Nx}O5YwRLy^F=Z+2Y3-Y2wPufDe~ueh3U0f9U^*T72q z(7R+LAXn7dRwyC!dLBs|NVh;#H;Sqql`Fct%xbqx<`|0au5}k#7g3cnlsXcdR#5uD z4!OZ*z%aC%D;2j5+EXeVTF7_)x*@HS0sH#nSGXmxf-XMYJp6 zYf)P#iehCtK4hNgjHlm<+tul-g=7|#g)Zh-Gu_ zyu7_hF%P6jP@OFwXj?X2Q1`JDvU>KERx+LINcKGGt->HMKl|dQr7}wv*@k@SuCC(! zX^=)2NxdF_-Wkbr1M~irXnNTo$0~x#Ia@8S>WRQQWQZ0SbFctK066a-x0#Zm+D?2+ znHDvf!mHudKW`I~y8}8kwRkigdtN|h6MynJ7g-db1NUPVC5j|<6u3FDN4V_e1qSsK zKxXzxevo%76U<9=tEUtd)(dah`GMs&gPr>4YP{8fGoahHai`4PGg^Pr6ZvEc)2s#{ZtSh^g{9o|Qc&sa_ze|ed zZXRp^tr&Kx)Z-tZ`h_i&FDoU*Z2|Z8ml-VkmXv`L)7UC~u;YUW9ql1*>3np< z!em3iN(q+5)}RJ*gRU1QJFr*o6Ylg2oT0zYdIlCeIFGyMC8`Nx7J21`f*Z#8pf4e=6Qw3L)tT?2`j=Dj-!kD#!S5fVG?NZFQizD7*82AThD#oP#|NW?M7 z-^(J;m~S{4Xa#b@ZKc&`@{<1|%uq$ie*<62L#0QEu;>_q{T#=(-8t9zXgqD*j%6-u8#fGyB?;eZy<5*uyI{rR*jDm*GF^IOkJRS5cRaKCA&g$kk zMkIa@ZfH9G<%z|OS;h+PNukWj8FX*8_Sv?EXTtUoPaVfoR~1gqU&l(g3Y;?0!^v?w zsQn=HA)mpU@Z|!LJB$3?DDMB@uAQ8<&NzU|t3<)PKsTo&f@rQ9L(dJT{|gZ!E0pXZ zGa#BBTT4XZd><{@YVWk<%FTPEEf4C9IM)KvD}}?_?*BokwLA@RyUY#pEm)cm>YI;c zGYagHL#f`E7EzZ*A;=E%hsayPOzzDbUX`-@aKT!It{6*2RvIfb9fpm5u6Xpj#HHo7 zkjgEw@!Hg`nX2f$c5d4ZLb;iiu8Ek2S>CIr8m2bLG>mRGiK}54{tAlI@HRuT?A{%D ze$@z2X<^}w@O=_i$4IP_lk=oIQt`pv-oyR;!vS?THlNPdoF_^1%+x@4glheo0^e2^ zL@$UVY^8E3n2{*3rq@iNfL(p?_152GLg@xEuhc<&=|%SDfXSIjTj)V^9zzNZVjyLU z4kwBfBXGs}(M4|Z2ux$Ww*4G5@FUm$SIMXiKmUa10-5iOoGJuOIoHRk8z{aWgQliq z-9Y#J?2%(U#S#Fd0Dv9^dBc)}b~(7dI{P1X>dN;};pOj7b|##IGWc49ue9f!yl#OP z^&#d}G2FSkCdnKFoaJIAm=C%5Z8N{a7_7s@^yQZkWFeQko;D7T**$vQ!o1D}K_kAu z+C9oS`K>k}l=ka(;6RHkZsvHhhC2^*Bfqi8ASLM+z}wNNZO?*w-#8nf3vK8~;(qEB z;@$-2Le&q=adEI$TL_-ZrN>kh&@^NW@?2q1c@h==c}>k~QoD<{uE`If(Fjsx?OGiU zJ3aD{CBFdj7`Ld~hy(<}+o|lHqG5$S?b!_e&Fw9P?QG&ioT!=7=z;9p<@^h<<>8J! z$W*KeNz5r$#5I724=TFUL+ZH>UG16&ghC+_cwBP47Xjw6T%v!gY9O~XgisMeNA}ntlj@5{;3i3; zhFx9QD`Xag3WA8IHU^me_+5hCejzTeEH$Up;3z7eUNe#5Bwzf$Q4QhD-nqc5K}muALzDYSaMFC>As=9W4al_QRpDSfHP@PXyb$1mLjOG);s zl!O*9`>;2z_zjkPCw|)r9}QUm?c=&r2G$?p978Z?i+_h#1w)k0xR^21CVS2MP2JD4 zsY%V|8z?%9i7rxZz#Oa-J{x2Yo5@o26Ypf30vFEQ=Y3J#kiVNEFyO6Su=Sn{an0Lb znOr81L0$W}Cq8vm1*kQ2mFjkb(?dlKu8~STv|`syd_U2Aq4aQ_oP`{m03WX?Kaqbl z?w@MWh4i(7t1@WdAtl2_d7_RyF~9fpUD)2bmUeDS7LSquFu!o4zBjdnZ)HP1R-v?5 zY|DpKYY${ZA&MNd$d#6dkGI`a-f)JMSeNJJjqLe1Kdohsr(G*SHP$eWXxeviOLFxk z#oSGV>Xt6&)b820S&EkVyaU~^)oz$~dzG`C=7LD)c75U!;7-3w{JXHKzt0rnwCtj< zDNtF5O3L(b3w0E*ZykEBs7#f7VLNce)hh2--iNN_=|cY7`M)I&dYrb3;Y1f?+2Xw| zMPI6~Th75Ph%Moo;v<4a6ZL%O7&9QZSzV%Tt<4oU$xr=zKA8sbK<>aR#_cIJ7jO-J zU+3oKS`dq#*&R+PMBOofQuw>?M9lqNNLoF_^AFJEO=Jg&OSw`kx8>8mO-1^@_c*p0 z?UN&1N>J+h!9+rKzx2(+N)#@cY2um_fR-0D-#x^YC2^lRT_!=j(i4j1w1P+8rPvaiJ`w;&>S-fAlg;*iNb zS?0&(OU{^KYu%8|H4l?bLW$ObL*#7IzaQ01REs%E~166>nMf2Y;JCjkgM4-6fm= zj3l<9!>ki(+h+zVq3YVUzt+FG8&tdcK69(ScquT&d$P7xdvYuTW{3zFL<+;1(8J*|At=*=~TABeR}5-zU~G zf{zC+e1#+Qp}W)c#**TziAsqha(-4Oqa0&OS@|aG?W3v5E6^uy3kIl~utpH3VxNLC zci*0ti!}=)RCGcYx&ZR_%YE}?@_xN<(n{^yp5Zh3gG#}Mc(+m{xG1UyIeoejcIW&yp&W+uEJvvF2;s`B zX9(f2boU?wrOmzkqPPuVNb{ObENY#Bn!O<{E9=P6mVF&_)6@f>&slDBF8fw(|L7k? zw8K*OAS_bdSt>nldVBugU9f}C`e<)g?R4E7#U4Q!7f!;zxZbfz(%Usi+yp3&Z-Bv6 zA7wn*iCsBv|H=*AGhdC)(d!w-%02%MzH*xrRW=^b=S zuAJ4UVqv*Z-F>6`$D3oDWTszSEi%b{$S?!O7PmiYwL9;|+C6zkr6K#nMaubMaai>F zmN{1(y5Asf|Lyah#42pU`$O`e={@J_gR(=fe>K_bG0YjnJkt)=L*^!3fBEZZ7}|<8QTvql$TZXAsgb5IFyUFsigGB-|hW`Pe^e8hJ>dqG9*6Fd`?vQhmtkZr(aB~n1PoC?lb+~Dxj zLB0-Y0fxTUa~GHkGH9Ve06T;Nc)Zze=J>1R&?h5{rip%2d;9)?%&P(!d)|7)h~IYV zKf-y-v*>s4p#wQb*D?4X@a5WGq}5Bgu3@0YRQB!q&*?kM{kk&dA@En?jc$B)kE$&!_vMZa z0;h*v6za{w0v5%DiIj{?GzA{(=cz2PZ-jOAs^|6>={~DC2scD*?o1<8%}seLFE|F; z^77;|x>nwh!W9YMjaSz@7ZDU5jp{l0FR}wSgHbMd zy-MOj67vja0A%do8jt7WL)QT)z-Jd^5xW1i?ygbtzIT= zQ4-uE9W}z=Gmzu;3H`6;+2ub2E?euas1)J(3fMpRH%>V7#G5kuaDw&n%ws;ux) zG~}6!I(bm7g3G)(+2&=J?$b)GlO5M`R}tjMpdF{hYW0I@4E)|en*?_7VI5g zUwFc1can~nbzcv5+9H4K#Ug5xavq^w&IcVIXP7)Cd=Zw0OVXYfbrqfUZZ}=?-1Tl) zlSUw5L%XV!y)0fm{M#4gg5#rudZyl;0Gyij)3tUu)*K)Bq_mmn^&QT+`taf>*K7i8 zonkyzK6`^`1)t&``cu3Obu(|o2_Sbg`I_{8Pz~>f9+tyH_)!Y!Mq4_qwJtq)=$EwT zR^p1M5eSTQeZr2{%JqBdmk_sX&`*AUTls(r*Ol0)wTF=aQkd`s#K}|vv>SB7g?di% zsnv!Dcn}HEPXM}n#h}G+9IbUto2}03Wy~;s< z$U(VaRExf1NMt?TRMN8F$(yLN%tFZ4SjA1xEA%oB0&>O$JyQ?3$uYk|TB>f7kuifzAZ0 zOT>v-=fP$6NqjSl(ao9X6RcXv z;@Cm$Uz-OGIXYguI(tiS$PAv2Sa^3B76&Peldp9e+Vk8w+kNGFFRO!6RZ1&ukplemUzOvkCOy4CxQ^pNlM_ z;a|_8{udC!2n(oqet+}*KIW6VRJLoD-ub^=D!)IuQZm>6TH;6K2_o2KM`n@*Yp-7 zq&~dtEV3L&J+^`8VDliab?YsC*u;^?`RTmpHoTL+s`W=hom6-S^%-!`0L+iNEx(uw z*5ugq-=cHp+LR34iHLgIK?JTYo;il@Tpm5Na~c9I}em03HpSCi&tK+BPs z?!~>??B{K1$hbJk50_~ZH1eomoh}JHBG4{h?S=#?rdF%j^FlTRw)uI5Z7#A-hZ#N@ z)FXR${Dmqv7e&1hsXUj_@}5$2>I_c|QVRmW)Ysh_)G{2EtU42ycJjYF|2mBZ-+9K@ zt^Dt)SnD4LU&wr*Tc;5J2BWYdtZsiu3uB!G>CyON6aN~Ibl%Z4?_-3jnU(=1J;Cnz zVy5N$3hr#=G+dgVg{&$4U0JE`wx-OUVmx-o_i&YtQpe}S~-g}k5q zcv5zuzF&XDK>qn&h?^zd9QoR{LW4HToPR^`(!sm2BzagddSgEZo>*pC4j2+`YmV94 z694-icsuL$mR*&JvZQCNPYvG8(vv{(;#h^jShw2KJ6E{8__4n)2Z-CfGj2C(Hw_)( zm(OI1yVBHliCFM--j2U+11b#sM$gqLHP;_At~;ViP9C>V;Q?gu4ii+QbN}2L>FiTf zTtC~i`4lHlvfHX3`D2oPf?%=5{jwfI#3pH$ETE}0XGA~8&l+IqCn)VZ9Py>`j zi5`_8xufaC?s~DQ#w3+zM9)-E!hyGZIP+(4$b-Q2!N7bqrfFn$W13mq?QsvBPx(Wd zUd20udRmC=4Rvrlt~s39ETK_nfjexik)5Fok8lhOk9}IqKWoP4l<;Qhuw*v@n0A(? zfjm=|x8o`@-fzF@HtN(9FQZg?e2+HBadWZG1_p#NH$EE(%{vVPfF!1rZhYPw_D%s; z!~Q%#Un8>^^hfRoWzW5&vBZii(5j8IG%1UjR!hYhyA@1ORbeVpaqiKv*jn&DzY#_n zK_^Y-vGj)eiMGwd+>IqGQfLN_JPO$y_|Q_D_KE%8if1Nns(nw`)}G`>+15t3Xo>qY zx638*xy>1G=N50|8#*YnjTeR`;5{U;)-TTW2V2bf`eob^CbIjrzx> z`ZD*j?QS+axwy~iIV{6f*&*LJtb;?SZJem3oY(RjnR?euaPql9LwAHtU2(#RPG#S^ z^5Qz`LF9gA;bluAe9NyRV*2XqvI=bfR^un77k83=$Q|f)_-+Xmz~9)A`RSjNY9{v2 zZ`oPz-5_Uw1J3iyf0|u@&LqZy3UG$1)gmTM_jP=FhN>?scK_lQe8)2NV32blR!mN{ z0rE)(a_huBgxR$8(oCy5xi3{a_3=BUFE369?^kWV`_&S6L{i7{Nw`$ZLWSNiUw4dB zUBCAFne7|G`1-FNf`j9&ig!w!U1m&QnI`|bwA9ytRP|{^HH}Iuq)?ol-!OWK=3)rM z*?WB!Jwg|8Lr=j#cI?JsP)}6=WFMqr}$TxbGs&^bZYAf~(#D@{ z%bia-d%Z;`l@spl3cAut6>KTd&a-#hqrsu}N~-3Y{+qjyP)<(UE$1jO5qfETP>HfT z?)Z3`VU^*?^+yf&XA9xC9KZoVsQCzY$jcaT({x$b!|uapUF*3RqV48vhPX8^^)HY2 zgb;0SoZbImYqVO`#p$p*SAE2^kHgi*HXbb#wwy@OA>J zJ3x=I=xFsOhijFfZoZCT$nML{GyvAJM=;|igMF@_`JSQX>bF?f_;f^$P8mqP`Z$O` zZVeON5ZBTIH3vb!7?XAFl@19gP#JpOpwCRD%_|+)7?g;Hpj~Eju`S9&Gu!h*mi1pG z-`(dDiUULrep^X}Yra|CCS>0#RF2|9Y?cF&YE6})dZnFy$tkuR!W=5fc^!8Tphi4+4?&w9i38}o5ogH6i1BYGS{D4mlh$QITG6Xj*uZ8gbLrZ741y| zjW^$Az}PA+N2kr`bI#7HH{^-8!$53=h;q))%gH0hP-(*&dyt$F4d1pE147S>%XFb!P-7UMFM+c-8%6fp#*8)R81W#mNzq}?;)HMWWYU_?U3u2WAM6YxYj z#fE3}LKY{bz7JkuLcj)3^@v8(U>TLwUJyeWo{*t!!`7oEpLu)g@fEw%+4Va za4)yD;IL1|Wve&=At}D>m7~~_AvI$&&IiI1nX!>8R(0vGx}y;d{G~osd`E7Ge4hZ{ zl(DCwDFj8{_=_~QW4=r^o#w*Wg6`sh-c#Gw za`1^vs}$#4_m06w*KRuglWHC!ZRcT&nH0qksM;YhMCYJ>YtFs&|3bh-*(r;9H?^XC z;>x;`(xK>-f}SxkSA>bP8t(|y>4wU`8UJ|ks8 zGDvs!$LtyF1KZ98aPGh^XJOG(C=cw1NwR^jb+&8StEuC!%SuE8U(*CcBt{HhkrJS@ zoe%N1PM3Vi#7T(JDJvBPrwxcGWw(ZK#|4R$_Nwr&`l2b zJQpW(QumWAQ{Fa8laOr?F29S1LF-cP$gB-CAG(LVx<8{ty1DQby(UR8;Eq+`wNit= zx@QP}_`n^NBGFj4W7tEAL#=O!Ij%7^A{toMB|l$I|CY7j3+<71r5nqsrhz9RCxJcK z9gVjoVoXmqy~VnJA-Kv4ho)10Wny=7 za*+2{fxyp~%7wkvB0*M;*pwB<`5fX6v@%0(3!Z)2v`0YdTTu>w^|R2#cT25BhcY0^ILZ-Yt5KSY^FZ8dfW>DRg>)k6gTOyoZJCvL#P;dF)=Qkv`H zqSzGW!lS@RgFyDWx*8I~07A~huI30cpNJ(V5Wlg(sMD2_f!7z`CLI4oMAdv%^%mss z#q$e8EXXpKj89LB#3U9(0=V;!p_9^U(BPN_Y0ZZ~j*h|R1xzY-%R`c^hIYAQQQeRWm%z@{4pmhvU{NLyp!BCSWX$cnSVhe6gyA9CN&;kC50%EULi1TTpMWLWnCm3gY zTEP?jWaVV^1(|zT@ay_1L?J|^T0wLiA_B<_#AIStO%GNp{Xlx{n}ZjehyO_M{Uw=3 z?L?cIg7&whngtd5$94M0h0i6SfAyz1Y=pm}dGI+WAmm^;)b!^2WM@7Ly(ct)LlE`~ z18Gel66*jrFqt%>n>^FZv)Rc=7Z3~Z9Faobc1=<3qh6rOT=PU%P_v@jliP3Ved>3= z-j+o)Wmc)5MYS`5#0)WKpJJ;-J_jJ5N3tQPoygmy?p*JQ+|wK+hlAWAq8e$y^=f2& zsfV0C`?3cZV47b6jqyJTsu+XToP1ah?1h?e2?agANP%-J=c{S`7hjB*=^q^Cp|lj5OJ?tcCFFhbB3q2Ser3 zVXQk8CPNl1%GW>MLnPXYkX3kfvpe$w4wcXUGbw`t9 zmD^8&1UK-ptH{G{k=S~X`yrf?-#LlFEU*kz3^l|D<_ns z=aXxDP*frw$vt>r%6hakhd(Dg01>G&b4RjI!l9xwG2Q~J;j`nSiyC0`E$=Li!gTn> zewNN-Q!tYgwyB&qK9tAoFusyt_}mJd#3mNDpW=^a1TBH+8>NC1Fd?JVWy+b%cKj1V z%6O)uB7vbmC^m{C9bGl(tN}~;ULto_EcPQrNY6ba?*u)eo)9ebcvtGtV#ez0lawf@ zT+;-Lskv3%s3GM%-aIfw*V!=*Y~8Tqj&sHW&k@r?orh5O$wv!%gP^IQ_pOH^hx1>Yup2PNuvjFN&GnyUaC(E+0#ECX8=J-L+3ar}u zQouwMR3jWT9d-rgamYdecq}}a=NF=e&Sy&*W=khA9i4yu(1 z&tF2cpKRIj>+x51CPbomwZbBMu$p#gW9l+F)aS)|W|mCGiSS*0Z2`S3FvOml@F!!i z8O&@1?+1Ye(}ErQ-~|05RD4dHeN?A+BYG7z;IY^0r2(0+zrzS92$DY;i!Yr^o=Mbh zo%g@hCUlE>>HQzK>fk0rjY@}v5Y&WdMv_s&`nCD-PyB5as>p@ zh~Ndla8gICuLdfSqML2I_1i_!Aqob)0a>a+I;RMi$e-e(L<|jrB^9;)i7TBa8ScOO zt55njzZ1+0w0sk%_@+ZTHoaCj)>%`U;~0Di;Z?$Kvl)-E_p9I}){8bLgD;Je-KHv{ zgHPd_E^iO#VgQ?u#g~&}#XiwM*Zb(3ziDA#q&+r-SHsw_ReO-u(A1)^R_KsfsB~n$ zGBD0$-W|+HMiG-@AKlTqrYxcS1)Q}5FH~PScm_3B?v}q_zUDkWZuRES#Lb+*l~jJ*@d>=nO*+wA^D;rY%O2Ffbu<@MtiyLH zwvs(41nW?KuWd^@J(mdP((el6(!Uh#Y!Un~yL)pq&<}o{3Euf;pDF~}8O*-s5_?Kc zq1cL?gyV5cvU}kD87Y)o;Pse`>OB&Y-ff7-kO7CJk6}teuIlM_AnkR&U1HTtj?`uS zV#xrM$&|BWV69!y)mUdmZ^G5j@9!Q7RLjm${Ps9vdg`jcL>7Nsn6P21sZ!GP4_r!% zS>*8E8&gUHE`JGZEiJ7(5!(%qz5mY#{X0j-=ME@&x+}mQeFuF8hC2_NK>T+LD%3;N zDRwOH6OsG3``y1Ag3ykoi*9c_3O*1dKrXtJcKJpOh4tg=4G8Ueo5gkNqo;gZ^q+=D z9=YHhyXGpZvn%RgM~;l3&UFE2F$^>jnt#?z0w{0sQ9gp3*oFULDs84q|#b$+5i$Z}%p{)#B4f zE%z(dJNNyfgPjbl(5hT_4%$-|Js%@-JqMwEka)8-veLji=uEo}#W8 zk;&?3$55m?j+#3}Aq?48W?Oa)`O^*&ILC;0*~UB;+7q&qEH+=*y^eED76 zt25xAp&R~Bu=&C#Eghb~=J$Wh0Z)~I`C+Z{g_B|v7go(d?zj%j%~^2b_R)auN4j9= zKk;)9(3w#)=Lo_)VF@!1JmZh4oge*Jee2}$mIi%(xfblZ zfgPTI+da<`BG{2ny^e^Y2|zj0T&8ro*uy7c$M%E8ppgDGnZPSze8|(0trz^Xm@X&u z*tm#n9-%B;^WEedlPs2H&CxM_doQg&9nf=gnGZ z21akIKm!A-m&f8GW!_9pVEd&fb)MKt=8F~97r#QkF+Ybc6nl68e1pwRt&mx>zm5pF zu7FFN1VwTS&vkhuqE?>fo<+Cq1INtZ*n@?IgoUonN|>1~}1u{9|<@+t^R~?<;jA#;BrW`ru%UFs(&qz-}a9 z`zh@b*eP}FrEV3!d&=vlZP~5+@OgFW*OzGA$3pb0*h3$+Ti?F5lTk7OGiyM~vH!k* zkm&r?gq$B*0_TL=g>+4y`KQnFj@~}<7X5NgWHMCv9NNQ8>ODY!65l}no5|Nc4{il~ z00^N%fgp8DT@w0EFW|~9=$D&oX3MQ$;XvoD1Fs9Ep8OiaM>HmQ9MNG^Tb`ei*wFF7 zO)S#VXAuOkCwkziv*?~VkseT_!-^ggCqA&gUrhqQK$IqwvPT;rB1!usdCmbcI$9(OZmXL&HSdZ9OtCbT0 z*I(XTQQ*EWJ|}#&Tj)~Sa&)@a+S#v&2?3!~m_nDN-Ms`tx5;4|ScnBr#v~L6>6yW& zqa{S6zO9{|KX9V;TdX1_cJsjO&9xS+aI*Lh{YPk%=&a=YhX;m9o(*RW0-Tl1TAo*c z_Le_U6Jo!mWq--d>?(YZFj(cp9s+h`*Lm}B0#st|kEp%?y66-P7m4GUJlhY}uZUyD z$5E>$Lb6d!PtZF4otIoS?kZUe3H%Ove?abwMtACOp#Wv|NsVCVolCR9nX!*!{sjW* zeY%m)_2>Nuw$RHfVr2fVSbo&|#qQz9e(0VU;cGh!a{eyl@IB=GpR>onqjaTN6El^L ze9&3!15xxf^_$x0Y3Q7@j zrV+(joC@-mQF3^3Lw2q);RbKX-?6|X>JVc3)6^sPef;nrvTjS%8p(+R79QU&->Dwk zR=DrZxp0ksAm?cRUyf8$mXzvd?aKEno^%lSfOpmxU`z2&N>!qnb9t!;qebqPe^u&C zow^h8$4>~^=-a?=&<3;D zcbKZ_yL2eDB+rGf*7p&i8?)rE{(m2Mipq3dg3?py?6W7&&Hlj+ZgMPt+*`u2RU;_I z5a;{ZkC?E?RsvFq$+>;1tYTclr{*+p0Z`bq>07$@cSQS3+rJTr-R$2+#4h`d>grw0 zG6IVkQhlWvu7#_wJl#~Dl@O3|;a!r1>puU4)!>r%+p>l{r9Q2u{;Z&|o@(bul<55z>PQXc2Oy?OZR7p!M)jiQEqWIFdGZy5`}bM-3Lc3*tPvn<~)L(+## zo!=MzUSOIWF(~;vSmBKlYN(*qg@=?M%a{Ft@fV_JNQ(wP7%2@fSa_y_b92lQphLDA z1&E<5-0}PtZaOw%liq+`-)4tAqaR8;Oc#;cSk?agu*K~vR#L(MkI*<~=%1Z*_qRj7 zs@!6Y>tDZkw;*w{>AvGT7APlr#ogd?I(@x=7cEkAY=)UNX;bQFzF@S7+_1oMSB10! zGObW8J>#hnSDR#IyQE98WVWHm8xbJF!(~7|*lAjf!=)>_hBL#~Yi!YAMpH z(7Mz7jw_z;fugLK<3E+$_6hEfe3h^j`ogEq>;pF^Yx@0V@&1R+ov9(|*YDA_IJ8A% zgwT{X{l-=nxm%cs!?|o5SUq8H%6V`rOe@6SuoD{ajO)hkjEN#mVdW^ZC9jxe|&jo z>!;%Di61Qw`6x}6IHj$M=d_1QXZ^6#JJf!4`#?~TWYZ8bSEjS1yb-&vEFBKO6dk1k z`LX=8fhQ6fCH7lO>WV{Y$ZalEI-)y64$l<bweG1|O9)_>a^wP}j1~iE};=XsFf* z9m);d%jXE-^J$WsCgbe(mQ3TJhK7*3JZxWE|DMHPLN3dTY{gFqf&>;SRBWKr{mx4i zH3{n|Ln4_%v!W3(T});*q9}%E8EFlPC0HL&sT;adVQnV83xQCe;sA@4yUaGuNqt9_ zoTPGJ7O4fBTQ^jsZfG(dHmUxl7VwC41zW#<&uN^cnzT7{LX55D4m+Q}4ou#r$4ulj zr3@JqGmryV$cabtkKcCH42Zk6(Ldm%1o;zPsdF?jfq>r3P7jV~5ac|9|0zw-oc2WO zTVx^Lw`ZS6H_>{#53Y~svGxRphn;^Y?e0`JxqIhkQpuPd<=&1MhKO>cF5r@R!B*{) zd69ANaFa2DME=AGdx@^aA6F(EO1Dbies^s66Gw_B=zlfs1A8P+C8j>Gf6u} zsHSoXoa%f9lAD*J1MPCdu<*Tp+`S536sd|+7pK2inY&}AvY6Pa51Y2@+v&p)>drpG zks^ral(i)pyR^=c$@dZ}a@xjd0)_p${P_Yljb0;dqwNf2=S5zfl%1t4#ni>#r*9CW z`+G>!;Y2z<%MC`*g~Bbg3h-AK!aVAfv%qqdCLVU{d_SuOs+reLN)g zRxZo#D)v#E&FiD9)c*n_rLS)w_iX(w0NiLWg$&xtc1s2xBmufWuR&O`jx2_d?v0q-FMsy@plZgi^{awXUgt@>ij>K^p*9WW>B&OZu>st08|IS9S>;uw zTPsmag*t6bi6GelHP%IQgIuP*$907>=T&~{``JnC#4o>2+c}3F7t1@abDtnbPs5l_ zUPm|>uI792?oFWWRK`y=%Hh;pH_TDjCfmJrseSzBw3@xLf_#8rBVi#Gkp`FgeKM~_ z!X@Xr{mf%xAzAA3nmF4zSoSvX&h>+wPK)uoDCzZ;_Mo5zlvNDu)$~PwFAMySQ3G6* z9Se6a{y~0Ipz4M7;W0&&H}=nOTrp2mNa3to-M2(##hLHt6wXRcer|y6o=Hm(p3FfW z-kFVTo@`;%n2K2TXCsp97Zd}94VI)aGXDm(*R;rh%bm=cZ6VQzS8fo7hw2WdsR+7^ zD|b~7`7B>U)v(=KoYgXmW`3?(>OlGwL$NS^OqyV8)Op8a6hzA6Bhzzuyz5nslxrA+nI0>@v|W22 zf&P!iH-K^uVv$-Ge^}DoWG)0dFf^%qwa?NZ+_KNOeTpY-Zhzh3EL33S%95RKp8b@7 zG{apuM0xP_EbN)O2|_#O_fuiR6HgzUYUWHyM08Q|Q{~?)&2J!$a?@j4Jyf-B)+!K` zR||Y*Yoy%5>CC8ho&E0(phU^_0qEn^FZYHlaD3axn~`ssW$Ds{u$GLQrMq49e}8p| z?+`Bh3ko~#*lLry0Ex9II;k7>U*^2P44WRWLCTodv7gj%Ina>RE#P>awHvcsUo`~# zf=V8=xOebhHrCCQZ~BiU#a#hj^8;n>d-lKn>G$SEV5z~|DyURzeAl9#u*wtKiB5}2 zUTPd&>iOYQMAgC&0+k2fRc%I)RElW;Qzd+e}tk$EQYM;{7A~pBGAkBn?XO zv*e$6B|p4N<2@!mQ>Eqsj3@mL%ks1maAOIy?yhFD;6k7ry$mw)JzeVV)6ZIS+CEqehA-KbA{4lpxZ61UN7jdimnV*OGRHJMFmh=CgfTj zD8Lf&SN7qGZfDUl^%%Vxs@hDS{XV9<_EdCNfOIS?rzfD?QiUZRrbDlm25T}sictHy zP^rqSL)3mcmD!cu?IYd2AwD)$tY2sQgjeBpcb zUmy*V%7?JslsaO;moqZKn>FK!~>#L|?O;!mO08TN=S_W9g-N;H- zQF|*tpM_Qe=#le0X4swr%3$gS_aCFb7!pMuUs1I zW5u1kBfSJsGB(c!%|GFRBh6}Tv;0{KU|cUtAa&KAwxxkRN!Ab~V;SEpOPY)3rw=!?+cJrEXj z6Pr6^HBytQU-R%vOrPJGe&!0o$4a1om9b+f3{-_l;|Ha$_N6XcrT(F+v(x?Q9PJ?=M0!}Lu_n1!bIK)!2?%mfHQ5cdTxU zaii|oz0E7GW1!$QMaxacGuA`&G%la?6L?X{8g60jellV9 zrYgIZB|N)(q;Hpyy=L3)v{X)x9Oiz8w@YCP=xAD)%3)e|BW$S5D~`i1c)$%13`okn z+MWJ=(a|94(IKN}1o^(Ft~mZHyE8eBmma6p!i?!{OlK`1TNN;?f9CaGsj<#Vs6#J5 zJMD+n-YylO(NxeZ3CQ}yBH`_>&fK!pM_k!N9$rDvlb$odOnY5Gp$Voup02CL($%#c zQPp&ko}hO_!Fs@I*{Z(x&LQpTxZ`&a``z7fsB4-)RCT8Nh`D#aM{{+?N65v64FR8i z_Z`Mt=L(NLo)eK|!q8dn6#Z*_;hb@-IUTcTs2m1@AL^)v&=osz^oWaLp``qX`0&Vlp7 z_g_}PC%EZ~LQR$HQccF$E#zGSX78UeFRTEfqFcD5)m-xO503DEj+6dpfh$|cGdow9 zFi$QAabWyF&Knb(l^JU=TagAoAMeB0wV8~*Hae_hd;ZlZeeQKOeu4?kI_(}xpM~so zYJ9L+@nSS1bt&W8MPN_$to$ukrq^zI=UelI^PdgrH+q zF?*cxvWkV@Li)IkRbR%3yk`{-M`$=#A=-}qDz;}MF!Rg zFc8$CYuQZ#XZkaHYM)tPItgirS0xltT*mjaReiDW&YZe*Cl;2KZV3v8Qhl<=b3Ra* z|JLDc{lH<&6d9jkU(HejGg8v}ncZ|n&xPV!>GY()g*@oO`txB`4}pbj{W`-iPF zcPP9NHNdwl^Z2;mxfSF&ERfXJua9M^pYy@D0wPadf1PraEU|bL?D0OzjxXW+G3TwZ zANYdi%dUCon;Fd#=qNfUuJJyX0{2&;#uy22#p6q zn_F22jvOLi0|?PfIwd2O`Z}Qr2;fXHm(q)`9Z_zBMw4BJW?jU$#`9w=bE}~zHjh3{*6@>w^i#}%{$K-xkf^@L@0+c1%QExvO`la* zq%_2tOa7NT{rRulj|AWH+}=WVtk3MU3%C1OZV)CD3op6#Jd2ectp}XQ7{zu6eUqm= zb##g~fyqN)G8p4{MUoVxrMjA(Z<-0M$?k;LxKSfto>ry#Bqk@QbgX@cOTrClrY4NR^WCOFWVGB*+v@D7E+he?al$kW8=$i zS4*8}(v&Ba8S31byZN2(vsN&ky%9&0fxS4^+?S8u9}tw4#wt?*>5$K&&8-iXZ+(-> zJXI!`i35E81RK_h9!PSuUSVY4dP4`o=`kPj)PX=uwkn?0sm{{KT!5*=`tN;Rj!Q3< zC-VzdsB+e`)#J==Jt31ySBmL#4;oSIVkFW4u^!maslwV?22OZlvNu9s&AdxxnbNU7 z+fH9Y)L8bIg;{`xKlfVW!trc~v&?Sa(iFh5(^_V?>we#K17B#>5$9ZtTH<16LR(gT z^@mhQrntekyH|r3J|HyC3a}!h-Q>^$z=znCaSp zefQ;^t#FvW9^*{Rt2C-f(g*fjnqC#lx|P-05?W5Vz9g4T)Q|eU4Y#uLnN|-#3eUG(EP`4#k_sZjt-NztNV)nC36v}srqjZ=SM=)o0q26~ zp%zALRBfEKv;I00U}n!O*F(hUD|s&qW2T?MjK=A7P7FN^ejx0(P8n)~K zHNQ}#!S&W=W8^CTsd(`SRsuKWa?qMG9E@>N>{{tMeEUG29D zhf`T`FX(+wVFx#m<{ZXguIbi;ki8;5QagXMyEB|PKZ7WO7l#saXHpt9fb{Dy%zsB( z9z`i*hQ#_8!(OfD&rOL*`Cd%pI>aDcPmU)+Sn;ddTa4f0Nz*z%_z8dUlv zL*pN(xfe4ZG!Y@*(Di~R9aYrwwVT=DM<_je8DJXio}O?)R##Qe0|pU`*y zBKcZnP2F7OAC` zh~Kw}JlxOn9u2dj*oqL$qg0^+abXi4^c-bn_^?II`Bb~2rqIqs|AJIf%Gi@LHtJ%# zGSZLM{G6#%Oc$McVfnS`$6*u4)%bD?k!yWoWabh9I3ev#0aUL#!|XL0Qx=Od4g|P5 zvDBXLb=G=1w^rcXSv&|D4(kq5Prg;Pv9(DdkrWCL?4B&l$qlaU?$iybx0dhJNR@~8 zoGjjDP1_(bg-NsPPbEnyXf}D9R;NVZ>r|)F%kVLafORg-P5i*h)HB+_HQt}Y2djcf zPt%@L16k~|-b*<9KC7Lek8>k#PJ2;me{a_3lS_5GDkU(3N1U$Q(mf2VL#N?2`!ekHhua3C72W-b}eHH@S(}77kx3Fo@Jdt7BdDRsM5Wt;y^z zx>%&Ylq32B9dv`7h~~=J^3Q>!8A~h5Zr$>K<;`fdux+?3A%z~)UiwcpNW=Q{((Il| zk$|uXOPOR0+C(IM@iY7DQb9`ep9v6syBdknuN-zis8Mm%sur}llB9?1uOwl$|S{ zn{iaNPei29z%1%6M{Fv#)A*$3$&XmI^Rix>r~GgtTWIZ4dA{VRrBq+VKk~)8z!6KO zXPJoWsP$?_3W}@q-y6MIKM&IHt!Mkl88HM9G|ZAkqoym^bU;?NMz8Mvh9h-9+U(gw z@?zlP(BH=WuPW~GQSrn{&70N5)TwQQa@NM23TNa6FhQo;gYEE#m!P{+-{*@W$h>ZG5?l$?C4x#M*WES~l$O&p*YLZy$F zV{un{ii`ca75qCdU`6AAaHRxNbK?)npQU-{K8NfMS;*&GM}p463$pK zU+CoLZ3N46a%#DHH;gF8d06$;Kq4~@Z8bHo{glSi*T0RBo;sX%$8=yfAN}M+8NBql zBP&L~i0!*|OkT(E&=>C#w9#@QBe2?3JS**Ra|ec$Y-E_eGdqE6$hby1oIM{utY+TcJUc7vo2b$oaJbW)MTI zcg*ITsNb*UY>BlyaoH83FAIgfkf&{@fgjlxmu{_}wO06WZrTC`c9e9rTg~eZ;kmqQ(pWpo<6#JiE&>f|NB#Rrjb9u?p|~}&feX2+ z7`%;X3#ah&l;T4jT=830=QoFhaHnK-zl1~^PuytTW%b=EZHycb4^*`hENYJs&bmT> zIJFICifG(F8BGYJnBPfilJya6XQWSL#JyAs0RVn|m1|x|plCUze?VnTG&%09dM;Ub zZSPuGr|F6FmpT?@OeHWHj7b4IRp1XbW+azFjLqO&V~1VR=fQ(zYVBdzF-oP>L!(`J z-8L1k+sqBxLWBN$1=O?rYuFtTa*lGC*Vzk62PApB#qNwL22?0C@h_~+gi`X1)`n6^ zMHwH}c90*2H#iUKi(W+^C5;ZMS1CjVBec7q5)XXIEXbcoo=r?vir8yBrcA0yPI|h(io4t-C zDcY)9`~9&id?NZK>OzXA`1ddbE}SH5z^^WjA~m*OOL3FN*^cq zkVRg|vUfGnNUF?g4XU*DtWrc!-Y%F;E?6R7Mv&iRq3(ob1)S|%n(Bq8=Q^ssp%KV1=2J>_v?D@& z=t3ctwi~vygMb?*1(3q}Ef?qdqmvG0!!Pkx&rB7tzT5K-!wQ8Mke1sG2Cvet2q>OnBCGEZ$_+Hw;c5jShwWi#BN z_?GiVx+6mk)?aK;jbiNp;^mziaKiVKD>7zjT7otTG+X-s9u8uwUQATEDvo6mn7Ys- zzW%b?nRb_xIwnh1KJT(4@AB3=Ta2G- z2La22X(5P0Z)f6f5xhm9XEyt^^%2@j%6gqOZkGmh1DQ$jxzi?>95m$@trQ4L6f=TK zQZldV4^A)}NnjDN8&l7}1}aZxp8f>+(e^@o`Po4;>7Sl#v8}%Srw?sIdMnn{=w0e^ z^&Md(@Gd0#mrI?ga}=pIGN4y_E7TU!>$PotT2QfD7M!<%#njD3aVUF5G;3xBtvC3A zE!cCpYic5ez2dPi)`9wD@IA zC7Ibvy{blV>s^m!7-7R7Vn1;sNOJMDI))!DJwN@i@nddV%g1RFC{2p;5CUY@!_zUl z^Otjy|#O|Y#M{3jt<8t*YgSC?8jXD=f4*C%-_+jKB=#dR* zKjw3JEJ-n!Ere8CtJ@qD2hu|?eHcH5HnrWCgd+nIh#THxz&-itt< zO#o4o3A@)Is7~osT7r%zM3TGU1O#K~!m?%4vbF`hq_tEz16Eob?By~Y^R+~L%8Dq( zejSa_Vg?MVej{x&_L^JkEY2trmU6bN-zoOunDb350TRZ1=q_gN#7n|pp#b$|j=7=w zbr+2h-ch!YTD)MoaBlZk6B-GB{1JtYi##r0WgQ$>!eugM_ZCJ599JDWq#J_8&P1tp z(KX_(7^6wXP}|+P`Eo0`T}!R6F9dktdt)mKo%-o}2Z;K-+U3sluCV}<&pq7ZDpv#*sFTpv$ zGUN?OE!$qNwdfi_tx4~(vaBBQ*H2sT^`~^aIQENQr~3H`nWyNdpYD9Lye}e9@=}rO zQGcm=LAkLDCeH5rN$7gHk^R+uL=rFe`8C~5qGlINPH)fdM?|^*0s)_BWE3iL)Ljq?a#SvS1z1UgSkN0yCII`l>$nJ(~H( zaO z7tQ_|mDY~fQ>QlJb<2qFvpk5Mk(}~PeMz3~7UR#hweXn^;PoLAwWTsI({`mt9`?Lt z2aF;+wr( z{j-4mb=Lbv1xZn)L#98&Oigs#_`Q4DdifM1GN|dPaq2sbxZ5=ARVH0|Ll-43U-zn4 zznUvMN|0YpXFQ*Gj5|S`BT5EA6CkmN5zEtH>j*PUx)SdfoJ3dbgo=C_$W{wCT|pe8GK`Jk1PGjbwVuq_t5dMo>p5OQ zs#jDj!?j>w4h{ycL;699wib*Xu<4nCiZ(KH*_faiMmT>-kg1ArToh!b2pygsFlf7@+qthY zyd(6{#2yaSlFu;E=2P#s3af`bPWaTLWE_KU>($M!CXd6q%hGob&C3r3m^8%OYa|%8 zq|XPAu0Js$)7GL9I7$~}q&nB-7*h!glLvdG=lUg!(Q#);$}A1Tdh-4Zum3E5g_RNT zn9DYkg65lWMK@7G8)@Gn)0kqdPs(#QVxBo37s~I|ZRz!@zJ5)? zBU-&?3F<*$87NwL!Z#!>5ur%3kc>@z7_W@7Ufpx^me^-8sZw&zgtN2MQ01SzSMDGfIe` z%Ab>D-cRMpzuFt^kjojm;O-b{AmpLdeR3C#;48^{QDsA#>Bx}UY!mEZYFJo}Lw^*| z2#oL+UmP(8N03+FW^Z77GXRE+LhxqR$IEq8fd_t4W+&^+=|z+Vx4T8b4uxAsh{{P{ z+z37$z;>X(m;baqZYsS7il-o8(?kgct+gx+i z+(&56Bnn+BWyWUikt-!8ESo%ks9)=$zta>izSL1uL4$LpjYWNh?Ja%UNw3 zOxnn&$xZpjVcd5G+<=xL#A-hVltD6NWP#3vQoYhl%{jn^Tc*g8;1%-G=1!3}^j%MK z=6EV)-BB2=#_?MG$-SH9>dhxIMfscS-*aj))e*5GN3=Qu8a@;w0djM?5tyUXWodd#z@qdc12UEXN|AL zUv$?b8x_4u!uPqJC2w3H7_q}9)1+qrOt+Z44mgjf zD8Ov~bO!A5ESxMy{c(4y#4MfT=Pp}8(fO!53Bv>+>Pma{HuEr>MDv^P?ccGp7Icj! zFJ0tPVbqF+!tlB^@sg5etD9U%@tKV)lVpiX!cp7_1E|-w>QwEw*Rsgv^!a8@XJA%wok`qNnl^Oiih^S%Mpvp(PPDy43OCmS@}$RA=@! z-zSF)<&=I+Zod7i{~!u0Sxlbh4)@7=@~%7N(8bH6__e$KVW`>W;EueCnfdz{*!$SC z!q1A-`whmY$y0gcXTM8M-5_&Ntpdf3G(mBaAo|iD_ukWUC3_0r={)LwE4Z9mygF2< zw+idFw=PCe6dSiD_Q`A4>9GxUg*lpcvh#PhQ;LrKb5^?rSF|<^5lYz5)rhX1b>>WJ z=))=3dST84%bLI#%5tnusJdd#kZ?P*%*^n_flut*(%TmL`%XAVUOorgQPG3T3@P^f z#^NC(;HzWN4~eubQ%Y6S%R}lYG77?P>#xpV3_MU=y)iq14(=~^Imn>&OtH@I zKCm`hV@jNBFM;Buw*+C0{-A4mo#|eJ$FxgXb;q6aX}UL{;ipr0>Imo-GsFHVCWFF_ z)x+lqvb7Df6uuQnwB-GLo4$>d9G-U8{)l*=VBcA`6i4PihVa?vl7ZO)d)u4)@_{T1@WF1WNFYpu&% zGkD+XUS6#70pb?TUt)Yq4mCvGCoe{GEq9ReDBhxz`Oxwl!DS+gylr7+{;@ZRyGkUb zn+^bnzt}%2b+OdH4)A@VRO+Izy6bU=k>7yDk|>vVI+4dlHlsL3O#BMoCxdJs7H3 zSji}Rd!bxvwE1viu+9?vN>a6s`s=g3585HD~FkrB=MaCj!coSSFa8KW*Qhn8WnzbEVQQpdKg1?|RJW#7#n# zyr=_}`LQb0yZU<&FS0e$^!-cQYr#XTYWn39T4n?ntX!PLk@U;`OT`{HP)4jFOjmwd zeU4HR`IBo3+lSaWr=y>eXZPQ*f_Gtnw#jVYMzP|mO*i$pr-2?ZHR`eBydCZ(Q6cnr z+l06N51sJ^^ahSGL6h#MzHX_{x^ZizM&W)v3ou168SUa3`$gxC?m$%T*>R(w5&ih# z`)|zs@;x&M8$6iYHr25gnN1?pM*Y0Q#vAnEa$SJ1i>~m;1%%yvMrK(G?BrSQqoMC~ z0?hjDLvmxU7QWLA{+GX#v>y{SO;Nleyr^0yI(4+>{3WCUI?dmjpIIKDNZJ6ukg@cx zBD|PvVfeGz!da-Rc&HI!m1AtSKa$HCC2vM48c0Yw-tq;c<>>^;Ku)Ui7Xfrg@6$!q zKF93AF-{m8`i@Brrz!p}BvWNj-Calpq%mj{>HFGsa1nQ)|E%`KT^<{HCtp?6&t~y0 zT?(#BEBtd9Z6dMDroeihrl5Y+>dE_R`GKHi!X&nLZ(53hg3`W{Sd?ADlLJamV9JG% z6Ce0q1jRa}&E8r?F9JfRJ`p@GE(!`0O}z%D9;_eveHTfI-!E)2u-Fpda>2YG>u@3_ zdo)`|ugm&`Jjw?e7Q#X-`p-O@5!`&QX5-UjXU!s2<@!QGz+%ad%678O z=QkYiz6Ggc45pU*MDiH|`e`4%j@XUb&1C+hsysSdFa12S(0huB`wOejT8_dOEp84E-;UA zSS$c5T$VbMdx)HeWUg3!SlQhC0frHMmE9mV=Y}lTs@>(%+@|2+;-Wt}jN7g!fGGk1 z`xQX_r01!ZldN91>({cmM%dK*URf5i8??_FsPDF#*ZTxap@w(sEs0mL*o|t&(om_tzj&?Zq_)oAs79qavbxF~krQDa(Hj|1 zwZ3;M@gilO1%co7SgxM3U>+?QmQlqJmC8xgo2hF2sMSlZgqUHni<{odTte`aD=Ysn z`;y}FB+RwWUQ(Kp(4+JL()dS4fV1@+yAD!ULiB1$rzbV%WvUtM_PcE5nObf;n{bMz z_lb5)H4YKUevxrr{O24^y%4tqA-?R=Z?V*O5pC70n@71CXx8>T=>yxP8WT|y)oX?^ z4DI<^@=J;y?;$2;@@8*T(ztH8#7Mx+`n?==z3>P1a+b1ScDDWU8owcs(S;uEPF?t{ z6IrZ0B>e-_saJp0T)L=GNyAsxYV-`+C)H}!BFi==Dyj1IZ=JP`fkd$dO-l<~jc@ zz;r~iQ&L$=#wS#Oe#pgKvS03cWPzSH`6t00VGn@^KrD^ls|ys~0aF@}`^kwAYSK3y zmw18&+g#pdJzJ)CdWPzW(bhE!w!a_PpR2b3QJR40L?v$0*u8}5#*u(8Zd8){l)`)& z1zFG^AUe7{86r@++AUgpTp?96o1_$Nrq!_BybG^NZ!}HSlSWPafL5mL3!BQ)yEv>-1vd$}q;DyO znG&6z`|JNPkTJPy!}K3wqH$kP!M|uuQ#7;v&H4sg^e&6yhr})b1FCusT_d$Leys3? zeb28{k8>Wwc>KF9yBGt**&+t9@eAXiOK}-lxeIZ9R_6!D5!)3SNh)`wD{8lpk|>IQ zE|BWP(bjyknSpK>H=kQSbQo=>mASuRk2DmgRPSEZKWXDRhgSMPer8`vChyeokM@4w zrgBB9BNbO+`^Yc%u9Z_1^vc8Cp60KLHwrIYSs@J!cVAM8K_KjloS;A5Qu2G0+i%GG zmo(+x?WQh(c_~m;Z&P5r5%lQ+(9KmdQP|(vMi!L^KBz0lMxUI35c{^!LhBmBRjPhL z8g1r=I@kI!=G45qt@l*utCEf{cPT)k4yyN1wHO$MZuDs>>h#s%RebPIJGuKSwK8zx zQS-!L^nmF%wU-o@oT7NL_FiPI+qDWi|GI#XTGA)6vC@?Kp&vSx9z)d2ql0rnum6j| zbVF&4!IRg@mM0@Zri#O1+Up*X)AGpnbyeo^h(MUeJ=hh!A0A1{Xj#3OON&->(^sS5 z0z8zlW8}JAeFlS6=9fr(Po;f11)0PxLqIH4rEr8S=TZXuTFEbug&mV91@p<393VYF z?@fn?si}U@r6VhQnGzK?Wt~>CUoWU@i^_ek!OzqLnaTr(&zh(Do&99Uq_%p6O;Zs$ z0D=w+PC6rcv9T=NJPM*kISHFqPcg&KOIg-KSW%14#$zSRWCC}V8h|8vx01UD$+RrJ zGNxiXnQ-x!2`QKSvdqk4$}D)D^{X}37F8}BuF9|!yKA`q_7O5Iv6zYY~w4Isu0 zL^Q>q$-OVvnub&N1<+PhvY!C%>3}JiT>RUl?K;_e+~e`u47Hvz)}z2wSMcU{YU~C5 zoLY8E1^JPb|MMG4)NoW;_a0O7-82mm{#!?O9mVlf9OvNlD63qjoo&nUKv!-c3|k|@ zNFZ4eb&xJIm(R8L-^}8$T`a4pqWo#I#7UBEh+g|%U5s$vCH>e;-fO0dQ}#37DHq4V z)xoemdY6avPu4O`VzxxUj$S2GO`cE##7J$mEn&gP?x1=X8A_vUs|o>kv69?0cj)#dviQ-e*imxOBxy5R9|H~jo9Hp^tH%mTUZ$u7O+`3o zS1+c!=s}bQKQ9Dvo%Fm2auT$Lu1gS)9eFpdueo=5*W)8eqRY|Z_y@4OzM-8FRVvRJ z`D#2c=bR}kOW@xP&Wr4fO8pv~ar0zC?4pjgccQ#DB9Z#A(o&z>^?2nRY)sd;q@|Up z-Ohn%&xt_o8vRk~M)T+&%+4cw)@fEB)ZfLSH@jQ(i*bw^@+V^&=zj9W(7Enk3PbH* z-4Gc&f15f+H7e9Ke$XW>PbJJAuaRfPOo_0OvwNkjSA<(Q0aI#>>DY``GV3^*q;5K& zUK`b;1k@4@$(dm`?#Yy|B zMt4@&1FPyV^2*ggPga{cLM@jV4$LX+X(_f+a=4K##q3f(U9G&C=<$**j9Q8NKjI+Ccf z&1We|Y)ZZBxu9s48?BQPir6^5=S!7J;034Cv9prLS)tJ$mM@grMXlqEn_qt}P1A6~ zoLd&u(-H2IS*dH-rqA`v3Z_6H*g)SA>z$ zDDt#Gq=17_?ZHk%j=55CV)veh;+}s*59x*8s29Z@8X3~{*Qr_6NnPznej%T|!kb`E z*h}F{%6D;4Kjq1ze$?}iVX+?w;@^Ky6|MrDAgNPN;8Ysav>WcidHM3%`2payj?^s{*Py0EvqU3w~rEk>7HR6HETh(i-5-yx9adBf(mUP4%WruJ*$*OxdZ=hSG zAp-JQR;qaFPyf7xYM8Ol>0`g&Yw|`{vvezZXNSFh5oB+j}JLHF|dcB@In&va-Fxhcfuf zbv8k_$W+cXXRUI-JBoM3)br2D)6X&1U1t@e@18=3Vi@SX;&@&0vR@t5JbEmroxJhm z9#5R94JX@`N@7B{T+1eju-*#Y)60pNLFo?U<7veAN|JL-;8YMcEB2l3KZ&eo@{+b_08HlN@cX_dy4QsTdaQkYd#}UjlHjGy2Huo zmFelQAxqIyErzruO)rH)WIh->CSLoogFKX6UScQvk?bv-|+1bcJGzFTn$zIojA(7Lz0{rbv-riZ##m-VS~ zx>T2;s^w9iL%-I*)lDB+S?7h1nI^qucH;=A^_WHa{nb{-YVl=kJchAZF}hPuc`z5L zA4EQ3?DFWT{QDSo1F7lC*JD-7St!ce;t$b@NA|RgzxxR39^T|3$Efd}?ibOW6;vE- z(%;p(rOkx2Y(8O$DNxnSqEDi+dgkmFIm9m-fky6lwzPe1xS2<_E(P3)m{AH!*+}Pny2DvF_f0&#u{^z0A5|@RO-O0_Ls64uh-TWp@tHHH z9Eh%kDYyJ{oJq;SdPkU3mm{;&r}j#mnaZ`?G?~;0vGA7dl&vtkST!T_&l%{4w%uFJEKR zGHy0fSwH%5f^XQhE+hG)r4xQ1-k!`Xm#YTsWlq*{v%Wa)4c?nU|EVYE`98f%9;(xJ zNv~d@NBztEFF0Mal>}&NotxMumt>*0Wh@;N(bEijk(00lDNC4sFmM!Y%C8pDR(ty#RH0>2&67MgQ=zoPgUaTz_ib zZ#FQE(h9H)$U1P1lkIj6**fJM8q&vS9EJF?(%Gxpd#PDVF`m}M*H0fiIlril)Qaj~ z#Hqz!ixVE%08JRq{Qd9UnFwSl1m^1)?kgm)ETPC_gt;uyHX_Ck)W*3nRVjJvnuOXq z(I~apN`1YRmiGE5Jo?5V5P#v!YvKFEwS}??K)oTJrSPz)-?vD9Q9?iJ5$6l8@-ZFJ z-PIYv8b+=bBN|fgtmjO#JdNw?EpE(|$-TVq0?0z^VuSytHzmxtG&54{5t7YcSCJ%} zw%D8pRrj>Cik$Z?;2YOWt}oB?{ViHEVo;Ew^5n3dO4N4mjAb|(^Vi4pxik0WzPHKB zJ6MKH(I>L(Zok!4GJk!2b0cx%v}$Y~t2crUKp$2! zHf`zpfxW;-)$Fxu`qiCpmN-2H7=&xRE4*MQJ_`5+|D+v1&PKo?3*V?=lhmUIQ>7^_;MvbW^I@M`7c)$PvtE$;_5 zO=?BIq3$#s#iVUcH$Qi9pE^R`%hE|uD2X=vgx@6u8N0r~_4a#Y)Gj;kJ z_0~#mJ-6B0Fk{|78#u2`RdZ;oUDV=AqxK&k=DGB0H3^T`K20>eOEYon=r+*Zv-NOJ zR*MUME9(<-os|T)N!4ZlRaId9wrdBV+cj$!rncT3R$y^Pj&Z|Hwq_m{99uapn_+q6 zfyF+pi!tSWR+9>XPkCus2&EuPr>`CD8 zE~*-HD?LGsOuIxJS# zo#K%cVb%ZdTQI0BFTWJJiZhUr(YYFluw2~(@r2Rq3U_{D1Zj;czqXEPe$K684$@LILJ6#9 zd}?IzW>s>w=#5Wqb`W38b0Nc(M@~6&6I?uu`pH&53mzH}oP!%wE=k3Qz^PBka zt8IRTx0&n0lk07r2jbktwBF2sNwl%pXBQ@|0~1bzC)=0P z5h(m++OJb|HJilL+u*SNWcja@TxI2t3jPaRgi<&9d=4u|o*==*q~S8bI3lXG8{;(# zE;>!i*KSFtsEUJy@R?kMPD`9O;yFIjI0vn?G=A2h>~^NCO&b_?8(_}6 z|1R~J8Za>L#9~T;V=?1JkG*hxj<040mu_jFiwpZf$pw0V_02+`70mwI6u}z1Pr|jA zdYt5j1&XeT;JrbaPJ}w3uxHGwE{UA1-Y@=IC=@V0jtmi3ydTbRHxXIh#JI zt5@#VeL3o-5%mP7sxr-UoujTVn`aZ6NcgI8NOD>lnl zNOkhAoC9A20eUAlUg=50SM2^eOjH4VIS?#%kZ7Vx`%o2|lFWW#4psFISFjCn<+5URpvI*tG zcjiwKw5et?r(<;Wt>B*V-#Y3Q{gt{W@*brTIQdGeNap?b(>(z}_cN#9oB*>pS;v8a^*|5=SYgbbgL3#jej|`lUroIRlDa zS27o}?&L4Hw|Z5FELv9@BD|95-G$@a!r8qQDj)6O1s=TH&K6FZDL6&!r(3Zbl+9y= zmWs!=*KU05FBc&U9PpSSFuFsS>U=ZBWa4M4wBY&ln7}<_sy^h}4jetv-9AFNW$kRQ zoP8Ou^#<>$sjTN`xp}oz`iZK6P&z;hPXj4};sevSP*B)A$%C$eeXA1g^MAB!;J>0! zQ#s1V_s97ki06H|uKP=n`}oG!WP4BYg!6#2X5lv>y7bi}Z&LxqK~Bj71J6^cg$_u? zAF6XIIf*R;UkjH0&5SkV7KnU$C?gmZq(5-#M+yBX zFQ5HXWyf5zfF&HtO#Kr%1lS#GAhw;_v(ciGxhrNZOikfB`O|1#fg&MG0h?j5^GN?S z>8jVaZjZ?@QIbstN6qsBmVn|jj?CNSG?eeo%R!)eFddwdr;?-69Oe+O8^F!K$YU{J zqD-Fy(MGN)15emv(SKpUwcj|K>mhD)aaXp3XZ#HuN*#y|q0MKJD1b2E zk}M}HJEWp)<3KejWZeP|CyFqYZrGn7&nDA7koaI^X=b`C!|xo}riY*Xf%oNY9Pcyn zDkZqhY;>60jItuef8<&DMQc-tJAdO=Nux)sp+pw+PU_KJzjFFo`N%G;Z4g-Z>u81x zDfjxpO$K4q4&E zRbU4NgNni&qHiNku5XM1zww0kqbozxWvlCtoAu;svMUw@%tXNhxUKt;4(n?Io-EU1N4YiTpOb33lOPT#xbgvdn zBF1dUDjp}0-um(506F2heXi3YPVZ+rCMvhWuH>gG5n+fw(pe&uAOtPs6Kn8aqtgO} zJ8{rM5i%r4l~|;j#4bD3tWqjxY2#84&$uGkQqSkDr3(ynnN$mh$5B0SUu3xVETxC+ z0;}38xzIQmgviAZWeTe;By9U)z`GtK(_i47C}_XFj=eD+XIUc`L86(YuOC6rsgqWvinmfK zh?A&IACTvQz{VH&Nbq#ZFnVSY6eZA+b4b;5TDyjGf1lH`N);5`w0PaR`W`L8B{DLaJ?}08N_}z6h30#FB&B z|KQMM_s*C2Cq}0ntQ75oKyes2@e|DOsKi)R5~1h^VJxlZXlS)oSpLD6R;i2K1!)}? z`&j4_LD*Z%ydVFq{}6>vWW}F!Mcp`uw5Uf`^A7(!m|cr5>!^U6bLuu3H5(=(P^DLp zU2s#H|21ZFDYRt~P52tq;_M4mWgTTr1->1}E3qM{krj9++cB)DOW^{F4*8Hvbom3? zcGzJ?F5JNo1X2n*1dOpH1)K+Cz|*d&=y$W=fs}(3JM_E(zA)xW0r5XwPvDL{(c2cz zo<0;klxEA@Ny?B^#0iQokS}7g(hDJJ`R#RbOOzigRmIMK$*!4Tg^DC!!i=N}Ku*jj z(67wCw<^}77jgPGj(>hnS-HdSI;|VmEk0AU)jJg~{>II(D}9@S^DJn$ii*4X5lmzu z5{28U1CdFXc4QZ3N?3-%;|L=PJQk3qKsbQB zm1AxC{TA_MIEg=?je%vrF+3*c_A`v-QCuH#dD zS_>^uL`3H?9hM5)*5TkD0x3 zz+TgMqB~}|yC5Jq7v5MPk>9k6lHllRQhh{G8uHo#VjG7Zk%8JH);C;`SWQX@BU#E( z$bDhlANNs#Vw5bATM+|xr5t~;0e?Z1p|bZT4%#AT17)BBDN%FzJQ$W@9+uMKMprdc*d7F6^=AA zt674aJJfSB4rw)ni+Wn4+w=ZBxGAMtE`G29+UwfYX#B4XLuWLRu@aDoTaQ;w1jE=D z-R7)#@8qawbn92Q_108wx;dJYxij#sq4?pr2D{<>7i%w^Kd4!HU;}=@*{Ys?^8(IF zu|CDD<~F9DtPngqAeVM2`J@*AzR^1}BA20#$YSy@-G~@OzL>z9TzXj8jhL)>avX_l z9|$#divQlQULyodIS>Ap#ktO{=Wq~>B-D!7++mVc+;*@uVCU()s?Lx`B>uRZg{dQB zJ7w6zrO+lrcp#IsJQm>#K?ZXsqIS4sb~h78j@U=7jBda|{rdGIR>JI9Jx;#zWQ*41 z+500GG#tTT4@~62%=(tW6b`BBBGG2u&BL{WgEgZYQt!9KYuR|ea0~}oGGzEy&|pR$ z>1tJq$Db&oSeneYef5Z1#&Zc!t^wo9q0;a~*^ zBd1|EJCU9&fvmQU#$Ia%`CxzYz2Z8kdBxexzhIma;lYiQgs!(3tNx6opz;gDyPAf} zhS8)P;4!8_ITi8ux1G6Ww^T8f5=p}RH~2=y@#+`w=M&b(!>|6NNhYB$gKf7x{Du3$ zdP$sHpUXy0(pNaU2r4f$0_)qof1g&VQXflc+h5#87I4Z`&>9XlmyIIR9?HqsW{#rq zGVUn{i?ULZ$X;Raid~?h@*l7{y49J2potJxyFkcMP3@F0Rd73cyBxHobh=U?r)O)9 z1~w&EoOPaS9ts5?3VR(?gLxnML_4R1Vf3djNI&)nDitA9D#?DGX>N)ae(gS_=27N^ z&m~T;Q6d~w`EX=?4<`kPsnhnDz$Zt7KUh)%K7J|@4R;9lvfLbCf2Exi{9Kn{ObY~)H&4IZm=PwtLKZ<_+6f8pwq zrB-u?23k7twF5G?Yt`X+mVY2$>|koSEI{=2E1vrd8`zzTKRizZC8-{dd@^ zW^Yj#f6Ibk(}I#{;rA6{{#ytD0Tq|!>lT7jpj zI!C7~U=4$+WxKNnxLT^w5Z@G6XBD}dX#oD64qnB}A#v!3g;yyBnQfb4l}+U9)1Z|&6Pz-@>DDguswYY9sgd<(;+fQj07hSJZf0m_3_5YHcvw4A+y7kd62oAzNBYcp};P0weYOD`ZvW z6D7t=qvz|)1TTf3OKerUcT&~^L($6oK_;lQ7W)@nVqp~8MD$+O_FgB1;I)!lyw5bj zxrk)X$&$lk|G7WI`y^4&YtPEO?oW{qL0p54o)oU6+ju;);l^KR)y>k*VTJ`qDPA6b zTVvWmsVIX@!oZL)49`Y!@W&bTp{0*}L7Skw*7i+Y0${G2SS!MNi={gFViTq#Kin|t z(W;d(PfL%4;Vo!~C3j;j7mfu#u{GcYXoioWj%nwHRYS zS+_W0ZD}m_&6oaL>dSdquQO+QcF~F~cR6FNCZ0^5p|acZYLA!yalfr_J037z^(TY+ zR1U{CLMQnjGzu);BL4ey#=1S>q<@iRsvgNN#K@53C$DV~F>TVO&m1^epP*c!@VSM2 zO6~mOnFr;?%tG!DF#DdLk@~8j=UL`6J@G}whO;Ez{=fx(<3`h+eBpt8a3zOM8eAzP zu?eAEkJ!R9{pg1Mm3g~dnR+%rmCjpbuUb378M|&SB3ya ze;Hqw*)8Zv+2i+|vHaAq+j2$+c=tHVfvez0%2`!w*l(>$z&!Z(P6fL@kY3|klzH+j zIlDWc&o9;_UsIZJ*+fufUyI%hz(cg7Am2hlz|!h?o>EAyTY!HZ62z?~b*_>>HZO;c zCyCQZ$NNk6*FoDHcfeP5Zaql$yUrbA8_XMP9CxV8W%_*KAV(sd#aBVRWiG|+1|)QO zlKaOJfr+4DmC|ImRWhl*QYc+Vqs_P|s`v1o8HGmc|8PWx1T42iyiW`kKK`dm(kPS| zt9Ix6Yuyj131_Z7WP4%kbqiU)zw0uljn21+ds=Ed+vM^CqR}{$fZGuSQ>TGj4I0&~G|HrKuK?)}XufR|>iC;4>wC z*#lmuVS=1f^VziScJe+EY)xo`^@vNUDygUDzb696BTqUqXQq?!1FO^RTdoL%QkZ@^ z(Z*MpZNDm~SYFLoEdq0C|6(pI|3xct*!H^fms~=JyHyW#-{I~xO)36-?%Yi@-pNI# zQ&I>R`2AP1mDRnfL&UZ)TRW1eDu!HKD~76X9m!<*x}W0!sEt23$6j9M_jtZc3P=pe zW*IbEG$>g`IeYie%Ibscy6x!s z{Axg}q(D_;wFGI8D%i6v8nJp9a!<)uaqIZhvtrrDTNBrG)E8!rSok_}UE-Ch;R4kM zYExH4{{pmsi8gglL+Nti>lEUiK0^zH_tAK!K#zUDY;XU)T(yUcqXMDMuFsVwfvXxc zs8PE65!Wuiy8cA$Pva+Cr8uWt*ea;$(U8yzM!o-In2JySNS8VySL!!s7^Xj8gi6d3 zf=L;b_T6lbWk^@ryK|+s7V+cqKS`P$Y7Ah#UN`vF%+SSQ^$q?~cfeH|R-c-u>S(z2 zRSvZ93;%TE)XnvTlMCp$h_TwIW{qxNJ4#1FjzM;CKzSNF3^+|m_7 zf@tuowy~Jv*%w*!M7&wLCoTt~;*7ode0y%){%V2CSL<=`!9Gy6&v5KxgsY(TK^XE&zlf7BT zPnMqeOgOO%cNu?uW?JVsU#@W1UVJj(9_~JV{lQTC^LVmUEW>u~EB0sYY;DiX#IA?G zF7V8iOL6~Z&+%uuPxrTx}JQ>ZY zAHG(mvTG6PEL)lAk=|GZ7X(4R$p#^IownZ#a(T?>u{S@s&z>Ult206zmc7+L+Gh_syZtG#g1T1NNKrPbb z7R6;ae`6=yM$XB$=DYgb zmo7|qMqm1iKK=PPiUZ*aH};5KTe6S0Z74Lb%HAsg=Ktm%p0wQ6cIl&VgM3dxXKF7c zf!h#v{_DF&uY$65iCLAymiZve%mu5)ybzY16&UJV1ejQou?~g;#0bnb1+Fs#yE$ci z#Gxa(0RG(yq2L1g?f^!P)&DdWV7X$I@UG|=aC(Tq{Yy4?Cfhp}5RZ$U=z7S>j^afL zog;7&IGy>6uK6t3PUb7pkvd!e&flEX2=jPWXN{`?U8V0dkhes07TRH_y{1@5*fRY>tiVJX7U8WN*Ij;WeLY#86JS>M#$;)rdybgaJ`~Y^hbt6J?PEk0j~WTEqO4UzS)|!=t=za6#DU#XDWH@?Rti z53tET1z{2TVBOaXn+4>Nvmt)slbM!=eh^mgD16y8hyM@l{1w<}kF{?a_1uTc(;LoS zMDsIp_)I3t3~;)Q@PP1S@-U>=55(3^-YN1(CT%3tOaQ*liD&@c-x3NOun~p=T~)u} z9h{^Y*c9~fajHMD8H-BbU^ZaO4sNz#4Dy=@0@)@D^(+I?tvRf*3Zx_>3LvmHbw&g` zmaSW=Bc8J{=eImpvCjfKgD-vs^aa;!!vzA5zD(ML!1A%gFuT}eyjTDi!~qm(36@Lt z29Ox8XoxcUxGVdNZqCD}&N9La{=$v1(R}@_!+M9|zu7FWBB1(pwomdiE+@45--;g& z;ldMyq>Kn?BR+tyiVwEXv*_JFZ;B6oGz1d!Zwwa>DYl13lnd@lyI#}-O5?_ci2#;$ zcBLzLR&J=flK>hm`54O;Q#U({*qdhRt|imkOqqS~$!$Ha^Hx;o zOCv7mvh4OzffG;gMyrA=^d1ticEoo5XIKS?r?EI{&J ztbz0RGK4SLBcJITZU&GV#wN#r_xGFXdq%jNu-=51r)D@P_NC$kNRlWlfn|Ho33~rL zN3HoyaR{#rxbktavN8lCd*4#s3H360+hzu{&k=~Gny$ZxD0A}b&jRH1)~nSxgM~8? zYPsV2%a_7V8dSsAB?GOdVw%U*=orn*`P_S!@T11?Vy_d+^QxssY&ZQQyw>XB$w9-l zR5Rw*InDW%@-JiW$MT zbnUi((w`48Hv?k7Y<#VL5C5)gYJQUnyGo6fwWrcxM_Aqo@4*G0RZ+jO?z%ofdZABj;MuZrIz8yX*q68w)oBR~~mE9EZ6(h%b=wf*d|uFb;px z>eY4o!EYgxg?i5&7vq-EE;HH3eg*jc%k|$iotZGyYYGHa@?=jYxN;hDRlFed(%7k^ zQ4xG#gMDEH7kH8r7R?8;1XoVAd^iOW@kE~a{jLU)fObH~L7%p?@#n>zEyb)JqxqJP z0*$zEn7L7K#&HcZ<1<{#tcm&#t?b0^luv6o+_BVJKbj*vAda`UWp`8|J4Y6615+4Ri4E zJ1Q%47%ZemXNX7odmfV)Kz_qjeOY_yt53@q_z)4=i+#p<8Ab9LDZKuS9N+M!GKHL* zY-NT45p3;S+s*N*=Sys$Yo;By?e;k@AfMNueY|lz@24DEvfrTai=$?6?e=Tc+d%u&t}3uh}V6y{p?G$KGDblfs>vr1z`C^M~PfOfT)gjuWNuxV6}gE#ka@ z!ec(H$GxLou877)LHtTW`qS_rX{axN%5O>Ds^U=^?kkN04rA_Sict}RkrlCpm;PN8 z^w;P@qZ__(2r`cKuFXWtbu}!vRMfimI6#YC)zFrwHuEi$x!wOAr1%e{$sQ|qE(Ap% zK|>O6;1Q$w8Y$%ypY_zJ(@~-pd*}AfqhTWM`1ip`!NXUM$mQMLh84@w}1UaTJGKYzF{kJn&#}@*ydDF*O-yZnhg|C!YSj66sP)EY z#kkZE$6b>i-k;;cg)}ju%U(6mMa0zdD*V#QUc--cYN zYf+QZ)vc7G-2f{6zd{=IOr2o&9OMWcnmSljCw{`W{2^+&Wcc6I9_1saBve^NS_`o9 zW$l;P`(><)(cuJ3s?QiLz|2^RhC=MnhMyAV1Kza+S(^3nr}tfk;fc1Tr~@i3xH!VM zSex%NrxGNJ=C8Twahwvt8TtN^n-;*911j5&`ZoW)8Cjp+ZNJoVpU!W>d;Z00(NB|` zx9LCO9Alp9Kz)DH9nGnp+tPE7i&A{EP&F)7(gGCEcUn336yRa<v_UWTS+cgZAVK)mXc8ChvkSDJ0S#(vOhc<;-l%HA(aA41k{3yg0M?UxoA)Z&8tV_T4Z@H7 z-Sy{Vu&mKL4yS7?kfvlK1GVJY!cI1P&|D(`b$n6!VIa_i*(7aq4#BBztdX)=JX#S( ze#de=C%!V%851ebNl$T6EYe(8BV&O*{h2x*0=<8@ctFiGL6dK_)^*@K#X;Elf+6TS z<1ccY{g#$LoEf0FpOTp3>EF2dHR+_kZL!AsJPe`xtjfLM?7X%QAD@K8&9&xkr=1$> z(b(Qq8?+Ur1`w$KGj!&GO#X2k-(|MBp1E(E`z-ercDUxAdx+eP5K`%6Gt8Aak|b@8 z$Q6=Qlrbf#5G6^7()mLwmF(yF`}yN}zTfX3-_Pgse!pKSQcEvzrQr}i-JE~fk2SAt zOU&RfJ7tel&u1<_r0GdBK+%|f<|~hjR+_IOO8Y6}5b@qQ#CQu!^p9&eUAq`Q?hHq3DUx1II6y_5wxO4gnv`gid04D; zKPQuRcoJTpz(0IXxLyu)QgpBO2IK{}$9)yk`P)NHgw$>Oky?Q_&dk8mY_4-q(g25t zgF8`IaY^bYbF*>E%i)CNZRo>maL!_Y%JFTrm&&P$*`Epd9X@1@+H#-qFjE>ywfSM` zbWrrDyx%+A*iKng^n`0pU9(zsgM2lfn-?3j@XvG&=anqD zi{>R@%e{To{d35;yiaoVf8(edZ=>_*-GWc}<%B~m`v>{8)vFZh1p?S#=d z%q)CQP`GBfbP@0x7bsm{B@+GhZiv5Owxgvm<5DyOt|z-lM2Xz}{frmW01#2?vcgl6 zcJAxE<0@M^%FgdaVw5G-oe9RL1PLilzVM5S4-}zy)N?WX@u$vbZ}IJ2>hxz%KUZ9P zLxU^EsIQ0z+dbzE(@ld$np;ez_@5NJRcm#~HToOH+S(O}Db?D-3;?4$xh^JqXzwxo z*}0?uxuQqs{_V_0uWwx>ybm*67LY$ZARr6S;;;Gv$AhBXEHEP;(xpJ&7ZG)7^!^w7 z*;g}c+A)U7T$h0I%VGh1ff##qgwW)7F>OS&R>r5NBM%lX)5{lQ1azhd(YbeRc@Zdh z{$k^DX0D34tKJ_YCZ;>^yzLxU#KmUn$&R;;Mc+5fn46SLY1d#D=qtWG|GWe`Mez0* zCk{gkCTtMz^)r{^O?BSlMAyaevJ8=5A+P`Hsu?`qCMEug$|Pu$rBLpfiM1(@KthA+ z0*buQRssS_7`&x`zb0^6s36{E9QSO%0lvo&BIJXC^8P{L`gE7~`^9S>B{yQUvmm2B zT3s3LU=btr=_X-_%GQV$G1d}`#jG@4!n*=T7L>@M**A=5#_$jN9!Wl2Yt%{Q3e~t4 zwlu%W{Rmzu;NM!x!Z77-(s%vdD|!dyExKjQ4_mMtqOfX!Fc?Rc%A+&IYzNRQk`UoSA550!zhCT;Jft}10K<(1%3p+r6EKj zb5m1NX^s#Mk&reWLx>rSAjvVET{c`nuMuAv&xdFXg23PdM4@xy0(tWF!YzNDIihAZ zFF6FeBa~PIoVV}d8y=nxdOX`qovyF`AQDu)gsWe;!Rge{Z-wN`^jkgP4xcN zcd*vvSn=synJeyUKrVfx6SW6BfRm2$y0>u?1E0|f`bNFDWvka2V{$1H`S@bi)`SMa zjL(D{0~Rcd3-s!GCivQNl|o-QmQlDsKn&6tr@Ju`cU+EYA1lkrp2Re$w_c9?bX%fk zQp0lQ+6e|AaJe))C(jD{HQt;}whB1GXTDFRnZx%oq|{$-KTI2{H6cXr^%2nF;S7z; z9McB_=Oy-@Xpw$u@q*w8r)hb7dlh)0*W$M6#5-KwQJ~{h;5|&|6*twp_X+Ya*o95} z8#~~tVbB0X0sIvoJRtvK`7=gHp9B*vy(H6W9&UO&nv^*i%&H#Wo3)4wego1$edplmaoMvyr-9(Kh9|GMNy;ttM;e)ORfFM zKeZ_JU&kob&XT??WR&xt&G%O?V?Q5xl2CJmB0Vnqd*YVvtD2vL9W6}=#Qmn`LMb6E zoQf3t<6>b%d!Q{;dU5~5Njy3x^>{(nS4jsg_{D4Kr<0X;0~&ADo(=UK&2-GEtpVF1 zorfqV=ceeAMt-L({npQ(#;F!#tK_v(2`u6APR(qC!&Fw9$I)EGZ+Z3HHHO0NgRJ$N zH~XkZU8E+-*_j{^_BTub1>%GBLA%dKus9fm*bN&)Dv~lWNi`K-fyDT|8J%8esOLNVd%pZhrT${*^Jb0TO z1M2nYAR^}ewp)gydSwPo873TePq@3l9J;KyO_`VE%6)4T zHiT-7jHxkgRHenR$`05=c9niysF+b!Kml;nax@3@lXOXwMX3!VmTwOsHK0p~H-@9* z9}0{HfW~FK#>@||L;U6Ow>UD)$Oq(Gx*SAM(p-Ltff~^@og(BNNUD&hiu94bD+Eq=e(u8)!ON%-c-&PZvo>`YOo135h7E^|q9U+_h%bB;}ZEWWOE-sn1v$gm$b|Ls~o>RpG>H|#=4Y%(=J8_gNompAFMl=DFSpA7hxYDIY2 z7LCt%g=<9r8f>Ig7tzR^_Zf#!oa)Mi6d5O{M9A4_46;WcC`$1c#S*m~vi?{65KPU( za3;JUG4T4P@px+~g`Xc416^kf;XmZ-lhKHkljERIt3oAueZ4*bTt#JdX{`flQnhbm z|F-oI2|^A?O_)GYE|$ZyJ^p5na-_|YY+$>;06Pvcz73hkT)~?-7?G!g^s%fp!8o%l zyd7z+cw?$n_#BZ|IMc8Ik3qI`5nt{~}`kn2XN~phaWnbw?^|{qWl2#>ae1;Mz(blIXp0;n%6NMR}vaLBtZ-sArmcY@Esj2@#TeM5Khj!T^nEG3`wew zoV^Su-uvPA4TC|s4U7n0UYi~~0t<5N8hL>9Dsm9Z$t~t#fny87|%1gK^Pkny%8y)c!%w{CDFWp2z0r zDjpk@9>P?aR<9Sw`(^3v-*!F*O9jg!qF6#SMKTp#fr?%@F5GTsg zg@>de1b2ew;};hI&1T5$dNt$U#Vs}QW$OwEJ$NLU&Z^Ul+#Q;f42$RSPv(*Bm}n?} z9Xh|mhBwPyzy}b5Pw!@rD3!EmvO~}50`@FCFNl}Mj+BTm_CJWpI!)U_^ista8>#m z`bq~Qe-hqt->=a+O@sNe`lCA?sebyAHOCX_GoPREOT}4}X_UG+6U-XyFh|4mH(hFD z#saiHeT8Y~Pnk5)&HbS+SGvd9**dFQrErgAVmGa*lo!A+?8{4b`ejP{zW<3MWrOP= zpt?k#VhhORgam|ExLt4$yv}cWTKK~nC57aPKYmkAVLx^%ZMN9)CA+^FgYu?t^qm@rdv7(>&vt4rDyaZ+v&*A>o^W>anmabgI5Db!Mm z>H}y=XCcn$os&h?JnQMLy?2jAU6)#(%o0AZRb|79oEltk5;ZgH?p&jh>tt?Hvd=~n zP;Pl*>LDjzMaKKKP!l~P!zuAO1a83?R~ z-p}Zo*8~=3rAnJKJ364bX`ZZuC28-WtB~$Hyya7Wom~FsMyvlivG)uk*T>axu=*>e z$6-NtieT$&clUhUBIfTad}UrI4;6^?UC?3~S1w9c_IEuIBp&Hf zF_=;;5%>j*EYQ2;JR}eSMkeK+M>#I0SHum9iq%$Kv2WIiJH;r}0!Otx?#1-0_ZKRh zLAq_P9KfpoG!qb=dZ=u3c0M2RN^K_A8^utVU5$6Mgi!1n_u1k8m~P6-hd>p4KJd9vaXoy0GE(9!G0yFzt0+DOb)5n-WI2uGiz(N}^0rVk8uzp9F zfuSWX7hJp{hP(-UmywK<@EP$3K6{_6l{p+|jH&>L>=Gbu$XOhG_U>YG^aq6}Lzx2D z(+e-r+yHiFj|3;|~RQtH3n}rf(@U z=lj05JqO_>dPDf&W^9fiE#Lc>SU*oH(&6OnmY5sj926X7?4+c);Zuk?$;1d44?vG` zVA2yp!{M??xtXw(==LqK*#VKrR3NU&1a71i@-wDIiVQKb;DeZHOo^mSWXJnlq!sXm zZLFRutZZ`DVClqrAK;QRU>dFwLq!lOnLr9B&niNG&&Q%mve{6=;Udkb zY9FPnUERAE4<^I0;ExMEFf7LB0e_>4{*ZueOK}D`v}08h$`L%lHmP3|(x(cgj)+W; zi@b<5SX!WI8YQ49!5*|!KDktnDm1WQ^!6<&9>6LQS z@OM$*ugI!o6Wz&-VgMh80XC+Aj5J_)TqsDYyg5A+%}B4UU>$nsuS`>SN+n5+An4@N zaa8F%5b`8O0Vko$jzJ)auD6_WJM6{lvw)KW$oe&w*@SRrFF>^l*bVo4s0RD=vP79H z)R$>{m;jVzYDO*-xRO!MG}~uZf$Gb#A2iOrn_+z1k|C-BSs?XgD5@G%!{QHnTn-S* zs@Pr8L#&UXf?$!^AE$&b6f1#i&TH%*4eY^61OtRjACNnVucG=?!6uOPEX3Ut!Z*%e z3jQs2{WtnCfcj>CfIogffOFcEOM}x&pbGCdO6a&PKBE%Wpp`Z zO2;L_<0=IRTB*djC_Vs{x42wH#Q?R-R{@$QRQ!~{BEs?_z>hn9!cfbR$c7k&$exrq zHzhooDavPwLa=Th*`iLOGEe=?Ta_#>~nzg)C=n1 z%;-rU=}zS=)?tf^3!bv=!d%3A642Z%d7#l(n->RNEaS6PcD^*k#yblfU z9JSQ2TbHOP!DrXvGX`8w%A-H!6j`A!OM+RHTY)-!7xZ$SniE96QWIFSzA(3B@M9Ff zMK=p!MOp@~2k*wbVK~oB0mnh4r1n)-c*oBZcBsxY>3DHB3xJvrbol`v7FvF7h$$C{ zt_-wDqha{qCPHr@D91H{UWRmfocK!#>AxTHRQ-JBPXe0$ z!0Mg6LZDY1tF81uCjZZY-4)ACc zAXP`l4h1s-E3rV(QOJxn@F!J2s;^0i#?8tH)|}AQgGZ@UBxgycw7^6b+&*Z7nC`r6 zpE_2x`cOCpMVh{ra~cByi@4VYJvJA=*y?My|4MbTJ=@Ub*VJ|Bdi2jn!{**S{|*7X z*+<~*M=I+Qj9M9g_ge@f9od1=2adq8xCg8j*@*(GqJw5E7O;+b$nDD$CNvd&1}c{9 zDunI{d41Htw4*Ih{N;w-DO5#^)-@{7 zYb5M>a!8Qdvb@G4{yA*_VB+_W3EMejBOc}TMhg6;^W)lG-G69(wu~iv-;;Q3(FoIb zwT<7CifzsrCm33HND@;$@qArc_iqm{S{(=-oQSdw zLm#X;@g22>y$+q|kysC2O`fo>KA_kZ6PXCqC;Ok*c&cB7m;-R(iwGXlF#ai+xHrsV)leOj4TnH+K_W6 z$cA?TV=M+T!thG+9AZxf>S@w&C?I%t0m@xKg((VoQb*d_54@WZN|{n!0j5)sn0r$W zJ#SvOwW86Y+GnRx>+E{WiB!HI7n-e4hbIp9a@N$F)M7%_MP z8FUk^txhm~qJQJd0%8yF{rH^ZJn(R1;fA|%nEebo%=Tb;@4wSd=I?}el)QU2d9!}OkMTpS;%}zcVoTKL&i>$cW_G~pINSOupbduY;s0yR zR;?AlI-U!^O;5>gAH%qXQ3ZAuw!Bxo&n}WI(IU#`e;Zd=&AqW{?GfJ|(cbx#oB ze883rL9y>36L&ptqHem7V*VZbl!iJZD|ve7^LK-{@gg6x=K-4ud0==|@wb?7X5_s@ zkaTA{5VoMk{kV1ztu4$oeOxL+82mdcZaD^gTzJHd2YPBg=)CC5|A9KSM7AQdaz{V( z%fIEbd-|G3w^>cH(==~a6&Uq^klBq$q~*}kr`edW9E zeb6V{`W2)k8iw`(4@=NWK0`u*7?b4jr#_{mYYuML546w>jM}@+Xzy{czzGVr9Zk zLe@_)vp`#cFkQ8(&A0oGeJ!`kb~Sx7kjftkDys7T9MJ9{gI^e3QW28YVC)*N z4M%V)uuI!|j;x%gGrz9CihBWjTq5yHEcDRqP5vR7Ow8gH7|PpMH~|Y|j*}oO z3s~2$Z$lZU&nr8;TI1lkqG~(-)bs`Wz`i?Ix;Y| zGaFyudX1`riSybzD*%)6miOmiJ1th0is+G?b5(d>wXe;Z*9sL=`zU#LPwju!@vZhb z=B2Hwzx?DH97;?(6UyBZCS6UOjt%a0lDl1%=%f(i&Ia$0OSuCX(cxGDag-v7Nt?aH z&F$&&5gok8m@LA)k>1Kh4NA*j8_K^b;l1xa%~4VHZ+Ak*Ivzz|Y}Km(bUQh2FSc_f zXzVN#4cR>1uTHkVmTx?3Z&LpRf|DaT0wA=_2LFosZHRM=m)}JOTNqx7fg&{jePC#F zCXH2d?+C>WzP|@M@8@$%-^_2+FAia|!L}A_u#t0Nph*dBA76y(SA{{*|zDUbo@q|uZzW&VCz>5?KJm0 zB7_Fd+T-_O*IM)??l4Sfmfix6?Z@cqjg`lgnqLGLi1gfh74Og+!TBcHWD$L#XoGeT zjS}^yvG#B1tbD75S5r5aOtBq(PuR3MALBraH-=BX+50;#8PDh4`KX~23i9!NM{5nnw2kwbS?zbd74^$tJ2<)*4(g91=5-K=>b4iz6DLr`Yq7;xbs%n8lTET+^ke#9YnSm&^nF7mwF@6PE(9t$Ffg8&ZJN4X{^3ZOef@CET8@1xu$&sU8kdw&Xhp7?Mac#HtYy5 zd_G?|NwfWQS&e=+co_fF7fkcR^UtEtZo$CdO?k2qLAr7PzblWSW(p?+Sv^9om4V^W zna7T}xd_5khjjBqjQbRrdW==27fqwIF48=@su8dfC_YfVB}Y_jL^_d6!lASUff$E= zn%{paz7w@qv=;~*JXp2*H3ca^XDetgKp^WS#HNXQLB}jPh`URDntl7Uh-0q&S|)r4 zO%jV{v$7?3O`LW5Oq-F=tGdto@ESsam7=Q5&lfhLQ&53x7>!1d<3`RBp3%1~Q7;^I z<*Cu7=K4}E-FFxV?Qo+4bORjnD)=T00+HBOI|-vbc-drhr*WdTm7)a$q=d~n%zAA<&fFxZ< zOfO!%CZTbux)7IB+IMnKO5Q^^rsjT5ULCUh$_tF(nVpED42GIQz)`PL4CBWc%WRl2 z5J60O^gu#0-xi=fz~xwtoy*aJK9a1*idd19e2!q0$Fbputtm=Nl8xF%nIJf(JmJAN z6{%GZzJTspk5j|7>T+I!by+Iv`42Vhf9eQLaUU<{-1F{x(3UGa?<>jm0e1Dk$XU3! z+wF#AjJKhrgS7=qtZ%n(N+rOt#G-RGdo{jpJCh<#PWGFBZ-=7m%{a*C)QulkpY7*H zq{u_c-2?T?Hgv|qrF{&YoR~13#(;8Hz$J|?&i*H;(bWX3F&NEFX^Dxw@lvfXwC;B! zhw-VH*BLgMJ^ac6Xe?41yNqWz{dp){2%C@}Td25ynVPzTF6y&sh=q8!NBukba`lrx zD^p!3+)H?-ia31L^>+YI_Tv8ANQb^DjYs0xT9jM$(ohKPI@uF!>ZyPDKznAbrW4;7 zrNp<;TcOAXv@IUcy7EAVPZ`z~=5`bOF%ZZJJPNyyHot0k>kxq{rmGl1uLeP3F#;t% z8)ogB6ZOpMB)BTeU5I?dXI_eVyy3(QVP3LouP4dl&24*MSP>?g$Mg$xZ*Q$uGZ#&cz9;6 zi&49es=!jrE7@^+VP?(w%U^5@WQSqs`fvhyAJ7rL=4cZC^SCO56^u{born@ zdq_MPWJ%=QAd8y-XNt-(%$-~T!-fjQdRZDf(0(n-$*fs9|1qrzut?-0%{-r&hwj4)<6FiCt2F+ z^{@ph_%uO;J#XPgJwAD+&k0f1F|ben3jQ288_H%3O_dC5lO(0Sowd@K9_uAio^IF) zZ9v|?KgQvsE_~3AmH4=?;mv%0wP~kIF(TT$#XN@}{0`wvURs5@DBrc; ztMyd$_I!Y|i$8CDI)2+;p1bwXsDk#V95f^i#X8!`;ls0K`TH$E^bWvOlO^6mz{qYr z!6(qNX!zZirwUR@J!zgW_ZmZ02iJhk0+12j`MIbm;m_QMy9EQ#_cFLg`|JQA&@5CN zw25LPk8Gc2VMt-mC%w2u8Ppw>?@X~#pn*1?dm=eYTNXcFTIMM`a3rrRc--i(b^mr3 zCYuGPvEgyaX0t7}A(h!dKzjz$s9d&O@H-f(hA@+70wg;c8D=Gpg2QZmK)dGdfw?1l zU6^|({^S<8BJlZ{Wp1WuS%j)Sv9@C$9S^1f;6yjX9|@*&8IhFLEm}F~oCUu4eDLBs zqJc1YL@n<^rNz;uY;UICD5a)WjY*~y^M9$LD0&9!YSr4ifW4Gzp~;+#1>DYEyr^RS zYd3^N6KMXFKGdFRQdxij?zP(^B*MYsTRjYn5~Fgj4?@6=$8*~j^jY9$3^1Pk6|`UF zWuy~mcmamxeLr37;iluf2YBX$-;LnMJUr)S~N>*PeX>MP+d~fos4970s@ZTv@aje z(#C)ofXeIqwr;wisoFhSrgL^?PAs$KI*024YXiCEc@DrP|2TM^Mt!#@(JLL%vNZoR z$978`J=x0Mjd{3^$lsl6>3$h3Dz{>+jwsr9-&IT;+|o^Re@N@FJ+QlhpV{>9cTB_)s$`~k zvZWy+6II?~B8j*<=i2Vaq`@5NTTu4_hK&B>F5zqv!q9sSCP*0$Qbb4%IR344b1oZk z|L7RL*)yzgTNFVPr4lZMV;)%*U5$Fc02H2yBiz?q)2sxZiX%L-Y9B@CRkhkBN;2!8 z*V?!q5eNd-KhV*=Q^Sp<6)TH9_!t$oaP%5IXFB?%@Y2HG=kuAC51 zdoB=)XZlj^U>fXcC~jMa%}{{(B&Yff)t+=f`}pEvJ+&s^#-f*Tc`a z=P%ap`Ygt2mA*dukIgn=w2tgv08S^zNw+4PW4|$2Gg%S9L1mwon;B0NS$mwHR)k1(CLFHb!S|bWFGKg zT8?Ddu1X{zo>O*LtN+!F2w zdJ^OZR>eTjQYfkLdo;{Mc`~>%Yr^55Ug7ghk^^(zvh~3Yt-9X~)l*({ic4;%V7cWp zw+E1ehF?Tn1+|_wtvMoG>U*6l_+nepH{;^kEZKW06Oo+xjK+Ksk`weVmyZEK>9R9pV~ZSZm{N5(ZJb-qG@;9e0pFf8n&=$u zS8*N_64FeWsbr~8`eK_qUTF3jxp=1YW!<_2N=HT0uv|!wIK#v z5#bab%osV~`!AP(fd$7EwNMRq{^~M%b5fFXGm-^2JsO_$mq_}IOZXvH$KZH%?WUGD zLcAO|AfTag!CILa`IYDMWq|>}4`Sf7@!ie^O_}m8DXiD$j@Ue>^z*f)5eE%(Ge&ZEZ-QDYk#(z)6PuBv9R>w?Am~r9({^rr2mD|Yd{vQ2 zQD&N(i@1zXl((}wm6#;vdkRy4wgzW_vXob&vRB{JI$pn@4p0O>1eH6=B!hJgm$^53 zct7@}dgOhLH`SK+Vvc0{O&9~5~;$H4~jn_UG+r8FYF zca=YxEmDr&``wtn8@I{++~yiLJDj7r80xL`qT4^jajS0$U{Z5JIH0Uo{!Cds0)6u} zZYQ_z^5b%|3CZkF%#|LEIrEmE=4ktVwiNSB4$~ohH}vUFb#HFlAs2E?Ro9-+*~&1B znLNG?P?-TVV9auw7Q)Kc-fmB3A7E!|CQcq8eS1EVCCY3teE&Hk8T6X?F?{A7V@vnN zsRhf$zP99DmrDYz_hUx#mtD$CHjopSi7*a_){cAuH0XT>@ibtWVF*!Gd`YO9_&Vk( zLOIx=Eq_(b>t$8$x+9WzZY;$i-(x%1trzy|%}c^aR;}+LS?<@zel@|FHy6+4M3B$9 zNw_Al4$%;~EerD!2hCQT5Fc{ZpEI-mRf5vf9%leoXiea})Q<-|nHHWXTNccAD~m`* zRBIx(QO01^ad6#Eu58Db<%SogPC z>R97yyzOG{!+(NjK?fL>-^&*Qvt@Gvjxzpk=LTiJ6?&HCO#a+`Pl7a_wND=vH7?W- zxJu^kLY_C4c6jMOV7FH#(dEd`ofT5`4j3A9wHnT zQXZaq=L|ejR#4}c;91JvldO%`eNQsj3D?F_6}01@>ngs&~8h)$v`p2GZ zjRWa4ASd1v8PNfySH7`(nyRlw&y_(u&S4t9O^}-Dxl@jl8L6Uy=y$y$Lft367FINo zV(s!a+nP$)H*?QBpeT4m5_wHciRnqH)&Dd(DaAw{|BRVFL}vvzu)D5L9)Ec*6`LhJ$GvOOT`MA9_SOn^Ht|Pd;yYBc-!auMK+#WfD*BY@1BISJ9;NrFDZ> zJErdY)GGS4QcEIB3gmU*-s{DA53_Y0EYmtWm(FKfdUhpz+|U@ye-$}tV|6H^%|`Oa z;%mexr_Svh#wxnr_uY5~&dcZBdvPVJ{AJ$1#}#d}?uYog(_cRQ_)I(?8t1>=;HFP0 zkdSto*-BXK&Ofa8KDd&Kt-GFq`sYhsA0Kp*yzNsheIZtypYOl(v4gv%Qj&2_<^g+T zSw&PzPp^GkJ8wDWye7XbdE&Q9o|N`vSJGD?KcN1cbjaIBa;N-(%nLnb){B z1vxY%WVIN3UsAz(Q(blmcTJxmWE@(u?&T!?ik&4|V&G6}UxhAtg{$+AjtFe=zJ+zC zCeQdtO7_=z?|t20?yQ_eUS=js_IHs@Cn-D;D{p^EDL=`)=TCBN|D*@(6&3h+IsMKy zu^>-Dse1yE9CT#HEH|j!!z6wBmzQ$-wi?Ofly@{!m7k$qiwKv=8}!$`v~A*HY=)&d zppgN7!_lRo>Kq}p6I1o}dwJ2b)aJ|Y)i~0j*GhcjzCzp_w>OvlRUNz;q$Go5({oO* z$PE)_*(XmhB10&pP|3&FKP}=#6_GYAm)d?(4Ca zMCY55QH6ZVVGj!%SAjkE!as^H-!p7L)s#4$e2A(O(&_$!dkH{&Pvr*rKF!JK#v%#3 zbA-`BzPeh2o9F(iA)@uRuVdEH07-@`AFoX;X0Jftj+i&=OMtiP1)zW8`7e6RQAbcx7-Fwb(ke!0wb6!2Oi{2U7Sx%5SRhv%<9Tk2La9qZ&)3WT(5j6 z?h7;CWFy>?Nspu>jZ2z9F_qq6QgUXOp3S1h9{iP@ur6@5S%+q0FOrg;mhbOgV$BIb zVErVmrIA{3qDG#M?5Nw<8lXxs`tQo`7?u70XK&4CI!aukDuw7Xq+8j;x&hwk$Y_J( z((9q{22=ghuQ-el4gwltTqL=Nhmv<8{~W-VjQYXUaoy@$=JpQOTkq7}lWFL#>GQS2 zDdv#A5k0oIwu=Ewtgv^f*E%JiFN1V7m_w z?@_PI4K}+WT6)PhobxeiQiw}Ag9{Qe37$~9WM2pDGP}VGd=;Hjjc^QJFNFlbkfJV- z1-xcgJ`fQsbP?3LE(2LrCHpxW%5YUTVch6@GO4O$3 zs1)lqycuptyjuoU(k9yE0*BLs*h7L=RA!aKAhtj|!aHuz^MWMynp7ttT2T^POx8A8 z`71cujJZ+<;t=%>^ZY}Tr;7>;Bmz|(wY52-N7ts!I#p4c)`Zb79fLCUmgRxWQt!G) zrILFgImSES$>fnAs>>i}$KZv=%&yp?13|<3;U!_(8$Yb0en0dGAlzk2#$tJEYQ|S- z!XF)7viP7OL7kdss$3m{g?fM(TT~MUQmRQ=cl_q|2y*(>DI9ET%cwaZE z=IknKZ*Q~)-$_;^DHKo7u8h5fe-t0~Ab5X;O}^?I&ZwhM7ZA6kkCw{zy9;~*Yy%t= zHu68?*uH9OJMSc^l{7K!)GY0N%W)4^^QXsJZX(VKE8*tS07Vt%?LK8S&ECnvf!WoDi4UFcD#6eWca zk*=0YdnT(>+865YRcvEK`V#SW2uPvHi3&Hom(n?nZgp%60eHt!7&9p4-@r#$Wt8*@u5Kxy^6oZ z>ES2UP90?$>nuG`QfrWVv+%=>encj~Ct9i_+5ee-Dl{L6R!x+>;w&>+7&W&vDsWvf zXuy6sW8jm@<%T#9v`a+w5?HS6NTuQ+#3%RpAJ#9P`F4*u2IqcZ9gGz@E*)+D-wyh#aQyO$#@-#wKrl-bT>c{n-3ou!H*Aeb${mP5_P~kB5dsKXm{}Yw@{19HTFF3=7H}P2iji!g)1dl`1H^=i z;i-q30kuwJL$j~4)>7mhNrMgRSyxluT>Ut7b(hvY@D39IYxd{Er02#RrwFq8Fx|ch zVl~#1j=B){J$m=3au@bCONsx$V$RP%B$t-z49(HZ_`zosR8P;cp zET(ojue5#WH*bpyqv{oGZ-*w0FY_v>Vog9QJ8Pc3yViClj@{dAs%9E^A$!7ew`j>FQr{vWdh?2R^7IdWJ%E zN^3X!-r|G_f&$N~j5yLAG>0leblWT3IBjEj!BLTT@b?N%a+0`O>(uRH%!+nPSabwc z<;2Z^H8E&Yl2|bB?&5PPefWt`p45IY5X40E@EAQ7f&Ni&qzM zh_F`RC2kd};=?eraW(B{uo5L5O}XOu8I>u5bohavv=#En2r-_V?7ty{8RC%&y5Wy^ z6m#;ty7&!02e|DrPFT!sK_e4j8~{1F2k;K4x?z}Md;ip)eCi|<49ogL7CRSlm*C{u z&6BaLLlr(aSOqezfr)nGRW0f2>Thw{ka_f6S`F`N$DHFP&nkiOdxF8@ErnE75{1-GfToz*ub{ z2R?|!hO|+?(75+pVZ+N=0f^$$k=h|3DZ#lP7+c=OHRa4=X zIaiXzcv}zlh|h7!aeAauZ{z? zZOQGIBP8cd)8jZES(T6z!00@=;>7l>ndR-aT!!-xd4L|9>Q_I6Jj2bb&~6e!^kYB%ivRCb=T5s?kJ#o_fmEaItA8@7zPSs2l+`~{aZF|0BU^|dyulPau3#YNS zAtVe|JILpmyrOGmCb{v3_I2C)jtY0Qd8&6noaw4Vy+IF8w)D&g-&7jFr6sAc>Dtt< zSkfZVor8=SRE1$k&5fk49JQknQ7CyM;~ZlrrbZ|&D>~K@Gk7NF8Ln?2p2cuki2jq{ zpej4)wKIfqYrAt zQ}NG$N1OYK`=6pSkB6%L-}vl1a||ZCGsDQ9Eqlz2eczXm#*!#Wp|lz^ma$Zp$lh2I zqQ;U)JOyAx_$$Y} z#M4Y^@3dtoi*!d>|C-$yU0d(RJ`ud!AydrI0g}ANy#2l4AE5*DU#?@~A(tPlZrl{u ztJmy)C9P)5DUMhC^J7SP^j596t+p>y)t2+2gCSv*%5UZDRQ;IyD+r$cg&Eyq?`rcP zzRl)Oj41TuOZ&*%tEmbDrN}(SJ9in)I@r~v7uarX2o>M8eSx{Xd}ok%Ya)rNe49vt zO(LS&%eH7}Y5ctH2)z+sp*MN_tKFZ)%W*AAyAYP@;WtnCr=5n+9_N*tr^#R()y`hC zQ+SkvDH6+omG~ocb8QUjrd)Y8W}YHD%Y%)U&)c7Pf3@~(n~6JqZZ$?yWTP-}q+AD~ z+@vO0avu_8F@0zra8QDv%A5@ za^<6t@gw5NZtFMkI0?%C4~QT6-opdB8zn>!Ua8X#Y)D+ipD% zCDL(;SBvUEbe6Cm1rmDbw(7z}PAK=KciN$)M-C7A)D#YqXRp~$xe<+eG57n9oo2#5 zx7$R*jrC6Wg_sOrTeCv#VJ&!wB69p~c&5bH&Hdz$C%wO}LIqacKv%CXa%L%J6A zF_rp17k~1PJlIjO+f9&UfmETf&01MxRXeMV%>Xn$7a`nWn9XD*Y znR*OpLm3V4!=41#He57}hQEL*9WZ=n?Ta;}8Y{>y+GDtSLl3RtMhAltIR)>SuD06R zu8CI>0g@xOSM=}xrB{229?i3ffyo2Avq`*D53FC=dHVd=r=!x%ezfmjH{Y(Ji+;LB zjDgmv$5Hn&a4yXR@iWV3;BtVi_A7Ps?qt}%>4s@P_w7kKDL$z@Rr<{rQEomU$LoXp zAP(&s*c00xfQg%E{lNsf!+kT()(|ALGgKuufBFtAT4IhKi72Tw%MkUOE^?3V7&%$^ z^>f^UHKG54!Ex133(5_R@$CcN%pX~Jr7QAy?B{M9On+Z1M+Ot`QnJSI<-G2+%^33} zeTrZOLDS48<$$Ahj+^WJ$iQ0v$^o{F?!}KzyX>X{?MCYydV~f$KL;HiP^X-G-+B91*Vg1}mrkC7^F$2HZ@>?qu|MUc zcGqWiD?)ML#T$F3N{6=WK&hOzb_Lbq>bE29S0XLFY~|V)?L7Yr&*hE#BeK#n+}^Z~ ztSp|bN~02fX5kCXg$~wd%@12jy|3c#c7$tr(|)w2faL;NSV z^=^&)lOuY*fBPkUp;;3)UR7xYlBU-V^PSR;-uNM?4@i?2_3v5CxqFanlnj$Bx@9L7 z>+t>I)X1OoU7~^h<0t=V>nobbZ?%WDbs`i#Cp_Pkc4Rx!f?8?AV#r+V!92Qx2IhrN+;=@|`ycAtq{z~-t1jDY% zwBEP7;DF1OU83sdX=0RH&eyF2cz>_|H9FpM7VEKFd8QYPv}q0Z^C?p*_o%i%cRDtv zH#lEA+%M~c=s*49vs;5+@2`i~*^6ukn;h*Q|7))G9APl++|;XTm)-EEbsROA;%925 zF;xHBIz{0>AdIt`&d5W1l|Zt>YcmT(gr`sMm434hb`VL6pX*9+8+SJp^(T7Hv_{xr ztu06nwpQ}7ohbkg+D`H1;G z88X-NENtUib_&U^OK+8EH{p|^f->n(ev$}AnxXpdt`WH4l{c^V6-p8^r6~C^R zrIb+|yE*5>t{MBsojPzm@SZ;Ag1Z!A+~$wK+cw{N%SWTTnzwndq)9xROWdKAJ$CIk zZltEBJw#-1z2lzt{9!8RkES~28wdD=*Bgs>s!37R3aiZzyxR=SVMbQ^wGw<5%xQTpUra;H!^!T{}}RWD57o-Z`T&IpY{zG^uPLz6=8GDnMK#z*Upo)qm{Sy zkHxEMTl!-*%3JU2`SEQU%XA~1nRGB{tMT)W;6QBDPQTLh_v&Hq7gw%&&gd;(y7otX z@sg)y*tOu&EyhG|L_p&ZfwOh_Ln&u~zo2a392s*V#dxlnmwI}3^{NBjdFUZ`)bJ~I zHAqy$eew-=yw|B=aU-*UJ9Wr^zUYIOP40)S;XX-|<*Am6l*wP{%DBE?*CPvqbsA)E zu}|p<_iybzRN@_XDyriAd}F=5>CP{ub}`q*zFf6lavVOuWxX%qo6V~SiSKwjTN_qh zZ`N?3)7P#Bqx$1W7Egww+K{oMxZ^$E?U?$@dZu&P@qaYWTr988e&g)xiX~G0n-a&N zFR1&v^&83#Y(b-BS>oBAJB;^8KA-BM?24AYCTdL>Ntxl@5_+n8U@s)R-pG7U?rnQt znuKpF;gizM2KrmRea=@AXf;)%sB)6c^;(lRwQg_IT=mxGh~73y+#yN>!pdx+r)KfC zX!yG_;+pI|#(+=wpn92(d70h(H*T?t9ggxyqbRWMz?I{81C@2tALH8ODW4s+IxSm_ zrKEf7=dw<4LOr?Q0R4zwHAWm0&LQ!d)Y3LGl~g6NN8^!arHwFcV-jGH07lj?AJncQ zwQ;vSfFkuL>*O@G1K`aA=ofZruR65x&aQz((u}n(`f6F4yGcz0PkBgiEj#uC=)XKl z&lBD%_WhvTDJg%ghKW$H3{&}dD%VAUq3KW;l`)#_5Uokox(LytE2rViH~oR*@hYdb zLsurrKZt#@ErC}hu2|qm53>^Wp^?GfsmWNWi;NcvhX7jyVUefMHtjH<`Vn+~BHtR=YgNMLDr&w*84IdG zqun;L8qf#2XTv0prNK;*tm^K8Uj_hYvFi$vXJBixdk4*QD#tn`{G>j76GD%+L%W!<};NIwO$`>Ogh-Pr7qvH+s zU;5-2AMD&eHXC~DSPCQVMOOt;+n_)z5Dky$mlaA_j$ljue$C@sL;P?FJJlZu?)7$Y z_0Dz*p^;&M-?((N-~sido@11xBal}DLDH7LqAjVSg7cwEwU3hGkYNu-kGIr#XfjlE zh8f}!QV7M)znO7(=7n1$6VbgP`M3Q0#BA<;7w+0SqHGwHXRCk^J02e#Z$IUNx@*2{j&7gS~e*(1L++xB?F-5!AvyZmecmM${tPRUif=2gPMfg1TEbhRsc zIpM|8ltkquN@5mGJ3NMEl16j%3GhyHU0S-QA2<{tTf>nX0NYA#4*3%~nBP%{s0aFc zG4!?Y2V$14N4UTfHGxjege<)9Iv7_tuwTE*T zt_~&J({O87jR}d*mcJo$R2f){${S#WCPMks`X!@>gyP#V^xL)J@11piC@=kTkHE~s zsjt|UiI|-ZpYR!cxjOxFX=(iCONpGJRN%63pnr-1oD@dPeQ!YDUG2Y6xpK^y_(7(1 zDLUUs?I<#Y{>D1)j6p=tKofFrfPrQKK{2cu`cKN~wmlNUUHtukvQc_q^0WD7z9(cO1R6Gj`Vm`o-8c}U;8dHheu z2Xd*#pjO-}-r!rz=l>Zd$mc`>@xC&m#kuheBcawC^hF`2>h)m&q3?c zimu#|aE0)97_BW#-_z!L)#T5eQ<^&$q;{wlAB>0J=}E?DLHc-QW=DHWN(+9Dv8Zdt zJUP|5u58!)I8GxJCKm3@O|$*Dn#J`Ich5^Pe`CYmG16-6h%-+jjLDfKIL94knvfB4 zBEJ2%eHg=nPACA^a9q#|Pn=H?Xrlf{RT@jm(0Em$vfK4o?#p)>HN8aQF?GN8%gbqX zU+eE9Wm9qXbXq)8t?43I#gBbfi?n5(GVOc%8A3RFy%#xvS!}K zp&BXgdN89`lJ!xVIVTm$`6AM$_W3g9_|==7LBs8_Qvm%_@j+S6LyF9(imAo* zig{`}efi()tftgBeQS%7=$uJhp#wEcon;422!&7;J{fg=XzM6VZIJe5wp|3;`; zviz$2>}c5*G&=l|$2>m_HmK&wkYeg-Hq!}ROJW;s9o$y!8j7V`?1LrnjfNEX zm{yV7?KumN<xV}P$f|*4EH%r%@Jx8Tmj?t#WxRpGlv@+p>9X{P{%F~ zO@IRIdK9va*YtX}MVA#uo^dZ7r{m+k5LO_>4dE>yZ0F9_kF_l0Ap z_3^vDTbfM#A0e>|BiYfH zdifv}Dj(do%q+Ke>-kuRG4bONF#$m- zDFUO(3HD_wfQE@p5aqOW@XIx(h=L`MG^bmrx`i}UJz_-c61d# zPKQzyY=5}IvtHEIYR&Hn7UEK{}mboG3x<^`BMb?5U)rN4 zYA7E$8iDxq#A?q|n&$`QXYKAd4*g_pgmbUy@+2r8h5JFFg(kU*QtxG4QV|GEGTSN2 z-rt{1?V4t5M>^7kvsiJxpUutgA3Fl~fWilLs-)gjj@Prmd4-TMdC!A>`4bF{CaQa? z)MM>4V>*kVIEYc`xi}j0 zAd&Ex=02}Xh0biH+Mhm#s^`nzoDHdBDIY2V?~>G3=9SO0u(87ZW4_3-%e3qPo0A`u zm%&%DOv3ZFe+>#$#y|;wZ3)pD+qaq{la&whD5M{L#0{x=0Zgj{5-ggtD3|!$Ty0?e z83ZT5z(d%$IhkTc!Uax~DK%OPmM9h;oz)3WU%JTGN@7HOTO<;H@VB<0CxZJT#h8jr zJ>SYXLdWdfMwnSoJ#~f^>PsaE_~3cEcSyds_z4j#^HEos zh;`hV-#@^}qbplsFG6mDWnI+1IA_w_Sp|kN{dnVO1V%UrM6nfOSHK!SSEbuj*I6Wo z1hDchpJt`#_Dh4JvU|5)l?}O=ZNc=h!6WltT`Kow44wqdBbBt;qE}t45y%P{=?zNlOYhuPwelK;_M>-V z1{`25nLs<&Tky$Jd0 zf(hayqlGjpma}6i_~n1Q9#&`lJC`HIw9%r5Z?TuxKtu7LLiJ7M8psvm{G}UIsp*3< z+f@x`#nk`#k_CxAO)mx!MPNq12`>DK&OB_Zq;@|QhbjeucW1^~;-a+~FytrpK!El% zeH+3OWJ54YZwu!sXG1a0$Av$8k4s<88iC#IfgKFM8pgq}&H^}WYBZwBn|JA$#L zHT5g3@Va9ABtCq28_U3R=0Z@5(lXz{iWYU)4co^<)vGj6s(xq@*MJdSiqS1BKFtBU4w)Z_6!F-&id52~{i+r|#jEA&qe9LUX zt4;k{!&46tnOCg~RW_@Y+Md)XEy}Dx?kywq+HQpPJDV9i1#QFl zp@q4X?K_fob&I{cR9|yqbzeiNM-E+@Wo7{wKQFLFJ(W33p zmSi>cmmoxsEUNZ_kLMnvBZo3#7azBTaj@$*4rtB81Kp~E``-S;PeDwoaimj+y1QOzkFw}_u|iw#0y!tTupEy5?4`^z(T_uJT2zp7J;zJ~doV}t zdJKbqz}+gm-O|0mmc7Ratigc3_d)sKX+E|Nb?MU&D@ONmrghktih^nOAEHGDBhgqL?WUKY!ZPUH4tj=b#M(6`TX1CW zgLgd%KaLvG?Y3E>|2-%#tm^xR!^RrqRQtgY-c+LHUofr}R|eweX*ABll=2YOe;>_Y z1^l6Sys3ukJ}2!sSFL7p#wj;dL2O4_n7=4>KA1V3aH+oC{IL$T`%2}vI+BrSj*x5o zWqy{6XI}k&Dhb1k_N>utC57Q?ieK$Ml{thv*rg`-7c`|KV0v!K_|&Rd$G0Ev>TrCj z_$RHxX_i8;Zcsuu75H$)I^zM@XG+_O81Q}#UY0;V`UwU?rQ>?#e)yG+gqa$5o{Rg^ zUTunqph$aCq?P`dqAQ2~cki)i&(^}pXyYqONe)Gz)u9{AFw?HVVAka+W~o9rp*k`B6ymnS$ig2I)O%NJDz`iq&Ygds z6RR>N|8w9tZl;_@&Y&$S!WUnv$uT@ts->ump6k~l>Nlu>2v@%%e{fk_tzJX6 zNaQLhmpPgGikw%S$ZpjN|KI$0aAeFy*w^lC^r)IZ;QLJ=v`xbDY5F;DZdE zd!C{~Jv7vNTudQWdd5Xp(MX=7bbg~+2m3j{6oxCBqA&t5Py{2$lnHoP6DDjV?RfbJ zT|0soB4KRzojkvw%AG~NySnnm5Bi<$U6i){V>6KaQg$)bZU@`5TsC}Q^^$CIhuTBy zQ-36*7{@wJL|r+gYl~r=HmX;uK&7rK@eq%Nv-n*lEErQE*3t7S0y>Fd1jm( zl5x^6VCioyOq{Xd3`hhZ<`&8Gjk7Ru-@tTLY)??>o6O|P-AmS|U4IiPxe^GGN=1Q; zDtHAwoT|e(-hnNuxH1N*=8G(y0d#d3*jTqNE;pRORr3B|on-0fiANL(Q+wE33EPcj z@=~eDqHx@??LIii;6AiXP-BZ;)*;Vk`S$`_;+`4$1J__LzdHX3?C__ScYD_lCog!d zdIV^73Hq$Zn6dk*r}>AKX&Igdc`9{*89-UfUv383?ctU2jxvT%s+igl_#YOrWl?q2Z%MjgR zC^?_RYCtYd=w8UyKBtxVOyo(DUGd*xWLv4+$%3uH%J%{He^QO6ti=cRfQ<0iJlV12IueWYN-`r^*ibj6>4o_H`@mDb@)WXdnI#>lrm zIzBv%E!$9{8G?N4Gh%%gQjs!nFouxTAF@K{b%SX;eQX@5WAhjXslG#58xL2yuAxcx zOUmLC9I}4`7qb$L)Xt&kMn#4Sxpg7m*Q~P)?BTBaqffi;A|Px4pQG0Z)W) z*is=z;y-Jp*)gvX$%|)?O<0csj}ASX1F9g1bg2Tn1i+TBzn8nXRh^-Cxf!gE#NsA- zfH64|8Mn@c+08;p0wf}}e@cmsE+VX{iY_IjMxk4h@}$)IB=#7(8rhUE_eA?ptcH}t zz9w>yUc_mtfies$ey8>Av@_(r>WtHgpx0k4Tyfvf;pt(|Wcyj@w^4$&KNRos7;R$y z^u4wELpkH<)LjBssYvl-{yAqCz`tD%TjX#YCz5$3hZn*qfS|MmVOYNnsD0RcW13(P zPC8eLrUM)ftFZ~MaRnSXaFY-fUy2;A4I`~?+pdbQ>Gg5Hv|(p(e{1WlN_wRw);#@ph|Q7~02ic=8u9_(Klpc1_A+)gM3)6t-%w+PPCRc*NUlhCU^*%4uO{ zo7?~~yQ${LB8A9NQU&&kRC)U@Y!bCW_j{<-w@{rXKq`3zZWeLtJ=rC1fCB~%T&M*X zSz4@_KLNod>S-^_nsDo z9d^`Gb=};}JO9XT$zo(f+sEd)^1jWz>90Cam{ZWIDCuB_ebJc~e`08oq%OEjDMe`I9-%JPrj+8#<%4FSwUIqM58hNny$dS3?2$h12L z7(4cv)Bj6Z+_!jamWy;bzu$7bvb3P3wp%?Iu=>#I_IIDz-9zl1PwlO4H$Odf@AR8* z9bq3()`2{fE-O_mkPfG5ICb#d^DwU4=$*nhPbnudxdU6u?H-s*G5Z1C@w7lhDpTsh zjz{NR?ts~|JO6F?N%R>=;-kH~>8vbwnlu=j}y+ z^mwpH=-%*956wuTI^g)T7!XO_K%m6oL%2}LJ?J?O+pxMW;A8d}#{JxSe-itzM~Va(^hv;w2Ym6AEEfQ?c9Q4yfZi42 zdx&HZS!c-v`tB!@z5$V<`$>&MDFVagfW7I@)imE3a;C5a5RqljxY`ZC#gM&o)B9BO zZA)a~w%t*W93@XKRIS}@(=$klo2JAjN8fySx@m)$3nZLQmfz2giD!GrO-KCdOzqfl zrsErNc86ruF{BWxz=p$iY#-|~pzA2#5CyPV=%q-&!c=l>MMV4x5Pz(QuL}S|Jmh`r$=c z4T$16w9zrdC0cD`_l}EfY^E7mcWZ>PL3?~6xDY=eS=%x^f$pNC-1v;DJ&c&Len zkVrt!QSz_=#cdK4O`G~;up8mD@Ni3z2^8~ApW`1iE`lY_Aqw=Ot(Lc_K0=|i^U)y zRfdP4U=4)ZOhMqWR6mJ-9d{^U^0t(YFH z7wY7=ls@66OJnM6Q;Wl?I?P<=J{QT!!J9^5;xlj0ZukIe!cKe`QY3|1szb%{1JH9J z`)@nqCgjl+@iS)xA_2Y{+!lQzJj#zQ9Rl_Xqz(!NRw4g7fN-Zn-A6}ZPNxCAJQ!jQ zaL<-4$=R+XzF%ydi0N_T#!(vCM9I*LEW(8VCGKiv^g$wwt#fbgrV} zS5SmjG@enBJZ~e1kUh{F^(#fdF(8y>Zv-$Zt>JXcF<(A2CCj`vwy5So$R5SR!kD z9F;F-xJi6S2fhj?AIB5+zrv$wM_gQ#P!uiE!C%IgO`7&2TXzk3i^kby#cMs}>Cj_RQ* zW3R{Oq1ak6G5TksD#~#AN9TF)0O1q#s_cG%aR4g$+ZOm+fGvg85PDA_7=&8{Nwa8Q zi)qENYsgqnvPTY}-2h0*KDhtmdQ=FY(Sm7)$hHcLL<=x`{=fD@m_Z&)TL{|;GNh&g zMV@0APOSms{E43>*uv7|0Z_Sn2Xwkm502a*w3cq3eML;@Yr*S#ej~=58{0kcOq54H zy3&WuCqKiL6QHke%lF^z?JxeU7;Lw%-S%8$F!1QgG>$@Cn4K1Z+(~?6`=}EZ>hJfd z1wS{r%}SmP2J9Y*j`CKnWAcyg2ajgdShunyv}a)sZc~=yPy<`5gLI2KcuASOK-f^p zPi(ygcD^!8Ru+8W1tjWM0pg~Hj+iD%P)i3V}6@0Y*sGLbx${2b}^n7M5l zJ3cDq4%lRrBj?b)S-?g0BALHp2)qB%k03X@G%?k|2gen?7k6wJDZ63+dCG4@Ph6^| z<9PWYmK8up`_Y3G&@L61G*M1kBX&U~-}b^N2QA#cy}nx+5sl!zJ#L2sdD91eqX+h-r$4S1$l3_#Z2b?)05{^q(=>kL}SRwqu)4gQWa}48#B3hcT~jISSf^c;2>h1Ku`c zj(K4l*!Vs=p^r^?t|Tc>hsnQbMNr`JjZ*0lWIOiD8K~q*Hs*B`bon1(2S57Gs^~7F z7eODVg8YN?{Kkq?ul|ez-U7HcA3*&j#;|{&d!JSOA$7h)>RPwB3S&BgGxaN0fLh;4)HgMiuZNBo574O<>kU+}j??5(g7(~7T>%jrHc zu77Ezb*JvZ{9PhXTn$J#J~oZg|BRHt$A2Mcp9W^XbR+X!j{#?%=#1~l0xEv2D=b5I z0DrvyRsXM6DWRj=hY3J#wuk=@xVB037Q#2iNQbPypuN6KH=OZaOky9EC=okvRkdEO zg}83T@qjRz#(>NbU`PObVMl)P{D{lHb%B4Wzclz2!z^J%Nq_*-aiYH}fqAnxV-bV0 zf9|*x)TO{>-Lb-d&;pN)2rM(79SCqhZk9cV*aG%Hm(4YtsV{Me7q=iZ#>O*DbQYfZt*x z(^-{zq7T3yXg!XsC-oxoRkS~qdcon`*xS+>;y`QP)*iT%o_}*N;)raB-D+xY`EJp^ z>R-fc62*(J{%=z|el_J}+8eWP#m%Vtn3noV*xRh<9dm=1u4;$|!AmMpPwqL{k0 z)k%SlW36We(c<@po+SKl1yCRQ9|s4zz^Odtik3O- z@=Ps=f;8Ai4XXjSPW91tt9jR5NHGt0Bp7bxb30OkjD{}6?wh&5Ip702qBwyp$Jcdf z3GZ)lKBx>ea@68kFc(?xSrhY}A5JzO6ixJr>1-Hn%nHaL5yk-nJNTI*$`qe~X$s_I z>)&6$nyvVl9+5#V5_;z0Ct2J=QOr8Wz6jRr>gC{0}8 zXn3CaE2M#2SlFAL540U?4SyJ_$7HZ(hhL?n4Vlksl*wGEHvS-ZcJ0WW-3x~~cxLUa zDb86{!qs^ojsIo~yCdvpQxDfgq#d2uBSL@LJp@J0F1}}T#62Oaf?VqV*C!P#98E_a z;Dxn;B_;gF4#qsr<42pOPh91fO*INM8o&q#<=b>Mj_$G)f@2B!p)3(Ho!Ss7BT`kv$w@{b2~X#)WGorSDHcUb@f=gfuUG6{l%faT+s;+%eaqrozaBt|yzDtbA0&GyW}Bui{5N?XuI}c} zDS%JC9U+<9FdzvEhlSQuWAg4sUHJ8d;iCrQZ8wH4YJgqBHv9CR9ZI)QhNp^T+QtpJ zGV{t)B=~I%$w<*N4UU@d6OCeOp!iP+wCnPlcHsgkC)&-D9$nnNHF2AxUnhQKd1(4X zblzI!*Eqs4c$XUWUrrv=QN$jUyLEhz74{;COx)hOPdb>r&bKs+PLtJaXt$O@+=d%(Hpw?RyQG#<7QY?p+*yWgdnx+2WFiD=^qBIQrHr z%5GF?zf%3MWZz$SYEt6x{Ce6j-CY1J#$RWc@6@-obA?q)Rxqxc+8QXSH%o33&2cwttg1m-|VpIg~FQI398yKyb_ z1}|nf3(}VvsS(k+A{ge#)JRHFkZS&SA8fkWW?Hr`*}ej9*XhwyQC=aSmu7}#WEk#N zm+-{MsVVLr0#~Y60XrDs*ltQYa5x-?qUQ~yoSjWpn6AXR0^H!g+^ej0MTV#OWa%h~ zGXCwL?w~jD+H0|?)#aIc$a~Z5nKY-tUuYnit=kG=V7$}#WL!|5b()*~-$-r7_-X0A zasv{E2ZrP_!}1)*IiS9n7lY&tlzpa{BlOcijJIC)c?JeGJq!hSzMREg6M>=!TKdOB zQ381&p(Ns6mFAM~8vTQEId#ZS9tk5rKEiE6)ERx|Bb?l)G*jF6MA_q9`35%iXc86` z{?1eV1X?St)XDyo5Y|kytNquo*@fhiUxh6szTjLVhyHRl${PeaO5ST(NoAKzQcZgF zF{vl1u9lvQW#~nwBt^3L;^!2RtSFbdr`^}H8X#m3di|xbG zj+c(_^aM52SHQ#N7>W!B>(F)iJgrHaVLn$IF?x9>0rkMIn2`q=O@p3Z^5G92$DMoY zG9eXaWaiVn6Bl@z%KPv+S(9Zxsd%VTz0=SVKMy6ycvUwYkJ~H!)sw~E9WeA8{rHfH zM3Bv@a&+`t+nafZxk5H_*qL#P8Mz15T90J zwWzH}f(0*V!s+y==Z}G}#Wd28s|j35u&Z{b5G2w;_+=$`hn=(!XJM81urz2!`ZSmH z(g$g*llq*a2N%4Y`WTrBB|$7TW~4nNaFb0S*%oP%+=~fX@t35V+)&EXw^3@;T}GDQ zBVhTA5Z3LK#8;peM4N%IIFS1lQD|kUtoFZgtKTy}&!LW;aK_HBrKobw6ILg}WxY+D zjkw_9+-{wy)r4$yGmXo;ZL3uz8qfW;amSoxBi8(&Z$z(NN4*CTa=`n_^%Ip>6NY&o z6|1gaKLD$(9YQ+-i5d4G&lY2z0;l7rs~d~phO;6~#&%FFC1lpe|A1pt+3!m~3kQ(~ zo;&8n43^dXRaqf}J5+F;$;Oe2?(vBdqS>oMkZMTGz><=+prHG{;#4p-z(Q%YN={G8o2&dPB?(_13Xu z7JsAdB`QY>;rX@+h^6+GkPm3_KF$lX75o5`Xw`m_D8-w-X-8Q4& z$fZn`${b;L{=-r}(meP+Coc`DK(qxeS;liMhj#5ZR-$n zFD-ei#k;7Ge?xG0H6FM7135_@vqGhMwHIAk%nGLRsQf;s4}(EY_O~}P7vAf~sPd#d z-S#+zA#a2ceV^Y;$V!=S0D|%Pz{-9+qkkt8Y8W1k0JM~pX7KN_d)7>^SaxYGw`-iD_ z=NH;o1<_i8sg!?|6|Hi2PSU}Yz7bC}9iL2L!w-mgth)N|Qs=$T@{ZA|B@f@y)xp>U zd+b>lr$AeeA+c-_%K@@tx={IG#_nqp97m*LH3q@b5niqcb=1pP5lGADBtL0s1<-pc z6)tF?iOCOm^0a+U>IbB9G<|n-M*g>57_gz0I;NT$U17f=3ENTPlMRey(a8x6OO+w} z+!{HWK9Ak1n|cfzK;unxO{nx+T4Ht>0%^q&h7N3ujSO!=q?%)6lx96pZZSPpBg3_l z;cnk~W<=-wRCl>C>b=V@&618VNk(uWPf}!_c$M&iJrN%9S#I&z$ap|5?78t*IIjCnDV%V zH*_algk^&WmB%lv3F#ya3IBK(9rdv*hH1l0nXk>0AJ@lHfS?0OIo0X#S{iTXQ*Ybk zw4Ksvx6i#!>Dop%BAq~_({`RxCYTGNeCQc7B6W-$CBsda?#6oV9NoJPVszu}ueJLh4o@*s=e)l(Xrw+z8IdtdW%_KPNEl z>PIAJ2%4zJ`^!!>uVj?xK|Iy*I3Dbn=}Q5a?j8+64gHtGLZ?_zGk&uN{d})1du~Ht zp~jeg+U@ikQ=B~g_1f{@T0F7{&{il3+~K*yw16eUXSq~i|43S9jKh5YqK#MN%w8>; z$<$6>(3TRvUz*1y8}pdF#|Qt9p)+xZs*S_&n8nOsI5YO$SjU<@WSOyVm3@mELPN+} zlrm$+ED>YhWi3i&Po+ZEP__z5wu(}ruTo(?=P!7#bDitF@AZ4{=YGyMERa-<_8A2x z%K8`ILE;S^60MoUC8*$?V!7i~mxb~~UhC)ubEA)%U#SPpdo3EvPDRM$_%yf8lT@Fn z9BtSSCFWN9+u|9RfjTdA=VdBlrHNS7E68i2oPO&w==MYM>I5GABp=K4ptU-WNToj4 zN4Ujlb?9*gENQh=wo46h-KiqWZF=C{T~pWm=|s}hUVZ-9SnB#}3Wz!Z{UGPxjug? zDOHt7ol7oBsR#R*+)1S%uZDYF^_fc{zH~QadRDM<nS7B$L1a0ok-BV)TEk`_!U#Z10_IKd~ zU-Gpw#O(@Z^b4t2+gs2gNn<*B^ak@%d0{JrtA-;#BT|3l(^U#uPNo7^FAwrBbydIL z@(67tb5J!Y&^g~sq)gWOr`=!*0TInwR#z7#v^!1B$HBZikod;BD6S4A$wR6JEvZ~? zkyx6lw!%bQN5RwqqV;(EN(ZY{)eJ{fdd#yFj2Jz3!kiR&ZTv+sDSh_X>)F?nAC7)Z zwf`7=^6e+3Wu*nCowi#847Tuf;k#zkP5x7n3($mv{FxyFE}0&yjZt8^yIX_y=UEIz zM59Q0{H6y&E_xR6rwAM(=*dY3YYvf8*>zv{P0g8*E>PGc|44o; zB=W~b%0cGbr>}fx>>zqC^ddK%$sbsOl#%g!dxKfM&miDF+YxCk8Z^76lVfz${JS~U z5cI$PpzT+oO=HU`_G!*Df*%ZvbY=Qe!u*6?1x&Guk=g;w{^K`c!t73MYy&ce3Tnxx) z_#32-7aLt*i5@guu7Ct_Tz0*ZfXjsAl?l2b@AsI9Uc@zx&%t|wMJjWFQ{_hI2!^Jl z($`8~kDfsU?Y+AOGRrT~c8rGRRWF3z4z%p%H3pzly%2NKB~Od1GUwlC9^d_NSs-Z^ z*~ zPr8XM12MIjn4{AjCC=3Dmlj&gn|9x6g6*k`YWz5gK+*5mslTb4-?w&f`I70W??b2DZpHF}D=;5fjZy_{i-aq7+4nz{2Ir#+| zG<*RW@H@gr%#2+B-?_zZk50oS-F$YDYAO$W`MF}at3s;Cp`gB^Z>JultQl6HZkAhl znhia=e^$GN%OMAcY*Cz*`-n%1NaBgeDy5ed=5V+A%|lfBbu%P7k2?b!@vjcY1KXsfy35({w+`qGVlkD+ouT9g9=WB9E$J#3WOTixwsf(1^5Ltd9MhFKX zf5P_CCVEgB^6HhuasM*Ifv~zgJ$jg}gfS3tr{^Pggy;jxP^LoA^f10kYC8*82jn@Z zosIA>}DjR=Nm!}s|M7jV$psj{(*u?ovFWIExFV(nO^Vj-iUxfV;kg^Pa z^tHocmWd#AZmqKL(97azElzNYLky=De6OI`XVp$xvt3m!{)$9?Zo+Owo*)6(hW>o%rZZ1`RSiiiyI%80X%3vs32wYM!YQ*+ zJKls5YCP_)n1mKGd}Iihi0kB9InEd+*iQ_9Gz?Plz{n5bmkZh%trp_OtCDyQT{&3v zmhZo>lE-uMmMmO2t&C1Bc}p$d{{ADtW0B$qLs;L}OK|B!E0~-Sd&;;!f-SSL!9Z2(z358 z5X}9zXC7~K6USc(@{rpkS9W<9a9e)TaM>iB*x#b5){ko4Yn>H}7EXJ;&Kc2t7K?UZ zE9qa~Sd$IFKl`z~*+uEDGB`I=aczJ>N;70NqA} za>NKDE}L1f98jwFssqCI@WYmR*r9V(!Y5t_>Am{!A|d_(FF`99eYl7#N3(|y>21vv z&t6S4kD)5}f22!SE%AqtsVBAFO3L;iXN}qrGqJB3tLRmOJj$Fjuw^>$5+)ZWVXtKE ziex3Lo;*@#gGmltT9#z9leDY0>u)W(@7rzdt$;Wd6G6`mwb>}2#XwOx ziZllc&WQM&!T}cXCJfz%M!nz-Mf(x%pw!=GKU`(-J@8=eu?qHQV+}Gt{|&aBEP@gm z$Lc*{ZbZkezR-hA^q$cLx3%r+r8*WQjU;F_r0Z#mz7eSw}ZlH5}h; zN;E#QfUmF9lIYLgtSfDk*z5WtjmYf?FJW+1z;hS6o=d1Dhs=pc-( zV9~Bk0oB?T`y={pvi?YT*>+z6vj`GJOGF$8RTnyS4gLJ+IU4Y{hZR8%61GnTfg9J0 zMO?qh)P)IcR`w}^AshAxcwV}Fqp+q5>f1c;b)40SUgrHU)Smkdn|2!k$cFb$oJ*x*BP-2 z2xDT4FK5Wg;Z%XaayjOPW)fADmRBqGttXE%}!hs=YH6m^~+rXZk7>@f`PZwF z(MJGuW4##2$99KigeEynRVatuEd3ewiSi`OvA~fdH}m7`eblNkmyOY<2EH0`>g`K* ziSTqXMa45jiz_pEtfkBPoQ^NjuU1O#lUw&gi}e<6yxf35qMXKe)(;DLZ%8dJq$12( z&wapj&?xghR2JwdMJ^vVzE688jsy!u1JHESCCw%`9HD4a`for9*{G;}!PF?m+B!aZi|KV6!O2tjC~G)URg$*ke6Mdc8E zdHGAHT}47EAKCMzPO-*AE#%P~8_EqPhfC(NKlcr7lPM9iD$KtvD?>X^Me`aTA0E%U zLf1AH#3@n5#{H2CrQMeACW03CSt%o_E*@Kb@0>|5uBW+7q>y?hATiMy`#l zqN|=Jflpk%#|8sX2^?(dcSsscz;Isev)qEU@8jq1Y)Z+V2s z-{T1zvgZmfpHC6$26>jN=~qd{6<0z76aKOs{I8T}=##lNRz4?u=>3}9@dKtN8HdV? zrRMt9cC}ouF?;{$E5)x8pCzEctTe%^L5`X!c*@!X{s!!4fAI-N&ayBV$#WM^)M~NI z#~)v+9**uO)Pb_(+v^Sfq~ra*)%%Wxb$r(u%r;F)@&kr@% z3}(q$U6pcZsU4;Xt5^6Bx73XkYM*{y=Foa$tkfv(^Zan@&6n5lu<+Qr2CwlN`&_kv z=WPvBH}UTgyZ<3>y}EtW_`xzQVWrNLgFw<~a7@izsS8yB|IP`#EiaG@!z8Y2S|7{g z=Kst1B&%SVv9J62>>F&W{{tTNlU)rZI}-)<3m8(oKnFk%+X)U<`bgYB>zC&+hQCJ@K{TsmU>3OU7R)$Efq2rc01Etf5KYi z{uRaaq-36?3Y*H#*x^gi;d<8yyKIFQmfHNaK?$t2zz}cWUjrvx?sdnya3K|eKr1Ln zn|&~*zUjhi+@^iDTm4ne(%qW}=a0KxhP6wo60y2G3RYHzYc`h*d}EG%*lpDyyweXB zk4&oD$-=g<@^xhByL!&r9O$!p&&!CsXM?(X+sBI_^=$#oHaTk$;bVc*T|5-%#v#G1-)fdR zUo_(gE&OfP?`0bLobDR)dMx~UsHWJ7|45NfKTGw|wI^~q<;7dF1^b3hMg<-N-j-U> zf@?S)jtN)kYt}d^EZlC5OW@-8GxdlVUP|qgzZ zinznA3!&(9@q*X6ei>F{7KEtcq#p}O;grtnUq8#-%#e#TL6q_=Q{B+kyhjfzVPUaU;aHmZ42%0b z59UVZhbB47qa`}o)=G*$A_dXlboOo^VA;*I$&9AW`Cx(fvoVTGiE|rJd446~)jUpO zUYw869S@$`^vrH3XTJ)rGqfaIwKJ#-UFM5o$EX|uh9t>c*C-@@6?dtj)qO&ZxDrVI z<)duN#k%{(vn)9)xuKu&i$fV*Z26f6rtZFuL+W^SuJLG<25E?MyzHy{^?lQ{KbRoa zj;W%++l}jZdjfKH_n6!>(113*IU`WYs#vmk#v)XOpM|Xr>zevdBgE7ER?JeMY)yib zljQtXsFw1gegJwId@Wq0k8f@qsnWfD6wHoD1pm2Vy-~m}Ktg#gs8!)z>ZwXit>xmB zn;m&oe5L%gxBgSKzsnu#kjl4l+l;SFonNUw)hOc1m0^ei=5H1Wc3iHFXronY&rS~w zKEG5{)ED~aV08H`&TBWs5f+3{N9timppLR#n^}=A$5rmhr6mpYWq;CvBBs)F-C(`< zt@lqOEwmB5_C()$k-liCDz{D0jsR&?5IepzqrN?S+?Ugsdb?D=NW~!-ur2DBvx-+G zYyvlYeVmGC+w4yYr1Hmt46*VGh;)fLz<7utFz9TreQRq#X}DG`SI%A^8suG3CU3Iv zeCW1gI`DYxxfjwm6(teo#}KL!AyEU*w_Gg`fAU&xnn~BM-+G_CUy}$2?m1vp=-w{;e&>;n zYY+SMp;ZGGnG*rmfq^X13H*;4b^G7kfizB058n>AHZ{6C#P-gi`tcicV21>;iJe21 z@e!{mLR8{zUtnsOQIlNuaknjg;#k*Wf3MuFcjpXUrUE&3pf4nLAsGtOVHV6)dHulvQ0cNV*-uqYW}} zpe5BQaiL<#3KvlanM(ZUM#FSVRXb=qY;y7lwpf}JoYVyqKUWA(MUh+-oB~B!z55%h zC}zBhJL^y!0{zb9(hS!1?0+?d{h!QAjTELmoAD8GqYtVGynwJ|$Ah0}2R`Uvh$KQg zb3)C_Yf<@}w7q!e4?|X4`VfpY>k4yIOGZM8RZ561dv&(h8_^g(N^Qr!tEZ-WO^Jz! z{Qy$_+R4#sk=n&iJ7s2_R7K}2cR5L;e|dVn(m+)F`A}vDYT5tOzJc_I?j#d=OgG4+ zt!bsARAj(|l+gN5c9!W!kio6+U+@thaj}gRcSBK3nV`tBxczwupC`~B|jNqzIoYKJ?1LHx}rPkYd>!_DqLtm4*NTJ z2qo3|!(-zdQoK*q?TUE2Ww2=VQuI;nvOq_KyPPstPdaooEc>=X9gyx=|*tbtd~G__ zc^cVAC$*0_p24hr3gEa1+u~!mb>KW$h%r7*ql)**ruDr|9yXbqFGvBh6b|7^=CC0h z7+8r75Tp%_{ViY(N?t~rwtRAhs*3(DRD8?N}9{lG;MwxUXhS1!PBUm^O&RXU9>2^8d?6CL-_?UBKAY4GWouTW3XR~X*yA%^WSx&x?c zBVeiWbdHiQc!_we(;^#_GpC3+vnBiFm5hRc4~I?q{Tsg`CK$EI0x$6%>BOAt3t)0K z!SZ;-)9y?GuB;w7=3YF7$Mw8e;2~YIf})&yD-I}q#SJGwmiv$eGnZ7V5;$ZwbPH*; zg~(XU=X66f$cNm>OdeO>$1WKUIzni_1x!K{rv~H2{s^3WlMPnNf%YH`iYWgSjQ46} z$q!_cb&Nv-B~{z?rC* zWGIpJlP!}RaNnA8Ple19(*6;&|lK~Tfhon^Ak|*;%I7R!pq`(9<0J` z9i9?x9?m8*OHVL^%noqWxeF*-`tjbw-xw)Wg)Q@rl0D&ARDc)r&@75!U#xV$>S8hQ z)>w+gY&>98NmGG)MD5cKR zMAZL5o&R&-1SRz2l+__+AjB~vER3&zG4)RW4LF)fdxJ_g07Q$bq>+w^6xl+MSP%g* zZDi|d^4>w)OFD)6yEd;o^0`tXI= z>xdZ0-M<0{to^-BJNXuaFlA{vc=2S zE)Xl-OO?y`XYmoRa}Gk%pJyp$u_%~!$AqJTE=$G!v@2L+r(3onN2SgD64Hi5Bvx_H*- zK+MulnMuHvr+Q(j`LSAG?$M$#wC5V3B-@ zV_TKfMYhiNBf|%u1n)Wl>!3%?Z;eyZ(CbFPWHg_s!EsCo`Z2pkMTZ-XZj#ti+r;R7 zO9Bx81dO`DL9V1;aSN<}TPQO@#_52mG7y=Cop6)Q@gLaXGT>I0TX__+K9H^%wz-R?)k@FSPb+$<=P z4MpG6?g3Be#Q((voki=*L2fJSK~5Y}^hn1T(NF*5@edS&)Cv};kg_dcSd!O7oXFum@Qm}TEze+1$txstF?AQQD>I>^_z z6RuZ|zHoN&HMw5^dJG{vmaRhe-ZIa=X}-}cdS+=X!`WD3%QCDn<7gqUBzO7UCf;Eu zhuhVB(!d1V+?QABrksrVzA5l^lmFlR%kP!^w=Mz4F7a=W`A?1tw&F+5PU!A{^}1Mq zUUabf+a9TjQAFSbkIsGQMaitGI$AQYC^Z>Zb^lc(`q5J30DE$#& z#PgAZy>=X|kh$c92(0-xi21V%Y_N+rqQ}k9BW;!AniEs`A%-zvJ@C@WkeLxA*CAH7 z-<{Yya#f?EN5l96A0s}$5^dI=l@fuJh*2MNEo_1~Ce)8O-X5Npt(LRsQT=KGkPV_<0(gP7dc{I;$?dL^5 za1)-GTf0-7%7-9SyURa;yO;Qn*i9cnn>KYTRa2y&R2ssI$nre|DZ;Vru{^iSRmq&x zL18%=@LvJ&)lp-@GX=_ml%zNUEjq*7qB{6mI*@on6JTZYK4z;95Z@suP@}WnkSg5O z9KbSs$|&zG9NQ+)&fA2)qS*ZKuT*(FPUb*^RI%wmb{tes^NN_95VSs209|{ zC6?=u5aJbw-ITH^0MdhAm^AybX1CZ~TYOaTi9KMvfc9tg9vW@6bj8^!Sd7yhj6CK# z()>cC(1}NZ7DWJ}^%h#?c9Xp5k<6n|J)F8S9Q1msY-7qvect74H+*#7IGfk@ourNq zAHsfWNgizkZsy>@x>Vl>4#56QiDo8nxfiJ+SEAUw;*Q2$ms`{7k@?Jtti)#mB}5m< z(yY`M(c9UNT^|CknhRU-JjKVXLM~eToSuXAD5{YF*Js9Ku(!Ne-y&@{Lw{hb+1j}0 zAtVAw--}E?D)?ZN=K*^>Tq{c<`>0>~px=1=4IXr2t1cd}SBp~NE^V^rSG^o0LzcnZ z>dt?4Y>jRX%$!^!9=%_q&7;QmZF%7!CG`zPseAuVfY)7gD_bhKTnh1b0*!qpY4UXR z1n}@SQ1gNc`nJjw!*?&*$LGqywiTqX&2#bsp=1U#_^y9_vESrO5XM4KzV%BxTTJTP z7loc;Sd1!x;M2zQEz@b+pVM zuNQv6DGBpezVgTXn0=CO^c~BmP{*zG%vk`Lw|0WPG$B?c1-g0%ntheewbe2s+sz!f zU%|gb`;ZxWb05-RhIls|? z9j)9j^?N|zD(c?g3 z3Z~@dKhEOs(~kh50HFIYB<(ohVhru$x^uT1EakC~&Jn=mrJ!HmMc0rMRxI|xXk1a& z{&`8+Omo2Mv?8CLBYJD>0;Q;z1Q_(+ec@xfdk6#C3K!P!;q3SL*?c*5h>DUnr-`{% z_r;^88vYf2^B=f|9^U&m6S-`kqi|_VZAjbOp+FP6UowLSLy?^DV`ZRPMYf3LJ}hi4 z4$+5W~PT{k?wu)^U%9V|T(`ZmBW6YGV68yKT(SiFTAoqvvwo9brnD z5_RjjH#)xbNXDhwPGG!B5Z$lTQGs5`Dh!F#)0Yxz)ZEFOW0N?>jIzIH8tRJHZ>fD=+f^}PCM!DR%Up`@&u^xW z9@BcL-wee#i5VMsQsu(758=L?WoGxTmL_Qoq_x1`M|i?+!dLRK-N#)D=&B zj!|>Mg4?mOmy<>9<#Zy~0$9+2LgLqt5+Ms)tN%WE_$airn|VVb*Q_CElQ;ev|Q8D#&^Bp^WiIzP( zB%^+o9+%VmD7-eg$|_y`ww=mlP3Pb5gch?OE|h9L?mMq~@28?)ti#)&FA=r-rl&ti zXa7DH-5A}69FJyPE$+v5=4aJYppL1a)SM@K!#1+?hk=T=^uTJY?fr=xarG8@(hnOd zTD(6y)rCr{c{j=+)qIIBzcv1lSgzGNI&_xLAusq*SKB9yXSJY;#xDW4&eaR!XHm8@ zXypRaHCd7Q6F;stUk#E9=3v{1B2a9#5z8Z;OA853fB1>|?HUww+n!(*JZ*gbXSj*d zFrIrqCRKX(*+s)yOYd9U1@#WW?%p*ePTy2`Pm=Gr-D3Asw(BfBN!3@+H;?Q~wG`6# z>c|>8C(aseW$9dvJ|`x`d*pQ<0aYBMcvy0HS#c6PXhuuJ#83&{TsR#F%}-G3XaqOAz!H`YW-O=4LdwP;^>_Me})T*z5@Mb5;F z#FN`h$i#yLaZP1E;(YB4g@nRzV2oepD_kcEjB| zc@h{hgT|qeitchY!<*z*tbTKDd9qkGFt%!?)SR95aQ2DgMBEj3g?CRr-k(Zb&ML+G zow6n#ex7{n1BO~=pU*v2Yn`#}wH=n>UR9{<$iRF=eF@2@akR{Ddi9O_ zz=FQs>D>vAhkkp3&Xw$xyA##wD!tQ<+*xjse!gBRU|zpbd8_I)8*y1TE`})?ED&vv z)HT7#juP)&2uA7~zInhtwoS(jlcl6nCFk?><$^QvO~xwArnWy?aYeof1@oO&-SH9Xh; z!(Uvz`2^pF;@52t!)_dYcsp7)_Dx)ep}a{gh>8lDOws6mFe+zf|L(r|U5A#FndK_V z0nL5re;#Mc@VqJ-w;ieVzgm9iGgTls^w~<}b8MPZxW`74_u>LKe9~3$(4BOFmw_ zlj)w%(`=P!62zR(Ds|Z4uTQM37au9k*sh6x^@NZ5)BsTGI({X^K zLtT8&8Skd+R;qM=8^1S!Xg;dK@-cq<2V1r&G!S@SDqNCA60D-7duE^HOz;oN*5sL3 z#%Y|d-<9Wa%MEus%^tTLFZ7Khiu3h`?Yqeh8*n`=D0CRa8`pMoingu%@kJ^A6eR^S z*$Qm6icXdyA|oww?C` zS=Abix8E`13%>*6H46J%Fg{nKo;|d}Zl4f2mOc!nD$G;4?i>~r% zJa;hp)IYd{9P-U=u9jXhKd#VJF0GD=2p=+=k3+t{*mUJlJMHYj?$dcf{fUTB=ZBgn zO>s{Sf(p&8J*`KMv|d8!)R4KfOS0<=_}1EBr&&sBHGfaDu8=Go)}Xy{(CyP5>1UgF z)a!S57!Rs)uZhV}jo?$-*GARhu}$1u`cmL&Twenjkw``o@f>QRW>XOB&6j$n4>zfj z{`MaOh-YCP^zMv+gt{JDOdHUinJ`?;C8dr?OCfFY5aP8xo>VR>!q7_h{)&1FYZ3ZW zud6yIZR!@PR{;r&6@B&m=C{=JmKl{GBrM~BWspOG{RxGs8N|6t;}|h3U48M1DKWn$ zm_HB9Zk*a3qzSJjBej`uGWlCNQykYma~8p;%~T~8+gwC6t|*|GWIiUDFm1A|z`Fb8 z;W>RHst=dIPJ1ZRoJpn#7xge_$XKCtFv!#!1XC=_1*s_vk@;+pMU^dss3h1B&P=|h z*ye3VF@(jy!OsHlm^J!~XZ_=)#S6tUuXP7FhWahLB{I}#W$Ie-wOBKj2^UGoDAJSzykPv1pGTq3CF=LBr0!73-Q=>ts z9V;g2d6ZOV6R#b!zNf0Ihk@WazYG6#b}*Z0{^f)@YN(htMMmL!Q1*kpIJMi;eGp$s z7f`=SJkuQ*nhh4WTO9OUbmUNh7L>6}tdDrJ1|tp!*XO~vDvC^{i=EB@DYe>PKMm@P zXI^_=@n~L<&xnhE2X029rvT(w68BS62OvZ7JCNS=$V7;S7%(*=Q(vYqK>|k3jK$HY zT?ViHBU@|drc$Obh%#nMk=P*bZH$h`BW#nIe={tdjM8wJA;wNAY69Y@4gIZWsyjKD zlE|mK49j@th(w#(RYI>cj+16Pt}^x0*Gh}e9{c1W63}#r+5IBWzZ+Q(LaySzIzLR= zp(34>N%~CDro$u>{g9rl(OKqzeTKv(rmzu+d&dg?!GyPdlnHPNthu2R5uVR%J#!I4 zcna#zC}eMxV{iHhz>Oac;1U5*ln&fhQ}VuR9aobOR}vYfKq}AUryoEt{siXK+7DLcAbkINRi_@ zu!3JqhXO|KRI!(IvJtRK)2@bE?lF$7LEY9o?ISInfvy26^W+bZ=GbwqJEIgqE|_q7 zWBRMgc!a_ZpBRG6z|-Ztlp`QE#$3BTpT|7(BjZDTvnLZm1;MUJv4lf9@L#mVsLVhm zrET5;6*E^LZTjD7@0OjcS8{OPa7JPgJTK-@aU3FVWqLf0`GN^SvhmU%TxFD4BncKr z#R&9X8$lW`^~Bbo_TW&(G#A8dwoUiRNQ4#9g4zvTB{8vkKFuKag0;yU?Wx#lf`C7z zD&8w+aa0&#PTd(DpMD+nvz1QfTc|zCB;KpUvGE3Tp4^B{1~@D0OjM;XgrV ze$JLFrC079P&`Jtmk{0m@!9%hnr~vFJG1DOYRyJ(!Aoi0P1jvDY&d@)3ryndUCo+% zk98Pw^-kIg7$w%O;I#};0q?t_j%y-d8edI3OEQs5FP^CekZm62%wL|b>VdkL`r7Qk zo$;rB_S5VUu>WBGjLLb23m4jjOCSQJ_mfPCqxkI2ldd5&_88Je7&gIBT?q2Ar{OJ@nEd?J) z9eQU^d}`rxib{kXcNy6UVWFc@p!1ZM1_1>mJ4h6QGj2*``Mj%FGOZusf9H@nIz#6* zWF8rMM=nDgH%$X>%-#AhGrGg;eHv;@x;45+AGh?O?&N@$=!ar>A{WIZA1;x4s65fN z2D?iIYL4pQE+8S2 zmw?o10jYNr`CfN(wLiHJd^)j`!t9&SxTTu|b1Y}ZyY!+6jOdx(QF6u%sWepQu^*Yw zNxa6@WPypJF}tZLL)18%Pcfm$Pr}zz5b$U@c+xTZLpn^Yb-M4JRgw;bRq5Wm_MFM) zb}c}l3=u*$6SxBAKmyZ+c#1*%kg`eRq%@^D79rGJxP*zw-2`O$yHjKS<3z)EHjZ{x zo*$hZ`k9@fCk|!@_2b@)i;*{SD5K-(;bw!^ND?ZWJxFdJEE*pw_yOZ6o z%^1)$!-8$UDzZd(81^n8-&c2(%9%vzt^!bh-q8M3LoD3oj+mJtB%o0FZ?c>2NovAQ;L=+6;fLr5 zVbT}oc(iEeskVK%_KOfvCTOMNTiri@b`(LXjZl8{oiHvemiBaj?Z+5Dr;o;de+|z8 z;1jJYU>&o*D9OvFuvZdqJzWD2i*qwe(Y)7~E&9x=D~Jm--*v;}4$riuxEQcPp0!*= z)Su_(yHF;!gAXf`Lh%*S$mr)rPHShW2*yLo=?}#prDfB@v{-$w$1JAi)B}~2i*re2gK%;%(;oL{ zKPv*k{%43tWHT;S#(#!=N9oXTJLl9DUUhC5Frsg`JoTcXn5bN2{4);zGFADSjI zsgW7}@8X9PeA)?o8qq%Ogiw0N3zF&YO-47@?%4T^{H@S{_LOn|1@e|~ia9LA{qU>Y z%6{wPe`Hxrj3kgqZZrH6dx7*IzK|b=JgH>g4LMNunHFt~9?X}Bv41)~(X1Is1t&dH z=rLqCb!Ur1+cPTKfqfg}pP2(OUj_dQ9uT20hhYBqbrJGL5Jpq@TQ*Hy2bvZYmY;CS zC<_rt{*}0PQocSlr89{t7sp`7y(fM%zW;%~dCmVk^W=G^PLxY*fnPL&Sw$BdON1%kSWY2jfcykhh12Ki=m`_bwx7bHnE=lVy5R$xz{JF)%74Z^ zL+cu^koK<$zLAV*?x*JvVTW?_QxK;QBmOHVu`+3g4h@gH80OGot3OpvsB2M1+kCJGp3a z#!8G`B=t&7E^KcYv)@}>G8II5oDVN{a;p+ENwv-c6m6;7eA{7DVy{ysxZPH`qvVXK zf&FyeGcNue1s@lEBftF8obNQmI`4S*M7?{+k>TUhjiwXM@WBL}OMl6Ba8f3@PsUp7 z-&HizQrdg=->3JJlx)8NU0g({fVLSwf14{i-jc@Sxg)FttRONV0goz|FDi`)D~g48 z@4aMxufP(YM~tL}n6$a-qK8d*mdAHC}TaZ0am zqmNE70RkabHyh||o?Fc{Dlf7j4;>}5+nNejuUxD?CtpQ^@@Wr|+<7=w;)sWY0!xkN)AUE5Rg0)Gj|+h2AWQ+Na7Knl}*b# z!Vcl!dM86Qs&oOZDSs=R#s2i!ToT9Q*7y@Bwzh=V+WNoa*8B~i$p-ERh5$-S-*gf$ zM_P1)3;tN;QQ`P(XKB=S<@BXD@WFQ~5j*D|N??g-;8Y=lDZ1ub!{uRF@ z^-EcE=drHS(bnml5%tHkWc`#Mdn;oWA9ic>gE-oj!}u(M@~p*2iS3uNvp@5mTO>SG zyp7Xvc*y2AB-sOun>x^J>#~+rHZM|eR{#~6Ky-0bXDYfOF15C)spr?B1GY{>F%|-=#oZhyrZP!gP6a2M*bV?Uk>ON1i0cPAnTQ^A*tjtQ)}GSBSc1n{j2h0n8A0F^rZj=p?033%m`s`0bQ zwP2iQ#loj>)QIP!UY*ae>UdpV9*NqlD_zP~c^|J4_E*Gd!K@ALUM8lu-=9OGdR7c$ zg8WxB4R#rLXtm+x3Bik283;i|UF$S)=z&cAgT-!>nW#rFEa9|#hMy()-4K%%BxV1% zX^a2j+NyNd5pHGE^BGtJD+x(63Dve$L9b?-VD&${=VERej?wa$Ig69);i1B@xLl>X zaZdX19Aw0Hn`Ss@3I2HEg@DOd@z+L*Rv5dy6CFxvDIg&ywWNAmK&>R?A6!RcRZwMy z3mIsis(fP7>M}YIs)qX<4d}jKZL9 zPDpMN`L{-gk!{Q8xy3zgCUzfilgIs*x^0x|{nYe8a1%3GtU;B?EN6uzOupAws%eFp zw>r%kqXc4q)cQ`e=BV_}sb&e74B;LLKC1tIbG``b9kXQGm`oBINCFQ^3!4DO(~8vQ%WrM(}&6_rDt&?xsf?6gSOS%`uand#LlXeqMwa0 zcM8JfRfFjJYbxa>|1)$Z{!IUI9JkqQuK8}p+_u?Vp*hNt*yX;D~Nh%~E)f~B^A5y7QNV!T#lCYou;QM)eKabDj^Lf8t@8{D{A`~5j@;+vIU#+KB zNZFM#;-R%#HE&(G3z5!9#>%)|Fq8jsHqf}+zIoC{;q9Gs``1Q^(k&1Imh$o%+>bSs zC~i?LjgfeC1946}KQNpk8F}WP{&bl5D@3nLCKvZHY!Dp3v6yA~h+b_;u{C-VT)Zo4 zP2H6YJ_Z}GR86D6UVfPVaPMs|whBAEzt*8uNP(U!;ouN1AP1jWl-hrlN~ea!_s&dQ z^)k+|ZdtT3dn`ajbe3v8@7d|pzXwRLKhV>$Kz9-f+py=9o^hW!B#EO zb=>(s%FJj=cXzfNhDFH&634M~WG(f{{zCKnSIl!nIu{T4X4?eH8SFVEj@l~NNJUR% z?uEzx>gvl+wFza!9k$Qum`6DtfxN=H7uX;0{&Qi2Cd%7RpV&3!C53OQ|BkVa6N{5c zZc0~+KiVDinVuurml1nMBr)(IWM@;ST`#1nuBfQt(g=|6>Yje5*263pYSi|;L3`lw z8hw_C`hEy7nt{N3oqk9|;s+oj@BHN9y|~svYxHO95^4ZI!%A`F6go4P-dJm&r=)=_ zUEH4eI$Fg#=Im`FFS1-KL5O_#b}db!R!DZ(5S2_yTWgkkO+aW2zO6AI*t^oP_j|hK zcba^22YIC9#O;n(qwN-hqE=(+jCY8Xha7{^{Q*7g0|{Uq`c;ZaW*uK1N5axi_G6yd zyj09Cpktj((l4l_TNrk#Zg!Z~r0-em2vnr26n_$9zA_o7HsM5@H{b3`a%b0ZRP^4x z`u*t)_CI_TR@0CUTjg9ggrH0gI?Vukk(_6N5*4a^ffNKue@|YcS-MY>13|J0=P7k* zlKC8(nRm1lM=U0*2%yUOxKyAozj;Et2kE#S5p31^ncUxDmM=O2kv%zU$J9&TJJT`H z0MVX$Usy0kPWE<#@H!vjoCLzR_eLis>*x(lkco*)Og&M{<<1Kc45EBlY04y7YPgh@ zuQcy-c^Nq&2p|pJwm}<+>Yxl|6#bd4HdsZtmN-fKkn zrPBzRE{ zQyo@P9Lvswls<^ZApiAuu>NnYYTZ$dtl<%gNPN<++se+ro#j{l zwSh%@(a$kyB6^OoDY+f^)gUL4kOK!^nSB4+{QGO_$q%%g5o^nj)}d`zdnvE}QbJZc zTYBV=278vP9F)ArG^%~>T7!R*5&CurK&_CGxj_!p^B*iZZT+LJfdmu+BHJR;agO7> zMT;_UC@#+TY=s^-=_9A%+$b=oRvF(7QA@E4UpkA`l95CDHd;yNzNEF^Da+ljMAup= znXB1mT?-**B~ViVRk4A*T~VSXj97~h&M9%0nrLHnok5MA4`*)f8TuL$b(iuE&vqORk*($KKO}Zd6cm^MABfCMt3ar0Dkw*i}zM;*B`n zoc7}@Zdzn5BIE71ySh${!%i{jm;2r7=^*KT@@k3#E$Wuj82h9W{ombb>tvl0ru$*V zoQ#LE4<%lk3p&K>Ir912ww!5eE{l19;1*>|yp5$n+BFp*Mh)yhPUSl(P9=BrskD%j zJv&Jg*$)JQkPNPieY;!~%XJD7WqS$k9=T9Uj}4o%P8cKmiYm5ntP>(xZJq>2JdOU< zdZvx}z5i%qwU6W2-(Ao96*-pjBGU8kw{k|Sy2BLZ^xlr^2*hv+oj=-?lM_4Ess&UHmOg-5)U z|7f?BuG)IbiR7~9>p`a)W#tkI?bBri?j6^S0|ae0pWZH|{{z1`My{PFSKhilM{m6- zmbJojyvU75wte_L={)FZZH|lDqKR_^FyCY1xt$e?^ezP|e$ZfS2{M9GNO~=E`!2@G zzUxj<-ZX;#yiiYb@Jok7R`P4z>IJ&8eX&Gzra3$vuSbz>$afk1J|j;sEV@Stq#3!- zTT2zsy$7evL6j>4u80-wqf@UU=(a8Mcr*Q!rg`V2u-9|tE3ti6M2KvRK7Sp8$ft{| zL@nf##cRppO#&EC05j`s^EvmrC&RiyzuhrQqhG&qRP?ruaKO6t=X2LA%6Pg}s7JJ; z==?e)IUCW{*eSV-sxyWDiemihimI2d1>Jf_UeN)6;K=t=g6koDczv;uMcgQ>89|rY zx@R}nnXUx+)llbDX?vq=O745UzQ_`{r^E)Xw>sr2&J*AdAA5sjCHnRc+^gU~R_gTF>ZqBZOd?l`er%}AmMb^^NSRY{f*7^r}cBL+lOU$n9@Po-UOqPn=`sRoThP<6Zx2%yI?<^McsG@KG~5{S_>8E_ zFZ!XEoy&%wpR{?scUE8CIy(k>+pyS)92QE`qINo!2qdex?F%qdCGO2~Kdr3TL|>%! zTD;R@xa!3kib;c;3G4OHMcXY3VFQG1prAr2$fN*~&+H3Q5dY8Z#wQa3u3v7%b(kga zu6=v6`{T5DDFyPVQ-uWK`z}7-q!9xdWsDd;eAPNU6!x=-)xt=aw|gr`;p8kj*GL1P zOXkX*#y>le%d(yQ9PtuCg@<%}aJw5>Mf>b zZbGSLquQlPC+>qWer-Um=kF$=pgpOPQc?_KfQzD}J!&M8kDvh!q9Y3J-M`URtp^F^ zqDZIT&ZM<`OGo1OpOQhg`m`jSmzPE7t`Yt*FjkBH$ z_>m>+T(fWWKhCr=f3^Lglmy)vxg)5ur9zIoMS+m$hm;Z#+dz&}TH>l_CP9IkR$&}i zJF{*>z%^V{t5h!e@Y1A_6YZ#@H4oVlbs`|p@UaQ|+8&AJ22e&8>(Nr&_7Q0Oj&1R- zX3to`wY1y^E#@iqgL6UOob^f+E1NFchMs-2cHoW^CwNae_c&ic0$Yg(uJkqU)y1lIiKe5Y_F`^tDtDE;ry%(nWdV@(NC6jpHL0jC@7I)Tl; zn-UeE0>%!?FTOu@?{Jb^%;V>~@6}$*V5^8 z-L!qzTOAtQLZh!k@QbeY_=F67#u{DvG#s9#*BL?YG$@55_2_SxAv>RTwd?J2XcBWM z+3xAkZ_&6{!rMY-+HT7#{A>{Ak5UPhn4_g|cgpthK# zw8=qOaZ9E!6X7l=cknIsyJxl$_IlM6dunxvyY=@_v<>@9lKC**#P;9A56T?dKKWmC zYK9>XtjJN9;0|HZFTN z7anrDwDTY{w?t?1VfHKha&~y8w7Pl1R2A#?;-EG8+;?w(FP%Y3snGedXGzqI9RXH= z)>*zUgwa*$Pv2viUwGTK*%;nt_Y}4uy{+02y&W2BM+#%i3h5CzP48G@Ud11`Aqq_> z0rJ_1{n%V4?AiPkwtW7Uy9~y(F5bPG>a8l=xBh2;gQJ_!^|9WG#h}&`Km4ENea!pF zywDsqz2)o4)a7sYNpn@d8wX8I)(e>jpx-3H7)2Z zLt8pu&p(r&<7bl)5;}xS)xF<%236q%-oLP zvlSlxL1tib1uOAiv35)PYGCo54C)e{W-WXdK6X0(@gcm2JJRN6aZI6hx1*u(xktA- zLSm7(dqZR!NlHH{f%(oe@@T~iWZkmv^{nga;p2$lw+-G^%UF`X=U|2mXA_pe_-gF% z!9D5h4n{_}?V3!~(mtK*r_jvj8g5a|-9#Vzw(q>kpvZ4xQWna(O{s;x;PND4L>1a? zaC2HYzH(Nx>{@T)Y)OD`-Sd9$q>ir|%xi74m(NF9Y9oy2x>l}lLvOHRvLAhnzo=dH zwukw4dva@@VNie7R}st%_2NdZz1796oXThRg$)DmGq&7YqI$n=*_Gvc-nmTdFFatA zaIw}yuRbG30em>a^;cz4>Brb<^`llQL2Kvh1GN=CBRro}x5~bZumjf!8_(TzHgd?A zJQ}pw-I~t$u~zdFQ;K?`>yMw5P>D$j?n9w2UsPq1Zb4ysftbCy4g zE240P3Hm0;HmJchR>5I-MZ!z%vR(B+mWnFmSkeV}`qmI>!}okt###IBm|}VX6r}n6 z@^BH|o!zWQI0GyAY<*7w>5TqHX{nR{Z;K_4)}2z)b39<3Ys)J}yC=XQ{bqwpGP!hW zz^N)8?1EO=9>Z>p0`7i-cenCqbB)CIisuT%@}0&v?_@|`7EX+X5u~<1!cVXLV0#P% zX`Wmyoho4LD``h_=`OfUd#{wMq1QT8Lr;%ifS-E0D6{+fq(&k4tNh3pBSy0xenIk$ zH7XeH_-@_)2#e3~*OD+pM%r^!r%TFkh*y~sr>5lB zC%v8^hTA&6&zcZC;K#7P&&Q9atF2)_;N-xP^m~b~8{68DqzBRaR4_yr8JZBcc@6>8+v1!sMDS>s8bs<(}9GqtijwygyD@DWhYz2S2o za+}(?QlLvlR2ppVqt~yo4@!99l#M(ZV|0;CW|`PmCfU1G3ta>p4Tbw=xw!Q|GPg?i zoi-K7J}%mg`c!q#-J)csGWgPb(ln(M`Hqy`NjPW&)g86P1$R<4>qr&y=(ww) z3oeKw11_k^xheu0C$1iG!yzW^PB#)HmF$%*F?b8Rx=DlR?d9%t0rczwrJeu9zf?W` z@BHziWuimK7pj6n!J(O3yO#-eBwwU3XRGZGmam^nh1XEsHo%Dl3pjdg8}2?KD<5#~ zC$-(8$ZVXF_44?=3fJQ6-(4#2qdf4kjOM}}o1!;#Z=ZE^q23>>r6NtAkQi@~GD)F7 zh?o9mg#`_NPVF>&Br&V5iI2_k+$cxi2N-Xtl#%_FN2_aUW9XF=xq29*;I)LsjQH3? z0!zQ@Ig6VP{o@_!;}qOL85cOJag7U^^v1m$;6BWH>sQw8BhkA+={b=vu${uytr*kC zP8`tNn!BVfZi9JNbnxo?W4MdNm0=XTB(btXX_!>4s+c4ZFvfi5^#rP)^h?5xw~l36 zah)yCNt<(rIR33m)(U~wJ%uF?aM!|h8475asdm4u5W5;DFLwBYnF-!=;${5j<3Q_s zK|_N@&$a(Fo@TU$#H|L}N52}MmJb<Fy-}V|#__Xj&ANIf=fU*t_TD z1TL1fns}?~w&G(YWPtBqOpSsqA^Kn8&iQZX_1qe}&LqZ7gY%xkrXv5#ksy9mHuJ8T zXUgKn`KO+bWABgMqs|yMXM2O5M|m7{I&d@pH-6MQZUe)RKRKUK#Hoxl$=;++wD5CX za5L^B7b31r>78!5`A9pC9zJxvLAv6qkT+p1hz0Z)ziN~vol1$(uw;ya6})Z`Y3*OL zZ>>`%Q9e@Y3pXEq>kkr|4hP z=d$_HWv})Te;SU{e1m_ck{0DkFZJvhMCPRqve9`lopCbdUsFvgdJgU9&R1A{y?s*+ zA9yV}1p?1aQ>VA*45s5HCSVS09$h5XzZ=m%QTts2rika^_e6vo-88<$n!7oDLja>0 zd!%Ha5q~Uf`<*)0Kdi5_H3dpKAEoyT``0}^O4xRL@;-a`T52yjYUg@-=wJ1Rn!hLs zxFcs+^3lN~k&y{upn^2M(#r)bFhx?M$|Q>6w?Ygj$Ja{dN72-G(NQg1e20~LKKEV_ zO2WsO;^ABTY2ixP^8C;{$(QF3+3u#mRGmRda807KotY{3ta% z=wyEtzFh`UK}zmhTmIG&R}oe{ukpSAUOj%Q;Z~=;JLLf05X~0%2VleVIm|8sDmeB1 z5A`qucJxiF8I87tJ7nF+FV0}f%5B^TfUgJe!?-*vW}dHsIM5SKBvH&SejyP+zv4Qy3T5!Cg9O_cynlYS$k3oO8?nHsO(H(&lGIe80IHK% z;kO;u@cs|Bj*s3<%+HaftaR`y2zg(=tQ=m1$QB=p#nbOA-*m^-@|7wnN~=fyAgF2O z_eA6-)%wmy*-uD43&niDh0`7&;qeXLY!w$a;+F=>CDefwiD&YBlD=Xix4}^3)tTGV z+0*J09)=CX5)!3dMaFvc`|4aZvC~6E7%X4oY>KA|<;!ngia}JA zng@zosP!u(>LpIiby*|oyu5GQ1iD=F4qj!-6W27M9@)2=IiawO!uud+g$O3emZNuE z<0!#}ILb(s2*x!Rg1dPh{SF8Fd+eB2N9mGdg}I$}HDK(hB$C10_Kg3IH}A8o^g z_hM|15$#{3h7HlTv%<+nG%f1goDjqcS;-J5y%~qKZXXcp-2>dw*5Gb>V1~?QZF2cf zb%DsCra1gP&fXF%oL;T#d@OZ}@eL6Yxm-cGAd6cK!DWIBj!nq9{=gE7%rw9%94Y*q zr|Nv6a%I~pqI_g4_~W>V56c4(St*e0>ZBEpt@57%sC&q4 zY+NH5X}BhknK3a~MHbsj;iCk4UB4_v&S#tbvb3I*E{V0P(>`M*JH*Zyl1jINw>3wv z*muyo9H{}ND-Mrh&<_x*?sD_P{M|UJkZI?%cfd&)tdQVFRZqb6i<2;T8I!M^IFM-^ z1*7tSZqk6W0Ld!YqoxErt9C8FHjMKMTqkyx>Ng#ozo$5O`0 zYypILvUkG+0we zQEEuQr-2MoJTdvvgn-`+b3XO7m~Yl=dYqBJTpT`TS^cGfe^xmmElzuFkRD0IE8e=V zUuXoYWtL+)BTfCBwKgTQJf zR9lP_@#E?$yl7bu(~{5tVN_ad*DHJoFTfmyPZkgt1RiqfRx4dd3H$J@MvqFIg70hj zGZd8vv(~pSs)XG-*e#|SI4+H5AH3zW((Xg-GjMcaDse$_VNf}SlhmpgzEj2-yvU4C zzqlAt(taN(*+(=n$=EF*qRDvDxIs_-u_I7G2NhWSM?Ex=xIV6aF&5Xq?@SE#m^Hp( zQh=0Vp%EGm6KyJUZK~s}O*M?Q_x+p8<8qFC(|zR$u$9VJzV;+Ju&9|pkL1gbsXk`o zN@0=%gtkzjvssKBJ}f)!r!UjaWcVb8387zL;MyVfBKXEjv4#{$D)H0HxAgiL#TAD4 zxr;%Sztzjz9A(%CMK7wXj$_5ZMjO9(3qi^aI5qx+EU_JY2x2~&N;~jmztNeb06a@JY!@|mP0pT$et$!=V#2Wl zq+)WS$9G?3U36lTvr_#iVLkoz_G$fPUQ^T^!+Dq(AZ@xaL@07cta?kTtw}AC_h?P_ z3g<@6z6p*#z~DFNni3}@!1{yuQI8&Gz@uGzZFwg@l*e3Wz#|)oR)?QQVpIGDJ6!O- z<7ZEs{!}kqQ5P9KadB2{P+NVfE!p}VF}iJOr8E4H+jTQHd=t(n@Ncmeo*~0lPCJZi z6h9)vR3IcAd559;v!!ydrwCx25a}oc9gmp!o(MAa^f%;2d|PQ6@NSp)EhIVwy9wK* z51i6QQzC2+nf2Q0YQ*W{m{$!I@XS@Qv2uw~L7+Dnso4(sbn=itSntriYv%rWlfAcC z7hs~L*Vi67TzueOj>wlA z<6ZfE@wDw=1?u=!jdG}*AFfm+R*Q)kWt`Gz2X4%$k80(h3r;jYx)8)p9tc)Vthuuv z9Aqhp?^5bHfXfbe&A$}$dvd1Q#B@H|OSzV%RQ=fL!zuhqaS^UPQos;DL)P1x5F7eVW%_$LJEH0yG8VYyAyK4x@30X1g2 zwfnqw7B2g4V)o_Js3=g?hT0ae3DZou-@IJ#J}##g=<@mYB3YRyH(?``0)VzO~zd!_59JS z9=Y;EFPLJ{Hu#uC;z+(cgI~KdYUjA5H25UG{2^{Etv`#3s&~XGwO#l5Dc-=lxwW*}q<>n{kj9#{Mkh!nE+3ze@B$J-G z)9O7NXgp3viZ8o7j~RRPOuj|FZ~P`Q#4b=7Zv|6YmHb33myq})HkTr{C3eAu_bM2V z8Tq%`^auG+M7o6`k?Dd9+fQ5|OOEjb8cYiz@7aI1ZyAnb`}i>ra2H1=PG;HlE_FOc zu(SOcd*#YIJVgGJW1pG+-935#{ywk)yX|Vz`}buP=pL0+*I=AIMbby*LDp4UIW~gv zn8?H3ztQktBty)bA!a)c^%qIs`{}(#`AG4*x+M|4=QE!%RLM!6ZNiNDB9`24g|~>u zF-`GT`I7lgl?#;~OfE~15 zZT*c&w3)b&Zm3jh*<9IkKHb!{#ZqXF%54kV3H7<{XIxN`n!7b?z6P6qc4T_X<$)$? z8x`Yx#lmK0_F$#EaO!IE^Io2Q6!>5h`b&SQ>G@reVgZ^zMvYjF$;~RklLsXcLR<7y z8f(Feb!T;b^YrlCGb67po9vL`HwFQkAJJE3vw|sY(7$UD3Od8qZZ{xSdy*t`1O-rs zZg-EEo>v6lE&U;W#UUwWGdo`6CitP#H7rkx2-6QEn#qCJmN$)8UNx=E zx@M@1sC0fkbX@peADSL{`F+T)0C&65KdqHXB|-x~x6vMprucwrv2VMb5jBqC5IKIC?IHQhIRD=7p@# zZJubS#R5Fz{0Sl2#!K(qhVjez429)Sr>rE7ORJXZA9tiMOH4ww;|4w0WR)4sE*4yW zh=ZS0Y>*^L56SI!k>7xSODIzDwpHAz-{>0>-DC(;J3Y=SQHkv|%m~p0E&qq3onkxc z{D&q2h@Hp7-H~<%a<<63v$gb06}1LFxpDKtmHpCtDIBjeSC{_7P>M#;ggo-H4DPui zy5G}$H|H#6&n$&Y&K&>ZR?>Ltc)EUL!+tN>+j4K*B{llTD`CQMn{acQIKhE(x8THA zQtku?RMI@U{v{iF`LECov!pm8PJx1qe;7c1;PR<|f3Os&bL+@?N)Gp*+jZE{gy*(e zLpRgOOl$$i%L(2v90j(?xgc@T6LytM93T8@P2`bcFG&AL$i59e-j22e_j(#Pw_LMsRcaCe>?(JNcIDUT?UL^JcNHO ze__zjP;&q+B++|Hgf->9lnABJTV=w<0(Dw^3lbu!m0>hxT_!%&e~H&p*#YcbJ4;sp zznkz>_Wt)fgZ!rVH_59U-+3oNR_8{R#;K`bd#&vI8-Ehoi@-ceX3X$4#W1++5_EH) z>~@M~B}zDK{?^&+7$u=0_;%9%di;A&$A7z=zFI||cE|kvO8_)ej&HiX{kHX>yHt#S zWO!V9V28U-vBJt%G$d%E-xKujbzx=|vYPK8@ixDVd}u%)eao%LmwnPK8#{PfQHD9Z z>yA}MK^}Ob?!udvf8l5K=$(XFoln+`Hi>E;4cn0~W-8^Gbs_hV-nlhV#VwEYg}u+g z<+5C8UUp#082)(^)MN zD|$Eg+>xyz4uL>9CgcTD4kQA0hKFbum-{5^X%KauoA!QfB*Kv_dNoM^aGK~8@6PfY z!jTGf7k+0iy-CeSZ^qtc-LAl=ts^xs6IE$8Zr!yk6QRJ7J9eb!@K!-i)wp;%G+V(n z`o!aB-zWW>OP&+-Pv!@0(41nfBD#&2|HZ?+WXNIibr-=)=?Rd#p`lN+<8PDU8 zzu2tP_*Q{jlOkQ|BN>hitF67rV;1a;t#q=`27vYFn9_|b%@e`B`@B)O=(d{)fjt9k z;HP@H0?%QQA!nZdW80S6cTLGC!(HK*`qg!qvNJOs_HJOmYfKIr$-LsQDJnd3&XT*+ zZ}!siga9h!N=mp=!F~mE>UlH0)>aXjKDbc5Z!uZslM{$jty4-RYum!ce7NNdUp8!U z`Xn!23fnm?C;c~+R{C2;pWay{|4Pwd`4OfSUg0y2yM*$j-6N#E}IO^To)o0|FV z4Se8!+|8gHvM_z_j=i^LLTIPz3^~4zP?g2k)(D;4!wrrKw}qtap;6s@V$67$rpLVh zz$u?+)J(^wc)PiVJ>;!8*sFXZz}tL?7O3o-WE0uqfD(xJS2Bd^IH~;_&B~5~ z^k*S_E`{JAFkK!g!|s<1-kDEI(1!Q~fwNLADL0r9it{hWz6&JVtfz(IuI>(jhn}9; z`+zs6>*_%k7E2hq=<8Gi%fcg_DTr7(TP(n}#ePnQO=pp)Wk z5qJ$$v79`a0dQuq+2DxUgVc3KI+p<Al}kDsL9%{=>mc4x-s0!qjF&M0K~6 zvqx5lM;FtT670nc8EwaW!>LC)0Woi@ZY@h@z3}{aOOAg&yIOj-&WVGR%C)5RIN**` zqRF3@XKvu^_VmCsn$b-yZ-?iCbDNvMtiP)du}oR#R_5`qUiIy=jWf=x^@sBd%xrCi z0&=yaXD6FLkxt}7v2LhzXG$Lpd2!)^hO*9ZE$f*Ras;-qfs*~VADb%@@A3v$WLKLTcntB zR*Sc+OY#$3+9&#sUcN+xHDeVw$YK_Oi|YGkFi0z19qE)0SdAE#M4#UnLC^VP@B zN%@k@6&7qc>Z9ZjA1*dayh#QMl_1kXzSP++jI7=KV5%nG zu(w&+PMlnY>#)3sV5)eEl&xo>wmcBV10B+90-i+l-}8@WZI^FYauJco9>~mo`%rT1 zpS|_eVM{HvHyL6ue$oXjOqlfncK?AU3|x$&d}@hB7>ZKCS}c0&BNvIgI+9O&xCIuZxc-hAL2_o9 zD%-XXA=Yg7epHGmo3!-oBok8>vk&GC+jVU?^;I1+h^JBmt9B% z9%(6@;$@0S{DO@?HC&_7M=n!HwQxpy6S z$DU@{Ooq$e2$!KlsJBJ?#P~{`lcJle=$RS01+N1_GCMNEQNdmOJAH2{Oe_C7JKsa8r_p{%XXJivu)qFU#=2x{Xl z#ImTdr)wwGv{?K0-ri;P*A~hT5lkY#nTeX#B6DWY3Vxx|Lt<)wWYPx3mbV>legNG^ zKk9e37%s)pK1IvJZOhmEKk?&^G>m!%NImTsc;b*^q6f4N1!YM--~x|t1f*mGdCSsg zYvE_IbLQaIc%VcRbRCMkj>m$tv#6ju3yhKQq5DR(u3mQel!LEG z%_1HAuucW#PfqCh`PEd90!)A;xr~BytsL%p`V z{19p%!##r!JY9n2h`{y2QI{Fek2b2o0410wcFGH~_7;sF2dVAxR9gh)>HvRc>voKT zwDapVS7p=|Z;+nfal!Glmr;rst-AJ`FLGc~{<=Dqmo4vH;P6hrY>53?aJPCIrC*1% z8rWaJp7> zA1{xz@rihT@4WH>7c%h@SJuo7Bu@evAVD%f%6g>RU__1>pIB;g@z|Xd*)i@09csl0_W_&~I8ikNg&AEKe;;)yQ40&wsZu-O=L8LE(5xi1DpGcP<|clY0{x zxMxYtUe4NZw~z}hFA@v3F(&C14udt*Ug-6K76@#y*s_@I5kYTW$u#bt! zUy<>SLU~#mTy1fPIt@H^mnwxw9X1c~#EM$RfJyFv@}S6vWtkJCBr8-`kckJZO$^fw zONcq169Z@M2cq>Qcx`T*WZAUal`Cl2mf7HArRe)|KKqz6I) z)G-FC9JRxT(vH8{yFcAsC$nAWTlDdkK9Y0c@ji9Cuc&Q&_vUWB#3672Ue7(?Jlv4| za|-1$&ZJ>)-(`WqZuqFC`KXwHkb|A;-1O2p)NY9rf_$Pg=tLJIV%z=)Mz(?LKw=)k zBy{m>ePdL{#PhHX;D`2qS18$5g-r>`$wCnUbz;Xp67(hqtTA7w;WS8)dmuI;IOy1z z69q`807i>FViRqncv#CFe5mN-jJ>z^8TJu16n{=AzYJ~P#p>{(>lo*kYcSMG_a2BJ zdhtXmoZO0u9fCaHkm>5j4t$Fg#=K7c2-trFY<+>~wvkou9J2|@e)7O*gQ!qM)Y2V5 z90m5rzydxRxi3O9V#R)_y!rPA(D&`0G*@Nii?6qeL1W>s5&@NYWaY%`lc!OA_VwE= zr^9Du+x3AG=Uu6zK$Mbil89E!WQxyH4RZZKhTM+h7K-q?cC+{nm8R3CdO}R;QR6H6 zn3fvMxj7B%#Rh0BD0JIR9RqT!Ie*Q5WQikdtB~XJ#KC1k{>h-^@Wufx@=G`fcG!Ka zv9Lv9H}pjrP<0Bh81cKdsD75$^*dSZraN%ooGDS?$tuM+Bk|`|f-dMLfJZ(7Gd1t!R#5Fh?|_VVX|L;vCbZkrS?Z z7W}n(N6`-kOEG?NZu^sg=0VA)q^I3b(Q!TC+ehGDf>_r%S?Ai9yKr4kMfD_NJ)XpN z8T8&x;328DB zkmT~oIuwxn_*O9=Btr&q17F7^sPEk`D{j*sANlo0Tz`xTv2V=w-0-c}Vg~4Mhh@XSNk{{q`035Uc zDaHU>c`o07p!j3J-bq_xAaLsd@JJ7H9Qn%h%WyvYy>o2L2G^(BXQC#hIMvPg%>m zGo`O{SEIv{c%*bF+gaRm?JbL*!*a~q@G@HDqOj&I+bs)v7gEXc^}R#?c1lq9N`9R& z9AZM+kShK$B)(~IcB%@gNU#VJg>egk<_`34{f5jid63U7-cPE{E|V8 z*tOuiLFw{TnLhxeck_$2u2~}lL=`R{{Cg$-+u#K4)}Y`|!o~>2{@3U7f0wt8zF)cj z`q{BlFM6{-C7)uSD~Feh;&15bLe6tEd&uc9ZgUZ!`$c`WQ5jzFqn5^%WcP)%52FvN^xP=Ht{>xx?Akmmy*-8( zL19PF^p>9#E1xc7bt;Cx6mm)`C}}LCwA|{9BvQd0$0fb9d#cjGuSUlD)5Ie!A91uw}EHvcc0Dq+kI)b zq^|v=Uv)W&i1W-r?48)C&Vo9oiF<(?oi|bzS&3z`B{WN_u3$BJYts_iEs}F5&W^;)-jMtEcluiL znBf7wn>8_9nk?4-SKTO6otv9?r({x{)SwQ3O+{zV?BgV|O0o1&(q0cUA9b#HAWi|! z;fQU`?GJurBoA-+cZ(v{uq3mizn;6`jjl-brXNkYeK8C>ssGTBqvG%RV$woZu@_mX zBXlQw8Nr)ns%=b<=^p%Q0=3A@jmGX-gK2ycLCzBTgR?z*R8WmsuP6{$!;an?uHcLd zK&XdFC|CF!%~tmSI!{V9XIXDeoIg#5gc&Or-`)z&vZ!KNNl@VmjnkqTt#&A(nV2H1 z5W()r!FG?@Xp<=UuRJ7hK{Mcl@e3EF^T*Y-W+b?S#(FDLX{j3(EMXE>lv67((*yZJ z%AmN=lP@4wvWFkxQB7^C5wS>|i0BsI?l^JEuoCCOk$993OIijo&hD$3RIeN*YHv}vP6B;%1-}vNuEAR>D?0cCNx^jI6IEF*w^Ae@yd*b1DBIId z$&(VtQ#d5x)2?at_*%Fk+!MAwnuYZVRiv-iwQ3_eRmCHwQxe(0F3yDd8LX)Cb^sq% ze%ui5Z(nqJD=phzs!|0KoJB2Nk_nhuR?n!#Q7k6+RI{d}4rzBN4yK{8;XGfsV#)rv z!Dp%3o&{VL1jUzBklH!~Akq0C=~ahtBK=t5_FfaK*XJli=;w$NFQ!%B@Qeg@F_%MO zIJ^^rDu=62*f0M3p(N^*E3Q=$u0!YpzGK1CA=)>o>y^$Pzxl!D&T#WT<5i>jl~+vt zKBC89NDW6BoI{{}Rm`MO<6cMZlC1EUwjrSYyIO0@T**?&48Mk-W%!B{u~R&Xj{ z&l2^%{Ser?ZBjtW2SvzIx$aHpZbr6=sRf8`m&!|W zqXQtwxrr6^%%NB}7@I{1BKOD%1dVH%`L9d9RXw$_hjRXT9WTBU=#~lJ%rjAxW-M31 z-(l$uEy|pJFb);;TtQT@iv>MNdvBe-ik}{Q&K`T(51qw?2Or z6^e+m@AbffxicRRV|`TM{ZkQn95W=YC#``R76#kl3z3qv`aYPuJ;m+gOg=`Z2ksq) z8q}V^ol~(VPzweba8WJW7!V%W%f7hvrNv}ZGXMgr%}Z_z&IWZ87wH}>?ykiTjG>b8S~DObN% zZ8Ip+qMg(xxqjpq)m3Dg(;6(5S%|m>?Yw%?2whQ;aXI0M>LdthtlwJrzFH(e;}W5jGcsk&_1 zEPMT^bKOI-TJs;J+8RNFA)hnFjcMK!r;NN4OE5rq4nqH}*_`upSf z?smg_u5+LJT$}r~>_#JLu2HJFri-E|y4hx%xi%4!%SgGD8b#7=}V;Q_38${8!)Zl zmMc-mBC+&mSNjH5F|u&S4)7mH4#ej*06+WFY}D1_5K50qi#Jeb_-|B=#?ylN6=#X7&FQrrMRsGhi)j3RRAI(n zh2IfK&emJ)LM1*Ud)26A+X1DFDd`+Bn^{s44(W+VgtvuPsz}#vX=|lIB%Gy_`(I%smeaz+S!R;4B9($}x zKYXpb^={SWZOJWzZ?ARXkzu}RFz~VBvm(gQ3p865Sd??2-N6OZBBeHM|uLbc>&s_h{(up<8#q9dsvsYC4qZk{*ntGw}4)boR8WryK6djEnjr#I?iW zdkdYv8j(!E6GVm+fpqexw%2EF{o=Tab&xh8$Z94|iziIy3dz!I93sS;0kM{Plfoex z+DOuv%-j_!n)T$8x_1+hj$EOgeIHM5S6m&V)@W$tyOhZzcP4}&Bg+t6GCv`Y&q@;T z#0GS2qy_-d#L?c;kPY8_=HHzeGTCf`zrNIq;gbTO00Yl<~{ey7?kla8aisO&9_Q zh`Pw=4n*uy)-Hlz!g^r(pdfrA+dc$GoN>AsD}3Tx+?r#?8v-eJfRw}Y_KdO@Z=#+F z*KB=sPd$gW2GjlUW87fGU;1|M}p2CH4@U_X*~(?4ftC*npau&iXRW^J1ey2G5rN& zZB)QdAnxOk{bKQ1(?#7sLWI|)>$LQQ^G7jF6d~Ut(?b}*Wma<*Ky$b3KdJ(4)7j=_ zkn!2F45m$BEn(Z4oYo=`f^}JQTki4cK*5kfMH)07qK7-4=_n$%&Z)mu&7pHgFjM>p;O3s@e7yT@Jf%Da0MxD{kuW&(SnLy1dS_4hP6rkOYfl&4AY8y z!hSv|P7hgYx@G4-g*|*BLb%FQf2O$@hDzEjWO?lStFXP1ow57JfxSpu4#>hDfJ`O!uWsFUB=SLMB2_*s;)EV2X5PuM@f1ta5P8t-Cn{f{++d z!QzI{gd6wbx#D7Tj|$X~mo27-FVckzD=JNqM9?|n0_S=e7oPWk2fD0~2C~Q}tmBbm z5<#f&u>Bji2okpNC1DNTpxs+>sIjn1m1vZl<-RzCZ#W*V5g#K}m2a1$VQcp+$euHnRUPRA>=8@am|LD-~M$^_1z%6pwCh$zY6 zqu6ZTuV0su+u+G*OM~S43*CoaTg%2cq+yN>Vn@ofUU;1Wj1T3nvte%IPV`;YzN21v z?zx_jPe&TH^*f!$A#v z;g??2LMXC5cYD)#x&8Ls%lzj*J}WAMnv%}l<4HkkNn3BFfpHDsf7^uMfT(snWS}EA zK}&c?PsQ?^hMP6#8lzCB_wtNILY+9o8-IE^<#Y!=?~#F1oiIBzV{Equ~C zJlJNejh_UgNhS@C!NbJxZ?{n2kwzhz1vhKm>&V4F(>2jRk+z3t0)D{Svvzu>{p8y%*)PN$hwD8i=FsLWkDRD z{hFTuQLS1PVZ2j2G|3T8&Tc^ZC+R$SII>)rBl9^i!M5hb zX6mYNXI%6BShhUCdFM(NY=~X`Pr+>arcbAz?cFY1Bd}{Otd7zX+6&lUo!%~ayj}V> zt3C@l0#|WcR={;=VDMni0&vWBWM^Wo#0PmLY$Br}uTuNejVH#MjNC#tmw~|BG-x+? zC_meVF+jf2+y}`OAk~~F-SF=;Td1>iOEXzZSfb zZD$}K>K?8f^Gbjg56AGrMW3xQhivw`%zVlq!OV`&bHW9i(|p2Qt55ob@RA;KTua=N zGpvPYbf`F(d zWkHyJ__=psLTBTev{XhvX$e4gleo}n4GK;#7+@1MyzW})q`phd!`ZR2}U?vH_hn*UII4JL`eA0fk@0e8Bxq#$t)XUIN(IF2)RSmY-xBK9Xi1ws{#3G47L?+Q3NNy$ohj-DoXe-~(J4~r`SsgOAr z%{Uq$h-oh)w9@#s1x}lBR`xgRN)<%*`G<2t(v7kMqG7I^92oDulP(bLpZvrNS$9b0 zGhX)czpYY~^O249#-NC)L;Kbr`OsabZpTaZf=4k_Qi3rlufJvB+3B0lQZ@-2Q=iw_ zrd(=1tbXJ0_WOxHw_#TOct8gmweXRj2394-Yi2E~?}EsicXHE`dBU9=HVZS%ILfX+ zR3;s4Bo@DF28RN5vf_o)D_PD+R%aa40l$BUzs`X<-Wvd;rP;;yLun*fthsRKUZ*gk zokK>$&h^4`yEbhcjxa6wcgZ|;qi@5RE&ozy#nn%bn|+yu&FsCjBkb^h`RC7X*#m!j zbo1^;r?5jm{!rikTB7}pjQYi4u`j#4y7-j6YA*b;wBZa(;yB#CqQF z28Wx*B}LQJU7roXwOJtU-fMP_-AIQ90J^(YYn0}@PH5<(VfsVzg6cApz{Fg#qrdec z;#V1dZK+-Q$y8xk#oHfd<7X&*D)71-w`i`WSm9$3!Iq6iwU zG1HXzQ>SR8f6ymu(2w|8l?YT&iOz!jeOG0XX`AGoms?NBQx-PK`xzAt`*9MgL}yN< zW2`}&LzKz~L_F1%Z_jriLXlle+6}Z3P0M+@hMS(xmlgN|Wj$ovLXaS52y9;B}zI@QF_u}Bw z`(9P+`7-^$({>2$Kzyt_ZQt}_OQ&b3Q)o!VzNfQcO0k{ay&C80coY|90XsA0;md;; z*>=U?q0VnkWy7+wajU9~_Gh9eYaEL&wJO5zh@Q#I;>!!iwClJn*!v~U80}>m1R4CY zo&qeMxbFf)$EV*dCC|sx_iy_d4<{}4qnG+chyTT(nWQ2L%%||n=boel7CQI>NzbMO zZ239@S?OP^TG}D!nW{n6Y{KoZVPcZnwQ#t&Hd?ic!8H^v_3Qm1Y0h0LNR_k3`-dhv zKjULFl_q8LD~2FAlI4VL>GC=@ZIva?G`!08rcouHSy<&T%`fy$k_? zeC>k;W7i$YL;iaq7NAYBY^kg+ z&DTGbHDm-hG!}_L%s_6P-?I&QX^{JdK-d8} zv*#X51syJ#I`BRM`7v@VTeF0IT0Tar9fLIt_ws3YX_}F#PL3*;GX97d>rp&?m>)x;o-+r<0DxlDV^6fG>lMH z`c{#gZ(8#hX$_UR2@W`(iK^W#8g0{3+h9I_@i|<>-c-f)l=+s{gjXwFmj$B_2qakp zr7TG|Q%K*D>6S^G4$~{PuggRfLP?sC4NWtRCf2dNRz^PA_%G8;>tvW!oCPY%Ck}fY z57k|%anEE-;@oGU+J7bn^$h%uCv^@U%ds`aOl)3Y%G2mS5Ut~1P1ewlR*{`f-@sM44N!=^44Us?kC!gC!qZw05^}{H}oe@czuWaalCu1Y0V}(*XXOcuRR$oQ2#(#fG_+Y))cciP}iY-r#AZC9b8K!29 zW!dX4#n5*UECkkjkk!dys;x|3^V%LqOg8vx%C#3UTGP-BN7)TInce<#t%{#oa@TlL zu&%~D0)e*3-t}LvD8Sal=)^lsnrpOR{AZ$t(HZgNhoI9gJD=atzZSkBpewj^LZVv6 z#0RSWRNnQa2Y0|(sDni)I37DJI5?YmnAYz8YaMl1&f?V>7z#I#xE*~?vRtc4KwfTi z3H$qsMN&(4NbHnBE^)!Dud(Pr_?RIn{Ntm!h{p(J)9&(R1=W#cSgIdk%>W?=aUl7Y z;8+*o{X}>5Rfzv^;Ft56E|&cmq$xlJE;v@$tT9nAY0d|nJLQ0ZL=79WlGW{XPauus3?d9y zv*IOCgi;@ln!*Sr)qE`G)v9V-jW_q)iRAlU2cDh2P@Nj&uU$K->1UUs z^Yr~k7L^V3*z${F2C5g!y^#Tw8P@s;8Z?b|2kZ1a$)xn>J~Z;2v@yv=xOH=N@b zttdrngz%H|ifZfozWvEFf~6A@FR0^NBL|JQfZpp4lCt<>ip9w9eg`|5YQBq!l8d*W zzoh7t;C6SA!7o?ZK0o9sQEaDO3f+hiEu_n%b}HA#AdlX81zhNkS{;X8mo86!qqlDA zmb+ZR$mBM_z;JQ=j-H>hM_*@%Ar;+#pF(#*nKFq(N4T7T8KvFV404r^X8 zxNVKrO26F~>7h#erdNEVHxch)QbiGQ?^*MThO-oq8)&2Cc;9D=)|iRVXXOcfCwIYq z$CmuOMaHs}PyHVD8p|3F4V)SVVL+79iN~;+lb{mV{vV3?QJ=FRuf4lQ10doiSA z9cmynJbYiI_(JqUi(VH#dvf(>;1X|d(-#Uu2wklQib6sG=kd;lSB3Z<1a%-j zUrb4oO7ijphNLB*5pSg8i0P8+O!|l39<3#|j(-n=#d7#S~U#2uR(G z#nlCsSEWJ%D_`F?r;bfw?e z?0f5-`W<~|8#)OHx7-WSw;%TsY1{M4Ggez(PO$%qdm=5)@-4>5yY;-WeA~U_TvV^E zsWNT(C6#<{#yVOKO~^bQdv+V1etnxi+!|z|J2@B$Lim%p_#VkE@^xuoYZ4hA^pGmv z8t*!+*Y+w7AF(^>SxXXI!Bc;ne1>wYcuzC#&FiNDY);TBl~n)xm!9cQ|dH}-If z#U_tO8Re&JXn7sJyO>uni>JBb+FyeTUazMdH~Kc+2R;(9vsO)U0G!Xx)A(MC6})i$ z%F_+cmTz2*8q2_eaizwtR3hk!Zn&{GqkGG~ARvhTpB5}tBX3c$o+bqcpRNhsRkQ79 z*8>}vu_wfr&~54oVdhg0-GDIDA^xwaw25<#pWj85lv}{?8F3K3s(#mA?X?zVT$|WL zwFF<+SIs1zBa)wJOLt2vfMIJRDl*gaKIjxaR*Xb+7W&}u_m^CI6s8zst0=%EGPC4C zk?Dw6iu48#gz-E>8Is<_4{3wJ($l?kqOP7uOsfDVX~X8yU|o(p9YR*+1V=yNJ$0dL ze_};?_)a6wCwB3rWV@$nZq;tJ=e~`f-)7GXi7+^#LB$rvVopO`e{2rlrK(?UAZMHE zeGAE?gg~7K^D-3$i~chjag~`GB?xi;zOcvC3jgP>JuS>LhE=aUEEdvP)vKxqWObMI>D*T{!;@e!@Z(LZ5Xa3HnHK9hKZk{$-rk6w`TcX z>eK9I?H>KXE7WXyM(9VjigPWmBFexi_72rtLBuT2^T2Kr!lcI_^}Hpdzfw<#@ls6 z>$S77T4(mCY`3IlD-@G4Ju{K)*b6~0q6IPuZCpd?x4U3jDTXy^aOI6EToaS-IlY2Y z_Vgo;FqiJ#UBx5RL9kDif^Kot;R3@Fv!e9WT{9qcUrUI;5Mn9pKC2D0vo@nmM?H3i z5dd_olF25l@{MPL$JS)B(@e|1-cCsVrKAfKUE)R3XD@PJ^uK%8?asj2AcPonoY~g` z+xyn3M=@!p(_)TB$=_AdvlBPqoygu5r-GSi=ss1@*^#YuL`BthwuYfvxxmp6nN4S% z>v_NX^j8icQqyoA+~^F`OyNu);5@X`@y_egX}I)2V4QBT$NdW|*@93$_3rG~OKtIx zwz*49T0DbedtSA8S1COvyn)|DBVeA*0gQx;j^r%I=7?K4a_zt#L;@L+AVs+H6t02d z@cP%S&-@hoU|n;SzFT?c3DC!;P9?K%ZNnPgZ`en-?40;4Ez3^j>CgUyrWEsZk=<&` z6-kY+8N{82{-rd=$JDCzx-+{IK~|D(Q~T`F0sHcA$Dcc_Ri(Y=EIhSLHKbzIsmHZ= zy6&*1Nvc_y_9!^Ksph3uEO+!Dl#q6jt6P>X;b*?~) zJ9Sal`&IfHT8LU)Bzw{Z_Opx~uSJJh)8nOQX$dEH*9l@0F|-cQ*!Dr`?Wra13s!g> zB)>~BpkE7*oeF{(BDpa>tAUMXPvxP5a8mmeG{-Col3 zsAjKWc(sXyPRv_Ri=|qcj5mfRHR;(m{r*Vp__EZBrj5WmFIzok4{v88VPy*e{)r(S zz0|$Zr;oPP%aDjPsb$#7)&Do$Q01Ql)KbWm*zv4_Ykj|$p_4a2iTI#D;kCwAvgwG$ z`kd`uNi8~q;6sl>@H#!Zk~jd3+wi)|t`wH8y_#9u8xd|B8TJLA#Bug`x*7uhVEeYD z1UB%7QacFvz6PK1;~Fjb8W(djKI|oLNt&BF$3Cy^jkM8<%!^e)|H~i#x(tV~3!Cj= zn2+k%uSMI{_QRQEvhSv;!d6L$vVs^PzfLg{KAdwm*34E?DvsIK%G9)J2Z7yS$6%g{nBsId zq(+Obc&1l}q!V(o^oo0EFjx{XHl#($v+j94DZLAMG~M;UP*>;q~23 z-jxd9c0K)iRpT^FGkyHgvFnc}w4bhP9vaG7|7c(1v>zhj!eWP&w?s%uu<>Tq!jC<; zZEL4H4(cEk2B@{8S(wq+jJK6}*|t68H1^+ldm5`fQ9wo~{N(O<&$NXdfX#2DbtT+u zA;sH?-06rL`Z{Z13x-z%tNS-yDG2UwiCnq&UK{kP!h1RrGCkLG-~OcA#xJ`(o;u%Kq%N)To=86Wy-T0?!)u~Fd=2-SGf&S% z&r^QS@U_vJkF(nro}ND2f6-csfBI5Uhj;pM@AgmL&;}VRT#87ux$Sced8w8%{V2ad z;MZxhx`)lbGH9$dcUB=E4zPSjEiev1T_aYH{EiGsKK1!VKv_0vi?1w=*F}P>9ecC; zaH_6wDROYtqrAi-Y{_-d`PkQ?X3f*2ckSPNysdNl7m75vI;C&O-J!>j^~-C>uxCw=(a@x!u3L?) z_fRSP*+zy&i`C)a#LTv&H*#8UwL-IG&*e3Ag%BwsDN!cRL>*Y;EhH-VO|-qf_&X(K z?3&MY>;r|Q{eB;BZP>i1I`g32r6;F0Oszvr*Fgk6+M}BwO;Wj9bH!tm$l=ea?OOgr z;Pu{WN#BC+F3It+|GZ*vCuM3L{@Rn;yPrnncFQ|n$vXm&%|@dXV;$JNN8Vu2I_$HT z+Z@U&pYeb8t3Px_LM7fS$B|K@j1IzokdZy(r(w8PWdrqy8g6dD7SQpI3zlDmoKp6O zPq2^B9xo0QrQw(cL{a&2E(|vX9Z)4g3|B6?lCr48Z7bfmvA7(m1LVKuCq_g0XZcnN zO}fGhCL8#X8b@l}7A}-#?1#-+yM8dxJ%fOwEa}W36K|wnC3Lt9~$kkcvlhrbLrHx$6-2fyADJl!Anz3d+F))4HdP)%#w=cocMd z*gCxnIdHIH(}V{{h4)Qh{&hN>88E(&QkErf-ioby=Y?%QP~m zE36q|U*tVRnCJeAeXpVG@w0mCnY}MQc#Yk?E{8!xgqw(NtE^xuhrI#Y9+(^FeXlE)*Ph&w0|2(bRDu@#0+d^UD?UAAWR(5==IV2+gS$X_CncmJ#%0L_qfF zUZC5JmmWjvZ#ijpNB?1#>|;+B+nRQMU$bd8gNHEv(=QawK9%4)lxrXwguFx1I~kH$M`nwAfiq`~sEs8UbS{;h9e@)ddI8@vC!{2pkv z^ck;?BmY{6iYfiEDXjTVTWsaXMyAH`%+$oVDoSa>f%|ETHguGEF;I*&S#6dVo@n7L zD970I36s?Cu_X&{H(;|-bZbxxcF}piEPaJt5+qllOTUg-vMfOsF zs7x9^E=ZM%0uA3UfJMmJ4{uKxY&Qqiv@RSLS)WS%QIZC~?X8`wpb<_mE@?Onn5Wx} zvBJl&YUe1fMm@Uv1$ocz3nJ^7FLn|{BtQUZk#|O{>v;&HM5z z=kgaWY!vBdxOIBY%0+5$JKfmFK>cB3X=bMe7tk*-W@0MeVU1Q?9PSQLX89ZLZ$B7?riz59_^x9T?NB zgFV^SGF*D&6R+<{>w;EYUOm~N6s{rgH}0NxKw*#9n}w5_^4h)F63LRxXH$cR)%{s##o3oB;*^Uiei@Ur8K!TjxryYmqEIRA7=HD%FO`hzQwYq z-H#Tg8>;_aqSD6;L-%$sDj#4TH0CFt)yLxQtiGu$M=xa=2L4jsHMGX^)L6GBYy?x~ znoQV7Ktf2}5K`v?g;?!W;`x0l!>kSbU|7ri&)rOb_Te{KZ08_0{4jX9*j1!$GFJ%Ky;9n<%tP zqH5!}y1F4s34k}!QOpq~Ff+BGZ{9BYG`-qmb7kGL`!UUe5i>#YJA;{yBx*cGBvCQ% zgn}2zgCbG<^1aUIdJJsL9-s_0?F1jY7S|noST3rSx z30-W8q)rw+zok)^j<7>0Jnwv#L(SBJU5=vw*1!Snp1St91-)Q~fw{x`6H_xj2DE6} zzAZd?#dF2}_m_Vw?@cl8wZ72%iD4!J_beHixK8j*MkFCdJqXyD^Cw(VP@xSFwUf3M zbIaVpMNS!-xrh_u^!QHy>#YIpP^JnN)%V+*Y+KMrp561#TyTv_8xTk zvR*X5?|KC!u+P5O4txDntj0|i-zMp6Zq!orSmmF7h)*~EKb4JyV7v_2;;Ww7@$fKG z4(>my{ZAv&bh-?C|Iixw@CIvTSXaz#H)qF&eEaB_(TfQ$Gg|s~FY)#Z6uWz})-Rtt zr&yO_womBTcVt1)qQlIMSVrMVib7jkU$}Hothc@n-Wv;lOpU@&WNBBh6c;INN#9`)Up+XhTR zBki*N5B=^pU01Vm9ZQdC+#y_i`NGFSdHRRs@fWXsUZTV668SfG23dvZ9^a|@V&Ry{ zFscp++mno-ET$bexGO=DtRJ<>LX1~2ggrDnaP~O_10#MMhSa1mRk}}HszH?`9fB;{ zREQ602Vy$u!0p(;zM(XQnv5}1VELCavK@Un$vjxqV%grftah{00o9Kts@28{$t*;v z`lg6N40YJ+9)c_q$3$B z`A<=X?{pK$(Ni$>02trPZtuZ^==7ur;xA>C6cm{T(ydW3m8gb|0>O3yWS7#u1YmGN zu;_v>A_E5ZkXvY$M2HJj4ATTV^u=V{CLP2~#=%{HmmsCYAYm{6u;#F~X<+0Fg3>Ej zl{7$MF(m>&Xc{CUKnIb6-C*@k#r})+K0BW~lT-^ag zi{dRH5MqZq?j+h_m=)j)l#sJ-E+OvUg&BNN< zMS?Qb3Q`QbdXHVs+WGYZF0P(&X=G#8;pkW1M_j>J)%9vu$e1fhyP%XD*G52*y%%ms zbYyeThOowtO&T2VymWP)333w3OlVX@LY4rhA<4OZb||SUaGH*i-`&nr2z#Zg}kI=gPhW<5LCKYAw4O)nBmjPY1)({C8Tb!@+!pg8Tg#|vCWEA$mjAk+u|ig3~;9h9Api?_=wz3%WU z8!(mHYvN7^YL(YbsS|}WNlo;kW@;`;_KDYVGW^{$Otx-<<6Y zzI6=T7IT1nrW$3JrxS(ZJl!1pq7M3UbNK>ldkvRjSgtk9g%@r1e4N#TGr{1 z5(uZr;|A{KFXheh^EvQBsAwXLRtosN064vBogM2H+>u36WI&@nv9`_+?UwOF2a=;z z){TO8h}V1*f9UfG`>7o72f#`W#`@w`QG5D1DHc;mu3`O$sf$8*nxvbU?<8~vlaKiU zE`OA`N6zs&ffxdS0qQzVf&5}reyYd9!6&Xc<#yNT*Ktp%7&gU2+!C(4p$bhSbAZ-a zaW7%_9Trx~%G~Z-)j$gvVJrT9X?FJl5c}?e6le8EeT^f0O_~KzL&$MSJ_GAgavo61 zC|8n$num`7o6q|KtP^g&MOaQ9WHJUl4Eg1X+ea^t;au({0@IxUC)EgA#eM1NyWz^&Bd>lhyI}3 zrINM7N=hEU9MHf%(xPCuDblsNV+5pw@%(lJw^W>?+7jp{X@GKyZ?RhiEhkhFr3Dwdw71_Xzt-y`HH*daD zMbtV)(r~3mfcOKqrZ{V}_Sgt!nKuZ9Z+tE)WTlZ>%%DN*V1aucgxXi>sC|};0JW`3 zY8x6JA8qhz>U{B1<@F!OXJ7~Y>l+&DZ>HmKZMc5|in?|8=-suPEXSLG)lmScofT`3 zByH%(Td<2X!acr*Zj+#Mt$+X+b`XRe`FmtYg4Oa@RGU>9Gc@kiGDjze7v-qp{$48m z-4<=-GPI-&1L`E-Jmg75dK^EWxyu^&uqRrhR}w7F`QF72-@Ls6__X_K8tX}0U*i}|9cj<_>ClI{;T5#4i{Vr7S6I2Lh4aCE#fFNg24#wI30z|Z&YAvs39-W{l4Z#yvz z)M|H3MgvH6)1-YAa+p}RAZ;aK+9t&AXEEw|zyK>#&tJtLQa7FF{PCX9^%}ZfT)Gz5 zsStQ)_$Q_&958%d(9zoB;0XxlI>~OhUY4bLCqP@)=P#PJaWBIM>%6EUXctoK_AsOE z@;?d__Cr~>FG?#8+x}ZwHjoFS+|V|x=%p}O@p=*o=8gpYl%dMC?C;3yl#^U4*ry;Z zcVLChEB>l?Xo?dOMW0m8RcjvIcF_b}+bHq;a6)V)R?=h>Nb z2i>Lkk|i_-qbo@di2syh-{nJw33&`P=RfsI8~T^z%gQ$+bro?#x;575K&y0^(lD!7 zrv_d38$~}pI=_B2sc_V1eAMr=N_zqjlq25Wb?CqATDniP%;z>g(ap*f1!0m=EN7>y zFScZaKY|AyHQEM@@*b%sk6f!b-}(IEI>QD?VCVY{Pqa#u-ixAIoLuTa=!BsvB(n(o z4+MZb0m4bGTfavU7yZGW<(yiK4CoTk;osI-* zD}jobrzv#cisZCf^3f}mz`RKD9vhXNhJLjRpHlH^M*95N=WO%`WC98F;rtku0KQiV z5ITS(F?Ijc>V}(llYkP1(}M=Xqc4uXc$t61L|U2;7WmP-M}dArVAQ4G>L}3l7#-KGc8}Z?V0@Qdj4~0z`6VCTmK%s1AtzuuwH*Y z1CW^z!Uo{;9zfaf_LuZxYBP{q0i53U!G$wbaOs15K_fW|`0{IL&vhfm4IPDfZ=iO_ zOp&g3qHjw&Zj`MUdka@Lbfe>!{YCi#I{S-iz18Z~x9wxn#B0^&h@(KT5_oeJpia1s zT#TWJJhmxO;Vp`z%wou-pv>sand2WIQBzR67bdo9W(8Bb9}Tsvn>ucHI_S@oRf1;! z1Ef=dQ65V>lYk6})Fwt(q-_s&JE8ag+~4T|#lQ)4%g(FkXL7!%mZm@6arE5#4R?+o zZ@I(55H{jYg#erqp!!P#%y8VcK6dTqadyKvVP$UW_Bgs`$_w`<`7*9rI&_ZRYPIL% z5jt=*0Jy)XeWB~)4#jz6J8Z&Q+$LKb=o&gqrmFTy!YyBnfql`uc&=VrEs1$uY6~V= z13&9jY(TJnBfv&E_Ki7^C?7iXcPH>{;|AE|==EHk%VP9@UvPnQTJxVJ{ZBcxN<;kIp43>+{hs=PO za0rE@F8KuY%*P=r2gmzv>eZk-YknoQ{Bj-srj7e3UsrxX^Si^@Mw+r)>B3Wlfm@>? zaB|cAg+$fW6x+5ns+W?m0`t;GNp7N1;GBog)*Tz29-g|w)|Vdx`VwFF{4?LaqD&^h zFua_DYs^m`ozt)!1vh@v?82l@{=Me9`IwjK<#j5(`*HtP<_7lPFN=Jrkla|ic7EGK z)#BU-8~3YRWzMcb98~0iorjM<&OH6Lsv`keIQxtL`kDhk9fI`PZ=ntCJx>7Qnf8PC zQKTdtb-&_OvJ|p%9JIJ;g3N_0d=2`cTtnf@Lu^urB*Qgaq^42Ik2S`$0^K;%dHl!( zQBY3b@~8g(DKj4;O=-$i7^v@Kl=$YBR)Mic#afTnEkBf>d2PMBVsr6B5v%jyOi$s_ zrjWUirqFt7P7ISuL8;*dBExqE*&LgdNgz5&sLaK;wlfR?4IuLsEJ!t>bh2Kk7rOXk z!y=0+QqFx&T4Yr!q*+C>$!i(??wRVXr#dj^c7zGG-c~9e5)&}3kces7FqI+F za)4d_=Q4fXo-=jr#rgJpZPz5oIXmmus$h?v(L!tCIkM2vnH8Jjd6>f#G zkbAlPj{;bGC912lWlDvC{JavC+pIH&ZZzX`-p5?Y=-74ASbF5;BrhY0$3}B%O=i4u ztSx7ZvS7vmCH*;1rpW^^?eiNEiS~`A=ZlZEJZfbB-l-8*e2*^P%r(sNJ}W4))KmRT z|1S5|k*Dtyf5f|z#meqP4xz=}{Qv=j&Y_7olED8Ae$-AM@M<)XO$=ZO6A9qEohDc9 zdj9A**hM6&XKO}m*EK!Y?K2sx2H$YxiMhK%ve$kaj?!(gT2rF3 z+>qylL&YVys>yMew;X)@IU!I-$Fw0xV;!r8H_xjuwBhVq_#)sK5rhEeP^`@MHnRMH zrLMvNC^QW7a-ter_ka+ZDVuJP$W5B|iyh)pdut0k4*6UDb5xlbB#00&RgXS5_Au!!YLzsQ-yS2h|St<_7P5-sV9CI1Vs8Zwjl%mn&Wo%5{7Gx9yPUzX#WPN3usb5)N}(b0U4+awEtb>Dv*2xaFTT)PTQ)8__7NVN zqxE%1%+!TqhldaMH8J7lyv?n_YIIJM*29HbO>xv~Ba?UKEW~;H+z9gO{pWEy2u@vM zb0g;rN>qg(c1zkW&R&FQbb!zZZdT%ZQ<@?z{1d&^`DcqV#C2o`g(%_>H0bVri{UD& z-|YAu-Ts?WYE}Q8Ds-rsH&EoEC(Yn-E~jTZf}&EtGAYQQTUtap6r2`*bG#pF#Xg?S@cDCH*5Nx$xO0ScA3fq6z@Abm zT&^U$4oeF_R{J3+{SD#vS2^tDd=Y1(LtUZbUOdmdo)@>NAniOFlngl-3qn6I5)InL zA|kCAhUix8blDdJHqZZ_iJ7`0-UO;IBRi-wE3V<{*0#!Lsx`FS@ILWZV^=MQ4E-|c zY6&&?kRm3#X8RU|FgPV_y5`2O*|vQnu4B@^Z}T@cogY0_Fm_V~rL_PWK+(6`kTA5} zNlrt_JkVjvBl74$_p`SY?X}q#6x1wy+(6qTIyEPEab zR)cU9&8nWZkF9f!0QLh3494&HMXcZDKI?`lPwfK7PdZpBc`S@Sp>pgFvmV`G7p6pPnEa10mP^MNH2#TMP z!oQQCLC9!z`@QeUIlrsEfA6UcoouE!9tl&tByE z)xR*JG0`VaEN9+uv5PY^_(q2BYpEPpSEGgZjDPu3#FLjvy?S(Flvj+=HZlsZw{=LF ze%g3QBnTTn=pR`5(@ZT)(a}xr_xzfl_c_H6$V7!!Zr!>c2B!Z$AC$}o1u$HUx3#~D zVIInP7j#|#ZQL2-*63ZWBr94S?aX~|ExO&Eb_<(c{&eKP`W;Gi(Yl(MkUP8872dWt z>)9nmC|1nuT6u>DR{GH_U^au81_x`%O6t26-wo70sD36J59$NH0(9>_#zui61kIq2 zRAk#+9XpaUI@xo>*rMucF5Dih9n6B{qd$}9oVHw!5ckLYUaz`BL1`jQWPN9P$Vm<0 z-SwgEqbpgF-qb|XqvAH0Ptw-MyTe*rQ-`6$%@nGHn@TGmC{xPb7Mv?Vr%bq|nknUU z;0j*(d;66CkD_yrXX^jsxUsA2Hgmt7&D<}!=N8)x%PqMJHTO#@q(aJWm}_$@Nt#Ph zQIblfV&+yVL`kZ-BuSD~>WlsS9*_OMowIY!KKs01ujdoot1Xu%E;Ko@yR6FlyjSe= zybswONlTsQlluInQ@uBK-gnUdy=))p^1S3E_|~~%AqsqoUJUuZ*@clT9dG&fhIUEO z`M~X6fk$UL?IJkB3oac-!{B1fW9~D;&gH?&}mFbXIdxX zj=g|QI&{Ml+r}dlSF~e=uzNOWkW7$B!v)*}I20#Zckhjzri}goK2+xnqq=9@t z0I1=vD^}wk62n4uR>df^3z|OFj={q~&(J zYM@i@WF;A&s)X%iGx)2>)J0Zch~DfB*lYyc=6)Wmd@HL1yckaON&-_%z?5Mz#UW0# zx0XMzXe7AwsqJHgTMbx5ccIL5={zj~%^2BNtJ0d2g|t^ku?@Sxk{tWEI4Iy$92a;0 zDDH7h7uaUKh5u8e?<-t}(>XY+`zNx6q1$8D&@Q~Tew$(kQiShfz;|s*AY{SWLC^BC zsJEt7*u)_7Yv$}%oDy>t_C6E%gM-{XWyTCe&e&0+!Wdq;T{a{L%4o{jSR_iVRsrZ8 zcJ;T46}NYJNu2{cZ*OToa&L_Z%VFd}mN%Hr245gJ)tNh)f%PoN7AW0TItNRSvtn)w zohIlaYmN*W$Oh9T>h}ON$3`OY5Pf-aD#}3_ejLb6PKPmCANtayT78QdP1%8hY+qeh zvv__7_7;8k!I%WcDgr+Hj*nOb7_+6r7E4ucg&&o2pI&>V7-~ly7NSSJ6D$7F#E)6&3rer<+!wr zOL3e`J-`;9)=UyW%gt_2P}%zgyN?bvB&BROIcs2}wyqOANt+z^4On`$>%tERlUjjj zqIvs?n+L>234OQXv4Vce_Ja2{_s0w#pkZt#4d9zszGQ={9jq(O5bPRB| zzcM69VOV7FE9LUf`;sPoS?jlj|2?5sT7=`-(r~)8NNM4O9;55Q>o~3eTbzW?eyakH zRCF~n@8^%26sHm0Ox&t7N+K26DN5{ugKo1#F|o?0pMN4sB=UT8;R#Koc|A5`N%ocn zd{mX4jbRJDyI8>%;P#DN$_lGG{n_^0%f)#qRJva$fbtF5F<;$VaUL=FuB+^ZeND9y z-uW=q0m?N(b-VaZE;wX8*I$>?x&f;f*~471*inE#U&2qg)qUBbJ~6E(NzgssdEUB} z2JWyc{)q@7Fc*=CxDGy)2X;umajlCLgkdA3AkNh6Y9+XzE(C?7qr9EuxQzRLAo{vD zo&6%OGf%APnOqY6vHd+plI>-cb~gzST;kF0+dYgRLPE1R5yN($IO|Sjjk&{;(gp{- z`Nbn7j%0UPu=E!gZVQ%byEp$FzDf00$?GryGYQtjFXb zzLniw12d@EK5@`Jt&yD=+5g2;aQ5SY$A3qDkpdi!^0-DcJy4djIwI zn#mgo=*e^N%MV6gyioZ_Tg~xAW{Cj=pTLCz?|te~7b$Nsw7Og0S5-BT40~nx5k`B-_EM|(sofFGtB*cp2!#2=heJGf!{*9%;7GHYX%iQo)}lQm}r-} zRF~OG3T^3O6$TBLP=@~+wV&dW0Czj4_p4}?=N6W3m)4nrLT~`ZOE`&vhv){FtHNXa zLAxyBs=9kQ72*eb?U5pcT+jnfehVqPoiP#6r_A<^dvlcw{ke3mco=pPC_Vrz~2`4(#_Ux@;lVfft(CStX2tI7LyR=7 zW0u7!Nt4C!NlV#%wPE#1aWW|)FwFVT%X085TGC;Z$8?&3YR2(>C*jF?=g~ zbabS<;L!b-GbSu{QPJJ%3A*=7AKid(UHElX_MKl7+jIzF3?x{gGUNi>Wz(GT!1?Z@ z@lG-G;0tlV#gyAMX}KrTF6$(7yS3oQET<&*mL#p4FxX(osI6DRR92VA2#eK?Wko50 z?Wtfsg7cdlNC#kEVzAVv(64twhy11XO-!{gMg6pRK&FWOqpJNl_SAxd!?W%SdCvJp z>^7;KAb3t}(^K?#SY$;&yk}=#Cg=t z30v4Xt|)$Uq{F+J1{Z0%s^*+C)a`LGeDuo$p?nE=V%Lke-{9dv+ohFvSpx#enAacG z;0bc<4mq~W>qxV9r#ZO?MTYnE{tIw&9uqO>=x-2LlZX5K^6S~1>zxL1qBMJ3Lp=Ie z*wYXnYsjCa3x7@>Am>f}S1~i7rYzzaIy*c?AFj#j>OVE89R8mmOZWY#9NWB-aa~zE zkrG+wUv#smmr>};WM^kt&u1YaCJS`^1(3-)Y+IzDKj4dFgKTReQLSzzz4W*+klaFy z<9Oud1?S5mpyO}lDy|}yr1DIWh<)5_4%^CZ1g2yK#{_5F!~4_W*_5Yq%FxR+W9jWD z;;%UM!HOB(yEPwT)*(Xs^9z6YW!JbgPr4~uG%Q>b9xBgH5Q&dP=8ire zRnU7OuEq|=gfP0o!dt0~v=}uJu_}4E%EbGFeUX^=vmd|Bcbozt$6qA}*eU?KUPZ#4 zee-XP8o6vpUPbZ?tl)>JzDM8gFWDv#3`8)zdl}rC7`-C#hWuBe_;ml0-@^z@x*cNx znoM=;uZ0X579ZdYZWDCEg0lT5n`j`@j^G+ts3;;6Il+>Y*XDG%6Swmw3H3gCtU zwqmQ>`(DAvmPm9T$T8Y!^PrWcZd48dr1vc3(YT0Q&U1`4{bPY-Y8R)tX))pcB0Xt= zj>MQ3i`l0Qp9ibnk}nd1tHl|{3t8;ad)KG*&PJTF)u%nqGuVRci#t5OKe~E2`+`WM z$?<_ND)8`a00v%cXSG?~?`s5y z53^DrPfa-58Wc=1q@QNK_j%9I{g2f)sRh>BBUx7#b-!()*NMWt|Orqmnw46DKlYdv*Uz z5=#!F9<3)uP7A^^cbL#&k#N(mbD);6)QU3&-6$#!3M2flF$SPcEIW0On#-%LaH?W zr}m3#^s6uBS8wV(zGO<=tS6TPjm-26vkG=`b$8OtR`j#iYx=(X+Vh`}ic7q14!oVR z`8B&jaFg*sdhy>Kd7YN)@;GEWaI|VC<2Al-6ZS=;_BI2Nk1oVZb_;RB4E|U$2i~8h zUzsF1Is)V~ERsZSg%02D%Q8&9v3`!X=6DXa1GN;z39&nAbEt&3cJr+u%Nw!Ulhg9H zZ3-UkZvW|ujvk{}oaDAINw3?U$ra9$2W?34@Q2vU#rJ|S#ssTOr&2<`dtXC_oY;l0 z{x{Yc@A@wPIxE=BdYt-~cjnsuJh#Bq)Iu1)d!KnnF%5C<4>o?m> zP3{YH4+M9U0y1MP?=5_aU~Z>5x|3AeUKrmBJ{(QC$xaKqr8ZY8(ln47A+;&0b8kS;zyU5<_9qrp%rBE!n5~)_UPsm11&4mk- zs6xCbyV65nmQNKpmX=swFpNN{{+uA5CUEo@2;{)2bJYE6VOI)xxwE7=jq;7QqOd zr&(NqMP2&HP}`>#A=5h2erK|)^sAAg5cmi((AV#9CP;D(86^pe&v`T~@`OQi+HDqG zM;rxtGDMgFcS7x-YWHJzyeOI)Rh)8~bvD{t4Ethi_YYN94^qt+HjM79i!23p?YpLv zwtLEEW5s3g(JfdI{H>?9rqa{IIWjo?qC<2kv|K=NvAU{+AP_|J77m|=>=LAY*0o7~`2<4iY{D$LpRY4boN(QL`_FdX zd2YCwjkNqBagZC>l|`wqhS+>Y{>`oN*X3MPs>?R|C)%6UT4x1K&mpc2xSpSbFqW#R zxp>Ic+p5B4fMP;HVZ=~w`_O(c=1`bF%aNPwjeVfHz(^yheC(dJKPECkj4%kHz3=81V4Px?kcMv43+=h~4B! zJk|dL-p27qxXkQG@w9(WJ@{6weU6JvMl)0GgEtx}3mTegc31u>$W4@D)Oc}qOoU@f zeFoGLc)`|eqs{JjmKFKP+rfuo;mP_$-n3P0sh--x$`8*HgD9DA5k__qz3x&Bi3mXi zldU;msTztrQa!7b$WheTs_o44L}IgVO=+80E8-ghAHmZHzHFgBjy->q3Y{L1Wq4<| z;N~cy*0Srg^)ng6P9-}{UjtGRQc5Q&suSEJ!o?g9x8Ym#7Ro3@0d%_wtlUZn}i}O_XCuq!$eMz)cx1cJWb+pq6A(R{NO4w zr%Y%Xz}!G#rKbuMr_$If8Lhy8&H>xu&n7VoixOTO4;eT7FPS(K#QXRI$N? zu$>d{AI-L_IwgYLm2&CkbgbsKnCZsv~rCiGkFd)P2c`m=o7$d6OUSAo*XozYU!YAJkqr#MIDEAbK%6-aOs0Lzm2R=XN z>)LJfFbkT<=?F$)01~XO^mXua1Uis58THs;8)d=nVqHD4U)v)IgbWpkDsyR&-W{i1 z6Py`}K8#`0FRptOg)*n840OR=OT9R{O3=c6+4w(3#A`QW8T{K;ArT#Wl@ISbWF^#) zb39C337k@8bpi=gCJ|Z0i5!0LL;qv%?BIJMegNVh=#}QTpY?&rs(JZi&*B~4*Ki0P z%L*Oz_ei>MA&lIdM0T0`pg^N*uzftr$t%y@VlqV}GHK)YMZ~!@cqTy-#sBp-$4hmP zNI2l3$Vnvy96fJQS{w zGyS-Cq((J72%%yod7)KFAhwIce6MO}`cxTyk<1Q$n$Cv&o^k95_DBM|hIY#$L0f~{ zyd#{Oy*z>{g5VGy*7EI?`6)pMs8pe-)_jiboO5i^C6##QSn6wM8(HmjaYuFX9}HP{ z;v&zezkKN|Z&PeTjZBgQe@Py2%jQ@}HmCtq&*Fi*|D zYyx+v5S3Zo<18JfW#I!(7uWhyTeUp|l$>dzsBPs5h$205p`ZfzN1|a}L@fcq6_KnG z@z8U zK71y-A#9Sb93fdA?sm+SvS*mCv_f3y{uInQM=lR+w~;uRtVt{%-nozL+dyBQ7Afcu z*xkJ_F2|2hB2Or>uxmmw>9a7TQNLeJo`c|mH-=vlox%bPOz zmc6*KZpXv{q8|y5WGS<{BR+`EVEGo6Jz>is_HWfdW}3&edMpc>%JLyZe2B*fzU10| zUv?m@r5jiNCY1<0TWoihm+6qK*Kbv>mh2jvcWh=HqH1|{iaC@!t!MKHqkt}&br;VVH-SX> zMQPIJ9Lq%&mjV2f~@lR8hLsC+88GOFmem4&b>K-_4^OMVBum`bK{i$AT z4gmW0McAc&e71DI;A?eUfq*43p>tZDrAZNWJS%E83HWx2Ip{9LU+!T}l5Lf+heox> z0kVCQm;s#YVJQ1#oZ-O+MRaNr{R#{F$nqObCPP}pt~fm|BkzT->CA{Dwb*>$Q%g#0 zofT!jB=Pt>%fT}WugcJA&>~Ta=L|`JzfNN?-5gktW$ zN4OhI)k@-H?F;gi#3!o@_m%k?8$Dg}EMxSxyj~0d>j0`GykCPytNK^Z!qD*wV%jXx zyIW&RtZEvpUCV-3c4f|kwOCuZNQ^6PI|m zYkKuqGSi15&w)s4s-$z_iy_){#Q}fWIrf9Pre=C=)8m7R%O%vMtD;+CDsdo{O5&Ro zo$x-E35E}bG?FLgYWHoMYAN^rhA(dP$a#c$#Tm*qcxbk5k1I)M466=RehX&%IiL|V zG)ooSr$0c5dpwfZrxs8i(E6LaJ|-e>K~xkG1%ilpGDDWkOB)n|kKpKvG;xCoQhWvJ zOX;#vIU_GdQ&@-}pJAn5#^2IfBvv0ho?%2BBFaY@5yyz#ll(T%VQgB$Vy^*FH+DuG zR(j)eQxveA?c&_=nOZ@P8e2S_!SZM=#!`57wTXuZ#E8@}M=o7`jg9q)MhqniB|Yue zgNfiqQdQo)E{1U$PijmLu)pw8ncRi~17lZ5GxEQb-uOb&Bl1aFo#Zu%uh3wFl>`rr3y~dR>ztI1hh=o}wsDyDa;zWo+vm8MxYG2wJ6aCS*CqEp<a)D3c4l4<}}evXw_lhlLe6M%0jDtT6iBd_Lr zSA_v6?>3L&xBc7Mi>XE8f)Oo8n3BWx!$y79!2eWvE3gi7#>eSigiP|ML|oC}Bs3Yn zcI4sXn?f8J-^$R*yyf(cp<|&yT8~_R>}1Cmb2*sma>Sx}hQB@cQer^Jzr&3E{AYuc zeAC1%Tz@)7eS5QboxI2z`S+c~-%lJ1?`%7q&Nk1qG%L&J>sClkZ8^!|6FoZV%V8-* zb~BtyXtA2PgdtB{et&-BaL%=AOUfECRNlIuRnMRIA5Os+ej{3t^ayUB<;g16bk!bJ zGV>OB*lD%YHHfv=nUr0{b?r24RQya<#_^ea;`U7)uF2o#_^PFyQ)C_T1;?fp1!^@D zIa@va{SCJbj}QxmPpfVn+DX!OEp(e&1nX`(X-2f2-s+(fK1tw7gT_s`27~k{V(e4y zp`|yRZl_rQoDmlvPgsAAOId)7#bn1zT!8VWEVK1j0t-BT^4FjH$<T3@=9c- zK24Jxg*--#6OY64Nfm{8UmF=uC^y(kj)h$kX>C6*B9PgKSegp<6YTo+Lyk)j!b?vT z`w)FTDczZocVpbZ0yHc|+{Vc}YOo&liq7|vZ9ICf2%Q>_JUH@|?=H3b88Pa>$4^FV zk|Fg$-jxcT;$I$xtV$^yT`?wxD#_#%Nq?_+h%{bTAcvgaSxWG!RADtXeZG3w3U*^r zwwJt%LXzXZ(0y+dIekd`LfW9de>{X~Zq4*hbFvv@dVfIgDs+n5qSrj%nR16|($wR0 zQYebt#_az*W7d_RV&P-RHF9c=SLXtL^QSVi%Z!Y+5yGTYrxmQ!mq@a ztnjRwQTP?UEV+EoeGfkygnPcC?CSaQ^NoIqk-Q|@^@KRbtNWDG_MYK8cBXsSAJcv# zU6cDh%Y~76Gu4aAn|(auV3Bm>!Bo^mCR5GqFY!7``W{j8HiU^cw%{c{vAt;QGUdE| zqqXY{+_A|N+v(R+6+586M5!9I zGIA72-K!g%FehHIQ?Anp*}OM^Xs~Vp8B|Mft71HHXVtFEJ6aI?`&l-$?`cuBx$O4f zHBz-m@ye60*BVK9j7zv5LwCcHWY07SVotr|H^XA6$7@7Ff0BJ{NX_G`f5?JAWEs5K z)&0#))-LZ#J%Aa0M^=byWmmzJk$A_Gd#B7M!%6o3wzo1j{fD}Vl7=E zr8r6khS)TFsYqYQ?kK8_08nyd_+}M@4uZX zb>3|#A!kG9OG<3ppMQUwDc69$TM^ZK_Ro1=l&vZoxM!hNqq+jN2Q8 z{`&5JV+MK*66jSn{)8%w7)gAv_SP|$SMC4A()+99HNU?D)4nS*^sLh{E{vii&&z~m z%@6-Q%mmO(s|ntnk>gzHPDnDa(2|w-*Hwe@8#^FlEsX|c_aM==nogu!g^$_Nok{ma zC6sk84WH(*%e^U@mt|k#Mk3Afwh&jjc|kwOE^O+kNo{D1aQ6a6CEWtvKxf%DlskFk z8{?L?!kr7PhjbSnX7S6I(t7?IjZ$m&w|nxlmK5WPJTO%|I&cGqb-AonbNJ1N6C0oN zg-`!B?qEG841h7v(pD}^BBi^8Zu|FkKM~$f%1g1KprlEB6?Oz-UeK28>ey=3%oBesaeUm7xO$3z(15N_38=K`&23m3E2cQ<(*5-Jf*voYpaf}D-Y z`1?<8@rUh>K^I~C^Cn7%`JYbH6Y*ReNbcVJ2cgkKn8LOoNS9z(7`>ClFhyInJb0+z z8T!R~LB<(_rIcrRcSm!r2G(7rEX%b99GK&EQnj1n`L)Im*n;1efUWep{2d!?oqeno zaa>o{vIpfQ18kYbJzh~WDF18{yHIn9qS^wuXeQ_+Fil39-CjdU-!z<&4kLh4@U83~ zdQHOQw-*VaSEVHkOjqxpuQb$sn*G{oLC=yuP&aok>mMk_@?B>z;gTP9CY!xtm|@DW zFz86(Dd5&G9b3SfkVnn_q@SlZMT$}*ruXk*Uz=XGOlu|4av|8i6-AK zYCl^P8Rb$7NpVVysjgXWD6DEVkbo1SFWVBp3aXZbIQJP1oeyDexfZat>B*jG=ePd$sE*v)TcW>98w2{U->CRRL3mSY#|M%e6IU6PN4u^E_aBprUSrQ+wocZpGaha}9 zXI+*>Jj}MPjT1QcBK6&0n8>aZPY{oJ6rp0ST+4vCGwTJQWW7Uv3xb z>8fac@!66Oj*DH_vpB>=3xtqtkTKWu{jC6&bZc(9?boG0oAq9)E9Xfc_^dzo1)(UL z$r!Sav-RU=h3O4>Y0SoQRK-sH%&(;)|N5(beVlN(;m{lWJ*wAOQs5Y_hK2xQ*kM&vRVlx8l`YC z87&#PTax9#<><&q<&UiCkn|ZPs`15`2Ak|Ad0ug9Y9z1=JBazMD<%2w3b1a#o)?e6 zzXyH3^r(ldVloZey@AE3JsX3f%p?oZtP25q2P!1dXp<5XiKh5Dg8E&~F|>H5km`9vR)2@V8(6o9VQB90#$PIk| zc|C1Wv&>`XwyW7^vIO_sI&)E4_{#51;=?`gsA2IuZm$7g%jCLq0gM^%gV-8G?Sm z6d?VDuL>E;iDt26$~7MauuZBBMW%S&*HMa&@X#H-%No@nE++YAx8ht6ILDEPiBm|S zn3@>2pD>*8I!~Ic{5+`71da*3Kl)4KxMif{VzSN9r?`qzHNL5i`o*mbi*I z69g`DF3R`l&*uWew8Y*6*?vH%SERG>R)Of3nV!SmSW-jOqT`tSb~@JO-3uq^4dFzI zq2tfN^Z%U6gz^ngG3=W?9~wIN9*4Cz%gK%~QfUaE=hq?M9{cz__tqLq&h|?}lbzEP z=0v^9R1(y(mHseVSF8`V`#Wg5BmYE5a)8m=?xXu3aeP$fsvyK(3+cLW1_q0me7C=r z)*^O7pa1-ff&RS@xXX1^INSu!r*kH+Aa4!O4`2D=p_$oD+%IPbb$b6SS{tW>VUTH^Jq zTVu_cX;&Nf2=W}5)^JkJ`P~oOsBbToeUcwd%OL89v-LksYg|@zS(q&PaAT`S_z-}? z?A$iam~V(N_2&OOYU75Co|*!V+}Wm#Cf~dDYDa^AUA@uqTO2Jh=Q~E%-uG`6y~|q3 zm;O8u-p2;H$_;%2j%cqCZrtEBJlN5mUiy(#^ZqkKBop`=)cJ7DMDn3>)bY1|V@WeL z$jOj{h?{qi8-X!XSjwquU`mWX91wuCsLLwdjD3#W#STXcHRq1T!;Xi~Hp#BVCvf7kUtZ;z3sU#D7C5 zbS-kG3uWDdtm*r6*Xe^~MDJGZ`m(g@>S168`ByPt z%6*`v;hDnI>wS~O5-0mnanFw)4@Z6~mS2c##*onBSo5vvKwLP^4J7B_g6%p2bTt4B zjw{A^D~=b_UMyuhBQ4HLP7)!Zok-qXu+NX}fB%r;zHV_W>VcSS7wvb0_Pvc^bLmeh zlZWi~Ps_(muLOk`G+qA=uj79(QHwHuxozwDTfE)%Oq;w02#cpX6T1}v6NOX#$f2Ab zXkF)T6YIkq91g2#PsDh4zk)NQe~V`h%?Q$>ru%SkTE6y#KzeCO+-eXaN(R?Gg{ILwD46&~@gHBzngjHVC-N7jwPd8rNI zpQR%dGHY!(%h>mqx0S{lG0pGb5lBm#p{hW`nkFWWi|!f%Y(YZwjM_<-EPY1SP83Bp z#g1ja1dqxgNa+#ZSro==9$V`q_yjMGPA!ywps)ElN7-8vTyjRN{yA2J3D%3d*Hu%71_*5*#b$}&D%7CcK&oVei^Q+&wC?@+eePGYxu4~hM*9l z($n7a`*clvRyBs7i@rmj_m;-9h>DXpfd>unnh4o8gPk|8Xo5wNcD1+^76S*jrk4Rj z)YUlAT}wbNkBUew1?Ad9(~j{I1fuVlK8~wx4KDxs5|Hlqb#RJ%*GJJbN@l*`r_d9M%do)5)&4 zg7Jt?Kv-?loj+ayD+GIN{Z4~qCsc@O zMO(^cq(7}_Jgr5`@T8AOdq{lOI9*FHBRw87#}$6s?BE~=N$Hud0A2|&-z8OAVFw1u zR8<%{^i2v+4>*7PY8F>+TU2D|BdRMWia{~#G>>Ab$<~`O)ld@dVx--EBuS2^D@ptV zB^?z_R;&XNq)3)hJp4UBWvCx^CLf22`11SuFWcE3TQ7U*)rU~gRgM>?g*P}um0|m1 zt(Q^0pEMl$RIV|BD^y^a`v^U=$*1NvlsOj5hV<9ftYNUrA}Hifz>Nz@5{Pa6(AakK z%J2Y#J7L}yI5S!G)PgYCx*{B1)@@pD@fAQF67wvKAB<40B_5FAeZKNy%a|qK_3d+C z&qB>m6uqiRgWiWdXrT7I!J`-IGd zHSuhz<-J(-UtS(GFeV~j{}>=@ie0{(e1C-)%TqBt0(ec!&-iGH*X@_7)3h7a8KdK` zPNyXvv)NBG_UoEv9XAZZu0|b$mE>mIGNhpFH@I$D^?4=y37`hhZx^{IJ!A{x380WN z_OMPnEd*8P{3`;w+6=B+)Tq<zH}I)G>)V^34-i@U&@%Ja+LMux-;>qak0M#czpdE7U1xQpM9^fonANLf*xJ zIgKj9Nj^225n$u;@`xQ%8c$rp;BotCfQKOc-eIh5cZMcUb&+l^d|!JMo}}9TM#pw)`BJXiNtn^ zI6tS=mWQWKF9I%3S|nSBdn@LynxIyjtG@Jfs+!*leM4{qxcsHdge zd>$fu8xm!8X<+8`sR-5A)5J^Rg?|$&G)2SXa9Zu0^TM4sAN8#(SIxN>RhCKBL1P4v z7%KR|Ux-_Kx#xN9KJ)QX@;HXEq3+;F0J&1MW>qCBr`tx86`!e9Nx-(h02EW;-l?j^-?1jdJvh2_8&#<| zTv?8B!Ji9RVC30Qnf-sw@S5WmI;#N+*xzg!?{sVzEuKU=3#(Js&%iFF{}g|LsOrV` zGZ-H)o4^>C?Pkdt0s1L#fES>hmS+#alO$w$c!84Tnjq1CO~Y$CQAfP^N8mnGgs+S3 zzsD%-egVXVP@bH^oPJ}D);bvSZ!pL$QFyCT8$)kA(kRiFOwe72(u{(e`Qq0q45h~> z3Vk6ig49?Z;lcr6STaU-3718cFW7%)Dpl)f)rdW8^CYgk~1 zOEWyHm9hwM1vXP$^$##H$#I~R8dcVX7>>8mo&eMzhPu5ubuKbinsL>x2ie}GIz&{r zI(b`)r2abgT#cCAaj~6RwcRgX=X(=zA)@Dn)2ahpTxGhVpGut_4!@l|pEwC59gI{; zL!5SQI3Ou{s8$t!BQNj28^Vg&|9~Um2FcRHRB7DZ3*|b}D_xRLxw{j)Wv;Q3|97x$^=UYe`09=at0_xrcYuA9FN6 z@Zvl{WK%=?<*ns4Am*~M{|t~|_tYj&W~Ns1@n?+;TFt%B^t?&&C1(cx9`!{VWGou+ z-zz7#3oHKz=%br|>fVc{(#h??L2-28+r? z=%wa2?v}vm&v1_#4?#0%*s@;1(-4LNBXmJDc0VnoM&MZdQU^MB%1s2e9E4TX3_n$B zpVpFA$UB1)&8VqIO47694dRn_G2Oz&<&^_r3|UD~-R-W6XEue^;RmPQYr^YnsU*pT zuB}vQT5&&2KNP#sY2LP(Vb{%ng37A$n1b;>G(mlRAaZUX0i*WtC7Kf+{pQGD4c;~= z0Qyp4yi}Z5BuBzLp_c8VLE}UrReY3jH%gKI4HGc_G8K4X!N@%hY;iBG((q;{f3$Pw zgu-y>D#2fZHyNf70Esc?9`#@obuoCGIe?8vAu^X}(5!QuY*|IZwtnO{I zYS-}tPhm4ZutE*|lkZ1TRuOg09oEOsK74??895@jD#wscaKx-W0@P{RBDg+B6`}an z*O3NpneDQqZ6@5bj-R)K(YdbB&?mbsEVBjwjIQs`1JIkywU;POl5}rjrtnJ%N8Qcj z;AH1t6CV{q*47kS{%dUuz{#q^bQ@xmSv_$1E$8(&zp#O= z`;)776<8f2>K+DeMBF*}=1DE&#K`7nXwliMlenkd=BDL1=VrYA`k#iR=PJ?#9nJN> zo5fYjc6gQJ2er!>#vU6-e|%@UA|akz56N+y_%m;|S`0dFY$Ha#&O91(8Yro?E;;#b z?5*j{_CP?q=3ihtaDh>cS2nBsq@hMou?daZ*rRA%scMo$TL_!UmQXY-+{vbQe*d*J z(spcOtTyzaaBkW8Xy5bdtmJh*Dr)!uI=qge3rXj>=|O^LhcVE63n7{awJaekLVmrv zAg&qDb|RJsTa0LAcdqp+C~h7_#hH|NBi)KOdf?O@zmC3i{BPma3&+<@vO`V@O}DtX zmz$cijw$WAcvopiEHW&n`p2H+{B*KAu@X3*O*D$Cg`%X>eTU6E?0@djCpwpZaQqT( zG7bOexfVk_m{SpT@wfv9qKuMr(FnV{?t?s?aYwFST{sOAIB6=EzjbQn`fzr>uoj4s z(;8mAq1bMev4~r1SH>xtohG8uS6(B*cPKzxVi=gd=&5fxIynUGdSq93RA{ z?4UV+s-gd4pKa8D#=Wh2ih@jcsj3h3*sAw|WQ@`^Vytbs(2e;1bwdrYW_!w&-d|I& z>~wo2z96*Ax}jGoZXwvW9-;(aa(a>GH%D>8lw`}k`+J24S9WV)NFX$pIOk%|uY;wD z?E;2`ZWplnG*K&9kn?Y)*l%F3Dj z8A|P!_9i&4<>K?Fl=F3@5kJpN$V9(-V`sU!4Q0t~h>)^JZmx(C$?&Lq zFsz<<=WJf@j#J)WoziIEMs`{%MO0wT;}10|jvPxAvTry=|2rdTp%TS?$$rk!CuZd}MUiPmqsciJjZ*{qs#TS*!U57PnLsbb>A}LC*me?20vA);~0wrSio!!gX zHLxI}xtDK>TstEcqmB0c*S`t;$#%|W?uXp3aq^>CvlCxpgSvQEP7_$XUXjd#|N7yW zoen7Oj_?5c1N#KX^Mx0+Q7TNeJFC$gig4`v>E=oeZJa4Sw_!;mHchlVbfU%(^OZpU zf-Nuq!!jH>%n5MjkljibGIaXQq#AYx_0((Cb1XrHB9f(*edHKqN!l7w zL$|8I$?BNf8N(kMWPqI`eby+a;!Gw~?_=x@YlmDaO54L5Bq!a+$eKvOt8vF217>sV zF?^}czqv|@b=k2ba#albiq<=Gf`vFUk|L9IuB@os|r0l~2w!nTb#1{L4>e`?i z+g$l9>>2_5`K!0{Hl(v^qfO`}^P`Jm47j*7$4Hvkj5_iG&*=GXN#kP_)fp=EgTls69l|A@8QNozTltY3rKOxZd=wvcb}q|5e1u%Z1nZ`^IpDn+u}FudQ%?v~S{)yt)s~a}-uwVx&}CKiL|G z>b3RJL5CoHmP}7~3(I22Q!7K(stB1B&Y)uy={?!rb?1ZKdDxkI&G_vW->VBtlqi4V zON!BL6hb-+%L7gAYPchfctdIZSJ8aqY~z5FkEHh(Bp?uhzfwUcZB4TnQ6!iXKtYXh z$V`(}4SzyG!14HJzXxSug+JN(O(GNRCJ}l=_!29*w$&&~`hN1`= z5D)|;bh8wcNKwEh9HS5=E)oK4h+UHYLQ=@dl(k3J9oT(#M7<<)2xY@VWygIlc>SO1 zt_5wBXL_;H6_byQbrHLQzx|RVx9+Ddhu&%pB%Vkd&9NQpCf&xh1m1x9H_PL@4=&$5 zGBt;kPI{|-A;JSC-j?^laOPfG(T@Wf3Lle+}NVQ>*QQWtnCQ)9o_knM~f(Z<*$1rtP)9#s!p=XAv>7 zB=Woc>0M%-Qb((kL<;)*;Fyk>vSY$X_%6jCPWHhZH$sfB6>Y^yQ3-lNISPy#ID6!P zaMk}A1OvgfPB|@Yj?2)f?WnxQV2TtwHf*{o^Jk@HWo7d7{ss5G&N=sUKIc5o`?>in<_1(hl>+~G zuMznmD~5CLN&H1N>FVw*Ddi4!#1`9#6IW9`X7m_BEDyQA^@ms08>gahkJ`O_%HXCC zko)O;6_e~V*xPQ9UGa;M+lH!~0&71?K&x*tTHVLD+8%J~F<^0!@ok7e))7>M{nhLf zzZ6dNPNd2vgsX38rl>G&0Ji%FA@Z04bLvD9^rR`0WZk*Xx@jN2`w(hb)2x2Ki=T0G z1VO-vxUU=kP%l+NjSs;aO==!|@k{sJGBo~MJRw3JOo$*BdxK1$svuBy39876!zEZp zazn%L#}_Qp=3yj=1^N=*vAP>^>L_ss=h%?|kY1=aTn)_gXS3Dg|+shbCFR|U@S)LxX= zW4%uHqt|c?1hV?-lqVx_Tfy@6LC5-xu-`+yiFI$@r<{ zn0Y$%T$&FAF%}E9S>QXrgAn~qC#mR%c7&>5xaK9?e@i$(36Gt}Bj&d!Q7n+-E{lMk zW?Sl^Z%{?}36>7*NAe-XJ@(}#_Of-*$Rm0eqZMY$*r)X~-Z$-&ImYhaq0*tXzx{)N zcs&VB;NiG?XBy-$1%vGX>jRoN`wKT~i*RD?t}i?FfqSZumx$t?+H0P5IWzi!KK|B{ zX_zazJn zVhyt#I~_U>3)4L~YXxfqeD~2j@DP-#bFrjti`r5yjtO0efwmllni$|ieiX|lD8&Gn zGgPUhW5!yKqqVvbRuF{!60VxO&j<9_Ab=cUm7Zdhn-xh-4XSge4olh!qS_F_OE~7F z5t4=o6f1e*c}Q+qmi`Ibap zGWRM*z&KJB@9?>t7=?R&Wm3yD1FMI@vET~Ck^ve&BGg2jZT1g^Qg1^G@ zJwB#*kb&B}bjZUmZLa``p;+PZ`7Nz!_0jq25v8{ygB!n>dhZ2M@_5j%>@Ha_5)7_$ z(YF({jSaQpr0^rI+9>?#=sj=qAOk#DL z)J!lqr;q!`D$puAh>SqzwgE}PBdCN3FIr2V0YL{A4hDCjGX*gUD%qRzm~b;nbfk49+6KD#QPnyQ46f4t=5E- zHyh<20`elj1(s?|9aMQKb2${mQK3bFRoe-d~Upq75!s zr;>q#V_iQ!8afRjLg+WtH6{5&f549Y;LCZ?{x6Pam+5oVn9I1iwd3X@fKqJE4ut5a zUd%>C*h*NqeciXdEnJdNq3tP&rY;@Yn+bb&XpjEgrM2ASdCgrkag7ra-Dz#DHdVV2 zq5di4)qA4Q`RQhZBgo0Zjo&Q5MQ~(k=k79Z`r6}DJkXgKR1CXbi-wDB zzeOCoBwGY4Mk}2GcjL_OwEV35_!OnX?yZnFI+@MP`n2h)lFAt$)7jxoN@caz_rNlK zZ~FNg_cIQ<_r=*ShLVy8!0_UU3uX}_F+=(XQ#veMQMSD)nu(Px0c8vHiyKt`zg?(^ z`%eZD{W@2)>ar8XhVc)?8^31F2mbz2s8H%Hb#vT4?y22%otvmI12H`J1R~eF^#UXZ zqyZ;M#6R+^Q3WH*9kBAeJ9x5+;8$)#zkJ&N@J+AdXM1#mpEMFhedtu^`!G;me0F{# z)5^Fc?1gV^(S@%w*e@_?g`MD?JYpdO=svmaFz24(E%d7QmEkqqz8dRyLg^6Vr9h8M zI?>r3_V^q7arT<{&yINGQmFXvEnyYx?lFX{`9ysZg36w7C&BAKINWu{5Xn_GOzoF3 zA*0ccrcsjIU0M8=np4sD>B5!xg!-ac)h1TL7;2|yQ|8?e`3ulcqRM9ceIa&4*k8JU zKTNsbbbLgXTzVRdk69|QTXwEzfyXW?%-CI3xPOxhL+QOl4Bk-doRr>Tg3cR6s|;!a)Ibfh9mutOHk2b zqvEOaC@yY6T(|W%&KQgCYiOPzLL_1c(R|{+H|cHvaQ31J$1#V_ZLe>^ka10V5r9)9p z;ZVX%ZLDVHhsfNRqPu?9cfA}5)en6G;=##(xL2cZY}+w_1NO?2WWsg1l2Qy3?kpomd*|=cd~%q8mrK2H0~W#<0zdf$JOe(}8uv*M&e?HM0+s~T)`NU-82wt-?HI&u=cm09 zzORK=>QdVjT8{>r#e^z>P-!s)HMS&6zN~Bsg?_yxv#s--H58QK5aLR<)5011{)Mm$ z8{lxl^j!j3N+i_Zd(~%;NN*3v^Slgx{w{n#v$?m*fTr>7*i^|*#>c^t=M?;l;J2!q zRq;twRK(bp)Qf8A^YFk{*YbEfLm6kZm8<}>QV)I%g$s&35L z%=Vyx80Pua!Hx4$!uWFTj6zeZ0)w&z!n29md*Z>+Q0!y*Cn458jzM_Fh4%CGe*hjc z+V>?VZlkJO9(*P$nB9TFvp<7(7TP5cusB>I|L2$|*pMbgEck8f=GBvp(b09ZNa(FL zPkrk%_hNju&mM#P{Chxq`g9@Ta-)wO^1Ty9@}aHBb3jYvkR+%6=XBhRZ8?pI@``nh zp;I@t_sz9rZs_DT>HIU|dFY%r3g7xx@CQHOq+pTP#oCw}g>sUamd`J*nWz`AAD(on zTY{qqO0Sc;7}IAnF~l|9yeVn~4=uGxpW!jJ8!aQHcTyXFBOQ4?4Q(XnW7qD2%yl}( zE2lia_oR7qv1WgJ#Z#U(@n^*9Bk$5Qd|}0BhY#D%rm_D3k6xQM((MR0P}W1s4@ye> zb?-+VcAT$Idy#u0{^`DXr_DjSS>44FhD`N0sS6`NJUqx3!ievziSADuNCi6`FRl5x z)oXidGJSlevv^)=fCUM2+;l0m}hO^R=*Q+0;rySCqc|6C#|M7S$H#u4(>oc(~ z0?glY6nXj0K6Mz2mfXy7Kg^wKI`K9kQJcEwA6uSdeqcV1+ znwI*{`!e8K`O$yR;a&uXn)Vcm7(hn`1tOA*0G*Of0`NlQ6N z>R?GcBJL++gROvA8s zd!#2nZE)_F2HLFVh^a$-hoGVH>a2d{XU;+kzCmumpKLL|%9Sphs2OCIFL?9I(n7rf zJU!zk-AjN7;6F*@|NdCn^7vaUMv}OC4x#L|?XYmpSDLQw|Qg?o&Vv%?Hf!AZ3#&v`_%<%dmhl#?UXjGPjfT* zB4cK=&`{{!^_pNOnQ>g0m35a3eR4DHfe%n%R^`o?(kI2FOOe*k{MM*?C~DpQHOF$G z!BIlf%+sD&J;&!&&@VSwUTu3g#2^s->f-G>Ts7CeR5ZLTgnejvoaTjhRSIXV5BLil zTeS@p2*up2>diMZgr>&sV;?^|0xI(Y_Kz0VX8Ta%xWbB6FU=?kb0BDMbt)(Hvcz)= zj(Hu)iAND`rVXY&duVg|z=8dSSGe0Wep0KY4S3=2H(I)_-?FTZ^w}QjDyIKbsAT0Ki0SHSCN-eztlbtn7e87%@)q0#wf$X-mxQ> z9{8S4gHB5nyZkH!0qN97>`A9)d@1XQHUh(~bvbW~*ICUa5C&4`q;^)&y>#d(r-|uC4D*HNmw^% zLq$RBvsiN`ky>O}x^tePE$Ai1=@i$P)=bOpPk5pMo4|*koK@Lc2AJ2*<0V0T{+gP9 z(Uh${2y;Uy#w%9#px7=D9wKiU{6pP+!oV|FS38{I#ecC7b?u&E6co$wfa|7n3XDaN z14R&oWAU@A(Z@7#gH(n-g)6g)3^@gbKC_}+kWcPI8Z!7Yd{%~%oE|n3gu6#m@ayZd zNVV00i&vkMWsgt6rN$?n9zIuKtiyq*1RCbs1>xHEaV@cmkvqn?$Z2gBXRv+QWrT#X zjG|#%|DY9hBC|SQ%xh@Js$;9p?aB-%TTJf{Dw3z)Jqf#^6YF8-t}W)EmzaUi-t&*C zvfuM6jzNRJV2VY2*v_~K*Rdh}rrO;ipS1M@)yT1#m9S{{5Ux4tbK#f40K zN|9-PW@uxzlHeCGDCcw$+-fH8AgQ1eZGIKn{Q~01o2a?~7JLJ95@otHnl>Mzsl|q# zA=U_0*R-$);^6LcYlUR}In>wnY^jCUcsY-*yAu8KO!*$3Sw$Om2jjELY7@`N2!T2v z1(UmvL7BY%tFdnb)X+zYE9BE;LxdR$QI0z^YtEZUu2w80en`wVqR56Gb)eFVYl^Ej zHyH(d7=#*%50@`4e@H6*dDZ_hgtFgOXDr%tyaC3I^oPLYA=i~JtbbnF)(GEH#X;GC zm4EihBQ%8UfGqGUPdfOm-Uq(A-Qx`2JXI6=fq&26@3hnvQBTe79`C$hUHy^FHVibK zaOtB02{P=HcQE~-j$gLT8uu}Vd)vk3QXKP~i>y=~!W|Ze4d(sMD6X5$;jH746SwW` zLD)UnwL-P4Q@j5=n||(9F@!Sx72>=DK&Xg0^(S`xc=Hc{RXi+$t*&RjR=9#N6rX&E z*h>lhH(*Pf8kNdr^_Z*<%6vQXRdlucv#?h33%q;z(5Yj*ZnX|^;AI>PSIYW|&W2$h z31>%)w9)>5m!14TSmiPw8|G-j%D8{!b|ILN;tgCojCEc`JA;+aD7@`<=Pgt8i@P#z ztV;JSmF@g(B+brw*?W~Ym?5Zugl^U{*poNCxnWtQ^KI`n!1J;av{%?@|K&il%Wdy%!;DRV7jZfl*&~7^dB@CvOyhyDtkZ` zI8Zzhlbca+zuHz1OqFw{W>VlbptXs9hTS4S*RRRvX1+R(1lG{yf6-;;4VF`yrgUx} zRT{07zw57&iBQ&j5Ntd^el26{x z;=4T2gasc@@rLducx@dk;z>n zHTl(bWj=H_f~Xh^RhzoYBN?OXDhoO4>Kj`sVL|2*toa5y_QX}+C-z)F;MWT!0h`B| z(gP6gXODZDu!R;9QAVHL7E1>%rrN2{4q4vXaL>?vG2v$OU;YUnDZfQbYJeH(6Nl|3 zP+)NJN>JN|TQf@cboJ9orNHh0XuceVz=m#}y@I_}WhN5V7{focRnFd2*HUsTgrsZ0 z6%3{CA$$N!v1{g%mHkz7H7x|)gXcowxvXjxPu5A2)` zwM0s!$}R!0;SCji7nFa}qlgHPTH(i+0$bP!=lR>bF}UA6FAYGt*ZBzA#M@b!d!{N% zA&i$bfb`fcL0g|ch3CJT9V~|2BdL;}^dSPhntd3VgOIQL%v1yTEh~JbN&p<=u+yCi zm7u%lya;RAx=KC5zvwPi*o_R^jsPItM{s-UiinzFFrWS>*FeAk723SdR@#aK_@jT( z4(v0&)c`Qm&I|T&7xMlF@SiR|N)z)A1psEBeXrj_2F>3uSjxOU&A8f)O%?IxAz&Lvri&vh#{Tc(=1u?54wetEN)8A3{Pj|@ zrd*oi;3-hlU$ml_^KOm9ePu4E4^5Oc5OOTda^eko(tVE2OQns)?N+F z<2@p$4yGG?tZCf&zE^cS|6fF5l@^bdFkX3R)<$%`3C;jsJ&x(?QaH&A*SP_e!??dvh9a zKW#r$u?+C&w>|zH@YvF(s>D@Jet5(cFDu2xtwR1&aaN?b6;z~yV7kq}QXW86W<#}> zc9<+`o*eFKVLvDTK}(dncf7Cf6la9?2f~l$-g@7gri9Axd@#?w^LvJ82H5)G z-2Q*r@RlNY*V#)Eoeoe-SS%;T84^Eu$%tr!e{Zv;bMhgQh>Gn zf**PY0?!V>Zuq}ZjeV#T%T2yAapdnd;^dWr)lk9e%MbW;@eH7_LD!%>;#JrwD!nz; zZ|AYzD8J{gl>k6x;LT27j|rawKB7o)=5`?e#rS`FBuoF@mB~>C!v$l5=#yjUr_TG6 z2TDCSaPb{@OVC-S4TAqnF~IEmj0I`-nP7}jILI0AFIS9xm^S4#f5uhN#k}g=#!KEV z+rAlB1ROPjYP^4*Cg{42FMEbh(K#Qcy)_e(WKX}!i?f5G9DSoBUx7Yk{S9_WW z;WPMD9e}+LhUswcG^##9l$#^LQ;%oRMQyRIJ|I~_R=72K(@0AGT_{c%d4NY|Y zMJN5^o7Dor`r7+?6;f*^c}h%5?j&XVSfxvuYwO)o_Df#uL)B!~jT1YcBZtYtD-l6_ zNG{iV?*wn~d76le1)%s|4y1-}z6i($@jou#n>$k_2kA|I)>aCE+n=~9U}eBE%vJVe zDDRQ7t$16QfN&Helxl-1|0-TE-=_`!$D7ha$Xqek&nQTGl{F7{T>xw=Ol{lt9@yyA zNr;=BkG=I}zs6=py)Y;z=@d%zA#hk}M_^gjiLni?Q>Ee9%TVycoC9`*3N7d`??2@w5G$eIAH!# zy6H4vHJ?#jFrUUk3~UE@`la6b2u8HvRbu^~n^|#GROE}+NUu!Z67Q=Qzh)ghu%Y4y zf(oge$aTK!vgv&FN>jBF>+;(U@V<1>NjS=L*?c@ zxATKdWUU4rcm4!agMhLB`C{ixe3Gf29*ED#4zVZT@f&SBuZsPx;KJe^Dl&B$%#c3I zr_Yyr3wh(wf`J(zN<=)JaG-iSAIZ7~UCo|+_-VFbKt>UB=vDe-N>&=>OQUQNfdX0& z2jrLbx7@W2Ew%ig=`12>Li9AWux-yBc=}~Xx&k=V`ICQYBS6a&xU$K&X|&5glyUrt z)iy2p%-Esrn}Y>xoDU~g0^|^Il^b;4V3DV|Ij6?};okMQ!iBKehbKMU?B22zq+IDe z$aa$md3dKt&(+7JB$PijOXLNdCTDFEXKrJEeqRJErO*&cmtU6i6PMzyQ?@obZ*r;pc&(ue53yC5A}hc&O}$ zeWGNn|2%|`2MY5rf-=Cq%|K8AJL(Jgi4nnKgiox@jRD@n5?=3B=PmlYn`d&+rx9Hw zK~YP*=L})gMmzN1uQ62Somyb}cXj}n65^6T4!qH+`MU77m1+|R&y zU%ufS-?##+oFU~GfiY?6u?z3JYBnSCKx}DSH+thINT!By(u*ZVHNNHirR%>6myD@q zrD^&##W!F(d(>tAWV=&&s;BvnYWZ5H4hSlAea$nyBmjp}wxH4Ng^&VWsO;%`FhH4} z=g~%W0SIPvM{dIGJ#$GFo;OZLxMxk1CDy#!eV9ldrT{GOAQp-wzPAfDhqP%&fe89U$Ff`H*XlJSE^UM}JPE)Bw@B zwtq&Uo@v7R0B-0hhl%NjC1sU_)w8ekL&w;>`X6V>>2=c6<}QX4^exh=dL70^3{61_ zLHd(6EaE9oFc0j6HrzgeI#H~$)_p3b{A;B?}3yZgpP z57RB3@T2=BJ>BtJ;eM=6&!A4Gqs6Sgv?pDe*0eEfw43BT59rma(W-8P5mt~h!%ch6 zxV+jn`H}v@6@hTj$t1pYdb(<$PPrfZdSU#zF0Lt~d7Arv`Fg(#&pEtm_$^csRj z?F1)U5Too~z}Liu)v9@t!_1HtlvPQSsjI#ro%KI(Jm0IxNS7o}D`cK@9P|DTgr_H{ z;_rA1ubzgV12htrp#CxDURgtKjZ{Px3E|p}Cuf3mM%=7h07`9B_c&5boq5Br?Bd=V zV_JD#=U*))` zlnVo@uuM_4f2Hw}as;{Ff|x)CZ?)d_tZ+;nTBMPB)}};Y^7ajwC>nw!XRX zkuW}a?g+jquQs{Nv{60C{`9$t)~#PB0(=qq)G{euHme8SZhC8M9FaLy?0x&x-C~ed z+68u!69IXbgEy?*Rt|a|H=b6Ut{WJ#s=eq=-gh~w!DU~AdD6}KZ{)!@h<>J@;-TBV zW-fbfFCU!x_WUnS#Wz%nDUqBkBsU6qdXanDcqV<@?)^p|0%n@0!6-ZmiXi1=bH?Nk zdC71f!gYgs#s_TX$*QDS2;@0 zqSAs>7kZrdK!v`DmeRZLtlCR7eoJ1n<=M&tb#1ctaC|N)S?sJ%vM^mq=yL^cq~mW; zo&K0K9@@ik{`d3R^~~2a&F3Y6CWh(WS@ua|gN7SF7iI4+79@5Bd+3^;ZgT}2Wt~P? zgOm;kz-N;+tm=ZcdI&vizVR#~rk!?;!Q>s0rA8qSK$m`SvVW??P^`?3+zMYyH3NQJo+bPB%|eb7iuR*e|cZ8T0qoIGBk`u4>S9Idf1 zRdRgxl~UIj@=zj|9CH#*TliRHYl@IfO;*&b@KJ(v#DgpS7NyN#fj%!< zsUGd_L3gXc%V=!ZMejF_u6~|d>~-@u>UUjx&G(dIhv6~wv2|xQ;`n2=klt*F>?e&1 zpr4Gn|0t8h*j}l$T^H5CzqQ_r!|Vk_8|@!bU%R1Tq##mpSh!TtRzyB5X>m2q!K17= zP&p9?Vf;!D44yiMpBx%TV@^B9o@`;J-)+R6dgGyX z)?4VXPe57?;B9q{pwM?66e0KW`&_s;c(Tt9;{ydrBtnP8s}V|wz38$5E`Sn~b?VCi zBT0KtVO0*vHukg3p%*3R2W>WDqPxF#6dMrc5D3%B*i$-*!cLpnzeeC6%e=DQEZxtX3U8(h-*rXsm zjO*N!JE{V+KER+m4Kf3!%f}0TUj;3RKQ*O-EQcX$V@|G7qekQL_3@f8>EwOA)~f?! z2Pu!s`l!f@sa$`EOIaG5g}5;b!EBv^BI+OrcgvUb=o_G-Qa4g%yzKHRJ9zEg3a!JR z=wU45JN~zVjgncKw5!*J7c8^~YkPCo*AvA}ddf@J;3q~sVt<$`}aF{o+b=Ts(a zg!fiVhzA8Bx1w)e{gCzJ3@Cdd%))u_6JG0-_4`c;-{@U`@0%w>wT`tt9w{*pjCsI_ zIid^Q(m%VnEAm?PEf-u|=9JDt#|sf3qg7a8Pr_AUa(*`Ep;mw)^_4cV&{R_M3U{{dI|qp?o!nR#Vu>3uVpu zv^F_IyW4~Qk>ba-eIGRf>}_8q(3ANu{%Kl?uVNo|2&>kYr09z#c*_w`gW7#sH_}5< z^X={YDIHm_D*90g9{oev^UV=8GRxm_v}hv;(e_M@a+$v^cUN(0nc`wq9JS9uMwT`b zK05x=>9raydDsa&LtD$BMZui5g&{m&%^JhTJ?Wigy!*k`m3!r?%y)W1aw3_<^!V(@ zJ6*n6Lym(8xKC+JraQ{`Y)~=;&8K4R#q`@^tYiPSvF(%gxD}*KU}?~+I>y2p+_TFC zxCjC4Wd4jpq}w3ainC3rvcAY&;17k3_0I#LMZ5L!&LVEk;JDLNX7M7|T;8)ttm2|J zL|=JVTFNb**o{BxVt2G;O&{v)sOc8W3T-92uRu#kJ)1^qiUUFl+Z0`lt5dgZmvU3p z{0FCRQ2YP|<@wqHj?mR^r_8SGAiJI5E`nPWRX6{ktB?5ICm}G`=iM6S!ccM>VfcNV5;=_8hovFcaK5%w>}MLfVR;g%avkj08I{3 z5>^9M5o@W8bVC>F90?C?T>IvrEC&l7>Bu-g>TP7{X}i6rU6P@Sec>bjoauy+k#?qr zbjYP`Gp=ioM%v#xy7DC25Lh>uhwxOTy?DO6vi_=I%IWqlqkTx+u7Ik&n`&CMX+Cef zOx@f*pH61EG_8Wc6vW%IH_~=UUINcozad_ke`6VR_Ne<05sq2P`F%X}TXF-gtG_!? z#zp!y#s#Wo%9}NDVc`4JL|kRL4JvCliq3PiKor)!bt>JV+y>-&Algh2iWJiP(OUZ3 z_cUGYVRPP;&&;O;M6t2U!}jO@BR_Um;Te4KcbT9e|G|wqpkDhJUO#tvDnWeiPP!_c z)lq);Wx8Haw%sq$1v>$eJI~>+4Xoq`A@bh%i?dx$?sQpunT2?TZ4E zrge{|Nb`$>M- zVIQ7nu}{PKh=y-;4%%hU@y6-qPmLe7eQnio_BpfkK@GPhtt*iGo7XdTb#WEKeM9#3 zAKA%M<&S%X(_CDjit+Ow|78#wyAMYy(tJKXC<_nu6ou)gp)~5&?w)Qu=$hwZdVn)fvFBSUKe9$EYah}#bDJWF|Dkp+djZKem2#)!_vb2E?t4Ah z-Y`%|a?Vln>}VXyu@42JmM^=y@FuREsqwthJX&pccwz0={ihGlBK#jHwOS0^OBEnG`s5s=LH(qq=lSi*R`kb=kg-^2Hhgc$Chuz(C$Aun1KODi+Cl|qBfP?oAtb_z-w44g!7UHEx2ERJp#LgCNM?g8c3)Bz2x33fHJVMC`NmI&)J2K0yU>W?0J+wvr{$W4;tw#j9aPrWQ{^>l;u_6XNQCqv5 z5-Ff&2>I`wpow%T{mW4y+H^^K?4Z%3kQfp5Tzti3N^ig37=x`Y*XM+n8gBsoSyq|M z1nIuf3e6im0>d?0{g94?J@bU5W!QLDH-xUKTc`YA;s)W5G$5xJyJjhN0+bkrFy-S5 z!rElQgo^??L2^{cifV%&3f-VJ+ItO*cAF9;S;r2wr@vK0kHDU zDVhEI5od@Abx+?bFBG>bHH|6L{+FLSb_Ti4yzhd^}PyES&gysqxr zI!xAycDabAJyx5LVMQKjcMYkl59PErJ6KU65<5WS4!re0=55rFu(!}o>&VwJ`N=_S z`t3o9AGYnFY~xibZ2yh%4vFJv9T}lhk5WTo zbem`}aYze&r+hq3kG{=QvpY1~Q-sGI$+hbCn3cAb-@W*J8UBgzv-Zw!JGT?ZF~ zt>ubvlBjmxXVJ0*RXW65 zVLVr^8#RL|G(q@@DwujzM@8@LG$Sk6JT;Uidduw|g~v+oe%Ig&azfxHw}gFKl4vIQ zw$wFB+FYDYpr_ZBayZgOjGa{+BoAym%HVLEuhn689bw9E-4K>rbz8~F&&pZ949gcP zluN_@cj(RkL^SZZ&>OFb6RWv-i-Xk)$HUvpu)v&W}k%h+G#~J$mOM7Mk^tgi(d__dqs@Uvd-FfpmTh%++ZkC~jkaK+i}n^-cIk*U7r^O+09?nrpuP2D zr31e8FTqkqNyuxQc-NaAV75fJ@7h_wC_X15ufsxHg}9|Z#!S;a zBk+@#v6{!J^&%Z}18=gWwMS$fU9h0i(_SEQv6CuBx~%s~BU|09AGm|V)|rRL_~RU} z{qlzbqXa0=1*c*!xI2XH0ubAE9BjFL+aL-ql@wB?F7Q z+|6^W+BrRLC$z(zm7oR+@;p$~^?@as&P_jZ#Xtmr92F$#eybAMu71&?{+0B146k@| zW#8Q>c!ggi5BY6d7-n^dz*~o7u9P9A7x5PD|XnU}ecEaatMiO$7AwRn?@IQZTO{(C97Nsi=+Y+_f{!%AK6MX>0 z9qR$JgSc>)6&}5^|17Zrx+R20oG;Hz+5rX zVrru6kH+Ga&tob76GFWkp2CKZ?yn37d{UNrE>H6&)Y7{gLCuF~<-(M6)kOCrntiZO zeYwttGu(jxX&4`*O-F%-&x7!c;JkC~$y#E7b8$7-{Qzt>fc1=|6*}+YIad~fh^iiD2 z=k4Jo3FbQ+)kh$^GDPPRu@dFdwWRC`V+2^q(~`S*|bA8mV_X!il1Cs z(75|GU-&WjI6P_>DfrK}I8LDJ6gncyB9F#S*H$ZeDax{0=PsqiYAKHVFE-dCA!ojF zr!m0|&=&3l&1GP-aQkuNpKGOx-nU58D_@+NIVh`&>8$rbfVKF*ha#VJi!ssW?73mD zbUPr4`eM@t(FQaYFKpO1J6mNU`GICj8mp0m+EFq;(vt}#nG*Mk-f-c?L#bq0C)c)_ z2fB>g_S&*q_5Qmqg3dKhWG;kZZDo{_gWgsB7(sce{24<(ljES@v`8utDVvW!D z|Lw`Di%j71tnGdhYcdShO5@_-Q3xojxhz$}^1tp320o3JK%ilkr!>b|GS57*=B!Zn z=+|I+Y$v-jJ4pdW$Ght{P9!`=x*nq8Qx#|fG8BMUE)8;&ZTx$crG8<(x z1veXm9c(y&WFGBp;3}Gjf6xQ(Gfq*M$!~wA$RRP$;PLJyc80Mh(#rA2840O)()c&K zXvoPr*j5bmpl<^CpZTWK<**R4%4hO!C)-2t_T4tFpfw5M!QY%P1zZ-!Qm3^)F{LGA z*qqoPbxAOIQ4joZbbrVWaGH}D<(`BX-*gh6rCmpUSv9esWWag?L3 z#eyXZg9aedRxyP0k5#2TKy4ubfO7Hk2dzkI&m!^vKJcWMF*$?$J0!555y@(1!~%L27#7K%EseTj2GZto&7rl z!QIxUIyrd~N_cI6G%tYdIk4|7D&=L{(XcB=$71pEF<>6JbpW;t+p8OGUT7=n1m_`g zS7NbjJ0i4&Naq|RL!vxgVXXnM4S$x`k}vHv$mQcz>Wh41r1(TOKugiD-u)53~H>(EoIz(!Xk5d_8*1K?1mQysz+GiJLCQfDg33Z+ zCFUm%lf|znPP!c^ofn${7l0wzGA|)}w4LA*vN}&MnlC3vj zHOZyu{HJNw`&l&l1l!q`w>wT+ zOv&^$EFWVR|2v)sFRDRI>x9{X!8bjGVkr}Olj+0O5utM{H`CkEf2u$^-`sn*7uVtHB-zHty(=; z(#VFp2O{lv`Ya3|Jvvq_O_sT^q$5*DS#hW~an&qXqRTW?cUTkey}WSe57^}Zeig|s zQrhle&S^6Dj0$Dw;xx?-q*Lfc-)W1_P?+^gu-Fsa+P2wlsUBV=yX}P>s)QvGvfOT} zoismzU}A6n!m+N$sWQdRh$+?EP_XWwqn03ppdaeFC*ANt?s<^QY`!pjT^z2%;@ zN=X(*SNb`Z&YlOysO2p~UU*|v<*Hk zOG~dil+&U`!-$2}S7`cn0=%aiXxp}XQy8{4+O%ANKTAnLn5SI21x9qNw?Xh7D?$t;6@5nO*qvr4fI^eV4L5(Er6$X~|yq~p0`iSk(2b^>FZIi?G zWYmpC*a&{-j-;2-TlCk0B`E~{pDrY=IiR{OX|XGCb4Qaq_8!}rY7W2K1&)yV{gZAJ8(-u@^GPbp%_c_u%kliyB$BI16~$O$%zz> z9X5-tR^QX4@8@VB%)>_@4bUT?a`TYt%24c&vhKf$sOc=f6mX6sJDm-_8_9gbEjZMA z;G40B^)Nmd+i4LGN*RH7ylzmRJW@8ii=bgww80DCH;duW+TO8H9=JJKh#v2?TJo~& zbxI{jvBLIu^^m*DI> zT4O=OPu)QG!=`xfIj>+|De_r^z~o!xNrQ-ISMk434*R`&Cp>=l{#&-k!Js zV(vWQlSqVOk=^uC0mpX&QLnoASG;pc3e3qgjO|PR>q`m^y<#g%YSy~wLTFT^a1|Px z{R*0Ui|Ov!cb->qhJ9HwE(of&FfZ5zX&|}3OcU9iVNHTWDLdtBste-eg*_MO{mgqe zJIM~;Mf;i4qWk~|62PwymH5ji5axcJYqHU+LJxaBqz8Ph1;xDw-w8c`M&RG7u$Mxp zm$!Ts1RGvTtf=aohcfW1DuvKR?cw2WroOl^%2*2+rbe_le#r`b$xt`>Pbu*0e-K+S ztM;;LS4W)7>&isY%~$AzuOfpityjt8{3ySK0?9R^xb20B-vj>vFF?=xcH9o;6P%nB z&|d~#l)RaiZ{`KXJ+iuq5)ChP(!M4(ohgY#mCbyG<_O`7zqx3qKnEwt7zTD?(8us>e=xhE`abKmO6QUjL z-!s4miY*-*|C;pjy8(Eii$an@rbH(&3Xb7p2uK2zbsFbpE$eQn8>612xJjMduq2PNHm0)>)>_`k|o@U7S! zS&7i2sYXKYZA&&iTEQ&HsOdv>CN{O7>M}+j7v2h#ilO!-YTcyfLmk&XiHVZG?0s(O4Z5>^gWS6%`lIi-h#vG-5%ge* z$6H7rT9GY#FEDW9F)$2rV_Ev2cKH2nc%uOiOA)84Rl(8y*+D zR8pk2bPTG?35)+JIj~aD><^96g=Vi#tL1IDp~Tlh#nuSo7@P0DPac8D-|VDQAzq83 z$y+*KU+_o*`e9HTO2E-Q=uB;YP3n30P2spdTu9far_EvWh0r_wlF@q-b0ubP^q`ks zL7SLbw>Q64sfu$9phaI6O5LG;_unS}9G4j66Jzt?-ygQ0b#F0qhTepBhoTK{5 zr2oJ5h>*O&=b#AqB(U&@&36uOQNM%(g)p7M8%Xtta$} zA^Nfw$|w#QJ|F&Vack}`Td2_HzU2i)eOfY8^LH+p(MCkhe!@5`l8X?n|W z{NZ_;tmnRP^h5f)uvTQwxZ^*V0xrO%Za<|-%Dj3BIcf`1s9+B2JC_0OAa(a*kz%}i zD@`d3r_sCQi*~x&<-H4e+-3sT>nWAh|6!OKLQT^0iEHxc_t00c=au8yy+tYxlqmTg zlZFal>3|}#=2(`g8l&zp`uF!~>eH_do?aek!3t{MQW?K6n#$%=*w;ce$l#G+#uY=C z=^Rt{wlA$sY15!C1H}*9<%!EKt>)Kv5lL#Y-yS>J%ZF9O-CMh{ld7%|yLV>NS!y+s z>AruxOLy}|V@i;ZyI`lZ-M)V_TthLOQU7?#Ik$cSPdl>AxR{*F6a<};BVQK$j_ z?9y2`o$Q0LV z`h@jQaxCi4Rj>8m*8nG!1I$;mj=?l@a&>%T=!&G@k0@FCezB3w9t+HdGG!}^hM{}B zht8F^dDlq%L=}eomH1h&hGDaRMJ#GAhu5WC{o;P|{ir`MxY1rVW%$0gq@`=!$FysT z6Luhg{3|o+Y4nF+jeT2&nwBbpe|(hm`E5yR>l>c2nwC$*{z?Jb%ntr&dBTVeC;-hy z$$j@6EYUiLTD!_0uR65+{ezPGIq31`f82Cdae0%1^`^Zs$S*1O_g2ksq^RMfBaNIz zJ&Yy2qSO^X$Bx=h4H<|heaO}vqnp$|hyB_kDonuWdZaMXlj}xm59jRl5!=>!dg}mj zOOh+1yIleE5Aw(y0V@*4J_}usxQ}F^YqmR;>{;8s)$GU z0{G#F-l809S{&6qoWBdEB1zfc*U(4KUo*T>cbhOE7`MA(KRc6WK4-_0bu~CVoj+r$ zayN-?F*??f#kj7bu|DTsNzAUV*HV0-{p;!8-kW&w!Fr*uUS+>$Zo{X*BNDu1(X*CZ zITotTF}f?CT6chzf#YozXN)SBkV!lS$!>B>LX5BMz&qxm$?KZPX|0Ho2;Hzdd@EbJ zM1pE7Z1a$${Dsjlh?J zQl62Q(6rwJn=YDR^l&F8zrY1{;)y9~v=vuQ#szOuz+adM6Ey83vz)9jCnO@7_nt-7 z2*|KV?9&PSlK0eXi%!o{RinBrZcC@>3q38r4ke+@_Xy6 zvcm^m+bS}avcW0?CI_EaLEFk9nLfN$%q7@&M`4&u!<{%=nvAD_@_Gq!>LVYBfVob` z4E6mt*zV*vOQu^LK`Bj=>|`*nYDhhesVOQZ7wE1DQn(`BGC>HO6XIk_m1ed!l6-#p zU%aE@Xai?h&hZ-7Qg5jkubV$Q(1YSB_#uV4RtGa2!zY$_+MsumrgzacziI$CDw#WT zAl3=xj@=qG9UBxPwsui>mpg%j?AUi(61Hi(LnhCsci`Jo4Cd}Vr7b?zi7g3xgA)RW z@LwBknI*@Ms|v`f^*G<&^{kYePI-)rp0qS+x~K}2sAdA&)bPSi=B!7jp1wM7Q7*0_ zK{ej>*v3F9_sKYa@8J6kGeap|%8c{`&XW0Ji#zlz^=UyjO6(g#~2zht@8J{PD-1Ai8iMAfQJ&o{EG z4o~v&1T7*hN;>o2S*qBcx{NbzYK3FknoVUF6uIlFXF)|jl{V71LNzm~{hh1+n?pgwpt3fusFKhe{ zu6#}aS#1iIEBuExcmK5p%INE?H6h!s=$d(Z7xn`~EKb+1-0}3CkH!#J|CRkE;&;7V(>;$ll$}QRIiDp1j2`SJ&*!|4{y=@S0rb zn3pS#?FyB8@2{p32*=$x_1)!K)2pYQZ&T)9eb4H^?7+#EFO>NCFXSMB4%PiwZ#h)S zD(_D7pU+wvtLq30xs$S0=7I)sUsHN?-pUlg!7kXZA_0@(wECKxj>kNUQX|#9*SGd< zoZcpH+i>x_e;YzPk2M9d&mbW=7HU5GB6iCtfY_Z(tR;vnBi$ruOAw>A-8wo%N^2KY z+rCalJ|It$TH-NcBn-QYZ{XbBVwP$8$A8O9`mg;F>g~6rkjVDaM+96LkUHTS!#poA zlk8VyDs`1I@n4Yz%eT-|gsl$I59FH5sUxRnHE_8xd%C1xzHF6Yh?uUz31fgs7e1EiYW zWOdZ83ClyIn(nTUFT=b#^(ZZrPoj=AeqYaMv${?Z ztf*~wRE0wPHjsq`h~t~7Bv7m-s|*8wC~PhIc<6pi_x9R025*K z^fnHeNKG*Ux*1Z-HmPU*?GNRSl!q!oC{m9m3$pqyX-RexN+E@RWd0cE>fNXPVo-Gv z3>%oEVLUiLwl%BohFJukC=-?+b|s5xC~_b0!3h8v9nY%1L}k*^*yFJF{HAz)(Jj7> zWYbTMV4MrXs>Ad{jkR5xwb-qG`@I~80`6=!LzdCsKGA=EQ6- zjH(FIpZJNz+Iu2>_vHBU>KTe6`HJ6H_;SpT^CT1*G2ohaq)dQUFf`T93L)lSRx^vQv7RKC7}4?(LEwp)VQ4eM%HkwaLXCx`hH|X6XAG=*CP)c6SIAWW83i^o5fax)SFQjio zZyBztf`5KA68-@6^c(Y*^duk!`I>=_1h6uvfLe0sTqbyM ziR9umZ?Frji~u(D@p+NO2JQ|~Z=}7*STSr&&?5&qONJf^{wowh1M7<6H9q--?!4%q zIrz8+4Sg72sbmN41U1dqIC$3M6Rr*akWq3}%6i!HoEZfVJihBY$b9?%r#< zo-uyME-?Hqfb9)|JbN}U@HALA*qO5BW4q~h0pVL@4+s{UZPS@fb3OvweM)7_R@vhj zjK*)Zxe1Anv;166eRP_OHB(FjFSmJ}IBH++2fE)Tno;<2B7q@!n&G*4A_r+tnQIo| z^U3MEk@qVXNqp}0Tgax~BjA^-A(%A51g(^TdY27pb6A(%DT5PX~h&aN8BW3+et3f^gr`7)WO@XdB}56%WvP`Ep}6 zMJkVq1djRSJ!&dGtj4MAdt4<-44K%3+ z_OXA#LyAq&37+M*7GLfOxtl-H)uqv4016BsIk}jHTxzZk$sv+Ab*Ia~)29-xZP(5FIxX5MSa`$rk9vyOqZ@<-%sD%k*@SoIjN(a+c|jKhT43(G#G( zF9pS|T1nEbI_`-K<9oq07)Y-g%7|lhSs#x|r@7;D4;>A>mw4}~WY)&tKd@&U*b z0NModyT3W_eOAbfkeppV+Nhfh9*5KQuQIY_AiFm0ecO%#U=03Mo!ot>DFdUc2x+ro zFUwJYI~VGc|K^N87<_UXY{hp)SZX1<8oY~UOss*p{YZ}la3b=}AM`T6Q8w>SW3WWW z0o?<9NOy=qI>z8zP^B?W+@8x~F5Yux==IQ)wFSdQSIA6$3V~dd7$$q;H5p2_zsT6w z;p;tkP0aAUeB*pUvp}kX6mU_%}!H0s}};^l|F7 znOLfc`H#*9M%5MC9DDuZcaCSP0F3}ZGeV@3UQ6xgNJYQ@5UkHBT(M7E`y_*VXq9V| zcD+%05WmTH2>Osr0)Ee9WEkeA5vQ@PC-Kbi)I5gyI^@2`@u2P8*Dosm@i zY-vM~L1bCm(3LmNP>#ghexz<-~B zpKw6Qm<5ylf(QB!#7)aRJ;&*z_ee^N`+}<7f>Zq^K&R1n<9h;5^9Rk{Nt=+6NN2&E z_0AkNz$EDX#)YtuVZcVfr$JXnhJGEL(SPBgv#}U}*ZI(yvfgUm4IKRoS$$Z404toM zDAA&+I8we9l6rq%Xk#S4uaC+!V?B~dNGUntu~zsmks+iVH@sgkU*>ua_#!ScLX#Mw z!If=RUHD}lwfUoHW#rF7h!~+kb;j>Gd%OG?r6 zpoZB3G(+dAF~#qA`mimbHHd=jH~VzW%g>B5s?rcDs?!n=JDY8ValbqFk#0zTu;M}C zi}>=nnBY>JQ0*S(CzOiW{)tpJ@ZPcNF=5VCBKzo}F$En{{1h<1Ve8}{cyYXME|xH* zcNYBTMj%Zy(Yuf42L>4{GqiVwqEDXTyR=Oy#ghw^Bl2Wv3kjS$%U~A2o)IUWdHCbfJD>D@A?-<@C6%DID?RpsrZTN-pS^_#ki&l7jBsJ0 z2+g~6l1*Xyi3@z^c?UnEIl)#Bj^)~p3cw@Ry;=n$(rGb*e|7T~5(IS90)8WFj5crakl%Vz<7TRYHAscznKE%-tMF>w8HL%_gq{4zB}(l);L9 zS&e5_Vh!Fm3xVaeiLJ!1&zAqC3J1d^yH@|RqX~QL{o#|O3grsPt1sO`b8Sj^rje8D zA{A{}B{DyLpMb#33V8!DxZ_1Z<~33l8=D*7G$xsr(`qhFhQ)Pm4VD{JQ?TciEDtkQ zjm!Z;7w;hZQ0jNFqInvR{dXvK_L}+4xR>3DAAfW{6_(z&*xGQ3J{+G>AJtCRTlvqq zqPPFF_h^Y5&js%9_`S&kMmX$u&IP1W4ld0yGVLGjz^<~h1ds2ff@QdQ1#q(jKGgG3 zkvYR4olH&7Rjn&^x*MCr5;q)$XLzoW#N%>%H9sl~ErUF6MO{Z-0M6t-9|}+4|SxD7e>VemwZ^g2#p41K4M%}exl;GaO4M{>EAk0*p#p`* zh9A<#Y|N81l#8t&d@I7v$50!c93+iLkr{nP_%n`9YSUUl_KlKeOWg0zlHVq$Ucp9p z{VXowiRg{KId5H?5sj7fW>0OuEfxIP#hJL(6G#JudLof5pDZxN5P`cFl`f2JKS>hg70hjMmCNDGHOz9 zCExl@y5zQGF6?r1eR-<Z%Xq<<{Xqjw6)bs3{5W&8znF-vLLKh3WZsI=c{NG zilPfNmpN%uTCfUTVVOD~nkEbi0F`|%?R!IR<06u*Hizei*PgH4zCG;N!Lv!$_j+XI zpLyU<_pq!dsvsVDF#OJK>(+qZxNk2j^oH1WX03BBR^;;uJTof1vaY5V#)6}kJQ;`g z8leJkd10gHX7#4w!Jh&qP^z9(^qv5AIVS0#0*PnM8Csj6ex*$8j=s&%WG7DAuo_2rQS zrBVP_(<8EvNiL{mzL(>deWnxZ@+Oc&q8c`R3Xx8^?5@wHl8NrDt70|buRK>Y;A?tT5-YtNn!>t;sVVFl{${-kr zf!~F#AazE)TOw23Bwjh7($~kNv#~OTF@ur;Gov!+@5#l#n${^vcYD__Rmk~Et-_2s zSnXV&T;+PGU;UM%WR_lNiJgI;nE|V?z7?MpVd-Uhp=of4;cTnX)H%gKe6BdFZt4DEU8W_!2;bRUmYs=D;fa8kAbI-A-%fMIG z49*PomANP6%F(=4P6-=Ddk^(j)f}#UpbgKEib99I+t}FQ@1J;PWXKAJFUhQc<)k*v+|LuPbff47zSfMd;I&>aY!y9 zBRFvHxkT4K@OV&xvaMP;CRcTf*>piK=x}K+=KC5vu71R{B%{TqXV8t;%EHP3z?gNM zOby;%yW(2O6VR}5_MVW-wO_s3>`%&XDj2kLese^6s-6pzVhcUUQJHKrP4oBHpo`@V z`w@pW89AEd2s(95+TtI8!==!PfAy0()J8}k-?5=8jdNxw66X5F15j7~I4-;IG_luL zQ*w1=QsXja>qv!;Osr)weL7-MN{Z8p6K}e8aQ`z3^u`F@)O68fls>Xv_BzR&d!uX} z=xi`^?WBCy2~@S%t-yf=NU(a7j0pXcX+=&!EE3i+ZTK$n&I^#umalqBC0<=SdC3(z zBqQuEL|~K(=lZQEBWB~V=WbCCd6S>K*vSuf)m_@ds|d#x7=ctSCQp152@v zKG@hmo>S>1ciCG(oeB~2ymXH26^sxwf#Idg1PdG5^KVOCtN6M8$odDW_`hq-I zktE6D^!27j>%6-cdD6{Z(8P;hfB9mQl0|DWRZ#DC9jt#yo+Lj@%I1c4;|{M!GThQw zJOcGl#lmc&k2xx!C_RwfCMo_=l`C8mi0$|}D)2kOrTD1_&?Mx#)v67mUGAJ_ zq|zt9t4|rm7Iiw@MdRGcL%f0z;~g^gk?1F`R`|=D8aDk9lXogc zB1}(Nns0DePWS#8sNjW)GTx)>xo0@}b{m;Eb&>}%V zW^V{GKytxnx7ycZ3wT4!UpR8caN+#2JFG@&-lP5cvJDB)-*CAG$C>|Y2eAmkvg@^i z!i?E=ggMDX!IN8IK@!M8vEd2_A~Oa!>mWnL?I|s5;jSogC$w-POk{?~)l91en?8Z( zu5Owze$)(8MoP$QjC*b!sLQk!-euc_q8poLZA^#OpZsUj^VEI)k@PWiayq|0n7Iv; z)^FnHjB(AZYK{bDTQbO4?qCi0#6e_7a|CX?1YxWBf&1AO1p+}3WkRIGjwV%Usu1@$ z-(_+r8nwvYv%9KC{q8Cy?8gm+p#v&dS{xy{Qp$VOqjcg>cMMQ{mhXUjytq5(j#s*9 z9%z1r=h&_{FFVc!DZByI+s${{$tB3tatSoa6Yhq~Hb^@iw*7E$-HFiYC7|5cJWBSl zH$euE?WneuIV4=c*P0&LyP-fVko((IhM8>)JXk3aTnLC-7yR5JA6@?y$H?WC5pZbc z0bvX%<}|Wu69Y4XE$NKcCeP`s+qMW(?meZ@uR7e~?mu^M~>fE?pu1C%l!6Vk@GRI5B=?Be0SLuftTxGagR z0m*Y&zJ!ImR`pi_CA}y? zYI9Lm$I-gdwQB-DhFh=&a&P9{eVLEVe@mivTCf#Z$Q^)lEKrlfLsz3(d-<3rxU8jE zTkQH30<0lm6b=Io1KT_wlIS>Z)xaQfeFG-fjVsiL5oT`Ws#DLmD27v^>bEH98G+|t z8HXmtHs&AV8H{ z@pp*D8Ak67srRw|7R;IDY9IG&!XjE-f@~Qe!SgLz=Tk^H0>4_{dT6)6{T)y6Uuik} z+_RJUut{jEah$WQ_TO0UH{h_|9KZGwf1A^X8d%GTgc3PmQ$SE0mfhrrpvcF4Osk!N zNAhD?xu>T@PwwDOrKm}It6tydDmKN(!~knjR8Fb#sP^8as+!aD)@`@@J>F?@iHU7` z4yUqGTvdAj$Pxl!j-v-t(8hgu7%kd!&R%Yd{3({K5Cc%GwjKEp5*+$LUYpW;=!1>v z6Mz#J@dLgmjkPB zy$>ymG}!UOh7LmKf@>sS67L0f`uIsPY^4b8ZZ7p4_&WJ@b`R;zP_LkIXzPh;K)?T{ zjbFz|T*qukJW&hB{p3>B`)Y{Xe(jxJ@$N!j9Q9)d{!gM1_TxU}px&B{EBD+%c)9&KmD)PSh_A zx!z9+h!42sICmwAI>B^Qac@Wtf>YJv=Iv93VGV}}SlJrrNw|NY+%3TuH^<{}i*Flo zk)Ome_;t3vwEi7>AD&&($~% zi|KM>cwW8BsIBY-^#Cdd{f8q`-Xb$+x20W4Yx-X!;vOc9}OqCr?zzo zkFobZcR6%yIUuOQM7Arc_5pkw_03b-4>5G+iw(>_Qk@}>9{j6MSGyEI7_hS%ushoH z&9dF(s7jan8ZXHJ{6w3tP~&Go;rfk>_gL_w*OEHB-8EkTZqnFSIu8Ea z;+d%g@!-)@&?Grfw)?K_a`IdHx|sczj7T*`rI4NXkZt_rL;k)%Y{+dvGpvevho}}; z8HkXAn0{d0(AyisPEe0X9sm3gtDl*2XE$wx+P!a$mQb#9Bj^%F$?!cpX1LDJ-ycz} z32H8go&6!Kx}Eek!`q4BA}D8{b?rpKx~SiVO*IMn)m!CNg^E?u?dxdtYS z2+E&hycW&6E(dVL=8fdqCo3o4iZzslf;;;;i4v{e$; z&m<^tQn}-cJ3Iyp)>7BN|1|?B9s#)>-Mm`kXu!rg&%q|sw)xH*CkWPQ_TfKymaOBbpQuzw)dOI zH;g!PCFa-?X<8?=srHojHp`~jySDc!*Cj=Ea|qOxN(XEKo3?)V!Xfjw z1Ee7UHpdz0oaL{D>)zmaYvTALzPD)f7{4m-`oss)|Kq+}n#-NFsE)GP?`G#8!yTUzNT0l_d3=gu90`9S{vv_ zdl}$NeRk!JM}wzoUsLBB5hbpNlArB#6UXQLu=)A0dY;|KcNs^d;fL8K#LSc|LW%w) zCzU7gg;QmSpft3UYI0vAtBOpitJ1aWeU_sZ|(%4*8&ZHXa@|`nxSX$KJnjj9}-OIM0z(qV7oY3Ho-x&lD zT@|4jSyO3Brq9qotWQq-;G^Rs{{J9846M52pT%=sj80OQjhs$8bZhCaigYWt6W{Wx zca(3lj&vSFA zvm`wX5}*K!IpvX!KZjIk9cmC$6pLs@h8vFltAlGZOCK}2ZLGA4%^$||L zkB?1a?0XAFDvw@D3hv(+70ebjDjU=l11RLpRQWV{c36F~e@h&NWS>r3sP~Dl3ZA&6 zz_0By)~Mm3fhtSr+rCe4KgRw?ae+&8ck@v0PsfQbDxwEaP=$ZkV)o&s={e(1F*p;62eMxC;ap1|LyjLeiQTYU8VC>uT1`wbfn zcDm=puts>(xN@uV*jwiGi?CLAI>YZq8@b!_$-SJ&2dm0*$$n|fLt~VRN5{2Nre@Es zD2>+cG(~nhx?J=pGBXvzhvjtrf7$yAp5{g2;npLML1@p_#5v?yo^Xo~J?Yo`>M%Gb zf_W){f-ju~`QhQW!-{iLjV8;Xru2wdEQD^8NJ%4>>a8JmgSnom?_>3A3f17 zBStw&zi7IyE1kagyp*hNHtL;oUEixN5PU`x7OT2{swR+r&wjRk?m1(&&A?|36}WfQ zM_&}Q_eS|%eL^HMYO&AjEsOcL1*e#HYlZ%1BsiH__xGSQQ;_o1NaYMKH{5ZVGlnATk5YN8#>gZ)D$hp5OLc3r(E(3!wkQnPW(BpXFmcmi}&Oy zwEWEaQ7!P){1s(ArQ*wy*0Zd~JhD6?RY>p+Bwxh!`&D@&W{`UPx!D8_FZ3bpGk#XL zcx6$it?`%C>FW%|#hoW`{eXl9n%qUPJf+LG=W}|W4c|cZ!W{My;kEg#fXKWpU^fVz zcWSRu7=+69U>G;C|Jo6~YMfF6B1<%^8bo~f1g!VImMm$V3baT4hoNvw;$cn7Yh5S! zlv$wrJ_Kj6vf{)0wnbUgY}C^F)nO9AD(BX!tlxc_38YNitI}4~JoDwuJLHjUBpodj zG>myithMH%#4|NjTuo<7e%eODFZ#PGeqi?I9~@*Je0|b$2zxt=G>J4T8MnJ}3QChz z%M?qVX}t2|&~d{JiH~^Re^IJG^>i#F5rX5`8>2%-DTqiU4uL zRn&L6ST1zB*zlppkfY}lNQ#%JymEIw*@Y|CoNR}97g}3WXO!~@j@On;y?40P7Lqbh z;jYPfM24b3GYGucnb{JlXe#&wVKD9C&j zH=3X}T4G6<(u!8QD7(zTanmlW=}&OL(UqM;df`~#{S>esGJGJs@@smBaPfknLjLz( zD-w~DtY)TT=^HK^G}fS=A413`1H-hl`@u?|`Gne+k*C762H%io>U(>ll)!49O4aks z?&deh_0Z!;p5jzt)}|MHZuij!o$Tb@Qsm9Agx~y)a{kYSdreN5h8Fo+Jgl(V=&bre zKkc4~C$j-1b%!wlS$Ui_mxz2;&9trF=)My)<5uWbOlh!Tc}oo2b=E zHjTs^rE46!d-Zv8V%fgfmRlKK^wq_$M?K4^T|I_EdV6P(4M@RDMxMhgQbJrMxb#TX z-M*~Wp{SH|A(9mobfEoklfrC>Scjs#`T)k`$P>3IPsE)x<4A^#d62{_UuT^1wi>LTrs^Ef}t+(08q4SFXsS%I`uVXF+gUlCMCS2 z?w>%=ar4~}Kaq`+ZaiAj-MP^=dJdXlzM!uqGi;48h7`PQ2!~})*gV_I3+s>@p8HQ}-a8|KdjcBMePE!ns1k5J_upHBL1_SaPvVQ7WiV?{h$4P3`!^5JFmlSA z1K{RCB4XIg(|gsB(gbc(UJL7Lgz=I5%Aqs*y}PUm&F5uP5URwvl5ExJBPC%HxQT$- zUv45RIoP=}Hvddy?wRpl-v^8%ThQH@OLL*W5d6>fS9T2T zikYkKoWh|N&QJkM-U-j76a>Pt4BtZd0R3Wk;U1hN8mpGxbCs`qizwUAQpu;8>X~8i1;w51VbxBy7V84qs75; z1WB~2ID*k8WyciV2Y_Ly&q#ha^%k0tn+0Qa5K#flQ^-6F;C?CE`#DtgqjGBuQiSYh zxspon+#k&r7)jLdRgsE(W?MG_f=i*3iY=o_;58L_WtPM~0P--DaD_eO!d?mrJw7Am z`2$)%U?<)yF5QDk!mlbkZ9p*_mGiOf;qO5|-zsm@Ci*(SVid-q&&w3B(hoMe&sMPq zwZ|k&yQ{H@D+(nI&-VwFSk2&De6ITd`3k7UUyqa}j41PogcxOFfS7yi9}Tw_@lE7m zeNHpKr^+TTcV2X}}?s&;ACrc|_sDKyz?Du&B%N2N1tkIdz|q(M@**pMDRu@+LE zWptt@2l9?@!H^>>wo0}dLg8E0eQvSzIl{-*lsB2s_p4go%knzdX1-6#NlYrxONHAE zD(eDP)6w+eU=fsL_-ZWNMe*jg@;2Z<5L$VStf+SzJwx^!Eto0Ogy5KdlV&s>ka|sLN1h=^OVE4(SvSzlW1B+Q z4qLt+-`Y>gBILevUm?58uRa&gx^(I5tIBDi6+vqD5~l!9-e_UKRCt+zQaJ1_t7pGK z(1j^@acxo;EvX;L(`=v^bChm$T`Q?TgV$vt4Vws-mm>O*5KB|6Na$?10{A;>6l#+E zRSR-Q-+S}S2XAQZDdbb6-2_G)*noT4vR|Dj$12#S4x5W%-M(Y;S=<`JU7@idZz`lHKISe1nLd#khwqP>>|<$N7XD)rdZ?aZ{lrtZE0 z@%ghakPI{O8uz`rnvB(o3J42}>qfPNmcTg{3h1UhBqZgHG4r;&VmN3-%)^W#4xB{F z$O;`p*0qRt?>F@HxOwtc6yH?ppNm0mFB`yCWe#xsxQ%6uo}U6*EQu83mZvUY?x%^5K zAnn_5c3@KO_cLT0<4Bm=%e)#1A{s^{=vSwvLb$nWpc`-M!^MB1C*E#CAzy>ukt6 zMwEy-*0by&h6P_5bV5;%I$#6?LV*Fxi@j%4mC?RR6zFc~3EoS0lmXUG^OD~d<{Szw zv+f(hTt;~lghtLH>-ezas?COWs$!g=3i^e!6%yyyq%>D`gu)T~KTxw_2*Vv^Dqsg< zWWTtaro=C0x#GofASrXaL++Sz?&i_E@|?=gC{n=DNWxvA?Awik=IpRj8{tY#qQ)|D z-Y#=fo+?|*hu`j?EIH`@pS1O6FB6^nPnpQ%!!hzAG?0YH~ zR$$aO=s1_;+1VLXnk@QI2dYK=H;7;0oYCzTB#g)5qN|vPOFr)`pVm*1Q1K=;cf?=L zV+BHYCXbcG&Yjq$8kFb{O0LQugRLqItSCgcM(SYm292d!&mddaaW*u^B-EdQJE(`% zmP#sTMH*x}1{LHQ{qfgV!JnNKDVI=hm6u@x<|NjI8q{mo?G&wICH`|N&fPPjX!fh>|Tes#WvG zSNL77bl-Dp;*|GqRzf)rvW*l9*+p;77&tk@)^LJ4H&(@C#twx89YXILuks&0vdySP zM<-@%d`AbscyMf@RlJR^#xX^XP}_ zB4PR)%XVvVkv#I%DS45t-^#UrP-RT9&;{`|+w#Iyi@T@K%grLemjf4_&Xx$N(7yy_ zt||8*C40ru#_feID>tG?6=l*8=-a5iNTk%*!L>&D#=UmGhOy6axi#g@iM@h`ez8+f zff4MDk%oEX%&J>z^SNIv6G}Kwh|;-_5?R7TfXPy`?sHZ6OMd)f6?)<$t*BKJu;Pit z9#KS>5A788KZ?%89m=;2!?Vvj)_3g7U}o(5lFFKyv5kG~ODa2Qu~w2YD`QDRNJ5B0 zDMTqPLu9fPl|tK)ilQH-QptS2f8lxG<9MFqzOU;%%^#9gMy4BU`O1&^mbHJ59V1Ef zsbY9vjiKA`8ZvL2X&1^6s+9>BcD0X}cV80DsDG~86ws=_p4hC?E$Zoh3ro^a$SSd` z%OzP$e-lz}&lH>Vbvxd&IT!yMb*BJQPN0PMf1s#^&Qi<>Ub`+I`3RBB%zL=EiZILX zm!!adMoZrHUe1rjhw)Bbbe5nYhM?O`0OJJotjo0?JHBBK9tOs!%v&|YY>=gKWa)2w z(1zhQomFn2BQA!BzM}9{74}38c8l5jIR1mVd?{gCm=N@3LZmdyLc^w!cZt+0LR`pz zY2U!zp8Uf2!Vy6sf>EFNC(}C}Z$}6|k;Sa48@v>;zm^*^*ow)l#qdlpi%)}?q(&~k zac;3i71qqIHAvuJ8r+M=6I#`X$`2zgPDA}i$!X`i520XqG)%hY;&iZ)cxNpsizIEu zI7ICY*mQe_Y`!?jxVb4pC$;$59BwV8645ptoMkZH{+Jv`D2og z@lv%1qz?yj)+0E$C<^UKV+|=Xd`%;rPdm=^8+~wbEAicVJ{tT{p?Z`ycIHaKtPD`6 zChC1^`d3wD)K0m6#F%NEe(%ohul~CkdsJcFB0WZ=4$RGaKsF|GpJbnMTtergGen5P zv}E7MecH8|b=9}&g(V$M!F8>o-a65Ygp!(Mi=KY3+J!uhw3D>9Nqu~3IguTW58rlu z*l}8QHla;_U*Om~jVK#tt@0LP&Ns-+@4a|2riqdItzkpCIZ}}_(a;83dL#aL|yD(g26Ryi`i=y-dwU43-7 zDA;DM0~QTb=FQXu{k0an8nbqXx4DQqw~Bfs1LcTgWrq{sEB$ro*e{kDg!%gyI`{nD@UqDVnFkSDwVI}zdw22q^}loD9^bdG zxBYz72;)z7M%b7AiC@~&25bT9b*R8D0YQ`x(QS&V2Uw;q!nSL$L2>2|?j-U8ayPzr z<%v9b{TWQkS37_gsPP*rdYDv1|GAs<-)M?4TI(=MW0%T{ae(Q~)`XG9pm^!t>z67?!w_+7!EICIh zWc`AmHgx?$jtZSCr(Re@>~c45sG_)A?_E4|NSId#O~X5eE98i0%h+z;0DV~M@pe@ zo6!Q!g#VP*EKPWc@he8GAJU?h5sk>HZFSDFS!*dx?&_yEO&mq*EDT{!zt@=T4v9~+ z*uL{PLslJ=apts`T-Z! zUEnRz9sX7777aFKLbG)i+^29ev(g~g05bOEXKGbH!!Vrj#T0Fh-?M{h%~X;O7m*5AV;p5Ik47L8hK3zR zwrVI=eBu5*%Iv;6hc#G-qpgz3@}fHXQ}l=e*}R>&k>x9nXUXEY6|QPu6mN@&8C!Vw z4;S}sJ9bQfmCYF|B7{98v*u@LTWAwb0ouj|mVL5i39vGnGw6US$<>?*SJw#Tsf0RV zXpm~-fYTSmw1=UOIt0YtS?-Qx&D~@}Ksni$t<(KUL-q?WA{GT-n~d`$SqidBDs(Q4 z_lF0(_9@@+Me=BMM-haNPL^iGQ_DkmlqKuhP*jec)t1V;7LK^NW#{X=p4srOjGYLY zXv@x`!x2VYje#Qo69+qfz0OD6yUdg2gb%7@g>OIq)Qd%zIDb8#ev!LPPTJ}z!BkHV zi7DZDZjPasFpe^mZzoUj^1`XMWzHYJdm*tg=E3+r`3gE*r=mb4WBn>_ za>2FwD8OD0W*i%Ok^DGSfjMV+9=*3$Vt2APkLt1gb)JuwR0@E8L6AUU;vc}Q>+3gbPM4`h@M#B9}Rc#hYy`$9HyNWGKCYsP;kOH}5sNq0|owm+d@*|%dcg~Q@8$IAcT$efgM>a$-6q&jm;Putm!GH(8(G2 zMpaW^$4Y>-@w4Z251I?wU4s+)A0~K<8bx&y5%WV7J}-^)`3rGUWgKrz?~}Wl44yyK zPO}b#$jk{)w@jWoMR;ne{?^b_dxQ+3%h8TB+()!8ILt!g z%%WYU5!O=`qT>7aKmKQt7g3-ohMnYRBHB?ay(by(}3d;j#;V2<#I4D{I=>wGn|N{pne zvL{(8o|m*ByeV3HCq&4ptw(l_CbO@<9y$!BoyqC>FFga}9s^3q{?RC_YgPJa zoD)#<*GcCq_lnKy;%rwT6p~wPN{7xyZaSH=bh#E{^%5VKw-_}1&Fymw=j|x}g!d0= zC%;g*VuPFQMuzq~SYQF$?rEHFDC+~J-l{CO*9S2U#cRF6N^>LdEw0U@!wZZG@mm6Q zJlQ(;DRlY-dsd2I)5UV)-FPXtaPy1&by08nYQ=B-nMj!zPbK0H+ES$R=$h2d9dM12 zh$S^lOWuxivM(*HZq%QMAU{6Q6mT^kuSWAlo6#6YKcB<@-NA*cn;E{OX9yp(Sqgti zW!zmBzs~@!)$NzJ5W)ZW9`uX`f5n1__-eUAj9VaBqX@`H9X%fmdIlmw+M*mFsFow( zXmr}tgP^Oy`}-Br5XH<*4X*7k=^dZ+-0_I0kGnNeyz0pcB0NAnqQC}CMI`?h!3RXN z<4G>ysBXM-6qxoNP+yf+O@+U@d0a+OMzc0zk7B~-IB<@w>fa^1I0v%)lAaQG;(l8B zcd330$VR5@TzhE^LraVakE~fnHDb4;mE;i}XeJ%#hU4y+ZXfbP+JBQyr`tyGlm9%^ zYK&F-Cj`IJz*Z7?k%!q=Yn3mHGWZo9vn(A_n}{fO4rJ}p<-!IY?n4q-qOrp;R(dKQ z{riK+MGeaJhH#`S`5||1)>M&^yWxS*1M^8~FU>O*qtu`h*)PR4w`FJ&RASp~ucc(& z>qYqR5eO)U0A(O&xKhOucwePWe?~A+hx%CaJxCBdV z7UaN_9CQlE)*u|%#yt>=Iuzn)`sSzM-+=-bD{R5b5=~(Vve;mY8xcV`9Cee3hoUAE zK#8(QrLhz5nyh~`=oeokS8X|R=oj`nEu)c~ydaQ(1%v;EsJP>i?tHi`8On7Pp%rp% zeYVK7E=yv6s3;0jHu;JQEAYT&Cn?71v=3Ny2uy$8nk}T$>WW=*vqZ`1Za33ie+3I( z?$J$CzGZb>S5|l8mtj$Dyl=O!XxV=YOmJ`=;kk-5FX&~rehIlu7 zTKPugk2x&$XrOBP-l60ptee?hZYp=Qk>Ojhp-0i*^+=+&bLyH73c&zZDIaOhFp=Sj zBE%Huu^~bR%Ma{Dcy0$hpZ&(FFGJfEkAaW;X*%fsBOpBle3kBx9B2Iw)N+Q!5u06U zx#~6pH9smc@|-kK7Y#}=H2TW7Tx7y2jq$P*blV4RdNNJk%G|2| z+A$1aA}SIcDa=E(BgU+;{xswcUaUrM8nT^vDnQLjyFjz}ObVoCOh<)HN7FvXdMU;s zi*68k__1>$I^f9!vH_eAJ&~Mgdmx_L-* zo*LG-m6RtngP`;CL=e>DM;9bQ6xkW52tL;6k4PFp+W#UiBd*s_g#89#?isMobbYa}W)DafCI03q>M=+UZsD@SF65Ha)%h?%M-zsvunC`fEaTP&+4 z)D`c{&+`3T^E9U|lMhZqjRrHXL=8cQR1$oU#-b)o)z|77}b&@pd_5q1URygVt!OgbDX|hHOUK+4bYa z$E>mQkJ8T;*DNl8XM62`!vn;EbmaHxj82{fJ7sNG%J0p(wtLE*oGLo&#! zW8Do+&EQKHj~QA(6@)R^<%?^B=E-a7e6S8e1q&~CNTqa$_^rs4TmM1P$7x_P4Yk7- z`-B2)`Cbg^)RXEIb(%4cdi3NC$F``?WKex22j{?;b4kjyOTXFZqcnN+jN!dLL(@Rl zG)+vZLgUygOob3QynrSB@cu6#p=11@b+Ig~JkrU0r!mDR-%v)utVp%?fvb7Zdv5mo zHEF_M$VV$fg%(`#7p!~xZm&mx&To|qJHb7?Q}`4L)JP@(&%F=5=Bl~_>8TQZ6to;l z(c6v<`%)FM6D;~;n1PU2;X|ZmdX$AR-Z#ob^n2A0Zb%jP4j%@^g4GbHPAROe;gu^A zaB_4QIKzf&n{_Wem)#TCiX=lqsIoPI%4Oq3$CU^6>kq8fi6hH$^;NC1EB6q+_Q%4& z4&K(BKO$9DGJ5UYeT5YCEe~8nuaQZI-i#x-^|R`aFfdLcQv}&`rlMF(WZ3102(0Ig zEO0gg{0U003bE|ALFEXjaxD}~yMZJ?Mbp+~J>zj0wYpId_bsewQSiqaOD618>Qv1a zk3q~NCuYda7_$Nc zsJ%CImJbcPA6D;8`0x^|q)BcolhwvUG@youaQ7UlTyM{c5Ab~ocMcH=mp9< zg(i<8R`@q+hjNBcTQr+Q%gBhO(M4C7E`2|u4zZ;bVa*#R3E$lc6e;xXQ<|9z)##1D zNXgePVI8s1r5D7cOt5yHsAoG7IC_sj08WI^J8*6$CAVbBO*f3%?w-A_K}Mf z;5v3sU6-tRBo=syjufke=1si8LT_OGI=5)l< zZ^zz{!9SiezLBpk5YD07cO!d&oIgh2Cto25$nt-x@xqx8Vrcb0$Sv2o2b1mXYz-eT zZ9_q?Y1F+@=)H}Ac8Qj6qf*`@i!nooz!Q{A$FJ99eu?Bqs~d8bu%jfffv-hhlc#YL zLrx%TcB1w$Q1>$se-B_u$%wrh(nfr^z`M-_a{tVdTT)GeY$VimCLwhLOYndpu=l)< zlh-cQ%JPh)YatS5Uq!S}3XwDSdhM^1#4eA0T{_4vC1K7ofL+T*(QOlm6h!Vp!Vz%z z&O+TTEt0Hpv%<_(5&uQFomtuvSQGylQH*Hb4HgYPgb*E4g(Fj>EebQr8J1|>x7b}{ z$US(?aY8e*Z4lwRD;$Zi;4Qk)7X>F4&G2x``*n?R>;~|zs1i2)JWl4kYx>X&jl4f@X?p>2k$pX>IBFI?g&SDpE#UnQjknvl zi;tYxLogx14N34b(x6L-X#KD5@_A(@M&2Z5a%|=SI}bO&n4~#TB=BZgO>0m3IBZ3O zh_&EICZ|YWBlR^cmFaO>M{)NUZRLXldb|7%+CuV+zCg(|`&EjW`?#iG258rpJeXG_ z{db*}hMuj-4w8LKE?pk!Gn6`OmL>CZPnoIslvC_0+FPq5@~xBY^*m3RoPC(j|BmD& z)v;@e{-vSD71}sioidhxPkDqfcWoT{UD*ceIAfyQ5A`y0Kgk_%{ry<@rS-#pPWJT$Iz8NgVvf-m!&cZ6Bnx+~NtP0Qm=3kAb%q{2!+G)r(Ti z!Yjd+KJz3XKX^)nmLh(axMYzeZ~~(Bf@?uf+YeuYx0QVwi+q2HfM+U1ni7uOJIXb& zm2qbl=9JS4r0%a(MAz-wA39&1OCdPdJy-fnG}0SN(3AO@L1iE{Q2{BP19p6f0S~wh zVTmXF&Ap){+ahGn>TvlCdBu8&)*IZcJ^@UXT@q|M?&hrBVt!w`oUN21C@^n`_^e^9 zY7?2uez>M<%j}Qg-r;DmxCJfUO-2NA8^yTJHVVuY0@g+O;M~c*7X< zy#>wJu#ZYPX{OT0lr-aqPz$zzMDCmHkfZas95aI6ZQHl6OKY#`xpVuo4anN^QF4_o zbuRABdhkH`e2O;KpTaiGWwV-sa&gOn^AWNzg~^-*ew}em`mqQmI^T}YzEKh_q#|ot ztuO1(%sY;lx6O4B^!axzPNpczJQ+Df=nxytF3Kp2nGn+99ltgrVLr^ob#%YT?ss*4 zp~sXAjo|O%v0CT30X3^5%7xYEQ$@v-gdH;9x^;t?C0gH$ZqsC?iWLo<QVA)D9@ejAS zQ^D}kmP1ndH3>t>=${L*@nS3d!mJlOAVjEz(N`g}w^ep#_4@a`$`hT+_y*adM&BEh zwwuya#tY@mhKbtLZ%hYa^)tv~GkS5dE-yGO}5n4rA{c!X5zgEtL(Ej>>^tK|1 zp2Q(Mm$k9d#-aC`rU^9Cv>3p^s&nCT7;xt*uadG(CK!4MhHsqWsR?KVypWAomGxZr8XNzX1+~mXsExag$M`T;N;9l zyxo1!!jI&4jt^69tLjp?VB~qnc^cY*w1o^IhTvgjUeF?{NIbMZTqXt$F~1__&_r=; ziD-s;nGzUPg^pU^ITo9UO^H<&(PaRP(u&3jDo_@3qCOiY0GDS(a&#>(@@P$`?TuIE z2+Ac}Xpx@PAN{!p(wiQ#S}~A2Wsovn+`9(V#$U53@rhSLl>vA&f{PBgF`P4lM>M<}ouG zUUY$k%Q7>&FajYGlKhqXR9f^Az+x{{(&hBEoX$EzKJPN6pU>N|0hc5Mat9_$49d(R zTSc@!2b5|L?hhBQbF@GNWEM38o< z>|07k%QNY}osCj^AzsQI^e6e{cq?sgzH0rm$M>wd5Hkx#2dbXu(`sSmTR$I66gOm2 z&)`k)T(Ns$tb+Au01?{Z{!RRrj$sVy-oIRoC-~yywmCSy?dl=f*&rQi&~XG-bLqLI z27WH0)yOId5ZvSiKt(?>lrjIT-+xYRdtN6=A8VmNeBZGv2;y;LusY@099!F%fHo>% zm=h_PBY?C?F9ci?j&W8t-iyc27gMw(urvC_#wULCIvo7Td%q4J6nEo$#J!gN&|i*! zGTV&6Cx2lljCR(XOrd~ue+AP92)uHoCG<8U_(%*~e)5oek>#)ixNo0M23b-jm8CPh z{jwC)lHA?G($jT9;+i_#t%z@Ay1VX1WBPLM(JHr)$cCd?r(|B-9?re;vXv}&mDK|7 z$?2St&JN-d6{B)`@}F*+@wfyfn0U}8DYP(1U@^3E3KY1bHeJ~Bb7eAHr%-*WNWW#X z*O50mBWy)mtPWAKK#txBMAP(lJEc?)S|j*#R7`lQNx2UK)RuOd?1IGaTI3-S=Lmq( zN`fA5I>yJ!z^-N)JV+ZXnyD+7he~FUG{avUq$Gm~=Ic}V z(dV77f9N3a-G|;QNt4Aaq&~56hoim?e5WAPUyjpeHA=g6$u{lQoPCY}yS!+}<6^3{T|2{Ja3K37?L3d?q61xeFq6rGK zMyAo@?qJ`4Zp8+NCMtjGmkFY~GmnE(# zihQYQye$N|Z3LqTa^}k(-Y?TROygm}X+t8)S|W^a?D%oVRg#c{=lCAw_%5&u2|y5+ zy$28Mv}(!`sB$J*cS>ZpTfr^Y#ANg;F`)Xhzq#?`yKGuL+^ikC_pbgJ{GTS*4rJNQ zUkk?PRr&*yDkrams=w9bqQ-7IX=LT>X$J z{^@V-I`IyhcS{LkcvkafyE}JLllwA++nH+HrBbE8b}f#{>~nWuhKOx@(7mP!9MUYv zuho=U*v1juw-zw1g_mDCvMjU!Xc_=r&kd$=gS)R~C){BxNieN)_R|2O=x?q)?{u~q zg3M#t)9-Qwn>$f!nHVXJwjTWo#?l(vdkpRkA>80wZvqRM^VYa^G(e@}aG-hs_Nh%@ z4a9s_m6FRX?t0(H?(X;^-jf{yYwghdc-nr7h12P|O@Q?1;vTkZ0LTlCw-VW>LYhY6U)&kZ|+X zU)akYjoX?=KT9m-^i9i>O~-2=83`Qt0>hj!CTV{o+l-&hXVa2N%x-MIvh`S~|jhE8SbF%&8U*;YvT&v}=NArr6K zf&;iREb~1cHgaDCYU{bh{Ueo$+r}rmP;Fa7Rd^xa^j|W8U7i>oFr*y-Bpzcl--f=s z4ZY@(XVi3UCXuVecRMRnB1$`)XO+N)bg7Pq4r94E%)#5CXN}5 zxbJ=%PV!d$=0`Hz0u6aI$QcXsMi07B^&~zVi{YCCB)506B`-b$mw-4` zR2}p1>X28?{B@)G>-qR`PDO|DoEvwI{wj>CAaK`Peh5YuW`}4VvNhdA{{DTf@;4ez zv4yWZH}tv!xHf4CJOD>LR&X6TpeoUoUcajr8A#U0h67NlValE27hK8Sen_vJ=UMX8 ze@4g$0V5BuaGw`A!w$4(FZVVn-DuqB|JalJxP->!jblloC`He^Vy8xC{?fpbNST zhTia?pVcbC`5p8-u! zCS-5DxCYcvbo{9=k@~y z_4~$bPv!>?Z=SL-<&Dbe!r<`=x>PrIX40iYldC{~R5R8R8pyqTAs}~c^i^0u4*$h{ zRY~P;Z$>RtA^Eb^m2sNHV0P0ZdK!0!xc>c0i6OD(4c0IxnSJmddP=pw%wCzpN3_cg zv-O^~_Ok3mldQ)5T)Vak))H6ofR(?K@<677)N22Shyiv6M4XhDazMP%5h81Q8+m}+ zGTK~fW*mNb>(2MhNRsi~b^jYQuM%!qq9p@cVe!QS;23wY?mnM-E!l!`-wXF_WN=OJ z3>*miHUBD?S{Ag6@$>p*4juN#KZH|zAzx_Nc;~!>9gwL7Fax;WO7d;&sft*xZ}C%P z3`t*J(hrXe>VBP#XU7$?_8#ahT{E3n%2UV~R~%*fH#zz52R<#3P-9n~Mbjh5>SOi# z%^X0ZG>6k2w)GJAB>N?1LO=F$dDNST~O&2zk_CTzgaNN3McMtp7+qx+{qh7T~$D4Q=&Goy{&?RN3c4l z*Z@b?E!Vao0GwOiyV_84qKB{T;=U@*c^P~!S$Ol1plXk5B?cnyM9 zkFa_+zGj4UZr>IQz-X9r2Dj_?wHLpphQ4+NAfq+6U*;zmkLSOIV%#|(RLTr0L7l}W zFg~XN{eghHoHX!?^CF*X@f@Y zwi)m6K+vDCsc23GGT%Q|B`&u9oPX`-8M`-O$&*Gm#@fS0E&-t_3~6cyW8!&pWrs4i zLtB*@t>Zf@^RaFtH=?E^yP`uuX?y%d0&^Y$QZKg@iQS6@@RPQz1mH6p__I&kMsR;4 z3celqVi9v5KM_&4gxFGxDBRmfOSVF~=y9KMvag;!@EgtesdDYnSr>J%0EsxG-Mc!Qh%RyN4&ZiS_JEbYj1KhG*PuR=x zK^0af^@C=%Jjj*VZ=uPJN(C&FS#CM|nRvE`H`jy8U35bn?p5%qZODP>otV{?smv)) zX~>=|%uYb$^7Y|L+ZsJ`Q$v%OZOB)x&c92@4 z6%(S2{JGeW4v*^RIruvsYRm|iI3^dGdThKs%6E4VAhTvGv$jLUEYNGzgdj-dM3`Ac zZ}~C%(ey7`1rq;@+n=lC*Glx=Li&`gcmMDU!=B;uRzlX^K){v9c2bBO<=hF3=ybf= zKllptqls~eB7Ix7P6Gn7Fl6qUIx+hzf|&6iOy%w=7FKF5p7d5FQ!!~*_FT#0!p#R7e~eX$=nKmwJU zJh|1tDuJno&UFU{M6a56CFF$17ijIHFqfA!25t1bx$3m9vRhrQW%{PRj{?D>PXB-$ z$bB{`FsbP9NAC5m)Kf(Q<}f+USnpDi+EX@(RelVx&PcnN&W^*GO@3F(5V=FOI5&c) zh{o(rMM=wUR{EuU{%+|=KY6EwRkja;pYWFrJj=eFQ6NIU7|&ofvCmb`uu163yH?UZ z+$Zvn#-5H;KFuJ5 zO4mDc_4R!wN}6cYO^WPAVWe%=kHGpKu!likBRVg_ndP}b<}FLRcNghk{kR!2Gbpy= z2FGfxmqnH`-919hh^7`YLnTaBLX)YzMA2d5;%}l$0Txw#HH*r6cppchub+cxQ7J9R z*fx4G(SU-d1u>x)kRv|ZkWZAVWP&}EStqJ7qn)d8)%MY3bHS+PL^H>sC` z!eCt{b^qICb!2Jd%a)5z&JBr#pv!Y#8rg+|5`A$huh5S|dIi2_4@X=Oz{ToC@0AWg znQS@HLS}{GuBp*rUf+PW9O#buu!GRgp>Djm4~E=tl=v?+BW z_dCe4lZ^I$lm2}Fd{mB3q4|YR_Z19w7e-L%^2H!bOiRx4g`-hhgdfYSb=gPEkn3C_ zAqwv*IfmRDNy| zMd3CZ@>8nFl#9wG=)4!M>4kQb3OyY{w0qeVg8$flvkgZ+8IFB%jx7G~JuMmYp(B@U zX32w6=D7j91W5*abXWCAU#y#XJE_<4J^}C}SBwc_$qn3K9!f=&o(u)BN~=&b>hAI> zv90~d56CwARd)FpEN*`Qcx{d4i7R!JU|t&QvUP0at!b>>i`Gtx7=aJUOOhhAH_0lb zm43%mx-ZB@9|F!O-y>=%^3s*rIm$Z9OtkuOw^=HAO6o=knRDXYyhCS0IqwGh19uFE zeB;aGAx}cX;>#I7pX^GqIyy!6etZza8P`8YWb*H+*C zL*=6VlyVn9zAc4}Xna;&5k+*0bM9aGK@*@_|N01q$jkV`Sz2kll!$w7j8m;ukE0Co z>TBI7Rqy>giguHpHTaAs%TiV!#q*@T8Iw!>{Y4H9&5d5;H*3h23_3Y;fgqOz~=O2_Nm9#2rYdoo5CgAT{FiMg6Z zY+~NcttC;^`UU44s9ts%Uma3Nn0~25NtepIxNpQ^ zH#^t(8`%r>8x|RINo(Rj(h*-3iA1T{yzEk#d=u3$RXxbAnPa?-rIoh4vQ1d{tfCC z>KP2oy1zrjE8apJlo0uM7pQhd)H87_c($-ueN%8Upf#IXl)TBRW9RADd?6HFh$K)Q zxtW_wc_#0H`Yh=|?)+t9bOtMSxl1|gAM21=zF+S~d(R1LBi|%XPJd@7#;6NL=+Fn$ zom04u&m)hyD@Bnbx*_&qK0F=r9`aSiGE|mpqgox;o$`(M_um5_x}5+XWYG-#yoA~U zkX!Dj}v`Xd5j5z)z~VUN)S4L$Oe?r#Q?UrQ^Hd8(ncAbUKeS=@gzj$BVe9gumH zD_R?O=)0vkp#N3lmmSp(^8kJ9hJ4k*HC>I*%GD-?Gh*RZd9hY$XGZzGZic>#j$#a8 zus%nQbyO6s4>DZ~XJFefx8CbqL<<-d(w;E{Wtd7EB-hgKBIfLzdw_=mhKD&`(BL05 zc%doVDp5yN5li+o3t+v5l%v;OeI+O1P3m(f92a_gURGZ^gKp6E+B?&m2SyVc&gwuJ zhcK*q1=48`N}B*nM24i8H`guFP6#O*A?ux8ZLyZhJ_`G%t^B7ozHFNqQparPlqjmC zHv7tfOKQm-ud^V`9?T5p$g{eh$_Zo~*6m8dz{T9pvtFgngXaGouhOy^^d4-ziEqd& z#P@~lWYZrW(vAG$IG+bjtUF?_WV~ku6K6adX8Y2eL^WX6bh~H$cVZ zjvMz8E;UN_+8Tj*Wv^4hpQp;2{qfpYmk^fAptr)@AdPH7spL1K-r~yuXqkV6TkqS- zTEvZ!TC(6_46A{Tx>XNlNp##md(CUTvByXp-wMaC35_gPX_Pr)Q2U8G30k+Z++&&U zY%5psBlBasZ%ktCf!V5441Sin{MJH=ccg`O#Ll^AG|l8SM});_X<3VhiOZ znKwB+_lz5w8J)@X_Tm63c~PT$o1oE<2{DCcd2ZG5B#7$^0(0#?h?XHJtu6vS_2d?m21ZOUoAwOAN z7EiD$Nc%i%WZ6BF6x<4^j4ckBJpPr2T3}CmxdP;ovrn>@`a-cc@7n2VwUuRr`U$g*pwB8nb((d33LedYIZGsUJllqPAA5mx~QDsJcjTNr#`@9YuEptG?$38&N zPG-$83l6Ma{2+r)pqwht~`VYa}34 zcf6JAh)|Kf@dDTlfdfHW}d$9bH$MI8sAeSu)n+_rdOlET&n5qC zP|IY{j z94TS`j?516E`8-7;VU=kC6~^a*n6714$RW4Xa0{3WeepI>dWBufvsbPSAkLGu?7?d#9VRIqt{R zsrV>IEs_&;cT5b#d*a2@3cfi1DXrb_@dA3ZxrDsjFWDwTJIR+UbPw1}O|%ap6ZlJk zP5|v}z@$5w50NaNl|0E7kpae=D#5dAD!K5ng~DU9khfC2%QXL)^#@t?k*Uq_&?&x_ z3V$wa0cmkVoVWhKHJPj^QLd;EPNqNHopqY5^;&(Ip|yBsyGp-`%WH>8#tQYx?C6Zj zi%6@(kLFTvXF4@cI=jN+%2E^hgYK2O&zIIk@QvDYVc?l;33)^$-*Gut&zke1LS{!0 z?bJ~(*9KSi6@L4QA6Xb7CZIc)6D{o-<$I?boK8<^X;ALelPdyc%X@KI&uEqGo_{P; z9j9vL*x$beLN&w?eHU+Xm&Jyoj|w|2xmT(7qEbG=@I{a^9!C_s!SQ!_*o-&^P{@lH z$@A~(w>G~2=O|Lkk3J(Oe5k~4kQY{COD+v)CY}v(l$$+Liqlkf53N^nUX!qQK{1p0 znWg+;XO5nHpoG;d(8LEw6HOJ6u>()U>;Umep_4*?r!z7bn&0=FGb?{WP*LOq=4$Q~C*+y!$EAv)$d{Yn|V5p^FOxHGC5y^-3OD1A2# zOU?DzhrLUT%0&kI@C72S&tdhV9tkJPgC*~toZVy#_Uk?5lm?o_leOZ>o?&xu2u`Js zlDdNutz}xurk#Tj1YgL$TS}34ga_?sFIBNMTS)YcDkRx?cOO^h1>Ursewj~ly6S}H zEr{Hc2e^m=>HRy&mNO1lK<0ieM!jlr={tv!-utcn%8<{F%Tr#TomZXr9A)T8zZrd+_cMLPxJrm&@$?s&jJoU2{+$(XtPx;FKe&D>?&` zQl=A2zs|TdML%-7B(1{#R~ufnT3Q#rU=&G09@R%Xfs67WYJPA;J@6QJ$ZZ61xjQ0& z4mpuIOLn4OrG?&fXMa6J-y`J(7Ai^{p9po5rP`bZ5h3XbWx_VLKa?@(__dbLoXh7YB=mt?1UnAif>8{UmfaKHD>At^c8NBfj3ym%xKE~ zk(8nfDMKxF6(cZeO?$bUodM!~i8EY_{$3q%1m?G}QbEVFcf<{ai%seEmOMF0FFNpa zNKN3-y@_X=GxwUhu>*19BIM~|r*BJ_uCXgz4$l2_IzPEIfLm|QYk0N8xrl7E@!R9CaqES3aCf zfbFboLX@)#3Lvwv}#7P7bK}<#fHunk-Y5a3ihA4zc4z z4eh4`o&r$LW-$NsPp2x%imGhKwuf~xizzCWc0?@~xV3nL)}(EpU4~G$Pvhl_`_Y56 zBkl)(?$V`+qZBIq4&0g184mB6`YB9@6(4c;i->%v9C_9pp`pn#Dsv4i)vMrXHq8B! zR{!2hoYvlzuB*n-**Fb9ytUqGchv2Hz!{dL`=|G$ORJM_kAiz)=SeK1P*87m{1Top zx>Xk>z!p~A6I%FuI6_RUmx4i#^Mo$I#|-e`?GFzxrjw?(1sC5&zKkZjx6~`toY{}c z%R(~Np5Vn(nA(Rj7td;!r>;M9OV}y#`-zgK%^>rnNMOd>KXo8}yirtI$Eie^1IjFv zIWSj=W)PKY5auF_z~gZ1JYLxOvbZo}P-eWUVp4_GMUrKOJ_wT5Pggr@3oas6cGMDj zNsD>{aYowsJiZz>apMA+hmFw-Lcdtx>+ACSzCGb3TfCcfC*A6>OiYk8G|0?bMh>nQQ6e*WMhS| zYf7ef<@+t4wcuf8VfdlG6erE6eHB?eD<+R%^qI_?L_~h~*={;$L#Mc2EdCZ#8rs>^p)m~r6PA#STwU?p0UNs`G8yq!4kRa^Vs7eFgVVzr6T ztlHl({3d40*cZ|Ad8Jwk86YFz1C=OXloabcD%(T4>|3=Z{e`9OXGa znn1=`)x5_yh5pAz>F2B#67DjTG|hLW7JrcXd6)TICsJk|9c1|vEaE&iuA-fr7Hu#b zHmirbQpZ?I8|3^=^H=QSh_fQOl9Px^EgLi=heU9~e?)Pi%Wt(BH&HXO-kjgEji_OO7mboOk6e3DAQX!SgFrg47-P|gbzKt#) z3H$mF&JR0h@5lS~e!iX>oAlmoOT1VuQ~MjlUvis2Tfs#ZtfvP6W z1bIt)GfoR`T4(DnDIW^s7<{DzX3}lgdsl|IcRmq*k^$pJYqub|rUoe%(BZAvv-s#7*UhDZA@d;RVremzC!L;nY$aLaGhN;nA3~l89L}X|Ms}flF59eu}uf*^crGFfvelk~BtPt>;0e9n9Xow#tYZ zIx)u_aXe6;?=q z>VNuM6w-Nyq!w_=JK=i|T$6^Q&FwoUkI80B+2@r<-uwoM&l!Z-b&Uh@JEO{QOjq~X zlFV(UgO@~Q(MvTz;T`c9(ZMMH$l7=1GFEfEn;n^=n2LUVg#rXh2vALzl>KF|ik?iQ zW|f1yFJpvse;MW!)g0Hk)lKkJm90O#kej6MjW$%qhzNS}Kj4uC4`zA@;{`j5^Ot

      kThqovq8`=bglRp_&!1UPl$Km2( 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

      KLP)d**)z|d0fsqu)w;warW$rqn{@Uz#ay@6F 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 z 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

      >6A*+sJO%6GNP?TQgrBqscnLZntvs{3EhYd(K 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%0D;p6OJiT^9 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

      -X*@L^|?mhncd}U0V7h04@ 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%0Dq$zPB+CDVNBAhfiOe6{sI|6^QxZ@_2qLT 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

      9`9W$mm*;2AuMs8BU;He}&}v=T3Sr4XmH~+ah(h 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 Date: Sat, 7 Sep 2024 16:40:04 -0700 Subject: [PATCH 176/189] Remove dev warnings from docs . --- docs/README.md | 2 -- docs/_coverpage.md | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/README.md b/docs/README.md index 8fb8678d..e3b86bb8 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,3 @@ -!> This documentation is for the unreleased `dev` branch! See the [Github README](https://github.com/dermotduffy/frigate-hass-card?tab=readme-ov-file#frigate-lovelace-card) for documentation of the released version. - # Getting Started ## Installation diff --git a/docs/_coverpage.md b/docs/_coverpage.md index ec27a485..d0ee729e 100644 --- a/docs/_coverpage.md +++ b/docs/_coverpage.md @@ -1,6 +1,6 @@ ![logo](images/frigate-logo.svg) -# Frigate Card 6.0.0 _*DEV*_ +# Frigate Card 6.0.0 > A comprehensive camera card for Home Assistant. From 1a3815273897fd525e48c7c5242de47fa62a5172 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 7 Sep 2024 16:41:17 -0700 Subject: [PATCH 177/189] Bump version to v6.0.0-beta.1 . --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4a969ab3..9b7ac717 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "frigate-hass-card", - "version": "5.2.0", + "version": "6.0.0-beta.1", "description": "Frigate Lovelace Card for Home Assistant", "keywords": [ "frigate", From e233ac385f6045966b0b5b96c5eb2f3e8f88eb2c Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sat, 7 Sep 2024 17:15:29 -0700 Subject: [PATCH 178/189] Add French translations --- src/localize/languages/fr.json | 164 ++++++++++++++++----------------- 1 file changed, 82 insertions(+), 82 deletions(-) diff --git a/src/localize/languages/fr.json b/src/localize/languages/fr.json index b41ebeaa..89128777 100644 --- a/src/localize/languages/fr.json +++ b/src/localize/languages/fr.json @@ -12,31 +12,31 @@ "camera_entity": "Entité caméra", "capabilities": { "capabilities": { - "clips": "", - "favorite-events": "", - "favorite-recordings": "", - "live": "", - "menu": "", - "ptz": "", - "recordings": "", - "seek": "", - "snapshots": "", - "substream": "" + "clips": "Clips", + "favorite-events": "Événements favoris", + "favorite-recordings": "Enregistrements favoris", + "live": "Vue en direct", + "menu": "Menu", + "ptz": "PTZ", + "recordings": "Enregistrements", + "seek": "Chercher", + "snapshots": "Snapshots", + "substream": "flux secondaire" }, - "disable": "", - "disable_except": "", - "editor_label": "" + "disable": "Désactiver", + "disable_except": "Désactive sauf", + "editor_label": "Capacités de la caméra" }, "cast": { "dashboard": { - "dashboard_path": "", - "view_path": "" + "dashboard_path": "Chemin du tableau de bord", + "view_path": "Voir le chemin" }, - "editor_label": "", - "method": "", + "editor_label": "Cast les options", + "method": "Cast les méthodes", "methods": { - "dashboard": "", - "standard": "" + "dashboard": "Dashboard", + "standard": "Standard" } }, "dependencies": { @@ -45,15 +45,15 @@ "editor_label": "Options de dépendance" }, "dimensions": { - "aspect_ratio": "", - "editor_label": "", + "aspect_ratio": "ratio d'aspect", + "editor_label": "Dimensions de la caméra", "layout": { - "editor_label": "", - "fit": "Adatta al layout", + "editor_label": "Disposition de la caméra", + "fit": "Ajustement de la disposition", "fits": { - "contain": "Il supporto è contenuto/in cassetta delle lettere", - "cover": "Il supporto si espande proporzionalmente per coprire la scheda", - "fill": "Il supporto viene allungato per riempire la scheda" + "contain": "Le média est contenu", + "cover": "Le média s'étend proportionnellement pour couvrir la carte", + "fill": "Le média est étiré pour remplir la carte" }, "pan": { "x": "", @@ -61,8 +61,8 @@ }, "position": { "editor_label": "", - "x": "Percentuale di posizionamento orizzontale", - "y": "Percentuale di posizionamento verticale" + "x": "Pourcentage de positionnement horizontal", + "y": "Pourcentage de positionnement vertical" }, "view_box": { "bottom": "", @@ -132,10 +132,10 @@ "editor_label": "Modèle de répertoire des films", "entities": "Déclencheur à partir d'autres entités", "events": { - "clips": "", - "editor_label": "", - "events": "", - "snapshots": "" + "clips": "Événements avec de nouveaux clips", + "editor_label": "Événements déclencheurs", + "events": "Tous les événements", + "snapshots": "Événements avec de nouveaux instantanés" }, "motion": "Déclenchement par détection automatique du capteur de mouvement", "occupancy": "Déclenchement par détection automatique du capteur de présence" @@ -176,10 +176,10 @@ "clips": "Miniatures de clips", "snapshots": "Miniatures d'instantanés" }, - "media_type": "", + "media_type": "Afficher ou non les vignettes des événements ou des enregistrements", "media_types": { - "events": "", - "recordings": "" + "events": "Événements", + "recordings": "Enregistrements" }, "mode": "Mode vignettes", "modes": { @@ -203,21 +203,21 @@ "below": "En dessous", "none": "Aucun" }, - "pan_mode": "", + "pan_mode": "Mode panoramique par défaut", "pan_modes": { - "pan": "", - "seek": "", - "seek-in-camera": "", - "seek-in-media": "" + "pan": "Pan", + "seek": "Pan cherche parmi toutes les caméras", + "seek-in-camera": "Pan ne cherche que parmi la caméra sélectionnée", + "seek-in-media": "Pan ne cherche que parmi les médias sélectionnés" } } }, "display": { - "editor_label": "", - "grid_columns": "", - "grid_max_columns": "", - "grid_selected_width_factor": "", - "mode": "" + "editor_label": "Affichage", + "grid_columns": "Nombre de colonnes de la grille", + "grid_max_columns": "Nombre maximum de colonnes de la grille", + "grid_selected_width_factor": "Augmenter la largeur du média sélectionnée par ce facteur", + "mode": "Mode" }, "media_action_conditions": { "all": "Toutes les opportunités", @@ -276,14 +276,14 @@ "controls": { "editor_label": "Contrôles en direct", "ptz": { - "editor_label": "", - "hide_home": "", - "hide_pan_tilt": "", - "hide_zoom": "", - "mode": "", + "editor_label": "PTZ", + "hide_home": "Cacher le bouton d'origine", + "hide_pan_tilt": "Caher les boutons panoramiques/inclinaison", + "hide_zoom": "Cahger le bouton de zoom", + "mode": "Mode", "modes": { - "off": "", - "on": "" + "off": "Eteint", + "on": "Allumé" }, "orientation": "", "orientations": { @@ -292,10 +292,10 @@ }, "position": "", "positions": { - "bottom-left": "", - "bottom-right": "", - "top-left": "", - "top-right": "" + "bottom-left": "Bas à gauche", + "bottom-right": "Bas à droite", + "top-left": "Haut à gauche", + "top-right": "haut à droite" } } }, @@ -412,9 +412,9 @@ "warning": "Cette carte est en mode profil bas, les paramètres par défaut ont donc été modifiés pour optimiser les performances." }, "profiles": { - "editor_label": "", - "low-performance": "", - "scrubbing": "" + "editor_label": "Configuration des profils", + "low-performance": "Basse performance", + "scrubbing": "Balayage vidéo" }, "status_bar": { "height": "", @@ -465,7 +465,7 @@ "inactive": "" } }, - "interaction_seconds": "", + "interaction_seconds": "Secondes après l'action de l'utilisateur pour maintenir l'interaction (0=jamais)", "keyboard_shortcuts": { "editor_label": "", "enabled": "", @@ -479,28 +479,28 @@ }, "triggers": { "actions": { - "editor_label": "", - "interaction_mode": "", + "editor_label": "Actions de déclenchement", + "interaction_mode": "Comment gérer les actions lorsque la carte comporte une interaction humaine ?", "interaction_modes": { - "active": "", - "all": "", - "inactive": "" + "active": "Ne déclencher des actions que lorsque la carte a une interaction humaine", + "all": "Déclencher des actions sans interaction humaine", + "inactive": "Ne déclencher des actions que lorsque la carte n'a pas d'interaction humaine" }, - "trigger": "", + "trigger": "Actions de déclenchement", "triggers": { - "default": "", - "live": "", - "media": "", - "none": "" + "default": "Changement ou mise à jour de la vue par défaut", + "live": "Change ou met a jour la vue en direct", + "media": "Changement d'affichage pour les nouveaux médias", + "none": "Pas d'acction" }, - "untrigger": "", + "untrigger": "Action de désactivation", "untriggers": { - "default": "", - "none": "" + "default": "Passage à la vue/caméra par défaut", + "none": "Pas d'action" } }, - "editor_label": "", - "filter_selected_camera": "", + "editor_label": "Comportement en cas de déclenchement d'une caméra", + "filter_selected_camera": "Déclenchement uniquement sur la caméra sélectionnée", "show_trigger_status": "Afficher la bordure clignotante lors du déclenchement", "untrigger_seconds": "Quelques secondes après le changement d'état inactif pour débloquer" }, @@ -519,14 +519,14 @@ } }, "display_modes": { - "grid": "", - "single": "" + "grid": "Afficher la visionneuse de médias pour chaque caméra d'une grille", + "single": "Affi une seule visionneuse" }, "editor": { "add_new_camera": "Ajouter une nouvelle caméra", "button": "Bouton", "camera": "Caméra", - "cameras": "Appareils photo", + "cameras": "Caméras", "cameras_secondary": "Quelles caméras afficher sur cette carte", "delete": "Supprimer", "dimensions": "Dimensions", @@ -547,7 +547,7 @@ "overrides_secondary": "Remplacements de configuration dynamique détectés", "performance": "Performance", "performance_secondary": "Options de performances de la carte", - "profiles": "", + "profiles": "Profils de confi", "profiles_secondary": "", "status_bar": "", "status_bar_secondary": "", @@ -570,10 +570,10 @@ } }, "error": { - "awaiting_live": "", + "awaiting_live": "En attente du flux en direct...", "camera_initialization": "", "could_not_render_elements": "Impossible de restituer les éléments de l'image", - "could_not_resolve": "", + "could_not_resolve": "Impossible de résoudre l'URL du média", "diagnostics": "Diagnostic de la carte. Veuillez enlever les informations confidentielles avant de les partager", "download_no_media": "Aucun média à télécharger", "download_sign_failed": "Impossible de signer l'URL du média à télécharger", @@ -661,7 +661,7 @@ "where": "Où" }, "media_viewer": { - "unseekable": "" + "unseekable": "Temps non trouvé dans les médias" }, "recording": { "camera": "Caméra", From 041656317a38fafe5cec92271f36a5926e485778 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 8 Sep 2024 16:48:26 -0700 Subject: [PATCH 179/189] Add support for arbitrary image entities --- docs/configuration/cameras/README.md | 4 + docs/configuration/cameras/live-provider.md | 11 +- docs/configuration/image.md | 21 ++-- .../status-bar-item-manager.ts | 2 +- src/components/image.ts | 108 +++++++++++++----- src/components/live/live-image.ts | 9 +- src/config/types.ts | 29 ++--- src/const.ts | 6 + src/editor.ts | 76 +++++++++--- src/localize/languages/ca.json | 24 ++-- src/localize/languages/en.json | 24 ++-- src/localize/languages/fr.json | 24 ++-- src/localize/languages/it.json | 24 ++-- src/localize/languages/pt-BR.json | 24 ++-- src/localize/languages/pt-PT.json | 24 ++-- tests/config/types.test.ts | 3 +- 16 files changed, 264 insertions(+), 149 deletions(-) diff --git a/docs/configuration/cameras/README.md b/docs/configuration/cameras/README.md index e1da9a0c..af6d895b 100644 --- a/docs/configuration/cameras/README.md +++ b/docs/configuration/cameras/README.md @@ -356,7 +356,11 @@ cameras: - camera_entity: camera.back_yard live_provider: image image: + mode: auto refresh_seconds: 1 + url: 'https://path/to/image.png' + entity: image.office_person + entity_parameters: 'width=400&height=200' - camera_entity: camera.office_motioneye motioneye: images: diff --git a/docs/configuration/cameras/live-provider.md b/docs/configuration/cameras/live-provider.md index a9b01412..af8ddb28 100644 --- a/docs/configuration/cameras/live-provider.md +++ b/docs/configuration/cameras/live-provider.md @@ -44,10 +44,13 @@ cameras: # [...] ``` -| Option | Default | Description | -| ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `refresh_seconds` | 1 | The image will be refreshed at least every `refresh_seconds`. `0` implies no refreshing. | -| `url` | | **Advanced**: A static image URL to be fetched in lieu of the Home Assistant image for the given camera. This may be useful for advanced configurations where the camera image is being provided by some non-Home Assistant system. This will also set the temporary loading image used when `show_image_during_load` is set to true under the `live` configuration. | +| Option | Default | Description | +| ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `entity` | | The entity to use when `mode` is set to `entity`. This entity is expected to have an `entity_picture` attribute that specifies the image URL. | +| `entity_parameters` | | Optional URL parameters to add to the URL generated for entity-based modes (i.e. when `mode` is `camera` or `entity`). | +| `mode` | `auto` | Value must be one of `url` (to fetch an arbitrary image URL), `camera` (to show a still of the currently selected camera entity using either `camera_entity` or `webrtc_card.entity` in that order of precedence), `entity` to show an image associated with a named entity (see the `entity` parameter below), or `screensaver` (to show an [embedded stock Frigate card logo](https://github.com/dermotduffy/frigate-hass-card/blob/main/src/images/frigate-bird-in-sky.jpg)). If `auto`, the mode is chosen automatically based on whether `url` or `entity` parameters have been specified. | +| `refresh_seconds` | 1 | The image will be refreshed at least every `refresh_seconds` (it may refresh more frequently, e.g. whenever Home Assistant updates its camera security token). `0` implies no refreshing. | +| `url` | | A static image URL to be used when the `mode` is set to `url` or when a temporary image is required (e.g. may appear momentarily prior to load of a camera snapshot in the `camera` mode). Note that a `_t=[timestsamp]` query parameter will be automatically added to all URLs such that the image will not be cached by the browser. | ## `jsmpeg` diff --git a/docs/configuration/image.md b/docs/configuration/image.md index 9141db6d..2727e289 100644 --- a/docs/configuration/image.md +++ b/docs/configuration/image.md @@ -7,12 +7,14 @@ image: # [...] ``` -| Option | Default | Description | -| ----------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `actions` | | [Actions](actions/README.md) to use for the `image` view. | -| `mode` | `url` | Mode of the the `image` view. Value must be one of `url` (to fetch an arbitrary image URL), `camera` (to show a still of the currently selected camera using either `camera_entity` or `webrtc_card.entity` in that order of precedence), or `screensaver` (to show an [embedded stock Frigate card logo](https://github.com/dermotduffy/frigate-hass-card/blob/main/src/images/frigate-bird-in-sky.jpg)). In either `url` or `camera` mode, the `screensaver` content is used as a fallback if a URL is not specified or cannot be derived. | -| `refresh_seconds` | 0 | The image will be refreshed at least every `refresh_seconds` (it may refresh more frequently, e.g. whenever Home Assistant updates its camera security token). `0` implies no refreshing. | -| `url` | | A static image URL to be used when the `mode` is set to `url` or when a temporary image is required (e.g. may appear momentarily prior to load of a camera snapshot in the `camera` mode). Note that a `_t=[timestsamp]` query parameter will be automatically added to all URLs such that the image will not be cached by the browser. | +| Option | Default | Description | +| ------------------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `actions` | | [Actions](actions/README.md) to use for the `image` view. | +| `entity` | | The entity to use when `mode` is set to `entity`. This entity is expected to have an `entity_picture` attribute that specifies the image URL. | +| `entity_parameters` | | Optional URL parameters to add to the URL generated for entity-based modes (i.e. when `mode` is `camera` or `entity`). | +| `mode` | `auto` | Value must be one of `url` (to fetch an arbitrary image URL), `camera` (to show a still of the currently selected camera entity using either `camera_entity` or `webrtc_card.entity` in that order of precedence), `entity` to show an image associated with a named entity (see the `entity` parameter below), or `screensaver` (to show an [embedded stock Frigate card logo](https://github.com/dermotduffy/frigate-hass-card/blob/main/src/images/frigate-bird-in-sky.jpg)). If `auto`, the mode is chosen automatically based on whether `url` or `entity` parameters have been specified. | +| `refresh_seconds` | 1 | The image will be refreshed at least every `refresh_seconds` (it may refresh more frequently, e.g. whenever Home Assistant updates its camera security token). `0` implies no refreshing. | +| `url` | | A static image URL to be used when the `mode` is set to `url` or when a temporary image is required (e.g. may appear momentarily prior to load of a camera snapshot in the `camera` mode). Note that a `_t=[timestsamp]` query parameter will be automatically added to all URLs such that the image will not be cached by the browser. | ?> When `mode` is set to `camera` this is effectively providing the same image as the `image` [live provider](cameras/live-provider.md) would show in the live camera carousel. @@ -22,8 +24,11 @@ image: ```yaml image: - mode: url - refresh_seconds: 0 + mode: auto + refresh_seconds: 1 + url: 'https://path/to/image.png' + entity: image.office_person + entity_parameters: 'width=400&height=200' actions: entity: light.office_main_lights tap_action: diff --git a/src/card-controller/status-bar-item-manager.ts b/src/card-controller/status-bar-item-manager.ts index f37bd791..3727c237 100644 --- a/src/card-controller/status-bar-item-manager.ts +++ b/src/card-controller/status-bar-item-manager.ts @@ -48,7 +48,7 @@ export class StatusBarItemManager { const engineLogoIcon = cameraMetadata?.engineLogo ?? null; const title = options?.view?.is('live') ? cameraMetadata?.title ?? null - : options?.view?.isAnyMediaView() + : options?.view?.isViewerView() ? options?.view.queryResults?.getSelectedResult()?.getTitle() ?? null : null; const resolution = options?.mediaLoadedInfo diff --git a/src/components/image.ts b/src/components/image.ts index 63335d86..c731a299 100644 --- a/src/components/image.ts +++ b/src/components/image.ts @@ -12,8 +12,9 @@ import { customElement, property } from 'lit/decorators.js'; import { live } from 'lit/directives/live.js'; import { createRef, ref, Ref } from 'lit/directives/ref.js'; import isEqual from 'lodash-es/isEqual'; +import { CameraManager } from '../camera-manager/manager.js'; import { CachedValueController } from '../components-lib/cached-value-controller.js'; -import { CameraConfig, ImageViewConfig } from '../config/types.js'; +import { CameraConfig, ImageMode, ImageViewConfig } from '../config/types.js'; import defaultImage from '../images/frigate-bird-in-sky.jpg'; import { localize } from '../localize/localize.js'; import imageStyle from '../scss/image.scss'; @@ -28,7 +29,6 @@ import { } from '../utils/media-info.js'; import { View } from '../view/view.js'; import { dispatchErrorMessageEvent } from './message.js'; -import { CameraManager } from '../camera-manager/manager.js'; // See TOKEN_CHANGE_INTERVAL in https://github.com/home-assistant/core/blob/dev/homeassistant/components/camera/__init__.py . const HASS_REJECTION_CUTOFF_MS = 5 * 60 * 1000; @@ -119,14 +119,12 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay return false; } - const cameraEntity = this._getCameraEntity(); - if ( - changedProps.has('hass') && - changedProps.size == 1 && - this.imageConfig?.mode === 'camera' && - cameraEntity - ) { - if (isHassDifferent(this.hass, changedProps.get('hass'), [cameraEntity])) { + const relevantEntity = this._getRelevantEntityForMode( + this._resolveMode(this.imageConfig?.mode), + ); + + if (changedProps.has('hass') && changedProps.size == 1 && relevantEntity) { + if (isHassDifferent(this.hass, changedProps.get('hass'), [relevantEntity])) { // If the state of the camera entity has changed, remove the cached // value (will be re-calculated in willUpdate). This is important to // ensure a changed access token is immediately used. @@ -158,6 +156,10 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay } } + const relevantEntity = this._getRelevantEntityForMode( + this._resolveMode(this.imageConfig?.mode), + ); + // If the camera or view changed, immediately discard the old value (view to // allow pressing of the image button to fetch a fresh image). Likewise, if // the state is not acceptable, discard the old value (to allow a stock or @@ -165,8 +167,7 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay if ( changedProps.has('cameraConfig') || changedProps.has('view') || - (this.imageConfig?.mode === 'camera' && - !this._getAcceptableState(this._getCameraEntity())) + (relevantEntity && !this._getAcceptableState(relevantEntity)) ) { this._cachedValueController?.clearValue(); } @@ -245,24 +246,75 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay /** * Build a working absolute image URL that the browser will not cache. * @param url An input URL (may be relative to document origin) - * @returns A new URL (absolute, will not be browser cached). + * @returns A new URL as a string (absolute, will not be browser cached). */ - protected _buildImageURL(url: string): string { - const urlObj = new URL(url, document.baseURI); - urlObj.searchParams.append('_t', String(Date.now())); - return urlObj.toString(); + protected _buildImageURL(url: URL): string { + url.searchParams.append('_t', String(Date.now())); + return url.toString(); + } + + protected _addQueryParametersToURL(url: URL, parameters?: string): URL { + if (parameters) { + const searchParams = new URLSearchParams(parameters); + for (const [key, value] of searchParams.entries()) { + url.searchParams.append(key, value); + } + } + return url; + } + + protected _getRelevantEntityForMode(mode: Exclude): string | null { + return mode === 'camera' + ? this._getCameraEntity() + : mode === 'entity' + ? this.imageConfig?.entity ?? null + : null; + } + + protected _resolveMode(mode?: ImageMode): Exclude { + if (!mode) { + return 'screensaver'; + } else if (mode !== 'auto') { + return mode; + } + + const cameraEntity = this._getCameraEntity(); + if (this.imageConfig?.entity) { + return 'entity'; + } else if (this.imageConfig?.url) { + return 'url'; + } else if (cameraEntity) { + return 'camera'; + } + + return 'screensaver'; } protected _getImageSource(): string { - if (this.hass && this.imageConfig?.mode === 'camera') { + const mode = this._resolveMode(this.imageConfig?.mode); + + if (this.hass && mode === 'camera') { const state = this._getAcceptableState(this._getCameraEntity()); if (state?.attributes.entity_picture) { - return this._buildImageURL(state.attributes.entity_picture); + const urlObj = new URL(state.attributes.entity_picture, document.baseURI); + this._addQueryParametersToURL(urlObj, this.imageConfig?.entity_parameters); + return this._buildImageURL(urlObj); } } - if (this.imageConfig?.mode !== 'screensaver' && this.imageConfig?.url) { - return this._buildImageURL(this.imageConfig.url); + + if (this.hass && mode === 'entity' && this.imageConfig?.entity) { + const state = this._getAcceptableState(this.imageConfig?.entity); + if (state?.attributes.entity_picture) { + const urlObj = new URL(state.attributes.entity_picture, document.baseURI); + this._addQueryParametersToURL(urlObj, this.imageConfig?.entity_parameters); + return this._buildImageURL(urlObj); + } } + + if (mode === 'url' && this.imageConfig?.url) { + return this._buildImageURL(new URL(this.imageConfig.url, document.baseURI)); + } + return defaultImage; } @@ -300,13 +352,15 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay } }} @error=${() => { - if (this.imageConfig?.mode === 'camera') { - // In camera mode, the user has likely not made an error, but HA - // may be unavailble, so show the stock image. Don't let the URL - // override the stock image in this case, as this could create an - // error loop if that URL subsequently failed to load. + const mode = this._resolveMode(this.imageConfig?.mode); + if (mode === 'camera' || mode === 'entity') { + // In camera or entity mode, the user has likely not made an + // error, but HA may be unavailble, so show the stock image. + // Don't let the URL override the stock image in this case, as + // this could create an error loop if that URL subsequently + // failed to load. this._forceSafeImage(true); - } else if (this.imageConfig?.mode === 'url') { + } else if (mode === 'url') { // In url mode, the user likely specified a URL that cannot be // resolved. Show an error message. dispatchErrorMessageEvent(this, localize('error.image_load_error'), { diff --git a/src/components/live/live-image.ts b/src/components/live/live-image.ts index a4d20cbd..92c833e1 100644 --- a/src/components/live/live-image.ts +++ b/src/components/live/live-image.ts @@ -64,15 +64,8 @@ export class FrigateCardLiveImage extends LitElement implements FrigateCardMedia return html` diff --git a/src/config/types.ts b/src/config/types.ts index 952777bb..3f7abb28 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -917,25 +917,25 @@ export type PTZControlsConfig = z.infer; // `image` card view. // ************************************************************************* -const imageBaseConfigDefault = { +const imageConfigDefault = { + mode: 'auto' as const, refresh_seconds: 1, }; +const IMAGE_MODES = ['auto', 'camera', 'entity', 'screensaver', 'url'] as const; +export type ImageMode = (typeof IMAGE_MODES)[number]; + const imageBaseConfigSchema = z.object({ + mode: z.enum(IMAGE_MODES).default(imageConfigDefault.mode), + + refresh_seconds: z.number().min(0).default(imageConfigDefault.refresh_seconds), + url: z.string().optional(), - refresh_seconds: z.number().min(0).default(imageBaseConfigDefault.refresh_seconds), + entity: z.string().optional(), + entity_parameters: z.string().optional(), }); -const IMAGE_MODES = ['screensaver', 'camera', 'url'] as const; -const imageConfigDefault = { - mode: 'url' as const, - ...imageBaseConfigDefault, -}; - const imageConfigSchema = imageBaseConfigSchema - .extend({ - mode: z.enum(IMAGE_MODES).default(imageConfigDefault.mode), - }) .merge(actionsSchema) .default(imageConfigDefault); export type ImageViewConfig = z.infer; @@ -1127,8 +1127,6 @@ const go2rtcConfigSchema = z.object({ stream: z.string().optional(), }); -const liveImageConfigSchema = imageBaseConfigSchema; - const webrtcCardConfigSchema = z .object({ entity: z.string().optional(), @@ -1302,9 +1300,6 @@ const cameraConfigDefault = { frigate: { client_id: 'frigate' as const, }, - image: { - refresh_seconds: 1, - }, live_provider: 'auto' as const, motioneye: { images: { @@ -1408,7 +1403,7 @@ export const cameraConfigSchema = z // Live provider options. live_provider: z.enum(LIVE_PROVIDERS).default(cameraConfigDefault.live_provider), go2rtc: go2rtcConfigSchema.optional(), - image: liveImageConfigSchema.default(cameraConfigDefault.image), + image: imageBaseConfigSchema.optional().default(imageConfigDefault), jsmpeg: jsmpegConfigSchema.optional(), webrtc_card: webrtcCardConfigSchema.optional(), diff --git a/src/const.ts b/src/const.ts index 08783be4..c9b1eb9f 100644 --- a/src/const.ts +++ b/src/const.ts @@ -31,6 +31,10 @@ export const CONF_CAMERAS_ARRAY_GO2RTC_STREAM = `${CONF_CAMERAS}.#.go2rtc.stream` as const; export const CONF_CAMERAS_ARRAY_ICON = `${CONF_CAMERAS}.#.icon` as const; export const CONF_CAMERAS_ARRAY_ID = `${CONF_CAMERAS}.#.id` as const; +export const CONF_CAMERAS_ARRAY_IMAGE_ENTITY = `${CONF_CAMERAS}.#.image.entity` as const; +export const CONF_CAMERAS_ARRAY_IMAGE_ENTITY_PARAMETERS = + `${CONF_CAMERAS}.#.image.entity_parameters` as const; +export const CONF_CAMERAS_ARRAY_IMAGE_MODE = `${CONF_CAMERAS}.#.image.mode` as const; export const CONF_CAMERAS_ARRAY_IMAGE_REFRESH_SECONDS = `${CONF_CAMERAS}.#.image.refresh_seconds` as const; export const CONF_CAMERAS_ARRAY_IMAGE_URL = `${CONF_CAMERAS}.#.image.url` as const; @@ -290,6 +294,8 @@ export const CONF_LIVE_MICROPHONE_ALWAYS_CONNECTED = export const CONF_LIVE_ZOOMABLE = `${CONF_LIVE}.zoomable` as const; const CONF_IMAGE = 'image' as const; +export const CONF_IMAGE_ENTITY = `${CONF_IMAGE}.entity` as const; +export const CONF_IMAGE_ENTITY_PARAMETERS = `${CONF_IMAGE}.entity_parameters` as const; export const CONF_IMAGE_MODE = `${CONF_IMAGE}.mode` as const; export const CONF_IMAGE_REFRESH_SECONDS = `${CONF_IMAGE}.refresh_seconds` as const; export const CONF_IMAGE_URL = `${CONF_IMAGE}.url` as const; diff --git a/src/editor.ts b/src/editor.ts index cc2e8318..8b9c0da3 100644 --- a/src/editor.ts +++ b/src/editor.ts @@ -66,6 +66,9 @@ import { CONF_CAMERAS_ARRAY_GO2RTC_STREAM, CONF_CAMERAS_ARRAY_ICON, CONF_CAMERAS_ARRAY_ID, + CONF_CAMERAS_ARRAY_IMAGE_ENTITY, + CONF_CAMERAS_ARRAY_IMAGE_ENTITY_PARAMETERS, + CONF_CAMERAS_ARRAY_IMAGE_MODE, CONF_CAMERAS_ARRAY_IMAGE_REFRESH_SECONDS, CONF_CAMERAS_ARRAY_IMAGE_URL, CONF_CAMERAS_ARRAY_LIVE_PROVIDER, @@ -85,6 +88,8 @@ import { CONF_DIMENSIONS_ASPECT_RATIO_MODE, CONF_DIMENSIONS_MAX_HEIGHT, CONF_DIMENSIONS_MIN_HEIGHT, + CONF_IMAGE_ENTITY, + CONF_IMAGE_ENTITY_PARAMETERS, CONF_IMAGE_MODE, CONF_IMAGE_REFRESH_SECONDS, CONF_IMAGE_URL, @@ -519,9 +524,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor protected _imageModes: EditorSelectOption[] = [ { value: '', label: '' }, - { value: 'camera', label: localize('config.image.modes.camera') }, - { value: 'screensaver', label: localize('config.image.modes.screensaver') }, - { value: 'url', label: localize('config.image.modes.url') }, + { value: 'camera', label: localize('config.common.image.modes.camera') }, + { value: 'entity', label: localize('config.common.image.modes.entity') }, + { value: 'screensaver', label: localize('config.common.image.modes.screensaver') }, + { value: 'url', label: localize('config.common.image.modes.url') }, ]; protected _timelineEventsMediaTypes: EditorSelectOption[] = [ @@ -1733,6 +1739,36 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ); } + protected _renderImageOptions( + configPathMode: string, + configPathUrl: string, + configPathEntity: string, + configPathEntityParameters: string, + configPathRefreshSeconds: string, + ): TemplateResult { + return html` + ${this._renderOptionSelector(configPathMode, this._imageModes, { + label: localize('config.common.image.mode'), + })} + ${this._renderStringInput(configPathUrl, { + label: localize('config.common.image.url'), + })} + ${this._renderOptionSelector( + configPathEntity, + this.hass ? getEntitiesFromHASS(this.hass) : [], + { + label: localize('config.common.image.entity'), + }, + )} + ${this._renderStringInput(configPathEntityParameters, { + label: localize('config.common.image.entity_parameters'), + })} + ${this._renderNumberInput(configPathRefreshSeconds, { + label: localize('config.common.image.refresh_seconds'), + })} + `; + } + /** * Render a camera section. * @param cameras The full array of cameras. @@ -2006,17 +2042,19 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor true, 'config.cameras.image.editor_label', { name: 'mdi:image' }, - html` - ${this._renderNumberInput( - getArrayConfigPath( - CONF_CAMERAS_ARRAY_IMAGE_REFRESH_SECONDS, - cameraIndex, - ), - )} - ${this._renderStringInput( - getArrayConfigPath(CONF_CAMERAS_ARRAY_IMAGE_URL, cameraIndex), - )} - `, + this._renderImageOptions( + getArrayConfigPath(CONF_CAMERAS_ARRAY_IMAGE_MODE, cameraIndex), + getArrayConfigPath(CONF_CAMERAS_ARRAY_IMAGE_URL, cameraIndex), + getArrayConfigPath(CONF_CAMERAS_ARRAY_IMAGE_ENTITY, cameraIndex), + getArrayConfigPath( + CONF_CAMERAS_ARRAY_IMAGE_ENTITY_PARAMETERS, + cameraIndex, + ), + getArrayConfigPath( + CONF_CAMERAS_ARRAY_IMAGE_REFRESH_SECONDS, + cameraIndex, + ), + ), )} ${this._putInSubmenu( MENU_CAMERAS_WEBRTC_CARD, @@ -2725,9 +2763,13 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor ${this._renderOptionSetHeader('image')} ${this._expandedMenus[MENU_OPTIONS] === 'image' ? html`

      - ${this._renderOptionSelector(CONF_IMAGE_MODE, this._imageModes)} - ${this._renderStringInput(CONF_IMAGE_URL)} - ${this._renderNumberInput(CONF_IMAGE_REFRESH_SECONDS)} + ${this._renderImageOptions( + CONF_IMAGE_MODE, + CONF_IMAGE_URL, + CONF_IMAGE_ENTITY, + CONF_IMAGE_ENTITY_PARAMETERS, + CONF_IMAGE_REFRESH_SECONDS, + )}
      ` : ''} ${this._renderOptionSetHeader('timeline')} diff --git a/src/localize/languages/ca.json b/src/localize/languages/ca.json index 27a008ef..01521890 100644 --- a/src/localize/languages/ca.json +++ b/src/localize/languages/ca.json @@ -219,6 +219,19 @@ "grid_selected_width_factor": "Augmenta l'amplada del suport multimèdia seleccionat en aquest factor", "mode": "Mode" }, + "image": { + "entity": "", + "entity_parameters": "", + "mode": "Mode de visualització d'imatges", + "modes": { + "camera": "Instantània de l'entitat de la càmera de Home Assistant", + "entity": "", + "screensaver": "Logotip de Frigate incrustat", + "url": "Imatge arbitrària especificada per URL" + }, + "refresh_seconds": "Nombre de segons després dels quals cal actualitzar (0=mai)", + "url": "URL d'imatge estàtica per a la visualització d'imatges" + }, "media_action_conditions": { "all": "Totes les oportunitats", "hidden": "A l'amagat del navegador/pestanya", @@ -257,17 +270,6 @@ "max_height": "Alçada màxima de la targeta en unitats CSS (p. ex., '100vh')", "min_height": "Alçada mínima de la targeta en unitats CSS (p. ex., '100 px')" }, - "image": { - "mode": "Mode de visualització d'imatges", - "modes": { - "camera": "Instantània de l'entitat de la càmera de Home Assistant", - "screensaver": "Logotip de Frigate incrustat", - "url": "Imatge arbitrària especificada per URL" - }, - "refresh_seconds": "Nombre de segons després dels quals cal actualitzar (0=mai)", - "url": "URL d'imatge estàtica per a la visualització d'imatges", - "zoomable": "La imatge es pot ampliar/escombrar" - }, "live": { "auto_mute": "Silencia automàticament les càmeres en directe", "auto_pause": "Posa en pausa automàticament les càmeres en directe", diff --git a/src/localize/languages/en.json b/src/localize/languages/en.json index f2279649..692edddf 100644 --- a/src/localize/languages/en.json +++ b/src/localize/languages/en.json @@ -219,6 +219,19 @@ "grid_selected_width_factor": "Increase selected media width by this factor", "mode": "Mode" }, + "image": { + "entity": "Entity for use with entity mode", + "entity_parameters": "Query parameters added to the entity-based picture URLs (e.g. width=1920&height=1080)", + "mode": "Image mode", + "modes": { + "camera": "Home Assistant camera snapshot of camera entity", + "entity": "Entity with entity_picture attribute", + "screensaver": "Embedded Frigate logo", + "url": "Arbitrary image specified by URL" + }, + "refresh_seconds": "Number of seconds after which to refresh (0=never)", + "url": "Static image URL" + }, "media_action_conditions": { "all": "All opportunities", "hidden": "On browser/tab hiding", @@ -257,17 +270,6 @@ "max_height": "Maximum card height in CSS units (e.g. '100vh')", "min_height": "Minimum card height in CSS units (e.g. '100px')" }, - "image": { - "mode": "Image view mode", - "modes": { - "camera": "Home Assistant camera snapshot of camera entity", - "screensaver": "Embedded Frigate logo", - "url": "Arbitrary image specified by URL" - }, - "refresh_seconds": "Number of seconds after which to refresh (0=never)", - "url": "Static image URL for image view", - "zoomable": "Image can be zoomed/panned" - }, "live": { "auto_mute": "Automatically mute live cameras", "auto_pause": "Automatically pause live cameras", diff --git a/src/localize/languages/fr.json b/src/localize/languages/fr.json index 89128777..981d9524 100644 --- a/src/localize/languages/fr.json +++ b/src/localize/languages/fr.json @@ -219,6 +219,19 @@ "grid_selected_width_factor": "Augmenter la largeur du média sélectionnée par ce facteur", "mode": "Mode" }, + "image": { + "entity": "", + "entity_parameters": "", + "mode": "Mode d'affichage des images", + "modes": { + "camera": "Instantané de la caméra Home Assistant de l'entité caméra", + "entity": "", + "screensaver": "Logo Frigate intégré", + "url": "Image arbitraire spécifiée par URL" + }, + "refresh_seconds": "Nombre de secondes après lesquelles actualiser (0=jamais)", + "url": "URL d'image statique pour l'affichage de l'image" + }, "media_action_conditions": { "all": "Toutes les opportunités", "hidden": "Sur le navigateur/onglet masqué", @@ -257,17 +270,6 @@ "max_height": "Hauteur maximale de la carte en unités CSS (par exemple '100vh')", "min_height": "Hauteur minimale de la carte en unités CSS (par exemple « 100 px »)" }, - "image": { - "mode": "Mode d'affichage des images", - "modes": { - "camera": "Instantané de la caméra Home Assistant de l'entité caméra", - "screensaver": "Logo Frigate intégré", - "url": "Image arbitraire spécifiée par URL" - }, - "refresh_seconds": "Nombre de secondes après lesquelles actualiser (0=jamais)", - "url": "URL d'image statique pour l'affichage de l'image", - "zoomable": "L'image peut être zoomée/panoramique" - }, "live": { "auto_mute": "Couper automatiquement le son des caméras en direct", "auto_pause": "Mettre automatiquement en pause les caméras en direct", diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index a87f9b75..5423350e 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -219,6 +219,19 @@ "grid_selected_width_factor": "", "mode": "" }, + "image": { + "entity": "", + "entity_parameters": "", + "mode": "Modalità Visualizza immagine", + "modes": { + "camera": "Istantanea della telecamera di Home Assistant dell'entità telecamera", + "entity": "", + "screensaver": "Logo Frigate incorporato", + "url": "Immagine arbitraria specificata dall'URL" + }, + "refresh_seconds": "Numero di secondi dopo i quali aggiornare (0 = mai)", + "url": "URL di immagine statica per la vista dell'immagine" + }, "media_action_conditions": { "all": "Tutte le opportunità", "hidden": "Sul browser/nascondere le schede", @@ -257,17 +270,6 @@ "max_height": "", "min_height": "" }, - "image": { - "mode": "Modalità Visualizza immagine", - "modes": { - "camera": "Istantanea della telecamera di Home Assistant dell'entità telecamera", - "screensaver": "Logo Frigate incorporato", - "url": "Immagine arbitraria specificata dall'URL" - }, - "refresh_seconds": "Numero di secondi dopo i quali aggiornare (0 = mai)", - "url": "URL di immagine statica per la vista dell'immagine", - "zoomable": "" - }, "live": { "auto_mute": "Muta automaticamente le telecamere in diretta", "auto_pause": "Metti in pausa automaticamente le telecamere in diretta", diff --git a/src/localize/languages/pt-BR.json b/src/localize/languages/pt-BR.json index 2fac32db..c54f68fe 100644 --- a/src/localize/languages/pt-BR.json +++ b/src/localize/languages/pt-BR.json @@ -219,6 +219,19 @@ "grid_selected_width_factor": "", "mode": "" }, + "image": { + "entity": "", + "entity_parameters": "", + "mode": "Modo de visualização de imagem", + "modes": { + "camera": "Instantâneo da câmera do Home Assistant, da entidade de câmera", + "entity": "", + "screensaver": "Logo Frigate embutido", + "url": "Imagem arbitrária especificada por URL" + }, + "refresh_seconds": "Número de segundos após o qual atualizar (0 = nunca)", + "url": "Imagem arbitrária especificada por URL" + }, "media_action_conditions": { "all": "Todas as oportunidades", "hidden": "Ao ocultar o navegador/aba", @@ -257,17 +270,6 @@ "max_height": "", "min_height": "" }, - "image": { - "mode": "Modo de visualização de imagem", - "modes": { - "camera": "Instantâneo da câmera do Home Assistant, da entidade de câmera", - "screensaver": "Logo Frigate embutido", - "url": "Imagem arbitrária especificada por URL" - }, - "refresh_seconds": "Número de segundos após o qual atualizar (0 = nunca)", - "url": "Imagem arbitrária especificada por URL", - "zoomable": "" - }, "live": { "auto_mute": "Silenciar câmeras ao vivo automaticamente", "auto_pause": "Pausar câmeras ao vivo automaticamente", diff --git a/src/localize/languages/pt-PT.json b/src/localize/languages/pt-PT.json index 7fdb3de5..10655859 100644 --- a/src/localize/languages/pt-PT.json +++ b/src/localize/languages/pt-PT.json @@ -219,6 +219,19 @@ "grid_selected_width_factor": "", "mode": "" }, + "image": { + "entity": "", + "entity_parameters": "", + "mode": "Modo de visualização de imagem", + "modes": { + "camera": "Instantâneo da câmera do Home Assistant, da entidade de câmera", + "entity": "", + "screensaver": "Logo Frigate embutido", + "url": "Imagem arbitrária especificada por URL" + }, + "refresh_seconds": "Número de segundos após o qual atualizar (0 = nunca)", + "url": "Imagem arbitrária especificada por URL" + }, "media_action_conditions": { "all": "Todas as oportunidades", "hidden": "Ao ocultar o navegador/aba", @@ -257,17 +270,6 @@ "max_height": "", "min_height": "" }, - "image": { - "mode": "Modo de visualização de imagem", - "modes": { - "camera": "Instantâneo da câmera do Home Assistant, da entidade de câmera", - "screensaver": "Logo Frigate embutido", - "url": "Imagem arbitrária especificada por URL" - }, - "refresh_seconds": "Número de segundos após o qual atualizar (0 = nunca)", - "url": "Imagem arbitrária especificada por URL", - "zoomable": "" - }, "live": { "auto_mute": "Silenciar câmeras ao vivo automaticamente", "auto_pause": "Parar câmeras ao vivo automaticamente", diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index cd313042..aa6bb356 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -24,6 +24,7 @@ describe('config defaults', () => { client_id: 'frigate', }, image: { + mode: 'auto', refresh_seconds: 1, }, live_provider: 'auto', @@ -58,7 +59,7 @@ describe('config defaults', () => { min_height: '100px', }, image: { - mode: 'url', + mode: 'auto', refresh_seconds: 1, }, live: { From 120eca1c78c9efe708d63bffcd200ed3e6bdc02b Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 8 Sep 2024 16:52:36 -0700 Subject: [PATCH 180/189] Remove superfluous whitespace. --- src/localize/languages/it.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/localize/languages/it.json b/src/localize/languages/it.json index 5423350e..b0a0a09e 100644 --- a/src/localize/languages/it.json +++ b/src/localize/languages/it.json @@ -231,7 +231,7 @@ }, "refresh_seconds": "Numero di secondi dopo i quali aggiornare (0 = mai)", "url": "URL di immagine statica per la vista dell'immagine" - }, + }, "media_action_conditions": { "all": "Tutte le opportunità", "hidden": "Sul browser/nascondere le schede", From 6fc4900c502599f872cbfd634053d78535bbd51b Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 8 Sep 2024 19:51:50 -0700 Subject: [PATCH 181/189] Block noisy console spam on build. --- .yarn/patches/README.md | 7 +++++++ .yarn/patches/sass-npm-1.77.4-13b6910aea.patch | 13 +++++++++++++ package.json | 2 +- yarn.lock | 17 +++++++++++++++-- 4 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 .yarn/patches/README.md create mode 100644 .yarn/patches/sass-npm-1.77.4-13b6910aea.patch diff --git a/.yarn/patches/README.md b/.yarn/patches/README.md new file mode 100644 index 00000000..addf62dc --- /dev/null +++ b/.yarn/patches/README.md @@ -0,0 +1,7 @@ +# Patches + +## `sass` + +`sass` is patched to avoid printing out a noisy deprecation notice on every +build. `sass` is imported by `rollup-plugin-styler`, in a way that triggers this +message. The patch simply prevents this console spam. \ No newline at end of file diff --git a/.yarn/patches/sass-npm-1.77.4-13b6910aea.patch b/.yarn/patches/sass-npm-1.77.4-13b6910aea.patch new file mode 100644 index 00000000..fe873bfd --- /dev/null +++ b/.yarn/patches/sass-npm-1.77.4-13b6910aea.patch @@ -0,0 +1,13 @@ +diff --git a/sass.node.mjs b/sass.node.mjs +index f59a3d8987162a3cbc9787c34f67186fb0f09186..b154f46118ccc03989b9a1c11309954c85515539 100644 +--- a/sass.node.mjs ++++ b/sass.node.mjs +@@ -40,7 +40,7 @@ export const NodePackageImporter = cjs.NodePackageImporter; + export const deprecations = cjs.deprecations; + export const Version = cjs.Version; + +-let printedDefaultExportDeprecation = false; ++let printedDefaultExportDeprecation = true; + function defaultExportDeprecation() { + if (printedDefaultExportDeprecation) return; + printedDefaultExportDeprecation = true; diff --git a/package.json b/package.json index 9b7ac717..302f5a78 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ "rollup-plugin-serve": "^1.1.1", "rollup-plugin-styler": "^1.8.0", "rollup-plugin-visualizer": "^5.12.0", - "sass": "^1.77.4", + "sass": "patch:sass@npm%3A1.77.4#~/.yarn/patches/sass-npm-1.77.4-13b6910aea.patch", "ts-prune": "^0.10.3", "type-fest": "^4.20.0", "typescript": "^5.4.5", diff --git a/yarn.lock b/yarn.lock index 7de17cfc..db2e71bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4123,7 +4123,7 @@ __metadata: rollup-plugin-serve: "npm:^1.1.1" rollup-plugin-styler: "npm:^1.8.0" rollup-plugin-visualizer: "npm:^5.12.0" - sass: "npm:^1.77.4" + sass: "patch:sass@npm%3A1.77.4#~/.yarn/patches/sass-npm-1.77.4-13b6910aea.patch" screenfull: "npm:^6.0.2" side-drawer: "npm:^3.1.0" ts-prune: "npm:^0.10.3" @@ -7671,7 +7671,7 @@ __metadata: languageName: node linkType: hard -"sass@npm:^1.77.4": +"sass@npm:1.77.4": version: 1.77.4 resolution: "sass@npm:1.77.4" dependencies: @@ -7684,6 +7684,19 @@ __metadata: languageName: node linkType: hard +"sass@patch:sass@npm%3A1.77.4#~/.yarn/patches/sass-npm-1.77.4-13b6910aea.patch": + version: 1.77.4 + resolution: "sass@patch:sass@npm%3A1.77.4#~/.yarn/patches/sass-npm-1.77.4-13b6910aea.patch::version=1.77.4&hash=0f2bd0" + dependencies: + chokidar: "npm:>=3.0.0 <4.0.0" + immutable: "npm:^4.0.0" + source-map-js: "npm:>=0.6.2 <2.0.0" + bin: + sass: sass.js + checksum: 10c0/39f768553fa1a29e4cfc11b672080c1a29a6b2565378ba0cca6b56604fb40db2d25dc224cbfcfac4caf0d448a154dae1fdfd1cd674a2f8396548ea8c0a43f868 + languageName: node + linkType: hard + "sax@npm:^1.2.4": version: 1.3.0 resolution: "sax@npm:1.3.0" From edb6531fed5fe26d520766945062f2bca23fa7b5 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Sun, 8 Sep 2024 19:55:48 -0700 Subject: [PATCH 182/189] Fix styling issues. --- .yarn/patches/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.yarn/patches/README.md b/.yarn/patches/README.md index addf62dc..2d835449 100644 --- a/.yarn/patches/README.md +++ b/.yarn/patches/README.md @@ -4,4 +4,4 @@ `sass` is patched to avoid printing out a noisy deprecation notice on every build. `sass` is imported by `rollup-plugin-styler`, in a way that triggers this -message. The patch simply prevents this console spam. \ No newline at end of file +message. The patch simply prevents this console spam. From a0283c35c1bf62ecc58385cb49776bae36188655 Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Mon, 9 Sep 2024 22:05:49 -0700 Subject: [PATCH 183/189] Add support for `perform-action` calls. --- docs/configuration/actions/stock/README.md | 22 ++++ docs/configuration/cameras/README.md | 22 ++-- docs/examples.md | 8 +- package.json | 4 +- rollup.config.js | 1 - src/components/image.ts | 2 +- src/components/submenu.ts | 8 +- src/config/management.ts | 29 +++++ src/config/types.ts | 68 +++++++---- tests/camera-manager/manager.test.ts | 4 +- tests/camera-manager/utils/ptz.test.ts | 8 +- tests/config/management.test.ts | 134 +++++++++++++++------ tests/config/types.test.ts | 20 +-- yarn.lock | 29 ++--- 14 files changed, 247 insertions(+), 112 deletions(-) diff --git a/docs/configuration/actions/stock/README.md b/docs/configuration/actions/stock/README.md index d8458d03..83fbbb4d 100644 --- a/docs/configuration/actions/stock/README.md +++ b/docs/configuration/actions/stock/README.md @@ -4,6 +4,8 @@ Call a service. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). +!> Home Assistant has deprecated the `call-service` action, please use [`perform-action`](#perform-action) instead. + ```yaml action: call-service # [...] @@ -27,6 +29,15 @@ action: navigate # [...] ``` +## `perform-action` + +Perform a Home Assistant action. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). + +```yaml +action: perform-action +# [...] +``` + ## `toggle` Toggle an entity. See [Home Assistant actions documentation](https://www.home-assistant.io/dashboards/actions/). @@ -117,4 +128,15 @@ elements: tap_action: action: fire-dom-event key: value + - type: icon + icon: mdi:numeric-8-box + title: Perform action + style: + left: 200px + top: 400px + tap_action: + action: perform-action + perform_action: homeassistant.toggle + target: + entity_id: light.office_main_lights ``` diff --git a/docs/configuration/cameras/README.md b/docs/configuration/cameras/README.md index af6d895b..78c2556e 100644 --- a/docs/configuration/cameras/README.md +++ b/docs/configuration/cameras/README.md @@ -210,8 +210,8 @@ the integration currently offers. | Option | Default | Description | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `actions_left`, `actions_right`, `actions_up`, `actions_down`, `actions_zoom_in`, `actions_zoom_out`, `actions_home` | Set by camera [engine](./engine.md) of the selected camera | The [call-service](../actions/stock/README.md?id=call-service) action that will be called for each PTZ action for relative movements. | -| `actions_left_start`, `actions_left_stop`, `actions_right_start`, `actions_right_stop`,`actions_up_start`, `actions_up_stop`,`actions_down_start`, `actions_down_stop`,`actions_zoom_in_start`, `actions_zoom_in_stop`,`actions_zoom_out_start`, `actions_zoom_out_stop` | Set by camera [engine](./engine.md) of the selected camera | The [call-service](../actions/stock/README.md?id=call-service) action that will be called for each PTZ action for continous movements. Both a `_start` and `_stop` variety must be provided for an action to be usable. | +| `actions_left`, `actions_right`, `actions_up`, `actions_down`, `actions_zoom_in`, `actions_zoom_out`, `actions_home` | Set by camera [engine](./engine.md) of the selected camera | The [perform-action](../actions/stock/README.md?id=perform-action) action that will be called for each PTZ action for relative movements. | +| `actions_left_start`, `actions_left_stop`, `actions_right_start`, `actions_right_stop`,`actions_up_start`, `actions_up_stop`,`actions_down_start`, `actions_down_stop`,`actions_zoom_in_start`, `actions_zoom_in_stop`,`actions_zoom_out_start`, `actions_zoom_out_stop` | Set by camera [engine](./engine.md) of the selected camera | The [perform-action](../actions/stock/README.md?id=perform-action) action that will be called for each PTZ action for continous movements. Both a `_start` and `_stop` variety must be provided for an action to be usable. | | `c2r_delay_between_calls_seconds` | `0.2` | When the camera is configured with continuous actions only (e.g. `left_start` and `left_stop`, but not `left`), if something requests a relative action (e.g. a manually configured [action](../actions/README.md)), then `start` will be called, followed by a delay of this number of seconds and finally `stop` will be called. Cameras / integrations that are slower to respond to continuous steps may need to increase this value to avoid the continuous motion being too small. Cameras / integrations that are rapid to respond may need to decrease this value to avoid the "relative step" being too large. | | `data_left`, `data_right`, `data_up`, `data_down`, `data_zoom_in`, `data_zoom_out`, `data_home` | | Shorthand for relative actions that call the service defined by the `service` parameter, with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[action]`. If both `actions_X` and `data_X` are specified, `actions_X` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). | | `data_left_start`, `data_left_stop`, `data_right_start`, `data_right_stop`, `data_up_start`, `data_up_stop`, `data_down_start`, `data_down_stop`, `data_zoom_in_start`, `data_zoom_in_stop`, `data_zoom_out_start`, `data_zoom_out_stop` | | Shorthand for continuous actions that call the service defined by the `service` parameter, with the data provided in this argument. Internally, this is just translated into the longer-form `actions_[action]_start` and `actions_[action]_stop`. If both `actions_X_*` and `data_X_*` are specified, `actions_X_*` takes priority. This is compatible with [AlexxIT's WebRTC Card PTZ configuration](https://github.com/AlexxIT/WebRTC/wiki/PTZ-Config-Examples). Both a `_start` and `_stop` variety must be provided for an action to be usable. | @@ -232,7 +232,7 @@ cameras: ? [action] ``` -`[action]` is any [call-service](../actions/stock/README.md?id=call-service) action. +`[action]` is any [perform-action](../actions/stock/README.md?id=perform-action) action. ## `triggers` @@ -382,22 +382,22 @@ cameras: r2c_delay_between_calls_seconds: 0.5 # Relative action (only `left` shown) actions_left: - action: call-service - service: service.of_your_choice + action: perform-action + perform_action: service.of_your_choice data: device: '048123' cmd: left # Continuous action (only `right` shown) actions_right_start: - action: call-service - service: service.of_your_choice + action: perform-action + perform_action: service.of_your_choice data: device: '048123' cmd: right phase: start actions_right_stop: - action: call-service - service: service.of_your_choice + action: perform-action + perform_action: service.of_your_choice data: device: '048123' phase: stop @@ -419,8 +419,8 @@ cameras: presets: # Preset using long form. armchair: - action: call-service - service: service.of_your_choice + action: perform-action + perform_action: service.of_your_choice data: device: '048123' cmd: preset diff --git a/docs/examples.md b/docs/examples.md index fb23a028..cdf29974 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -205,7 +205,7 @@ elements: right: 25px bottom: 50px tap_action: - action: call-service + action: perform-action service: amcrest.ptz_control data: entity_id: camera.kitchen @@ -252,9 +252,9 @@ elements: style: color: red tap_action: - action: call-service - service: homeassistant.toggle - data: + action: perform-action + perform_action: homeassistant.toggle + target: entity_id: siren.siren conditions: - condition: triggered diff --git a/package.json b/package.json index 302f5a78..b85b3521 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "license": "MIT", "dependencies": { "@cycjimmy/jsmpeg-player": "^6.0.5", - "@dermotduffy/custom-card-helpers": "^1.9.0", + "@dermotduffy/custom-card-helpers": "^1.9.1", "@dermotduffy/panzoom": "^4.5.1", "@egjs/hammerjs": "^2.0.17", "@graphiteds/core": "^1.9.21", @@ -29,7 +29,7 @@ "date-fns-tz": "^3.1.3", "embla-carousel": "^8.1.4", "embla-carousel-wheel-gestures": "^8.0.1", - "home-assistant-js-websocket": "^8.2.0", + "home-assistant-js-websocket": "^9.4.0", "keycharm": "^0.4.0", "lit": "^3.1.4", "lodash-es": "^4.17.21", diff --git a/rollup.config.js b/rollup.config.js index faa6e37a..b8701d18 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -101,7 +101,6 @@ const config = { moduleContext: { './node_modules/@formatjs/intl-utils/lib/src/diff.js': 'window', './node_modules/@formatjs/intl-utils/lib/src/resolve-locale.js': 'window', - './node_modules/flatpickr/dist/esm/index.js': 'window', }, }; diff --git a/src/components/image.ts b/src/components/image.ts index c731a299..fecb17f4 100644 --- a/src/components/image.ts +++ b/src/components/image.ts @@ -131,7 +131,7 @@ export class FrigateCardImage extends LitElement implements FrigateCardMediaPlay this._cachedValueController?.clearValue(); return true; } - return false; + return !this.hasUpdated; } return true; } diff --git a/src/components/submenu.ts b/src/components/submenu.ts index 4d36e1e0..4bc361f0 100644 --- a/src/components/submenu.ts +++ b/src/components/submenu.ts @@ -229,12 +229,14 @@ export class FrigateCardSubmenuSelect extends LitElement { title: title || option, ...((entityID.startsWith('select.') || entityID.startsWith('input_select.')) && { tap_action: { - action: 'call-service', - service: entityID.startsWith('select.') + action: 'perform-action', + perform_action: entityID.startsWith('select.') ? 'select.select_option' : 'input_select.select_option', - data: { + target: { entity_id: entityID, + }, + data: { option: option, }, }, diff --git a/src/config/management.ts b/src/config/management.ts index 9110fa4b..570b0f91 100644 --- a/src/config/management.ts +++ b/src/config/management.ts @@ -446,6 +446,21 @@ const conditionToConditionsTransform = (data: unknown): boolean => { return false; }; +const callServiceToPerformActionTransform = (data: unknown): boolean => { + if ( + typeof data !== 'object' || + !data || + data['action'] !== 'call-service' || + typeof data['service'] !== 'string' + ) { + return false; + } + data['action'] = 'perform-action'; + data['perform_action'] = data['service']; + delete data['service']; + return true; +}; + /** * Transform service_data -> data * See: https://github.com/dermotduffy/frigate-hass-card/issues/1103 @@ -849,4 +864,18 @@ const UPGRADES = [ }), deleteWithOverrides('live.controls.title'), deleteWithOverrides('media_viewer.controls.title'), + + // Upgrade call-service calls throughout the card config. They could show up + // attached to any element, any automation, or any card/view action (i.e. very + // broadly across the config), so it's challenging to better target this + // upgrade. As written, this will convert things that look like call-service + // calls recurseively throughout the whole card config, but this could + // conceivably be an overreach if (e.g.) some totally unrelated object has { + // action: 'call-service', service: '' } that means something + // different. + (data: unknown): boolean => { + return upgradeObjectRecursively(callServiceToPerformActionTransform)( + typeof data === 'object' && data ? (data as RawFrigateCardConfig) : {}, + ); + }, ]; diff --git a/src/config/types.ts b/src/config/types.ts index 3f7abb28..4a6f3056 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -4,9 +4,11 @@ import { MoreInfoActionConfig, NavigateActionConfig, NoActionConfig, + PerformActionActionConfig, ToggleActionConfig, UrlActionConfig, } from '@dermotduffy/custom-card-helpers'; +import { HassServiceTarget } from 'home-assistant-js-websocket'; import { z } from 'zod'; import { MEDIA_CHUNK_SIZE_DEFAULT, MEDIA_CHUNK_SIZE_MAX } from '../const.js'; import { capabilityKeys } from '../types.js'; @@ -168,6 +170,28 @@ const toggleActionSchema = schemaForType< }), ); +const targetSchema = schemaForType()( + z.object({ + entity_id: z.string().optional(), + device_id: z.string().optional(), + area_id: z.string().optional(), + }), +); + +const performActionActionSchema = schemaForType< + PerformActionActionConfig & ExtendedConfirmationRestrictionConfig +>()( + actionBaseSchema.extend({ + action: z.literal('perform-action'), + perform_action: z.string(), + data: z.object({}).passthrough().optional(), + target: targetSchema.optional(), + }), +); + +// Note: call-service is deprecated and will eventually go away. Please use +// perform-action instead. +// See: https://www.home-assistant.io/blog/2024/08/07/release-20248/#goodbye-service-calls-hello-actions- const callServiceActionSchema = schemaForType< CallServiceActionConfig & ExtendedConfirmationRestrictionConfig >()( @@ -175,6 +199,7 @@ const callServiceActionSchema = schemaForType< action: z.literal('call-service'), service: z.string(), data: z.object({}).passthrough().optional(), + target: targetSchema.optional(), }), ); @@ -391,6 +416,7 @@ export type FrigateCardCustomAction = z.infer const name = match?.[1]; if (name && !(`${suffix}${name}` in data)) { out[`${suffix}${name}`] = { - action: 'call-service', - service: data['service'], + action: 'perform-action', + perform_action: data['service'], data: data[key], }; delete out[key]; @@ -830,29 +856,29 @@ const ptzCameraConfigSchema = z.preprocess( dataPTZFormatToFullFormat('actions_'), z .object({ - actions_left: callServiceActionSchema.optional(), - actions_left_start: callServiceActionSchema.optional(), - actions_left_stop: callServiceActionSchema.optional(), + actions_left: performActionActionSchema.optional(), + actions_left_start: performActionActionSchema.optional(), + actions_left_stop: performActionActionSchema.optional(), - actions_right: callServiceActionSchema.optional(), - actions_right_start: callServiceActionSchema.optional(), - actions_right_stop: callServiceActionSchema.optional(), + actions_right: performActionActionSchema.optional(), + actions_right_start: performActionActionSchema.optional(), + actions_right_stop: performActionActionSchema.optional(), - actions_up: callServiceActionSchema.optional(), - actions_up_start: callServiceActionSchema.optional(), - actions_up_stop: callServiceActionSchema.optional(), + actions_up: performActionActionSchema.optional(), + actions_up_start: performActionActionSchema.optional(), + actions_up_stop: performActionActionSchema.optional(), - actions_down: callServiceActionSchema.optional(), - actions_down_start: callServiceActionSchema.optional(), - actions_down_stop: callServiceActionSchema.optional(), + actions_down: performActionActionSchema.optional(), + actions_down_start: performActionActionSchema.optional(), + actions_down_stop: performActionActionSchema.optional(), - actions_zoom_in: callServiceActionSchema.optional(), - actions_zoom_in_start: callServiceActionSchema.optional(), - actions_zoom_in_stop: callServiceActionSchema.optional(), + actions_zoom_in: performActionActionSchema.optional(), + actions_zoom_in_start: performActionActionSchema.optional(), + actions_zoom_in_stop: performActionActionSchema.optional(), - actions_zoom_out: callServiceActionSchema.optional(), - actions_zoom_out_start: callServiceActionSchema.optional(), - actions_zoom_out_stop: callServiceActionSchema.optional(), + actions_zoom_out: performActionActionSchema.optional(), + actions_zoom_out_start: performActionActionSchema.optional(), + actions_zoom_out_stop: performActionActionSchema.optional(), // The number of seconds between subsequent relative calls when converting a // relative request into a continuous request. @@ -870,7 +896,7 @@ const ptzCameraConfigSchema = z.preprocess( .preprocess( dataPTZFormatToFullFormat(''), z.union([ - z.record(callServiceActionSchema), + z.record(performActionActionSchema), // This is used by the data_ style of action. z.object({ service: z.string().optional() }), diff --git a/tests/camera-manager/manager.test.ts b/tests/camera-manager/manager.test.ts index 545235b3..39e2e8f1 100644 --- a/tests/camera-manager/manager.test.ts +++ b/tests/camera-manager/manager.test.ts @@ -1120,8 +1120,8 @@ describe('CameraManager', async () => { const hass = createHASS(); vi.mocked(api.getHASSManager().getHASS).mockReturnValue(hass); const action = { - action: 'call-service' as const, - service: 'service', + action: 'perform-action' as const, + perform_action: 'action', }; const manager = createCameraManager(api, engine, [ { diff --git a/tests/camera-manager/utils/ptz.test.ts b/tests/camera-manager/utils/ptz.test.ts index 32470596..a7bafc34 100644 --- a/tests/camera-manager/utils/ptz.test.ts +++ b/tests/camera-manager/utils/ptz.test.ts @@ -1,15 +1,15 @@ -import { describe, expect, it, vi } from 'vitest'; +import { describe, expect, it } from 'vitest'; import { getConfiguredPTZAction, getConfiguredPTZMovementType, getPTZCapabilitiesFromCameraConfig, } from '../../../src/camera-manager/utils/ptz'; -import { createCameraConfig } from '../../test-utils'; import { PTZAction } from '../../../src/config/ptz'; +import { createCameraConfig } from '../../test-utils'; const action = { - action: 'call-service' as const, - service: 'service', + action: 'perform-action' as const, + perform_action: 'action', data: { device: '048123', cmd: 'preset', diff --git a/tests/config/management.test.ts b/tests/config/management.test.ts index be8da942..7595b3de 100644 --- a/tests/config/management.test.ts +++ b/tests/config/management.test.ts @@ -21,6 +21,7 @@ import { import { PTZControlAction } from '../../src/config/ptz'; import { Actions, + PerformActionActionConfig, RawFrigateCardConfig, frigateCardConfigSchema, } from '../../src/config/types'; @@ -752,8 +753,8 @@ describe('should handle version specific upgrades', () => { color: 'white', }, tap_action: { - action: 'call-service', - service: 'notify.persistent_notification', + action: 'perform-action', + perform_action: 'notify.persistent_notification', data: { message: 'Hello 1', }, @@ -773,15 +774,15 @@ describe('should handle version specific upgrades', () => { view: { actions: { double_tap_action: { - action: 'call-service', - service: 'notify.persistent_notification', + action: 'perform-action', + perform_action: 'notify.persistent_notification', data: { message: 'Hello 2', }, }, hold_action: { - action: 'call-service', - service: 'notify.persistent_notification', + action: 'perform-action', + perform_action: 'notify.persistent_notification', data: { message: 'Hello 3', }, @@ -812,7 +813,7 @@ describe('should handle version specific upgrades', () => { }); describe('should move PTZ elements to live', () => { - it('case with 1 element', () => { + it('xxx case with 1 element', () => { const config = { type: 'custom:frigate-card', cameras: [{ camera_entity: 'camera.office' }], @@ -843,11 +844,11 @@ describe('should handle version specific upgrades', () => { cameras_global: { ptz: { actions_up: { - action: 'call-service', + action: 'perform-action', data: { message: 'Hello 1', }, - service: 'notify.persistent_notification', + perform_action: 'notify.persistent_notification', }, }, }, @@ -907,11 +908,11 @@ describe('should handle version specific upgrades', () => { cameras_global: { ptz: { actions_up: { - action: 'call-service', + action: 'perform-action', data: { message: 'Hello 1', }, - service: 'notify.persistent_notification', + perform_action: 'notify.persistent_notification', }, }, }, @@ -1000,11 +1001,11 @@ describe('should handle version specific upgrades', () => { cameras_global: { ptz: { actions_up: { - action: 'call-service', + action: 'perform-action', data: { message: 'Hello 1', }, - service: 'notify.persistent_notification', + perform_action: 'notify.persistent_notification', }, }, }, @@ -1073,11 +1074,11 @@ describe('should handle version specific upgrades', () => { cameras_global: { ptz: { actions_up: { - action: 'call-service', + action: 'perform-action', data: { message: 'Hello 1', }, - service: 'notify.persistent_notification', + perform_action: 'notify.persistent_notification', }, }, }, @@ -1160,11 +1161,11 @@ describe('should handle version specific upgrades', () => { cameras_global: { ptz: { actions_up: { - action: 'call-service', + action: 'perform-action', data: { message: 'Hello 1', }, - service: 'notify.persistent_notification', + perform_action: 'notify.persistent_notification', }, }, }, @@ -1237,11 +1238,11 @@ describe('should handle version specific upgrades', () => { cameras_global: { ptz: { actions_up: { - action: 'call-service', + action: 'perform-action', data: { message: 'Original', }, - service: 'notify.persistent_notification', + perform_action: 'notify.persistent_notification', }, }, }, @@ -2855,7 +2856,7 @@ describe('should handle version specific upgrades', () => { }); describe('split live.ptz', () => { - const getAction = (action: PTZControlAction): CallServiceActionConfig => ({ + const getActionBefore = (action: PTZControlAction): CallServiceActionConfig => ({ action: 'call-service', service: 'service', data: { @@ -2863,8 +2864,16 @@ describe('should handle version specific upgrades', () => { }, }); + const getActionAfter = (action: PTZControlAction): PerformActionActionConfig => ({ + action: 'perform-action', + perform_action: 'service', + data: { + arg: action, + }, + }); + const getTapAction = (action: PTZControlAction): Actions => ({ - tap_action: getAction(action), + tap_action: getActionBefore(action), }); it('with action_ format', () => { @@ -2882,7 +2891,7 @@ describe('should handle version specific upgrades', () => { actions_zoom_out: getTapAction('zoom_out'), actions_home: { ...getTapAction('home'), - double_tap_action: getAction('up'), + double_tap_action: getActionBefore('up'), }, mode: 'auto' as const, @@ -2907,14 +2916,14 @@ describe('should handle version specific upgrades', () => { cameras: [{}], cameras_global: { ptz: { - actions_left: getAction('left'), - actions_right: getAction('right'), - actions_up: getAction('up'), - actions_down: getAction('down'), - actions_zoom_in: getAction('zoom_in'), - actions_zoom_out: getAction('zoom_out'), + actions_left: getActionAfter('left'), + actions_right: getActionAfter('right'), + actions_up: getActionAfter('up'), + actions_down: getActionAfter('down'), + actions_zoom_in: getActionAfter('zoom_in'), + actions_zoom_out: getActionAfter('zoom_out'), presets: { - home: getAction('home'), + home: getActionAfter('home'), }, }, }, @@ -3052,7 +3061,7 @@ describe('should handle version specific upgrades', () => { controls: { ptz: { actions_up: { - double_tap_action: getAction('up'), + double_tap_action: getActionBefore('up'), }, actions_down: getTapAction('down'), }, @@ -3065,7 +3074,7 @@ describe('should handle version specific upgrades', () => { expect.objectContaining({ cameras_global: { ptz: { - actions_down: getAction('down'), + actions_down: getActionAfter('down'), }, }, }), @@ -3081,8 +3090,8 @@ describe('should handle version specific upgrades', () => { controls: { ptz: { presets: { - home: getAction('left'), - other: getAction('right'), + home: getActionBefore('left'), + other: getActionBefore('right'), }, actions_home: getTapAction('home'), }, @@ -3096,8 +3105,8 @@ describe('should handle version specific upgrades', () => { cameras_global: { ptz: { presets: { - other: getAction('right'), - home: getAction('home'), + other: getActionAfter('right'), + home: getActionAfter('home'), }, }, }, @@ -3303,5 +3312,60 @@ describe('should handle version specific upgrades', () => { }); }); }); + + it('call-service -> perform-action', () => { + const config = { + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + type: 'icon', + icon: 'mdi:cow', + tap_action: { + action: 'call-service', + service: 'foo', + }, + }, + ], + view: { + actions: { + double_tap_action: { + action: 'call-service', + service: 'bar', + data: { + key: 'value', + }, + }, + }, + }, + }; + expect(upgradeConfig(config)).toBeTruthy(); + expect(config).toEqual({ + type: 'custom:frigate-card', + cameras: [{ camera_entity: 'camera.office' }], + elements: [ + { + type: 'icon', + icon: 'mdi:cow', + tap_action: { + action: 'perform-action', + perform_action: 'foo', + }, + }, + ], + view: { + actions: { + double_tap_action: { + action: 'perform-action', + perform_action: 'bar', + data: { + key: 'value', + }, + }, + }, + }, + }); + postUpgradeChecks(config); + }); }); }); diff --git a/tests/config/types.test.ts b/tests/config/types.test.ts index aa6bb356..6d7dadd2 100644 --- a/tests/config/types.test.ts +++ b/tests/config/types.test.ts @@ -423,8 +423,8 @@ describe('should convert webrtc card PTZ to Frigate card PTZ', () => { expect.objectContaining({ ptz: expect.objectContaining({ [`actions_${action}`]: { - action: 'call-service', - service: 'foo', + action: 'perform-action', + perform_action: 'foo', data: { device: '048123', cmd: action, @@ -465,8 +465,8 @@ describe('should convert webrtc card PTZ to Frigate card PTZ', () => { expect.objectContaining({ ptz: expect.objectContaining({ [`actions_${action}_start`]: { - action: 'call-service', - service: 'foo', + action: 'perform-action', + perform_action: 'foo', data: { device: '048123', cmd: action, @@ -474,8 +474,8 @@ describe('should convert webrtc card PTZ to Frigate card PTZ', () => { }, }, [`actions_${action}_stop`]: { - action: 'call-service', - service: 'foo', + action: 'perform-action', + perform_action: 'foo', data: { device: '048123', cmd: action, @@ -511,16 +511,16 @@ describe('should convert webrtc card PTZ to Frigate card PTZ', () => { ptz: expect.objectContaining({ presets: { home: { - action: 'call-service', - service: 'service_inner', + action: 'perform-action', + perform_action: 'service_inner', data: { device: '048123', cmd: 'home', }, }, another: { - action: 'call-service', - service: 'service_inner', + action: 'perform-action', + perform_action: 'service_inner', data: { device: '048123', cmd: 'another', diff --git a/yarn.lock b/yarn.lock index db2e71bc..fe330e3c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -603,18 +603,18 @@ __metadata: languageName: node linkType: hard -"@dermotduffy/custom-card-helpers@npm:^1.9.0": - version: 1.9.0 - resolution: "@dermotduffy/custom-card-helpers@npm:1.9.0" +"@dermotduffy/custom-card-helpers@npm:^1.9.1": + version: 1.9.1 + resolution: "@dermotduffy/custom-card-helpers@npm:1.9.1" dependencies: "@formatjs/intl-utils": "npm:^3.8.4" - home-assistant-js-websocket: "npm:^6.0.1" + home-assistant-js-websocket: "npm:^9.4.0" intl-messageformat: "npm:^9.11.1" lit: "npm:^2.1.1" rollup: "npm:^2.63.0" superstruct: "npm:^0.15.3" typescript: "npm:^4.5.4" - checksum: 10c0/312a31a9abe6ddc37109ffe2725df30e72213b4fa2cceacbb4bdb3712b46a73e49b9fb7fab69dc521050538e882d7180e3d7434011f637a34f2bc9098b880e97 + checksum: 10c0/e42073e00682195c3d253f9b36dc091f7329a5e2a5cdd395bf0988ec2c8585db887ef772975894e4a1126653a2f3cb348a4ea4c1fbe8ce739002fd0f8461da40 languageName: node linkType: hard @@ -4075,7 +4075,7 @@ __metadata: "@babel/plugin-proposal-decorators": "npm:^7.24.7" "@babel/plugin-transform-class-properties": "npm:^7.24.7" "@cycjimmy/jsmpeg-player": "npm:^6.0.5" - "@dermotduffy/custom-card-helpers": "npm:^1.9.0" + "@dermotduffy/custom-card-helpers": "npm:^1.9.1" "@dermotduffy/panzoom": "npm:^4.5.1" "@egjs/hammerjs": "npm:^2.0.17" "@graphiteds/core": "npm:^1.9.21" @@ -4106,7 +4106,7 @@ __metadata: eslint-config-airbnb-base: "npm:^15.0.0" eslint-config-prettier: "npm:^9.1.0" eslint-plugin-import: "npm:^2.29.1" - home-assistant-js-websocket: "npm:^8.2.0" + home-assistant-js-websocket: "npm:^9.4.0" jsdom: "npm:^21.1.2" keycharm: "npm:^0.4.0" lit: "npm:^3.1.4" @@ -4559,17 +4559,10 @@ __metadata: languageName: node linkType: hard -"home-assistant-js-websocket@npm:^6.0.1": - version: 6.1.1 - resolution: "home-assistant-js-websocket@npm:6.1.1" - checksum: 10c0/fe00b8d7a681d39b31ac5078b79fa1ef67cccd37df2c7ec31b1ad9ded33c899570b453c9439db71c3bda24df6d0c1e3d9d040583b0717f4630476ab528120a9f - languageName: node - linkType: hard - -"home-assistant-js-websocket@npm:^8.2.0": - version: 8.2.0 - resolution: "home-assistant-js-websocket@npm:8.2.0" - checksum: 10c0/9a1f1f5cb39ce0629653347d5ae31a14f14742596c15fea7bd72f4c0ee4ce4613b1172b4f4df52f293b4e5aeb3b5ead75f395d5fe5c4785193e7d00f8355ef5a +"home-assistant-js-websocket@npm:^9.4.0": + version: 9.4.0 + resolution: "home-assistant-js-websocket@npm:9.4.0" + checksum: 10c0/9c8a5ff903648ebe7856f62a58af53e3d89dd24a30c600a2145ed518cd5f5f2218345048cfc42bdc3ee5d6f2994da3948765c77b6012ed56cf4546173a1a1de1 languageName: node linkType: hard From 22de42b5a8320b0acf46971ba533151ef7ef68ac Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Thu, 12 Sep 2024 10:00:46 -0300 Subject: [PATCH 184/189] Fix devcontainer But this is still failing with permission denied in some cases. --- .devcontainer/Dockerfile | 5 ++++- .devcontainer/devcontainer.json | 8 +++----- docker-compose.yml | 7 ++++--- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 5c196009..bc136453 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/devcontainers/base:ubuntu-22.04 +FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04 USER vscode @@ -7,3 +7,6 @@ ARG HOME="/home/vscode" ENV VOLTA_HOME="${HOME}/.volta" ENV PATH="${VOLTA_HOME}/bin:${PATH}" RUN bash -c "$(curl -fsSL https://get.volta.sh)" -- --skip-setup + +ENTRYPOINT ["/usr/local/share/docker-init.sh"] +CMD ["sleep", "infinity"] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 9f34149b..883dbe3f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -4,12 +4,10 @@ "service": "dev", "features": { "ghcr.io/devcontainers/features/docker-outside-of-docker:1": { - "moby": false, - "dockerDashComposeVersion": "v2" + "moby": false } }, "workspaceFolder": "${localWorkspaceFolder}", - "shutdownAction": "stopCompose", "forwardPorts": [10001, "hass:8123", "frigate:5000"], "portsAttributes": { "10001": { @@ -25,8 +23,8 @@ "onAutoForward": "silent" } }, - "initializeCommand": ".devcontainer/initialize.sh", - "postCreateCommand": "yarn install", + "initializeCommand": [".devcontainer/initialize.sh"], + "postCreateCommand": ["yarn", "install"], "customizations": { "vscode": { "extensions": [ diff --git a/docker-compose.yml b/docker-compose.yml index bc9e5cc1..7d56cfb4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,9 +2,10 @@ services: dev: init: true - build: .devcontainer - entrypoint: /usr/local/share/docker-init.sh - command: sleep infinity + build: + context: . + dockerfile: .devcontainer/Dockerfile + network_mode: host env_file: - .env volumes: From 49924fc80100463c05415a2896e045fccdb6255a Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Thu, 12 Sep 2024 13:52:56 +0000 Subject: [PATCH 185/189] Switch to devcontainer:@ --- .devcontainer/Dockerfile | 16 +++++----------- .devcontainer/devcontainer.json | 5 ----- docker-compose.yml | 5 +---- 3 files changed, 6 insertions(+), 20 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index bc136453..aaa78bf0 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,12 +1,6 @@ -FROM mcr.microsoft.com/devcontainers/base:ubuntu-24.04 +FROM ghcr.io/felipecrs/devcontainer:2 -USER vscode - -# Install Volta -ARG HOME="/home/vscode" -ENV VOLTA_HOME="${HOME}/.volta" -ENV PATH="${VOLTA_HOME}/bin:${PATH}" -RUN bash -c "$(curl -fsSL https://get.volta.sh)" -- --skip-setup - -ENTRYPOINT ["/usr/local/share/docker-init.sh"] -CMD ["sleep", "infinity"] +RUN --mount=type=bind,source=package.json,target=/tmp/package.json \ + retry --tries 3 --sleep 15s -- volta install \ + "node@$(jq -er .volta.node /tmp/package.json)" \ + "yarn@$(jq -er .volta.yarn /tmp/package.json)" diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 883dbe3f..6725e351 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -2,11 +2,6 @@ { "dockerComposeFile": "../docker-compose.yml", "service": "dev", - "features": { - "ghcr.io/devcontainers/features/docker-outside-of-docker:1": { - "moby": false - } - }, "workspaceFolder": "${localWorkspaceFolder}", "forwardPorts": [10001, "hass:8123", "frigate:5000"], "portsAttributes": { diff --git a/docker-compose.yml b/docker-compose.yml index 7d56cfb4..46142256 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,15 +1,12 @@ ---- services: dev: - init: true build: context: . dockerfile: .devcontainer/Dockerfile - network_mode: host env_file: - .env volumes: - - /var/run/docker.sock:/var/run/docker-host.sock + - /var/run/docker.sock:/var/run/docker.sock - .:${LOCAL_WORKSPACE_FOLDER}:cached hass: extends: From e45b281b53b73eb84bf72ac5667c0f703489be36 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Thu, 12 Sep 2024 16:29:17 +0000 Subject: [PATCH 186/189] Switch back to original container --- .devcontainer/Dockerfile | 15 ++++++++++----- .devcontainer/devcontainer.json | 15 ++++++++++++--- .devcontainer/frigate-hass-integration | 2 +- .vscode/tasks.json | 5 ++++- docker-compose.yml | 9 ++++----- 5 files changed, 31 insertions(+), 15 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index aaa78bf0..32df1809 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,11 @@ -FROM ghcr.io/felipecrs/devcontainer:2 +FROM mcr.microsoft.com/devcontainers/base:ubuntu-22.04 -RUN --mount=type=bind,source=package.json,target=/tmp/package.json \ - retry --tries 3 --sleep 15s -- volta install \ - "node@$(jq -er .volta.node /tmp/package.json)" \ - "yarn@$(jq -er .volta.yarn /tmp/package.json)" +USER vscode + +# Install Volta +ARG HOME="/home/vscode" +ENV VOLTA_HOME="${HOME}/.volta" +ENV PATH="${VOLTA_HOME}/bin:${PATH}" +RUN bash -c "$(curl -fsSL https://get.volta.sh)" -- --skip-setup + +CMD ["sleep", "infinity"] diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 6725e351..7c51330b 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,8 +1,16 @@ // See https://aka.ms/vscode-remote/devcontainer.json for format details. { "dockerComposeFile": "../docker-compose.yml", - "service": "dev", + "service": "devcontainer", + "features": { + "ghcr.io/devcontainers/features/docker-outside-of-docker:1": { + "moby": false + } + }, + "updateRemoteUserUID": true, "workspaceFolder": "${localWorkspaceFolder}", + "initializeCommand": [".devcontainer/initialize.sh"], + "postCreateCommand": ["yarn", "install"], "forwardPorts": [10001, "hass:8123", "frigate:5000"], "portsAttributes": { "10001": { @@ -18,8 +26,6 @@ "onAutoForward": "silent" } }, - "initializeCommand": [".devcontainer/initialize.sh"], - "postCreateCommand": ["yarn", "install"], "customizations": { "vscode": { "extensions": [ @@ -32,9 +38,12 @@ "davidanson.vscode-markdownlint", "redhat.vscode-yaml", "lokalise.i18n-ally", + "vitest.explorer", + "inlang.vs-code-extension", "ms-azuretools.vscode-docker" ], "settings": { + "task.allowAutomaticTasks": "on", "files.eol": "\n", "editor.tabSize": 2, "editor.formatOnPaste": false, diff --git a/.devcontainer/frigate-hass-integration b/.devcontainer/frigate-hass-integration index f54791ce..74ed5e69 160000 --- a/.devcontainer/frigate-hass-integration +++ b/.devcontainer/frigate-hass-integration @@ -1 +1 @@ -Subproject commit f54791cef3c214eb8df4fd433beddc2b9e0a66a9 +Subproject commit 74ed5e6948001347d35c292cd9c6862d2ebc6c39 diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 53d59ad8..e8cbbcd0 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -20,7 +20,10 @@ "endsPattern": "^created" } }, - "isBackground": true + "isBackground": true, + "runOptions": { + "runOn": "folderOpen" + } } ] } diff --git a/docker-compose.yml b/docker-compose.yml index 46142256..a8ce8b8e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,12 +1,11 @@ services: - dev: - build: - context: . - dockerfile: .devcontainer/Dockerfile + devcontainer: + build: .devcontainer + init: true env_file: - .env volumes: - - /var/run/docker.sock:/var/run/docker.sock + - /var/run/docker.sock:/var/run/docker-host.sock - .:${LOCAL_WORKSPACE_FOLDER}:cached hass: extends: From ed307ebd0da088da4cc1bebf0e55d9a2d6000b70 Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Thu, 12 Sep 2024 16:31:52 +0000 Subject: [PATCH 187/189] Add YAML --- --- docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.yml b/docker-compose.yml index a8ce8b8e..84415b0e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,4 @@ +--- services: devcontainer: build: .devcontainer From 270921d91423f6a7c8fe8506372ff4c6c40a973d Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Fri, 13 Sep 2024 08:48:57 -0300 Subject: [PATCH 188/189] Update integration submodule --- .devcontainer/frigate-hass-integration | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/frigate-hass-integration b/.devcontainer/frigate-hass-integration index 74ed5e69..070fbf2e 160000 --- a/.devcontainer/frigate-hass-integration +++ b/.devcontainer/frigate-hass-integration @@ -1 +1 @@ -Subproject commit 74ed5e6948001347d35c292cd9c6862d2ebc6c39 +Subproject commit 070fbf2eccda6c8437b82c3bc23dc95e80826375 From d3754b0c34c1b89be8800c0df9650ca46d6987dd Mon Sep 17 00:00:00 2001 From: Dermot Duffy Date: Fri, 13 Sep 2024 07:51:33 -0700 Subject: [PATCH 189/189] Fix test name typo --- tests/config/management.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/config/management.test.ts b/tests/config/management.test.ts index 7595b3de..e819b80b 100644 --- a/tests/config/management.test.ts +++ b/tests/config/management.test.ts @@ -813,7 +813,7 @@ describe('should handle version specific upgrades', () => { }); describe('should move PTZ elements to live', () => { - it('xxx case with 1 element', () => { + it('case with 1 element', () => { const config = { type: 'custom:frigate-card', cameras: [{ camera_entity: 'camera.office' }],

      HD7g$Pae|>~!O-}UdpQ&U(ILIp1-SdN9X6Rp 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�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�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%0Aq_?^O% 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

      R5Lx{(~cuwc(2AjyP6SB1hbA0+LK%}Qe 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Ⓢ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