Stop video content when the view is changed.
This commit is contained in:
+62
-8
@@ -5,8 +5,6 @@
|
|||||||
|
|
||||||
// TODO comments per method.
|
// TODO comments per method.
|
||||||
|
|
||||||
// TODO: Stop the live view video when I hide it.
|
|
||||||
|
|
||||||
// TODO Check for HA state presence and validity before using it, otherwise warn.
|
// TODO Check for HA state presence and validity before using it, otherwise warn.
|
||||||
|
|
||||||
// TODO Add material tooltips
|
// TODO Add material tooltips
|
||||||
@@ -38,7 +36,7 @@ import './editor';
|
|||||||
|
|
||||||
import style from './frigate-card.scss'
|
import style from './frigate-card.scss'
|
||||||
|
|
||||||
import type { FrigateCardConfig, FrigateEvent, GetEventsParameters } from './types';
|
import type { FrigateCardConfig, FrigateEvent, GetEventsParameters, ControlVideosParameters } from './types';
|
||||||
import { actionHandler } from './action-handler-directive';
|
import { actionHandler } from './action-handler-directive';
|
||||||
import { CARD_VERSION } from './const';
|
import { CARD_VERSION } from './const';
|
||||||
import { localize } from './localize/localize';
|
import { localize } from './localize/localize';
|
||||||
@@ -120,7 +118,7 @@ export class FrigateCard extends LitElement {
|
|||||||
if (cardConfig.camera_entity.includes(".")) {
|
if (cardConfig.camera_entity.includes(".")) {
|
||||||
cardConfig.frigate_camera_name = cardConfig.camera_entity.split('.', 2)[1]
|
cardConfig.frigate_camera_name = cardConfig.camera_entity.split('.', 2)[1]
|
||||||
} else {
|
} else {
|
||||||
throw new Error(localize('common.invalid_configuration_missing') + ": camera");
|
throw new Error(localize('common.invalid_configuration_missing') + ": camera_entity");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,23 +269,78 @@ export class FrigateCard extends LitElement {
|
|||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected _controlVideos({
|
||||||
|
stop,
|
||||||
|
control_live = false,
|
||||||
|
control_clip = false}: ControlVideosParameters): void {
|
||||||
|
const controlVideo = (stop: boolean, is_live: boolean, video: HTMLVideoElement) => {
|
||||||
|
if (video) {
|
||||||
|
if (stop) {
|
||||||
|
video.pause();
|
||||||
|
video.currentTime = 0;
|
||||||
|
} else {
|
||||||
|
if (is_live) {
|
||||||
|
// If it's a live view, 'fast-forward' to most recent content.
|
||||||
|
const duration = video.duration;
|
||||||
|
video.currentTime = duration;
|
||||||
|
}
|
||||||
|
video.play();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!this.shadowRoot) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (control_clip) {
|
||||||
|
controlVideo(
|
||||||
|
stop,
|
||||||
|
false,
|
||||||
|
this.shadowRoot?.querySelector(
|
||||||
|
`#frigate-card-clip-player`) as HTMLVideoElement);
|
||||||
|
}
|
||||||
|
if (control_live) {
|
||||||
|
// Don't have direct access to the live video player as it is buried in
|
||||||
|
// multiple components/shadow-roots, so need to navigate the path to get to <video>.
|
||||||
|
const ha_camera_stream = this.shadowRoot?.querySelector(`#frigate-card-live-player`);
|
||||||
|
if (ha_camera_stream && ha_camera_stream?.shadowRoot) {
|
||||||
|
const ha_hls_player = ha_camera_stream.shadowRoot.querySelector(`ha-hls-player`);
|
||||||
|
if (ha_hls_player && ha_hls_player?.shadowRoot) {
|
||||||
|
controlVideo(
|
||||||
|
stop,
|
||||||
|
true,
|
||||||
|
ha_hls_player.shadowRoot.querySelector(`video`) as HTMLVideoElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected _renderNavigationBar(): TemplateResult {
|
protected _renderNavigationBar(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="frigate-card-navbar" >
|
<div class="frigate-card-navbar" >
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
class="button"
|
class="button"
|
||||||
icon="mdi:cctv"
|
icon="mdi:cctv"
|
||||||
@click=${() => this._viewMode = FrigateCardView.LIVE}
|
@click=${() => {
|
||||||
|
this._controlVideos({stop: true, control_clip: true});
|
||||||
|
this._controlVideos({stop: false, control_live: true});
|
||||||
|
this._viewMode = FrigateCardView.LIVE
|
||||||
|
}}
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
class="button"
|
class="button"
|
||||||
icon = "mdi:filmstrip"
|
icon = "mdi:filmstrip"
|
||||||
@click=${() => this._viewMode = FrigateCardView.CLIPS}
|
@click=${() => {
|
||||||
|
this._controlVideos({stop: true, control_live: true});
|
||||||
|
this._viewMode = FrigateCardView.CLIPS
|
||||||
|
}}
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
<ha-icon-button
|
<ha-icon-button
|
||||||
class="button"
|
class="button"
|
||||||
icon = "mdi:camera"
|
icon = "mdi:camera"
|
||||||
@click=${() => this._viewMode = FrigateCardView.SNAPSHOTS}
|
@click=${() => {
|
||||||
|
this._controlVideos({stop: true, control_clip: true, control_live: true});
|
||||||
|
this._viewMode = FrigateCardView.SNAPSHOTS
|
||||||
|
}}
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
</div>`
|
</div>`
|
||||||
}
|
}
|
||||||
@@ -313,7 +366,7 @@ export class FrigateCard extends LitElement {
|
|||||||
const url = `${this.config.frigate_url}/clips/` +
|
const url = `${this.config.frigate_url}/clips/` +
|
||||||
`${event.camera}-${event.id}.mp4`;
|
`${event.camera}-${event.id}.mp4`;
|
||||||
return html`
|
return html`
|
||||||
<video class="frigate-card-viewer" autoplay controls>
|
<video id="frigate-card-clip-player" class="frigate-card-viewer" autoplay controls>
|
||||||
<source src="${url}" type="video/mp4">
|
<source src="${url}" type="video/mp4">
|
||||||
</video>`
|
</video>`
|
||||||
}
|
}
|
||||||
@@ -360,6 +413,7 @@ export class FrigateCard extends LitElement {
|
|||||||
protected _renderLiveViewer(): TemplateResult {
|
protected _renderLiveViewer(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<ha-camera-stream
|
<ha-camera-stream
|
||||||
|
id="frigate-card-live-player"
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.stateObj=${this.hass.states[this.config.camera_entity]}
|
.stateObj=${this.hass.states[this.config.camera_entity]}
|
||||||
.controls=${true}
|
.controls=${true}
|
||||||
|
|||||||
@@ -44,3 +44,9 @@ export interface GetEventsParameters {
|
|||||||
has_snapshot?: boolean;
|
has_snapshot?: boolean;
|
||||||
limit?: number;
|
limit?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ControlVideosParameters {
|
||||||
|
stop: boolean;
|
||||||
|
control_live?: boolean;
|
||||||
|
control_clip?: boolean;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user