Fix substantial performance issue with thumbnails.

This commit is contained in:
Dermot Duffy
2022-09-22 17:44:44 -07:00
parent b9b539bf72
commit c910b5d2a4
3 changed files with 70 additions and 23 deletions
+55 -13
View File
@@ -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 {
+1
View File
@@ -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
View File
@@ -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()],
); );
}; };