diff --git a/api/video/youtube.py b/api/video/youtube.py index 7bbbda2a..fe0b8e71 100644 --- a/api/video/youtube.py +++ b/api/video/youtube.py @@ -378,17 +378,20 @@ def register_routes(bp): limit = 200 try: db = get_video_db() - pl = yt.resolve_playlist("https://www.youtube.com/playlist?list=" + playlist_id, limit=60) + # Pull the WHOLE playlist. With cookies configured (youtube.cookies_browser, + # like ytdl-sub) yt-dlp pages the full list; anonymous, YouTube throttles + # us to ~100, so the InnerTube catalog (~200 + the true header count) is the + # better source. Use whichever got more, with the true total. + pl = yt.resolve_playlist("https://www.youtube.com/playlist?list=" + playlist_id, limit=5000) if not pl: return jsonify({"success": False, "error": "Playlist not found"}), 404 - # yt-dlp flat caps playlists at ~100 and its count is often unset. Overlay - # the InnerTube catalog (curator order, up to ~200) + the TRUE header count. try: cat = yt.innertube_playlist_catalog(playlist_id) - if cat.get("videos"): + if len(cat.get("videos") or []) > len(pl.get("videos") or []): pl["videos"] = cat["videos"] - if cat.get("total"): - pl["video_count"] = cat["total"] + total = max(pl.get("video_count") or 0, cat.get("total") or 0) + if total: + pl["video_count"] = total except Exception: pass vids = pl.get("videos") or [] diff --git a/webui/static/video/video-detail.js b/webui/static/video/video-detail.js index 97a676b1..6fb344b6 100644 --- a/webui/static/video/video-detail.js +++ b/webui/static/video/video-detail.js @@ -1571,9 +1571,10 @@ ytVideoMap = {}; vids.forEach(function (v) { ytVideoMap[v.youtube_id] = v; }); var total = pl.video_count || vids.length; - // YouTube only exposes ~200 of a playlist via browsing — be honest when partial. + // Anonymous, YouTube throttles us to ~100-200; with YouTube cookies set in + // Settings, yt-dlp pages the whole playlist (like ytdl-sub). Be honest when partial. var note = total > vids.length - ? 'Showing the first ' + vids.length + ' of ' + total + ' videos (YouTube limits playlist browsing).' : ''; + ? 'Showing ' + vids.length + ' of ' + total + ' videos — add YouTube cookies in Settings to load the full playlist.' : ''; var season = { season_number: 1, title: 'Videos', poster_url: ytProx(pl.thumbnail_url), episode_owned: 0, episode_total: vids.length, episodes: vids.map(ytEpisodeOf) }; return { kind: 'playlist', source: 'youtube', id: pl.playlist_id, title: pl.title || 'Playlist',