Fix substantial performance issue with thumbnails.
This commit is contained in:
+55
-13
@@ -16,6 +16,7 @@ import { renderTask } from '../utils/task.js';
|
|||||||
import { createFetchThumbnailTask } from '../utils/thumbnail.js';
|
import { createFetchThumbnailTask } from '../utils/thumbnail.js';
|
||||||
import { View } from '../view.js';
|
import { View } from '../view.js';
|
||||||
import { MediaSeek } from './viewer.js';
|
import { MediaSeek } from './viewer.js';
|
||||||
|
import { TaskStatus } from '@lit-labs/task';
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
ExtendedHomeAssistant,
|
ExtendedHomeAssistant,
|
||||||
@@ -38,22 +39,63 @@ export class FrigateCardThumbnailFeatureEvent extends LitElement {
|
|||||||
this,
|
this,
|
||||||
() => this.hass,
|
() => this.hass,
|
||||||
() => this.thumbnail,
|
() => this.thumbnail,
|
||||||
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Only load thumbnails on view in case there is a very large number of them.
|
||||||
|
protected _intersectionObserver: IntersectionObserver;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this._intersectionObserver = new IntersectionObserver(
|
||||||
|
this._intersectionHandler.bind(this),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component connected callback.
|
||||||
|
*/
|
||||||
|
connectedCallback(): void {
|
||||||
|
this._intersectionObserver.observe(this);
|
||||||
|
super.connectedCallback();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component disconnected callback.
|
||||||
|
*/
|
||||||
|
disconnectedCallback(): void {
|
||||||
|
super.disconnectedCallback();
|
||||||
|
this._intersectionObserver.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the live view intersects with the viewport.
|
||||||
|
* @param entries The IntersectionObserverEntry entries (should be only 1).
|
||||||
|
*/
|
||||||
|
protected _intersectionHandler(entries: IntersectionObserverEntry[]): void {
|
||||||
|
if (
|
||||||
|
this._embedThumbnailTask.status === TaskStatus.INITIAL &&
|
||||||
|
entries.some((entry) => entry.isIntersecting)
|
||||||
|
) {
|
||||||
|
this._embedThumbnailTask.run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected render(): TemplateResult | void {
|
protected render(): TemplateResult | void {
|
||||||
return html`
|
const imageOff = html`<ha-icon
|
||||||
${this.thumbnail
|
icon="mdi:image-off"
|
||||||
? renderTask(
|
title=${localize('thumbnail.no_thumbnail')}
|
||||||
this,
|
></ha-icon> `;
|
||||||
this._embedThumbnailTask,
|
|
||||||
(embeddedThumbnail: string | null) =>
|
return html`${this.thumbnail
|
||||||
embeddedThumbnail ? html`<img src="${embeddedThumbnail}" />` : html``,
|
? renderTask(
|
||||||
)
|
this,
|
||||||
: html`<ha-icon
|
this._embedThumbnailTask,
|
||||||
icon="mdi:image-off"
|
(embeddedThumbnail: string | null) =>
|
||||||
title=${localize('thumbnail.no_thumbnail')}
|
embeddedThumbnail ? html`<img src="${embeddedThumbnail}" />` : html``,
|
||||||
></ha-icon> `}
|
() => imageOff,
|
||||||
`;
|
)
|
||||||
|
: imageOff} `;
|
||||||
}
|
}
|
||||||
|
|
||||||
static get styles(): CSSResult {
|
static get styles(): CSSResult {
|
||||||
|
|||||||
@@ -30,4 +30,5 @@ ha-icon {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.3);
|
border: 1px solid rgba(255, 255, 255, 0.3);
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
opacity: 0.2;
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-10
@@ -55,19 +55,23 @@ export const createFetchThumbnailTask = (
|
|||||||
host: ReactiveControllerHost,
|
host: ReactiveControllerHost,
|
||||||
getHASS: () => HomeAssistant | undefined,
|
getHASS: () => HomeAssistant | undefined,
|
||||||
getThumbnailURL: () => string | undefined,
|
getThumbnailURL: () => string | undefined,
|
||||||
|
autoRun = true,
|
||||||
): Task<FetchThumbnailTaskArgs, string | null> => {
|
): Task<FetchThumbnailTaskArgs, string | null> => {
|
||||||
return new Task(
|
return new Task(
|
||||||
host,
|
host,
|
||||||
async ([haveHASS, thumbnailURL]: FetchThumbnailTaskArgs): Promise<
|
{
|
||||||
string | null
|
// Do not re-run the task if hass changes, unless it was previously undefined.
|
||||||
> => {
|
args: (): FetchThumbnailTaskArgs => [!!getHASS(), getThumbnailURL()],
|
||||||
const hass = getHASS();
|
task: async ([haveHASS, thumbnailURL]: FetchThumbnailTaskArgs): Promise<
|
||||||
if (!haveHASS || !hass || !thumbnailURL) {
|
string | null
|
||||||
return null;
|
> => {
|
||||||
}
|
const hass = getHASS();
|
||||||
return fetchThumbnail(hass, thumbnailURL);
|
if (!haveHASS || !hass || !thumbnailURL) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return fetchThumbnail(hass, thumbnailURL);
|
||||||
|
},
|
||||||
|
autoRun: autoRun,
|
||||||
},
|
},
|
||||||
// Do not re-run the task if hass changes, unless it was previously undefined.
|
|
||||||
(): FetchThumbnailTaskArgs => [!!getHASS(), getThumbnailURL()],
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user