diff --git a/src/invidious/yt_backend/connection_pool.cr b/src/invidious/yt_backend/connection_pool.cr index c7c4c675..0c836491 100644 --- a/src/invidious/yt_backend/connection_pool.cr +++ b/src/invidious/yt_backend/connection_pool.cr @@ -52,7 +52,7 @@ def add_yt_headers(request) request.headers["User-Agent"] ||= "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" request.headers["Accept-Charset"] ||= "ISO-8859-1,utf-8;q=0.7,*;q=0.7" - request.headers["Accept"] ||= "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8" + request.headers["Accept"] ||= "*" request.headers["Accept-Language"] ||= "en-us,en;q=0.5" # Preserve original cookies and add new YT consent cookie for EU servers diff --git a/src/invidious/yt_backend/youtube_api.cr b/src/invidious/yt_backend/youtube_api.cr index b2760532..d5babd86 100644 --- a/src/invidious/yt_backend/youtube_api.cr +++ b/src/invidious/yt_backend/youtube_api.cr @@ -23,6 +23,10 @@ module YoutubeAPI private IOS_USER_AGENT = "com.google.ios.youtube/#{IOS_APP_VERSION} (iPhone14,5; U; CPU iOS 17_6 like Mac OS X;)" private IOS_VERSION = "17.6.1.21G93" # Major.Minor.Patch.Build + # From reddit: https://web.archive.org/web/20210506123457/https://www.reddit.com/r/youtube/comments/n660l1/how_to_access_tv_mode_in_2020/ + private YOUTUBE_TV_USER_AGENT = "Mozilla/5.0 (Web0S; Linux/SmartTV) AppleWebKit/538.2 (KHTML, like Gecko) Large Screen Safari/538.2 LG Browser/7.00.00(LGE; 24LF4820-BU; 03.20.14; 1; DTV_W15L); webOS.TV-2015; LG NetCast.TV-2013 Compatible (LGE, 24LF4820-BU, wireless),gzip(gfe)" + + private WEB_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36,gzip(gfe)" private WINDOWS_VERSION = "10.0" # Enumerate used to select one of the clients supported by the API @@ -48,39 +52,51 @@ module YoutubeAPI # List of hard-coded values used by the different clients HARDCODED_CLIENTS = { ClientType::Web => { - name: "WEB", - name_proto: "1", - version: "2.20240814.00.00", - screen: "WATCH_FULL_SCREEN", - os_name: "Windows", - os_version: WINDOWS_VERSION, - platform: "DESKTOP", + name: "WEB", + name_proto: "1", + version: "2.20240814.00.00", + screen: "WATCH_FULL_SCREEN", + os_name: "Windows", + os_version: WINDOWS_VERSION, + browser_name: "Chrome", + browser_version: "128.0.0.0", + platform: "DESKTOP", + user_agent: WEB_USER_AGENT, }, ClientType::WebEmbeddedPlayer => { - name: "WEB_EMBEDDED_PLAYER", - name_proto: "56", - version: "1.20240812.01.00", - screen: "EMBED", - os_name: "Windows", - os_version: WINDOWS_VERSION, - platform: "DESKTOP", + name: "WEB_EMBEDDED_PLAYER", + name_proto: "56", + version: "1.20240812.01.00", + screen: "EMBED", + os_name: "Windows", + os_version: WINDOWS_VERSION, + browser_name: "Chrome", + browser_version: "128.0.0.0", + platform: "DESKTOP", + user_agent: WEB_USER_AGENT, }, ClientType::WebMobile => { - name: "MWEB", - name_proto: "2", - version: "2.20240813.02.00", - os_name: "Android", - os_version: ANDROID_VERSION, - platform: "MOBILE", + name: "MWEB", + name_proto: "2", + version: "2.20240813.02.00", + os_name: "Android", + os_version: ANDROID_VERSION, + browser_name: "Chrome", + browser_version: "128.0.0.0", + platform: "MOBILE", + user_agent: WEB_USER_AGENT, }, ClientType::WebScreenEmbed => { - name: "WEB", - name_proto: "1", - version: "2.20240814.00.00", - screen: "EMBED", - os_name: "Windows", - os_version: WINDOWS_VERSION, - platform: "DESKTOP", + name: "WEB", + name_proto: "1", + version: "2.20240814.00.00", + screen: "EMBED", + os_name: "Windows", + os_version: WINDOWS_VERSION, + browser_name: "Chrome", + browser_version: "128.0.0.0", + platform: "DESKTOP", + user_agent: WEB_USER_AGENT, }, # Android @@ -99,6 +115,7 @@ module YoutubeAPI name: "ANDROID_EMBEDDED_PLAYER", name_proto: "55", version: ANDROID_APP_VERSION, + user_agent: ANDROID_USER_AGENT, }, ClientType::AndroidScreenEmbed => { name: "ANDROID", @@ -170,6 +187,7 @@ module YoutubeAPI name_proto: "85", version: "2.0", screen: "EMBED", + user_agent: YOUTUBE_TV_USER_AGENT, }, } @@ -232,8 +250,8 @@ module YoutubeAPI HARDCODED_CLIENTS[@client_type][:android_sdk_version]? end - def user_agent : String? - HARDCODED_CLIENTS[@client_type][:user_agent]? + def user_agent : String + HARDCODED_CLIENTS[@client_type][:user_agent] end def os_name : String? @@ -252,6 +270,14 @@ module YoutubeAPI HARDCODED_CLIENTS[@client_type][:os_version]? end + def browser_name : String? + HARDCODED_CLIENTS[@client_type][:browser_name]? + end + + def browser_version : String? + HARDCODED_CLIENTS[@client_type][:browser_version]? + end + def platform : String? HARDCODED_CLIENTS[@client_type][:platform]? end @@ -280,10 +306,19 @@ module YoutubeAPI client_context = { "client" => { - "hl" => "en", - "gl" => client_config.region || "US", # Can't be empty! - "clientName" => client_config.name, - "clientVersion" => client_config.version, + "hl" => "en", + "gl" => client_config.region || "US", # Can't be empty! + "clientName" => client_config.name, + "clientVersion" => client_config.version, + "memoryTotalKbytes" => "8000000", + "originalUrl" => "https://www.youtube.com", + "screenDensityFloat" => 1, + "screenHeightPoints" => 1440, + "screenPixelDensity" => 1, + "screenWidthPoints" => 2560, + "userInterfaceTheme" => "USER_INTERFACE_THEME_LIGHT", + "userAgent" => client_config.user_agent, + "clientFormFactor" => "SMALL_FORM_FACTOR", } of String => String | Int64, } @@ -302,6 +337,14 @@ module YoutubeAPI client_context["client"]["androidSdkVersion"] = android_sdk_version end + if browser_name = client_config.browser_name + client_context["client"]["osName"] = browser_name + end + + if browser_version = client_config.browser_version + client_context["client"]["osVersion"] = browser_version + end + if device_make = client_config.device_make client_context["client"]["deviceMake"] = device_make end @@ -468,9 +511,15 @@ module YoutubeAPI end # 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 + "html5Preference" => "HTML5_PREF_WANTS", + "referer" => "https://www.youtube.com/watch?v=#{video_id}", + "lactMilliseconds" => "-1", + "splay" => false, + "vis" => 0, + "autoCaptionsDefaultOn" => false, + "autonavState" => "STATE_ON", + "currentUrl" => "/watch?v=#{video_id}", + } of String => String | Int64 | Bool if {"WEB", "TVHTML5"}.any? { |s| client_config.name.starts_with? s } if sts = DECRYPT_FUNCTION.try &.get_sts @@ -486,6 +535,11 @@ module YoutubeAPI "racyCheckOk" => true, "user" => { "lockedSafetyMode" => false, + "enableSafetyMode" => false, + }, + "request" => { + "internalExperimentFlags" => {} of String => Hash(Nil, Nil), + "useSsl" => true, }, "playbackContext" => { "contentPlaybackContext" => playback_ctx,