From 6cfaca382cd198c5827995a7fef89b9d860afb0f Mon Sep 17 00:00:00 2001 From: Mattias Thall Date: Tue, 26 May 2026 22:42:30 +0200 Subject: [PATCH] =?UTF-8?q?Fix=20playlist=20thumbnails=20=E2=80=94=20extra?= =?UTF-8?q?ct=20from=20yt-dlp=20thumbnails=20array?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _stable_thumbnail expects a video ID but was being passed a playlist ID (PLxxx), producing a broken URL. Now picks the best thumbnail from yt-dlp's thumbnails array, falling back to the singular thumbnail field. Also backfills playlist.thumbnail_url from the first video when indexing a playlist that still has no thumbnail. Co-Authored-By: Claude Sonnet 4.6 --- backend/routers/playlists.py | 4 ++++ backend/services/ytdlp.py | 11 ++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/backend/routers/playlists.py b/backend/routers/playlists.py index 19ca392..dde2b2b 100644 --- a/backend/routers/playlists.py +++ b/backend/routers/playlists.py @@ -189,6 +189,10 @@ def _index_playlist_task(playlist_id: int, youtube_playlist_id: str, channel_id: playlist.video_count = len(video_yt_ids) playlist.indexed_at = datetime.utcnow() playlist.video_ids = json.dumps(video_yt_ids) + # Backfill thumbnail from first video if playlist has none + if not playlist.thumbnail_url and video_yt_ids: + from ..services.ytdlp import _stable_thumbnail + playlist.thumbnail_url = _stable_thumbnail(video_yt_ids[0]) db.commit() except Exception: db.rollback() diff --git a/backend/services/ytdlp.py b/backend/services/ytdlp.py index b148ef2..197fde0 100644 --- a/backend/services/ytdlp.py +++ b/backend/services/ytdlp.py @@ -378,11 +378,20 @@ def fetch_channel_playlists(channel_id: str, max_results: int = 100) -> list[dic title = info.get("title") or info.get("playlist_title") or "" if not pl_id or not title or pl_id == channel_id: continue + # Thumbnail: yt-dlp gives a thumbnails array for playlist entries; + # fall back to singular thumbnail field. Never use _stable_thumbnail + # here because the id is a playlist ID, not a video ID. + thumbs = info.get("thumbnails") or [] + thumb_url = info.get("thumbnail") + if thumbs: + best = max(thumbs, key=lambda t: (t.get("width") or 0) * (t.get("height") or 0), default=None) + if best: + thumb_url = best.get("url") or thumb_url playlists.append({ "youtube_playlist_id": pl_id, "title": title, "description": info.get("description"), - "thumbnail_url": _stable_thumbnail(info.get("id")) if info.get("_type") == "url" else None, + "thumbnail_url": thumb_url, "video_count": info.get("playlist_count") or info.get("n_entries") or 0, }) except json.JSONDecodeError: