From 664835fcee5f0dc1fa5aba63c845c4561628a20f Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sun, 30 May 2021 17:01:14 +0200 Subject: Add option to only save audio for youtube videos. Use youtube plugin for info urls. Use youtube plugin for urls on matrix --- src/QuickMedia.cpp | 162 ++++++++++++++++++++++++++++++++++----------------- src/plugins/Info.cpp | 15 ++++- 2 files changed, 121 insertions(+), 56 deletions(-) (limited to 'src') diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index a61b836..595ae7b 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -289,6 +289,38 @@ namespace QuickMedia { HistoryType history_type; }; + using OptionsPageHandler = std::function; + + class OptionsPage : public Page { + public: + OptionsPage(Program *program, std::string title) : Page(program), title(std::move(title)) {} + const char* get_title() const override { return title.c_str(); } + + PluginResult submit(const std::string&, const std::string &url, std::vector&) override { + const int handlers_index = atoi(url.c_str()); + handlers[handlers_index](); + program->set_go_to_previous_page(); + return PluginResult::OK; + } + + bool submit_is_async() override { return false; } + + void add_option(BodyItems &items, std::string title, std::string description, OptionsPageHandler handler) { + assert(handler); + auto body_item = BodyItem::create(std::move(title)); + if(!description.empty()) { + body_item->set_description(std::move(description)); + body_item->set_description_color(sf::Color(179, 179, 179)); + } + body_item->url = std::to_string(handlers.size()); + handlers.push_back(std::move(handler)); + items.push_back(std::move(body_item)); + } + private: + std::string title; + std::vector handlers; + }; + Program::Program() : disp(nullptr), window_size(1280, 720), @@ -1528,10 +1560,10 @@ namespace QuickMedia { } } - void Program::page_loop(std::vector &tabs, int start_tab_index, PageLoopSubmitHandler after_submit_handler) { + bool Program::page_loop(std::vector &tabs, int start_tab_index, PageLoopSubmitHandler after_submit_handler) { if(tabs.empty()) { show_notification("QuickMedia", "No tabs provided!", Urgency::CRITICAL); - return; + return false; } malloc_trim(0); @@ -1845,7 +1877,7 @@ namespace QuickMedia { redraw = true; else if(event.type == sf::Event::KeyPressed) { if(event.key.code == sf::Keyboard::Escape) { - goto page_end; + return false; } else if(event.key.code == sf::Keyboard::Tab) { if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->set_to_autocomplete(); } else if(event.key.code == sf::Keyboard::Enter) { @@ -2085,12 +2117,11 @@ namespace QuickMedia { if(go_to_previous_page) { go_to_previous_page = false; - goto page_end; + return true; } } - page_end: - {} + return false; } static bool youtube_url_extract_id(const std::string &youtube_url, std::string &youtube_video_id) { @@ -2279,20 +2310,58 @@ namespace QuickMedia { return false; } + void Program::video_page_download_video(const std::string &url, bool use_youtube_dl, sf::WindowHandle video_player_window) { + if(!use_youtube_dl) { + download_async_gui(url, FileManagerPage::get_last_accessed_directory(file_manager_start_dir).string(), use_youtube_dl, no_video); + return; + } + + bool audio_only = false; + auto body = create_body(); + + auto options_page = std::make_unique(this, "Select download option"); + options_page->add_option(body->items, "Download video and audio", "", [&audio_only](){ + audio_only = false; + }); + options_page->add_option(body->items, "Download only audio", "", [&audio_only](){ + audio_only = true; + }); + + if(video_player_window) { + XUnmapWindow(disp, video_player_window); + XSync(disp, False); + } + + std::vector tabs; + tabs.push_back(Tab{ std::move(body), std::move(options_page), nullptr }); + bool selected = page_loop(tabs); + + if(video_player_window) { + XMapWindow(disp, video_player_window); + XSync(disp, False); + } + + if(!selected) + return; + + download_async_gui(url, FileManagerPage::get_last_accessed_directory(file_manager_start_dir).string(), true, audio_only); + } + #define CLEANMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask|Mod4Mask|Mod5Mask)) void Program::video_content_page(Page *parent_page, VideoPage *video_page, std::string video_title, bool download_if_streaming_fails, BodyItems &next_play_items, int play_index, int *parent_body_page, const std::string &parent_page_search) { - sf::Clock time_watched_timer; - bool video_loaded = false; - const bool is_youtube = strcmp(plugin_name, "youtube") == 0; - const bool is_matrix = strcmp(plugin_name, "matrix") == 0; - PageType previous_page = pop_page_stack(); std::string video_url = video_page->get_url(); std::string original_video_url = video_url; + sf::Clock time_watched_timer; + bool video_loaded = false; + std::string youtube_video_id; + const bool is_youtube = youtube_url_extract_id(video_url, youtube_video_id); + const bool is_matrix = strcmp(plugin_name, "matrix") == 0; + bool video_url_is_local = false; - if(download_if_streaming_fails) { + if(!is_youtube && download_if_streaming_fails) { Path video_cache_dir = get_cache_dir().join("media"); Path video_path = video_cache_dir; SHA256 sha256; @@ -2361,13 +2430,13 @@ namespace QuickMedia { std::function video_event_callback; - auto load_video_error_check = [this, &related_videos, &channel_url, &video_url, &video_title, &video_player, previous_page, &time_watched_timer, &video_loaded, video_page, &video_event_callback, &on_window_create, &video_player_window, is_matrix](bool resume_video) mutable { + auto load_video_error_check = [this, &related_videos, &channel_url, &video_url, &video_title, &video_player, previous_page, &time_watched_timer, &video_loaded, video_page, &video_event_callback, &on_window_create, &video_player_window, is_youtube, is_matrix](bool resume_video) mutable { time_watched_timer.restart(); video_loaded = false; video_player_window = None; watched_videos.insert(video_url); - video_player = std::make_unique(no_video, use_system_mpv_config, resume_video, is_matrix, video_event_callback, on_window_create, resources_root, get_largest_monitor_height(disp)); + video_player = std::make_unique(no_video, use_system_mpv_config, resume_video, is_matrix && !is_youtube, video_event_callback, on_window_create, resources_root, get_largest_monitor_height(disp)); VideoPlayer::Error err = video_player->load_video(video_url.c_str(), window.getSystemHandle(), plugin_name, video_title); if(err != VideoPlayer::Error::OK) { std::string err_msg = "Failed to play url: "; @@ -2490,8 +2559,6 @@ namespace QuickMedia { window_set_fullscreen(disp, window.getSystemHandle(), WindowFullscreenState::TOGGLE); } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::C && event.key.control) { save_video_url_to_clipboard(); - } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::S && event.key.control) { - download_async_gui(original_video_url, FileManagerPage::get_last_accessed_directory(file_manager_start_dir).string(), !is_matrix, no_video); } } handle_window_close(); @@ -2512,7 +2579,7 @@ namespace QuickMedia { } else if(pressed_keysym == XK_f && pressing_ctrl) { window_set_fullscreen(disp, window.getSystemHandle(), WindowFullscreenState::TOGGLE); } else if(pressed_keysym == XK_s && pressing_ctrl) { - download_async_gui(original_video_url, FileManagerPage::get_last_accessed_directory(file_manager_start_dir).string(), !is_matrix, no_video); + video_page_download_video(original_video_url, !is_matrix || is_youtube, video_player_window); } else if(pressed_keysym == XK_r && pressing_ctrl) { if(!cursor_visible) window.setMouseCursorVisible(true); @@ -2540,7 +2607,7 @@ namespace QuickMedia { tabs.push_back(Tab{std::move(related_videos_body), std::move(related_videos_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } if(channels_page) { - tabs.push_back(Tab{create_body(), std::move(channels_page), create_search_bar("Search...", is_youtube ? 350 : SEARCH_DELAY_FILTER)}); + tabs.push_back(Tab{create_body(), std::move(channels_page), create_search_bar("Search...", 350)}); } bool page_changed = false; @@ -2591,7 +2658,7 @@ namespace QuickMedia { show_notification("QuickMedia", "Failed to connect to mpv ipc after 10 seconds", Urgency::CRITICAL); current_page = previous_page; break; - } else if(update_err == VideoPlayer::Error::EXITED && video_player->exit_status == 0 && !is_matrix) { + } else if(update_err == VideoPlayer::Error::EXITED && video_player->exit_status == 0 && (!is_matrix || is_youtube)) { std::string new_video_url; std::string new_video_title; @@ -2608,7 +2675,7 @@ namespace QuickMedia { }; find_next_video(); - if(new_video_url.empty() && parent_page && parent_body_page) { + if(new_video_url.empty() && parent_page && parent_body_page && video_page->autoplay_next_item()) { BodyItems new_body_items; const int fetch_page = (*parent_body_page) + 1; TaskResult load_next_page_result = run_task_with_loading_screen([parent_page, parent_page_search, fetch_page, &new_body_items] { @@ -4890,19 +4957,18 @@ namespace QuickMedia { bool avatar_applied = false; - auto launch_url = [this, matrix_chat_page, &video_page, &redraw, &avatar_applied](const std::string &url) mutable { + auto launch_url = [this, matrix_chat_page, &tabs, MESSAGES_TAB_INDEX, &redraw, &avatar_applied](const std::string &url) mutable { if(url.empty()) return; std::string video_id; if(youtube_url_extract_id(url, video_id)) { - page_stack.push(PageType::CHAT); watched_videos.clear(); + page_stack.push(PageType::CHAT); current_page = PageType::VIDEO_CONTENT; - video_page->url = url; - BodyItems next_items; - // TODO: Add title - video_content_page(matrix_chat_page, video_page.get(), "", false, next_items, 0); + auto youtube_video_page = std::make_unique(this, url); + // TODO: Use real title + video_content_page(matrix_chat_page, youtube_video_page.get(), "", false, tabs[MESSAGES_TAB_INDEX].body->items, tabs[MESSAGES_TAB_INDEX].body->get_selected_item()); redraw = true; avatar_applied = false; } else { @@ -6489,7 +6555,7 @@ namespace QuickMedia { } loading_bar.set_size(sf::Vector2f( - std::floor((loading_bar_background.get_size().x - loading_bar_padding_x) * ui_progress), + std::floor((loading_bar_background.get_size().x - loading_bar_padding_x * 2.0f) * ui_progress), loading_bar_height - loading_bar_padding_y * 2.0f)); window.clear(sf::Color(33, 37, 44)); @@ -6516,29 +6582,6 @@ namespace QuickMedia { exit(exit_code); } - class ConfirmationPage : public Page { - public: - ConfirmationPage(Program *program, bool *file_overwrite, const std::string &title) : Page(program), file_overwrite(file_overwrite), title(title) {} - const char* get_title() const override { return title.c_str(); } - PluginResult submit(const std::string &title, const std::string&, std::vector&) override { - if(title == "Yes") - *file_overwrite = true; - else - *file_overwrite = false; - - program->set_go_to_previous_page(); - return PluginResult::OK; - } - - static void add_items(BodyItems &items) { - items.push_back(BodyItem::create("No")); - items.push_back(BodyItem::create("Yes")); - } - private: - bool *file_overwrite; - std::string title; - }; - std::string Program::file_save_page(const std::string &filename) { sf::Vector2f body_pos; sf::Vector2f body_size; @@ -6590,10 +6633,10 @@ namespace QuickMedia { const float bottom_panel_spacing = 10.0f; Button cancel_button("Cancel", FontLoader::get_font(FontLoader::FontType::LATIN), 16, 100.0f, &rounded_rectangle_shader, get_ui_scale()); - cancel_button.set_background_color(sf::Color(104, 2, 2)); + cancel_button.set_background_color(sf::Color(41, 45, 50)); Button save_button("Save", FontLoader::get_font(FontLoader::FontType::LATIN), 16, 100.0f, &rounded_rectangle_shader, get_ui_scale()); - save_button.set_background_color(sf::Color(35, 35, 236)); + save_button.set_background_color(sf::Color(71, 75, 180)); sf::Text file_name_label("File name:", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(16.0f * get_ui_scale())); @@ -6621,11 +6664,20 @@ namespace QuickMedia { } else { if(std::filesystem::exists(filename_full_path.data)) { bool overwrite = false; - std::vector tabs; auto body = create_body(); - ConfirmationPage::add_items(body->items); - tabs.push_back(Tab{ std::move(body), std::make_unique(this, &overwrite, "Are you sure you want to overwrite " + filename_full_path.data + "?"), nullptr }); + + auto options_page = std::make_unique(this, "Are you sure you want to overwrite " + filename_full_path.data + "?"); + options_page->add_option(body->items, "No", "", [&overwrite](){ + overwrite = false; + }); + options_page->add_option(body->items, "Yes", "", [&overwrite](){ + overwrite = true; + }); + + std::vector tabs; + tabs.push_back(Tab{ std::move(body), std::move(options_page), nullptr }); page_loop(tabs); + if(overwrite) return std::move(filename_full_path.data); } else { diff --git a/src/plugins/Info.cpp b/src/plugins/Info.cpp index b1943b3..a68033f 100644 --- a/src/plugins/Info.cpp +++ b/src/plugins/Info.cpp @@ -1,5 +1,6 @@ #include "../../plugins/Info.hpp" #include "../../plugins/Saucenao.hpp" +#include "../../plugins/Youtube.hpp" #include "../../include/StringUtils.hpp" #include "../../include/Program.hpp" #include "../../include/Notification.hpp" @@ -7,11 +8,18 @@ namespace QuickMedia { static const char *REVERSE_IMAGE_SEARCH_URL = "reverse-image-search://"; + static bool is_youtube_url(const std::string &url) { + return url.find("youtube.com/") != std::string::npos || url.find("youtu.be/") != std::string::npos; + } + PluginResult InfoPage::submit(const std::string&, const std::string &url, std::vector &result_tabs) { if(string_starts_with(url, REVERSE_IMAGE_SEARCH_URL)) { std::string image_url = url.substr(strlen(REVERSE_IMAGE_SEARCH_URL)); result_tabs.push_back(Tab{create_body(), std::make_unique(program, image_url, false), nullptr}); return PluginResult::OK; + } else if(is_youtube_url(url)) { + result_tabs.push_back(Tab{nullptr, std::make_unique(program, url), nullptr}); + return PluginResult::OK; } else { const char *launch_program = "xdg-open"; if(!is_program_executable_by_name("xdg-open")) { @@ -33,7 +41,12 @@ namespace QuickMedia { // static std::shared_ptr InfoPage::add_url(const std::string &url) { - auto body_item = BodyItem::create("Open " + url + " in a browser"); + std::string title; + if(is_youtube_url(url)) + title = "Play " + url; + else + title = "Open " + url + " in a browser"; + auto body_item = BodyItem::create(std::move(title)); body_item->url = url; return body_item; } -- cgit v1.2.3