From 261b0263f34ffcbe439d68b2e901fd3abbfc1eaf Mon Sep 17 00:00:00 2001 From: dec05eba Date: Fri, 23 Oct 2020 07:26:39 +0200 Subject: Re-add creators page --- src/Body.cpp | 20 ++-- src/QuickMedia.cpp | 257 ++++++++++++++++++++++++-------------------- src/SearchBar.cpp | 25 +++-- src/plugins/FileManager.cpp | 1 - src/plugins/Fourchan.cpp | 2 - src/plugins/Manga.cpp | 6 ++ src/plugins/Mangadex.cpp | 13 +-- src/plugins/Manganelo.cpp | 159 +++++++++++++++++---------- src/plugins/Mangatown.cpp | 20 ++-- src/plugins/NyaaSi.cpp | 2 - 10 files changed, 285 insertions(+), 220 deletions(-) (limited to 'src') diff --git a/src/Body.cpp b/src/Body.cpp index ee32b08..20e7404 100644 --- a/src/Body.cpp +++ b/src/Body.cpp @@ -86,7 +86,7 @@ namespace QuickMedia { progress_text("", *font, 14), replies_text("", *font, 14), embedded_item_load_text("", *font, 14), - draw_thumbnails(false), + draw_thumbnails(true), wrap_around(false), line_separator_color(sf::Color(32, 37, 43, 255)), body_item_render_callback(nullptr), @@ -574,15 +574,15 @@ namespace QuickMedia { } // TODO: Better message? maybe fallback to the reply message, or message status (such as message redacted) - static const char* embedded_item_status_to_string(EmbeddedItemStatus embedded_item_status) { + static const char* embedded_item_status_to_string(FetchStatus embedded_item_status) { switch(embedded_item_status) { - case EmbeddedItemStatus::NONE: + case FetchStatus::NONE: return ""; - case EmbeddedItemStatus::LOADING: + case FetchStatus::LOADING: return "Loading message..."; - case EmbeddedItemStatus::FINISHED_LOADING: + case FetchStatus::FINISHED_LOADING: return "Finished loading message..."; - case EmbeddedItemStatus::FAILED_TO_LOAD: + case FetchStatus::FAILED_TO_LOAD: return "Failed to load message!"; } return ""; @@ -591,7 +591,7 @@ namespace QuickMedia { void Body::draw_item(sf::RenderWindow &window, BodyItem *item, const sf::Vector2f &pos, const sf::Vector2f &size, const float item_height, const int item_index, const Json::Value &content_progress, bool include_embedded_item) { // TODO: Instead of generating a new hash everytime to access textures, cache the hash of the thumbnail url std::shared_ptr item_thumbnail; - if(draw_thumbnails) { + if(draw_thumbnails && !item->thumbnail_url.empty()) { auto item_thumbnail_it = item_thumbnail_textures.find(item->thumbnail_url); if(item_thumbnail_it == item_thumbnail_textures.end()) { item_thumbnail = std::make_shared(); @@ -620,7 +620,7 @@ namespace QuickMedia { } float text_offset_x = padding_x; - if(draw_thumbnails) { + if(draw_thumbnails && !item->thumbnail_url.empty()) { double elapsed_time_thumbnail = 0.0; if(item_thumbnail->loading_state == LoadingState::APPLIED_TO_TEXTURE) elapsed_time_thumbnail = item_thumbnail->texture_applied_time.getElapsedTime().asSeconds(); //thumbnail_fade_duration_sec @@ -707,7 +707,7 @@ namespace QuickMedia { item_pos.y += item->author_text->getHeight() - 2.0f; } - if(include_embedded_item && item->embedded_item_status != EmbeddedItemStatus::NONE) { + if(include_embedded_item && item->embedded_item_status != FetchStatus::NONE) { float embedded_item_height = item->embedded_item ? get_item_height(item->embedded_item.get(), true, false) : (embedded_item_load_text.getLocalBounds().height + embedded_item_padding_y * 2.0f); const float border_width = 4.0f; sf::RectangleShape border_left(sf::Vector2f(border_width, std::floor(embedded_item_height))); @@ -776,7 +776,7 @@ namespace QuickMedia { if(item->author_text) { item_height += item->author_text->getHeight() - 2.0f; } - if(include_embedded_item && item->embedded_item_status != EmbeddedItemStatus::NONE) { + if(include_embedded_item && item->embedded_item_status != FetchStatus::NONE) { if(item->embedded_item) item_height += (get_item_height(item->embedded_item.get(), load_texture, false) + 4.0f + embedded_item_padding_y * 2.0f); else diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 046ba9d..c9950a0 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -40,7 +40,7 @@ static const sf::Color back_color(21, 25, 30); static const std::string fourchan_google_captcha_api_key = "6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc"; -static const float tab_text_size = 18.0f; +static const float tab_text_size = 16.0f; static const float tab_height = tab_text_size + 10.0f; static const sf::Color tab_selected_color(55, 60, 68); static const float tab_margin_x = 10.0f; @@ -188,6 +188,11 @@ namespace QuickMedia { Page *search_page; }; + template + static bool is_future_ready(const std::future &future) { + return future.valid() && future.wait_for(std::chrono::seconds(0)) == std::future_status::ready; + } + static Path get_recommended_filepath(const char *plugin_name) { Path video_history_dir = get_storage_dir().join("recommended"); if(create_directory_recursive(video_history_dir) != 0) { @@ -555,7 +560,6 @@ namespace QuickMedia { if(strcmp(plugin_name, "manganelo") == 0) { auto search_body = create_body(); - search_body->draw_thumbnails = true; tabs.push_back(Tab{std::move(search_body), std::make_unique(this), create_search_bar("Search...", 200)}); auto history_body = create_body(); @@ -563,7 +567,6 @@ namespace QuickMedia { tabs.push_back(Tab{std::move(history_body), std::make_unique(this, tabs.front().page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } else if(strcmp(plugin_name, "mangatown") == 0) { auto search_body = create_body(); - search_body->draw_thumbnails = true; tabs.push_back(Tab{std::move(search_body), std::make_unique(this), create_search_bar("Search...", 200)}); auto history_body = create_body(); @@ -571,7 +574,6 @@ namespace QuickMedia { tabs.push_back(Tab{std::move(history_body), std::make_unique(this, tabs.front().page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } else if(strcmp(plugin_name, "mangadex") == 0) { auto search_body = create_body(); - search_body->draw_thumbnails = true; tabs.push_back(Tab{std::move(search_body), std::make_unique(this), create_search_bar("Search...", 300)}); auto history_body = create_body(); @@ -598,21 +600,17 @@ namespace QuickMedia { tabs.push_back(Tab{std::move(file_manager_body), std::move(file_manager_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } else if(strcmp(plugin_name, "youtube") == 0) { auto search_body = create_body(); - search_body->draw_thumbnails = true; tabs.push_back(Tab{std::move(search_body), std::make_unique(this), create_search_bar("Search...", 350)}); auto history_body = create_body(); - history_body->draw_thumbnails = true; 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 recommended_body = create_body(); - recommended_body->draw_thumbnails = true; fill_recommended_items_from_json(plugin_name, load_recommended_json(), recommended_body->items); tabs.push_back(Tab{std::move(recommended_body), std::make_unique(this, tabs.front().page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } else if(strcmp(plugin_name, "pornhub") == 0) { auto search_body = create_body(); - search_body->draw_thumbnails = true; tabs.push_back(Tab{std::move(search_body), std::make_unique(this), create_search_bar("Search...", 500)}); } @@ -928,6 +926,7 @@ namespace QuickMedia { for(Tab &tab : tabs) { tab.body->thumbnail_max_size = tab.page->get_thumbnail_max_size(); + tab.page->on_navigate_to_page(); } const Json::Value *json_chapters = &Json::Value::nullSingleton(); @@ -937,15 +936,27 @@ namespace QuickMedia { json_chapters = &chapters_json; } + enum class FetchType { + SEARCH, + LAZY + }; + + struct FetchResult { + BodyItems body_items; + PluginResult result; + }; + struct TabAssociatedData { std::string update_search_text; bool search_text_updated = false; - bool search_running = false; + FetchStatus fetch_status = FetchStatus::NONE; + bool lazy_fetch_finished = false; + FetchType fetch_type; bool typing = false; bool fetching_next_page_running = false; int fetched_page = 0; sf::Text search_result_text; - std::future search_future; + std::future fetch_future; std::future next_page_future; }; @@ -969,7 +980,7 @@ namespace QuickMedia { bool loop_running = true; bool redraw = true; - auto submit_handler = [this, &tabs, &selected_tab, &loop_running, &redraw]() { + auto submit_handler = [this, &json_chapters, &tabs, &selected_tab, &loop_running, &redraw]() { BodyItem *selected_item = tabs[selected_tab].body->get_selected(); if(!selected_item) return; @@ -1039,6 +1050,10 @@ namespace QuickMedia { redraw = true; } else { page_loop(std::move(new_tabs)); + tabs[selected_tab].page->on_navigate_to_page(); + const Json::Value &chapters_json = content_storage_json["chapters"]; + if(chapters_json.isObject()) + json_chapters = &chapters_json; } } else { // TODO: Show the exact cause of error (get error message from curl). @@ -1093,6 +1108,8 @@ namespace QuickMedia { while (window.isOpen() && loop_running) { sf::Int32 frame_time_ms = frame_timer.restart().asMilliseconds(); + Tab ¤t_tab = tabs[selected_tab]; + TabAssociatedData ¤t_tab_associated_data = tab_associated_data[selected_tab]; while (window.pollEvent(event)) { if (event.type == sf::Event::Closed) { @@ -1104,10 +1121,10 @@ namespace QuickMedia { window.setView(sf::View(visible_area)); } - if(tabs[selected_tab].search_bar) { + if(current_tab.search_bar) { if(event.type == sf::Event::TextEntered) - tabs[selected_tab].search_bar->onTextEntered(event.text.unicode); - tabs[selected_tab].search_bar->on_event(event); + current_tab.search_bar->onTextEntered(event.text.unicode); + current_tab.search_bar->on_event(event); } if(event.type == sf::Event::Resized || event.type == sf::Event::GainedFocus) @@ -1117,26 +1134,26 @@ namespace QuickMedia { bool hit_bottom = false; switch(event.key.code) { case sf::Keyboard::Down: - hit_bottom = !tabs[selected_tab].body->select_next_item(); + hit_bottom = !current_tab.body->select_next_item(); break; case sf::Keyboard::PageDown: - hit_bottom = !tabs[selected_tab].body->select_next_page(); + hit_bottom = !current_tab.body->select_next_page(); break; case sf::Keyboard::End: - tabs[selected_tab].body->select_last_item(); + current_tab.body->select_last_item(); hit_bottom = true; break; default: hit_bottom = false; break; } - if(hit_bottom && !tab_associated_data[selected_tab].search_running && !tab_associated_data[selected_tab].fetching_next_page_running && tabs[selected_tab].page) { + if(hit_bottom && current_tab_associated_data.fetch_status == FetchStatus::NONE && !current_tab_associated_data.fetching_next_page_running && current_tab.page) { 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; - Page *page = tabs[selected_tab].page.get(); - std::string update_search_text = tab_associated_data[selected_tab].update_search_text; - tab_associated_data[selected_tab].next_page_future = std::async(std::launch::async, [update_search_text, next_page, page]() { + current_tab_associated_data.fetching_next_page_running = true; + int next_page = current_tab_associated_data.fetched_page + 1; + Page *page = current_tab.page.get(); + std::string update_search_text = current_tab_associated_data.update_search_text; + current_tab_associated_data.next_page_future = std::async(std::launch::async, [update_search_text, next_page, page]() { BodyItems result_items; if(page->get_page(update_search_text, next_page, result_items) != PluginResult::OK) fprintf(stderr, "Failed to get next page (page %d)\n", next_page); @@ -1144,33 +1161,33 @@ namespace QuickMedia { }); } } else if(event.key.code == sf::Keyboard::Up) { - tabs[selected_tab].body->select_previous_item(); + current_tab.body->select_previous_item(); } else if(event.key.code == sf::Keyboard::PageUp) { - tabs[selected_tab].body->select_previous_page(); + current_tab.body->select_previous_page(); } else if(event.key.code == sf::Keyboard::Home) { - tabs[selected_tab].body->select_first_item(); + current_tab.body->select_first_item(); } else if(event.key.code == sf::Keyboard::Escape) { goto page_end; } else if(event.key.code == sf::Keyboard::Left) { if(selected_tab > 0) { - tabs[selected_tab].body->clear_cache(); + current_tab.body->clear_cache(); --selected_tab; redraw = true; } } else if(event.key.code == sf::Keyboard::Right) { if(selected_tab < (int)tabs.size() - 1) { - tabs[selected_tab].body->clear_cache(); + current_tab.body->clear_cache(); ++selected_tab; redraw = true; } } else if(event.key.code == sf::Keyboard::Tab) { - if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->set_to_autocomplete(); + if(current_tab.search_bar) current_tab.search_bar->set_to_autocomplete(); } else if(event.key.code == sf::Keyboard::Enter) { - if(!tabs[selected_tab].search_bar) submit_handler(); + if(!current_tab.search_bar) submit_handler(); } else if(event.key.code == sf::Keyboard::T && event.key.control) { - BodyItem *selected_item = tabs[selected_tab].body->get_selected(); - if(selected_item && tabs[selected_tab].page && tabs[selected_tab].page->is_trackable()) { - TrackablePage *trackable_page = static_cast(tabs[selected_tab].page.get()); + BodyItem *selected_item = current_tab.body->get_selected(); + if(selected_item && current_tab.page && current_tab.page->is_trackable()) { + TrackablePage *trackable_page = static_cast(current_tab.page.get()); TrackResult track_result = trackable_page->track(selected_item->get_title()); // TODO: Show proper error message when this fails. For example if we are already tracking the manga if(track_result == TrackResult::OK) { @@ -1185,9 +1202,9 @@ namespace QuickMedia { if(redraw) { redraw = false; - if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->onWindowResize(window_size); + if(current_tab.search_bar) current_tab.search_bar->onWindowResize(window_size); // TODO: Dont show tabs if there is only one tab - get_body_dimensions(window_size, tabs[selected_tab].search_bar.get(), body_pos, body_size, true); + get_body_dimensions(window_size, current_tab.search_bar.get(), body_pos, body_size, true); gradient_points[0].position.x = 0.0f; gradient_points[0].position.y = window_size.y - gradient_height; @@ -1202,12 +1219,24 @@ namespace QuickMedia { gradient_points[3].position.y = window_size.y; } - if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->update(); + if(current_tab.search_bar) current_tab.search_bar->update(); + + if(current_tab.page->is_lazy_fetch_page() && current_tab_associated_data.fetch_status == FetchStatus::NONE && !current_tab_associated_data.lazy_fetch_finished) { + current_tab_associated_data.fetch_status = FetchStatus::LOADING; + current_tab_associated_data.fetch_type = FetchType::LAZY; + current_tab_associated_data.search_result_text.setString("Fetching page..."); + LazyFetchPage *lazy_fetch_page = static_cast(current_tab.page.get()); + current_tab_associated_data.fetch_future = std::async(std::launch::async, [lazy_fetch_page]() { + FetchResult fetch_result; + fetch_result.result = lazy_fetch_page->lazy_fetch(fetch_result.body_items); + return fetch_result; + }); + } for(size_t i = 0; i < tabs.size(); ++i) { TabAssociatedData &associated_data = tab_associated_data[i]; - if(associated_data.fetching_next_page_running && associated_data.next_page_future.valid() && associated_data.next_page_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { + if(associated_data.fetching_next_page_running && is_future_ready(associated_data.next_page_future)) { BodyItems new_body_items = associated_data.next_page_future.get(); fprintf(stderr, "Finished fetching page %d, num new messages: %zu\n", associated_data.fetched_page + 1, new_body_items.size()); size_t num_new_messages = new_body_items.size(); @@ -1218,65 +1247,66 @@ namespace QuickMedia { associated_data.fetching_next_page_running = false; } - if(associated_data.search_text_updated && !associated_data.search_running && !associated_data.fetching_next_page_running) { - Page *page = tabs[i].page.get(); + if(associated_data.search_text_updated && associated_data.fetch_status == FetchStatus::NONE && !associated_data.fetching_next_page_running) { std::string update_search_text = associated_data.update_search_text; - associated_data.search_future = std::async(std::launch::async, [update_search_text, page]() { - BodyItems result_items; - if(page->search(update_search_text, result_items) != SearchResult::OK) { - show_notification("QuickMedia", "Search failed!", Urgency::CRITICAL); - } - return result_items; - }); - update_search_text.clear(); + associated_data.update_search_text.clear(); associated_data.search_text_updated = false; - associated_data.search_running = true; + associated_data.fetch_status = FetchStatus::LOADING; + associated_data.fetch_type = FetchType::SEARCH; associated_data.search_result_text.setString("Searching..."); + Page *page = tabs[i].page.get(); + associated_data.fetch_future = std::async(std::launch::async, [update_search_text, page]() { + FetchResult fetch_result; + fetch_result.result = search_result_to_plugin_result(page->search(update_search_text, fetch_result.body_items)); + return fetch_result; + }); } - if(associated_data.search_running && associated_data.search_future.valid() && associated_data.search_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { + if(associated_data.fetch_status == FetchStatus::LOADING && associated_data.fetch_type == FetchType::SEARCH && is_future_ready(associated_data.fetch_future)) { if(!associated_data.search_text_updated) { - BodyItems result_items = associated_data.search_future.get(); - tabs[i].body->items = std::move(result_items); + FetchResult fetch_result = associated_data.fetch_future.get(); + tabs[i].body->items = std::move(fetch_result.body_items); tabs[i].body->select_first_item(); associated_data.fetched_page = 0; - if(tabs[i].body->items.empty()) + if(fetch_result.result != PluginResult::OK) + associated_data.search_result_text.setString("Search failed!"); + else if(tabs[i].body->items.empty()) associated_data.search_result_text.setString("No results found"); else associated_data.search_result_text.setString(""); } else { - associated_data.search_future.get(); + associated_data.fetch_future.get(); } - associated_data.search_running = false; + associated_data.fetch_status = FetchStatus::NONE; } - } - - // if(!autocomplete_text.empty() && !autocomplete_running) { - // autocomplete_future = std::async(std::launch::async, [this, autocomplete_text]() { - // return current_plugin->autocomplete_search(autocomplete_text); - // }); - // autocomplete_text.clear(); - // autocomplete_running = true; - // } - // if(autocomplete_running && autocomplete_future.valid() && autocomplete_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { - // if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->set_autocomplete_text(autocomplete_future.get()); - // autocomplete_running = false; - // } + if(associated_data.fetch_status == FetchStatus::LOADING && associated_data.fetch_type == FetchType::LAZY && is_future_ready(associated_data.fetch_future)) { + associated_data.lazy_fetch_finished = true; + FetchResult fetch_result = associated_data.fetch_future.get(); + tabs[i].body->items = std::move(fetch_result.body_items); + if(fetch_result.result != PluginResult::OK) + associated_data.search_result_text.setString("Failed to fetch page!"); + else if(tabs[i].body->items.empty()) + associated_data.search_result_text.setString("No results found"); + else + associated_data.search_result_text.setString(""); + associated_data.fetch_status = FetchStatus::NONE; + } + } window.clear(back_color); - if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->draw(window, false); + if(current_tab.search_bar) current_tab.search_bar->draw(window, false); { float shade_extra_height = 0.0f; - if(!tabs[selected_tab].search_bar) + if(!current_tab.search_bar) shade_extra_height = 10.0f; const float width_per_tab = window_size.x / tabs.size(); tab_background.setSize(sf::Vector2f(std::floor(width_per_tab - tab_margin_x * 2.0f), tab_height)); - float tab_vertical_offset = tabs[selected_tab].search_bar ? tabs[selected_tab].search_bar->getBottomWithoutShadow() : 0.0f; - tabs[selected_tab].body->draw(window, body_pos, body_size, *json_chapters); + float tab_vertical_offset = current_tab.search_bar ? current_tab.search_bar->getBottomWithoutShadow() : 0.0f; + current_tab.body->draw(window, body_pos, body_size, *json_chapters); const float tab_y = tab_spacer_height + std::floor(tab_vertical_offset + tab_height * 0.5f - (tab_text_size + 5.0f) * 0.5f) + shade_extra_height; tab_shade.setPosition(0.0f, tab_spacer_height + std::floor(tab_vertical_offset)); @@ -1299,7 +1329,7 @@ namespace QuickMedia { } } - if(tab_associated_data[selected_tab].fetching_next_page_running) { + if(current_tab_associated_data.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); @@ -1311,12 +1341,12 @@ namespace QuickMedia { window.draw(gradient_points, 4, sf::Quads); // Note: sf::Quads doesn't work with egl } - if(!tab_associated_data[selected_tab].search_result_text.getString().isEmpty()) { - auto search_result_text_bounds = tab_associated_data[selected_tab].search_result_text.getLocalBounds(); - tab_associated_data[selected_tab].search_result_text.setPosition( + if(!current_tab_associated_data.search_result_text.getString().isEmpty()) { + auto search_result_text_bounds = current_tab_associated_data.search_result_text.getLocalBounds(); + current_tab_associated_data.search_result_text.setPosition( std::floor(body_pos.x + body_size.x * 0.5f - search_result_text_bounds.width * 0.5f), std::floor(body_pos.y + body_size.y * 0.5f - search_result_text_bounds.height * 0.5f)); - window.draw(tab_associated_data[selected_tab].search_result_text); + window.draw(current_tab_associated_data.search_result_text); } window.display(); @@ -1328,8 +1358,8 @@ namespace QuickMedia { for(TabAssociatedData &associated_data : tab_associated_data) { if(associated_data.next_page_future.valid()) associated_data.next_page_future.get(); - if(associated_data.search_future.valid()) - associated_data.search_future.get(); + if(associated_data.fetch_future.valid()) + associated_data.fetch_future.get(); } } @@ -1491,7 +1521,6 @@ namespace QuickMedia { const float related_videos_text_height = related_videos_text.getCharacterSize(); auto related_media_body = create_body(); - related_media_body->draw_thumbnails = true; sf::WindowHandle video_player_window = None; auto on_window_create = [this, &video_player_window](sf::WindowHandle _video_player_window) mutable { @@ -2440,12 +2469,14 @@ namespace QuickMedia { comment_input_shade.setFillColor(sf::Color(33, 38, 44)); sf::Sprite logo_sprite(plugin_logo); + logo_sprite.setScale(0.8f, 0.8f); + sf::Vector2f logo_size(plugin_logo.getSize().x * logo_sprite.getScale().x, plugin_logo.getSize().y * logo_sprite.getScale().y); float prev_chat_height = comment_input.get_height(); float chat_input_height_full = 0.0f; const float logo_padding_x = 15.0f; - const float chat_input_padding_x = 15.0f; - const float chat_input_padding_y = 15.0f; + const float chat_input_padding_x = 10.0f; + const float chat_input_padding_y = 10.0f; sf::Vector2f body_pos; sf::Vector2f body_size; @@ -2641,8 +2672,8 @@ namespace QuickMedia { redraw = false; comment_input.set_max_width(window_size.x); - comment_input.set_max_width(window_size.x - (logo_padding_x + plugin_logo.getSize().x + chat_input_padding_x * 2.0f)); - comment_input.set_position(sf::Vector2f(logo_padding_x + plugin_logo.getSize().x + chat_input_padding_x, chat_input_padding_y)); + comment_input.set_max_width(window_size.x - (logo_padding_x + logo_size.x + chat_input_padding_x + logo_padding_x)); + comment_input.set_position(sf::Vector2f(std::floor(logo_padding_x + logo_size.x + chat_input_padding_x), chat_input_padding_y)); float body_padding_horizontal = 25.0f; float body_padding_vertical = 5.0f; @@ -2658,7 +2689,7 @@ namespace QuickMedia { body_pos = sf::Vector2f(body_padding_horizontal, comment_input_shade.getSize().y + body_padding_vertical); body_size = sf::Vector2f(body_width, window_size.y - comment_input_shade.getSize().y - body_padding_vertical); - logo_sprite.setPosition(logo_padding_x, comment_input_shade.getSize().y * 0.5f - plugin_logo.getSize().y * 0.5f); + logo_sprite.setPosition(logo_padding_x, std::floor(comment_input_shade.getSize().y * 0.5f - logo_size.y * 0.5f)); } //comment_input.update(); @@ -2702,7 +2733,7 @@ namespace QuickMedia { } else if(navigation_stage == NavigationStage::VIEWING_ATTACHED_IMAGE) { // TODO: Use image instead of data with string. texture->loadFromMemory creates a temporary image anyways that parses the string. std::string image_data; - if(downloading_image && load_image_future.valid() && load_image_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { + if(downloading_image && is_future_ready(load_image_future)) { downloading_image = false; image_data = load_image_future.get(); @@ -2932,16 +2963,9 @@ namespace QuickMedia { return result_items; } - enum class PinnedEventStatus { - NONE, - LOADING, - FINISHED_LOADING, - FAILED_TO_LOAD - }; - struct PinnedEventData { std::string event_id; - PinnedEventStatus status = PinnedEventStatus::NONE; + FetchStatus status = FetchStatus::NONE; }; void Program::chat_page() { @@ -2953,7 +2977,6 @@ namespace QuickMedia { ChatTab pinned_tab; pinned_tab.body = std::make_unique(this, font.get(), bold_font.get(), cjk_font.get(), loading_icon); - pinned_tab.body->draw_thumbnails = true; pinned_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE; pinned_tab.body->thumbnail_mask_shader = &circle_mask_shader; //pinned_tab.body->line_separator_color = sf::Color::Transparent; @@ -2962,7 +2985,6 @@ namespace QuickMedia { ChatTab messages_tab; messages_tab.body = std::make_unique(this, font.get(), bold_font.get(), cjk_font.get(), loading_icon); - messages_tab.body->draw_thumbnails = true; messages_tab.body->thumbnail_max_size = CHAT_MESSAGE_THUMBNAIL_MAX_SIZE; messages_tab.body->thumbnail_mask_shader = &circle_mask_shader; //messages_tab.body->line_separator_color = sf::Color::Transparent; @@ -2971,7 +2993,6 @@ namespace QuickMedia { ChatTab rooms_tab; rooms_tab.body = std::make_unique(this, font.get(), bold_font.get(), cjk_font.get(), loading_icon); - rooms_tab.body->draw_thumbnails = true; //rooms_tab.body->line_separator_color = sf::Color::Transparent; rooms_tab.body->thumbnail_mask_shader = &circle_mask_shader; rooms_tab.text = sf::Text("Rooms", *font, tab_text_size); @@ -3106,6 +3127,8 @@ namespace QuickMedia { sf::Text replying_to_text("Replying to:", *font, 18); sf::Sprite logo_sprite(plugin_logo); + logo_sprite.setScale(0.8f, 0.8f); + sf::Vector2f logo_size(plugin_logo.getSize().x * logo_sprite.getScale().x, plugin_logo.getSize().y * logo_sprite.getScale().y); sf::Text room_name_text("", *bold_font, 18); const float room_name_text_height = 20.0f; @@ -3141,7 +3164,7 @@ namespace QuickMedia { auto set_body_as_deleted = [](Message *message, BodyItem *body_item) { body_item->embedded_item = nullptr; - body_item->embedded_item_status = EmbeddedItemStatus::NONE; + body_item->embedded_item_status = FetchStatus::NONE; body_item->thumbnail_url = message->user->avatar_url; body_item->thumbnail_mask_type = ThumbnailMaskType::CIRCLE; body_item->set_description_color(sf::Color::White); @@ -3196,7 +3219,7 @@ namespace QuickMedia { body->set_description("Loading message..."); PinnedEventData *event_data = new PinnedEventData(); event_data->event_id = event; - event_data->status = PinnedEventStatus::NONE; + event_data->status = FetchStatus::NONE; body->userdata = event_data; tabs[PINNED_TAB_INDEX].body->items.push_back(std::move(body)); } @@ -3346,14 +3369,14 @@ namespace QuickMedia { return; PinnedEventData *event_data = static_cast(body_item->userdata); - if(!event_data || event_data->status != PinnedEventStatus::NONE) + if(!event_data || event_data->status != FetchStatus::NONE) return; // Check if we already have the referenced message as a body item in the messages list, so we dont create a new one auto related_body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size(), event_data->event_id); if(related_body_item) { *body_item = *related_body_item; - event_data->status = PinnedEventStatus::FINISHED_LOADING; + event_data->status = FetchStatus::FINISHED_LOADING; body_item->userdata = event_data; return; } @@ -3362,7 +3385,7 @@ namespace QuickMedia { std::string message_event_id = event_data->event_id; fetch_future_room = current_room; fetch_body_item = body_item; - body_item->embedded_item_status = EmbeddedItemStatus::LOADING; + body_item->embedded_item_status = FetchStatus::LOADING; fetch_message_tab = PINNED_TAB_INDEX; // TODO: Check if the message is already cached before calling async? is this needed? is async creation expensive? fetch_message_future = std::async(std::launch::async, [this, &fetch_future_room, message_event_id]() { @@ -3378,14 +3401,14 @@ namespace QuickMedia { Message *message = static_cast(body_item->userdata); assert(message); - if(message->related_event_id.empty() || body_item->embedded_item_status != EmbeddedItemStatus::NONE) + if(message->related_event_id.empty() || body_item->embedded_item_status != FetchStatus::NONE) return; // Check if we already have the referenced message as a body item, so we dont create a new one auto related_body_item = find_body_item_by_event_id(tabs[MESSAGES_TAB_INDEX].body->items.data(), tabs[MESSAGES_TAB_INDEX].body->items.size(), message->related_event_id); if(related_body_item) { body_item->embedded_item = related_body_item; - body_item->embedded_item_status = EmbeddedItemStatus::FINISHED_LOADING; + body_item->embedded_item_status = FetchStatus::FINISHED_LOADING; return; } @@ -3393,7 +3416,7 @@ namespace QuickMedia { std::string message_event_id = message->related_event_id; fetch_future_room = current_room; fetch_body_item = body_item; - body_item->embedded_item_status = EmbeddedItemStatus::LOADING; + body_item->embedded_item_status = FetchStatus::LOADING; fetch_message_tab = MESSAGES_TAB_INDEX; // TODO: Check if the message is already cached before calling async? is this needed? is async creation expensive? fetch_message_future = std::async(std::launch::async, [this, &fetch_future_room, message_event_id]() { @@ -3442,8 +3465,8 @@ namespace QuickMedia { float prev_chat_height = chat_input.get_height(); float chat_input_height_full = 0.0f; const float logo_padding_x = 15.0f; - const float chat_input_padding_x = 15.0f; - const float chat_input_padding_y = 15.0f; + const float chat_input_padding_x = 10.0f; + const float chat_input_padding_y = 10.0f; Body url_selection_body(this, font.get(), bold_font.get(), cjk_font.get(), loading_icon); @@ -3902,8 +3925,8 @@ namespace QuickMedia { tab_shade_height = tab_spacer_height + std::floor(tab_vertical_offset) + tab_height + room_name_padding_y + padding_bottom; - chat_input.set_max_width(window_size.x - (logo_padding_x + plugin_logo.getSize().x + chat_input_padding_x * 2.0f)); - chat_input.set_position(sf::Vector2f(logo_padding_x + plugin_logo.getSize().x + chat_input_padding_x, window_size.y - chat_height - chat_input_padding_y)); + chat_input.set_max_width(window_size.x - (logo_padding_x + logo_size.x + chat_input_padding_x + logo_padding_x)); + chat_input.set_position(sf::Vector2f(std::floor(logo_padding_x + logo_size.x + chat_input_padding_x), window_size.y - chat_height - chat_input_padding_y)); float body_padding_horizontal = 25.0f; float body_padding_vertical = 5.0f; @@ -3922,7 +3945,7 @@ namespace QuickMedia { more_messages_below_rect.setSize(sf::Vector2f(window_size.x, gradient_height)); more_messages_below_rect.setPosition(0.0f, std::floor(window_size.y - chat_input_shade.getSize().y - gradient_height)); - logo_sprite.setPosition(logo_padding_x, window_size.y - chat_input_shade.getSize().y * 0.5f - plugin_logo.getSize().y * 0.5f); + logo_sprite.setPosition(logo_padding_x, std::floor(window_size.y - chat_input_shade.getSize().y * 0.5f - logo_size.y * 0.5f)); } room_search_bar.update(); @@ -3945,7 +3968,7 @@ namespace QuickMedia { }); } - if(sync_future.valid() && sync_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { + if(is_future_ready(sync_future)) { SyncFutureResult sync_result = sync_future.get(); add_new_rooms(sync_result.rooms); @@ -3962,13 +3985,13 @@ namespace QuickMedia { synced = true; } - if(set_read_marker_future.valid() && set_read_marker_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { + if(is_future_ready(set_read_marker_future)) { set_read_marker_future.get(); read_marker_timer.restart(); setting_read_marker = false; } - if(fetching_previous_messages_running && previous_messages_future.valid() && previous_messages_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { + if(fetching_previous_messages_running && is_future_ready(previous_messages_future)) { Messages new_messages = previous_messages_future.get(); fprintf(stderr, "Finished fetching older messages, num new messages: %zu\n", new_messages.size()); // Ignore finished fetch of messages if it happened in another room. When we navigate back to the room we will get the messages again @@ -3989,7 +4012,7 @@ namespace QuickMedia { fetching_previous_messages_running = false; } - if(fetching_message_running && fetch_message_future.valid() && fetch_message_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { + if(fetching_message_running && is_future_ready(fetch_message_future)) { std::shared_ptr message = fetch_message_future.get(); fprintf(stderr, "Finished fetching message: %s\n", message ? message->event_id.c_str() : "(null)"); // Ignore finished fetch of messages if it happened in another room. When we navigate back to the room we will get the messages again @@ -3998,18 +4021,18 @@ namespace QuickMedia { PinnedEventData *event_data = static_cast(fetch_body_item->userdata); if(message) { *fetch_body_item = *message_to_body_item(message.get(), matrix->get_me(current_room).get()); - event_data->status = PinnedEventStatus::FINISHED_LOADING; + event_data->status = FetchStatus::FINISHED_LOADING; fetch_body_item->userdata = event_data; } else { fetch_body_item->set_description("Failed to load message!"); - event_data->status = PinnedEventStatus::FAILED_TO_LOAD; + event_data->status = FetchStatus::FAILED_TO_LOAD; } } else if(fetch_message_tab == MESSAGES_TAB_INDEX) { if(message) { fetch_body_item->embedded_item = message_to_body_item(message.get(), matrix->get_me(current_room).get()); - fetch_body_item->embedded_item_status = EmbeddedItemStatus::FINISHED_LOADING; + fetch_body_item->embedded_item_status = FetchStatus::FINISHED_LOADING; } else { - fetch_body_item->embedded_item_status = EmbeddedItemStatus::FAILED_TO_LOAD; + fetch_body_item->embedded_item_status = FetchStatus::FAILED_TO_LOAD; } } } diff --git a/src/SearchBar.cpp b/src/SearchBar.cpp index 382b06a..6895dcb 100644 --- a/src/SearchBar.cpp +++ b/src/SearchBar.cpp @@ -8,10 +8,13 @@ // TODO: Use a seperate placeholder sf::Text instead of switching the text to placeholder text.... -const sf::Color text_placeholder_color(255, 255, 255, 100); -const sf::Color front_color(55, 60, 68); -const float background_margin_horizontal = 15.0f; -const float PADDING_HORIZONTAL = 25.0f; +static const sf::Color text_placeholder_color(255, 255, 255, 100); +static const sf::Color front_color(55, 60, 68); +static const float background_margin_horizontal = 15.0f; +static const float PADDING_HORIZONTAL = 25.0f; +static const float padding_top = 10.0f; +static const float padding_bottom = 15.0f; +static const float background_margin_vertical = 4.0f; namespace QuickMedia { SearchBar::SearchBar(sf::Font &font, sf::Texture *plugin_logo, const std::string &placeholder, bool input_masked) : @@ -22,8 +25,8 @@ namespace QuickMedia { text_autosearch_delay(0), autocomplete_search_delay(0), caret_visible(true), - text(placeholder, font, 18), - autocomplete_text("", font, 18), + text(placeholder, font, 16), + autocomplete_text("", font, 16), background(sf::Vector2f(1.0f, 1.0f), 10.0f, 10), placeholder_str(placeholder), show_placeholder(true), @@ -127,20 +130,20 @@ namespace QuickMedia { sf::Vector2f texture_size_f(texture_size.x, texture_size.y); sf::Vector2f new_size = wrap_to_size(texture_size_f, sf::Vector2f(200.0f, one_line_height)); plugin_logo_sprite.setScale(get_ratio(texture_size_f, new_size)); - plugin_logo_sprite.setPosition(25.0f, padding_vertical + vertical_pos); + plugin_logo_sprite.setPosition(25.0f, padding_top + vertical_pos); offset_x = 25.0f + new_size.x + 25.0f; } const float width = std::floor(window_size.x - offset_x - padding_horizontal); background.setSize(sf::Vector2f(width, rect_height)); - shade.setSize(sf::Vector2f(window_size.x, padding_vertical + rect_height + padding_vertical)); + shade.setSize(sf::Vector2f(window_size.x, padding_top + rect_height + padding_bottom)); caret.setSize(sf::Vector2f(2.0f, text.getCharacterSize() + 2.0f)); background_shadow.setSize(sf::Vector2f(window_size.x, 5.0f)); - background.setPosition(offset_x, padding_vertical + vertical_pos); + background.setPosition(offset_x, padding_top + vertical_pos); shade.setPosition(0.0f, vertical_pos); background_shadow.setPosition(0.0f, std::floor(shade.getSize().y + vertical_pos)); - sf::Vector2f font_position(std::floor(offset_x + background_margin_horizontal), std::floor(padding_vertical + background_margin_vertical + vertical_pos)); + sf::Vector2f font_position(std::floor(offset_x + background_margin_horizontal), std::floor(padding_top + background_margin_vertical + vertical_pos)); autocomplete_text.setPosition(font_position); text.setPosition(font_position); } @@ -302,7 +305,7 @@ namespace QuickMedia { float SearchBar::getBottomWithoutShadow() const { float font_height = text.getCharacterSize() + 7.0f; - return std::floor(font_height + background_margin_vertical * 2.0f) + padding_vertical + padding_vertical; + return std::floor(font_height + background_margin_vertical * 2.0f) + padding_top + padding_bottom; } std::string SearchBar::get_text() const { diff --git a/src/plugins/FileManager.cpp b/src/plugins/FileManager.cpp index 5fac79c..f65486e 100644 --- a/src/plugins/FileManager.cpp +++ b/src/plugins/FileManager.cpp @@ -48,7 +48,6 @@ namespace QuickMedia { auto body = create_body(); body->items = std::move(result_items); - body->draw_thumbnails = true; result_tabs.push_back(Tab{std::move(body), nullptr, nullptr}); return PluginResult::OK; } diff --git a/src/plugins/Fourchan.cpp b/src/plugins/Fourchan.cpp index 7f8008c..d042a2a 100644 --- a/src/plugins/Fourchan.cpp +++ b/src/plugins/Fourchan.cpp @@ -267,7 +267,6 @@ namespace QuickMedia { auto body = create_body(); body->items = std::move(result_items); - body->draw_thumbnails = true; result_tabs.push_back(Tab{std::move(body), std::make_unique(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); return PluginResult::OK; } @@ -459,7 +458,6 @@ namespace QuickMedia { auto body = create_body(); body->items = std::move(result_items); - body->draw_thumbnails = true; result_tabs.push_back(Tab{std::move(body), std::make_unique(program, board_id, url, std::move(cached_media_urls)), nullptr}); return PluginResult::OK; } diff --git a/src/plugins/Manga.cpp b/src/plugins/Manga.cpp index 70a1664..323794c 100644 --- a/src/plugins/Manga.cpp +++ b/src/plugins/Manga.cpp @@ -9,4 +9,10 @@ namespace QuickMedia { else return TrackResult::ERR; } + + void MangaChaptersPage::on_navigate_to_page() { + std::string manga_id; + if(extract_id_from_url(content_url, manga_id)) + load_manga_content_storage(get_service_name(), content_title, manga_id); + } } \ No newline at end of file diff --git a/src/plugins/Mangadex.cpp b/src/plugins/Mangadex.cpp index 3574914..e798b60 100644 --- a/src/plugins/Mangadex.cpp +++ b/src/plugins/Mangadex.cpp @@ -112,8 +112,7 @@ namespace QuickMedia { } PluginResult MangadexSearchPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - std::string manga_id = title_url_extract_manga_id(url); - std::string request_url = "https://mangadex.org/api/?id=" + manga_id + "&type=manga"; + std::string request_url = "https://mangadex.org/api/?id=" + title_url_extract_manga_id(url) + "&type=manga"; rapidjson::Document json_root; DownloadResult result = download_to_json(request_url, json_root, {}, is_tor_enabled(), true); @@ -169,10 +168,7 @@ namespace QuickMedia { } result_tabs.push_back(Tab{std::move(body), std::make_unique(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); - - if(load_manga_content_storage("mangadex", title, manga_id)) - return PluginResult::OK; - return PluginResult::ERR; + return PluginResult::OK; } bool MangadexSearchPage::get_rememberme_token(std::string &rememberme_token_output) { @@ -212,6 +208,11 @@ namespace QuickMedia { return PluginResult::OK; } + bool MangadexChaptersPage::extract_id_from_url(const std::string &url, std::string &manga_id) const { + manga_id = title_url_extract_manga_id(url); + return true; + } + ImageResult MangadexImagesPage::get_number_of_images(int &num_images) { num_images = 0; ImageResult image_result = get_image_urls_for_chapter(url); diff --git a/src/plugins/Manganelo.cpp b/src/plugins/Manganelo.cpp index b260dea..7f0a2f9 100644 --- a/src/plugins/Manganelo.cpp +++ b/src/plugins/Manganelo.cpp @@ -25,49 +25,12 @@ namespace QuickMedia { return true; } - SearchResult ManganeloSearchPage::search(const std::string &str, BodyItems &result_items) { - std::string url = "https://manganelo.com/getstorysearchjson"; - std::string search_term = "searchword="; - search_term += url_param_encode(str); - CommandArg data_arg = { "--data", std::move(search_term) }; - - Json::Value json_root; - DownloadResult result = download_json(json_root, url, {data_arg}, true); - if(result != DownloadResult::OK) return download_result_to_search_result(result); - - if(json_root.isNull()) - return SearchResult::OK; - - if(!json_root.isArray()) - return SearchResult::ERR; - - for(const Json::Value &child : json_root) { - if(!child.isObject()) - continue; - - Json::Value name = child.get("name", ""); - Json::Value nameunsigned = child.get("nameunsigned", ""); - if(name.isString() && name.asCString()[0] != '\0' && nameunsigned.isString() && nameunsigned.asCString()[0] != '\0') { - std::string name_str = name.asString(); - while(remove_html_span(name_str)) {} - auto item = BodyItem::create(strip(name_str)); - item->url = "https://manganelo.com/manga/" + url_param_encode(nameunsigned.asString()); - Json::Value image = child.get("image", ""); - if(image.isString() && image.asCString()[0] != '\0') - item->thumbnail_url = image.asString(); - result_items.push_back(std::move(item)); - } - } - - return SearchResult::OK; - } - - PluginResult ManganeloSearchPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { + static PluginResult submit_manga(Page *page, const std::string &title, const std::string &url, std::vector &result_tabs, bool use_tor) { BodyItems chapters_items; std::vector creators; std::string website_data; - if(download_to_string(url, website_data, {}, is_tor_enabled(), true) != DownloadResult::OK) + if(download_to_string(url, website_data, {}, use_tor, true) != DownloadResult::OK) return PluginResult::NET_ERR; QuickMediaHtmlSearch html_search; @@ -105,23 +68,64 @@ namespace QuickMedia { if(result != 0) return PluginResult::ERR; - auto chapters_body = create_body(); + auto chapters_body = page->create_body(); chapters_body->items = std::move(chapters_items); - result_tabs.push_back(Tab{std::move(chapters_body), std::make_unique(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + result_tabs.push_back(Tab{std::move(chapters_body), std::make_unique(page->program, title, url), page->create_search_bar("Search...", SEARCH_DELAY_FILTER)}); for(Creator &creator : creators) { - result_tabs.push_back(Tab{create_body(), std::make_unique(program, std::move(creator)), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + result_tabs.push_back(Tab{page->create_body(), std::make_unique(page->program, std::move(creator)), page->create_search_bar("Search...", SEARCH_DELAY_FILTER)}); } - std::string manga_id; - if(extract_id_from_url(url, manga_id)) { - if(load_manga_content_storage("manganelo", title, manga_id)) - return PluginResult::OK; + return PluginResult::OK; + } + + SearchResult ManganeloSearchPage::search(const std::string &str, BodyItems &result_items) { + std::string url = "https://manganelo.com/getstorysearchjson"; + std::string search_term = "searchword="; + search_term += url_param_encode(str); + CommandArg data_arg = { "--data", std::move(search_term) }; + + Json::Value json_root; + DownloadResult result = download_json(json_root, url, {data_arg}, true); + if(result != DownloadResult::OK) return download_result_to_search_result(result); + + if(json_root.isNull()) + return SearchResult::OK; + + if(!json_root.isArray()) + return SearchResult::ERR; + + for(const Json::Value &child : json_root) { + if(!child.isObject()) + continue; + + Json::Value name = child.get("name", ""); + Json::Value nameunsigned = child.get("nameunsigned", ""); + if(name.isString() && name.asCString()[0] != '\0' && nameunsigned.isString() && nameunsigned.asCString()[0] != '\0') { + std::string name_str = name.asString(); + while(remove_html_span(name_str)) {} + auto item = BodyItem::create(strip(name_str)); + item->url = "https://manganelo.com/manga/" + url_param_encode(nameunsigned.asString()); + Json::Value image = child.get("image", ""); + if(image.isString() && image.asCString()[0] != '\0') + item->thumbnail_url = image.asString(); + result_items.push_back(std::move(item)); + } } - return PluginResult::ERR; + + return SearchResult::OK; + } + + PluginResult ManganeloSearchPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { + return submit_manga(this, title, url, result_tabs, is_tor_enabled()); + } + + PluginResult ManganeloChaptersPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { + result_tabs.push_back(Tab{create_body(), std::make_unique(program, content_title, title, url), nullptr}); + return PluginResult::OK; } - - bool ManganeloSearchPage::extract_id_from_url(const std::string &url, std::string &manga_id) const { + + bool ManganeloChaptersPage::extract_id_from_url(const std::string &url, std::string &manga_id) const { bool manganelo_website = false; if(url.find("mangakakalot") != std::string::npos || url.find("manganelo") != std::string::npos) manganelo_website = true; @@ -154,17 +158,56 @@ namespace QuickMedia { } } - PluginResult ManganeloChaptersPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - result_tabs.push_back(Tab{create_body(), std::make_unique(program, content_title, title, url), nullptr}); - return PluginResult::OK; + PluginResult ManganeloCreatorPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { + return submit_manga(this, title, url, result_tabs, is_tor_enabled()); } - PluginResult ManganeloCreatorPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - (void)title; - (void)url; - (void)result_tabs; - // TODO: Implement - return PluginResult::ERR; + PluginResult ManganeloCreatorPage::lazy_fetch(BodyItems &result_items) { + std::string website_data; + if(download_to_string(creator.url, website_data, {}, is_tor_enabled(), true) != DownloadResult::OK) + return PluginResult::NET_ERR; + + QuickMediaHtmlSearch html_search; + int result = quickmedia_html_search_init(&html_search, website_data.c_str()); + if(result != 0) + goto cleanup; + + result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='search-story-item']//a[class='item-img']", + [](QuickMediaHtmlNode *node, void *userdata) { + auto *item_data = (BodyItems*)userdata; + const char *href = quickmedia_html_node_get_attribute_value(node, "href"); + const char *title = quickmedia_html_node_get_attribute_value(node, "title"); + if(href && title && strstr(href, "/manga/")) { + auto body_item = BodyItem::create(title); + body_item->url = href; + item_data->push_back(std::move(body_item)); + } + }, &result_items); + + if(result != 0) + goto cleanup; + + BodyItemImageContext body_item_image_context; + body_item_image_context.body_items = &result_items; + body_item_image_context.index = 0; + + result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='search-story-item']//a[class='item-img']//img", + [](QuickMediaHtmlNode *node, void *userdata) { + auto *item_data = (BodyItemImageContext*)userdata; + const char *src = quickmedia_html_node_get_attribute_value(node, "src"); + if(src && item_data->index < item_data->body_items->size()) { + (*item_data->body_items)[item_data->index]->thumbnail_url = src; + item_data->index++; + } + }, &body_item_image_context); + + cleanup: + quickmedia_html_search_deinit(&html_search); + if(result != 0) { + result_items.clear(); + return PluginResult::ERR; + } + return PluginResult::OK; } ImageResult ManganeloImagesPage::get_number_of_images(int &num_images) { diff --git a/src/plugins/Mangatown.cpp b/src/plugins/Mangatown.cpp index d9013f7..89bf447 100644 --- a/src/plugins/Mangatown.cpp +++ b/src/plugins/Mangatown.cpp @@ -106,16 +106,15 @@ namespace QuickMedia { auto body = create_body(); body->items = std::move(chapters_items); result_tabs.push_back(Tab{std::move(body), std::make_unique(program, title, url), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + return PluginResult::OK; + } - std::string manga_id; - if(extract_id_from_url(url, manga_id)) { - if(load_manga_content_storage("mangatown", title, manga_id)) - return PluginResult::OK; - } - return PluginResult::ERR; + PluginResult MangatownChaptersPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { + result_tabs.push_back(Tab{create_body(), std::make_unique(program, content_title, title, url), nullptr}); + return PluginResult::OK; } - - bool MangatownSearchPage::extract_id_from_url(const std::string &url, std::string &manga_id) const { + + bool MangatownChaptersPage::extract_id_from_url(const std::string &url, std::string &manga_id) const { size_t start_index = url.find("/manga/"); if(start_index == std::string::npos) return false; @@ -131,11 +130,6 @@ namespace QuickMedia { return true; } - PluginResult MangatownChaptersPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - result_tabs.push_back(Tab{create_body(), std::make_unique(program, content_title, title, url), nullptr}); - return PluginResult::OK; - } - ImageResult MangatownImagesPage::get_number_of_images(int &num_images) { num_images = 0; ImageResult image_result = get_image_urls_for_chapter(url); diff --git a/src/plugins/NyaaSi.cpp b/src/plugins/NyaaSi.cpp index fa4e94f..b6a6488 100644 --- a/src/plugins/NyaaSi.cpp +++ b/src/plugins/NyaaSi.cpp @@ -184,7 +184,6 @@ namespace QuickMedia { auto body = create_body(); body->items = std::move(result_items); - body->draw_thumbnails = true; result_tabs.push_back(Tab{std::move(body), std::make_unique(program, strip(title), url), create_search_bar("Search...", 200)}); return PluginResult::OK; } @@ -372,7 +371,6 @@ namespace QuickMedia { auto body = create_body(); body->items = std::move(result_items); - body->draw_thumbnails = true; result_tabs.push_back(Tab{std::move(body), std::make_unique(program), nullptr}); return PluginResult::OK; } -- cgit v1.2.3