#include "../../plugins/MangaCombined.hpp" namespace QuickMedia { static const int SEARCH_TIMEOUT_MILLISECONDS = 5000; MangaCombinedSearchPage::MangaCombinedSearchPage(Program *program, std::vector search_pages) : LazyFetchPage(program), search_pages(std::move(search_pages)) { } using PluginFinishedState = std::pair>; static void result_items_add_thread_results(std::vector &search_threads, BodyItems &result_items) { std::sort(search_threads.begin(), search_threads.end(), [](const MangaCombinedSearchThread &plugin1, const MangaCombinedSearchThread &plugin2){ return plugin1.first->title < plugin2.first->title; }); std::vector plugin_finished_state(search_threads.size()); for(size_t i = 0; i < plugin_finished_state.size(); ++i) { plugin_finished_state[i].first = search_threads[i].first; plugin_finished_state[i].second = nullptr; } int accumulated_sleep_time = 0; while(true) { if(program_is_dead_in_current_thread()) break; size_t num_dead_threads = 0; for(size_t i = 0; i < search_threads.size(); ++i) { auto &search_thread = search_threads[i]; if(!search_thread.second.valid()) { if(!plugin_finished_state[i].second) ++num_dead_threads; continue; } if(!search_thread.second.ready()) continue; plugin_finished_state[i].second = std::make_unique(search_thread.second.get()); if(plugin_finished_state[i].second->empty()) continue; for(auto &new_body_item : *plugin_finished_state[i].second) { new_body_item->userdata = search_thread.first->page.get(); } } if(num_dead_threads == search_threads.size()) break; size_t num_finished_plugins = 0; for(auto &f : plugin_finished_state) { if(f.second) ++num_finished_plugins; } if(num_finished_plugins == search_threads.size()) { for(auto &f : plugin_finished_state) { if(f.second && !f.second->empty()) { auto title_item = BodyItem::create("", false); title_item->set_author(f.first->title); result_items.push_back(std::move(title_item)); result_items.insert(result_items.end(), std::move_iterator(f.second->begin()), std::move_iterator(f.second->end())); } } break; } int sleep_time_ms = 50; std::this_thread::sleep_for(std::chrono::milliseconds(sleep_time_ms)); accumulated_sleep_time += sleep_time_ms; if(accumulated_sleep_time >= SEARCH_TIMEOUT_MILLISECONDS) { for(auto &f : plugin_finished_state) { if(f.second) { if(!f.second->empty()) { auto title_item = BodyItem::create("", false); title_item->set_author(f.first->title); result_items.push_back(std::move(title_item)); result_items.insert(result_items.end(), std::move_iterator(f.second->begin()), std::move_iterator(f.second->end())); } } else { auto title_item = BodyItem::create("", false); title_item->set_author(f.first->title + " timed out "); result_items.push_back(std::move(title_item)); } } break; } } } SearchResult MangaCombinedSearchPage::search(const std::string &str, BodyItems &result_items) { search_threads.clear(); if(str.empty()) return SearchResult::OK; for(auto &search_page : search_pages) { search_threads.push_back(std::make_pair(&search_page, AsyncTask([&str, &search_page]() { BodyItems search_page_body_items; search_page.page->search(str, search_page_body_items); return search_page_body_items; }))); } result_items_add_thread_results(search_threads, result_items); return SearchResult::OK; } PluginResult MangaCombinedSearchPage::get_page(const std::string &str, int page, BodyItems &result_items) { search_threads.clear(); for(auto &search_page : search_pages) { search_threads.push_back(std::make_pair(&search_page, AsyncTask([&str, page, &search_page]() { BodyItems search_page_body_items; search_page.page->get_page(str, page, search_page_body_items); return search_page_body_items; }))); } result_items_add_thread_results(search_threads, result_items); return PluginResult::OK; } PluginResult MangaCombinedSearchPage::submit(const SubmitArgs &args, std::vector &result_tabs) { Page *page = (Page*)args.userdata; if(!page) return PluginResult::OK; return page->submit(args, result_tabs); } PluginResult MangaCombinedSearchPage::lazy_fetch(BodyItems&) { for(MangaPlugin &manga_plugin : search_pages) { if(manga_plugin.local_manga) { LazyFetchPage *lazy_fetch_page = dynamic_cast(manga_plugin.page.get()); if(lazy_fetch_page) { BodyItems dummy_body_items; lazy_fetch_page->lazy_fetch(dummy_body_items); } } } return PluginResult::OK; } void MangaCombinedSearchPage::cancel_operation() { for(auto &search_thread : search_threads) { search_thread.second.cancel(); } search_threads.clear(); } }