From c2efd1e6587223cf9fff302fbc0ef80fcb4340e2 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 8 Aug 2021 14:56:46 +0200 Subject: Youtube: use innertube api for loading videos (and pretend to be android) --- src/plugins/Youtube.cpp | 112 ++++++++++++++---------------------------------- 1 file changed, 32 insertions(+), 80 deletions(-) (limited to 'src/plugins/Youtube.cpp') diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index f81d934..ea72f03 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -18,64 +18,7 @@ extern "C" { #include namespace QuickMedia { - static const char *youtube_client_version = "x-youtube-client-version: 2.20210615.01.00"; - static const std::string key_api_request_data = -R"END( -{ - "context": { - "client": { - "hl": "en", - "gl": "US", - "deviceMake": "", - "deviceModel": "", - "userAgent": "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0,gzip(gfe)", - "clientName": "WEB", - "clientVersion": "2.20210615.01.00", - "osName": "Windows", - "osVersion": "10.0", - "originalUrl": "https://www.youtube.com/watch?v=%VIDEO_ID%", - "platform": "DESKTOP", - "clientFormFactor": "UNKNOWN_FORM_FACTOR", - "timeZone": "UTC", - "browserName": "Firefox", - "browserVersion": "78.0", - "screenWidthPoints": 1054, - "screenHeightPoints": 289, - "screenPixelDensity": 1, - "screenDensityFloat": 1, - "utcOffsetMinutes": 0, - "userInterfaceTheme": "USER_INTERFACE_THEME_LIGHT", - "clientScreen": "WATCH", - "mainAppWebInfo": { - "graftUrl": "/watch?v=%VIDEO_ID%", - "webDisplayMode": "WEB_DISPLAY_MODE_BROWSER", - "isWebNativeShareAvailable": false - } - }, - "user": { - "lockedSafetyMode": false - }, - "request": { - "useSsl": true, - "internalExperimentFlags": [], - "consistencyTokenJars": [] - } - }, - "videoId": "%VIDEO_ID%", - "playbackContext": { - "contentPlaybackContext": { - "currentUrl": "/watch?v=%VIDEO_ID%", - "vis": 0, - "splay": false, - "autoCaptionsDefaultOn": false, - "autonavState": "STATE_NONE", - "html5Preference": "HTML5_PREF_WANTS" - } - }, - "racyCheckOk": false, - "contentCheckOk": false -} -)END"; + static const char *youtube_client_version = "x-youtube-client-version: 2.20210622.10.00"; bool youtube_url_extract_id(const std::string &youtube_url, std::string &youtube_video_id) { size_t index = youtube_url.find("youtube.com/watch?v="); @@ -1259,7 +1202,7 @@ R"END( client_json["deviceModel"] = ""; client_json["userAgent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"; client_json["clientName"] = "WEB"; - client_json["clientVersion"] = "2.20210701.07.00"; + client_json["clientVersion"] = "2.20210622.10.00"; client_json["osName"] = "X11"; client_json["osVersion"] = ""; client_json["originalUrl"] = video_url; @@ -1347,7 +1290,7 @@ R"END( client_json["deviceModel"] = ""; client_json["userAgent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"; client_json["clientName"] = "WEB"; - client_json["clientVersion"] = "2.20210304.08.01"; + client_json["clientVersion"] = "2.20210622.10.00"; client_json["osName"] = "X11"; client_json["osVersion"] = ""; client_json["originalUrl"] = url + "/videos"; @@ -1436,7 +1379,7 @@ R"END( client_json["deviceModel"] = ""; client_json["userAgent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36"; client_json["clientName"] = "WEB"; - client_json["clientVersion"] = "2.20210304.08.01"; + client_json["clientVersion"] = "2.20210622.10.00"; client_json["osName"] = "X11"; client_json["osVersion"] = ""; client_json["originalUrl"] = url + "/videos"; @@ -2387,34 +2330,43 @@ R"END( return PluginResult::ERR; } + std::string request_data = +R"END( +{ + "context": { + "client": { + "clientName": "ANDROID", + "clientVersion": "16.20", + "hl": "en" + } + }, + "videoId": "%VIDEO_ID%", + "playbackContext": { + "contentPlaybackContext": { + "html5Preference": "HTML5_PREF_WANTS" + } + }, + "contentCheckOk": true, + "racyCheckOk": true +} +)END"; + string_replace_all(request_data, "%VIDEO_ID%", video_id); + std::vector additional_args = { - { "-H", "x-youtube-client-name: 1" }, - { "-H", youtube_client_version }, + { "-H", "Content-Type: application/json" }, + { "-H", "X-YouTube-Client-Name: 3" }, + { "-H", "X-YouTube-Client-Version: 16.20" }, + { "--data-raw", std::move(request_data) } }; std::vector cookies = get_cookies(); additional_args.insert(additional_args.end(), cookies.begin(), cookies.end()); - // TODO: Remove this code completely and replace with existing player? api Json::Value json_root; - DownloadResult download_result = download_json(json_root, "https://www.youtube.com/watch?v=" + video_id + "&pbj=1&gl=US&hl=en", additional_args, true); + DownloadResult download_result = download_json(json_root, "https://www.youtube.com/youtubei/v1/player?key=" + api_key + "&gl=US&hl=en", additional_args, true); if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result); - if(!json_root.isArray()) - return PluginResult::ERR; - - for(const Json::Value &json_item : json_root) { - if(!json_item.isObject()) - continue; - - const Json::Value &player_response_json = json_item["playerResponse"]; - if(!player_response_json.isObject()) - continue; - - return parse_video_response(player_response_json, title, channel_url, chapters); - } - - return PluginResult::ERR; + return parse_video_response(json_root, title, channel_url, chapters); } void YoutubeVideoPage::mark_watched() { -- cgit v1.2.3