From 9f12d8a7f6e4cdf0cb95130b69da2b368cc9cbb5 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Thu, 3 Feb 2022 21:09:26 +0100 Subject: Add thumbnail to manga history page. Start on new manga history format (one json file) --- include/QuickMedia.hpp | 4 +- plugins/Manga.hpp | 4 +- plugins/MangaGeneric.hpp | 4 +- plugins/Mangadex.hpp | 4 +- plugins/Manganelo.hpp | 3 +- src/QuickMedia.cpp | 180 +++++++++++++++++++++++++++--------------- src/plugins/Manga.cpp | 1 + src/plugins/MangaCombined.cpp | 1 + src/plugins/MangaGeneric.cpp | 2 +- src/plugins/Mangadex.cpp | 2 +- src/plugins/Manganelo.cpp | 2 +- src/plugins/Page.cpp | 33 ++++++-- 12 files changed, 158 insertions(+), 82 deletions(-) diff --git a/include/QuickMedia.hpp b/include/QuickMedia.hpp index f476396..ce63fbb 100644 --- a/include/QuickMedia.hpp +++ b/include/QuickMedia.hpp @@ -99,7 +99,7 @@ namespace QuickMedia { void manga_get_watch_history(const char *plugin_name, BodyItems &history_items); void youtube_get_watch_history(BodyItems &history_items); - Json::Value load_video_history_json(); + Json::Value load_history_json(); void set_clipboard(const std::string &str); private: @@ -121,6 +121,7 @@ namespace QuickMedia { bool video_download_if_non_streamable(std::string &video_url, std::string &audio_url, bool &is_audio_only, bool &has_embedded_audio, PageType previous_page); int video_get_max_height(); void video_content_page(Page *parent_page, VideoPage *video_page, std::string video_title, bool download_if_streaming_fails, Body *parent_body, int play_index, int *parent_body_page = nullptr, const std::string &parent_page_search = ""); + void update_manga_history(const std::string &manga_id, const std::string &thumbnail_url); void save_manga_progress(MangaImagesPage *images_page, Json::Value &json_chapters, Json::Value &json_chapter, int &latest_read); // Returns -1 to go to previous chapter, 0 to stay on same chapter and 1 to go to next chapter int image_page(MangaImagesPage *images_page, Body *chapters_body); @@ -167,6 +168,7 @@ namespace QuickMedia { int image_index; Path content_storage_file; Path content_cache_dir; + std::string manga_id; std::string manga_id_base64; Json::Value content_storage_json; bool content_storage_file_modified = false; diff --git a/plugins/Manga.hpp b/plugins/Manga.hpp index a298c11..7b67e13 100644 --- a/plugins/Manga.hpp +++ b/plugins/Manga.hpp @@ -20,7 +20,8 @@ namespace QuickMedia { class MangaImagesPage : public Page { public: - MangaImagesPage(Program *program, std::string manga_name, std::string chapter_name, std::string url) : Page(program), manga_name(std::move(manga_name)), chapter_name(std::move(chapter_name)), url(std::move(url)), chapter_num_pages(-1) {} + MangaImagesPage(Program *program, std::string manga_name, std::string chapter_name, std::string url, std::string thumbnail_url) : + Page(program), manga_name(std::move(manga_name)), thumbnail_url(std::move(thumbnail_url)), chapter_name(std::move(chapter_name)), url(std::move(url)), chapter_num_pages(-1) {} virtual ~MangaImagesPage() = default; const char* get_title() const override { return chapter_name.c_str(); } PageTypez get_type() const override { return PageTypez::MANGA_IMAGES; } @@ -46,6 +47,7 @@ namespace QuickMedia { virtual const char* get_website_url() const = 0; const std::string manga_name; + const std::string thumbnail_url; protected: std::string chapter_name; std::string url; diff --git a/plugins/MangaGeneric.hpp b/plugins/MangaGeneric.hpp index bb7eb65..439fc19 100644 --- a/plugins/MangaGeneric.hpp +++ b/plugins/MangaGeneric.hpp @@ -183,8 +183,8 @@ namespace QuickMedia { class MangaGenericImagesPage : public MangaImagesPage { public: - MangaGenericImagesPage(Program *program, std::string manga_name, std::string chapter_name, std::string url, const char *service_name, const std::string &website_url, const ListPageQuery *list_page_query, bool fail_on_http_error) : - MangaImagesPage(program, std::move(manga_name), std::move(chapter_name), std::move(url)), service_name(service_name), website_url(website_url), list_page_query(list_page_query), fail_on_http_error(fail_on_http_error) {} + MangaGenericImagesPage(Program *program, std::string manga_name, std::string chapter_name, std::string url, const char *service_name, const std::string &website_url, const ListPageQuery *list_page_query, bool fail_on_http_error, std::string thumbnail_url) : + MangaImagesPage(program, std::move(manga_name), std::move(chapter_name), std::move(url), std::move(thumbnail_url)), service_name(service_name), website_url(website_url), list_page_query(list_page_query), fail_on_http_error(fail_on_http_error) {} ImageResult get_number_of_images(int &num_images) override; ImageResult for_each_page_in_chapter(PageCallback callback) override; const char* get_service_name() const override { return service_name; } diff --git a/plugins/Mangadex.hpp b/plugins/Mangadex.hpp index 2741f0c..d6206cc 100644 --- a/plugins/Mangadex.hpp +++ b/plugins/Mangadex.hpp @@ -51,8 +51,8 @@ namespace QuickMedia { class MangadexImagesPage : public MangaImagesPage { public: - MangadexImagesPage(Program *program, MangadexSearchPage *search_page, std::string manga_name, std::string chapter_id, std::string chapter_name) : - MangaImagesPage(program, std::move(manga_name), std::move(chapter_name), std::move(chapter_id)), search_page(search_page) {} + MangadexImagesPage(Program *program, MangadexSearchPage *search_page, std::string manga_name, std::string chapter_id, std::string chapter_name, std::string thumbnail_url) : + MangaImagesPage(program, std::move(manga_name), std::move(chapter_name), std::move(chapter_id), std::move(thumbnail_url)), search_page(search_page) {} ImageResult get_number_of_images(int &num_images) override; ImageResult for_each_page_in_chapter(PageCallback callback) override; const char* get_service_name() const override { return "mangadex"; } diff --git a/plugins/Manganelo.hpp b/plugins/Manganelo.hpp index a96d0c9..8946447 100644 --- a/plugins/Manganelo.hpp +++ b/plugins/Manganelo.hpp @@ -35,7 +35,8 @@ namespace QuickMedia { class ManganeloImagesPage : public MangaImagesPage { public: - ManganeloImagesPage(Program *program, std::string manga_name, std::string chapter_name, std::string url) : MangaImagesPage(program, std::move(manga_name), std::move(chapter_name), std::move(url)) {} + ManganeloImagesPage(Program *program, std::string manga_name, std::string chapter_name, std::string url, std::string thumbnail_url) : + MangaImagesPage(program, std::move(manga_name), std::move(chapter_name), std::move(url), std::move(thumbnail_url)) {} ImageResult get_number_of_images(int &num_images) override; ImageResult for_each_page_in_chapter(PageCallback callback) override; const char* get_service_name() const override { return "manganelo"; } diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index cbe8ea4..a5c423d 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -204,6 +204,7 @@ namespace QuickMedia { LazyFetchPage(program), search_page(search_page), history_type(history_type) {} const char* get_title() const override { return "History"; } PluginResult submit(const std::string &title, const std::string &url, std::vector &result_tabs) override { + search_page->submit_body_item = submit_body_item; return search_page->submit(title, url, result_tabs); } PluginResult lazy_fetch(BodyItems &result_items) override { @@ -1064,7 +1065,7 @@ namespace QuickMedia { tabs.push_back(Tab{create_body(), std::make_unique(this, search_page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); tabs.push_back(Tab{create_body(false, true), std::move(search_page), create_search_bar("Search...", 400)}); - auto history_page = std::make_unique(this, tabs.front().page.get(), HistoryType::MANGA); + auto history_page = std::make_unique(this, tabs.back().page.get(), HistoryType::MANGA); tabs.push_back(Tab{create_body(), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); start_tab_index = 1; @@ -1075,7 +1076,7 @@ namespace QuickMedia { tabs.push_back(Tab{create_body(), std::make_unique(this, search_page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); tabs.push_back(Tab{create_body(), std::move(search_page), create_search_bar("Search...", 400)}); - auto history_page = std::make_unique(this, tabs.front().page.get(), HistoryType::MANGA); + auto history_page = std::make_unique(this, tabs.back().page.get(), HistoryType::MANGA); tabs.push_back(Tab{create_body(), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); start_tab_index = 1; @@ -1086,7 +1087,7 @@ namespace QuickMedia { tabs.push_back(Tab{create_body(), std::make_unique(this, search_page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); tabs.push_back(Tab{create_body(), std::move(search_page), create_search_bar("Search...", 400)}); - auto history_page = std::make_unique(this, tabs.front().page.get(), HistoryType::MANGA); + auto history_page = std::make_unique(this, tabs.back().page.get(), HistoryType::MANGA); tabs.push_back(Tab{create_body(), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); start_tab_index = 1; @@ -1097,7 +1098,7 @@ namespace QuickMedia { tabs.push_back(Tab{create_body(), std::make_unique(this, search_page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); tabs.push_back(Tab{create_body(), std::move(search_page), create_search_bar("Search...", 400)}); - auto history_page = std::make_unique(this, tabs.front().page.get(), HistoryType::MANGA); + auto history_page = std::make_unique(this, tabs.back().page.get(), HistoryType::MANGA); tabs.push_back(Tab{create_body(), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); start_tab_index = 1; @@ -1108,7 +1109,7 @@ namespace QuickMedia { tabs.push_back(Tab{create_body(), std::make_unique(this, search_page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); tabs.push_back(Tab{create_body(), std::move(search_page), create_search_bar("Search...", 400)}); - auto history_page = std::make_unique(this, tabs.front().page.get(), HistoryType::MANGA); + auto history_page = std::make_unique(this, tabs.back().page.get(), HistoryType::MANGA); tabs.push_back(Tab{create_body(), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); start_tab_index = 1; @@ -1119,7 +1120,7 @@ namespace QuickMedia { tabs.push_back(Tab{create_body(), std::make_unique(this, search_page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); tabs.push_back(Tab{create_body(), std::move(search_page), create_search_bar("Search...", 400)}); - auto history_page = std::make_unique(this, tabs.front().page.get(), HistoryType::MANGA); + auto history_page = std::make_unique(this, tabs.back().page.get(), HistoryType::MANGA); tabs.push_back(Tab{create_body(), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); start_tab_index = 1; @@ -1130,7 +1131,7 @@ namespace QuickMedia { tabs.push_back(Tab{create_body(), std::make_unique(this, search_page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); tabs.push_back(Tab{create_body(), std::move(search_page), create_search_bar("Search...", 400)}); - auto history_page = std::make_unique(this, tabs.front().page.get(), HistoryType::MANGA); + auto history_page = std::make_unique(this, tabs.back().page.get(), HistoryType::MANGA); tabs.push_back(Tab{create_body(), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); start_tab_index = 1; @@ -1330,27 +1331,41 @@ namespace QuickMedia { LOGIN }; - static void fill_history_items_from_json(const Json::Value &history_json, BodyItems &history_items) { + static void fill_youtube_history_items_from_json(const Json::Value &history_json, BodyItems &history_items) { assert(history_json.isArray()); - time_t time_now = time(NULL); + std::vector history_json_items; for(const Json::Value &item : history_json) { if(!item.isObject()) continue; - const Json::Value &video_id = item["id"]; + const Json::Value ×tamp = item["timestamp"]; + if(!timestamp.isNumeric()) + continue; + + history_json_items.push_back(&item); + } + + std::sort(history_json_items.begin(), history_json_items.end(), [](const Json::Value *val1, const Json::Value *val2) { + const Json::Value ×tamp1 = (*val1)["timestamp"]; + const Json::Value ×tamp2 = (*val2)["timestamp"]; + return timestamp1.asInt64() > timestamp2.asInt64(); + }); + + time_t time_now = time(NULL); + for(const Json::Value *item : history_json_items) { + const Json::Value &video_id = (*item)["id"]; if(!video_id.isString()) continue; - std::string video_id_str = video_id.asString(); - const Json::Value &title = item["title"]; + const Json::Value &title = (*item)["title"]; if(!title.isString()) continue; - std::string title_str = title.asString(); - const Json::Value ×tamp = item["timestamp"]; - if(!timestamp.isNumeric()) - continue; + const Json::Value ×tamp = (*item)["timestamp"]; + + std::string title_str = title.asString(); + std::string video_id_str = video_id.asString(); auto body_item = BodyItem::create(std::move(title_str)); body_item->url = "https://www.youtube.com/watch?v=" + video_id_str; @@ -1360,32 +1375,28 @@ namespace QuickMedia { body_item->thumbnail_size = mgl::vec2i(192, 108); history_items.push_back(std::move(body_item)); } - - std::reverse(history_items.begin(), history_items.end()); } - static Path get_video_history_filepath(const char *plugin_name) { - Path video_history_dir = get_storage_dir().join("history"); - if(create_directory_recursive(video_history_dir) != 0) { - std::string err_msg = "Failed to create video history directory "; - err_msg += video_history_dir.data; - show_notification("QuickMedia", err_msg.c_str(), Urgency::CRITICAL); + static Path get_history_filepath(const char *plugin_name) { + Path history_dir = get_storage_dir().join("history"); + if(create_directory_recursive(history_dir) != 0) { + show_notification("QuickMedia", "Failed to create history directory " + history_dir.data, Urgency::CRITICAL); exit(1); } - Path video_history_filepath = video_history_dir; - return video_history_filepath.join(plugin_name).append(".json"); + Path history_filepath = history_dir; + return history_filepath.join(plugin_name).append(".json"); } // This is not cached because we could have multiple instances of QuickMedia running the same plugin! // TODO: Find a way to optimize this - Json::Value Program::load_video_history_json() { - Path video_history_filepath = get_video_history_filepath(plugin_name); + Json::Value Program::load_history_json() { + Path history_filepath = get_history_filepath(plugin_name); Json::Value json_result; - FileType file_type = get_file_type(video_history_filepath); + FileType file_type = get_file_type(history_filepath); if(file_type == FileType::REGULAR) { - if(!read_file_as_json(video_history_filepath, json_result) || !json_result.isArray()) { - show_notification("QuickMedia", "Failed to read " + video_history_filepath.data, Urgency::CRITICAL); + if(!read_file_as_json(history_filepath, json_result) || !json_result.isArray()) { + show_notification("QuickMedia", "Failed to read " + history_filepath.data, Urgency::CRITICAL); abort(); } } else { @@ -1406,8 +1417,21 @@ namespace QuickMedia { abort(); } + Json::Value history_json = load_history_json(); + std::unordered_map manga_id_to_thumbnail_url_map; + for(const Json::Value &history_item : history_json) { + const Json::Value &id = history_item["id"]; + const Json::Value &thumbnail_url = history_item["thumbnail_url"]; + + if(!id.isString() || !thumbnail_url.isString()) + continue; + + manga_id_to_thumbnail_url_map[id.asString()] = thumbnail_url.asString(); + } + + // TODO: Remove this once manga history file has been in use for a few months and is filled with history time_t now = time(NULL); - for_files_in_dir_sort_last_modified(content_storage_dir, [&history_items, plugin_name, now](const Path &filepath) { + for_files_in_dir_sort_last_modified(content_storage_dir, [&history_items, plugin_name, &manga_id_to_thumbnail_url_map, now](const Path &filepath) { // This can happen when QuickMedia crashes/is killed while writing to storage. // In that case, the storage wont be corrupt but there will be .tmp files. // TODO: Remove these .tmp files if they exist during startup @@ -1423,6 +1447,7 @@ namespace QuickMedia { // TODO: Manga combined const char *filename = filepath.filename(); + std::string manga_id = base64_url_decode(filename); const Json::Value &manga_name = body["name"]; if(!manga_name.isString()) @@ -1436,20 +1461,26 @@ namespace QuickMedia { body_item->set_description("Last read " + seconds_to_relative_time_str(now - last_modified_time)); body_item->set_description_color(get_theme().faded_text_color); + auto thumbnail_it = manga_id_to_thumbnail_url_map.find(manga_id); + if(thumbnail_it != manga_id_to_thumbnail_url_map.end()) { + body_item->thumbnail_url = thumbnail_it->second; + body_item->thumbnail_size = {101, 141}; + } + if(strcmp(plugin_name, "manganelo") == 0) - body_item->url = "https://manganelo.com/manga/" + base64_url_decode(filename); + body_item->url = "https://manganelo.com/manga/" + manga_id; else if(strcmp(plugin_name, "manganelos") == 0) - body_item->url = "http://manganelos.com/manga/" + base64_url_decode(filename); + body_item->url = "http://manganelos.com/manga/" + manga_id; else if(strcmp(plugin_name, "mangadex") == 0) - body_item->url = base64_url_decode(filename); + body_item->url = manga_id; else if(strcmp(plugin_name, "mangatown") == 0) - body_item->url = "https://mangatown.com/manga/" + base64_url_decode(filename); + body_item->url = "https://mangatown.com/manga/" + manga_id; else if(strcmp(plugin_name, "mangakatana") == 0) - body_item->url = "https://mangakatana.com/manga/" + base64_url_decode(filename); + body_item->url = "https://mangakatana.com/manga/" + manga_id; else if(strcmp(plugin_name, "onimanga") == 0) - body_item->url = "https://onimanga.com/" + base64_url_decode(filename); + body_item->url = "https://onimanga.com/" + manga_id; else if(strcmp(plugin_name, "readm") == 0) - body_item->url = "https://readm.org/manga/" + base64_url_decode(filename); + body_item->url = "https://readm.org/manga/" + manga_id; else fprintf(stderr, "Error: Not implemented: filename to manga chapter list\n"); @@ -1459,7 +1490,7 @@ namespace QuickMedia { } void Program::youtube_get_watch_history(BodyItems &history_items) { - fill_history_items_from_json(load_video_history_json(), history_items); + fill_youtube_history_items_from_json(load_history_json(), history_items); } static void get_body_dimensions(const mgl::vec2i &window_size, SearchBar *search_bar, mgl::vec2f &body_pos, mgl::vec2f &body_size, bool has_tabs = false) { @@ -1494,6 +1525,7 @@ namespace QuickMedia { bool Program::load_manga_content_storage(const char *service_name, const std::string &manga_title, const std::string &manga_url, const std::string &manga_id) { Path content_storage_dir = get_storage_dir().join(service_name); + this->manga_id = manga_id; manga_id_base64 = base64_url_encode(manga_id); content_storage_file = content_storage_dir.join(manga_id_base64); content_storage_json.clear(); @@ -1629,7 +1661,9 @@ namespace QuickMedia { } std::string bookmark_title = body_item->get_title(); - if(bookmark_title.empty()) bookmark_title = body_item->get_author(); + if(bookmark_title.empty()) + bookmark_title = body_item->get_author(); + show_notification("QuickMedia", "Removed " + bookmark_title + " from bookmarks"); removed = true; return true; @@ -2357,12 +2391,10 @@ namespace QuickMedia { return false; } - static int watch_history_get_item_by_id(const Json::Value &video_history_json, const char *id) { - assert(video_history_json.isArray()); + static Json::Value* history_get_item_by_id(Json::Value &history_json, const char *id) { + assert(history_json.isArray()); - int index = -1; - for(const Json::Value &item : video_history_json) { - ++index; + for(Json::Value &item : history_json) { if(!item.isObject()) continue; @@ -2371,10 +2403,10 @@ namespace QuickMedia { continue; if(strcmp(id, id_json.asCString()) == 0) - return index; + return &item; } - return -1; + return nullptr; } enum class WindowFullscreenState { @@ -2924,25 +2956,21 @@ namespace QuickMedia { return; } - Json::Value video_history_json = load_video_history_json(); + Json::Value video_history_json = load_history_json(); - int existing_index = watch_history_get_item_by_id(video_history_json, video_id.c_str()); - if(existing_index != -1) { - Json::Value removed; - /* TODO: Optimize. This is slow */ - video_history_json.removeIndex(existing_index, &removed); - } - time_t time_now = time(NULL); + Json::Value *json_item = history_get_item_by_id(video_history_json, video_id.c_str()); + if(json_item) { + (*json_item)["timestamp"] = (Json::Int64)time_now; + } else { + Json::Value new_content_object(Json::objectValue); + new_content_object["id"] = video_id; + new_content_object["title"] = video_title; + new_content_object["timestamp"] = (Json::Int64)time_now; + video_history_json.append(std::move(new_content_object)); + } - Json::Value new_content_object(Json::objectValue); - new_content_object["id"] = video_id; - new_content_object["title"] = video_title; - new_content_object["timestamp"] = (Json::Int64)time_now; - - video_history_json.append(std::move(new_content_object)); - - Path video_history_filepath = get_video_history_filepath(plugin_name); + Path video_history_filepath = get_history_filepath(plugin_name); save_json_to_file_atomic(video_history_filepath, video_history_json); } }; @@ -3483,6 +3511,28 @@ namespace QuickMedia { } } + void Program::update_manga_history(const std::string &manga_id, const std::string &thumbnail_url) { + Json::Value history_json = load_history_json(); + const time_t time_now = time(NULL); + + Json::Value *json_item = history_get_item_by_id(history_json, manga_id.c_str()); + if(json_item) { + (*json_item)["timestamp"] = (Json::Int64)time_now; + if(!thumbnail_url.empty()) + (*json_item)["thumbnail_url"] = thumbnail_url; + } else { + Json::Value new_content_object(Json::objectValue); + new_content_object["id"] = manga_id; + new_content_object["timestamp"] = (Json::Int64)time_now; + if(!thumbnail_url.empty()) + new_content_object["thumbnail_url"] = thumbnail_url; + history_json.append(std::move(new_content_object)); + } + + Path history_filepath = get_history_filepath(plugin_name); + save_json_to_file_atomic(history_filepath, history_json); + } + void Program::save_manga_progress(MangaImagesPage *images_page, Json::Value &json_chapters, Json::Value &json_chapter, int &latest_read) { image_index = std::max(0, std::min(image_index, num_manga_pages)); @@ -3540,6 +3590,7 @@ namespace QuickMedia { Json::Value json_chapter; int latest_read; save_manga_progress(images_page, json_chapters, json_chapter, latest_read); + update_manga_history(manga_id, images_page->thumbnail_url); if(image_index < num_manga_pages) { std::string error_msg; @@ -3751,6 +3802,7 @@ namespace QuickMedia { if(!save_json_to_file_atomic(content_storage_file, content_storage_json)) { show_notification("QuickMedia", "Failed to save manga progress", Urgency::CRITICAL); } + update_manga_history(manga_id, images_page->thumbnail_url); } } diff --git a/src/plugins/Manga.cpp b/src/plugins/Manga.cpp index 5f0aae7..4401974 100644 --- a/src/plugins/Manga.cpp +++ b/src/plugins/Manga.cpp @@ -24,6 +24,7 @@ namespace QuickMedia { std::shared_ptr MangaChaptersPage::get_bookmark_body_item() { auto body_item = BodyItem::create(content_title); body_item->url = content_url; + body_item->thumbnail_url = thumbnail_url; return body_item; } } \ No newline at end of file diff --git a/src/plugins/MangaCombined.cpp b/src/plugins/MangaCombined.cpp index 0742562..f678e57 100644 --- a/src/plugins/MangaCombined.cpp +++ b/src/plugins/MangaCombined.cpp @@ -122,6 +122,7 @@ namespace QuickMedia { PluginResult MangaCombinedSearchPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { Page *page = (Page*)submit_body_item->userdata; if(!page) return PluginResult::OK; + page->submit_body_item = submit_body_item; return page->submit(title, url, result_tabs); } diff --git a/src/plugins/MangaGeneric.cpp b/src/plugins/MangaGeneric.cpp index e25fd96..0c1ee37 100644 --- a/src/plugins/MangaGeneric.cpp +++ b/src/plugins/MangaGeneric.cpp @@ -380,7 +380,7 @@ namespace QuickMedia { } PluginResult MangaGenericChaptersPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - result_tabs.push_back(Tab{nullptr, std::make_unique(program, content_title, title, url, service_name, website_url, list_page_query, fail_on_http_error), nullptr}); + result_tabs.push_back(Tab{nullptr, std::make_unique(program, content_title, title, url, service_name, website_url, list_page_query, fail_on_http_error, thumbnail_url), nullptr}); return PluginResult::OK; } diff --git a/src/plugins/Mangadex.cpp b/src/plugins/Mangadex.cpp index 8dd6822..88f4c18 100644 --- a/src/plugins/Mangadex.cpp +++ b/src/plugins/Mangadex.cpp @@ -377,7 +377,7 @@ namespace QuickMedia { } PluginResult MangadexChaptersPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - result_tabs.push_back(Tab{nullptr, std::make_unique(program, search_page, content_title, url, title), nullptr}); + result_tabs.push_back(Tab{nullptr, std::make_unique(program, search_page, content_title, url, title, thumbnail_url), nullptr}); return PluginResult::OK; } diff --git a/src/plugins/Manganelo.cpp b/src/plugins/Manganelo.cpp index e5c5719..55f0467 100644 --- a/src/plugins/Manganelo.cpp +++ b/src/plugins/Manganelo.cpp @@ -154,7 +154,7 @@ namespace QuickMedia { } PluginResult ManganeloChaptersPage::submit(const std::string &title, const std::string &url, std::vector &result_tabs) { - result_tabs.push_back(Tab{nullptr, std::make_unique(program, content_title, title, url), nullptr}); + result_tabs.push_back(Tab{nullptr, std::make_unique(program, content_title, title, url, thumbnail_url), nullptr}); return PluginResult::OK; } diff --git a/src/plugins/Page.cpp b/src/plugins/Page.cpp index 34ca889..2e3caf4 100644 --- a/src/plugins/Page.cpp +++ b/src/plugins/Page.cpp @@ -85,16 +85,34 @@ namespace QuickMedia { if(!read_file_as_json(bookmark_path, json_root) || !json_root.isArray()) return PluginResult::OK; + std::vector bookmark_json_items; + for(const Json::Value &item : json_root) { + if(!item.isObject()) + continue; + + const Json::Value ×tamp = item["timestamp"]; + if(!timestamp.isInt64()) + continue; + + bookmark_json_items.push_back(&item); + } + + std::sort(bookmark_json_items.begin(), bookmark_json_items.end(), [](const Json::Value *val1, const Json::Value *val2) { + const Json::Value ×tamp1 = (*val1)["timestamp"]; + const Json::Value ×tamp2 = (*val2)["timestamp"]; + return timestamp1.asInt64() > timestamp2.asInt64(); + }); + const time_t time_now = time(nullptr); - for(const Json::Value &item_json : json_root) { - if(!item_json.isObject()) + for(const Json::Value *item_json : bookmark_json_items) { + if(!item_json->isObject()) continue; - const Json::Value &title_json = item_json["title"]; - const Json::Value &author_json = item_json["author"]; - const Json::Value &url_json = item_json["url"]; - const Json::Value &thumbnail_url_json = item_json["thumbnail_url"]; - const Json::Value ×tamp_json = item_json["timestamp"]; + const Json::Value &title_json = (*item_json)["title"]; + const Json::Value &author_json = (*item_json)["author"]; + const Json::Value &url_json = (*item_json)["url"]; + const Json::Value &thumbnail_url_json = (*item_json)["thumbnail_url"]; + const Json::Value ×tamp_json = (*item_json)["timestamp"]; auto body_item = BodyItem::create(title_json.isString() ? title_json.asString() : ""); if(author_json.isString()) @@ -116,7 +134,6 @@ namespace QuickMedia { result_items.push_back(std::move(body_item)); } - std::reverse(result_items.begin(), result_items.end()); return PluginResult::OK; } } \ No newline at end of file -- cgit v1.2.3