From 27e748dec4792ac8612fb77e21a6d857a41a816c Mon Sep 17 00:00:00 2001 From: dec05eba Date: Sat, 3 Oct 2020 09:49:25 +0200 Subject: Nyaa.si: fetch next page when reaching the bottom --- TODO | 1 - plugins/NyaaSi.hpp | 3 ++ plugins/Plugin.hpp | 9 ++++ src/QuickMedia.cpp | 132 +++++++++++++++++++++++++++++++++++++++++-------- src/plugins/NyaaSi.cpp | 15 ++++-- 5 files changed, 135 insertions(+), 25 deletions(-) diff --git a/TODO b/TODO index 4a6ffab..177f7ab 100644 --- a/TODO +++ b/TODO @@ -17,7 +17,6 @@ Some text is not visible on 4chan, such as code blocks. Show indication when search is in progress (or when something is loading). Some sites such as youtube and mangadex are slow at searching. Add login page for mangadex instead of having to manually add remember_me token to config file. Allow deleting watch history with delete key (and show confirmation). -Add pagination to nyaa.si results. Add navigation to nyaa.si submitter torrents. Create a large texture and add downloaded images to it. This will save memory usage because sfml has to use power of two textures (and so does opengl internally) for textures, so if you have multiple textures they will use more memory than one large texture with the same texture data. Use fallback cjk font for regular sf::Text as well (search, tabs, chapter name when viewing a page, path in file-manager, etc). diff --git a/plugins/NyaaSi.hpp b/plugins/NyaaSi.hpp index 428d8b5..97b69e7 100644 --- a/plugins/NyaaSi.hpp +++ b/plugins/NyaaSi.hpp @@ -14,6 +14,7 @@ namespace QuickMedia { ~NyaaSi() override; PluginResult get_front_page(BodyItems &result_items) override; SearchResult content_list_search(const std::string &list_url, const std::string &text, BodyItems &result_items) override; + SearchResult content_list_search_page(const std::string &list_url, const std::string &text, int page, BodyItems &result_items) override; bool search_suggestions_has_thumbnails() const override { return true; } bool search_results_has_thumbnails() const override { return false; } int get_search_delay() const override { return 150; } @@ -22,5 +23,7 @@ namespace QuickMedia { bool content_list_search_is_filter() const override { return false; } PluginResult get_content_list(const std::string &url, BodyItems &result_items) override; PluginResult get_content_details(const std::string &list_url, const std::string &url, BodyItems &result_items) override; + private: + SearchResult search_page(const std::string &list_url, const std::string &text, int page, BodyItems &result_items); }; } \ No newline at end of file diff --git a/plugins/Plugin.hpp b/plugins/Plugin.hpp index d2caa67..2cc08cc 100644 --- a/plugins/Plugin.hpp +++ b/plugins/Plugin.hpp @@ -53,6 +53,15 @@ namespace QuickMedia { virtual SearchResult search(const std::string &text, BodyItems &result_items); virtual SuggestionResult update_search_suggestions(const std::string &text, BodyItems &result_items); virtual SearchResult content_list_search(const std::string &list_url, const std::string &text, BodyItems &result_items); + // TODO: Merge with above? + // page 0 is the first page + virtual SearchResult content_list_search_page(const std::string &list_url, const std::string &text, int page, BodyItems &result_items) { + (void)list_url; + (void)text; + (void)page; + (void)result_items; + return SearchResult::OK; + } virtual BodyItems get_related_media(const std::string &url); virtual PluginResult get_content_list(const std::string &url, BodyItems &result_items) { (void)url; diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 782506d..64955dd 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -153,6 +153,18 @@ static bool enable_vsync(Display *disp, Window window) { return false; } +static sf::Color interpolate_colors(sf::Color source, sf::Color target, double progress) { + int diff_r = (int)target.r - (int)source.r; + int diff_g = (int)target.g - (int)source.g; + int diff_b = (int)target.b - (int)source.b; + int diff_a = (int)target.a - (int)source.a; + return sf::Color( + source.r + diff_r * progress, + source.g + diff_g * progress, + source.b + diff_b * progress, + source.a + diff_a * progress); +} + namespace QuickMedia { Program::Program() : disp(nullptr), @@ -2381,16 +2393,70 @@ namespace QuickMedia { return true; }; + int fetched_page = 0; + bool fetching_next_page_running = false; + double gradient_inc = 0; + const float gradient_height = 5.0f; + sf::Vertex gradient_points[4]; + std::future next_page_future; + sf::Vector2f body_pos; sf::Vector2f body_size; bool redraw = true; sf::Event event; + sf::Clock frame_timer; while (current_page == Page::CONTENT_LIST) { + sf::Int32 frame_time_ms = frame_timer.restart().asMilliseconds(); + while (window.pollEvent(event)) { - base_event_handler(event, Page::SEARCH_SUGGESTION); - if(event.type == sf::Event::Resized || event.type == sf::Event::GainedFocus) + base_event_handler(event, Page::SEARCH_SUGGESTION, false); + if(event.type == sf::Event::Resized || event.type == sf::Event::GainedFocus) { redraw = true; + } else if(event.type == sf::Event::KeyPressed) { + if(event.key.code == sf::Keyboard::Down || event.key.code == sf::Keyboard::PageDown || event.key.code == sf::Keyboard::End) { + bool hit_bottom = false; + switch(event.key.code) { + case sf::Keyboard::Down: + hit_bottom = !body->select_next_item(); + break; + case sf::Keyboard::PageDown: + hit_bottom = !body->select_next_page(); + break; + case sf::Keyboard::End: + body->select_last_item(); + hit_bottom = true; + break; + default: + hit_bottom = false; + break; + } + if(hit_bottom && !search_running && !fetching_next_page_running) { + gradient_inc = 0; + fetching_next_page_running = true; + int next_page = fetched_page + 1; + std::string content_list_url_copy = content_list_url; + std::string update_search_text_copy = update_search_text; + next_page_future = std::async(std::launch::async, [this, content_list_url_copy, update_search_text_copy, next_page]() { + BodyItems result_items; + if(current_plugin->content_list_search_page(content_list_url_copy, update_search_text_copy, next_page, result_items) != SearchResult::OK) + fprintf(stderr, "Failed to get next content list page (page %d)\n", next_page); + return result_items; + }); + } + } else if(event.key.code == sf::Keyboard::Up) { + body->select_previous_item(); + } else if(event.key.code == sf::Keyboard::PageUp) { + body->select_previous_page(); + } else if(event.key.code == sf::Keyboard::Home) { + body->select_first_item(); + } else if(event.key.code == sf::Keyboard::Escape) { + current_page = Page::SEARCH_SUGGESTION; + body->clear_items(); + body->reset_selected(); + search_bar->clear(); + } + } } // TODO: This code is duplicated in many places. Handle it in one place. @@ -2398,19 +2464,32 @@ namespace QuickMedia { redraw = false; search_bar->onWindowResize(window_size); get_body_dimensions(window_size, search_bar.get(), body_pos, body_size); + + gradient_points[0].position.x = 0.0f; + gradient_points[0].position.y = window_size.y - gradient_height; + + gradient_points[1].position.x = window_size.x; + gradient_points[1].position.y = window_size.y - gradient_height; + + gradient_points[2].position.x = window_size.x; + gradient_points[2].position.y = window_size.y; + + gradient_points[3].position.x = 0.0f; + gradient_points[3].position.y = window_size.y; } search_bar->update(); - if(search_text_updated && !search_running) { - search_future = std::async(std::launch::async, [this, update_search_text]() { + if(search_text_updated && !fetching_next_page_running && !search_running) { + std::string search_term = update_search_text; + search_future = std::async(std::launch::async, [this, search_term]() { BodyItems result; - if(current_plugin->content_list_search(content_list_url, update_search_text, result) != SearchResult::OK) { - show_notification("Search", "Search failed!", Urgency::CRITICAL); + if(current_plugin->content_list_search(content_list_url, search_term, result) != SearchResult::OK) { + // TODO: Show this? + //show_notification("Search", "Search failed!", Urgency::CRITICAL); } return result; }); - update_search_text.clear(); search_text_updated = false; search_running = true; } @@ -2423,11 +2502,34 @@ namespace QuickMedia { search_future.get(); } search_running = false; + fetched_page = 0; + } + + if(fetching_next_page_running && next_page_future.valid() && next_page_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { + BodyItems new_body_items = next_page_future.get(); + fprintf(stderr, "Finished fetching page %d, num new messages: %zu\n", fetched_page + 1, new_body_items.size()); + size_t num_new_messages = new_body_items.size(); + if(num_new_messages > 0) { + body->append_items(std::move(new_body_items)); + fetched_page++; + } + fetching_next_page_running = false; } window.clear(back_color); search_bar->draw(window); body->draw(window, body_pos, body_size); + if(fetching_next_page_running) { + double progress = 0.5 + std::sin(std::fmod(gradient_inc, 360.0) * 0.017453292519943295 - 1.5707963267948966*0.5) * 0.5; + gradient_inc += (frame_time_ms * 0.5); + sf::Color bottom_color = interpolate_colors(back_color, sf::Color(175, 180, 188), progress); + + gradient_points[0].color = back_color; + gradient_points[1].color = back_color; + gradient_points[2].color = bottom_color; + gradient_points[3].color = bottom_color; + window.draw(gradient_points, 4, sf::Quads); // Note: sf::Quads doesn't work with egl + } window.display(); } @@ -3217,18 +3319,6 @@ namespace QuickMedia { sf::Text text; }; - static sf::Color interpolate_colors(sf::Color source, sf::Color target, double progress) { - int diff_r = (int)target.r - (int)source.r; - int diff_g = (int)target.g - (int)source.g; - int diff_b = (int)target.b - (int)source.b; - int diff_a = (int)target.a - (int)source.a; - return sf::Color( - source.r + diff_r * progress, - source.g + diff_g * progress, - source.b + diff_b * progress, - source.a + diff_a * progress); - } - static std::string extract_first_line(const std::string &str, size_t max_length) { size_t index = str.find('\n'); if(index == std::string::npos) { @@ -4078,8 +4168,8 @@ namespace QuickMedia { ++i; } - // TODO: Stop showing this when switching rooms, or have one for each room. Also add bottom one? for fetching new messages - if(fetching_previous_messages_running) { + // TODO: Have one for each room. Also add bottom one? for fetching new messages (currently not implemented, is it needed?) + if(fetching_previous_messages_running && tabs[selected_tab].type == ChatTabType::MESSAGES) { double progress = 0.5 + std::sin(std::fmod(gradient_inc, 360.0) * 0.017453292519943295 - 1.5707963267948966*0.5) * 0.5; gradient_inc += (frame_time_ms * 0.5); sf::Color top_color = interpolate_colors(back_color, sf::Color(175, 180, 188), progress); diff --git a/src/plugins/NyaaSi.cpp b/src/plugins/NyaaSi.cpp index 98c6eee..1cdfc5f 100644 --- a/src/plugins/NyaaSi.cpp +++ b/src/plugins/NyaaSi.cpp @@ -71,10 +71,19 @@ namespace QuickMedia { return PluginResult::OK; } + + SearchResult NyaaSi::content_list_search(const std::string &list_url, const std::string &text, BodyItems &result_items) { + return search_page(list_url, text, 1, result_items); + } + + SearchResult NyaaSi::content_list_search_page(const std::string &list_url, const std::string &text, int page, BodyItems &result_items) { + return search_page(list_url, text, 1 + page, result_items); + } + // TODO: Also show the number of comments for each torrent. TODO: Optimize? // TODO: Show each field as seperate columns instead of seperating by | - SearchResult NyaaSi::content_list_search(const std::string &list_url, const std::string &text, BodyItems &result_items) { - std::string full_url = "https://nyaa.si/?c=" + list_url + "&f=0&p=1&q="; + SearchResult NyaaSi::search_page(const std::string &list_url, const std::string &text, int page, BodyItems &result_items) { + std::string full_url = "https://nyaa.si/?c=" + list_url + "&f=0&p=" + std::to_string(page) + "&q="; full_url += url_param_encode(text); std::string website_data; @@ -218,7 +227,7 @@ namespace QuickMedia { } PluginResult NyaaSi::get_content_list(const std::string &url, BodyItems &result_items) { - return search_result_to_plugin_result(content_list_search(url, "", result_items)); + return search_result_to_plugin_result(search_page(url, "", 1, result_items)); } struct BodyItemImageContext { -- cgit v1.2.3