diff options
Diffstat (limited to 'src/QuickMedia.cpp')
-rw-r--r-- | src/QuickMedia.cpp | 218 |
1 files changed, 117 insertions, 101 deletions
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 053c97f..5bdc67e 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -1265,7 +1265,8 @@ namespace QuickMedia { MangaImagesPage *manga_images_page = static_cast<MangaImagesPage*>(new_tabs[0].page.get()); window.setKeyRepeatEnabled(false); downloading_chapter_url.clear(); - while(true) { + + while(window.isOpen() && (current_page == PageType::IMAGES || current_page == PageType::IMAGES_CONTINUOUS)) { if(current_page == PageType::IMAGES) { window.setFramerateLimit(20); while(current_page == PageType::IMAGES) { @@ -1287,10 +1288,14 @@ namespace QuickMedia { idle = true; } else if(current_page == PageType::IMAGES_CONTINUOUS) { image_continuous_page(manga_images_page); - } else { - break; } } + + image_download_cancel = true; + image_download_future.cancel(); + image_download_cancel = false; + images_to_upscale_queue.clear(); + num_manga_pages = 0; window.setKeyRepeatEnabled(true); malloc_trim(0); } else if(new_tabs.size() == 1 && new_tabs[0].page->get_type() == PageTypez::IMAGE_BOARD_THREAD) { @@ -1436,12 +1441,12 @@ namespace QuickMedia { 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 = [update_search_text, next_page, page]() { + tab_associated_data[selected_tab].next_page_future = AsyncTask<BodyItems>([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); return result_items; - }; + }); } } else if(event.key.code == sf::Keyboard::Up || (event.key.control && event.key.code == sf::Keyboard::K)) { tabs[selected_tab].body->select_previous_item(); @@ -1528,11 +1533,11 @@ namespace QuickMedia { tab_associated_data[selected_tab].fetch_type = FetchType::LAZY; tab_associated_data[selected_tab].search_result_text.setString("Fetching page..."); LazyFetchPage *lazy_fetch_page = static_cast<LazyFetchPage*>(tabs[selected_tab].page.get()); - tab_associated_data[selected_tab].fetch_future = [lazy_fetch_page]() { + tab_associated_data[selected_tab].fetch_future = AsyncTask<FetchResult>([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) { @@ -1558,11 +1563,11 @@ namespace QuickMedia { associated_data.fetch_type = FetchType::SEARCH; associated_data.search_result_text.setString("Searching..."); Page *page = tabs[i].page.get(); - associated_data.fetch_future = [update_search_text, page]() { + associated_data.fetch_future = AsyncTask<FetchResult>([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.fetch_status == FetchStatus::LOADING && associated_data.fetch_type == FetchType::SEARCH && associated_data.fetch_future.ready()) { @@ -2276,7 +2281,7 @@ namespace QuickMedia { if(upscale_image_action != UpscaleImageAction::NO) { Path image_filepath_upcaled = image_path; image_filepath_upcaled.append(".upscaled"); - if(get_file_type(image_filepath_upcaled) == FileType::FILE_NOT_FOUND && image_upscale_status[image_index] == 0) + if(get_file_type(image_filepath_upcaled) == FileType::FILE_NOT_FOUND && image_index < (int)image_upscale_status.size() && image_upscale_status[image_index] == 0) upscaled_ok = false; } @@ -2311,13 +2316,29 @@ namespace QuickMedia { image_download_future.cancel(); image_download_cancel = false; + std::promise<int> num_manga_pages_promise; + num_manga_pages_future = num_manga_pages_promise.get_future(); + Path content_cache_dir_ = content_cache_dir; - image_download_future = [images_page, content_cache_dir_, this]() { + image_download_future = AsyncTask<void, std::promise<int>>([images_page, content_cache_dir_, this](std::promise<int> num_manga_pages_promise) { + std::vector<std::string> page_image_urls; + if(images_page->get_page_image_urls(page_image_urls) != ImageResult::OK) { + num_manga_pages_promise.set_value(0); + if(!image_download_cancel) show_notification("QuickMedia", "Failed to fetch page images", Urgency::CRITICAL); + return; + } else { + num_manga_pages_promise.set_value(page_image_urls.size()); + image_upscale_status.resize(page_image_urls.size(), 0); + } + + if(page_image_urls.empty()) + return; + // TODO: Download images in parallel int page = 1; - images_page->for_each_page_in_chapter([content_cache_dir_, &page, images_page, this](const std::string &url) { + for(const std::string &url : page_image_urls) { if(image_download_cancel) - return false; + return; int image_index = page - 1; @@ -2334,7 +2355,7 @@ namespace QuickMedia { } if(get_file_type(image_filepath) != FileType::FILE_NOT_FOUND && upscaled_ok) - return true; + continue; std::vector<CommandArg> extra_args; const bool is_manganelo = (strcmp(images_page->get_service_name(), "manganelo") == 0); @@ -2355,7 +2376,7 @@ namespace QuickMedia { size_t file_size = 0; if(download_to_file(url, image_filepath_tmp.data, extra_args, true) != DownloadResult::OK || (is_manganelo && file_get_size(image_filepath_tmp, &file_size) == 0 && file_size < 255)) { if(!image_download_cancel) show_notification("QuickMedia", "Failed to download image: " + url, Urgency::CRITICAL); - return true; + continue; } bool rename_immediately = true; @@ -2391,26 +2412,45 @@ namespace QuickMedia { if(rename(image_filepath_tmp.data.c_str(), image_filepath.data.c_str()) != 0) { perror(image_filepath_tmp.data.c_str()); show_notification("QuickMedia", "Failed to save image to file: " + image_filepath.data, Urgency::CRITICAL); - return true; + continue; } } + } + }, std::move(num_manga_pages_promise)); - return true; - }); - }; + sf::Event event; + PageType current_manga_page = current_page; + + while (current_page == current_manga_page && window.isOpen()) { + while(window.pollEvent(event)) { + 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 = pop_page_stack(); + } + } + handle_window_close(); + + if(num_manga_pages_future.valid() && num_manga_pages_future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) { + num_manga_pages = num_manga_pages_future.get(); + break; + } + + window.clear(back_color); + load_sprite.setPosition(window_size.x * 0.5f, window_size.y * 0.5f); + load_sprite.setRotation(load_sprite_timer.getElapsedTime().asSeconds() * 400.0); + window.draw(load_sprite); + window.display(); + } } int Program::image_page(MangaImagesPage *images_page, Body *chapters_body) { int page_navigation = 0; image_download_cancel = false; - sf::Texture image_texture; - sf::Sprite image; - sf::Text error_message("", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(30 * get_ui_scale())); - error_message.setFillColor(sf::Color::White); - - bool download_in_progress = false; - content_cache_dir = get_cache_dir().join(images_page->get_service_name()).join(manga_id_base64).join(base64_encode(images_page->get_chapter_name())); if(create_directory_recursive(content_cache_dir) != 0) { show_notification("QuickMedia", "Failed to create directory: " + content_cache_dir.data, Urgency::CRITICAL); @@ -2418,20 +2458,21 @@ namespace QuickMedia { return 0; } - int num_images = 0; - if(images_page->get_number_of_images(num_images) != ImageResult::OK) { - show_notification("QuickMedia", "Failed to get number of images", Urgency::CRITICAL); - current_page = pop_page_stack(); - return 0; - } - image_index = std::min(image_index, num_images); - - if(num_images != (int)image_upscale_status.size()) - image_upscale_status.resize(num_images); + sf::Texture image_texture; + sf::Sprite image; + sf::Text error_message("", *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(30 * get_ui_scale())); + error_message.setFillColor(sf::Color::White); + + bool download_in_progress = false; + sf::Event event; download_chapter_images_if_needed(images_page); + if(current_page != PageType::IMAGES || !window.isOpen()) + return 0; + + image_index = std::min(image_index, num_manga_pages); - if(image_index < num_images) { + if(image_index < num_manga_pages) { sf::String error_msg; LoadImageResult load_image_result = load_image_by_index(image_index, image_texture, error_msg); if(load_image_result == LoadImageResult::OK) @@ -2439,7 +2480,7 @@ namespace QuickMedia { else if(load_image_result == LoadImageResult::DOWNLOAD_IN_PROGRESS) download_in_progress = true; error_message.setString(error_msg); - } else if(image_index == num_images) { + } else if(image_index == num_manga_pages) { error_message.setString("End of " + images_page->get_chapter_name()); } @@ -2460,8 +2501,8 @@ namespace QuickMedia { json_chapters = Json::Value(Json::objectValue); json_chapter = Json::Value(Json::objectValue); } - json_chapter["current"] = std::min(latest_read, num_images); - json_chapter["total"] = num_images; + json_chapter["current"] = std::min(latest_read, num_manga_pages); + json_chapter["total"] = num_manga_pages; json_chapters[images_page->get_chapter_name()] = json_chapter; if(!save_json_to_file_atomic(content_storage_file, content_storage_json)) { show_notification("QuickMedia", "Failed to save manga progress", Urgency::CRITICAL); @@ -2470,8 +2511,8 @@ namespace QuickMedia { bool error = !error_message.getString().isEmpty(); bool redraw = true; - sf::Text chapter_text(images_page->manga_name + " | " + images_page->get_chapter_name() + " | Page " + std::to_string(image_index + 1) + "/" + std::to_string(num_images), *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14 * get_ui_scale())); - if(image_index == num_images) + sf::Text chapter_text(images_page->manga_name + " | " + images_page->get_chapter_name() + " | Page " + std::to_string(image_index + 1) + "/" + std::to_string(num_manga_pages), *FontLoader::get_font(FontLoader::FontType::LATIN), std::floor(14 * get_ui_scale())); + if(image_index == num_manga_pages) chapter_text.setString(images_page->manga_name + " | " + images_page->get_chapter_name() + " | End"); chapter_text.setFillColor(sf::Color::White); sf::RectangleShape chapter_text_background; @@ -2487,10 +2528,6 @@ namespace QuickMedia { sf::Clock check_downloaded_timer; const sf::Int32 check_downloaded_timeout_ms = 500; - sf::Event event; - // Consume events sent during above call to get_number_of_images which sends a request to server which may take a while. We dont want pages to be skipped when pressing arrow up/down - while(window.pollEvent(event)) {} - malloc_trim(0); // TODO: Show to user if a certain page is missing (by checking page name (number) and checking if some are skipped) @@ -2514,10 +2551,10 @@ namespace QuickMedia { goto end_of_images_page; } } else if(event.key.code == sf::Keyboard::Down || (event.key.control && event.key.code == sf::Keyboard::J)) { - if(image_index < num_images) { + if(image_index < num_manga_pages) { ++image_index; goto end_of_images_page; - } else if(image_index == num_images && chapters_body->get_selected_item() > 0) { + } else if(image_index == num_manga_pages && chapters_body->get_selected_item() > 0) { page_navigation = 1; goto end_of_images_page; } @@ -2601,13 +2638,6 @@ namespace QuickMedia { } end_of_images_page: - if(current_page != PageType::IMAGES && current_page != PageType::IMAGES_CONTINUOUS) { - image_download_cancel = true; - image_download_future.cancel(); - image_download_cancel = false; - images_to_upscale_queue.clear(); - image_upscale_status.clear(); - } return page_navigation; } @@ -2621,17 +2651,9 @@ namespace QuickMedia { return; } - int num_images = 0; - if(images_page->get_number_of_images(num_images) != ImageResult::OK) { - show_notification("QuickMedia", "Failed to get number of images", Urgency::CRITICAL); - current_page = pop_page_stack(); - return; - } - - if(num_images != (int)image_upscale_status.size()) - image_upscale_status.resize(num_images); - download_chapter_images_if_needed(images_page); + if(current_page != PageType::IMAGES_CONTINUOUS || !window.isOpen()) + return; Json::Value &json_chapters = content_storage_json["chapters"]; Json::Value json_chapter; @@ -2650,7 +2672,7 @@ namespace QuickMedia { json_chapter = Json::Value(Json::objectValue); } - ImageViewer image_viewer(&window, images_page, images_page->manga_name, images_page->get_chapter_name(), image_index, content_cache_dir); + ImageViewer image_viewer(&window, num_manga_pages, images_page->manga_name, images_page->get_chapter_name(), image_index, content_cache_dir); json_chapter["current"] = std::min(latest_read, image_viewer.get_num_pages()); json_chapter["total"] = image_viewer.get_num_pages(); @@ -2690,14 +2712,6 @@ namespace QuickMedia { } } - if(current_page != PageType::IMAGES && current_page != PageType::IMAGES_CONTINUOUS) { - image_download_cancel = true; - image_download_future.cancel(); - image_download_cancel = false; - images_to_upscale_queue.clear(); - image_upscale_status.clear(); - } - window_size.x = window.getSize().x; window_size.y = window.getSize().y; @@ -2844,17 +2858,17 @@ namespace QuickMedia { comment_to_post = std::move(text); if(!captcha_post_id.empty() && captcha_solved_time.getElapsedTime().asSeconds() < 120) { - post_comment_future = [&post_comment]() -> bool { + post_comment_future = AsyncTask<bool>([&post_comment]() -> bool { post_comment(); return true; - }; + }); } else if(thread_page->get_pass_id().empty()) { request_new_google_captcha_challenge(); } else if(!thread_page->get_pass_id().empty()) { - post_comment_future = [&post_comment]() -> bool { + post_comment_future = AsyncTask<bool>([&post_comment]() -> bool { post_comment(); return true; - }; + }); } return true; }; @@ -2940,7 +2954,7 @@ namespace QuickMedia { load_image_future.cancel(); downloading_image = true; navigation_stage = NavigationStage::VIEWING_ATTACHED_IMAGE; - load_image_future = [&thread_body]() { + load_image_future = AsyncTask<std::string>([&thread_body]() { std::string image_data; BodyItem *selected_item = thread_body->get_selected(); if(!selected_item || selected_item->attached_content_url.empty()) { @@ -2951,7 +2965,7 @@ namespace QuickMedia { image_data.clear(); } return image_data; - }; + }); } } } @@ -4025,9 +4039,9 @@ namespace QuickMedia { 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 = [this, ¤t_room, message_event_id]() { + fetch_message_future = AsyncTask<FetchMessageResult>([this, ¤t_room, message_event_id]() { return FetchMessageResult{FetchMessageType::MESSAGE, matrix->get_message_by_id(current_room, message_event_id)}; - }; + }); return; } @@ -4056,9 +4070,9 @@ namespace QuickMedia { event_data->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 = [this, ¤t_room, message_event_id]() { + fetch_message_future = AsyncTask<FetchMessageResult>([this, ¤t_room, message_event_id]() { return FetchMessageResult{FetchMessageType::MESSAGE, matrix->get_message_by_id(current_room, message_event_id)}; - }; + }); }; // TODO: How about instead fetching all messages we have, not only the visible ones? also fetch with multiple threads. @@ -4080,11 +4094,11 @@ namespace QuickMedia { RoomData *room = current_room; std::string event_id = read_message->event_id; int64_t event_timestamp = read_message->timestamp; - set_read_marker_future = [this, room, event_id, event_timestamp]() mutable { + set_read_marker_future = AsyncTask<void>([this, room, event_id, event_timestamp]() mutable { if(matrix->set_read_marker(room, event_id, event_timestamp) != PluginResult::OK) { fprintf(stderr, "Warning: failed to set read marker to %s\n", event_id.c_str()); } - }; + }); } } @@ -4093,10 +4107,10 @@ namespace QuickMedia { fetch_message = message; message->user->resolve_state = UserResolveState::RESOLVING; std::string user_id = message->user->user_id; - fetch_message_future = [this, ¤t_room, user_id]() { + fetch_message_future = AsyncTask<FetchMessageResult>([this, ¤t_room, user_id]() { matrix->update_user_with_latest_state(current_room, user_id); return FetchMessageResult{FetchMessageType::USER_UPDATE, nullptr}; - }; + }); return; } else if(message->user->resolve_state == UserResolveState::RESOLVING) { return; @@ -4119,9 +4133,9 @@ namespace QuickMedia { 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 = [this, ¤t_room, message_event_id]() { + fetch_message_future = AsyncTask<FetchMessageResult>([this, ¤t_room, message_event_id]() { return FetchMessageResult{FetchMessageType::MESSAGE, matrix->get_message_by_id(current_room, message_event_id)}; - }; + }); }; tabs[MESSAGES_TAB_INDEX].body->body_item_merge_handler = [](BodyItem *prev_item, BodyItem *this_item) { @@ -4164,23 +4178,23 @@ namespace QuickMedia { auto fetch_more_previous_messages_if_needed = [this, &tabs, ¤t_room, &fetched_enough_messages, &previous_messages_future]() { if(!fetched_enough_messages && !previous_messages_future.valid()) { if(tabs[MESSAGES_TAB_INDEX].body->items.size() < 30) { - previous_messages_future = [this, ¤t_room]() { + previous_messages_future = AsyncTask<Messages>([this, ¤t_room]() { Messages messages; if(matrix->get_previous_room_messages(current_room, messages) != PluginResult::OK) fprintf(stderr, "Failed to get previous matrix messages in room: %s\n", current_room->id.c_str()); return messages; - }; + }); } } }; if(!matrix->is_initial_sync_finished()) { - previous_messages_future = [this, ¤t_room]() { + previous_messages_future = AsyncTask<Messages>([this, ¤t_room]() { Messages messages; if(matrix->get_previous_room_messages(current_room, messages, true) != PluginResult::OK) fprintf(stderr, "Failed to get previous matrix messages in room: %s\n", current_room->id.c_str()); return messages; - }; + }); } sf::RectangleShape more_messages_below_rect; @@ -4428,10 +4442,10 @@ namespace QuickMedia { //update_ } else { // TODO: Race condition? maybe use matrix /members instead which has a since parameter to make the members list match current sync - fetch_users_future = [this, ¤t_room]() { + fetch_users_future = AsyncTask<bool>([this, ¤t_room]() { matrix->update_room_users(current_room); return true; - }; + }); } float tab_shade_height = 0.0f; @@ -4531,12 +4545,12 @@ namespace QuickMedia { } if(hit_top && !previous_messages_future.valid() && selected_tab == MESSAGES_TAB_INDEX && current_room) { gradient_inc = 0; - previous_messages_future = [this, ¤t_room]() { + previous_messages_future = AsyncTask<Messages>([this, ¤t_room]() { Messages messages; if(matrix->get_previous_room_messages(current_room, messages) != PluginResult::OK) fprintf(stderr, "Failed to get previous matrix messages in room: %s\n", current_room->id.c_str()); return messages; - }; + }); } } else if(event.key.code == sf::Keyboard::Down || (event.key.control && event.key.code == sf::Keyboard::J)) { tabs[selected_tab].body.get()->select_next_item(); @@ -5057,7 +5071,9 @@ namespace QuickMedia { const float margin = 5.0f; const float replying_to_text_height = replying_to_text.getLocalBounds().height + margin; - const float item_height = std::min(body_size.y - replying_to_text_height - margin, tabs[MESSAGES_TAB_INDEX].body->get_item_height(currently_operating_on_item.get(), body_size.x) + margin); + float item_height = std::min(body_size.y - replying_to_text_height - margin, tabs[MESSAGES_TAB_INDEX].body->get_item_height(currently_operating_on_item.get(), body_size.x) + margin); + if(item_height < 0.0f) + item_height = 0.0f; sf::RectangleShape overlay(sf::Vector2f(window_size.x, window_size.y - chat_input_height_full)); overlay.setFillColor(sf::Color(0, 0, 0, 240)); @@ -5066,8 +5082,8 @@ namespace QuickMedia { sf::Vector2f body_item_pos(body_pos.x, window_size.y - chat_input_height_full - item_height); sf::Vector2f body_item_size(body_size.x, item_height); - sf::RectangleShape item_background(sf::Vector2f(window_size.x, body_item_size.y + replying_to_text_height + margin + body_item_size.y)); - item_background.setPosition(sf::Vector2f(0.0f, body_item_pos.y - replying_to_text_height - margin)); + sf::RectangleShape item_background(sf::Vector2f(window_size.x, body_item_size.y + chat_input_height_full + replying_to_text_height + margin)); + item_background.setPosition(sf::Vector2f(0.0f, window_size.y - (body_item_size.y + chat_input_height_full + replying_to_text_height + margin))); item_background.setFillColor(back_color); window.draw(item_background); |