|
|
|
@ -16,6 +16,14 @@ def produce_channel_videos_continuation(ucid, page = 1, auto_generated = nil, so
|
|
|
|
|
.try { |i| Base64.urlsafe_encode(i) }
|
|
|
|
|
.try { |i| URI.encode_www_form(i) }
|
|
|
|
|
|
|
|
|
|
sort_by_numerical =
|
|
|
|
|
case sort_by
|
|
|
|
|
when "newest" then 1_i64
|
|
|
|
|
when "popular" then 2_i64
|
|
|
|
|
when "oldest" then 3_i64 # Broken as of 10/2022 :c
|
|
|
|
|
else 1_i64 # Fallback to "newest"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
object_inner_1 = {
|
|
|
|
|
"110:embedded" => {
|
|
|
|
|
"3:embedded" => {
|
|
|
|
@ -24,7 +32,7 @@ def produce_channel_videos_continuation(ucid, page = 1, auto_generated = nil, so
|
|
|
|
|
"1:string" => object_inner_2_encoded,
|
|
|
|
|
"2:string" => "00000000-0000-0000-0000-000000000000",
|
|
|
|
|
},
|
|
|
|
|
"3:varint" => 1_i64,
|
|
|
|
|
"3:varint" => sort_by_numerical,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
@ -52,34 +60,66 @@ def produce_channel_videos_continuation(ucid, page = 1, auto_generated = nil, so
|
|
|
|
|
return continuation
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def get_channel_videos_response(ucid, page = 1, auto_generated = nil, sort_by = "newest")
|
|
|
|
|
continuation = produce_channel_videos_continuation(ucid, page,
|
|
|
|
|
auto_generated: auto_generated, sort_by: sort_by, v2: true)
|
|
|
|
|
|
|
|
|
|
return YoutubeAPI.browse(continuation)
|
|
|
|
|
# Used in bypass_captcha_job.cr
|
|
|
|
|
def produce_channel_videos_url(ucid, page = 1, auto_generated = nil, sort_by = "newest", v2 = false)
|
|
|
|
|
continuation = produce_channel_videos_continuation(ucid, page, auto_generated, sort_by, v2)
|
|
|
|
|
return "/browse_ajax?continuation=#{continuation}&gl=US&hl=en"
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def get_60_videos(ucid, author, page, auto_generated, sort_by = "newest")
|
|
|
|
|
videos = [] of SearchVideo
|
|
|
|
|
module Invidious::Channel::Tabs
|
|
|
|
|
extend self
|
|
|
|
|
|
|
|
|
|
# 2.times do |i|
|
|
|
|
|
# initial_data = get_channel_videos_response(ucid, page * 2 + (i - 1), auto_generated: auto_generated, sort_by: sort_by)
|
|
|
|
|
initial_data = get_channel_videos_response(ucid, 1, auto_generated: auto_generated, sort_by: sort_by)
|
|
|
|
|
videos = extract_videos(initial_data, author, ucid)
|
|
|
|
|
# end
|
|
|
|
|
# -------------------
|
|
|
|
|
# Regular videos
|
|
|
|
|
# -------------------
|
|
|
|
|
|
|
|
|
|
return videos.size, videos
|
|
|
|
|
end
|
|
|
|
|
def make_initial_video_ctoken(ucid, sort_by) : String
|
|
|
|
|
return produce_channel_videos_continuation(ucid, sort_by: sort_by)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def get_latest_videos(ucid)
|
|
|
|
|
initial_data = get_channel_videos_response(ucid)
|
|
|
|
|
author = initial_data["metadata"]?.try &.["channelMetadataRenderer"]?.try &.["title"]?.try &.as_s
|
|
|
|
|
# Wrapper for AboutChannel, as we still need to call get_videos with
|
|
|
|
|
# an author name and ucid directly (e.g in RSS feeds).
|
|
|
|
|
# TODO: figure out how to get rid of that
|
|
|
|
|
def get_videos(channel : AboutChannel, *, continuation : String? = nil, sort_by = "newest")
|
|
|
|
|
return get_videos(
|
|
|
|
|
channel.author, channel.ucid,
|
|
|
|
|
continuation: continuation, sort_by: sort_by
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return extract_videos(initial_data, author, ucid)
|
|
|
|
|
end
|
|
|
|
|
# Wrapper for InvidiousChannel, as we still need to call get_videos with
|
|
|
|
|
# an author name and ucid directly (e.g in RSS feeds).
|
|
|
|
|
# TODO: figure out how to get rid of that
|
|
|
|
|
def get_videos(channel : InvidiousChannel, *, continuation : String? = nil, sort_by = "newest")
|
|
|
|
|
return get_videos(
|
|
|
|
|
channel.author, channel.id,
|
|
|
|
|
continuation: continuation, sort_by: sort_by
|
|
|
|
|
)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# Used in bypass_captcha_job.cr
|
|
|
|
|
def produce_channel_videos_url(ucid, page = 1, auto_generated = nil, sort_by = "newest", v2 = false)
|
|
|
|
|
continuation = produce_channel_videos_continuation(ucid, page, auto_generated, sort_by, v2)
|
|
|
|
|
return "/browse_ajax?continuation=#{continuation}&gl=US&hl=en"
|
|
|
|
|
def get_videos(author : String, ucid : String, *, continuation : String? = nil, sort_by = "newest")
|
|
|
|
|
continuation ||= make_initial_video_ctoken(ucid, sort_by)
|
|
|
|
|
initial_data = YoutubeAPI.browse(continuation: continuation)
|
|
|
|
|
|
|
|
|
|
return extract_items(initial_data, author, ucid)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
def get_60_videos(channel : AboutChannel, *, continuation : String? = nil, sort_by = "newest")
|
|
|
|
|
if continuation.nil?
|
|
|
|
|
# Fetch the first "page" of video
|
|
|
|
|
items, next_continuation = get_videos(channel, sort_by: sort_by)
|
|
|
|
|
else
|
|
|
|
|
# Fetch a "page" of videos using the given continuation token
|
|
|
|
|
items, next_continuation = get_videos(channel, continuation: continuation)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
# If there is more to load, then load a second "page"
|
|
|
|
|
# and replace the previous continuation token
|
|
|
|
|
if !next_continuation.nil?
|
|
|
|
|
items_2, next_continuation = get_videos(channel, continuation: next_continuation)
|
|
|
|
|
items.concat items_2
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
return items, next_continuation
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|