From 56acc142c6ef9a65147acdea6737acbfaeb7eca4 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Tue, 15 Oct 2019 19:57:24 +0200 Subject: Add tor support --- src/Body.cpp | 6 ++-- src/QuickMedia.cpp | 82 ++++++++++++++++++++++++++++++++++++++------------ src/StringUtils.cpp | 17 +++++++++++ src/VideoPlayer.cpp | 23 +++++++++----- src/plugins/Plugin.cpp | 35 +++++++++++---------- 5 files changed, 118 insertions(+), 45 deletions(-) create mode 100644 src/StringUtils.cpp (limited to 'src') diff --git a/src/Body.cpp b/src/Body.cpp index fb44929..7ed1a7f 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -1,4 +1,5 @@ #include "../include/Body.hpp" +#include "../include/QuickMedia.hpp" #include "../plugins/Plugin.hpp" #include #include @@ -9,7 +10,8 @@ const sf::Color front_color(43, 45, 47); const sf::Color back_color(33, 35, 37); namespace QuickMedia { - Body::Body(sf::Font &font) : + Body::Body(Program *program, sf::Font &font) : + program(program), title_text("", font, 14), progress_text("", font, 14), selected_item(0), @@ -96,7 +98,7 @@ namespace QuickMedia { loading_thumbnail = true; thumbnail_load_thread = std::thread([this, result, url]() { std::string texture_data; - if(download_to_string(url, texture_data) == DownloadResult::OK) { + if(program->get_current_plugin()->download_to_string(url, texture_data) == DownloadResult::OK) { if(result->loadFromMemory(texture_data.data(), texture_data.size())) result->generateMipmap(); } diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index f277f46..6ac47bf 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -6,6 +6,7 @@ #include "../include/Scale.hpp" #include "../include/Program.h" #include "../include/VideoPlayer.hpp" +#include "../include/StringUtils.hpp" #include #include @@ -52,7 +53,7 @@ namespace QuickMedia { fprintf(stderr, "Failed to load font!\n"); abort(); } - body = new Body(font); + body = new Body(this, font); struct sigaction action; action.sa_handler = sigpipe_handler; @@ -83,9 +84,32 @@ namespace QuickMedia { } static void usage() { - fprintf(stderr, "usage: QuickMedia \n"); + fprintf(stderr, "usage: QuickMedia [--tor]\n"); fprintf(stderr, "OPTIONS:\n"); - fprintf(stderr, "plugin The plugin to use. Should be either manganelo, youtube or pornhub\n"); + fprintf(stderr, "plugin The plugin to use. Should be either 4chan, manganelo, pornhub or youtube\n"); + fprintf(stderr, "--tor Use tor. Disabled by default\n"); + fprintf(stderr, "EXAMPLES:\n"); + fprintf(stderr, "QuickMedia manganelo\n"); + fprintf(stderr, "QuickMedia youtube --tor\n"); + } + + static bool is_program_executable_by_name(const char *name) { + // TODO: Implement for Windows. Windows also uses semicolon instead of colon as a separator + char *env = getenv("PATH"); + std::unordered_set paths; + string_split(env, ':', [&paths](const char *str, size_t size) { + paths.insert(std::string(str, size)); + return true; + }); + + for(const std::string &path_str : paths) { + Path path(path_str); + path.join(name); + if(get_file_type(path) == FileType::REGULAR) + return true; + } + + return false; } int Program::run(int argc, char **argv) { @@ -94,24 +118,44 @@ namespace QuickMedia { return -1; } + current_plugin = nullptr; std::string plugin_logo_path; - if(strcmp(argv[1], "manganelo") == 0) { - current_plugin = new Manganelo(); - plugin_logo_path = "../../../images/manganelo_logo.png"; - } else if(strcmp(argv[1], "youtube") == 0) { - current_plugin = new Youtube(); - plugin_logo_path = "../../../images/yt_logo_rgb_dark_small.png"; - } else if(strcmp(argv[1], "pornhub") == 0) { - current_plugin = new Pornhub(); - plugin_logo_path = "../../../images/pornhub_logo.png"; - } else if(strcmp(argv[1], "4chan") == 0) { - current_plugin = new Fourchan(); - plugin_logo_path = "../../../images/4chan_logo.png"; - } else { + bool use_tor = false; + + for(int i = 1; i < argc; ++i) { + if(!current_plugin) { + if(strcmp(argv[i], "manganelo") == 0) { + current_plugin = new Manganelo(); + plugin_logo_path = "../../../images/manganelo_logo.png"; + } else if(strcmp(argv[i], "youtube") == 0) { + current_plugin = new Youtube(); + plugin_logo_path = "../../../images/yt_logo_rgb_dark_small.png"; + } else if(strcmp(argv[i], "pornhub") == 0) { + current_plugin = new Pornhub(); + plugin_logo_path = "../../../images/pornhub_logo.png"; + } else if(strcmp(argv[i], "4chan") == 0) { + current_plugin = new Fourchan(); + plugin_logo_path = "../../../images/4chan_logo.png"; + } + } + + if(strcmp(argv[i], "--tor") == 0) { + use_tor = true; + } + } + + if(!current_plugin) { usage(); return -1; } + if(use_tor && !is_program_executable_by_name("torsocks")) { + fprintf(stderr, "torsocks needs to be installed (and accessible from PATH environment variable) when using the --tor option\n"); + return -2; + } + + current_plugin->use_tor = use_tor; + if(!plugin_logo_path.empty()) { if(!plugin_logo.loadFromFile(plugin_logo_path)) { fprintf(stderr, "Failed to load plugin logo, path: %s\n", plugin_logo_path.c_str()); @@ -532,7 +576,7 @@ namespace QuickMedia { } }; - video_player = std::make_unique([this, &video_player, &seekable, &load_video_error_check](const char *event_name) { + video_player = std::make_unique(current_plugin->use_tor, [this, &video_player, &seekable, &load_video_error_check](const char *event_name) { bool end_of_file = false; if(strcmp(event_name, "pause") == 0) { double time_remaining = 0.0; @@ -861,7 +905,7 @@ namespace QuickMedia { return true; std::string image_content; - if(download_to_string(url, image_content) != DownloadResult::OK) { + if(current_plugin->download_to_string(url, image_content) != DownloadResult::OK) { show_notification("Manganelo", "Failed to download image: " + url, Urgency::CRITICAL); return false; } @@ -981,7 +1025,7 @@ namespace QuickMedia { } sf::Clock check_downloaded_timer; - const sf::Int32 check_downloaded_timeout_ms = 1000; + const sf::Int32 check_downloaded_timeout_ms = 500; // TODO: Show to user if a certain page is missing (by checking page name (number) and checking if some are skipped) while (current_page == Page::IMAGES) { diff --git a/src/StringUtils.cpp b/src/StringUtils.cpp new file mode 100644 index 0000000..deb4949 --- /dev/null +++ b/src/StringUtils.cpp @@ -0,0 +1,17 @@ +#include "../include/StringUtils.hpp" + +namespace QuickMedia { + void string_split(const std::string &str, char delimiter, StringSplitCallback callback_func) { + size_t index = 0; + while(true) { + size_t new_index = str.find(delimiter, index); + if(new_index == std::string::npos) + break; + + if(!callback_func(str.data() + index, new_index - index)) + break; + + index = new_index + 1; + } + } +} \ No newline at end of file diff --git a/src/VideoPlayer.cpp b/src/VideoPlayer.cpp index 2336367..dfe6603 100644 --- a/src/VideoPlayer.cpp +++ b/src/VideoPlayer.cpp @@ -14,11 +14,11 @@ const int RETRY_TIME_MS = 1000; const int MAX_RETRIES_CONNECT = 5; -const int MAX_RETRIES_FIND_WINDOW = 10; const int READ_TIMEOUT_MS = 200; namespace QuickMedia { - VideoPlayer::VideoPlayer(EventCallbackFunc _event_callback, VideoPlayerWindowCreateCallback _window_create_callback) : + VideoPlayer::VideoPlayer(bool use_tor, EventCallbackFunc _event_callback, VideoPlayerWindowCreateCallback _window_create_callback) : + use_tor(use_tor), video_process_id(-1), ipc_socket(-1), connected_to_ipc(false), @@ -64,15 +64,18 @@ namespace QuickMedia { } const std::string parent_window_str = std::to_string(parent_window); - const char *args[] = { "mpv", "--keep-open=yes", /*"--keep-open-pause=no",*/ "--input-ipc-server", ipc_server_path, + std::vector args; + if(use_tor) + args.push_back("torsocks"); + args.insert(args.end(), { "mpv", "--keep-open=yes", /*"--keep-open-pause=no",*/ "--input-ipc-server", ipc_server_path, "--no-config", "--no-input-default-bindings", "--input-vo-keyboard=no", "--no-input-cursor", "--cache-secs=120", "--demuxer-max-bytes=40M", "--demuxer-max-back-bytes=20M", "--no-input-terminal", "--no-osc", "--profile=gpu-hq", /*"--vo=gpu", "--hwdec=auto",*/ - "--wid", parent_window_str.c_str(), "--", path, nullptr }; - if(exec_program_async(args, &video_process_id) != 0) + "--wid", parent_window_str.c_str(), "--", path, nullptr }); + if(exec_program_async(args.data(), &video_process_id) != 0) return Error::FAIL_TO_LAUNCH_PROCESS; printf("mpv input ipc server: %s\n", ipc_server_path); @@ -125,13 +128,17 @@ namespace QuickMedia { } VideoPlayer::Error VideoPlayer::update() { + int max_retries_find_window = 10; + if(use_tor) + max_retries_find_window = 30; + if(ipc_socket == -1) return Error::INIT_FAILED; if(connect_tries == MAX_RETRIES_CONNECT) return Error::FAIL_TO_CONNECT_TIMEOUT; - if(find_window_tries == MAX_RETRIES_FIND_WINDOW) + if(find_window_tries == max_retries_find_window) return Error::FAIL_TO_FIND_WINDOW; if(!connected_to_ipc && retry_timer.getElapsedTime().asMilliseconds() >= RETRY_TIME_MS) { @@ -153,8 +160,8 @@ namespace QuickMedia { size_t num_children = child_windows.size(); if(num_children == 0) { ++find_window_tries; - if(find_window_tries == MAX_RETRIES_FIND_WINDOW) { - fprintf(stderr, "Failed to find mpv window after %d seconds\n", (RETRY_TIME_MS * MAX_RETRIES_FIND_WINDOW)/1000); + if(find_window_tries == max_retries_find_window) { + fprintf(stderr, "Failed to find mpv window after %d seconds\n", (RETRY_TIME_MS * max_retries_find_window)/1000); return Error::FAIL_TO_FIND_WINDOW_TIMEOUT; } } else if(num_children == 1) { diff --git a/src/plugins/Plugin.cpp b/src/plugins/Plugin.cpp index c56ff67..d1490d5 100644 --- a/src/plugins/Plugin.cpp +++ b/src/plugins/Plugin.cpp @@ -28,22 +28,6 @@ namespace QuickMedia { return {}; } - DownloadResult download_to_string(const std::string &url, std::string &result, const std::vector &additional_args) { - sf::Clock timer; - std::vector args = { "curl", "-f", "-H", "Accept-Language: en-US,en;q=0.5", "--compressed", "-s", "-L" }; - for(const CommandArg &arg : additional_args) { - args.push_back(arg.option.c_str()); - args.push_back(arg.value.c_str()); - } - args.push_back("--"); - args.push_back(url.c_str()); - args.push_back(nullptr); - if(exec_program(args.data(), accumulate_string, &result) != 0) - return DownloadResult::NET_ERR; - fprintf(stderr, "Download duration for %s: %d ms\n", url.c_str(), timer.getElapsedTime().asMilliseconds()); - return DownloadResult::OK; - } - static bool is_whitespace(char c) { return c == ' ' || c == '\n' || c == '\t' || c == '\v'; } @@ -112,4 +96,23 @@ namespace QuickMedia { return result.str(); } + + DownloadResult Plugin::download_to_string(const std::string &url, std::string &result, const std::vector &additional_args) { + sf::Clock timer; + std::vector args; + if(use_tor) + args.push_back("torsocks"); + args.insert(args.end(), { "curl", "-f", "-H", "Accept-Language: en-US,en;q=0.5", "--compressed", "-s", "-L" }); + for(const CommandArg &arg : additional_args) { + args.push_back(arg.option.c_str()); + args.push_back(arg.value.c_str()); + } + args.push_back("--"); + args.push_back(url.c_str()); + args.push_back(nullptr); + if(exec_program(args.data(), accumulate_string, &result) != 0) + return DownloadResult::NET_ERR; + fprintf(stderr, "Download duration for %s: %d ms\n", url.c_str(), timer.getElapsedTime().asMilliseconds()); + return DownloadResult::OK; + } } \ No newline at end of file -- cgit v1.2.3