diff options
Diffstat (limited to 'src/QuickMedia.cpp')
-rw-r--r-- | src/QuickMedia.cpp | 63 |
1 files changed, 52 insertions, 11 deletions
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 1f7629e..cfe4e15 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -1,6 +1,7 @@ #include "../include/QuickMedia.hpp" #include "../plugins/Manganelo.hpp" #include "../plugins/Mangadex.hpp" +#include "../plugins/LocalManga.hpp" #include "../plugins/MangaGeneric.hpp" #include "../plugins/MangaCombined.hpp" #include "../plugins/MediaGeneric.hpp" @@ -79,6 +80,7 @@ static const std::pair<const char*, const char*> valid_plugins[] = { std::make_pair("mangadex", "mangadex_logo.png"), std::make_pair("onimanga", nullptr), std::make_pair("readm", "readm_logo.png"), + std::make_pair("local-manga", nullptr), std::make_pair("manga", nullptr), std::make_pair("youtube", "yt_logo_rgb_dark_small.png"), std::make_pair("peertube", "peertube_logo.png"), @@ -200,8 +202,8 @@ namespace QuickMedia { class HistoryPage : public LazyFetchPage { public: - HistoryPage(Program *program, Page *search_page, HistoryType history_type) : - LazyFetchPage(program), search_page(search_page), history_type(history_type) {} + HistoryPage(Program *program, Page *search_page, HistoryType history_type, bool local_thumbnail = false) : + LazyFetchPage(program), search_page(search_page), history_type(history_type), local_thumbnail(local_thumbnail) {} const char* get_title() const override { return "History"; } PluginResult submit(const SubmitArgs &args, std::vector<Tab> &result_tabs) override { return search_page->submit(args, result_tabs); @@ -212,7 +214,7 @@ namespace QuickMedia { program->youtube_get_watch_history(result_items); break; case HistoryType::MANGA: - program->manga_get_watch_history(program->get_plugin_name(), result_items); + program->manga_get_watch_history(program->get_plugin_name(), result_items, local_thumbnail); break; } return PluginResult::OK; @@ -222,6 +224,7 @@ namespace QuickMedia { private: Page *search_page; HistoryType history_type; + bool local_thumbnail; }; using OptionsPageHandler = std::function<void()>; @@ -279,7 +282,7 @@ namespace QuickMedia { static void usage() { fprintf(stderr, "usage: quickmedia [plugin] [--no-video] [--dir <directory>] [-e <window>] [youtube-url]\n"); fprintf(stderr, "OPTIONS:\n"); - fprintf(stderr, " plugin The plugin to use. Should be either launcher, 4chan, manga, manganelo, manganelos, mangatown, mangakatana, mangadex, readm, onimanga, youtube, peertube, lbry, soundcloud, nyaa.si, matrix, saucenao, hotexamples, anilist, file-manager, stdin, pornhub, spankbang, xvideos or xhamster\n"); + fprintf(stderr, " plugin The plugin to use. Should be either launcher, 4chan, manga, manganelo, manganelos, mangatown, mangakatana, mangadex, readm, onimanga, local-manga, youtube, peertube, lbry, soundcloud, nyaa.si, matrix, saucenao, hotexamples, anilist, file-manager, stdin, pornhub, spankbang, xvideos or xhamster\n"); fprintf(stderr, " --no-video Only play audio when playing a video. Disabled by default\n"); fprintf(stderr, " --upscale-images Upscale low-resolution manga pages using waifu2x-ncnn-vulkan. Disabled by default\n"); fprintf(stderr, " --upscale-images-always Upscale manga pages using waifu2x-ncnn-vulkan, no matter what the original image resolution is. Disabled by default\n"); @@ -296,7 +299,15 @@ namespace QuickMedia { } static bool is_manga_plugin(const char *plugin_name) { - return strcmp(plugin_name, "manga") == 0 || strcmp(plugin_name, "manganelo") == 0 || strcmp(plugin_name, "manganelos") == 0 || strcmp(plugin_name, "mangatown") == 0 || strcmp(plugin_name, "mangakatana") == 0 || strcmp(plugin_name, "mangadex") == 0 || strcmp(plugin_name, "readm") == 0 || strcmp(plugin_name, "onimanga") == 0; + return strcmp(plugin_name, "manga") == 0 + || strcmp(plugin_name, "manganelo") == 0 + || strcmp(plugin_name, "manganelos") == 0 + || strcmp(plugin_name, "mangatown") == 0 + || strcmp(plugin_name, "mangakatana") == 0 + || strcmp(plugin_name, "mangadex") == 0 + || strcmp(plugin_name, "readm") == 0 + || strcmp(plugin_name, "onimanga") == 0 + || strcmp(plugin_name, "local-manga") == 0; } static std::shared_ptr<BodyItem> create_launcher_body_item(const char *title, const char *plugin_name, const std::string &thumbnail_url) { @@ -617,6 +628,10 @@ namespace QuickMedia { resources_root = program_path + "../../../"; } + // Initialize config and theme early to prevent possible race condition on initialize + get_config(); + get_theme(); + set_resource_loader_root_path(resources_root.c_str()); set_use_system_fonts(get_config().use_system_fonts); init_body_themes(); @@ -1041,6 +1056,7 @@ namespace QuickMedia { create_launcher_body_item("AniList", "anilist", resources_root + "images/anilist_logo.png"), create_launcher_body_item("Hot Examples", "hotexamples", ""), create_launcher_body_item("Lbry", "lbry", resources_root + "icons/lbry_launcher.png"), + create_launcher_body_item("Local manga", "local-manga", ""), create_launcher_body_item("Manga (all)", "manga", ""), create_launcher_body_item("Mangadex", "mangadex", resources_root + "icons/mangadex_launcher.png"), create_launcher_body_item("Mangakatana", "mangakatana", resources_root + "icons/mangakatana_launcher.png"), @@ -1134,6 +1150,16 @@ namespace QuickMedia { tabs.push_back(Tab{create_body(), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); start_tab_index = 1; + } else if(strcmp(plugin_name, "local-manga") == 0) { + auto search_page = std::make_unique<LocalMangaSearchPage>(this, true); + + tabs.push_back(Tab{create_body(), std::make_unique<BookmarksPage>(this, search_page.get(), true), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + tabs.push_back(Tab{create_body(), std::move(search_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + + auto history_page = std::make_unique<HistoryPage>(this, tabs.back().page.get(), HistoryType::MANGA, true); + tabs.push_back(Tab{create_body(), std::move(history_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)}); + + start_tab_index = 1; } else if(strcmp(plugin_name, "manga") == 0) { auto mangadex = std::make_unique<MangadexSearchPage>(this); upgrade_legacy_mangadex_ids(this, mangadex.get()); @@ -1149,6 +1175,7 @@ namespace QuickMedia { add_onimanga_handlers(onimanga.get()); auto readm = std::make_unique<MangaGenericSearchPage>(this, "readm", "https://readm.org/"); add_readm_handlers(readm.get()); + auto local_manga = std::make_unique<LocalMangaSearchPage>(this, false); // TODO: Use async task pool std::vector<MangaPlugin> pages; @@ -1160,6 +1187,9 @@ namespace QuickMedia { pages.push_back({std::move(readm), "Readm", "readm"}); pages.push_back({std::move(mangadex), "Mangadex", "mangadex"}); + if(!get_config().local_manga_directory.empty()) + pages.push_back({std::move(local_manga), "Local manga", "local-manga", true}); + tabs.push_back(Tab{create_body(), std::make_unique<MangaCombinedSearchPage>(this, std::move(pages)), create_search_bar("Search...", 400)}); } else if(strcmp(plugin_name, "nyaa.si") == 0) { auto categories_nyaa_si_body = create_body(); @@ -1408,7 +1438,7 @@ namespace QuickMedia { window.set_clipboard(str); } - void Program::manga_get_watch_history(const char *plugin_name, BodyItems &history_items) { + void Program::manga_get_watch_history(const char *plugin_name, BodyItems &history_items, bool local_thumbnail) { // TOOD: Make generic, instead of checking for plugin Path content_storage_dir = get_storage_dir().join(plugin_name); if(create_directory_recursive(content_storage_dir) != 0) { @@ -1430,7 +1460,7 @@ namespace QuickMedia { // 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, &manga_id_to_thumbnail_url_map, 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, local_thumbnail](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 @@ -1464,6 +1494,7 @@ namespace QuickMedia { if(thumbnail_it != manga_id_to_thumbnail_url_map.end()) { body_item->thumbnail_url = thumbnail_it->second; body_item->thumbnail_size = {101, 141}; + body_item->thumbnail_is_local = local_thumbnail; } if(strcmp(plugin_name, "manganelo") == 0) @@ -1480,6 +1511,8 @@ namespace QuickMedia { body_item->url = "https://onimanga.com/" + manga_id; else if(strcmp(plugin_name, "readm") == 0) body_item->url = "https://readm.org/manga/" + manga_id; + else if(strcmp(plugin_name, "local-manga") == 0) + body_item->url = manga_id; else fprintf(stderr, "Error: Not implemented: filename to manga chapter list\n"); @@ -3434,10 +3467,18 @@ namespace QuickMedia { Path image_filepath_tmp(image_filepath.data + ".tmpz"); // TODO: Move to page - size_t file_size = 0; - if(download_to_file(url, image_filepath_tmp.data, extra_args, true, cloudflare_bypass) != 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; + if(images_page->is_local()) { + int res = symlink(url.c_str(), image_filepath_tmp.data.c_str()); + if(res == -1 && errno != EEXIST) { + show_notification("QuickMedia", "Failed to symlink " + image_filepath_tmp.data + " to " + url); + return true; + } + } else { + size_t file_size = 0; + if(download_to_file(url, image_filepath_tmp.data, extra_args, true, cloudflare_bypass) != 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; + } } bool rename_immediately = true; |