From 89383cff1ba5d8a928262fcb4c40382a981c78c8 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Fri, 11 Jun 2021 04:51:03 +0200 Subject: Remove dependency on youtube-dl for streaming youtube, resulting in faster video startup --- plugins/ImageBoard.hpp | 6 ++---- plugins/Matrix.hpp | 6 ++---- plugins/MediaGeneric.hpp | 6 ++---- plugins/Page.hpp | 18 ++++++++++++++--- plugins/Soundcloud.hpp | 7 ++----- plugins/Youtube.hpp | 39 ++++++++++++++++++++++++++++++------ plugins/youtube/Signature.hpp | 46 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 102 insertions(+), 26 deletions(-) create mode 100644 plugins/youtube/Signature.hpp (limited to 'plugins') diff --git a/plugins/ImageBoard.hpp b/plugins/ImageBoard.hpp index 6b287b6..651eabf 100644 --- a/plugins/ImageBoard.hpp +++ b/plugins/ImageBoard.hpp @@ -16,16 +16,15 @@ namespace QuickMedia { class ImageBoardThreadPage : public VideoPage { public: - ImageBoardThreadPage(Program *program, std::string board_id, std::string thread_id) : VideoPage(program), board_id(std::move(board_id)), thread_id(std::move(thread_id)) {} + ImageBoardThreadPage(Program *program, std::string board_id, std::string thread_id) : VideoPage(program, ""), board_id(std::move(board_id)), thread_id(std::move(thread_id)) {} const char* get_title() const override { return ""; } PageTypez get_type() const override { return PageTypez::IMAGE_BOARD_THREAD; } bool autoplay_next_item() override { return true; } - std::unique_ptr create_related_videos_page(Program *program, const std::string &video_url, const std::string &video_title) override; + std::unique_ptr create_related_videos_page(Program *program) override; std::unique_ptr create_channels_page(Program*, const std::string&) override { return nullptr; } - std::string get_url() override { return video_url; } virtual PluginResult login(const std::string &token, const std::string &pin, std::string &response_msg); // If |filepath| is empty then no file is uploaded virtual PostResult post_comment(const std::string &captcha_id, const std::string &comment, const std::string &filepath = "") = 0; @@ -33,6 +32,5 @@ namespace QuickMedia { const std::string board_id; const std::string thread_id; - std::string video_url; }; } \ No newline at end of file diff --git a/plugins/Matrix.hpp b/plugins/Matrix.hpp index ebaa166..568357a 100644 --- a/plugins/Matrix.hpp +++ b/plugins/Matrix.hpp @@ -410,16 +410,14 @@ namespace QuickMedia { // Dummy, only play one video. TODO: Play all videos in room, as related videos? class MatrixVideoPage : public VideoPage { public: - MatrixVideoPage(Program *program) : VideoPage(program) {} + MatrixVideoPage(Program *program) : VideoPage(program, "") {} const char* get_title() const override { return ""; } - std::unique_ptr create_related_videos_page(Program*, const std::string&, const std::string&) override { + std::unique_ptr create_related_videos_page(Program*) override { return nullptr; } std::unique_ptr create_channels_page(Program*, const std::string&) override { return nullptr; } - std::string get_url() override { return url; } - std::string url; }; class MatrixChatPage : public Page { diff --git a/plugins/MediaGeneric.hpp b/plugins/MediaGeneric.hpp index c7ce00b..102e315 100644 --- a/plugins/MediaGeneric.hpp +++ b/plugins/MediaGeneric.hpp @@ -80,17 +80,15 @@ namespace QuickMedia { class MediaGenericVideoPage : public VideoPage { public: - MediaGenericVideoPage(Program *program, MediaGenericSearchPage *search_page, const std::string &url) : VideoPage(program), search_page(search_page), url(url) {} + MediaGenericVideoPage(Program *program, MediaGenericSearchPage *search_page, const std::string &url) : VideoPage(program, url), search_page(search_page) {} const char* get_title() const override { return ""; } BodyItems get_related_media(const std::string &url, std::string &channel_url) override; std::unique_ptr create_search_page(Program *program, int &search_delay) override; - std::unique_ptr create_related_videos_page(Program *program, const std::string &video_url, const std::string &video_title) override; + std::unique_ptr create_related_videos_page(Program *program) override; std::unique_ptr create_channels_page(Program*, const std::string&) override { return nullptr; } - std::string get_url() override { return url; } private: MediaGenericSearchPage *search_page; - std::string url; }; } \ No newline at end of file diff --git a/plugins/Page.hpp b/plugins/Page.hpp index 54d7d88..0c5b093 100644 --- a/plugins/Page.hpp +++ b/plugins/Page.hpp @@ -102,18 +102,30 @@ namespace QuickMedia { class VideoPage : public Page { public: - VideoPage(Program *program) : Page(program) {} + VideoPage(Program *program, std::string url) : Page(program), url(std::move(url)) {} virtual PageTypez get_type() const override { return PageTypez::VIDEO; } virtual bool autoplay_next_item() { return false; } virtual BodyItems get_related_media(const std::string &url, std::string &channel_url) { (void)url; (void)channel_url; return {}; } virtual std::unique_ptr create_search_page(Program *program, int &search_delay) { (void)program; (void)search_delay; return nullptr; } virtual std::unique_ptr create_comments_page(Program *program) { (void)program; return nullptr; } // Return nullptr if the service doesn't support related videos page - virtual std::unique_ptr create_related_videos_page(Program *program, const std::string &video_url, const std::string &video_title) = 0; + virtual std::unique_ptr create_related_videos_page(Program *program) = 0; // Return nullptr if the service doesn't support channels page virtual std::unique_ptr create_channels_page(Program *program, const std::string &channel_url) = 0; - virtual std::string get_url() = 0; + void set_url(std::string new_url) { url = std::move(new_url); } + std::string get_url() { return url; } + // Falls back to |get_url| if this and |get_audio_url| returns empty strings + virtual std::string get_video_url(int max_height, bool &has_embedded_audio) { + (void)max_height; + has_embedded_audio = true; + return ""; + } + // Only used if |get_video_url| sets |has_embedded_audio| to false + virtual std::string get_audio_url() { return ""; } virtual std::string url_get_playable_url(const std::string &url) { return url; } virtual bool video_should_be_skipped(const std::string &url) { (void)url; return false; } + virtual PluginResult load() { return PluginResult::OK; } + protected: + std::string url; }; } \ No newline at end of file diff --git a/plugins/Soundcloud.hpp b/plugins/Soundcloud.hpp index 873de5a..c7883ba 100644 --- a/plugins/Soundcloud.hpp +++ b/plugins/Soundcloud.hpp @@ -57,15 +57,12 @@ namespace QuickMedia { class SoundcloudAudioPage : public VideoPage { public: - SoundcloudAudioPage(Program *program, const std::string &url) : VideoPage(program), url(url) {} + SoundcloudAudioPage(Program *program, const std::string &url) : VideoPage(program, url) {} const char* get_title() const override { return ""; } bool autoplay_next_item() override { return true; } - std::unique_ptr create_related_videos_page(Program *, const std::string &, const std::string &) override { return nullptr; } + std::unique_ptr create_related_videos_page(Program *) override { return nullptr; } std::unique_ptr create_channels_page(Program *, const std::string &) override { return nullptr; } - std::string get_url() override { return url; } std::string url_get_playable_url(const std::string &url) override; bool video_should_be_skipped(const std::string &url) override { return url == "track" || url.find("/stream/users/") != std::string::npos; } - private: - std::string url; }; } \ No newline at end of file diff --git a/plugins/Youtube.hpp b/plugins/Youtube.hpp index 746619c..dea6cc2 100644 --- a/plugins/Youtube.hpp +++ b/plugins/Youtube.hpp @@ -5,14 +5,35 @@ #include namespace QuickMedia { - class YoutubeSearchPage : public Page { + struct YoutubeFormat { + std::string url; + int bitrate = 0; + }; + + struct YoutubeVideoFormat { + YoutubeFormat base; + int width = 0; + int height = 0; + int fps = 0; + bool has_embedded_audio = false; + }; + + struct YoutubeAudioFormat { + YoutubeFormat base; + }; + + bool youtube_url_extract_id(const std::string &youtube_url, std::string &youtube_video_id); + + class YoutubeSearchPage : public LazyFetchPage { public: - YoutubeSearchPage(Program *program) : Page(program) {} + YoutubeSearchPage(Program *program) : LazyFetchPage(program) {} const char* get_title() const override { return "Search"; } bool search_is_filter() override { return false; } SearchResult search(const std::string &str, BodyItems &result_items) override; PluginResult get_page(const std::string &str, int page, BodyItems &result_items) override; PluginResult submit(const std::string &title, const std::string &url, std::vector &result_tabs) override; + PluginResult lazy_fetch(BodyItems &result_items) override; + bool lazy_fetch_is_loader() override { return true; } private: PluginResult search_get_continuation(const std::string &url, const std::string &continuation_token, BodyItems &result_items); private: @@ -110,18 +131,24 @@ namespace QuickMedia { class YoutubeVideoPage : public VideoPage { public: - YoutubeVideoPage(Program *program, const std::string &url) : VideoPage(program), url(url) {} + YoutubeVideoPage(Program *program, std::string url) : VideoPage(program, std::move(url)) {} const char* get_title() const override { return ""; } BodyItems get_related_media(const std::string &url, std::string &channel_url) override; std::unique_ptr create_search_page(Program *program, int &search_delay) override; std::unique_ptr create_comments_page(Program *program) override; - std::unique_ptr create_related_videos_page(Program *program, const std::string &video_url, const std::string &video_title) override; + std::unique_ptr create_related_videos_page(Program *program) override; std::unique_ptr create_channels_page(Program *program, const std::string &channel_url) override; - std::string get_url() override { return url; } + std::string get_video_url(int max_height, bool &has_embedded_audio) override; + std::string get_audio_url() override; + PluginResult load() override; + private: + void parse_format(const Json::Value &format_json, bool is_adaptive); + void parse_formats(const Json::Value &streaming_data_json); private: std::string xsrf_token; std::string comments_continuation_token; - std::string url; + std::vector video_formats; + std::vector audio_formats; std::string playback_url; std::string watchtime_url; diff --git a/plugins/youtube/Signature.hpp b/plugins/youtube/Signature.hpp new file mode 100644 index 0000000..7456615 --- /dev/null +++ b/plugins/youtube/Signature.hpp @@ -0,0 +1,46 @@ +#pragma once + +#include "../../include/AsyncTask.hpp" +#include +#include +#include +#include +#include + +namespace QuickMedia { + // Thread safe + class YoutubeSignatureDecryptor { + public: + static YoutubeSignatureDecryptor& get_instance(); + bool decrypt(const std::string &s, const std::string &sp, std::string &sig_key, std::string &sig_value); + private: + YoutubeSignatureDecryptor(); + ~YoutubeSignatureDecryptor(); + YoutubeSignatureDecryptor(const YoutubeSignatureDecryptor&) = delete; + YoutubeSignatureDecryptor& operator=(const YoutubeSignatureDecryptor&) = delete; + + struct DecryptFuncCall { + std::string func_name; + long arg; + }; + + enum class DecryptFunction { + REVERSE, + SPLICE, + SWAP + }; + + bool 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); + int update_decrypt_function(); + private: + AsyncTask poll_task; + std::mutex update_signature_mutex; + std::string decryption_function; + time_t decrypt_function_last_updated = 0; + bool running = false; + bool up_to_date = false; + + std::vector func_calls; + std::map func_decls; + }; +} \ No newline at end of file -- cgit v1.2.3