diff --git a/src/components/reader/Reader.svelte b/src/components/reader/Reader.svelte index da4ff61..06f4a33 100644 --- a/src/components/reader/Reader.svelte +++ b/src/components/reader/Reader.svelte @@ -37,13 +37,13 @@ const pageCache = new Map(); const inflight = new Map>(); - const isAuth = () => (appStore.settings.serverAuthMode ?? "NONE") === "BASIC_AUTH"; + const useBlob = $derived((appStore.settings.serverAuthMode ?? "NONE") === "BASIC_AUTH"); function resolveUrl(url: string, priority = 0): Promise { - return isAuth() ? getBlobUrl(url, priority) : Promise.resolve(url); + return useBlob ? getBlobUrl(url, priority) : Promise.resolve(url); } - function fetchPages(chapterId: number, signal?: AbortSignal): Promise { + function fetchPages(chapterId: number, signal?: AbortSignal, priorityPage = 0): Promise { const cached = pageCache.get(chapterId); if (cached) return Promise.resolve(cached); if (signal?.aborted) return Promise.reject(new DOMException("Aborted", "AbortError")); @@ -52,7 +52,10 @@ const p = gql<{ fetchChapterPages: { pages: string[] } }>(FETCH_CHAPTER_PAGES, { chapterId }) .then(d => { const urls = d.fetchChapterPages.pages.map(p => plainThumbUrl(p)); - if (isAuth()) preloadBlobUrls(urls, urls.length); + if (useBlob) { + if (urls[priorityPage]) getBlobUrl(urls[priorityPage], urls.length + 999); + preloadBlobUrls(urls.filter((_, i) => i !== priorityPage), urls.length); + } pageCache.set(chapterId, urls); return urls; }) @@ -286,12 +289,13 @@ store.pageNumber = 1; try { - const urls = await fetchPages(id, ctrl.signal); + const urls = await fetchPages(id, ctrl.signal, resumeTo > 1 ? resumeTo - 1 : 0); if (ctrl.signal.aborted) return; store.pageUrls = urls; if (resumeTo > 1) store.pageNumber = Math.min(resumeTo, urls.length || resumeTo); pageReady = true; loading = false; + if (adjacent.next) fetchPages(adjacent.next.id).catch(() => {}); } catch (e: any) { if (ctrl.signal.aborted) return; error = e instanceof Error ? e.message : String(e); @@ -480,7 +484,7 @@ const ahead = store.settings.preloadPages ?? 3; const current = store.pageUrls[store.pageNumber - 1]; if (!current) return; - if (isAuth()) { + if (useBlob) { getBlobUrl(current, 999); const upcoming = Array.from({ length: ahead }, (_, i) => store.pageUrls[store.pageNumber + i]).filter(Boolean) as string[]; const behind = store.pageUrls[store.pageNumber - 2]; diff --git a/src/components/settings/Settings.svelte b/src/components/settings/Settings.svelte index 0e975a0..4932ca8 100644 --- a/src/components/settings/Settings.svelte +++ b/src/components/settings/Settings.svelte @@ -1759,6 +1759,13 @@ {/if} + {#if store.settings.serverAuthMode === "BASIC_AUTH"} +
+
+

Images are proxied through Tauri when Basic Auth is active, which reduces loading speed.

+
+ {/if} +
@@ -2455,6 +2462,7 @@ .sec-eye-btn { position: absolute; right: 8px; top: 50%; transform: translateY(-50%); display: flex; align-items: center; justify-content: center; padding: 0; border: none; background: none; color: var(--text-faint); cursor: pointer; transition: color var(--t-base); } .sec-eye-btn:hover { color: var(--text-muted); } .sec-btn-row { display: flex; align-items: center; gap: var(--sp-2); flex-shrink: 0; } + .auth-perf-note { font-size: var(--text-xs); color: var(--text-faint); max-width: 260px; line-height: var(--leading-snug); } .sec-action-btn { font-family: var(--font-ui); font-size: var(--text-xs); letter-spacing: var(--tracking-wide); padding: 5px 14px; border-radius: var(--radius-md); border: 1px solid var(--border-dim); background: none; color: var(--text-muted); cursor: pointer; flex-shrink: 0; transition: color var(--t-base), border-color var(--t-base), background var(--t-base); } .sec-action-btn:hover:not(:disabled) { color: var(--text-secondary); border-color: var(--border-strong); } .sec-action-btn:disabled { opacity: 0.35; cursor: default; } diff --git a/src/lib/imageCache.ts b/src/lib/imageCache.ts index 5cdfb67..012aad6 100644 --- a/src/lib/imageCache.ts +++ b/src/lib/imageCache.ts @@ -4,7 +4,7 @@ import { store } from "../store/state.svelte"; const cache = new Map(); const inflight = new Map>(); -const MAX_CONCURRENT = 6; +const MAX_CONCURRENT = 14; let active = 0; interface QueueEntry {