diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/QuickMedia.cpp | 15 | ||||
-rw-r--r-- | src/plugins/Youtube.cpp | 79 | ||||
-rw-r--r-- | src/plugins/youtube/Signature.cpp | 33 |
3 files changed, 83 insertions, 44 deletions
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 82741bb..77098a3 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -1360,8 +1360,15 @@ namespace QuickMedia { Json::Value Program::load_video_history_json() { Path video_history_filepath = get_video_history_filepath(plugin_name); Json::Value json_result; - if(!read_file_as_json(video_history_filepath, json_result) || !json_result.isArray()) + FileType file_type = get_file_type(video_history_filepath); + if(file_type == FileType::REGULAR) { + if(!read_file_as_json(video_history_filepath, json_result) || !json_result.isArray()) { + show_notification("QuickMedia", "Failed to read " + video_history_filepath.data, Urgency::CRITICAL); + abort(); + } + } else { json_result = Json::Value(Json::arrayValue); + } return json_result; } @@ -1473,6 +1480,10 @@ namespace QuickMedia { FileType file_type = get_file_type(content_storage_file); if(file_type == FileType::REGULAR) { result = read_file_as_json(content_storage_file, content_storage_json) && content_storage_json.isObject(); + if(!result) { + show_notification("QuickMedia", "Failed to read " + content_storage_file.data, Urgency::CRITICAL); + abort(); + } } else { result = true; } @@ -2916,9 +2927,9 @@ namespace QuickMedia { load_video_error_check(); } else if(update_err != VideoPlayer::Error::OK) { + ++load_try; if(load_try < num_load_tries_max) { fprintf(stderr, "Failed to play the media, retrying (try %d out of %d)\n", 1 + load_try, num_load_tries_max); - ++load_try; load_video_error_check(prev_start_time); } else { show_notification("QuickMedia", "Failed to play the video (error code " + std::to_string((int)update_err) + ")", Urgency::CRITICAL); diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index ed30aec..d9d9239 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -472,11 +472,37 @@ R"END( return "AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8"; } + static std::string cpn; + + static bool generate_random_characters(char *buffer, int buffer_size, const char *alphabet, size_t alphabet_size) { + int fd = open("/dev/urandom", O_RDONLY); + if(fd == -1) { + perror("/dev/urandom"); + return false; + } + + if(read(fd, buffer, buffer_size) < buffer_size) { + fprintf(stderr, "Failed to read %d bytes from /dev/urandom\n", buffer_size); + close(fd); + return false; + } + + for(int i = 0; i < buffer_size; ++i) { + unsigned char c = *(unsigned char*)&buffer[i]; + buffer[i] = alphabet[c % alphabet_size]; + } + close(fd); + return true; + } + static std::vector<CommandArg> get_cookies() { std::lock_guard<std::mutex> lock(cookies_mutex); if(cookies_filepath.empty()) { YoutubeSignatureDecryptor::get_instance(); + cpn.resize(16); + generate_random_characters(cpn.data(), cpn.size(), "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_", 64); + Path cookies_filepath_p; if(get_cookies_filepath(cookies_filepath_p, "youtube") != 0) { show_notification("QuickMedia", "Failed to create youtube cookies file", Urgency::CRITICAL); @@ -1331,14 +1357,20 @@ R"END( std::unordered_set<std::string> channel_ids; std::string subscriptions_str; - if(file_get_content(subscriptions_path, subscriptions_str) == 0) { - string_split(subscriptions_str, '\n', [&channel_ids](const char *str, size_t size) { - std::string line(str, size); - line = strip(line); - if(!line.empty()) - channel_ids.insert(std::move(line)); - return true; - }); + FileType file_type = get_file_type(subscriptions_path); + if(file_type == FileType::REGULAR) { + if(file_get_content(subscriptions_path, subscriptions_str) == 0) { + string_split(subscriptions_str, '\n', [&channel_ids](const char *str, size_t size) { + std::string line(str, size); + line = strip(line); + if(!line.empty()) + channel_ids.insert(std::move(line)); + return true; + }); + } else { + show_notification("QuickMedia", "Failed to read " + subscriptions_path.data, Urgency::CRITICAL); + abort(); + } } auto it = channel_ids.find(channel_id); @@ -2044,27 +2076,6 @@ R"END( return PluginResult::OK; } - static bool generate_random_characters(char *buffer, int buffer_size, const char *alphabet, size_t alphabet_size) { - int fd = open("/dev/urandom", O_RDONLY); - if(fd == -1) { - perror("/dev/urandom"); - return false; - } - - if(read(fd, buffer, buffer_size) < buffer_size) { - fprintf(stderr, "Failed to read %d bytes from /dev/urandom\n", buffer_size); - close(fd); - return false; - } - - for(int i = 0; i < buffer_size; ++i) { - unsigned char c = *(unsigned char*)&buffer[i]; - buffer[i] = alphabet[c % alphabet_size]; - } - close(fd); - return true; - } - void YoutubeVideoPage::mark_watched() { if(playback_url.empty()) { fprintf(stderr, "Failed to mark video as watched because playback_url is empty\n"); @@ -2079,10 +2090,6 @@ R"END( std::vector<CommandArg> cookies = get_cookies(); additional_args.insert(additional_args.end(), cookies.begin(), cookies.end()); - std::string cpn; - cpn.resize(16); - generate_random_characters(cpn.data(), cpn.size(), "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_", 64); - std::string response; DownloadResult download_result = download_to_string(playback_url + "&ver=2&cpn=" + cpn, response, std::move(additional_args), true); if(download_result != DownloadResult::OK) { @@ -2106,12 +2113,8 @@ R"END( if(cipher_params.empty() || url.empty()) return false; - std::string cpn; - cpn.resize(16); - generate_random_characters(cpn.data(), cpn.size(), "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_", 64); - std::string url_decoded = url_param_decode(url); - url_decoded += "&alr=yes&cver=2.20210615.01.00&altitags=395,394&cpn=" + cpn; + url_decoded += "&alr=yes&cver=2.20210615.01.00&cpn=" + cpn; const std::string &s = cipher_params["s"]; const std::string &sp = cipher_params["sp"]; diff --git a/src/plugins/youtube/Signature.cpp b/src/plugins/youtube/Signature.cpp index 8c87817..7631182 100644 --- a/src/plugins/youtube/Signature.cpp +++ b/src/plugins/youtube/Signature.cpp @@ -4,6 +4,7 @@ #include "../../../include/DownloadUtils.hpp" #include "../../../include/StringUtils.hpp" #include "../../../include/Program.hpp" +#include "../../../include/NetUtils.hpp" #include <regex> #include <mutex> #include <unistd.h> @@ -18,6 +19,26 @@ namespace QuickMedia { static std::mutex update_signature_mutex; static const int timeout_default_sec = 60 * 5; // 5 minutes + static bool is_whitespace(char c) { + switch(c) { + case ' ': + case '\r': + case '\n': + case '\t': + return true; + } + return false; + } + + static std::string remove_whitespaces(const std::string &str) { + std::string result; + for(char c : str) { + if(!is_whitespace(c)) + result += c; + } + return result; + } + bool YoutubeSignatureDecryptor::js_code_to_operations(const std::string &function_body_str, const std::string &var_body_str, std::vector<DecryptFuncCall> &new_func_calls, std::map<std::string, DecryptFunction> &new_func_decls) { std::vector<std::string> function_body; string_split(function_body_str, ';', [&function_body](const char *str, size_t size) { @@ -77,7 +98,7 @@ namespace QuickMedia { std::string func_name = func_decl_str.substr(0, func_name_split_index); func_name = strip(func_name); std::string function_body = func_decl_str.substr(func_start_index + 1); - function_body = strip(function_body); + function_body = strip(remove_whitespaces(function_body)); if(!function_body.empty() && function_body.back() == '}') function_body.pop_back(); @@ -86,8 +107,12 @@ namespace QuickMedia { decrypt_function = DecryptFunction::REVERSE; else if(function_body == "a.splice(0,b)") decrypt_function = DecryptFunction::SPLICE; - else + else if(function_body.find("a[0]=a[b%a.length]") != std::string::npos) decrypt_function = DecryptFunction::SWAP; + else { + fprintf(stderr, "Unexpected decryption function body: |%s|\n", function_body.c_str()); + return false; + } //fprintf(stderr, "declared function: %s, body: |%s|\n", func_name.c_str(), function_body.c_str()); new_func_decls[std::move(func_name)] = decrypt_function; } @@ -216,7 +241,7 @@ namespace QuickMedia { break; } case DecryptFunction::SWAP: { - if(sig.empty()) { + if(sig.empty() || func_call.arg < 0) { fprintf(stderr, "YoutubeSignatureDecryptor: sig unexpectedly empty in swap\n"); } else { char c = sig[0]; @@ -229,7 +254,7 @@ namespace QuickMedia { } sig_key = sp; - sig_value = sig; + sig_value = url_param_encode(sig); return true; } |