diff options
author | dec05eba <dec05eba@protonmail.com> | 2022-02-12 04:31:44 +0100 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2022-02-12 04:33:00 +0100 |
commit | 74b98bed98aad3e70e8abe51292767ea8a7d109a (patch) | |
tree | ea1558431137f8a1e52f4d550c0438e68e676f6f /src/plugins | |
parent | cc445c60d4806fb462a3efc27bf8d727176f77da (diff) |
Local-manga: show if the latest chapter of a manga has been read
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/LocalManga.cpp | 86 | ||||
-rw-r--r-- | src/plugins/Manga.cpp | 2 |
2 files changed, 79 insertions, 9 deletions
diff --git a/src/plugins/LocalManga.cpp b/src/plugins/LocalManga.cpp index c39752b..1807ca7 100644 --- a/src/plugins/LocalManga.cpp +++ b/src/plugins/LocalManga.cpp @@ -4,7 +4,8 @@ #include "../../include/Theme.hpp" #include "../../include/StringUtils.hpp" #include "../../include/Storage.hpp" -#include <unordered_set> +#include "../../external/cppcodec/base64_url.hpp" +#include <json/value.h> namespace QuickMedia { // Pages are sorted from 1.png to n.png @@ -80,8 +81,60 @@ namespace QuickMedia { return manga_list; } - static std::shared_ptr<BodyItem> local_manga_to_body_item(const LocalManga &local_manga, time_t time_now) { - auto body_item = BodyItem::create(local_manga.name); + static bool has_finished_reading_latest_chapter(const LocalManga &manga, const Json::Value &chapters_json) { + if(manga.chapters.empty()) + return false; + + const Json::Value &chapter_json = chapters_json[manga.chapters.front().name]; + if(!chapter_json.isObject()) + return false; + + const Json::Value ¤t_json = chapter_json["current"]; + const Json::Value &total_json = chapter_json["total"]; + if(!current_json.isInt() || !total_json.isInt()) + return false; + + return current_json.asInt() >= total_json.asInt(); + } + + // TODO: Check if this is too slow with a lot of manga. + // In that case, only save latest read chapter (or newest chapter read) + // into one file with a list of all manga. + static std::unordered_set<std::string> get_manga_finished_reading(const std::vector<LocalManga> &manga_list) { + Path local_manga_config_dir = get_storage_dir().join("local-manga"); + std::unordered_set<std::string> finished_reading; + + for(const LocalManga &local_manga : manga_list) { + std::string manga_name_base64_url = cppcodec::base64_url::encode<std::string>(local_manga.name); + Path manga_progress_filepath = local_manga_config_dir; + manga_progress_filepath.join(manga_name_base64_url); + + Json::Value json_root; + if(!read_file_as_json(manga_progress_filepath, json_root)) + continue; + + if(!json_root.isObject()) + continue; + + const Json::Value &chapters_json = json_root["chapters"]; + if(!chapters_json.isObject()) + continue; + + if(has_finished_reading_latest_chapter(local_manga, chapters_json)) + finished_reading.insert(local_manga.name); + } + return finished_reading; + } + + static std::shared_ptr<BodyItem> local_manga_to_body_item(const LocalManga &local_manga, time_t time_now, bool has_finished_reading) { + std::string title; + if(has_finished_reading) + title = "[Finished reading] "; + title += local_manga.name; + + auto body_item = BodyItem::create(std::move(title)); + if(has_finished_reading) + body_item->set_title_color(mgl::Color(43, 255, 47)); body_item->url = local_manga.name; body_item->set_description("Latest chapter: " + local_manga.chapters.front().name + "\nUpdated " + seconds_to_relative_time_str(time_now - local_manga.modified_time_seconds)); body_item->set_description_color(get_theme().faded_text_color); @@ -94,8 +147,10 @@ namespace QuickMedia { SearchResult LocalMangaSearchPage::search(const std::string &str, BodyItems &result_items) { time_t time_now = time(nullptr); for(const LocalManga &local_manga : manga_list) { - if(string_find_fuzzy_case_insensitive(local_manga.name, str)) - result_items.push_back(local_manga_to_body_item(local_manga, time_now)); + if(string_find_fuzzy_case_insensitive(local_manga.name, str)) { + const bool has_finished_reading = finished_reading_manga.find(local_manga.name) != finished_reading_manga.end(); + result_items.push_back(local_manga_to_body_item(local_manga, time_now, has_finished_reading)); + } } return SearchResult::OK; } @@ -128,13 +183,14 @@ namespace QuickMedia { auto chapters_body = create_body(); chapters_body->set_items(std::move(chapters_items)); - auto chapters_page = std::make_unique<LocalMangaChaptersPage>(program, args.title, args.url, args.thumbnail_url); + auto chapters_page = std::make_unique<LocalMangaChaptersPage>(program, args.url, args.url, args.thumbnail_url); result_tabs.push_back(Tab{std::move(chapters_body), std::move(chapters_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); return PluginResult::OK; } PluginResult LocalMangaSearchPage::lazy_fetch(BodyItems &result_items) { manga_list.clear(); + finished_reading_manga.clear(); if(get_config().local_manga_directory.empty()) { show_notification("QuickMedia", "local_manga_directory config is not set", Urgency::CRITICAL); @@ -148,14 +204,28 @@ namespace QuickMedia { manga_list = get_manga_in_directory(get_config().local_manga_directory); + if(standalone) + finished_reading_manga = get_manga_finished_reading(manga_list); + const time_t time_now = time(nullptr); for(const LocalManga &local_manga : manga_list) { - result_items.push_back(local_manga_to_body_item(local_manga, time_now)); + const bool has_finished_reading = finished_reading_manga.find(local_manga.name) != finished_reading_manga.end(); + result_items.push_back(local_manga_to_body_item(local_manga, time_now, has_finished_reading)); } return PluginResult::OK; } + std::shared_ptr<BodyItem> LocalMangaSearchPage::get_bookmark_body_item(BodyItem *selected_item) { + if(!selected_item) + return nullptr; + + auto body_item = BodyItem::create(selected_item->url); + body_item->url = selected_item->url; + body_item->thumbnail_url = selected_item->thumbnail_url; + return body_item; + } + static std::unordered_set<std::string> get_lines_in_file(const Path &filepath) { std::unordered_set<std::string> lines; @@ -208,7 +278,7 @@ namespace QuickMedia { return PluginResult::OK; } - result_tabs.push_back(Tab{nullptr, std::make_unique<LocalMangaImagesPage>(program, content_title, args.title, args.url, thumbnail_url), nullptr}); + result_tabs.push_back(Tab{nullptr, std::make_unique<LocalMangaImagesPage>(program, content_title, args.url, args.url, thumbnail_url), nullptr}); if(is_program_executable_by_name("automedia")) append_seen_manga_to_automedia_seen(content_url + "/" + args.url); diff --git a/src/plugins/Manga.cpp b/src/plugins/Manga.cpp index 4401974..e4269fe 100644 --- a/src/plugins/Manga.cpp +++ b/src/plugins/Manga.cpp @@ -21,7 +21,7 @@ namespace QuickMedia { load_manga_content_storage(get_service_name(), content_title, content_url, manga_id); } - std::shared_ptr<BodyItem> MangaChaptersPage::get_bookmark_body_item() { + std::shared_ptr<BodyItem> MangaChaptersPage::get_bookmark_body_item(BodyItem*) { auto body_item = BodyItem::create(content_title); body_item->url = content_url; body_item->thumbnail_url = thumbnail_url; |