diff options
| author | Fuwn <[email protected]> | 2026-03-29 06:32:12 +0000 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-03-29 06:32:12 +0000 |
| commit | 4140869d8e5a26db6f9d63c400051bd440c575bd (patch) | |
| tree | 9ef09729aa5907f0265388e12e9bb8c15cde6b57 /src/lib/Media | |
| parent | fix(proxy): improve native chapter source routing (diff) | |
| download | due.moe-4140869d8e5a26db6f9d63c400051bd440c575bd.tar.xz due.moe-4140869d8e5a26db6f9d63c400051bd440c575bd.zip | |
perf(manga): progressively hydrate native chapter counts
Diffstat (limited to 'src/lib/Media')
| -rw-r--r-- | src/lib/Media/Manga/chapters.ts | 87 |
1 files changed, 76 insertions, 11 deletions
diff --git a/src/lib/Media/Manga/chapters.ts b/src/lib/Media/Manga/chapters.ts index ff861609..0f51af4a 100644 --- a/src/lib/Media/Manga/chapters.ts +++ b/src/lib/Media/Manga/chapters.ts @@ -27,6 +27,7 @@ interface NativeChapterCountsResponse { const chapterMemoryCache = new Map<number, number | null>(); const MAX_PENDING_RETRIES = 2; const DEFAULT_PENDING_RETRY_MS = 750; +const NATIVE_PROGRESSIVE_CHUNK_SIZE = 10; const browserChapterCacheDisabled = () => env.PUBLIC_DISABLE_MANGA_BROWSER_CACHE === "true"; @@ -77,6 +78,17 @@ const writeCachedChapterCount = async ( }); }; +const writeNativeChapterCount = async ( + mangaId: number, + chapters: number | null, +) => { + const existing = browserChapterCacheDisabled() + ? undefined + : await database.chapters.get(mangaId); + + await writeCachedChapterCount(mangaId, chapters, existing?.volumes ?? null); +}; + const getActivityChapterCount = async ( identity: UserIdentity, manga: Media, @@ -233,10 +245,54 @@ const fetchNativeChapterCounts = async (manga: Media[]) => { return { data, failedIds }; }; +export const hydrateNativeChapterCountsProgressively = async ( + manga: Media[], + onChunkResolved?: () => void, +) => { + const uniqueManga = manga + .filter((entry) => entry.format !== "NOVEL") + .filter( + (entry, index, array) => + array.findIndex((candidate) => candidate.id === entry.id) === index, + ); + + for ( + let index = 0; + index < uniqueManga.length; + index += NATIVE_PROGRESSIVE_CHUNK_SIZE + ) { + const chunk = uniqueManga.slice( + index, + index + NATIVE_PROGRESSIVE_CHUNK_SIZE, + ); + const { data: nativeCounts, failedIds } = + await fetchNativeChapterCounts(chunk); + let changed = false; + + for (const entry of chunk) { + if (failedIds.has(entry.id)) continue; + + const nativeCount = nativeCounts[String(entry.id)]?.chapter; + + if (nativeCount === null || nativeCount === undefined) continue; + + await writeNativeChapterCount(entry.id, nativeCount); + changed = true; + } + + if (changed) onChunkResolved?.(); + } +}; + export const hydrateChapterCounts = async ( identity: UserIdentity, manga: Media[], disableGuessing: boolean, + options: { + deferNative?: boolean; + startDeferredNative?: boolean; + onNativeChunkResolved?: () => void; + } = {}, ): Promise<{ rateLimited: boolean }> => { const uniqueManga = manga.filter( (entry, index, array) => @@ -270,23 +326,32 @@ export const hydrateChapterCounts = async ( } if (nativeCountManga.length) { - const { data: nativeCounts, failedIds } = - await fetchNativeChapterCounts(nativeCountManga); + if (options.deferNative) { + unresolvedManga.push(...nativeCountManga); + if (options.startDeferredNative) + void hydrateNativeChapterCountsProgressively( + nativeCountManga, + options.onNativeChunkResolved, + ); + } else { + const { data: nativeCounts, failedIds } = + await fetchNativeChapterCounts(nativeCountManga); - for (const entry of nativeCountManga) { - if (failedIds.has(entry.id)) continue; + for (const entry of nativeCountManga) { + if (failedIds.has(entry.id)) continue; - const nativeCount = nativeCounts[String(entry.id)]?.chapter; + const nativeCount = nativeCounts[String(entry.id)]?.chapter; - if (nativeCount === null) { - unresolvedManga.push(entry); + if (nativeCount === null) { + unresolvedManga.push(entry); - continue; - } + continue; + } - if (nativeCount === undefined) continue; + if (nativeCount === undefined) continue; - await writeCachedChapterCount(entry.id, nativeCount); + await writeNativeChapterCount(entry.id, nativeCount); + } } } |