aboutsummaryrefslogtreecommitdiff
path: root/src/QuickMedia.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/QuickMedia.cpp')
-rw-r--r--src/QuickMedia.cpp63
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;