From 0df8b3812334fc73a38f4e01b3402a218ff30ff7 Mon Sep 17 00:00:00 2001 From: Fijxu Date: Sun, 30 Nov 2025 17:29:39 -0300 Subject: [PATCH] Remove DECRYPT_FUNCTION and shrink player function --- src/invidious.cr | 4 -- src/invidious/videos.cr | 4 ++ src/invidious/videos/parser.cr | 48 +++------------------ src/invidious/yt_backend/youtube_api.cr | 55 ++++--------------------- 4 files changed, 18 insertions(+), 93 deletions(-) diff --git a/src/invidious.cr b/src/invidious.cr index fabb1e81..7fa0725e 100644 --- a/src/invidious.cr +++ b/src/invidious.cr @@ -170,10 +170,6 @@ Invidious::Database.check_integrity(CONFIG) {% puts "\nDone checking player dependencies, now compiling Invidious...\n" %} {% end %} -# Misc - -DECRYPT_FUNCTION = nil - # Start jobs if CONFIG.channel_threads > 0 diff --git a/src/invidious/videos.cr b/src/invidious/videos.cr index 348a0a66..46b36940 100644 --- a/src/invidious/videos.cr +++ b/src/invidious/videos.cr @@ -326,6 +326,10 @@ end def fetch_video(id, region) 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 == "Video unavailable" raise NotFoundException.new(reason.as_s || "") diff --git a/src/invidious/videos/parser.cr b/src/invidious/videos/parser.cr index 4f45e33c..7f57bac8 100644 --- a/src/invidious/videos/parser.cr +++ b/src/invidious/videos/parser.cr @@ -53,11 +53,12 @@ def parse_related_video(related : JSON::Any) : Hash(String, JSON::Any)? end def extract_video_info(video_id : String) - # Init client config for the API - client_config = YoutubeAPI::ClientConfig.new - # 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 @@ -105,37 +106,6 @@ def extract_video_info(video_id : String) params = parse_video_info(video_id, player_response) 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| params[f] = player_response[f] if player_response[f]? end @@ -163,7 +133,7 @@ end 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.") - response = YoutubeAPI.player(video_id: id, params: "2AMB", client_config: client_config) + response = YoutubeAPI.player(video_id: id) playability_status = response["playabilityStatus"]["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 LOGGER.debug("convert_url: Decoding '#{cfr}'") - - unsig = DECRYPT_FUNCTION.try &.decrypt_signature(cfr["s"]) - params[sp] = unsig if unsig else url = URI.parse(fmt["url"].as_s) params = url.query_params end - n = DECRYPT_FUNCTION.try &.decrypt_nsig(params["n"]) - params["n"] = n if n - url.query_params = params LOGGER.trace("convert_url: new url is '#{url}'") diff --git a/src/invidious/yt_backend/youtube_api.cr b/src/invidious/yt_backend/youtube_api.cr index e5056911..dd709920 100644 --- a/src/invidious/yt_backend/youtube_api.cr +++ b/src/invidious/yt_backend/youtube_api.cr @@ -199,10 +199,6 @@ module YoutubeAPI # conf_1 = ClientConfig.new(region: "NO") # 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 # Type of client to emulate. @@ -451,58 +447,23 @@ module YoutubeAPI end #################################################################### - # player(video_id, params, client_config?) + # player(video_id) # - # Requests the youtubei/v1/player endpoint with the required headers - # and POST data in order to get a JSON reply. + # Requests the youtubei/v1/player Invidious Companion endpoint with + # the requested video ID. # - # The requested data is a video ID (`v=` parameter), with some - # additional parameters, formatted as a base64 string. + # The requested data is a video ID (`v=` parameter). # - # An optional ClientConfig parameter can be passed, too (see - # `struct ClientConfig` above for more details). - # - 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 + def player(video_id : String) + # JSON Request data, required by Invidious Companion data = { - "contentCheckOk" => true, - "videoId" => video_id, - "context" => self.make_context(client_config, video_id), - "racyCheckOk" => true, - "user" => { - "lockedSafetyMode" => false, - }, - "playbackContext" => { - "contentPlaybackContext" => playback_ctx, - }, + "videoId" => video_id, } - # Append the additional parameters if those were provided - if params != "" - data["params"] = params - end - if CONFIG.invidious_companion.present? return self._post_invidious_companion("/youtubei/v1/player", data) else - return self._post_json("/youtubei/v1/player", data, client_config) + return nil end end