From e1644b636b8af7a13bf0a0bb84718f943a8126ca Mon Sep 17 00:00:00 2001 From: Max Nuding Date: Sat, 19 Jul 2025 12:54:35 +0200 Subject: [PATCH] add thumbnail data caching --- src/lib/server/db.ts | 81 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/src/lib/server/db.ts b/src/lib/server/db.ts index 10ae856..454a83a 100644 --- a/src/lib/server/db.ts +++ b/src/lib/server/db.ts @@ -68,6 +68,11 @@ type Migration = { statement: string; }; const db: sqlite3.Database = new sqlite3.cached.Database('moshingmammut.db'); +const maxThumbnailCacheSize = 100; +const maxThumbnailCacheAge = 1 * 60 * 60 * 1000; //1h in ms +const thumbnailCache = new Map(); +let thumbnailCacheHits = 0; +let thumbnailCacheMisses = 0; export function close() { try { @@ -803,6 +808,7 @@ async function getPostsInternal( .flatMap((x) => x) .map((x) => x.thumbnailUrl) .filter((x) => x !== undefined) + .filter((x) => getCachedThumbnail(x) === null) .toArray(); if (turls) { const tMap = await getSongThumbnailData('?, '.repeat(turls.length).slice(0, -2), turls); @@ -811,7 +817,11 @@ async function getPostsInternal( if (songInfo.thumbnailUrl === undefined) { continue; } - const thumbs = tMap.get(songInfo.thumbnailUrl) ?? []; + let thumbs = getCachedThumbnail(songInfo.thumbnailUrl); + if (thumbs === null) { + thumbs = tMap.get(songInfo.thumbnailUrl) ?? []; + cacheThumbnail(songInfo.thumbnailUrl, thumbs); + } songInfo.resizedThumbnails = thumbs; } } @@ -969,6 +979,73 @@ export async function getSongThumbnails(song: SongInfo): Promise= maxThumbnailCacheSize) { + logger.debug('Sweeping cache. Current size', initialSize); + const deleteTimestampsOlderThan = + thumbnailCache + .values() + .map((x) => x.ts) + .toArray() + .sort((a, b) => a - b) + .slice(0, 20) + .pop() ?? 0; + const timestampExpired = now - maxThumbnailCacheAge; + const threshold = Math.max(timestampExpired, deleteTimestampsOlderThan); + thumbnailCache.forEach((v, k) => { + if (v.ts <= threshold) { + thumbnailCache.delete(k); + } + }); + if (Logger.isDebugEnabled()) { + logger.debug( + 'Swept cache. New size', + thumbnailCache.size, + 'deleted', + initialSize - thumbnailCache.size, + 'entries' + ); + logger.debug( + 'Current hitrate', + thumbnailCacheHits, + '/', + thumbnailCacheHits + thumbnailCacheMisses, + '=', + ((100.0 * thumbnailCacheHits) / (thumbnailCacheHits + thumbnailCacheMisses)).toFixed(2), + '%' + ); + } + } + thumbnailCache.set(thumbnailUrl, { + data: thumbnails, + ts: now + }); }