From 915b77b740beb2f42b378f1b9e04c8f97b10f6bb Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN <53631862+PR0M3TH3AN@users.noreply.github.com> Date: Sat, 13 Jun 2026 07:57:04 -0400 Subject: [PATCH] fix(watch-history): stop infinite feed-refresh loop pegging the CPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updateFingerprintCache (and the fingerprint getter) emitted "fingerprint" unconditionally on every load. The For You feed subscribes to that event and re-runs refreshFeed -> loadLatest -> updateFingerprintCache -> emit, so once the For You feed was active the app entered an infinite loop: a full feed rebuild plus a watch-history reload (with extension decrypts) every ~400ms. That pegged the CPU (fans maxing) and starved every other load — videos, hashtags, subs, DMs and watch history all failed to appear. Emit "fingerprint" only when the fingerprint actually changes. The first real resolution emits once (triggering a single refresh); the follow-up load produces the same fingerprint and emits nothing, so the loop settles immediately. Co-Authored-By: Claude Opus 4.8 --- js/watchHistoryService.js | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/js/watchHistoryService.js b/js/watchHistoryService.js index f093c24e..d13c1f15 100644 --- a/js/watchHistoryService.js +++ b/js/watchHistoryService.js @@ -663,6 +663,7 @@ async function updateFingerprintCache(actorKey, items) { items ); const entry = state.fingerprintCache.get(actorKey) || {}; + const previousFingerprint = entry.fingerprint; const nextEntry = { ...entry, items: Array.isArray(items) ? items : [], @@ -671,7 +672,17 @@ async function updateFingerprintCache(actorKey, items) { }; delete nextEntry.promise; state.fingerprintCache.set(actorKey, nextEntry); - emit("fingerprint", { actor: actorKey, fingerprint, items: nextEntry.items }); + // Only emit when the fingerprint actually CHANGED. Emitting unconditionally + // created an infinite loop: the For You feed listens for "fingerprint" and + // re-runs refreshFeed -> loadLatest -> updateFingerprintCache -> emit, which + // pegged the CPU with a full feed rebuild every ~400ms. + if (fingerprint !== previousFingerprint) { + emit("fingerprint", { + actor: actorKey, + fingerprint, + items: nextEntry.items, + }); + } return fingerprint; } @@ -1337,13 +1348,16 @@ async function getFingerprint(actorInput) { } const fingerprint = await nostrClient.getWatchHistoryFingerprint(actorKey); const ttl = Math.max(0, Number(WATCH_HISTORY_CACHE_TTL_MS) || 0); + const previousFingerprint = cacheEntry?.fingerprint; const nextEntry = { ...(cacheEntry || {}), fingerprint, expiresAt: now + ttl, }; state.fingerprintCache.set(actorKey, nextEntry); - emit("fingerprint", { actor: actorKey, fingerprint }); + if (fingerprint !== previousFingerprint) { + emit("fingerprint", { actor: actorKey, fingerprint }); + } return fingerprint; }