From ece4fbc792ccc7ff47e8144b09aabb9754d0093c Mon Sep 17 00:00:00 2001 From: BoulderBadgeDad Date: Wed, 17 Jun 2026 10:07:51 -0700 Subject: [PATCH] Channel detail: fix episode-row layout + graceful seasons MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - The YouTube episode rows reused .vd-ep's 5-column grid (index·thumb·info· badge·chev) but only have 4 children, so the thumb squished into the index slot and the Wish button stretched across the info column. Give .vd-ep--yt its own 4-column grid (thumb·info·wish·chev). - Flat listing omits per-video dates, so all videos bucketed into a lone 'Undated' season. Now a single dateless channel shows one 'All Videos' season (year-grouping still kicks in for any videos that DO have dates); the 'Missing only' toggle is hidden for channels (videos aren't owned/missing). --- webui/static/video/video-detail.js | 7 +++++-- webui/static/video/video-side.css | 2 ++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/webui/static/video/video-detail.js b/webui/static/video/video-detail.js index b754edb4..7e0cfc28 100644 --- a/webui/static/video/video-detail.js +++ b/webui/static/video/video-detail.js @@ -1324,7 +1324,10 @@ still_url: ytProx(v.thumbnail_url), youtube_id: v.youtube_id }; }); var wishedN = eps.filter(function (e) { return e.owned; }).length; - return { season_number: yr, title: yr ? String(yr) : 'Undated', poster_url: poster || ytProx(ch.avatar_url), + // No upload dates (flat listing omits them) → a single "All Videos" + // season instead of a lone "Undated"; mixed → label the dateless bucket. + var label = yr ? String(yr) : (years.length === 1 ? 'All Videos' : 'Unknown date'); + return { season_number: yr, title: label, poster_url: poster || ytProx(ch.avatar_url), episode_owned: wishedN, episode_total: eps.length, episodes: eps }; }); return { kind: 'channel', source: 'youtube', id: ch.youtube_id, title: ch.title || 'Channel', @@ -1353,7 +1356,7 @@ data = ytToShow(resp); menuOpen = false; missingOnly = false; selectedSeason = data.seasons.length ? data.seasons[0].season_number : null; var mt = q('[data-vd-missing-toggle]'); - if (mt) { mt.hidden = !data.seasons.length; mt.classList.remove('vd-missing-toggle--on'); } + if (mt) { mt.hidden = true; mt.classList.remove('vd-missing-toggle--on'); } // n/a for channels renderBillboard(data); renderViewToggle(); renderSeasonNav(); ensureSeasonEpisodes(); var sub = document.querySelector('.video-subpage[data-video-subpage="video-show-detail"]'); if (sub) sub.scrollTop = 0; diff --git a/webui/static/video/video-side.css b/webui/static/video/video-side.css index ddde3055..c479acd3 100644 --- a/webui/static/video/video-side.css +++ b/webui/static/video/video-side.css @@ -2945,6 +2945,8 @@ body[data-side="video"] #soulsync-toggle { display: none; } .vd-yt-link:hover { background: rgba(255,59,59,0.12); } .vd-section-h { font-size: 20px; font-weight: 800; color: #fff; margin: 0 0 16px; } .vd-yt-pl-section { margin-top: 34px; } +/* YouTube episode rows have no index/badge → 4 columns (thumb · info · wish · chev) */ +.vd-ep--yt { grid-template-columns: 150px 1fr auto auto; } /* per-video Wish button inside an episode row */ .vd-yt-wish { flex-shrink: 0; align-self: center; border: 1px solid rgba(255,255,255,0.14); cursor: pointer; background: rgba(255,255,255,0.05); color: rgba(255,255,255,0.78); font-size: 11.5px; font-weight: 800;