From c00df179ba190977e53c45d6a7a973538d40c9d2 Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Wed, 17 Jun 2026 13:22:23 -0700 Subject: [PATCH] Channel page: fix re-poll never refreshing when recent videos collapse to one year MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The date re-poll only re-rendered if the season COUNT increased — but for a daily channel the 90 recent videos all land in the current year, so it went from [2026(3), Earlier(87)] (2 seasons) to [2026(90)] (1 season): count dropped, so the years (which WERE cached, per the logs) never showed and the spinner hung. Now it re-renders whenever the 'Earlier videos' bucket shrinks too. Also extended the poll window (20/45/80/120/160s) for channels queued behind others. --- webui/static/video/video-detail.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/webui/static/video/video-detail.js b/webui/static/video/video-detail.js index 9ad1651f..e56ba93a 100644 --- a/webui/static/video/video-detail.js +++ b/webui/static/video/video-detail.js @@ -1352,30 +1352,39 @@ // pop in WITHOUT a manual reload (only re-renders if more years appeared). var ytRepollTimers = []; function ytClearRepoll() { ytRepollTimers.forEach(function (t) { clearTimeout(t); }); ytRepollTimers = []; } + function _undatedCount(seasons) { + var n = 0; + (seasons || []).forEach(function (s) { if (s.season_number === 0) n = s.episodes.length; }); + return n; + } function ytRefetch(id) { var before = ((data && data.seasons) || []).length; + var undatedBefore = _undatedCount(data && data.seasons); fetch('/api/video/youtube/channel/' + encodeURIComponent(id) + '?limit=90', { headers: { 'Accept': 'application/json' } }) .then(function (r) { return r.ok ? r.json() : null; }) .then(function (resp) { if (!resp || !resp.success || currentId !== id || currentSource !== 'youtube') return; var nd = ytToShow(resp); - if (nd.seasons.length <= before) return; // no new years yet → don't disrupt the view + // Re-render when dating IMPROVED — new year-seasons appeared OR the + // "Earlier videos" (undated) bucket shrank. (Season count alone misses + // the common case where many recent videos all collapse into one year.) + if (nd.seasons.length <= before && _undatedCount(nd.seasons) >= undatedBefore) return; data = nd; if (!seasonByNum(selectedSeason)) selectedSeason = nd.seasons.length ? nd.seasons[0].season_number : null; renderBillboard(nd); renderSeasonNav(); renderEpisodes(); - // years filled in → stop the "fetching dates" spinner + the polling if (!nd.seasons.some(function (s) { return s.season_number === 0; })) { showEpSyncing(false); ytClearRepoll(); } }) .catch(function () { /* ignore */ }); } function ytScheduleRepoll(id) { ytClearRepoll(); - // Tell the user dates are being fetched (the enricher takes ~30-45s). + // Tell the user dates are being fetched (the enricher takes ~30-45s, more + // if the channel is queued behind others), and poll until they land. showEpSyncing(true, 'Fetching upload dates from YouTube… your year-seasons will fill in shortly.'); - [25000, 60000, 110000].forEach(function (ms) { + [20000, 45000, 80000, 120000, 160000].forEach(function (ms) { ytRepollTimers.push(setTimeout(function () { ytRefetch(id); }, ms)); }); - ytRepollTimers.push(setTimeout(function () { if (currentId === id) showEpSyncing(false); }, 125000)); + ytRepollTimers.push(setTimeout(function () { if (currentId === id) showEpSyncing(false); }, 175000)); } function loadChannel(id) {