Playlists: page the FULL list when YouTube cookies are set (like ytdl-sub)

Correcting my earlier 'YouTube caps at ~200' claim — that's the ANONYMOUS ceiling.
YouTube throttles unauthenticated playlist extraction to ~100 (yt-dlp) / ~200
(InnerTube); ytdl-sub gets everything because it runs with browser cookies. Our
code already wires cookiesfrombrowser via youtube.cookies_browser (same as the
music client) — it's just unset. The detail endpoint now resolves with a high
limit so a cookie-authenticated yt-dlp pages the WHOLE playlist, and uses whichever
source (yt-dlp vs InnerTube) returned more, with the true header count. The partial
note now tells you to add cookies in Settings to load the full list.
This commit is contained in:
BoulderBadgeDad 2026-06-17 22:07:50 -07:00
parent 8e56273c9d
commit 67197ce956
2 changed files with 12 additions and 8 deletions

View file

@ -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 []

View file

@ -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',