aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/QuickMedia.cpp15
-rw-r--r--src/plugins/Youtube.cpp79
-rw-r--r--src/plugins/youtube/Signature.cpp33
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;
}