aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-04-16 23:36:37 +0200
committerdec05eba <dec05eba@protonmail.com>2021-04-16 23:36:37 +0200
commit78f01f5d041ba291aca05f768bb71eba71ebb58e (patch)
treee63c4992ff642813770f5ac093fa0eb57e69eb97
parent1376a92ef6d6a6418efefbcde5e01d1958e52fd5 (diff)
Add a combined manga search page, highlight urls ending with ?
-rw-r--r--README.md2
-rw-r--r--TODO3
-rw-r--r--plugins/MangaCombined.hpp27
-rw-r--r--plugins/Manganelo.hpp1
-rw-r--r--src/NetUtils.cpp6
-rw-r--r--src/QuickMedia.cpp36
-rw-r--r--src/plugins/MangaCombined.cpp55
-rw-r--r--tests/main.cpp5
8 files changed, 123 insertions, 12 deletions
diff --git a/README.md b/README.md
index 771c3d0..0368766 100644
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Cache is stored under `$HOME/.cache/quickmedia`.
```
usage: quickmedia <plugin> [--use-system-mpv-config] [--dir <directory>] [-e <window>]
OPTIONS:
- plugin The plugin to use. Should be either launcher, 4chan, manganelo, manganelos, mangatown, mangakatana, mangadex, youtube, spotify, soundcloud, nyaa.si, matrix, file-manager or stdin
+ plugin The plugin to use. Should be either launcher, 4chan, manga, manganelo, manganelos, mangatown, mangakatana, mangadex, youtube, spotify, soundcloud, nyaa.si, matrix, file-manager or stdin
--no-video Only play audio when playing a video. Disabled by default
--use-system-mpv-config Use system mpv config instead of no config. Disabled by default
--upscale-images Upscale low-resolution manga pages using waifu2x-ncnn-vulkan. Disabled by default
diff --git a/TODO b/TODO
index b29e434..c1d6fc9 100644
--- a/TODO
+++ b/TODO
@@ -133,4 +133,5 @@ Convert nyaa.si/spotify/soundcloud date from ISO date string to local time.
When ui is scaled then the predicted thumbnail size will be wrong since its scaled in Body but not in the plugins where they are requested.
Check if get_page handlers in pages need to check if next batch is valid. If the server returns empty next batch we shouldn't fetch the first page...
Cloudflare kicks in when downloading manga on manganelo.. figure out a way to bypass it. This doesn't seem to happen when using python requests as is done in AutoMedia.
-Replace cppcodec with another library for base64 url encoding/decoding. Its way too large for what it does. \ No newline at end of file
+Replace cppcodec with another library for base64 url encoding/decoding. Its way too large for what it does.
+Add a combined manga plugin that allows you to search for manga across all manga plugins. \ No newline at end of file
diff --git a/plugins/MangaCombined.hpp b/plugins/MangaCombined.hpp
new file mode 100644
index 0000000..b9627fe
--- /dev/null
+++ b/plugins/MangaCombined.hpp
@@ -0,0 +1,27 @@
+#pragma once
+
+#include "Manga.hpp"
+#include <vector>
+#include <map>
+
+namespace QuickMedia {
+ struct MangaPlugin {
+ std::unique_ptr<Page> page;
+ std::string title;
+ std::string service_name;
+ std::string logo_path;
+ };
+
+ class MangaCombinedSearchPage : public Page {
+ public:
+ MangaCombinedSearchPage(Program *program, std::vector<MangaPlugin> search_pages);
+ const char* get_title() const override { return "All"; }
+ bool search_is_filter() override { return false; }
+ SearchResult search(const std::string &str, BodyItems &result_items) override;
+ PluginResult get_page(const std::string &str, int page, BodyItems &result_items) override;
+ PluginResult submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) override;
+ sf::Vector2i get_thumbnail_max_size() override { return sf::Vector2i(101, 141); };
+ private:
+ std::vector<MangaPlugin> search_pages;
+ };
+} \ No newline at end of file
diff --git a/plugins/Manganelo.hpp b/plugins/Manganelo.hpp
index 530a1f2..ca44e05 100644
--- a/plugins/Manganelo.hpp
+++ b/plugins/Manganelo.hpp
@@ -1,7 +1,6 @@
#pragma once
#include "Manga.hpp"
-#include <functional>
namespace QuickMedia {
class ManganeloSearchPage : public Page {
diff --git a/src/NetUtils.cpp b/src/NetUtils.cpp
index 8bb5a0e..3539d46 100644
--- a/src/NetUtils.cpp
+++ b/src/NetUtils.cpp
@@ -1617,12 +1617,12 @@ namespace QuickMedia {
contains_dot = true;
}
- if(url_start != std::string::npos && !is_valid_url && contains_dot && (is_whitespace(c) || c == '/' || c == ',' || c == ':' || c == ')' || c == '\0' || (c == '.' && i == str.size()))) {
+ if(url_start != std::string::npos && !is_valid_url && contains_dot && (is_whitespace(c) || c == '/' || c == ',' || c == ':' || c == '?' || c == ')' || c == '\0' || (c == '.' && i == str.size()))) {
size_t tld_end = i - 1;
char prev_char = str[i - 1];
// We want to remove the last . or , because the string could contain for example "click on this link: example.com. There you can..."
// and we want those links to work, I guess?
- if(prev_char == '.' || prev_char == ',' || prev_char == ':')
+ if(prev_char == '.' || prev_char == ',' || prev_char == ':' || prev_char == '?')
--tld_end;
else if(prev_char == ')' && parentheses_depth != 0)
--tld_end;
@@ -1669,7 +1669,7 @@ namespace QuickMedia {
char prev_char = str[i - 1];
// We want to remove the last . or , because the string could contain for example "click on this link: example.com. There you can..."
// and we want those links to work, I guess?
- if(prev_char == '.' || prev_char == ',' || prev_char == ':')
+ if(prev_char == '.' || prev_char == ',' || prev_char == ':' || prev_char == '?')
--url_length;
else if(prev_char == ')' && parentheses_depth != 0)
--url_length;
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index 5fcddba..0f69f85 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -2,6 +2,7 @@
#include "../plugins/Manganelo.hpp"
#include "../plugins/Mangadex.hpp"
#include "../plugins/MangaGeneric.hpp"
+#include "../plugins/MangaCombined.hpp"
#include "../plugins/Youtube.hpp"
#include "../plugins/Pornhub.hpp"
#include "../plugins/Spankbang.hpp"
@@ -64,6 +65,7 @@ static const std::pair<const char*, const char*> valid_plugins[] = {
std::make_pair("mangatown", "mangatown_logo.png"),
std::make_pair("mangakatana", "mangakatana_logo.png"),
std::make_pair("mangadex", "mangadex_logo.png"),
+ std::make_pair("manga", nullptr),
std::make_pair("youtube", "yt_logo_rgb_dark_small.png"),
std::make_pair("spotify", "spotify_logo.png"),
std::make_pair("soundcloud", "soundcloud_logo.png"),
@@ -421,7 +423,7 @@ namespace QuickMedia {
static void usage() {
fprintf(stderr, "usage: quickmedia <plugin> [--no-video] [--use-system-mpv-config] [--dir <directory>] [-e <window>]\n");
fprintf(stderr, "OPTIONS:\n");
- fprintf(stderr, " plugin The plugin to use. Should be either launcher, 4chan, manganelo, manganelos, mangatown, mangakatana, mangadex, pornhub, spankbang, youtube, spotify, soundcloud, nyaa.si, matrix, file-manager or stdin\n");
+ fprintf(stderr, " plugin The plugin to use. Should be either launcher, 4chan, manga, manganelo, manganelos, mangatown, mangakatana, mangadex, pornhub, spankbang, youtube, spotify, soundcloud, nyaa.si, matrix, file-manager or stdin\n");
fprintf(stderr, " --no-video Only play audio when playing a video. Disabled by default\n");
fprintf(stderr, " --use-system-mpv-config Use system mpv config instead of no config. Disabled by default\n");
fprintf(stderr, " --upscale-images Upscale low-resolution manga pages using waifu2x-ncnn-vulkan. Disabled by default\n");
@@ -436,16 +438,18 @@ namespace QuickMedia {
}
static bool is_manga_plugin(const char *plugin_name) {
- return 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;
+ 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;
}
static std::shared_ptr<BodyItem> create_launcher_body_item(const char *title, const char *plugin_name, const std::string &thumbnail_url) {
auto body_item = BodyItem::create(title);
body_item->url = plugin_name;
- body_item->thumbnail_url = thumbnail_url;
- body_item->thumbnail_is_local = true;
- body_item->thumbnail_size.x = 32;
- body_item->thumbnail_size.y = 32;
+ if(!thumbnail_url.empty()) {
+ body_item->thumbnail_url = thumbnail_url;
+ body_item->thumbnail_is_local = true;
+ body_item->thumbnail_size.x = 32;
+ body_item->thumbnail_size.y = 32;
+ }
return body_item;
}
@@ -775,6 +779,7 @@ namespace QuickMedia {
if(strcmp(plugin_name, "launcher") == 0) {
auto pipe_body = create_body();
pipe_body->items.push_back(create_launcher_body_item("4chan", "4chan", resources_root + "icons/4chan_launcher.png"));
+ pipe_body->items.push_back(create_launcher_body_item("Manga (all)", "manga", ""));
pipe_body->items.push_back(create_launcher_body_item("Mangadex", "mangadex", resources_root + "icons/mangadex_launcher.png"));
pipe_body->items.push_back(create_launcher_body_item("Mangakatana", "mangakatana", resources_root + "icons/mangakatana_launcher.png"));
pipe_body->items.push_back(create_launcher_body_item("Manganelo", "manganelo", resources_root + "icons/manganelo_launcher.png"));
@@ -833,6 +838,23 @@ namespace QuickMedia {
auto search_bar = create_search_bar("Search...", SEARCH_DELAY_FILTER);
auto history_page = std::make_unique<HistoryPage>(this, tabs.front().page.get(), search_bar.get(), HistoryType::MANGA);
tabs.push_back(Tab{std::move(history_body), std::move(history_page), std::move(search_bar)});
+ } else if(strcmp(plugin_name, "manga") == 0) {
+ auto manganelo = std::make_unique<ManganeloSearchPage>(this);
+ auto manganelos = std::make_unique<MangaGenericSearchPage>(this, plugin_name, nullptr);
+ add_manganelos_handlers(manganelos.get());
+ auto mangatown = std::make_unique<MangaGenericSearchPage>(this, plugin_name, "https://www.mangatown.com");
+ add_mangatown_handlers(mangatown.get());
+ auto mangakatana = std::make_unique<MangaGenericSearchPage>(this, plugin_name, "https://mangakatana.com", false);
+ add_mangakatana_handlers(mangakatana.get());
+
+ std::vector<MangaPlugin> pages;
+ pages.push_back({std::move(manganelo), "Manganelo", "manganelo", resources_root + "images/" + get_plugin_logo_name("manganelo")});
+ pages.push_back({std::move(manganelos), "Manganelos", "manganelos", resources_root + "images/" + get_plugin_logo_name("manganelos")});
+ pages.push_back({std::move(mangatown), "Mangatown", "mangatown", resources_root + "images/" + get_plugin_logo_name("mangatown")});
+ pages.push_back({std::move(mangakatana), "Mangakatana", "mangakatana", resources_root + "images/" + get_plugin_logo_name("mangakatana")});
+ // TODO: Add mangadex
+
+ 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 category_page = std::make_unique<NyaaSiCategoryPage>(this);
auto categories_body = create_body();
@@ -1087,6 +1109,8 @@ namespace QuickMedia {
return true;
}
+ // TODO: Manga combined
+
auto filename = filepath.filename();
const Json::Value &manga_name = body["name"];
if(!filename.empty() && manga_name.isString()) {
diff --git a/src/plugins/MangaCombined.cpp b/src/plugins/MangaCombined.cpp
new file mode 100644
index 0000000..8b989fb
--- /dev/null
+++ b/src/plugins/MangaCombined.cpp
@@ -0,0 +1,55 @@
+#include "../../plugins/MangaCombined.hpp"
+
+namespace QuickMedia {
+ MangaCombinedSearchPage::MangaCombinedSearchPage(Program *program, std::vector<MangaPlugin> search_pages) :
+ Page(program), search_pages(std::move(search_pages))
+ {
+
+ }
+
+ SearchResult MangaCombinedSearchPage::search(const std::string &str, BodyItems &result_items) {
+ for(auto &search_page : search_pages) {
+ BodyItems search_page_body_items;
+ search_page.page->search(str, search_page_body_items);
+ if(search_page_body_items.empty())
+ continue;
+
+ auto title_item = BodyItem::create("");
+ title_item->set_author("======================== " + search_page.title + " ========================");
+ title_item->url = search_page.service_name;
+
+ result_items.push_back(std::move(title_item));
+ for(auto &new_body_item : search_page_body_items) {
+ new_body_item->userdata = search_page.page.get();
+ }
+ result_items.insert(result_items.end(), std::move_iterator(search_page_body_items.begin()), std::move_iterator(search_page_body_items.end()));
+ }
+ return SearchResult::OK;
+ }
+
+ PluginResult MangaCombinedSearchPage::get_page(const std::string &str, int page, BodyItems &result_items) {
+ for(auto &search_page : search_pages) {
+ BodyItems search_page_body_items;
+ search_page.page->get_page(str, page, search_page_body_items);
+ if(search_page_body_items.empty())
+ continue;
+
+ auto title_item = BodyItem::create("");
+ title_item->set_author("======================== " + search_page.title + " ========================");
+ title_item->url = search_page.service_name;
+
+ result_items.push_back(std::move(title_item));
+ for(auto &new_body_item : search_page_body_items) {
+ new_body_item->userdata = search_page.page.get();
+ }
+ result_items.insert(result_items.end(), std::move_iterator(search_page_body_items.begin()), std::move_iterator(search_page_body_items.end()));
+ }
+ return PluginResult::OK;
+ }
+
+ PluginResult MangaCombinedSearchPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) {
+ Page *page = (Page*)submit_body_item->userdata;
+ if(!page) return PluginResult::OK;
+ return page->submit(title, url, result_tabs);
+ }
+} \ No newline at end of file
diff --git a/tests/main.cpp b/tests/main.cpp
index 306cdf2..ca09d4c 100644
--- a/tests/main.cpp
+++ b/tests/main.cpp
@@ -33,6 +33,11 @@ int main() {
assert_equals(urls.size(), 1);
assert_equals(urls[0], "example.com");
+ str = "is it example.com? or not?";
+ urls = QuickMedia::ranges_get_strings(str, QuickMedia::extract_urls(str));
+ assert_equals(urls.size(), 1);
+ assert_equals(urls[0], "example.com");
+
str = "these. are. not. websites.";
urls = QuickMedia::ranges_get_strings(str, QuickMedia::extract_urls(str));
assert_equals(urls.size(), 0);