aboutsummaryrefslogtreecommitdiff
path: root/src/plugins
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2022-02-12 13:42:04 +0100
committerdec05eba <dec05eba@protonmail.com>2022-02-12 13:42:04 +0100
commita8d597d59e347a80b109060ec8c7a88827487f57 (patch)
tree27ed53ec000739a0b6b21355e5a936ae6e55ba39 /src/plugins
parent74b98bed98aad3e70e8abe51292767ea8a7d109a (diff)
Local manga: add ctrl+r to search page to mark manga as read/unread
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/LocalManga.cpp113
1 files changed, 112 insertions, 1 deletions
diff --git a/src/plugins/LocalManga.cpp b/src/plugins/LocalManga.cpp
index 1807ca7..8344527 100644
--- a/src/plugins/LocalManga.cpp
+++ b/src/plugins/LocalManga.cpp
@@ -5,9 +5,12 @@
#include "../../include/StringUtils.hpp"
#include "../../include/Storage.hpp"
#include "../../external/cppcodec/base64_url.hpp"
+#include "../../include/QuickMedia.hpp"
#include <json/value.h>
namespace QuickMedia {
+ static const mgl::Color finished_reading_color = mgl::Color(43, 255, 47);
+
// Pages are sorted from 1.png to n.png
static std::vector<LocalMangaPage> get_images_in_manga(const Path &directory) {
std::vector<LocalMangaPage> page_list;
@@ -81,6 +84,94 @@ namespace QuickMedia {
return manga_list;
}
+ enum class ReadStatus {
+ READ,
+ UNREAD
+ };
+
+ // Returns the new read status
+ static bool toggle_read_save_to_file(Program *program, const std::string &manga_name, const std::string &thumbnail_url, ReadStatus &read_status) {
+ if(get_config().local_manga_directory.empty()) {
+ show_notification("QuickMedia", "local_manga_directory config is not set", Urgency::CRITICAL);
+ return false;
+ }
+
+ if(get_file_type(get_config().local_manga_directory) != FileType::DIRECTORY) {
+ show_notification("QuickMedia", "local_manga_directory config is not set to a valid directory", Urgency::CRITICAL);
+ return false;
+ }
+
+ Path manga_url = Path(get_config().local_manga_directory).join(manga_name);
+ std::vector<LocalMangaChapter> chapters = get_chapters_in_manga(manga_url);
+ if(chapters.empty() || chapters.front().pages.empty())
+ return false;
+
+ Path content_storage_dir = get_storage_dir().join("local-manga");
+ if(create_directory_recursive(content_storage_dir) != 0) {
+ show_notification("QuickMedia", "Failed to create directory: " + content_storage_dir.data, Urgency::CRITICAL);
+ return false;
+ }
+
+ Path content_storage_file = content_storage_dir;
+ content_storage_file.join(cppcodec::base64_url::encode<std::string>(manga_name));
+ Json::Value content_storage_json;
+
+ bool result = true;
+ FileType file_type = get_file_type(content_storage_file);
+ if(file_type == FileType::REGULAR) {
+ result = read_file_as_json(content_storage_file, content_storage_json) && content_storage_json.isObject();
+ if(!result) {
+ show_notification("QuickMedia", "Failed to read " + content_storage_file.data, Urgency::CRITICAL);
+ return false;
+ }
+ } else {
+ result = true;
+ }
+
+ if(!content_storage_json.isObject())
+ content_storage_json = Json::Value(Json::objectValue);
+
+ content_storage_json["name"] = manga_name;
+ content_storage_json["url"] = manga_name;
+
+ Json::Value *chapters_json = &content_storage_json["chapters"];
+ if(!chapters_json->isObject()) {
+ content_storage_json["chapters"] = Json::Value(Json::objectValue);
+ chapters_json = &content_storage_json["chapters"];
+ }
+
+ const LocalMangaChapter &latest_chapter = chapters.front();
+ Json::Value *chapter_json = &(*chapters_json)[latest_chapter.name];
+ if(!chapter_json->isObject()) {
+ (*chapters_json)[latest_chapter.name] = Json::Value(Json::objectValue);
+ chapters_json = &(*chapters_json)[latest_chapter.name];
+ }
+
+ bool read = false;
+ const Json::Value &current_json = (*chapter_json)["current"];
+ const Json::Value &total_json = (*chapter_json)["total"];
+ if(current_json.isInt() && total_json.isInt() && current_json.asInt() >= total_json.asInt()) {
+ chapters_json->removeMember(latest_chapter.name);
+ read = true;
+ } else {
+ (*chapter_json)["current"] = (int)latest_chapter.pages.size();
+ (*chapter_json)["total"] = (int)latest_chapter.pages.size();
+ (*chapter_json)["url"] = latest_chapter.name;
+ read = false;
+ }
+
+ if(!save_json_to_file_atomic(content_storage_file, content_storage_json)) {
+ show_notification("QuickMedia", std::string("Failed to mark manga as ") + (read ? "unread" : "read"), Urgency::CRITICAL);
+ return false;
+ }
+
+ read_status = (read ? ReadStatus::UNREAD : ReadStatus::READ);
+ if(read_status == ReadStatus::READ)
+ program->update_manga_history(manga_name, thumbnail_url);
+
+ return true;
+ }
+
static bool has_finished_reading_latest_chapter(const LocalManga &manga, const Json::Value &chapters_json) {
if(manga.chapters.empty())
return false;
@@ -134,7 +225,7 @@ namespace QuickMedia {
auto body_item = BodyItem::create(std::move(title));
if(has_finished_reading)
- body_item->set_title_color(mgl::Color(43, 255, 47));
+ body_item->set_title_color(finished_reading_color);
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);
@@ -226,6 +317,26 @@ namespace QuickMedia {
return body_item;
}
+ void LocalMangaSearchPage::toggle_read(BodyItem *selected_item) {
+ if(!selected_item)
+ return;
+
+ ReadStatus read_status;
+ if(!toggle_read_save_to_file(program, selected_item->url, selected_item->thumbnail_url, read_status))
+ return;
+
+ mgl::Color color = get_theme().text_color;
+ std::string title;
+ if(read_status == ReadStatus::READ) {
+ title = "[Finished reading] ";
+ color = finished_reading_color;
+ }
+ title += selected_item->url;
+
+ selected_item->set_title(std::move(title));
+ selected_item->set_title_color(color);
+ }
+
static std::unordered_set<std::string> get_lines_in_file(const Path &filepath) {
std::unordered_set<std::string> lines;