#pragma once #include "Path.hpp" #include "AsyncTask.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; int64_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 char *yt_dl_name, 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; const char *yt_dl_name; }; struct MediaMetadata { std::string url; int64_t content_length; }; struct YoutubeReadProgram { ReadProgram read_program; int64_t offset = 0; int64_t content_length = -1; int64_t bytes_downloaded = 0; int64_t downloaded_since_last_check = 0; char *url = nullptr; std::string output_filepath; std::string output_filepath_tmp; double progress = 0.0; std::string progress_text; std::string download_speed_text; bool finished = false; }; class YoutubeDownloader : public Downloader { public: YoutubeDownloader(const MediaMetadata &video_metadata, const MediaMetadata &audio_metadata, const std::string &output_filepath); ~YoutubeDownloader(); 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: YoutubeReadProgram* get_min_progress_downloader(); DownloadUpdateStatus update(size_t program_index); private: MediaMetadata video_metadata; MediaMetadata audio_metadata; std::string video_output_filepath; std::string audio_output_filepath; YoutubeReadProgram *program[2]; AsyncTask downloader_tasks[2]; }; }