From b6b972e2dae816a8f0686f4986029a5ed50e592c Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 4 Nov 2020 01:30:38 +0100 Subject: Add channels page to related videos menu, fix related videos menu broken after video failing to load --- src/QuickMedia.cpp | 378 +++++++++++++++++++++++---------------------- src/plugins/ImageBoard.cpp | 6 +- src/plugins/Page.cpp | 5 - src/plugins/Pornhub.cpp | 20 ++- src/plugins/Youtube.cpp | 51 +++++- 5 files changed, 263 insertions(+), 197 deletions(-) (limited to 'src') diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 7d7e97f..bd19f2a 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -169,15 +169,35 @@ static sf::Color interpolate_colors(sf::Color source, sf::Color target, double p } namespace QuickMedia { + enum class HistoryType { + YOUTUBE, + MANGA + }; + class HistoryPage : public Page { public: - HistoryPage(Program *program, Page *search_page) : Page(program), search_page(search_page) {} + HistoryPage(Program *program, Page *search_page, SearchBar *search_bar, HistoryType history_type) : + Page(program), search_page(search_page), search_bar(search_bar), history_type(history_type) {} const char* get_title() const override { return "History"; } PluginResult submit(const std::string &title, const std::string &url, std::vector &result_tabs) override { return search_page->submit(title, url, result_tabs); } + void on_navigate_to_page(Body *body) override { + body->clear_items(); + switch(history_type) { + case HistoryType::YOUTUBE: + program->youtube_get_watch_history(body->items); + break; + case HistoryType::MANGA: + program->manga_get_watch_history(program->get_plugin_name(), body->items); + break; + } + body->filter_search_fuzzy(search_bar->get_text()); + } private: Page *search_page; + SearchBar *search_bar; + HistoryType history_type; }; class RecommendedPage : public Page { @@ -533,22 +553,25 @@ namespace QuickMedia { tabs.push_back(Tab{std::move(search_body), std::make_unique(this), create_search_bar("Search...", 200)}); auto history_body = create_body(); - manga_get_watch_history(plugin_name, history_body->items); - tabs.push_back(Tab{std::move(history_body), std::make_unique(this, tabs.front().page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + auto search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER); + auto history_page = std::make_unique(this, tabs.front().page.get(), search_bar.get(), HistoryType::MANGA); + tabs.push_back(Tab{std::move(history_body), std::move(history_page), std::move(search_bar)}); } else if(strcmp(plugin_name, "mangatown") == 0) { auto search_body = create_body(); tabs.push_back(Tab{std::move(search_body), std::make_unique(this), create_search_bar("Search...", 200)}); auto history_body = create_body(); - manga_get_watch_history(plugin_name, history_body->items); - tabs.push_back(Tab{std::move(history_body), std::make_unique(this, tabs.front().page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + auto search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER); + auto history_page = std::make_unique(this, tabs.front().page.get(), search_bar.get(), HistoryType::MANGA); + tabs.push_back(Tab{std::move(history_body), std::move(history_page), std::move(search_bar)}); } else if(strcmp(plugin_name, "mangadex") == 0) { auto search_body = create_body(); tabs.push_back(Tab{std::move(search_body), std::make_unique(this), create_search_bar("Search...", 300)}); auto history_body = create_body(); - manga_get_watch_history(plugin_name, history_body->items); - tabs.push_back(Tab{std::move(history_body), std::make_unique(this, tabs.front().page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + auto search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER); + auto history_page = std::make_unique(this, tabs.front().page.get(), search_bar.get(), HistoryType::MANGA); + tabs.push_back(Tab{std::move(history_body), std::move(history_page), std::move(search_bar)}); } else if(strcmp(plugin_name, "nyaa.si") == 0) { auto category_page = std::make_unique(this); auto categories_body = create_body(); @@ -573,8 +596,9 @@ namespace QuickMedia { tabs.push_back(Tab{std::move(search_body), std::make_unique(this), create_search_bar("Search...", 350)}); auto history_body = create_body(); - youtube_get_watch_history(history_body->items); - tabs.push_back(Tab{std::move(history_body), std::make_unique(this, tabs.front().page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + auto search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER); + auto history_page = std::make_unique(this, tabs.front().page.get(), search_bar.get(), HistoryType::YOUTUBE); + tabs.push_back(Tab{std::move(history_body), std::move(history_page), std::move(search_bar)}); auto recommended_body = create_body(); fill_recommended_items_from_json(plugin_name, load_recommended_json(), recommended_body->items); @@ -890,7 +914,7 @@ namespace QuickMedia { } } - void Program::page_loop(std::vector &tabs) { + void Program::page_loop(std::vector &tabs, int start_tab_index, std::function after_submit_handler) { if(tabs.empty()) { show_notification("QuickMedia", "No tabs provided!", Urgency::CRITICAL); return; @@ -947,96 +971,106 @@ namespace QuickMedia { sf::Vertex gradient_points[4]; sf::Text tab_text("", *FontLoader::get_font(FontLoader::FontType::LATIN), tab_text_size); - int selected_tab = 0; + int selected_tab = std::min(std::max(0, start_tab_index), (int)tabs.size() - 1); bool loop_running = true; bool redraw = true; - auto submit_handler = [this, &json_chapters, &tabs, &selected_tab, &loop_running, &redraw]() { + auto window_size_u = window.getSize(); + window_size.x = window_size_u.x; + window_size.y = window_size_u.y; + + auto submit_handler = [this, &after_submit_handler, &json_chapters, &tabs, &selected_tab, &loop_running, &redraw]() { BodyItem *selected_item = tabs[selected_tab].body->get_selected(); if(!selected_item) return; std::vector new_tabs; PluginResult submit_result = tabs[selected_tab].page->submit(selected_item->get_title(), selected_item->url, new_tabs); - if(submit_result == PluginResult::OK) { - if(tabs[selected_tab].page->is_single_page()) { - tabs[selected_tab].search_bar->clear(); - if(new_tabs.size() == 1) - tabs[selected_tab].body = std::move(new_tabs[0].body); - else - loop_running = false; - return; - } + if(submit_result != PluginResult::OK) { + // TODO: Show the exact cause of error (get error message from curl). + show_notification("QuickMedia", std::string("Submit failed for page ") + tabs[selected_tab].page->get_title(), Urgency::CRITICAL); + return; + } - if(new_tabs.empty()) - return; + if(after_submit_handler) + after_submit_handler(); - for(Tab &tab : tabs) { - tab.body->clear_cache(); - } + if(tabs[selected_tab].page->is_single_page()) { + tabs[selected_tab].search_bar->clear(); + if(new_tabs.size() == 1) + tabs[selected_tab].body = std::move(new_tabs[0].body); + else + loop_running = false; + return; + } - if(new_tabs.size() == 1 && new_tabs[0].page->get_type() == PageTypez::MANGA_IMAGES) { - select_episode(selected_item, false); - Body *chapters_body = tabs[selected_tab].body.get(); - chapters_body->filter_search_fuzzy(""); // Needed (or not really) to go to the next chapter when reaching the last page of a chapter - MangaImagesPage *manga_images_page = static_cast(new_tabs[0].page.get()); - window.setKeyRepeatEnabled(false); - while(true) { - if(current_page == PageType::IMAGES) { - window.setFramerateLimit(20); - while(current_page == PageType::IMAGES) { - int page_navigation = image_page(manga_images_page, chapters_body); - if(page_navigation == -1) { - // TODO: Make this work if the list is sorted differently than from newest to oldest. - chapters_body->select_next_item(); - select_episode(chapters_body->get_selected(), true); - image_index = 99999; // Start at the page that shows we are at the end of the chapter - manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url); - } else if(page_navigation == 1) { - // TODO: Make this work if the list is sorted differently than from newest to oldest. - chapters_body->select_previous_item(); - select_episode(chapters_body->get_selected(), true); - manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url); - } + if(new_tabs.empty()) + return; + + for(Tab &tab : tabs) { + tab.body->clear_cache(); + } + + if(new_tabs.size() == 1 && new_tabs[0].page->get_type() == PageTypez::MANGA_IMAGES) { + select_episode(selected_item, false); + Body *chapters_body = tabs[selected_tab].body.get(); + chapters_body->filter_search_fuzzy(""); // Needed (or not really) to go to the next chapter when reaching the last page of a chapter + MangaImagesPage *manga_images_page = static_cast(new_tabs[0].page.get()); + window.setKeyRepeatEnabled(false); + while(true) { + if(current_page == PageType::IMAGES) { + window.setFramerateLimit(20); + while(current_page == PageType::IMAGES) { + int page_navigation = image_page(manga_images_page, chapters_body); + if(page_navigation == -1) { + // TODO: Make this work if the list is sorted differently than from newest to oldest. + chapters_body->select_next_item(); + select_episode(chapters_body->get_selected(), true); + image_index = 99999; // Start at the page that shows we are at the end of the chapter + manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url); + } else if(page_navigation == 1) { + // TODO: Make this work if the list is sorted differently than from newest to oldest. + chapters_body->select_previous_item(); + select_episode(chapters_body->get_selected(), true); + manga_images_page->change_chapter(chapters_body->get_selected()->get_title(), chapters_body->get_selected()->url); } - if(vsync_set) - window.setFramerateLimit(0); - else - window.setFramerateLimit(monitor_hz); - } else if(current_page == PageType::IMAGES_CONTINUOUS) { - image_continuous_page(manga_images_page); - } else { - break; } + if(vsync_set) + window.setFramerateLimit(0); + else + window.setFramerateLimit(monitor_hz); + } else if(current_page == PageType::IMAGES_CONTINUOUS) { + image_continuous_page(manga_images_page); + } else { + break; } - window.setKeyRepeatEnabled(true); - } else if(new_tabs.size() == 1 && new_tabs[0].page->get_type() == PageTypez::IMAGE_BOARD_THREAD) { - current_page = PageType::IMAGE_BOARD_THREAD; - image_board_thread_page(static_cast(new_tabs[0].page.get()), new_tabs[0].body.get()); - } else if(new_tabs.size() == 1 && new_tabs[0].page->get_type() == PageTypez::VIDEO) { - current_page = PageType::VIDEO_CONTENT; - video_content_page(new_tabs[0].page.get(), selected_item->url, selected_item->get_title(), false); - } else if(new_tabs.size() == 1 && new_tabs[0].page->get_type() == PageTypez::CHAT) { - current_page = PageType::CHAT; - current_chat_room = matrix->get_room_by_id(selected_item->url); - chat_page(static_cast(new_tabs[0].page.get()), current_chat_room); - select_body_item_by_room(tabs[selected_tab].body.get(), current_chat_room); - current_chat_room = nullptr; - } else { - page_loop(new_tabs); - } - tabs[selected_tab].page->on_navigate_to_page(tabs[selected_tab].body.get()); - if(content_storage_json.isObject()) { - const Json::Value &chapters_json = content_storage_json["chapters"]; - if(chapters_json.isObject()) - json_chapters = &chapters_json; } - redraw = true; + window.setKeyRepeatEnabled(true); + } else if(new_tabs.size() == 1 && new_tabs[0].page->get_type() == PageTypez::IMAGE_BOARD_THREAD) { + current_page = PageType::IMAGE_BOARD_THREAD; + image_board_thread_page(static_cast(new_tabs[0].page.get()), new_tabs[0].body.get()); + } else if(new_tabs.size() == 1 && new_tabs[0].page->get_type() == PageTypez::VIDEO) { + current_page = PageType::VIDEO_CONTENT; + video_content_page(static_cast(new_tabs[0].page.get()), selected_item->url, selected_item->get_title(), false); + } else if(new_tabs.size() == 1 && new_tabs[0].page->get_type() == PageTypez::CHAT) { + current_page = PageType::CHAT; + current_chat_room = matrix->get_room_by_id(selected_item->url); + chat_page(static_cast(new_tabs[0].page.get()), current_chat_room); + select_body_item_by_room(tabs[selected_tab].body.get(), current_chat_room); + current_chat_room = nullptr; } else { - // TODO: Show the exact cause of error (get error message from curl). - show_notification("QuickMedia", std::string("Submit failed for page ") + tabs[selected_tab].page->get_title(), Urgency::CRITICAL); + page_loop(new_tabs); + } + for(Tab &tab : tabs) { + tab.page->on_navigate_to_page(tab.body.get()); } + if(content_storage_json.isObject()) { + const Json::Value &chapters_json = content_storage_json["chapters"]; + if(chapters_json.isObject()) + json_chapters = &chapters_json; + } + redraw = true; }; for(size_t i = 0; i < tabs.size(); ++i) { @@ -1121,7 +1155,12 @@ namespace QuickMedia { hit_bottom = false; break; } - if(hit_bottom && tab_associated_data[selected_tab].fetch_status == FetchStatus::NONE && !tab_associated_data[selected_tab].fetching_next_page_running && tabs[selected_tab].page) { + if(hit_bottom + && tab_associated_data[selected_tab].fetch_status == FetchStatus::NONE + && !tab_associated_data[selected_tab].fetching_next_page_running + && tabs[selected_tab].page + && (!tabs[selected_tab].page->is_lazy_fetch_page() || tab_associated_data[selected_tab].lazy_fetch_finished)) + { gradient_inc = 0.0; tab_associated_data[selected_tab].fetching_next_page_running = true; int next_page = tab_associated_data[selected_tab].fetched_page + 1; @@ -1259,6 +1298,7 @@ namespace QuickMedia { associated_data.lazy_fetch_finished = true; FetchResult fetch_result = associated_data.fetch_future.get(); tabs[i].body->items = std::move(fetch_result.body_items); + tabs[i].body->filter_search_fuzzy(tabs[i].search_bar->get_text()); if(fetch_result.result != PluginResult::OK) associated_data.search_result_text.setString("Failed to fetch page!"); else if(tabs[i].body->items.empty()) @@ -1433,7 +1473,7 @@ namespace QuickMedia { return true; } - void Program::save_recommendations_from_related_videos(const std::string &video_url, const std::string &video_title, const Body *related_media_body) { + void Program::save_recommendations_from_related_videos(const std::string &video_url, const std::string &video_title, const BodyItems &related_media_body_items) { std::string video_id; if(!youtube_url_extract_id(video_url, video_id)) { std::string err_msg = "Failed to extract id of youtube url "; @@ -1465,7 +1505,7 @@ namespace QuickMedia { } int saved_recommendation_count = 0; - for(const auto &body_item : related_media_body->items) { + for(const auto &body_item : related_media_body_items) { std::string recommended_video_id; if(youtube_url_extract_id(body_item->url, recommended_video_id)) { Json::Value &existing_recommendation = recommended_json[recommended_video_id]; @@ -1514,6 +1554,10 @@ namespace QuickMedia { && (memcmp(&result[36], "moov", 4) != 0); } + const char* Program::get_plugin_name() const { + return plugin_name; + } + TaskResult Program::run_task_with_loading_screen(std::function callback) { assert(std::this_thread::get_id() == main_thread_id); @@ -1567,17 +1611,13 @@ namespace QuickMedia { #define CLEANMASK(mask) ((mask) & (ShiftMask|ControlMask|Mod1Mask|Mod4Mask|Mod5Mask)) - void Program::video_content_page(Page *page, std::string video_url, std::string video_title, bool download_if_streaming_fails) { + void Program::video_content_page(VideoPage *video_page, std::string video_url, std::string video_title, bool download_if_streaming_fails) { sf::Clock time_watched_timer; bool added_recommendations = false; bool video_loaded = false; PageType previous_page = pop_page_stack(); - sf::Sprite load_sprite(loading_icon); - sf::Vector2u loading_icon_size = loading_icon.getSize(); - load_sprite.setOrigin(loading_icon_size.x * 0.5f, loading_icon_size.y * 0.5f); - bool video_url_is_local = false; if(download_if_streaming_fails) { Path video_cache_dir = get_cache_dir().join("video"); @@ -1629,14 +1669,9 @@ namespace QuickMedia { time_watched_timer.restart(); std::unique_ptr video_player; - std::unique_ptr related_media_window; - sf::Vector2f related_media_window_size; - bool related_media_window_visible = false; - sf::Text related_videos_text("Related videos", *FontLoader::get_font(FontLoader::FontType::LATIN_BOLD), 20); - const float related_videos_text_height = related_videos_text.getCharacterSize(); - - auto related_media_body = create_body(); + BodyItems related_videos; + std::string channel_url; sf::WindowHandle video_player_window = None; auto on_window_create = [this, &video_player_window](sf::WindowHandle _video_player_window) mutable { @@ -1645,7 +1680,7 @@ namespace QuickMedia { XSync(disp, False); }; - auto load_video_error_check = [this, &related_media_body, &video_url, &video_title, &video_player, previous_page, &time_watched_timer, &video_loaded, &added_recommendations, page]() mutable { + auto load_video_error_check = [this, &related_videos, &channel_url, &video_url, &video_title, &video_player, previous_page, &time_watched_timer, &video_loaded, &added_recommendations, video_page]() mutable { time_watched_timer.restart(); video_loaded = false; added_recommendations = false; @@ -1657,9 +1692,9 @@ namespace QuickMedia { show_notification("QuickMedia", err_msg.c_str(), Urgency::CRITICAL); current_page = previous_page; } else { - related_media_body->clear_items(); - related_media_body->clear_thumbnails(); - related_media_body->items = page->get_related_media(video_url); + channel_url.clear(); + // TODO: Make async. What if the server is frozen? + related_videos = video_page->get_related_media(video_url, channel_url); // TODO: Make this also work for other video plugins if(strcmp(plugin_name, "youtube") != 0) @@ -1698,7 +1733,7 @@ namespace QuickMedia { }; bool has_video_started = true; - auto video_event_callback = [this, &related_media_body, &video_url, &video_title, &video_player, &load_video_error_check, previous_page, &has_video_started, &time_watched_timer, &video_loaded](const char *event_name) mutable { + auto video_event_callback = [this, &related_videos, &video_url, &video_title, &video_player, &load_video_error_check, previous_page, &has_video_started, &time_watched_timer, &video_loaded](const char *event_name) mutable { bool end_of_file = false; if(strcmp(event_name, "pause") == 0) { double time_remaining = 9999.0; @@ -1720,7 +1755,7 @@ namespace QuickMedia { std::string new_video_title; // Find video that hasn't been played before in this video session // TODO: Remove duplicates - for(auto it = related_media_body->items.begin(), end = related_media_body->items.end(); it != end; ++it) { + for(auto it = related_videos.begin(), end = related_videos.end(); it != end; ++it) { if(watched_videos.find((*it)->url) == watched_videos.end()) { new_video_url = (*it)->url; new_video_title = (*it)->get_title(); @@ -1776,62 +1811,20 @@ namespace QuickMedia { while (current_page == PageType::VIDEO_CONTENT && window.isOpen()) { while (window.pollEvent(event)) { - base_event_handler(event, previous_page, related_media_body.get(), nullptr, true, false); - if(event.type == sf::Event::Resized && related_media_window) { - related_media_window_size.x = window_size.x * RELATED_MEDIA_WINDOW_WIDTH; - related_media_window_size.y = window_size.y; - related_media_window->setSize(sf::Vector2u(related_media_window_size.x, related_media_window_size.y)); - related_media_window->setPosition(sf::Vector2i(window_size.x - related_media_window_size.x, 0)); - sf::FloatRect visible_area(0, 0, related_media_window_size.x, related_media_window_size.y); - related_media_window->setView(sf::View(visible_area)); - } - } - - while(related_media_window && related_media_window->pollEvent(event)) { - if(!related_media_window_visible) - continue; - if(event.type == sf::Event::KeyPressed) { - if(event.key.code == sf::Keyboard::Up) { - related_media_body->select_previous_item(); - } else if(event.key.code == sf::Keyboard::Down) { - related_media_body->select_next_item(); - } else if(event.key.code == sf::Keyboard::PageUp) { - related_media_body->select_previous_page(); - } else if(event.key.code == sf::Keyboard::PageDown) { - related_media_body->select_next_page(); - } else if(event.key.code == sf::Keyboard::Home) { - related_media_body->select_first_item(); - } else if(event.key.code == sf::Keyboard::End) { - related_media_body->select_last_item(); - } else if(event.key.code == sf::Keyboard::Escape) { - related_media_window_visible = false; - related_media_window->setVisible(false); - } else if(event.key.code == sf::Keyboard::R && event.key.control) { - related_media_window_visible = false; - related_media_window->setVisible(related_media_window_visible); - related_media_body->clear_cache(); - } else if(event.key.code == sf::Keyboard::F && event.key.control) { - window_set_fullscreen(disp, window.getSystemHandle(), WindowFullscreenState::TOGGLE); - fullscreen = !fullscreen; - } else if(event.key.code == sf::Keyboard::Enter) { - BodyItem *selected_item = related_media_body->get_selected(); - if(!selected_item) - continue; - - related_media_window_visible = false; - related_media_window->setVisible(false); - has_video_started = false; - - video_url = selected_item->url; - video_title = selected_item->get_title(); - load_video_error_check(); - } else if(event.key.code == sf::Keyboard::C && event.key.control) { - save_video_url_to_clipboard(); - } + if (event.type == sf::Event::Closed) { + current_page = PageType::EXIT; + window.close(); + } else if(event.type == sf::Event::Resized) { + window_size.x = event.size.width; + window_size.y = event.size.height; + sf::FloatRect visible_area(0, 0, window_size.x, window_size.y); + window.setView(sf::View(visible_area)); + } else if(event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) { + current_page = previous_page; } } - if(video_player_window && XCheckTypedWindowEvent(disp, video_player_window, KeyPress, &xev)/* && xev.xkey.subwindow == video_player_window*/ && !related_media_window_visible) { + if(video_player_window && XCheckTypedWindowEvent(disp, video_player_window, KeyPress, &xev)/* && xev.xkey.subwindow == video_player_window*/) { #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" KeySym pressed_keysym = XKeycodeToKeysym(disp, xev.xkey.keycode, 0); @@ -1842,26 +1835,47 @@ namespace QuickMedia { } else if(pressed_keysym == XK_f && pressing_ctrl) { window_set_fullscreen(disp, window.getSystemHandle(), WindowFullscreenState::TOGGLE); fullscreen = !fullscreen; - } else if(pressed_keysym == XK_r && pressing_ctrl && strcmp(plugin_name, "4chan") != 0) { - if(!related_media_window) { - related_media_window_size.x = window_size.x * RELATED_MEDIA_WINDOW_WIDTH; - related_media_window_size.y = window_size.y; - related_media_window = std::make_unique(sf::VideoMode(related_media_window_size.x, related_media_window_size.y), "", 0); - related_media_window->setFramerateLimit(0); - if(!enable_vsync(disp, related_media_window->getSystemHandle())) { - fprintf(stderr, "Failed to enable vsync, fallback to frame limiting\n"); - related_media_window->setFramerateLimit(monitor_hz); - } - related_media_window->setVisible(false); - XReparentWindow(disp, related_media_window->getSystemHandle(), video_player_window, window_size.x - related_media_window_size.x, 0); - XSync(disp, False); - } - - related_media_window_visible = true; - related_media_window->setVisible(related_media_window_visible); + } else if(pressed_keysym == XK_r && pressing_ctrl) { if(!cursor_visible) window.setMouseCursorVisible(true); cursor_visible = true; + + int search_delay = 0; + auto search_page = video_page->create_search_page(this, search_delay); + auto related_videos_page = video_page->create_related_videos_page(this, video_url, video_title); + auto channels_page = video_page->create_channels_page(this, channel_url); + if(search_page || related_videos_page || channels_page) { + XUnmapWindow(disp, video_player_window); + XSync(disp, False); + + std::vector tabs; + if(search_page) { + tabs.push_back(Tab{create_body(), std::move(search_page), create_search_bar("Search...", search_delay)}); + } + if(related_videos_page) { + auto related_videos_body = create_body(); + related_videos_body->items = related_videos; + 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...", SEARCH_DELAY_FILTER)}); + } + + bool page_changed = false; + page_loop(tabs, 1, [this, &video_player, &page_changed]() { + window.setMouseCursorVisible(true); + video_player.reset(); + page_changed = true; + }); + + if(page_changed) { + current_page = previous_page; + return; + } else { + XMapWindow(disp, video_player_window); + XSync(disp, False); + } + } } else if(pressed_keysym == XK_c && pressing_ctrl) { save_video_url_to_clipboard(); } @@ -1893,7 +1907,7 @@ namespace QuickMedia { if(!video_loaded) { window.clear(back_color); load_sprite.setPosition(window_size.x * 0.5f, window_size.y * 0.5f); - load_sprite.setRotation(time_watched_timer.getElapsedTime().asSeconds() * 400.0); + load_sprite.setRotation(load_sprite_timer.getElapsedTime().asSeconds() * 400.0); window.draw(load_sprite); window.display(); continue; @@ -1902,22 +1916,11 @@ namespace QuickMedia { /* Only save recommendations for the video if we have been watching it for 15 seconds */ if(is_youtube && video_loaded && !added_recommendations && time_watched_timer.getElapsedTime().asSeconds() >= 15) { added_recommendations = true; - save_recommendations_from_related_videos(video_url, video_title, related_media_body.get()); + save_recommendations_from_related_videos(video_url, video_title, related_videos); } +#if 0 if(video_player_window) { - if(related_media_window && related_media_window_visible) { - sf::Vector2f body_pos, body_size; - get_related_media_body_dimensions(window_size, body_pos, body_size, related_videos_text_height); - - related_media_window->clear(back_color); - related_videos_text.setPosition(body_pos.x, 10.0f); - related_media_window->draw(related_videos_text); - related_media_body->draw(*related_media_window, body_pos, body_size); - related_media_window->display(); - continue; - } - if(!cursor_visible) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); continue; @@ -1930,6 +1933,9 @@ namespace QuickMedia { } } std::this_thread::sleep_for(std::chrono::milliseconds(50)); + #endif + window.clear(back_color); + window.display(); } window.setMouseCursorVisible(true); diff --git a/src/plugins/ImageBoard.cpp b/src/plugins/ImageBoard.cpp index ac05f80..6f97082 100644 --- a/src/plugins/ImageBoard.cpp +++ b/src/plugins/ImageBoard.cpp @@ -1,7 +1,7 @@ #include "../../plugins/ImageBoard.hpp" namespace QuickMedia { - BodyItems ImageBoardThreadPage::get_related_media(const std::string &url) { + BodyItems ImageBoardThreadPage::get_related_media(const std::string &url, std::string&) { BodyItems body_items; auto it = std::find(cached_media_urls.begin(), cached_media_urls.end(), url); if(it == cached_media_urls.end()) @@ -16,6 +16,10 @@ namespace QuickMedia { return body_items; } + std::unique_ptr ImageBoardThreadPage::create_related_videos_page(Program*, const std::string&, const std::string&) { + return nullptr; + } + PluginResult ImageBoardThreadPage::login(const std::string &token, const std::string &pin, std::string &response_msg) { (void)token; (void)pin; diff --git a/src/plugins/Page.cpp b/src/plugins/Page.cpp index e444ecd..9e0e97a 100644 --- a/src/plugins/Page.cpp +++ b/src/plugins/Page.cpp @@ -3,11 +3,6 @@ #include namespace QuickMedia { - BodyItems Page::get_related_media(const std::string &url) { - (void)url; - return {}; - } - DownloadResult Page::download_json(Json::Value &result, const std::string &url, std::vector additional_args, bool use_browser_useragent, std::string *err_msg) { std::string server_response; if(download_to_string(url, server_response, std::move(additional_args), is_tor_enabled(), use_browser_useragent, err_msg == nullptr) != DownloadResult::OK) { diff --git a/src/plugins/Pornhub.cpp b/src/plugins/Pornhub.cpp index f527e76..1f0840e 100644 --- a/src/plugins/Pornhub.cpp +++ b/src/plugins/Pornhub.cpp @@ -138,16 +138,28 @@ namespace QuickMedia { return search_result_to_plugin_result(get_videos_in_page(url, is_tor_enabled(), result_items)); } - PluginResult PornhubSearchPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - (void)title; - (void)url; + PluginResult PornhubSearchPage::submit(const std::string&, const std::string&, std::vector &result_tabs) { result_tabs.push_back(Tab{nullptr, std::make_unique(program), nullptr}); return PluginResult::OK; } - BodyItems PornhubVideoPage::get_related_media(const std::string &url) { + PluginResult PornhubRelatedVideosPage::submit(const std::string&, const std::string&, std::vector &result_tabs) { + result_tabs.push_back(Tab{nullptr, std::make_unique(program), nullptr}); + return PluginResult::OK; + } + + BodyItems PornhubVideoPage::get_related_media(const std::string &url, std::string&) { BodyItems result_items; get_videos_in_page(url, is_tor_enabled(), result_items); return result_items; } + + std::unique_ptr PornhubVideoPage::create_search_page(Program *program, int &search_delay) { + search_delay = 500; + return std::make_unique(program); + } + + std::unique_ptr PornhubVideoPage::create_related_videos_page(Program *program, const std::string&, const std::string&) { + return std::make_unique(program); + } } \ No newline at end of file diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index 1ca25a3..2418073 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -647,9 +647,33 @@ namespace QuickMedia { return PluginResult::OK; } + PluginResult YoutubeChannelPage::lazy_fetch(BodyItems &result_items) { + std::vector additional_args = { + { "-H", "x-spf-referer: " + url }, + { "-H", "x-youtube-client-name: 1" }, + { "-H", "x-spf-previous: " + url }, + { "-H", "x-youtube-client-version: 2.20200626.03.00" }, + { "-H", "referer: " + url } + }; + + //std::vector cookies = get_cookies(); + //additional_args.insert(additional_args.end(), cookies.begin(), cookies.end()); + + Json::Value json_root; + DownloadResult result = download_json(json_root, url + "/videos?pbj=1", std::move(additional_args), true); + if(result != DownloadResult::OK) return download_result_to_plugin_result(result); + result_items = parse_channel_videos(json_root, continuation_token, added_videos); + return PluginResult::OK; + } + + PluginResult YoutubeRelatedVideosPage::submit(const std::string&, const std::string&, std::vector &result_tabs) { + result_tabs.push_back(Tab{nullptr, std::make_unique(program), nullptr}); + return PluginResult::OK; + } + // TODO: Make this faster by using string search instead of parsing html. // TODO: If the result is a play - BodyItems YoutubeVideoPage::get_related_media(const std::string &url) { + BodyItems YoutubeVideoPage::get_related_media(const std::string &url, std::string &channel_url) { BodyItems result_items; std::string modified_url = remove_index_from_playlist_url(url); @@ -677,6 +701,18 @@ namespace QuickMedia { if(!json_item.isObject()) continue; + if(channel_url.empty()) { + const Json::Value &player_response_json = json_item["playerResponse"]; + if(player_response_json.isObject()) { + const Json::Value &video_details_json = player_response_json["videoDetails"]; + if(video_details_json.isObject()) { + const Json::Value &channel_id_json = video_details_json["channelId"]; + if(channel_id_json.isString()) + channel_url = "https://www.youtube.com/channel/" + channel_id_json.asString(); + } + } + } + const Json::Value &response_json = json_item["response"]; if(!response_json.isObject()) continue; @@ -730,4 +766,17 @@ namespace QuickMedia { return result_items; } + + std::unique_ptr YoutubeVideoPage::create_search_page(Program *program, int &search_delay) { + search_delay = 350; + return std::make_unique(program); + } + + std::unique_ptr YoutubeVideoPage::create_related_videos_page(Program *program, const std::string&, const std::string&) { + return std::make_unique(program); + } + + std::unique_ptr YoutubeVideoPage::create_channels_page(Program *program, const std::string &channel_url) { + return std::make_unique(program, channel_url, "", "Channel videos"); + } } \ No newline at end of file -- cgit v1.2.3