Show still images during live camera load.
This commit is contained in:
+2
-1
@@ -1010,6 +1010,7 @@ export class FrigateCard extends LitElement {
|
||||
view: this._view?.clone().mergeInContext(ev.detail),
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before each update.
|
||||
*/
|
||||
@@ -1795,7 +1796,7 @@ export class FrigateCard extends LitElement {
|
||||
@frigate-card:message=${this._messageHandler.bind(this)}
|
||||
@frigate-card:view:change=${this._changeViewHandler.bind(this)}
|
||||
@frigate-card:view:change-context=${this._addViewContextHandler.bind(this)}
|
||||
@frigate-card:media-show=${this._mediaShowHandler}
|
||||
@frigate-card:media-show=${this._mediaShowHandler.bind(this)}
|
||||
@frigate-card:render=${() => this.requestUpdate()}
|
||||
>
|
||||
${renderMenuAbove ? this._renderMenu() : ''}
|
||||
|
||||
+79
-19
@@ -17,17 +17,14 @@ import { guard } from 'lit/directives/guard.js';
|
||||
import { keyed } from 'lit/directives/keyed.js';
|
||||
import { until } from 'lit/directives/until.js';
|
||||
import { ConditionState, getOverriddenConfig } from '../card-condition.js';
|
||||
import {
|
||||
dispatchFrigateCardErrorEvent,
|
||||
dispatchMessageEvent,
|
||||
renderProgressIndicator,
|
||||
} from '../components/message.js';
|
||||
import { dispatchMessageEvent, renderProgressIndicator } from '../components/message.js';
|
||||
import { localize } from '../localize/localize.js';
|
||||
import liveFrigateStyle from '../scss/live-frigate.scss';
|
||||
import liveJSMPEGStyle from '../scss/live-jsmpeg.scss';
|
||||
import liveWebRTCStyle from '../scss/live-webrtc.scss';
|
||||
import liveStyle from '../scss/live.scss';
|
||||
import liveCarouselStyle from '../scss/live-carousel.scss';
|
||||
import liveProviderStyle from '../scss/live-provider.scss';
|
||||
import {
|
||||
CameraConfig,
|
||||
ExtendedHomeAssistant,
|
||||
@@ -44,10 +41,7 @@ import {
|
||||
WebRTCCardConfig,
|
||||
} from '../types.js';
|
||||
import { stopEventFromActivatingCardWideActions } from '../utils/action.js';
|
||||
import {
|
||||
contentsChanged,
|
||||
errorToConsole,
|
||||
} from '../utils/basic.js';
|
||||
import { contentsChanged, errorToConsole } from '../utils/basic.js';
|
||||
import { getCameraIcon, getCameraTitle } from '../utils/camera.js';
|
||||
import { homeAssistantSignPath } from '../utils/ha';
|
||||
import { getFullDependentBrowseMediaQueryParameters } from '../utils/ha/browse-media.js';
|
||||
@@ -69,6 +63,8 @@ import './surround-thumbnails';
|
||||
import '../patches/ha-camera-stream';
|
||||
import { EmblaCarouselPlugins } from './carousel.js';
|
||||
import { renderTask } from '../utils/task.js';
|
||||
import { classMap } from 'lit/directives/class-map.js';
|
||||
import './image';
|
||||
|
||||
// Number of seconds a signed URL is valid for.
|
||||
const URL_SIGN_EXPIRY_SECONDS = 24 * 60 * 60;
|
||||
@@ -591,7 +587,7 @@ export class FrigateCardLiveCarousel extends LitElement {
|
||||
@frigate-card:media-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, { thumbnails: { fetch: true } });
|
||||
}}
|
||||
>
|
||||
<frigate-card-next-previous-control
|
||||
@@ -657,6 +653,9 @@ export class FrigateCardLiveProvider extends LitElement {
|
||||
@property({ attribute: false })
|
||||
public label = '';
|
||||
|
||||
@state()
|
||||
protected _isVideoMediaLoaded = false;
|
||||
|
||||
protected _providerRef: Ref<Element & FrigateCardMediaPlayer> = createRef();
|
||||
|
||||
/**
|
||||
@@ -694,7 +693,11 @@ export class FrigateCardLiveProvider extends LitElement {
|
||||
this._providerRef.value?.seek(seconds);
|
||||
}
|
||||
|
||||
protected _getResolvedProvider(): LiveProvider {
|
||||
/**
|
||||
* Get the fully resolved live provider.
|
||||
* @returns A live provider (that is not 'auto').
|
||||
*/
|
||||
protected _getResolvedProvider(): Omit<LiveProvider, 'auto'> {
|
||||
if (this.cameraConfig?.live_provider === 'auto') {
|
||||
if (
|
||||
this.cameraConfig?.webrtc_card?.entity ||
|
||||
@@ -713,6 +716,35 @@ export class FrigateCardLiveProvider extends LitElement {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a camera image should be shown in lieu of the real stream
|
||||
* whilst loading.
|
||||
* @returns`true` if an image should be shown.
|
||||
*/
|
||||
protected _shouldShowImageDuringLoading(): boolean {
|
||||
return (
|
||||
!!this.cameraConfig?.camera_entity &&
|
||||
!!this.hass &&
|
||||
!!this.liveConfig?.show_image_during_load
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record that video media is being shown.
|
||||
*/
|
||||
protected _videoMediaShowHandler(): void {
|
||||
this._isVideoMediaLoaded = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before each update.
|
||||
*/
|
||||
protected willUpdate(): void {
|
||||
if (this.disabled) {
|
||||
this._isVideoMediaLoaded = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Master render method.
|
||||
* @returns A rendered template.
|
||||
@@ -727,32 +759,60 @@ export class FrigateCardLiveProvider extends LitElement {
|
||||
this.ariaLabel = this.label;
|
||||
|
||||
const provider = this._getResolvedProvider();
|
||||
const showImage = !this._isVideoMediaLoaded && this._shouldShowImageDuringLoading();
|
||||
const providerClasses = {
|
||||
hidden: showImage,
|
||||
};
|
||||
|
||||
return html`
|
||||
${provider == 'ha'
|
||||
? html` <frigate-card-live-ha
|
||||
${ref(this._providerRef)}
|
||||
${showImage
|
||||
? html`<frigate-card-image
|
||||
.imageConfig=${{
|
||||
mode: 'camera' as const,
|
||||
refresh_seconds: 1,
|
||||
}}
|
||||
.hass=${this.hass}
|
||||
.cameraConfig=${this.cameraConfig}
|
||||
>
|
||||
</frigate-card-image>`
|
||||
: html``}
|
||||
${provider === 'ha'
|
||||
? html` <frigate-card-live-ha
|
||||
${ref(this._providerRef)}
|
||||
class=${classMap(providerClasses)}
|
||||
.hass=${this.hass}
|
||||
.cameraConfig=${this.cameraConfig}
|
||||
@frigate-card:media-show=${this._videoMediaShowHandler.bind(this)}
|
||||
>
|
||||
</frigate-card-live-ha>`
|
||||
: provider == 'webrtc-card'
|
||||
: provider === 'webrtc-card'
|
||||
? html`<frigate-card-live-webrtc-card
|
||||
${ref(this._providerRef)}
|
||||
class=${classMap(providerClasses)}
|
||||
.hass=${this.hass}
|
||||
.cameraConfig=${this.cameraConfig}
|
||||
.webRTCConfig=${this.liveConfig.webrtc_card}
|
||||
@frigate-card:media-show=${this._videoMediaShowHandler.bind(this)}
|
||||
>
|
||||
</frigate-card-live-webrtc-card>`
|
||||
: html` <frigate-card-live-jsmpeg
|
||||
${ref(this._providerRef)}
|
||||
class=${classMap(providerClasses)}
|
||||
.hass=${this.hass}
|
||||
.cameraConfig=${this.cameraConfig}
|
||||
.jsmpegConfig=${this.liveConfig.jsmpeg}
|
||||
@frigate-card:media-show=${this._videoMediaShowHandler.bind(this)}
|
||||
>
|
||||
</frigate-card-live-jsmpeg>`}
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get styles.
|
||||
*/
|
||||
static get styles(): CSSResultGroup {
|
||||
return unsafeCSS(liveProviderStyle);
|
||||
}
|
||||
}
|
||||
|
||||
@customElement('frigate-card-live-ha')
|
||||
@@ -1006,11 +1066,11 @@ export class FrigateCardLiveWebRTCCard extends LitElement {
|
||||
this.updateComplete.then(() => {
|
||||
const video = this._getPlayer();
|
||||
if (video) {
|
||||
const onloadedmetadata = video.onloadedmetadata;
|
||||
const onloadeddata = video.onloadeddata;
|
||||
|
||||
video.onloadedmetadata = (e) => {
|
||||
if (onloadedmetadata) {
|
||||
onloadedmetadata.call(video, e);
|
||||
video.onloadeddata = (e) => {
|
||||
if (onloadeddata) {
|
||||
onloadeddata.call(video, e);
|
||||
}
|
||||
dispatchMediaShowEvent(this, video);
|
||||
};
|
||||
|
||||
@@ -119,6 +119,7 @@ export const CONF_LIVE_LAZY_LOAD = `${CONF_LIVE}.lazy_load` as const;
|
||||
export const CONF_LIVE_LAZY_UNLOAD = `${CONF_LIVE}.lazy_unload` as const;
|
||||
export const CONF_LIVE_PRELOAD = `${CONF_LIVE}.preload` as const;
|
||||
export const CONF_LIVE_TRANSITION_EFFECT = `${CONF_LIVE}.transition_effect` as const;
|
||||
export const CONF_LIVE_SHOW_IMAGE_DURING_LOAD = `${CONF_LIVE}.show_image_during_load` as const;
|
||||
export const CONF_LIVE_WEBRTC_CARD = `${CONF_LIVE}.webrtc_card` as const;
|
||||
|
||||
export const CONF_IMAGE = 'image' as const;
|
||||
|
||||
+11
-6
@@ -9,7 +9,7 @@ import {
|
||||
getConfigValue,
|
||||
isConfigUpgradeable,
|
||||
setConfigValue,
|
||||
upgradeConfig
|
||||
upgradeConfig,
|
||||
} from './config-mgmt.js';
|
||||
import {
|
||||
CONF_CAMERAS,
|
||||
@@ -57,6 +57,7 @@ import {
|
||||
CONF_LIVE_LAZY_LOAD,
|
||||
CONF_LIVE_LAZY_UNLOAD,
|
||||
CONF_LIVE_PRELOAD,
|
||||
CONF_LIVE_SHOW_IMAGE_DURING_LOAD,
|
||||
CONF_LIVE_TRANSITION_EFFECT,
|
||||
CONF_MEDIA_VIEWER_AUTO_MUTE,
|
||||
CONF_MEDIA_VIEWER_AUTO_PAUSE,
|
||||
@@ -99,7 +100,7 @@ import {
|
||||
CONF_VIEW_TIMEOUT_SECONDS,
|
||||
CONF_VIEW_UPDATE_CYCLE_CAMERA,
|
||||
CONF_VIEW_UPDATE_FORCE,
|
||||
CONF_VIEW_UPDATE_SECONDS
|
||||
CONF_VIEW_UPDATE_SECONDS,
|
||||
} from './const.js';
|
||||
import { localize } from './localize/localize.js';
|
||||
import frigate_card_editor_style from './scss/editor.scss';
|
||||
@@ -110,7 +111,7 @@ import {
|
||||
RawFrigateCardConfig,
|
||||
RawFrigateCardConfigArray,
|
||||
THUMBNAIL_WIDTH_MAX,
|
||||
THUMBNAIL_WIDTH_MIN
|
||||
THUMBNAIL_WIDTH_MIN,
|
||||
} from './types.js';
|
||||
import { arrayMove } from './utils/basic.js';
|
||||
import { getCameraID, getCameraTitle } from './utils/camera.js';
|
||||
@@ -1203,6 +1204,10 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
CONF_LIVE_TRANSITION_EFFECT,
|
||||
this._transitionEffects,
|
||||
)}
|
||||
${this._renderSwitch(
|
||||
CONF_LIVE_SHOW_IMAGE_DURING_LOAD,
|
||||
defaults.live.show_image_during_load,
|
||||
)}
|
||||
${this._putInSubmenu(
|
||||
MENU_LIVE_CONTROLS,
|
||||
true,
|
||||
@@ -1511,7 +1516,7 @@ export class FrigateCardEditor extends LitElement implements LovelaceCardEditor
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
"frigate-card-editor": FrigateCardEditor
|
||||
}
|
||||
interface HTMLElementTagNameMap {
|
||||
'frigate-card-editor': FrigateCardEditor;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
"lazy_load": "Live cameras are lazily loaded",
|
||||
"lazy_unload": "Live cameras are lazily unloaded",
|
||||
"preload": "Preload live view in the background",
|
||||
"show_image_during_load": "Show still image while the live stream is loading",
|
||||
"transition_effect": "Live camera transition effect"
|
||||
},
|
||||
"media_viewer": {
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
"lazy_load": "Le telecamere dal vivo sono pigramente cariche",
|
||||
"lazy_unload": "Le telecamere dal vivo sono pigramente non caricate",
|
||||
"preload": "Precarica Live View in background",
|
||||
"show_image_during_load": "",
|
||||
"transition_effect": "Effetto di transizione della telecamera dal vivo"
|
||||
},
|
||||
"media_viewer": {
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
"lazy_load": "As câmeras ao vivo são carregadas lentamente",
|
||||
"lazy_unload": "As câmeras ao vivo são descarregadas preguiçosamente",
|
||||
"preload": "Pré-carregar a visualização ao vivo em segundo plano",
|
||||
"show_image_during_load": "",
|
||||
"transition_effect": "Efeito de transição de câmera ao vivo"
|
||||
},
|
||||
"media_viewer": {
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
@@ -642,6 +642,7 @@ const liveConfigDefault = {
|
||||
lazy_unload: 'never' as const,
|
||||
draggable: true,
|
||||
transition_effect: 'slide' as const,
|
||||
show_image_during_load: true,
|
||||
controls: {
|
||||
next_previous: {
|
||||
size: 48,
|
||||
@@ -739,6 +740,7 @@ const liveOverridableConfigSchema = z
|
||||
.default(liveConfigDefault.controls.title),
|
||||
})
|
||||
.default(liveConfigDefault.controls),
|
||||
show_image_during_load: z.boolean().default(liveConfigDefault.show_image_during_load),
|
||||
})
|
||||
.merge(actionsSchema);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user