Files
MajoorWaldi-ComfyUI-Majoor-…/js/features/viewer/imagePreloader.js
T
Ewald 79f98217c5 feat(viewer): enhance video controls and asset navigation
- Add keyboard shortcuts for video in-point (I), out-point (O), and navigation (Home/End)
- Implement swipe gesture for navigating between assets in the viewer
- Add option to copy prompt to clipboard (Ctrl/Cmd+C)
- Improve stack group card functionality and representative selection
- Optimize image preloading for smoother navigation
- Enhance audio visualizer with WebGL support and mode switching
- Refine feed card appearance and interaction
2026-04-08 20:50:26 +02:00

94 lines
3.2 KiB
JavaScript

/**
* Image preloader module — prefetches adjacent images while browsing assets.
*/
export function createImagePreloader({ buildAssetViewURL, IMAGE_PRELOAD_EXTENSIONS, state }) {
function getPreloadKey(asset) {
if (!asset) return null;
if (asset.id != null) return `id:${asset.id}`;
const fallback = asset.filepath || asset.path || asset.filename;
if (fallback) return `path:${fallback}`;
return null;
}
function isImageAsset(asset) {
if (!asset) return false;
const kind = String(asset.kind || "").toLowerCase();
if (kind === "image" || kind.startsWith("image/")) return true;
const filename = String(asset.filepath || asset.path || asset.filename || "");
const ext = filename.split(".").pop()?.toLowerCase() || "";
return IMAGE_PRELOAD_EXTENSIONS.has(ext);
}
function trackPreloadRef(img) {
if (!img) return;
try {
state._preloadRefs = state._preloadRefs || new Set();
state._preloadRefs.add(img);
const cleanup = () => {
try {
state._preloadRefs?.delete?.(img);
} catch (e) {
console.debug?.(e);
}
};
img.addEventListener("load", cleanup, { once: true, passive: true });
img.addEventListener("error", cleanup, { once: true, passive: true });
} catch (e) {
console.debug?.(e);
}
}
function preloadImageForAsset(asset, url) {
if (!asset || !url) return;
if (!isImageAsset(asset)) return;
const key = getPreloadKey(asset) || url;
if (key) {
state._preloadedAssetKeys = state._preloadedAssetKeys || new Set();
if (state._preloadedAssetKeys.has(key)) return;
state._preloadedAssetKeys.add(key);
if (state._preloadedAssetKeys.size > 250) {
try {
state._preloadedAssetKeys.clear();
} catch (e) {
console.debug?.(e);
}
}
}
try {
const img = new Image();
img.decoding = "async";
try {
img.loading = "lazy";
} catch (e) {
console.debug?.(e);
}
img.alt = "";
img.src = url;
trackPreloadRef(img);
} catch (e) {
console.debug?.(e);
}
}
function preloadAdjacentAssets(assets, centerIndex) {
const assetList = Array.isArray(assets) ? assets : [];
if (!assetList.length) return;
// Preload ±3 images for smoother navigation (prioritize closest first)
const candidates = [
centerIndex - 1, centerIndex + 1,
centerIndex - 2, centerIndex + 2,
centerIndex - 3, centerIndex + 3,
];
for (const idx of candidates) {
if (idx < 0 || idx >= assetList.length) continue;
const asset = assetList[idx];
if (!asset) continue;
const url = buildAssetViewURL(asset);
preloadImageForAsset(asset, url);
}
}
return { preloadAdjacentAssets, preloadImageForAsset, trackPreloadRef };
}