The channel avatar (and video thumbnails) are yt3.googleusercontent.com /
i.ytimg.com URLs; hotlink/CORS policy could blank them (failed <img> hides on
the watchlist, falls to initials on the wishlist orb) — which is why the poster
'vanished' on both pages.
Extend the /api/video/img proxy allowlist to YouTube CDN hosts (ytimg.com /
ggpht.com / googleusercontent.com, https-only, still SSRF-safe) and route all
YouTube art through it: VideoYoutube.img() helper used by the watchlist channel
cards, search chip, the wishlist nebula orb/season/still art, and the channel
detail avatar/banner/thumbnails. 2 img-proxy tests green; JS balanced.
Two big pieces:
1) Wishlist YouTube tab now renders through the EXACT TV nebula (channel = show
orb, upload YEAR = season, video = episode) instead of a flat list. Made the
nebula source-aware: a youtube orb/season/label opens the in-app channel page
(not tmdb); season name shows the year; episode meta shows the upload date;
removes route through the youtube source_id endpoints (video / year / whole
channel); the info bar shows a selected video's description (no cast/no tmdb
fetch). Identical look — music wl-* + TMDB path untouched.
2) New in-app YouTube channel detail page (video-channel.js, sibling of
video-person.js) — opens via open-detail {kind:'channel'} from the watchlist
card, the wishlist orb/season, and deep links (/video-detail/youtube/channel/
<id>; router now accepts string ids + the new page). Banner hero, avatar,
subs/handle/video stats, description, Follow toggle, and a video grid where
each upload can be wished individually (duration + views + watch-on-YouTube).
Watchlist channel cards now open this page instead of bouncing to YouTube.
video-side.css .vc-*; JS brace-balanced; backend tests green.