mirror of
https://github.com/willmiao/ComfyUI-Lora-Manager.git
synced 2026-09-20 18:51:26 -03:00
perf(showcase): prefetch adjacent examples and shrink gallery thumbnails
- Warm the HTTP cache for examples adjacent to the active one after expand and on every navigation, so prev/next feels instant (images only, deduped, low fetch priority) - Add GALLERY_THUMBNAIL optimization mode (width=160) for the 72px gallery strip instead of reusing the 450px card thumbnails - Hint priorities: fetchpriority=high on the main media, low on strip thumbnails
This commit is contained in:
@@ -197,4 +197,64 @@ describe('Showcase gallery', () => {
|
||||
expect(document.querySelector('.gallery-indicator-bar')).toBeTruthy();
|
||||
expect(document.querySelectorAll('.gallery-thumb')).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('prefetches adjacent example images (skipping videos) while expanded', async () => {
|
||||
const { renderShowcaseContent, initShowcaseContent, updateMainDisplay } = await import(SHOWCASE_MODULE);
|
||||
|
||||
const prefetched = [];
|
||||
class MockImage {
|
||||
set src(value) { prefetched.push(value); }
|
||||
set fetchPriority(_value) { /* jsdom lacks fetchPriority */ }
|
||||
}
|
||||
vi.stubGlobal('Image', MockImage);
|
||||
|
||||
// Unique URLs: the module-level prefetch dedup set persists across tests
|
||||
const images = [
|
||||
{ url: 'https://image.civitai.com/pf/aaa.jpeg', width: 100, height: 100, nsfwLevel: 0 },
|
||||
{ url: 'https://image.civitai.com/pf/bbb.jpeg', width: 100, height: 100, nsfwLevel: 0 },
|
||||
{ url: 'https://image.civitai.com/pf/ccc.mp4', width: 100, height: 100, nsfwLevel: 0 },
|
||||
];
|
||||
document.body.innerHTML = `<div id="showcase-tab">${renderShowcaseContent(images, [], PREVIEW_URL, true)}</div>`;
|
||||
initShowcaseContent(document.querySelector('.showcase-gallery'));
|
||||
|
||||
// galleryState.activeIndex persists across tests → pin it to 0
|
||||
updateMainDisplay(0);
|
||||
|
||||
// Active index 0 → prefetches index 1; index 2 is a video and is skipped
|
||||
expect(prefetched).toContain('https://image.civitai.com/pf/bbb.jpeg');
|
||||
expect(prefetched).not.toContain('https://image.civitai.com/pf/ccc.mp4');
|
||||
|
||||
// Navigating to 1 prefetches the new neighbor (index 0)
|
||||
updateMainDisplay(1);
|
||||
expect(prefetched).toContain('https://image.civitai.com/pf/aaa.jpeg');
|
||||
|
||||
// Navigating back does not duplicate prefetch requests
|
||||
const count = prefetched.length;
|
||||
updateMainDisplay(0);
|
||||
expect(prefetched).toHaveLength(count);
|
||||
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
|
||||
it('does not prefetch while collapsed', async () => {
|
||||
const { renderShowcaseContent, initShowcaseContent } = await import(SHOWCASE_MODULE);
|
||||
|
||||
const prefetched = [];
|
||||
class MockImage {
|
||||
set src(value) { prefetched.push(value); }
|
||||
set fetchPriority(_value) { /* jsdom lacks fetchPriority */ }
|
||||
}
|
||||
vi.stubGlobal('Image', MockImage);
|
||||
|
||||
const images = [
|
||||
{ url: 'https://image.civitai.com/pc/ddd.jpeg', width: 100, height: 100, nsfwLevel: 0 },
|
||||
{ url: 'https://image.civitai.com/pc/eee.jpeg', width: 100, height: 100, nsfwLevel: 0 },
|
||||
];
|
||||
document.body.innerHTML = `<div id="showcase-tab">${renderShowcaseContent(images, [], PREVIEW_URL)}</div>`;
|
||||
initShowcaseContent(document.querySelector('.showcase-gallery'));
|
||||
|
||||
expect(prefetched).toHaveLength(0);
|
||||
|
||||
vi.unstubAllGlobals();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
getOptimizedUrl,
|
||||
getShowcaseUrl,
|
||||
getThumbnailUrl,
|
||||
getGalleryThumbnailUrl,
|
||||
extractCivitaiImageId,
|
||||
extractCivitaiModelUrlParts,
|
||||
classifyModelRelinkUrl,
|
||||
@@ -22,6 +23,7 @@ describe('civitaiUtils', () => {
|
||||
it('should have correct mode values', () => {
|
||||
expect(OptimizationMode.SHOWCASE).toBe('showcase');
|
||||
expect(OptimizationMode.THUMBNAIL).toBe('thumbnail');
|
||||
expect(OptimizationMode.GALLERY_THUMBNAIL).toBe('gallery-thumbnail');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -107,6 +109,22 @@ describe('civitaiUtils', () => {
|
||||
expect(rewritten).toBe('https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/abc123/width=450,optimized=true/12345.jpeg');
|
||||
});
|
||||
|
||||
it('should rewrite image URLs with /original=true for gallery-thumbnail mode (width=160)', () => {
|
||||
const originalUrl = 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/abc123/original=true/12345.jpeg';
|
||||
const [rewritten, wasRewritten] = rewriteCivitaiUrl(originalUrl, 'image', OptimizationMode.GALLERY_THUMBNAIL);
|
||||
|
||||
expect(wasRewritten).toBe(true);
|
||||
expect(rewritten).toBe('https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/abc123/width=160,optimized=true/12345.jpeg');
|
||||
});
|
||||
|
||||
it('should rewrite video URLs with /original=true for gallery-thumbnail mode', () => {
|
||||
const originalUrl = 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/abc123/original=true/12345.mp4';
|
||||
const [rewritten, wasRewritten] = rewriteCivitaiUrl(originalUrl, 'video', OptimizationMode.GALLERY_THUMBNAIL);
|
||||
|
||||
expect(wasRewritten).toBe(true);
|
||||
expect(rewritten).toBe('https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/abc123/transcode=true,width=160,optimized=true/12345.mp4');
|
||||
});
|
||||
|
||||
it('should not rewrite URLs without /original=true', () => {
|
||||
const originalUrl = 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/abc123/width=450/12345.jpeg';
|
||||
const [rewritten, wasRewritten] = rewriteCivitaiUrl(originalUrl, 'image', OptimizationMode.THUMBNAIL);
|
||||
@@ -232,6 +250,22 @@ describe('civitaiUtils', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGalleryThumbnailUrl', () => {
|
||||
it('should return gallery-thumbnail-optimized URL (width=160)', () => {
|
||||
const originalUrl = 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/abc123/original=true/12345.jpeg';
|
||||
const thumbnailUrl = getGalleryThumbnailUrl(originalUrl, 'image');
|
||||
|
||||
expect(thumbnailUrl).toBe('https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/abc123/width=160,optimized=true/12345.jpeg');
|
||||
});
|
||||
|
||||
it('should handle videos for gallery thumbnails', () => {
|
||||
const originalUrl = 'https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/abc123/original=true/12345.mp4';
|
||||
const thumbnailUrl = getGalleryThumbnailUrl(originalUrl, 'video');
|
||||
|
||||
expect(thumbnailUrl).toBe('https://image.civitai.com/xG1nkqKTMzGDvpLrqFT7WA/abc123/transcode=true,width=160,optimized=true/12345.mp4');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isCivitaiUrl', () => {
|
||||
it('should return true for CivitAI URLs', () => {
|
||||
expect(isCivitaiUrl('https://image.civitai.com/something')).toBe(true);
|
||||
|
||||
Reference in New Issue
Block a user