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
+49 -7
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"
title=${localize('thumbnail.no_thumbnail')}
></ha-icon> `;
return html`${this.thumbnail
? renderTask( ? renderTask(
this, this,
this._embedThumbnailTask, this._embedThumbnailTask,
(embeddedThumbnail: string | null) => (embeddedThumbnail: string | null) =>
embeddedThumbnail ? html`<img src="${embeddedThumbnail}" />` : html``, embeddedThumbnail ? html`<img src="${embeddedThumbnail}" />` : html``,
() => imageOff,
) )
: html`<ha-icon : imageOff} `;
icon="mdi:image-off"
title=${localize('thumbnail.no_thumbnail')}
></ha-icon> `}
`;
} }
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;
} }
+7 -3
View File
@@ -55,10 +55,14 @@ 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< {
// Do not re-run the task if hass changes, unless it was previously undefined.
args: (): FetchThumbnailTaskArgs => [!!getHASS(), getThumbnailURL()],
task: async ([haveHASS, thumbnailURL]: FetchThumbnailTaskArgs): Promise<
string | null string | null
> => { > => {
const hass = getHASS(); const hass = getHASS();
@@ -67,7 +71,7 @@ export const createFetchThumbnailTask = (
} }
return fetchThumbnail(hass, thumbnailURL); return fetchThumbnail(hass, thumbnailURL);
}, },
// Do not re-run the task if hass changes, unless it was previously undefined. autoRun: autoRun,
(): FetchThumbnailTaskArgs => [!!getHASS(), getThumbnailURL()], },
); );
}; };