From e671784144174c4fceaa6df3737ba9b4de4a6c63 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 17 Jul 2021 09:43:20 +0200 Subject: Youtube: remove dependency on youtube-dl for downloads (also fixes downloads of age restricted videos) --- include/DownloadUtils.hpp | 2 +- include/Downloader.hpp | 104 ++++++++++++++++++++++++++++++++++++++++++++++ include/QuickMedia.hpp | 4 +- 3 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 include/Downloader.hpp (limited to 'include') diff --git a/include/DownloadUtils.hpp b/include/DownloadUtils.hpp index dbac921..398f82c 100644 --- a/include/DownloadUtils.hpp +++ b/include/DownloadUtils.hpp @@ -32,6 +32,6 @@ namespace QuickMedia { // Note: if |cloudflare_bypass| is set to true then tls is limited to version 1.1 and the user agent is changed. DownloadResult download_to_file(const std::string &url, const std::string &destination_filepath, const std::vector &additional_args, bool use_browser_useragent = false, bool cloudflare_bypass = false); // Returns false if there was an error trying to create the download process - bool download_async_gui(const std::string &url, const std::string &file_manager_start_dir, bool use_youtube_dl, bool no_video); + bool download_async_gui(const std::string &url, const std::string &file_manager_start_dir, bool no_video); DownloadResult download_to_json(const std::string &url, rapidjson::Document &result, const std::vector &additional_args, bool use_browser_useragent = false, bool fail_on_error = true); } \ No newline at end of file diff --git a/include/Downloader.hpp b/include/Downloader.hpp new file mode 100644 index 0000000..f09f9bf --- /dev/null +++ b/include/Downloader.hpp @@ -0,0 +1,104 @@ +#pragma once + +#include "Path.hpp" +#include "AsyncTask.hpp" +#include "../plugins/youtube/YoutubeMediaProxy.hpp" +#include + +namespace QuickMedia { + enum class DownloadUpdateStatus { + DOWNLOADING, + FINISHED, + ERROR + }; + + class Downloader { + public: + Downloader(const std::string &url, const std::string &output_filepath) : url(url), output_filepath(output_filepath) {} + virtual ~Downloader() = default; + + virtual bool start() = 0; + virtual bool stop(bool download_completed) = 0; + virtual DownloadUpdateStatus update() = 0; + + virtual float get_progress() = 0; + virtual std::string get_progress_text() = 0; + virtual std::string get_download_speed_text() = 0; + + const std::string& get_output_filepath() { return output_filepath; } + protected: + std::string url; + std::string output_filepath; + }; + + class CurlDownloader : public Downloader { + public: + CurlDownloader(const std::string &url, const std::string &output_filepath, int64_t content_length = -1); + bool start() override; + bool stop(bool download_completed) override; + DownloadUpdateStatus update() override; + float get_progress() override; + std::string get_progress_text() override; + std::string get_download_speed_text() override; + private: + Path output_filepath_tmp; + ReadProgram read_program; + AsyncTask header_reader; + std::string header; + int64_t content_length = -1; + size_t downloaded_since_last_check = 0; + float progress = 0.0f; + std::mutex content_length_mutex; + std::string progress_text; + std::string download_speed_text; + bool finished = false; + }; + + class YoutubeDlDownloader : public Downloader { + public: + YoutubeDlDownloader(const std::string &url, const std::string &output_filepath, bool no_video); + bool start() override; + bool stop(bool download_completed) override; + DownloadUpdateStatus update() override; + float get_progress() override; + std::string get_progress_text() override; + std::string get_download_speed_text() override; + private: + ReadProgram read_program; + FILE *read_program_file = nullptr; + AsyncTask youtube_dl_output_reader; + std::mutex progress_update_mutex; + float progress = 0.0f; + std::string progress_text; + std::string download_speed_text; + bool no_video; + bool finished = false; + }; + + struct MediaMetadata { + std::string url; + int64_t content_length; + }; + + class YoutubeDownloader : public Downloader { + public: + YoutubeDownloader(const MediaMetadata &video_metadata, const MediaMetadata &audio_metadata, const std::string &output_filepath); + bool start() override; + bool stop(bool download_completed) override; + DownloadUpdateStatus update() override; + float get_progress() override; + std::string get_progress_text() override; + std::string get_download_speed_text() override; + private: + CurlDownloader* get_min_progress_downloader(); + private: + MediaMetadata video_metadata; + MediaMetadata audio_metadata; + std::string video_output_filepath; + std::string audio_output_filepath; + std::unique_ptr downloaders[2]; + AsyncTask downloader_task; + std::unique_ptr youtube_video_media_proxy; + std::unique_ptr youtube_audio_media_proxy; + }; +} \ No newline at end of file diff --git a/include/QuickMedia.hpp b/include/QuickMedia.hpp index cc4a10f..765a346 100644 --- a/include/QuickMedia.hpp +++ b/include/QuickMedia.hpp @@ -113,7 +113,7 @@ namespace QuickMedia { using PageLoopSubmitHandler = std::function &new_tabs)>; // Returns false if the page loop was escaped by user navigation (pressing escape) or if there was an error at startup bool page_loop(std::vector &tabs, int start_tab_index = 0, PageLoopSubmitHandler after_submit_handler = nullptr); - void video_page_download_video(const std::string &url, bool use_youtube_dl, sf::WindowHandle video_player_window = None); + void video_page_download_video(const std::string &url, sf::WindowHandle video_player_window = None); bool video_download_if_non_streamable(std::string &video_url, std::string &audio_url, bool &is_audio_only, bool &has_embedded_audio, PageType previous_page); void video_content_page(Page *parent_page, VideoPage *video_page, std::string video_title, bool download_if_streaming_fails, Body *parent_body, BodyItems &next_play_items, int play_index, int *parent_body_page = nullptr, const std::string &parent_page_search = ""); // Returns -1 to go to previous chapter, 0 to stay on same chapter and 1 to go to next chapter @@ -123,7 +123,7 @@ namespace QuickMedia { void chat_login_page(); bool chat_page(MatrixChatPage *matrix_chat_page, RoomData *current_room); void after_matrix_login_page(); - void download_page(const char *url, bool download_use_youtube_dl); + void download_page(const std::string &url); // Returns the full path where the file should be saved, or an empty string if the operation was cancelled std::string file_save_page(const std::string &filename); -- cgit v1.2.3