From c1d0fe75d267f33724c38af95efc7b1c050dc160 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 17 Jun 2021 08:54:00 +0200 Subject: Temporary abort on fail to read file.. if its being modified while reading --- TODO | 3 +- src/QuickMedia.cpp | 15 +++++++- src/plugins/Youtube.cpp | 79 ++++++++++++++++++++------------------- src/plugins/youtube/Signature.cpp | 33 ++++++++++++++-- 4 files changed, 85 insertions(+), 45 deletions(-) diff --git a/TODO b/TODO index 7f3440a..6af2d71 100644 --- a/TODO +++ b/TODO @@ -168,4 +168,5 @@ Load the next page in chapter list when reaching the bottom (when going to previ Loading image background should be rounded. //Workaround mpv issue where video is frozen after seeking (with and without cache enabled, but more often with cache enabled). This happens because of audio. Reloading audio fixes this but audio will then be gone. Fix youtube comments not working because of youtube update. Missing xsrf_token. -Fix youtube copyrighted videos not working. Youtube triggers recaptcha for request to watch?v, but signature code is also broken? \ No newline at end of file +Fix youtube copyrighted videos not working. Youtube triggers recaptcha for request to watch?v, but signature code is also broken? +Better deal with reading from file errors. This could happen when reading a file while its being modified. See read_file_as_json. \ No newline at end of file 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 get_cookies() { std::lock_guard 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 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 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 #include #include @@ -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 &new_func_calls, std::map &new_func_decls) { std::vector 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; } -- cgit v1.2.3