Implement downloading and correct MediaShow events in carousel.
This commit is contained in:
@@ -10,7 +10,7 @@ import {
|
||||
MenuStateIcon,
|
||||
PictureElements,
|
||||
} from '../types.js';
|
||||
import { dispatchErrorMessageEvent, dispatchEvent } from '../common.js';
|
||||
import { dispatchErrorMessageEvent, dispatchFrigateCardEvent } from '../common.js';
|
||||
|
||||
import elementsStyle from '../scss/elements.scss';
|
||||
import { localize } from '../localize/localize.js';
|
||||
@@ -134,7 +134,11 @@ export class FrigateCardElements extends LitElement {
|
||||
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).
|
||||
dispatchEvent<MenuButton>(this, 'menu-remove', (ev as CustomEvent).detail);
|
||||
dispatchFrigateCardEvent<MenuButton>(
|
||||
this,
|
||||
'menu-remove',
|
||||
(ev as CustomEvent).detail,
|
||||
);
|
||||
}
|
||||
|
||||
protected _menuAddHandler(ev: Event): void {
|
||||
@@ -274,13 +278,13 @@ export class FrigateCardElementsBaseMenuIcon<T> extends LitElement {
|
||||
connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
if (this._config) {
|
||||
dispatchEvent<T>(this, 'menu-add', this._config);
|
||||
dispatchFrigateCardEvent<T>(this, 'menu-add', this._config);
|
||||
}
|
||||
}
|
||||
|
||||
disconnectedCallback(): void {
|
||||
if (this._config) {
|
||||
dispatchEvent<T>(this, 'menu-remove', this._config);
|
||||
dispatchFrigateCardEvent<T>(this, 'menu-remove', this._config);
|
||||
}
|
||||
super.disconnectedCallback();
|
||||
}
|
||||
|
||||
@@ -1,28 +1,25 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { until } from 'lit/directives/until.js';
|
||||
import { HomeAssistant } from 'custom-card-helpers';
|
||||
import { customElement, property, state } from 'lit/decorators.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
import { until } from 'lit/directives/until.js';
|
||||
|
||||
import type {
|
||||
BrowseMediaSource,
|
||||
BrowseMediaQueryParameters,
|
||||
ExtendedHomeAssistant,
|
||||
} from '../types.js';
|
||||
|
||||
import { BrowseMediaUtil } from '../browse-media-util.js';
|
||||
import { View } from '../view.js';
|
||||
import {
|
||||
browseMedia,
|
||||
browseMediaQuery,
|
||||
dispatchErrorMessageEvent,
|
||||
dispatchMessageEvent,
|
||||
getFirstTrueMediaChildIndex,
|
||||
} from '../common.js';
|
||||
import { localize } from '../localize/localize.js';
|
||||
import { renderProgressIndicator } from './message.js';
|
||||
|
||||
import galleryStyle from '../scss/gallery.scss';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
|
||||
const MAX_THUMBNAIL_WIDTH = 175;
|
||||
const DEFAULT_COLUMNS = 5;
|
||||
@@ -79,15 +76,15 @@ export class FrigateCardGallery extends LitElement {
|
||||
let parent: BrowseMediaSource | null;
|
||||
try {
|
||||
if (this.view.target) {
|
||||
parent = await browseMedia(this.hass, this.view.target.media_content_id);
|
||||
parent = await BrowseMediaUtil.browseMedia(this.hass, this.view.target.media_content_id);
|
||||
} else {
|
||||
parent = await browseMediaQuery(this.hass, this.browseMediaQueryParameters);
|
||||
parent = await BrowseMediaUtil.browseMediaQuery(this.hass, this.browseMediaQueryParameters);
|
||||
}
|
||||
} catch (e: any) {
|
||||
return dispatchErrorMessageEvent(this, e.message);
|
||||
}
|
||||
|
||||
if (!parent || !parent.children || getFirstTrueMediaChildIndex(parent) == null) {
|
||||
if (!parent || !parent.children || BrowseMediaUtil.getFirstTrueMediaChildIndex(parent) == null) {
|
||||
return dispatchMessageEvent(
|
||||
this,
|
||||
this._getMediaType() == 'clips'
|
||||
@@ -149,7 +146,7 @@ export class FrigateCardGallery extends LitElement {
|
||||
src="${child.thumbnail}"
|
||||
@click=${() => {
|
||||
new View({
|
||||
view: this._getMediaType() == 'clips' ? 'clip' : 'snapshot',
|
||||
view: this._getMediaType() == 'clips' ? 'clip-specific' : 'snapshot-specific',
|
||||
target: parent ?? undefined,
|
||||
childIndex: index,
|
||||
previous: this.view ?? undefined,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
|
||||
import { dispatchMediaLoadEvent } from '../common.js';
|
||||
import { dispatchMediaShowEvent } from '../common.js';
|
||||
|
||||
import imageStyle from '../scss/image.scss';
|
||||
import defaultImage from '../images/frigate-bird-in-sky.jpg'
|
||||
@@ -15,7 +15,7 @@ export class FrigateCardImage extends LitElement {
|
||||
return html` <img
|
||||
src=${this.image || defaultImage}
|
||||
@load=${(e) => {
|
||||
dispatchMediaLoadEvent(this, e);
|
||||
dispatchMediaShowEvent(this, e);
|
||||
}}
|
||||
>`;
|
||||
}
|
||||
|
||||
+15
-18
@@ -1,19 +1,17 @@
|
||||
import { CSSResultGroup, LitElement, TemplateResult, html, unsafeCSS } from 'lit';
|
||||
import type { ExtendedHomeAssistant, FrigateCardConfig } from '../types.js';
|
||||
import { HomeAssistant } from 'custom-card-helpers';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { until } from 'lit/directives/until.js';
|
||||
import { HomeAssistant } from 'custom-card-helpers';
|
||||
|
||||
import { signedPathSchema } from '../types.js';
|
||||
import type { ExtendedHomeAssistant, FrigateCardConfig } from '../types.js';
|
||||
|
||||
import { localize } from '../localize/localize.js';
|
||||
import {
|
||||
dispatchErrorMessageEvent,
|
||||
dispatchMediaLoadEvent,
|
||||
dispatchMediaShowEvent,
|
||||
dispatchMessageEvent,
|
||||
dispatchPauseEvent,
|
||||
dispatchPlayEvent,
|
||||
homeAssistantWSRequest,
|
||||
homeAssistantSignPath,
|
||||
} from '../common.js';
|
||||
import { renderProgressIndicator } from '../components/message.js';
|
||||
|
||||
@@ -142,7 +140,7 @@ export class FrigateCardLiveWebRTC extends LitElement {
|
||||
if (onloadedmetadata) {
|
||||
onloadedmetadata.call(video, e);
|
||||
}
|
||||
dispatchMediaLoadEvent(this, video);
|
||||
dispatchMediaShowEvent(this, video);
|
||||
};
|
||||
video.onplay = (e) => {
|
||||
if (onplay) {
|
||||
@@ -184,21 +182,20 @@ export class FrigateCardLiveJSMPEG extends LitElement {
|
||||
return null;
|
||||
}
|
||||
|
||||
const request = {
|
||||
type: 'auth/sign_path',
|
||||
path: `/api/frigate/${this.clientId}` + `/jsmpeg/${this.cameraName}`,
|
||||
expires: URL_SIGN_EXPIRY_SECONDS,
|
||||
};
|
||||
// Sign the path so it includes an authSig parameter.
|
||||
let response;
|
||||
let response: string | null | undefined;
|
||||
try {
|
||||
response = await homeAssistantWSRequest(this.hass, signedPathSchema, request);
|
||||
response = await homeAssistantSignPath(
|
||||
this.hass,
|
||||
`/api/frigate/${this.clientId}` + `/jsmpeg/${this.cameraName}`,
|
||||
URL_SIGN_EXPIRY_SECONDS);
|
||||
} catch (err) {
|
||||
console.warn(err);
|
||||
return null;
|
||||
}
|
||||
const url = this.hass.hassUrl(response.path);
|
||||
return url.replace(/^http/i, 'ws');
|
||||
if (!response) {
|
||||
return null;
|
||||
}
|
||||
return response.replace(/^http/i, 'ws');
|
||||
}
|
||||
|
||||
protected _createJSMPEGPlayer(): JSMpeg.VideoElement {
|
||||
@@ -229,7 +226,7 @@ export class FrigateCardLiveJSMPEG extends LitElement {
|
||||
// ignore any subsequent calls.
|
||||
if (!videoDecoded && this._jsmpegCanvasElement) {
|
||||
videoDecoded = true;
|
||||
dispatchMediaLoadEvent(this, this._jsmpegCanvasElement);
|
||||
dispatchMediaShowEvent(this, this._jsmpegCanvasElement);
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
+112
-71
@@ -6,36 +6,33 @@ import {
|
||||
unsafeCSS,
|
||||
PropertyValues,
|
||||
} from 'lit';
|
||||
import { BrowseMediaUtil } from '../browse-media-util.js';
|
||||
import EmblaCarousel, { EmblaCarouselType } from 'embla-carousel';
|
||||
import { HomeAssistant } from 'custom-card-helpers';
|
||||
import { customElement, property } from 'lit/decorators.js';
|
||||
import { until } from 'lit/directives/until.js';
|
||||
import { ifDefined } from 'lit-html/directives/if-defined.js';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import dayjs_custom_parse_format from 'dayjs/plugin/customParseFormat.js';
|
||||
import { until } from 'lit/directives/until.js';
|
||||
|
||||
import type {
|
||||
BrowseMediaNeighbors,
|
||||
BrowseMediaQueryParameters,
|
||||
BrowseMediaSource,
|
||||
ExtendedHomeAssistant,
|
||||
MediaShowInfo,
|
||||
NextPreviousControlStyle,
|
||||
} from '../types.js';
|
||||
import { ResolvedMediaCache, ResolvedMediaUtil } from '../resolved-media.js';
|
||||
import { localize } from '../localize/localize.js';
|
||||
import { View } from '../view.js';
|
||||
import {
|
||||
browseMediaQuery,
|
||||
createMediaShowInfo,
|
||||
dispatchErrorMessageEvent,
|
||||
dispatchMediaLoadEvent,
|
||||
dispatchMessageEvent,
|
||||
dispatchPauseEvent,
|
||||
dispatchPlayEvent,
|
||||
getFirstTrueMediaChildIndex,
|
||||
isTrueMedia,
|
||||
dispatchExistingMediaShowInfoAsEvent,
|
||||
isValidMediaShowInfo,
|
||||
} from '../common.js';
|
||||
|
||||
import { View } from '../view.js';
|
||||
import { localize } from '../localize/localize.js';
|
||||
import { renderProgressIndicator } from '../components/message.js';
|
||||
|
||||
import './next-prev-control.js';
|
||||
@@ -45,9 +42,6 @@ import viewerStyle from '../scss/viewer.scss';
|
||||
const IMG_TRANSPARENT_1x1 =
|
||||
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=';
|
||||
|
||||
// Load dayjs plugin(s).
|
||||
dayjs.extend(dayjs_custom_parse_format);
|
||||
|
||||
@customElement('frigate-card-viewer')
|
||||
export class FrigateCardViewer extends LitElement {
|
||||
@property({ attribute: false })
|
||||
@@ -89,7 +83,7 @@ export class FrigateCardViewer extends LitElement {
|
||||
|
||||
let errorFree = true;
|
||||
for (let i = 0; target.children && i < (target.children || []).length; ++i) {
|
||||
if (isTrueMedia(target.children[i])) {
|
||||
if (BrowseMediaUtil.isTrueMedia(target.children[i])) {
|
||||
errorFree &&= !!(await ResolvedMediaUtil.resolveMedia(
|
||||
this.hass,
|
||||
target.children[i],
|
||||
@@ -110,16 +104,18 @@ export class FrigateCardViewer extends LitElement {
|
||||
}
|
||||
|
||||
let autoplay = true;
|
||||
let view = this.view;
|
||||
|
||||
if (!view.target) {
|
||||
if (this.view.is('clip') || this.view.is('snapshot')) {
|
||||
let parent: BrowseMediaSource | null = null;
|
||||
try {
|
||||
parent = await browseMediaQuery(this.hass, this.browseMediaQueryParameters);
|
||||
parent = await BrowseMediaUtil.browseMediaQuery(
|
||||
this.hass,
|
||||
this.browseMediaQueryParameters,
|
||||
);
|
||||
} catch (e) {
|
||||
return dispatchErrorMessageEvent(this, (e as Error).message);
|
||||
}
|
||||
const childIndex = getFirstTrueMediaChildIndex(parent);
|
||||
const childIndex = BrowseMediaUtil.getFirstTrueMediaChildIndex(parent);
|
||||
if (!parent || !parent.children || childIndex == null) {
|
||||
return dispatchMessageEvent(
|
||||
this,
|
||||
@@ -129,11 +125,8 @@ export class FrigateCardViewer extends LitElement {
|
||||
this.view.is('clip') ? 'mdi:filmstrip-off' : 'mdi:camera-off',
|
||||
);
|
||||
}
|
||||
view = new View({
|
||||
view: this.view.view,
|
||||
target: parent,
|
||||
childIndex: childIndex,
|
||||
});
|
||||
this.view.target = parent;
|
||||
this.view.childIndex = childIndex;
|
||||
|
||||
// In this block, no clip has been manually selected, so this is loading
|
||||
// the most recent clip on card load. In this mode, autoplay of the clip
|
||||
@@ -143,12 +136,12 @@ export class FrigateCardViewer extends LitElement {
|
||||
autoplay = this.autoplayClip ?? true;
|
||||
}
|
||||
|
||||
if (view.target && !(await this._resolveAllMediaForTarget(view.target))) {
|
||||
if (this.view.target && !(await this._resolveAllMediaForTarget(this.view.target))) {
|
||||
return dispatchErrorMessageEvent(this, localize('error.could_not_resolve'));
|
||||
}
|
||||
|
||||
return html` <frigate-card-viewer-core
|
||||
.view=${view}
|
||||
.view=${this.view}
|
||||
.nextPreviousControlStyle=${this.nextPreviousControlStyle}
|
||||
.resolvedMediaCache=${this.resolvedMediaCache}
|
||||
.autoplayClip=${autoplay}
|
||||
@@ -198,6 +191,10 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
// (Folders are not media items that can be rendered).
|
||||
protected _slideToChild: Record<number, number> = {};
|
||||
|
||||
// A "map" from slide number to MediaShowInfo object or null if the slide has
|
||||
// been lazy loaded, but the MediaShowInfo object is not yet available.
|
||||
protected _mediaShowInfo: Record<number, MediaShowInfo | null> = {};
|
||||
|
||||
/**
|
||||
* The updated lifecycle callback for this element.
|
||||
* @param changedProperties The properties that were changed in this render.
|
||||
@@ -233,8 +230,9 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
this._carousel = EmblaCarousel(carouselNode, {
|
||||
startIndex: isNaN(startIndex) ? undefined : startIndex,
|
||||
});
|
||||
// Update views based on slide selections.
|
||||
this._carousel.on('select', this._slideSelectHandler.bind(this));
|
||||
// Update views and dispatch media-show events based on slide selections.
|
||||
this._carousel.on('select', this._selectSlideSetViewHandler.bind(this));
|
||||
this._carousel.on('select', this._selectSlideMediaShowHandler.bind(this));
|
||||
|
||||
// Lazily load media that is displayed. These handlers are registered
|
||||
// regardless of the value of this.lazyLoad to allow that value to change
|
||||
@@ -245,28 +243,6 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the event start time from a media object.
|
||||
* @param browseMedia The media object to extract the start time from.
|
||||
* @returns The start time in unix/epoch time, or null if it cannot be determined.
|
||||
*/
|
||||
protected _extractEventStartTimeFromBrowseMedia(
|
||||
browseMedia: BrowseMediaSource,
|
||||
): number | null {
|
||||
// Example: 2021-08-27 20:57:22 [10s, Person 76%]
|
||||
const result = browseMedia.title.match(/^(?<iso_datetime>.+) \[/);
|
||||
if (result && result.groups) {
|
||||
const iso_datetime_str = result.groups['iso_datetime'];
|
||||
if (iso_datetime_str) {
|
||||
const iso_datetime = dayjs(iso_datetime_str, 'YYYY-MM-DD HH:mm:ss', true);
|
||||
if (iso_datetime.isValid()) {
|
||||
return iso_datetime.unix();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the previous and next true media items from the current view.
|
||||
* @returns A BrowseMediaNeighbors with indices and objects of true media
|
||||
@@ -286,7 +262,7 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
let prevIndex: number | null = null;
|
||||
for (let i = this.view.childIndex - 1; i >= 0; i--) {
|
||||
const media = this.view.target.children[i];
|
||||
if (media && isTrueMedia(media)) {
|
||||
if (media && BrowseMediaUtil.isTrueMedia(media)) {
|
||||
prevIndex = i;
|
||||
break;
|
||||
}
|
||||
@@ -296,7 +272,7 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
let nextIndex: number | null = null;
|
||||
for (let i = this.view.childIndex + 1; i < this.view.target.children.length; i++) {
|
||||
const media = this.view.target.children[i];
|
||||
if (media && isTrueMedia(media)) {
|
||||
if (media && BrowseMediaUtil.isTrueMedia(media)) {
|
||||
nextIndex = i;
|
||||
break;
|
||||
}
|
||||
@@ -330,7 +306,7 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
return null;
|
||||
}
|
||||
|
||||
const snapshotStartTime = this._extractEventStartTimeFromBrowseMedia(snapshot);
|
||||
const snapshotStartTime = BrowseMediaUtil.extractEventStartTime(snapshot);
|
||||
if (!snapshotStartTime) {
|
||||
return null;
|
||||
}
|
||||
@@ -348,10 +324,10 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
let latest: number | null = null;
|
||||
for (let i = 0; i < this.view.target.children.length; i++) {
|
||||
const child = this.view.target.children[i];
|
||||
if (!isTrueMedia(child)) {
|
||||
if (!BrowseMediaUtil.isTrueMedia(child)) {
|
||||
continue;
|
||||
}
|
||||
const startTime = this._extractEventStartTimeFromBrowseMedia(child);
|
||||
const startTime = BrowseMediaUtil.extractEventStartTime(child);
|
||||
|
||||
if (startTime && (earliest === null || startTime < earliest)) {
|
||||
earliest = startTime;
|
||||
@@ -367,7 +343,7 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
let clips: BrowseMediaSource | null;
|
||||
|
||||
try {
|
||||
clips = await browseMediaQuery(this.hass, {
|
||||
clips = await BrowseMediaUtil.browseMediaQuery(this.hass, {
|
||||
...this.browseMediaQueryParameters,
|
||||
mediaType: 'clips',
|
||||
before: latest,
|
||||
@@ -384,13 +360,13 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
|
||||
for (let i = 0; i < clips.children.length; i++) {
|
||||
const child = clips.children[i];
|
||||
if (!isTrueMedia(child)) {
|
||||
if (!BrowseMediaUtil.isTrueMedia(child)) {
|
||||
continue;
|
||||
}
|
||||
const clipStartTime = this._extractEventStartTimeFromBrowseMedia(child);
|
||||
const clipStartTime = BrowseMediaUtil.extractEventStartTime(child);
|
||||
if (clipStartTime && clipStartTime === snapshotStartTime) {
|
||||
return new View({
|
||||
view: 'clip',
|
||||
view: 'clip-specific',
|
||||
target: clips,
|
||||
childIndex: i,
|
||||
previous: this.view,
|
||||
@@ -403,12 +379,12 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
/**
|
||||
* Handle the user selecting a new slide in the carousel.
|
||||
*/
|
||||
protected _slideSelectHandler(): void {
|
||||
protected _selectSlideSetViewHandler(): void {
|
||||
if (!this._carousel || !this.view) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update the childIndex in the view (without re-render)
|
||||
// Update the childIndex in the view.
|
||||
const slidesInView = this._carousel.slidesInView(true);
|
||||
if (slidesInView.length) {
|
||||
const childIndex = this._slideToChild[slidesInView[0]];
|
||||
@@ -434,8 +410,6 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
|
||||
/**
|
||||
* Lazily load media in the carousel.
|
||||
* @param eventName The Embla event name that triggered this load.
|
||||
* // TODO delete eventName above?
|
||||
*/
|
||||
protected _lazyLoadMediaHandler(): void {
|
||||
if (!this.lazyLoad || !this._carousel) {
|
||||
@@ -459,6 +433,12 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
}
|
||||
|
||||
slidesToLoad.forEach((index) => {
|
||||
// Only lazy loads slides that are not already loaded.
|
||||
if (index in this._mediaShowInfo) {
|
||||
return;
|
||||
}
|
||||
this._mediaShowInfo[index] = null;
|
||||
|
||||
const slide = slides[index];
|
||||
|
||||
// Snapshots.
|
||||
@@ -505,7 +485,7 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
this._slideToChild = {};
|
||||
|
||||
for (let i = 0; i < this.view.target.children?.length; ++i) {
|
||||
const slide = this._renderMediaItem(this.view.target.children[i]);
|
||||
const slide = this._renderMediaItem(this.view.target.children[i], slides.length);
|
||||
if (slide) {
|
||||
this._slideToChild[slides.length] = i;
|
||||
slides.push(slide);
|
||||
@@ -541,15 +521,72 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fire a media show event when a slide is selected.
|
||||
*/
|
||||
protected _selectSlideMediaShowHandler(): void {
|
||||
if (!this._carousel || !this.view) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._carousel.slidesInView(true).forEach((slideIndex) => {
|
||||
if (slideIndex in this._mediaShowInfo) {
|
||||
const mediaShowInfo = this._mediaShowInfo[slideIndex];
|
||||
if (mediaShowInfo) {
|
||||
dispatchExistingMediaShowInfoAsEvent(this, mediaShowInfo);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a media-show event that is generated by a child component, saving the
|
||||
* contents for future use when the relevant slide is shown.
|
||||
* @param slideIndex The relevant slide index.
|
||||
* @param event The media-show event from the child component.
|
||||
*/
|
||||
protected _mediaShowEventHandler(
|
||||
slideIndex: number,
|
||||
event: CustomEvent<MediaShowInfo>,
|
||||
): void {
|
||||
this._mediaShowInfoHandler(slideIndex, event.detail);
|
||||
// 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();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle a MediaShowInfo object that is generated on media load, by saving it
|
||||
* for future, or immediate use, when the relevant slide is displayed.
|
||||
* @param slideIndex The relevant slide index.
|
||||
* @param mediaShowInfo The MediaShowInfo object generated by the media.
|
||||
*/
|
||||
protected _mediaShowInfoHandler(
|
||||
slideIndex: number,
|
||||
mediaShowInfo?: MediaShowInfo | null,
|
||||
): void {
|
||||
// isValidMediaShowInfo is used to weed out the initial load of the
|
||||
// transparent 1x1 placeholders.
|
||||
if (mediaShowInfo && isValidMediaShowInfo(mediaShowInfo)) {
|
||||
this._mediaShowInfo[slideIndex] = mediaShowInfo;
|
||||
if (this._carousel && this._carousel?.slidesInView(true).includes(slideIndex)) {
|
||||
dispatchExistingMediaShowInfoAsEvent(this, mediaShowInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a given media item.
|
||||
* @param mediaToRender The media item to render.
|
||||
* @returns A template or void if the item could not be rendered.
|
||||
*/
|
||||
protected _renderMediaItem(mediaToRender: BrowseMediaSource): TemplateResult | void {
|
||||
protected _renderMediaItem(
|
||||
mediaToRender: BrowseMediaSource,
|
||||
slideIndex: number,
|
||||
): TemplateResult | void {
|
||||
// media that can be expanded (folders) cannot be resolved to a single media
|
||||
// item, skip them.
|
||||
if (!this.view || !isTrueMedia(mediaToRender)) {
|
||||
if (!this.view || !BrowseMediaUtil.isTrueMedia(mediaToRender)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -560,7 +597,7 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
|
||||
return html`
|
||||
<div class="embla__slide">
|
||||
${this.view.is('clip')
|
||||
${this.view.isClipRelatedView()
|
||||
? resolvedMedia?.mime_type.toLowerCase() == 'application/x-mpegurl'
|
||||
? html`<frigate-card-ha-hls-player
|
||||
.hass=${this.hass}
|
||||
@@ -572,6 +609,8 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
playsinline
|
||||
allow-exoplayer
|
||||
?autoplay="${this.autoplayClip}"
|
||||
@frigate-card:media-show=${(e: CustomEvent<MediaShowInfo>) =>
|
||||
this._mediaShowEventHandler(slideIndex, e)}
|
||||
>
|
||||
</frigate-card-ha-hls-player>`
|
||||
: html`<video
|
||||
@@ -580,7 +619,9 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
controls
|
||||
playsinline
|
||||
?autoplay="${this.autoplayClip}"
|
||||
@loadedmetadata="${(e) => dispatchMediaLoadEvent(this, e)}"
|
||||
@loadedmetadata="${(e: Event) => {
|
||||
this._mediaShowInfoHandler(slideIndex, createMediaShowInfo(e));
|
||||
}}"
|
||||
@play=${() => dispatchPlayEvent(this)}
|
||||
@pause=${() => dispatchPauseEvent(this)}
|
||||
>
|
||||
@@ -603,9 +644,9 @@ export class FrigateCardViewerCore extends LitElement {
|
||||
});
|
||||
}
|
||||
}}
|
||||
@load=${(e) => {
|
||||
dispatchMediaLoadEvent(this, e);
|
||||
}}
|
||||
@load="${(e: Event) => {
|
||||
this._mediaShowInfoHandler(slideIndex, createMediaShowInfo(e));
|
||||
}}"
|
||||
/>`}
|
||||
</div>
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user