Implement workaround for broken shorts objects
This commit is contained in:
parent
f9eb839c7a
commit
a37522a03d
3 changed files with 46 additions and 15 deletions
|
@ -127,16 +127,38 @@ module Invidious::Channel::Tabs
|
|||
# Shorts
|
||||
# -------------------
|
||||
|
||||
def get_shorts(channel : AboutChannel, continuation : String? = nil)
|
||||
private def fetch_shorts_data(ucid : String, continuation : String? = nil)
|
||||
if continuation.nil?
|
||||
# EgZzaG9ydHPyBgUKA5oBAA%3D%3D is the protobuf object to load "shorts"
|
||||
# TODO: try to extract the continuation tokens that allows other sorting options
|
||||
initial_data = YoutubeAPI.browse(channel.ucid, params: "EgZzaG9ydHPyBgUKA5oBAA%3D%3D")
|
||||
return YoutubeAPI.browse(ucid, params: "EgZzaG9ydHPyBgUKA5oBAA%3D%3D")
|
||||
else
|
||||
initial_data = YoutubeAPI.browse(continuation: continuation)
|
||||
return YoutubeAPI.browse(continuation: continuation)
|
||||
end
|
||||
end
|
||||
|
||||
def get_shorts(channel : AboutChannel, continuation : String? = nil)
|
||||
initial_data = self.fetch_shorts_data(channel.ucid, continuation)
|
||||
|
||||
begin
|
||||
# Try to parse the initial data fetched above
|
||||
return extract_items(initial_data, channel.author, channel.ucid)
|
||||
rescue ex : RetryOnceException
|
||||
# Sometimes, for a completely unknown reason, the "reelItemRenderer"
|
||||
# object is missing some critical information (it happens once in about
|
||||
# 20 subsequent requests). Refreshing the page is required to properly
|
||||
# show the "shorts" tab.
|
||||
#
|
||||
# In order to make the experience smoother for the user, we simulate
|
||||
# said page refresh by fetching again the JSON. If that still doesn't
|
||||
# work, we raise a BrokenTubeException, as something is really broken.
|
||||
begin
|
||||
initial_data = self.fetch_shorts_data(channel.ucid, continuation)
|
||||
return extract_items(initial_data, channel.author, channel.ucid)
|
||||
rescue ex : RetryOnceException
|
||||
raise BrokenTubeException.new "reelPlayerHeaderSupportedRenderers"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# -------------------
|
||||
|
|
|
@ -33,3 +33,8 @@ end
|
|||
|
||||
class VideoNotAvailableException < Exception
|
||||
end
|
||||
|
||||
# Exception used to indicate that the JSON response from YT is missing
|
||||
# some important informations, and that the query should be sent again.
|
||||
class RetryOnceException < Exception
|
||||
end
|
||||
|
|
|
@ -408,18 +408,22 @@ private module Parsers
|
|||
private def self.parse(item_contents, author_fallback)
|
||||
video_id = item_contents["videoId"].as_s
|
||||
|
||||
begin
|
||||
video_details_container = item_contents.dig(
|
||||
reel_player_overlay = item_contents.dig(
|
||||
"navigationEndpoint", "reelWatchEndpoint",
|
||||
"overlay", "reelPlayerOverlayRenderer",
|
||||
"overlay", "reelPlayerOverlayRenderer"
|
||||
)
|
||||
|
||||
# Sometimes, the "reelPlayerOverlayRenderer" object is missing the
|
||||
# important part of the response. We use this exception to tell
|
||||
# the calling function to fetch the content again.
|
||||
if !reel_player_overlay.as_h.has_key?("reelPlayerHeaderSupportedRenderers")
|
||||
raise RetryOnceException.new
|
||||
end
|
||||
|
||||
video_details_container = reel_player_overlay.dig(
|
||||
"reelPlayerHeaderSupportedRenderers",
|
||||
"reelPlayerHeaderRenderer"
|
||||
)
|
||||
rescue ex : KeyError
|
||||
# Extract key name from original message
|
||||
key = /"([^"]+)"/.match(ex.message || "").try &.[1]?
|
||||
raise BrokenTubeException.new(key || "reelPlayerOverlayRenderer")
|
||||
end
|
||||
|
||||
# Author infos
|
||||
|
||||
|
|
Loading…
Reference in a new issue