Remove DECRYPT_FUNCTION and shrink player function

This commit is contained in:
Fijxu 2025-11-30 17:29:39 -03:00
parent e649b8105a
commit 0df8b38123
4 changed files with 18 additions and 93 deletions

View File

@ -170,10 +170,6 @@ Invidious::Database.check_integrity(CONFIG)
{% puts "\nDone checking player dependencies, now compiling Invidious...\n" %} {% puts "\nDone checking player dependencies, now compiling Invidious...\n" %}
{% end %} {% end %}
# Misc
DECRYPT_FUNCTION = nil
# Start jobs # Start jobs
if CONFIG.channel_threads > 0 if CONFIG.channel_threads > 0

View File

@ -326,6 +326,10 @@ end
def fetch_video(id, region) def fetch_video(id, region)
info = extract_video_info(video_id: id) info = extract_video_info(video_id: id)
if info.nil?
raise InfoException.new("Invidious companion is not available. Video playback cannot continue.")
end
if reason = info["reason"]? if reason = info["reason"]?
if reason == "Video unavailable" if reason == "Video unavailable"
raise NotFoundException.new(reason.as_s || "") raise NotFoundException.new(reason.as_s || "")

View File

@ -53,11 +53,12 @@ def parse_related_video(related : JSON::Any) : Hash(String, JSON::Any)?
end end
def extract_video_info(video_id : String) def extract_video_info(video_id : String)
# Init client config for the API
client_config = YoutubeAPI::ClientConfig.new
# Fetch data from the player endpoint # Fetch data from the player endpoint
player_response = YoutubeAPI.player(video_id: video_id, params: "2AMB", client_config: client_config) player_response = YoutubeAPI.player(video_id: video_id)
if player_response.nil?
return nil
end
playability_status = player_response.dig?("playabilityStatus", "status").try &.as_s playability_status = player_response.dig?("playabilityStatus", "status").try &.as_s
@ -105,37 +106,6 @@ def extract_video_info(video_id : String)
params = parse_video_info(video_id, player_response) params = parse_video_info(video_id, player_response)
params["reason"] = JSON::Any.new(reason) if reason params["reason"] = JSON::Any.new(reason) if reason
if !CONFIG.invidious_companion.present?
if player_response.dig?("streamingData", "adaptiveFormats", 0, "url").nil?
LOGGER.warn("Missing URLs for adaptive formats, falling back to other YT clients.")
players_fallback = {YoutubeAPI::ClientType::TvSimply, YoutubeAPI::ClientType::WebMobile}
players_fallback.each do |player_fallback|
client_config.client_type = player_fallback
next if !(player_fallback_response = try_fetch_streaming_data(video_id, client_config))
adaptive_formats = player_fallback_response.dig?("streamingData", "adaptiveFormats")
if adaptive_formats && (adaptive_formats.dig?(0, "url") || adaptive_formats.dig?(0, "signatureCipher"))
streaming_data = player_response["streamingData"].as_h
streaming_data["adaptiveFormats"] = adaptive_formats
player_response["streamingData"] = JSON::Any.new(streaming_data)
break
end
rescue InfoException
next LOGGER.warn("Failed to fetch streams with #{player_fallback}")
end
end
# Seems like video page can still render even without playable streams.
# its better than nothing.
#
# # Were we able to find playable video streams?
# if player_response.dig?("streamingData", "adaptiveFormats", 0, "url").nil?
# # No :(
# end
end
{"captions", "playabilityStatus", "playerConfig", "storyboards"}.each do |f| {"captions", "playabilityStatus", "playerConfig", "storyboards"}.each do |f|
params[f] = player_response[f] if player_response[f]? params[f] = player_response[f] if player_response[f]?
end end
@ -163,7 +133,7 @@ end
def try_fetch_streaming_data(id : String, client_config : YoutubeAPI::ClientConfig) : Hash(String, JSON::Any)? def try_fetch_streaming_data(id : String, client_config : YoutubeAPI::ClientConfig) : Hash(String, JSON::Any)?
LOGGER.debug("try_fetch_streaming_data: [#{id}] Using #{client_config.client_type} client.") LOGGER.debug("try_fetch_streaming_data: [#{id}] Using #{client_config.client_type} client.")
response = YoutubeAPI.player(video_id: id, params: "2AMB", client_config: client_config) response = YoutubeAPI.player(video_id: id)
playability_status = response["playabilityStatus"]["status"] playability_status = response["playabilityStatus"]["status"]
LOGGER.debug("try_fetch_streaming_data: [#{id}] Got playabilityStatus == #{playability_status}.") LOGGER.debug("try_fetch_streaming_data: [#{id}] Got playabilityStatus == #{playability_status}.")
@ -480,17 +450,11 @@ private def convert_url(fmt)
params = url.query_params params = url.query_params
LOGGER.debug("convert_url: Decoding '#{cfr}'") LOGGER.debug("convert_url: Decoding '#{cfr}'")
unsig = DECRYPT_FUNCTION.try &.decrypt_signature(cfr["s"])
params[sp] = unsig if unsig
else else
url = URI.parse(fmt["url"].as_s) url = URI.parse(fmt["url"].as_s)
params = url.query_params params = url.query_params
end end
n = DECRYPT_FUNCTION.try &.decrypt_nsig(params["n"])
params["n"] = n if n
url.query_params = params url.query_params = params
LOGGER.trace("convert_url: new url is '#{url}'") LOGGER.trace("convert_url: new url is '#{url}'")

View File

@ -199,10 +199,6 @@ module YoutubeAPI
# conf_1 = ClientConfig.new(region: "NO") # conf_1 = ClientConfig.new(region: "NO")
# YoutubeAPI::search("Kollektivet", params: "", client_config: conf_1) # YoutubeAPI::search("Kollektivet", params: "", client_config: conf_1)
# #
# # Use the Android client to request video streams URLs
# conf_2 = ClientConfig.new(client_type: ClientType::Android)
# YoutubeAPI::player(video_id: "dQw4w9WgXcQ", client_config: conf_2)
#
# #
struct ClientConfig struct ClientConfig
# Type of client to emulate. # Type of client to emulate.
@ -451,58 +447,23 @@ module YoutubeAPI
end end
#################################################################### ####################################################################
# player(video_id, params, client_config?) # player(video_id)
# #
# Requests the youtubei/v1/player endpoint with the required headers # Requests the youtubei/v1/player Invidious Companion endpoint with
# and POST data in order to get a JSON reply. # the requested video ID.
# #
# The requested data is a video ID (`v=` parameter), with some # The requested data is a video ID (`v=` parameter).
# additional parameters, formatted as a base64 string.
# #
# An optional ClientConfig parameter can be passed, too (see def player(video_id : String)
# `struct ClientConfig` above for more details). # JSON Request data, required by Invidious Companion
#
def player(
video_id : String,
*, # Force the following parameters to be passed by name
params : String,
client_config : ClientConfig | Nil = nil,
)
# Playback context, separate because it can be different between clients
playback_ctx = {
"html5Preference" => "HTML5_PREF_WANTS",
"referer" => "https://www.youtube.com/watch?v=#{video_id}",
} of String => String | Int64
if {"WEB", "TVHTML5"}.any? { |s| client_config.name.starts_with? s }
if sts = DECRYPT_FUNCTION.try &.get_sts
playback_ctx["signatureTimestamp"] = sts.to_i64
end
end
# JSON Request data, required by the API
data = { data = {
"contentCheckOk" => true, "videoId" => video_id,
"videoId" => video_id,
"context" => self.make_context(client_config, video_id),
"racyCheckOk" => true,
"user" => {
"lockedSafetyMode" => false,
},
"playbackContext" => {
"contentPlaybackContext" => playback_ctx,
},
} }
# Append the additional parameters if those were provided
if params != ""
data["params"] = params
end
if CONFIG.invidious_companion.present? if CONFIG.invidious_companion.present?
return self._post_invidious_companion("/youtubei/v1/player", data) return self._post_invidious_companion("/youtubei/v1/player", data)
else else
return self._post_json("/youtubei/v1/player", data, client_config) return nil
end end
end end