From d0d2d63cc730539059c53685f7b6faa7e6f6899a Mon Sep 17 00:00:00 2001 From: KrX3D Date: Sun, 8 Mar 2026 21:45:17 +0100 Subject: [PATCH] fix(hqify): use hqdefault with async sddefault upgrade hqdefault is guaranteed for every video; sddefault is not generated for older uploads and returns 404, causing a grey placeholder. Set hqdefault immediately, then HEAD-check sddefault and upgrade the thumbnail reference in-place if the CDN confirms it exists. --- mods/features/adblock.js | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/mods/features/adblock.js b/mods/features/adblock.js index 4d330c5f..64c5f6cf 100644 --- a/mods/features/adblock.js +++ b/mods/features/adblock.js @@ -323,22 +323,27 @@ function deArrowify(items) { } } - function hqify(items) { for (const item of items) { if (!item.tileRenderer) continue; if (item.tileRenderer.style !== 'TILE_STYLE_YTLR_DEFAULT') continue; - if (configRead('enableHqThumbnails')) { - const videoID = item.tileRenderer.onSelectCommand.watchEndpoint.videoId; - const queryArgs = item.tileRenderer.header.tileHeaderRenderer.thumbnail.thumbnails[0].url.split('?')[1]; - item.tileRenderer.header.tileHeaderRenderer.thumbnail.thumbnails = [ - { - url: `https://i.ytimg.com/vi/${videoID}/sddefault.jpg${queryArgs ? `?${queryArgs}` : ''}`, - width: 640, - height: 480 - } - ]; - } + if (!configRead('enableHqThumbnails')) continue; + const videoID = item.tileRenderer.onSelectCommand?.watchEndpoint?.videoId; + if (!videoID) continue; + // Guard: some home page tiles have no thumbnail yet (lazy-loaded) — skip rather than crash. + const existingUrl = item.tileRenderer.header?.tileHeaderRenderer?.thumbnail?.thumbnails?.[0]?.url; + if (!existingUrl) continue; + // Do NOT carry over query args: the original `sqp` param is a signed token tied to the + // original filename — reusing it on a different filename causes a CDN signature mismatch + // and YouTube returns the grey "not available" placeholder instead of the real thumbnail. + // Start with hqdefault (guaranteed for every video), then async-upgrade to + // sddefault (640x480) if it exists on the CDN. On a TV the JSON parse → + // layout pipeline is slow enough that the HEAD usually resolves in time. + const thumbs = item.tileRenderer.header.tileHeaderRenderer.thumbnail.thumbnails; + thumbs[0] = { url: `https://i.ytimg.com/vi/${videoID}/hqdefault.jpg`, width: 480, height: 360 }; + fetch(`https://i.ytimg.com/vi/${videoID}/sddefault.jpg`, { method: 'HEAD' }) + .then(res => { if (res.ok) thumbs[0] = { url: `https://i.ytimg.com/vi/${videoID}/sddefault.jpg`, width: 640, height: 480 }; }) + .catch(() => {}); } }