From f24b4f50643143be39ec4ab5ab26db1caa80c8d9 Mon Sep 17 00:00:00 2001 From: Joe Wise Date: Tue, 19 May 2026 22:06:10 -0700 Subject: [PATCH] Fix KeyError 'entries' when YouTube redirects channel ID --- backend/channel/src/remote_query.py | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/backend/channel/src/remote_query.py b/backend/channel/src/remote_query.py index 71049757..994cce18 100644 --- a/backend/channel/src/remote_query.py +++ b/backend/channel/src/remote_query.py @@ -91,6 +91,27 @@ class VideoQueryBuilder: return (vid_type, None) +def _resolve_channel_query( + channel_id: str, + url: str, + obs: dict, + config: AppConfigType, +) -> dict | None: + """extract channel query, following a redirect if yt-dlp returns one""" + channel_query, _ = YtWrap(obs, config).extract(url) + if not channel_query: + return None + + # yt-dlp may return a redirect (_type: 'url') instead of a playlist + # when YouTube redirects a channel ID to another. Follow the redirect. + if channel_query.get("_type") == "url" and channel_query.get("url"): + redirect_url = channel_query["url"] + print(f"{channel_id}: following channel redirect to {redirect_url}") + channel_query, _ = YtWrap(obs, config).extract(redirect_url) + + return channel_query or None + + def get_last_channel_videos( channel_id: str, config: AppConfigType, @@ -127,10 +148,14 @@ def get_last_channel_videos( obs["playlist_items"] = f":{limit_amount}:1" url = f"https://www.youtube.com/channel/{channel_id}/{vid_type}" - channel_query, _ = YtWrap(obs, config).extract(url) + channel_query = _resolve_channel_query(channel_id, url, obs, config) if not channel_query: continue + if "entries" not in channel_query: + print(f"{channel_id}: no entries found for {vid_type}, skipping") + continue + for entry in channel_query["entries"]: entry["vid_type"] = vid_type last_videos.append(entry)