diff --git a/src/card.ts b/src/card.ts index d98920de..0777f25c 100644 --- a/src/card.ts +++ b/src/card.ts @@ -106,8 +106,8 @@ export class FrigateCard extends LitElement { @query('frigate-card-menu') _menu!: FrigateCardMenu; - // Whether or not there is an active clip being played. - protected _clipPlaying = false; + // Whether or not media is actively playing (live or clip). + protected _mediaPlaying = false; // A small cache to avoid needing to create a new list of entities every time // a hass update arrives. @@ -253,7 +253,7 @@ export class FrigateCard extends LitElement { // 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 a clip active playing. - if (this._interactionTimerID || this._clipPlaying) { + if (this._interactionTimerID || this._mediaPlaying) { return false; } return shouldUpdateBasedOnHass(this._hass, oldHass, this._entitiesToMonitor); @@ -294,35 +294,6 @@ export class FrigateCard extends LitElement { return `${this.config.frigate_url}/events?camera=${this.config.frigate_camera_name}`; } - public updated(): void { - this.updateComplete.then(() => { - // DOM elements are not always present until after updateComplete promise - // is resolved. Note that children of children (i.e. the underlying video - // element) is not always present even when the promise returns, so - // capture the event at the upper shadow root instead. - const hls_player = this.renderRoot - ?.querySelector('ha-card') - ?.querySelector('ha-hls-player'); - - if (hls_player) { - hls_player.shadowRoot?.addEventListener( - 'play', - () => { - this._clipPlaying = true; - }, - true, - ); - hls_player.shadowRoot?.addEventListener( - 'pause', - () => { - this._clipPlaying = true; - }, - true, - ); - } - }); - } - // Record interactions with the card. protected _interactionHandler(): void { if (!this.config.view_timeout) { @@ -363,6 +334,14 @@ export class FrigateCard extends LitElement { zone: this.config.zone, }; } + + protected _playHandler(): void { + this._mediaPlaying = true; + } + + protected _pauseHandler(): void { + this._mediaPlaying = false; + } protected _mediaLoadHandler(e: CustomEvent): void { const mediaInfo = e.detail; @@ -461,7 +440,9 @@ export class FrigateCard extends LitElement { .autoplayClip=${this.config.autoplay_clip} @frigate-card:change-view=${this._changeViewHandler} @frigate-card:media-load=${this._mediaLoadHandler} - > + @frigate-card:pause=${this._pauseHandler} + @frigate-card:play=${this._playHandler} + > ` : ``} ${this._view.is('live') @@ -469,6 +450,8 @@ export class FrigateCard extends LitElement { .hass=${this._hass} .config=${this.config} @frigate-card:media-load=${this._mediaLoadHandler} + @frigate-card:pause=${this._pauseHandler} + @frigate-card:play=${this._playHandler} > ` : ``} diff --git a/src/components/live.ts b/src/components/live.ts index 3a815929..6cee32c6 100644 --- a/src/components/live.ts +++ b/src/components/live.ts @@ -7,7 +7,12 @@ import { signedPathSchema } from '../types'; import type { ExtendedHomeAssistant, FrigateCardConfig } from '../types'; import { localize } from '../localize/localize'; -import { dispatchMediaLoadEvent, homeAssistantWSRequest } from '../common'; +import { + dispatchMediaLoadEvent, + dispatchPauseEvent, + dispatchPlayEvent, + homeAssistantWSRequest, +} from '../common'; import { renderMessage, renderErrorMessage, @@ -95,7 +100,6 @@ export class FrigateCardViewerWebRTC extends LitElement { protected _webRTCElement: HTMLElement | null = null; protected _createWebRTC(): TemplateResult | void { - // eslint-disable-next-line @typescript-eslint/no-explicit-any const webrtcElement = customElements.get('webrtc-camera') as any; if (webrtcElement) { @@ -125,11 +129,30 @@ export class FrigateCardViewerWebRTC extends LitElement { this.updateComplete.then(() => { const video = this.renderRoot.querySelector('#video') as HTMLVideoElement; if (video) { - video.onloadedmetadata = () => { + const onloadedmetadata = video.onloadedmetadata; + const onplay = video.onplay; + const onpause = video.onpause; + + video.onloadedmetadata = (e) => { + if (onloadedmetadata) { + onloadedmetadata.call(video, e); + } dispatchMediaLoadEvent(this, video); - } + }; + video.onplay = (e) => { + if (onplay) { + onplay.call(video, e); + } + dispatchPlayEvent(this); + }; + video.onpause = (e) => { + if (onpause) { + onpause.call(video, e); + } + dispatchPauseEvent(this); + }; } - }) + }); } static get styles(): CSSResultGroup { @@ -212,11 +235,16 @@ export class FrigateCardViewerJSMPEG extends LitElement { // amount of time the canvas is empty (and show the spinner // instead). play: () => { + dispatchPlayEvent(this); resolve(html`${this._jsmpegCanvasElement}`); }, + pause: () => { + dispatchPauseEvent(this); + }, }, }, - { protocols: [], + { + protocols: [], videoBufferSize: 1024 * 1024 * 4, onVideoDecode: () => { // This is the only callback that is called after the dimensions @@ -226,8 +254,8 @@ export class FrigateCardViewerJSMPEG extends LitElement { videoDecoded = true; dispatchMediaLoadEvent(this, this._jsmpegCanvasElement); } - } - }, + }, + }, ); }); } diff --git a/src/patches/ha-hls-player.ts b/src/patches/ha-hls-player.ts index 40e03d2c..e05422c1 100644 --- a/src/patches/ha-hls-player.ts +++ b/src/patches/ha-hls-player.ts @@ -14,7 +14,7 @@ import { html, } from 'lit'; import { customElement } from 'lit/decorators'; -import { dispatchMediaLoadEvent } from '../common'; +import { dispatchMediaLoadEvent, dispatchPauseEvent, dispatchPlayEvent } from '../common'; customElements.whenDefined("ha-hls-player").then(() => { @customElement("frigate-card-ha-hls-player") @@ -33,6 +33,8 @@ customElements.whenDefined("ha-hls-player").then(() => { ?controls=${this.controls} @loadedmetadata=${(e) => dispatchMediaLoadEvent(this, e)} @loadeddata=${this._elementResized} + @pause=${() => dispatchPauseEvent(this)} + @play=${() => dispatchPlayEvent(this)} > `; }