aboutsummaryrefslogtreecommitdiff
path: root/src/QuickMedia.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/QuickMedia.cpp')
-rw-r--r--src/QuickMedia.cpp218
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, &current_room, message_event_id]() {
+ fetch_message_future = AsyncTask<FetchMessageResult>([this, &current_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, &current_room, message_event_id]() {
+ fetch_message_future = AsyncTask<FetchMessageResult>([this, &current_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, &current_room, user_id]() {
+ fetch_message_future = AsyncTask<FetchMessageResult>([this, &current_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, &current_room, message_event_id]() {
+ fetch_message_future = AsyncTask<FetchMessageResult>([this, &current_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, &current_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, &current_room]() {
+ previous_messages_future = AsyncTask<Messages>([this, &current_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, &current_room]() {
+ previous_messages_future = AsyncTask<Messages>([this, &current_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, &current_room]() {
+ fetch_users_future = AsyncTask<bool>([this, &current_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, &current_room]() {
+ previous_messages_future = AsyncTask<Messages>([this, &current_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);