Add live view lazy unloading support.
This commit is contained in:
@@ -1,12 +1,15 @@
|
||||
import { EmblaCarouselType, EmblaPluginType } from 'embla-carousel';
|
||||
import { EmblaCarouselType, EmblaEventType, EmblaPluginType } from 'embla-carousel';
|
||||
|
||||
export type LazyloadOptionsType = {
|
||||
count?: number;
|
||||
lazyloadCallback: (index: number, slide: HTMLElement) => void;
|
||||
// Number of slides to lazyload left/right of selected (0 == only selected slide).
|
||||
lazyloadCount?: number;
|
||||
|
||||
lazyloadCallback?: (index: number, slide: HTMLElement) => void;
|
||||
lazyunloadCallback?: (index: number, slide: HTMLElement) => void;
|
||||
};
|
||||
|
||||
export const defaultOptions: Partial<LazyloadOptionsType> = {
|
||||
count: 0,
|
||||
lazyloadCount: 0,
|
||||
};
|
||||
|
||||
export type LazyloadType = EmblaPluginType<LazyloadOptionsType> & {
|
||||
@@ -20,6 +23,9 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType {
|
||||
let slides: HTMLElement[];
|
||||
const isSlideLazyloaded: Record<number, boolean> = {};
|
||||
|
||||
const loadEvents: EmblaEventType[] = ['init', 'select', 'resize'];
|
||||
const unloadEvents: EmblaEventType[] = ['select'];
|
||||
|
||||
/**
|
||||
* Initialize the plugin.
|
||||
*/
|
||||
@@ -27,18 +33,24 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType {
|
||||
carousel = embla;
|
||||
slides = carousel.slideNodes();
|
||||
|
||||
carousel.on('init', lazyLoadHandler);
|
||||
carousel.on('select', lazyLoadHandler);
|
||||
carousel.on('resize', lazyLoadHandler);
|
||||
if (options.lazyloadCallback) {
|
||||
loadEvents.forEach((evt) => carousel.on(evt, lazyloadHandler));
|
||||
}
|
||||
if (options.lazyunloadCallback) {
|
||||
unloadEvents.forEach((evt) => carousel.on(evt, lazyunloadHandler));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the plugin.
|
||||
*/
|
||||
function destroy(): void {
|
||||
carousel.off('init', lazyLoadHandler);
|
||||
carousel.off('select', lazyLoadHandler);
|
||||
carousel.off('resize', lazyLoadHandler);
|
||||
if (options.lazyloadCallback) {
|
||||
loadEvents.forEach((evt) => carousel.off(evt, lazyloadHandler));
|
||||
}
|
||||
if (options.lazyunloadCallback) {
|
||||
unloadEvents.forEach((evt) => carousel.off(evt, lazyunloadHandler));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -53,21 +65,18 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType {
|
||||
/**
|
||||
* Lazily load media in the carousel.
|
||||
*/
|
||||
function lazyLoadHandler(): void {
|
||||
const lazyLoadCount = options.count ?? 0;
|
||||
const slidesInView = carousel.slidesInView(true);
|
||||
function lazyloadHandler(): void {
|
||||
const lazyLoadCount = options.lazyloadCount ?? 0;
|
||||
const currentIndex = carousel.selectedScrollSnap();
|
||||
const slidesToLoad = new Set<number>();
|
||||
|
||||
const minSlide = Math.min(...slidesInView);
|
||||
const maxSlide = Math.max(...slidesInView);
|
||||
|
||||
// Lazily load 'count' slides on either side of the slides in view.
|
||||
for (let i = 1; i <= lazyLoadCount && minSlide - i >= 0; i++) {
|
||||
slidesToLoad.add(minSlide - i);
|
||||
for (let i = 1; i <= lazyLoadCount && currentIndex - i >= 0; i++) {
|
||||
slidesToLoad.add(currentIndex - i);
|
||||
}
|
||||
slidesInView.forEach((index) => slidesToLoad.add(index));
|
||||
for (let i = 1; i <= lazyLoadCount && maxSlide + i < slides.length; i++) {
|
||||
slidesToLoad.add(maxSlide + i);
|
||||
slidesToLoad.add(currentIndex);
|
||||
for (let i = 1; i <= lazyLoadCount && currentIndex + i < slides.length; i++) {
|
||||
slidesToLoad.add(currentIndex + i);
|
||||
}
|
||||
|
||||
slidesToLoad.forEach((index) => {
|
||||
@@ -75,11 +84,29 @@ export function Lazyload(userOptions?: LazyloadOptionsType): LazyloadType {
|
||||
if (isSlideLazyloaded[index]) {
|
||||
return;
|
||||
}
|
||||
isSlideLazyloaded[index] = true;
|
||||
options.lazyloadCallback(index, slides[index]);
|
||||
if (options.lazyloadCallback) {
|
||||
isSlideLazyloaded[index] = true;
|
||||
options.lazyloadCallback(index, slides[index]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily unload media in the carousel.
|
||||
*/
|
||||
function lazyunloadHandler(): void {
|
||||
const index = carousel.previousScrollSnap();
|
||||
|
||||
// Only lazy unload slides that are loaded.
|
||||
if (!isSlideLazyloaded[index]) {
|
||||
return;
|
||||
}
|
||||
if (options.lazyunloadCallback) {
|
||||
options.lazyunloadCallback(index, slides[index]);
|
||||
isSlideLazyloaded[index] = false;
|
||||
}
|
||||
}
|
||||
|
||||
const self: LazyloadType = {
|
||||
name: 'Lazyload',
|
||||
options,
|
||||
|
||||
+21
-14
@@ -297,13 +297,14 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
|
||||
*/
|
||||
protected _getPlugins(): EmblaPluginType[] | undefined {
|
||||
return [
|
||||
...(this.liveConfig?.lazy_load
|
||||
? [
|
||||
Lazyload({
|
||||
lazyloadCallback: this._lazyLoadSlide.bind(this),
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
Lazyload({
|
||||
lazyloadCallback: this.liveConfig?.lazy_load
|
||||
? (...args) => this._lazyloadOrUnloadSlide('load', ...args)
|
||||
: undefined,
|
||||
lazyunloadCallback: this.liveConfig?.lazy_unload
|
||||
? (...args) => this._lazyloadOrUnloadSlide('unload', ...args)
|
||||
: undefined,
|
||||
}),
|
||||
MediaAutoPlayPause({
|
||||
playerSelector: 'frigate-card-live-provider',
|
||||
}),
|
||||
@@ -367,12 +368,16 @@ export class FrigateCardLiveCarousel extends FrigateCardMediaCarousel {
|
||||
* @param _index The slide number to lazy load.
|
||||
* @param slide The slide to lazy load.
|
||||
*/
|
||||
protected _lazyLoadSlide(_index: number, slide: HTMLElement): void {
|
||||
protected _lazyloadOrUnloadSlide(
|
||||
action: 'load' | 'unload',
|
||||
_index: number,
|
||||
slide: HTMLElement,
|
||||
): void {
|
||||
const liveProvider = slide.querySelector(
|
||||
'frigate-card-live-provider',
|
||||
) as FrigateCardLiveProvider;
|
||||
if (liveProvider) {
|
||||
liveProvider.disabled = false;
|
||||
liveProvider.disabled = action == 'load' ? false : true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -680,11 +685,13 @@ export class FrigateCardLiveWebRTC extends LitElement {
|
||||
* Play the video.
|
||||
*/
|
||||
public play(): void {
|
||||
this._getPlayer()?.play().catch(() => {
|
||||
// WebRTC appears to generate additional spurious load events, which may
|
||||
// result in loads after a play() call, which causes the browser to spam
|
||||
// the logs unless the promise rejection is handled here.
|
||||
})
|
||||
this._getPlayer()
|
||||
?.play()
|
||||
.catch(() => {
|
||||
// WebRTC appears to generate additional spurious load events, which may
|
||||
// result in loads after a play() call, which causes the browser to spam
|
||||
// the logs unless the promise rejection is handled here.
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -311,14 +311,11 @@ export class FrigateCardViewerCarousel extends FrigateCardMediaCarousel {
|
||||
*/
|
||||
protected _getPlugins(): EmblaPluginType[] | undefined {
|
||||
return [
|
||||
...(this.viewerConfig?.lazy_load
|
||||
? [
|
||||
Lazyload({
|
||||
lazyloadCallback: this._lazyLoadSlide.bind(this),
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
|
||||
Lazyload({
|
||||
lazyloadCallback: this.viewerConfig?.lazy_load
|
||||
? this._lazyloadSlide.bind(this)
|
||||
: undefined,
|
||||
}),
|
||||
// Don't need autoplay/pause for snapshots.
|
||||
...(this.view?.is('clip')
|
||||
? [
|
||||
@@ -493,7 +490,7 @@ export class FrigateCardViewerCarousel extends FrigateCardMediaCarousel {
|
||||
* @param slide The slide to lazy load.
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
protected _lazyLoadSlide(index: number, slide: HTMLElement): void {
|
||||
protected _lazyloadSlide(index: number, slide: HTMLElement): void {
|
||||
const childIndex: number | undefined = this._slideToChild[index];
|
||||
|
||||
if (
|
||||
|
||||
Reference in New Issue
Block a user