summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSamantaz Fox <coding@samantaz.fr>2021-03-20 22:12:06 +0000
committerSamantaz Fox <coding@samantaz.fr>2021-03-21 15:47:03 +0100
commit980f5f129910fa2d2aca77b686469484f932680b (patch)
tree8589775a5cac38756b1a76dae66076b8a414a3d0 /src
parentf99d62a2bcd5992656217f727beb25751e11d143 (diff)
downloadinvidious-980f5f129910fa2d2aca77b686469484f932680b.tar.gz
invidious-980f5f129910fa2d2aca77b686469484f932680b.tar.bz2
invidious-980f5f129910fa2d2aca77b686469484f932680b.zip
Playlist: Fix video continuation (100+ videos playlists)
Diffstat (limited to 'src')
-rw-r--r--src/invidious/playlists.cr62
1 files changed, 40 insertions, 22 deletions
diff --git a/src/invidious/playlists.cr b/src/invidious/playlists.cr
index 71f8360d..1ef71a84 100644
--- a/src/invidious/playlists.cr
+++ b/src/invidious/playlists.cr
@@ -436,38 +436,56 @@ def fetch_playlist(plid, locale)
end
def get_playlist_videos(db, playlist, offset, locale = nil, continuation = nil)
- if playlist.is_a? InvidiousPlaylist
- db.query_all("SELECT * FROM playlist_videos WHERE plid = $1 ORDER BY array_position($2, index) LIMIT 100 OFFSET $3", playlist.id, playlist.index, offset, as: PlaylistVideo)
- else
- fetch_playlist_videos(playlist.id, playlist.video_count, offset, locale, continuation)
- end
-end
-
-def fetch_playlist_videos(plid, video_count, offset = 0, locale = nil, continuation = nil)
- if continuation
- response = YT_POOL.client &.get("/watch?v=#{continuation}&list=#{plid}&gl=US&hl=en")
- initial_data = extract_initial_data(response.body)
- offset = initial_data["currentVideoEndpoint"]?.try &.["watchEndpoint"]?.try &.["index"]?.try &.as_i64 || offset
+ # Show empy playlist if requested page is out of range
+ if offset >= playlist.video_count
+ return [] of PlaylistVideo
end
- response = YT_POOL.client &.get("/playlist?list=#{plid}&gl=US&hl=en")
- initial_data = extract_initial_data(response.body)
+ if playlist.is_a? InvidiousPlaylist
+ db.query_all("SELECT * FROM playlist_videos WHERE plid = $1 ORDER BY array_position($2, index) LIMIT 100 OFFSET $3",
+ playlist.id, playlist.index, offset, as: PlaylistVideo)
+ else
+ if offset >= 100
+ # Normalize offset to match youtube's behavior (100 videos chunck per request)
+ offset = (offset / 100).to_i64 * 100_i64
- return [] of PlaylistVideo if !initial_data
- videos = extract_playlist_videos(initial_data)
+ ctoken = produce_playlist_continuation(playlist.id, offset)
+ initial_data = JSON.parse(request_youtube_api_browse(ctoken)).as_h
+ else
+ response = YT_POOL.client &.get("/playlist?list=#{playlist.id}&gl=US&hl=en")
+ initial_data = extract_initial_data(response.body)
+ end
- until videos.empty? || videos[0].index == offset
- videos.shift
+ if initial_data
+ return extract_playlist_videos(initial_data)
+ else
+ return [] of PlaylistVideo
+ end
end
-
- return videos
end
def extract_playlist_videos(initial_data : Hash(String, JSON::Any))
videos = [] of PlaylistVideo
- (initial_data["contents"]?.try &.["twoColumnBrowseResultsRenderer"]["tabs"].as_a.select(&.["tabRenderer"]["selected"]?.try &.as_bool)[0]["tabRenderer"]["content"]["sectionListRenderer"]["contents"][0]["itemSectionRenderer"]["contents"][0]["playlistVideoListRenderer"]["contents"].as_a ||
- initial_data["response"]?.try &.["continuationContents"]["playlistVideoListContinuation"]["contents"].as_a).try &.each do |item|
+ if initial_data["contents"]?
+ tabs = initial_data["contents"]["twoColumnBrowseResultsRenderer"]["tabs"]
+ tabs_renderer = tabs.as_a.select(&.["tabRenderer"]["selected"]?.try &.as_bool)[0]["tabRenderer"]
+
+ if tabs_renderer["contents"]?
+ # Initial playlist data
+ list_renderer = tabs_renderer.["contents"]["sectionListRenderer"]["contents"][0]
+ item_renderer = list_renderer.["itemSectionRenderer"]["contents"][0]
+ contents = item_renderer.["playlistVideoListRenderer"]["contents"].as_a
+ else
+ # Continuation data
+ contents = initial_data["onResponseReceivedActions"][0]?
+ .try &.["appendContinuationItemsAction"]["continuationItems"].as_a
+ end
+ else
+ contents = initial_data["response"]?.try &.["continuationContents"]["playlistVideoListContinuation"]["contents"].as_a
+ end
+
+ contents.try &.each do |item|
if i = item["playlistVideoRenderer"]?
video_id = i["navigationEndpoint"]["watchEndpoint"]["videoId"].as_s
plid = i["navigationEndpoint"]["watchEndpoint"]["playlistId"].as_s