aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2021-05-06 13:31:21 +0200
committerdec05eba <dec05eba@protonmail.com>2021-05-06 13:31:21 +0200
commit75ca528807ae0eb77d3d11ab6075e256d0bfadd2 (patch)
tree820a857aadf5fdaf1305c41233ae9a5a240ef990
parente66d24f74d5458241d869fb3df42b4f2a2ea69f4 (diff)
Add saucenao
-rw-r--r--README.md6
m---------depends/html-search0
-rw-r--r--include/QuickMedia.hpp5
-rw-r--r--plugins/Saucenao.hpp18
-rw-r--r--src/QuickMedia.cpp59
-rw-r--r--src/plugins/Saucenao.cpp56
6 files changed, 131 insertions, 13 deletions
diff --git a/README.md b/README.md
index 537b233..8dafdbf 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
# QuickMedia
A dmenu-inspired native client for web services.
-Currently supported web services: `youtube`, `spotify (podcasts)`, `soundcloud`, `nyaa.si`, `manganelo`, `manganelos`, `mangatown`, `mangakatana`, `mangadex`, `readm`, `4chan`, `matrix` and _others_.\
+Currently supported web services: `youtube`, `spotify (podcasts)`, `soundcloud`, `nyaa.si`, `manganelo`, `manganelos`, `mangatown`, `mangakatana`, `mangadex`, `readm`, `4chan`, `matrix`, `saucenao` and _others_.\
**Note:** file-manager is early in progress.\
Config data, including manga progress is stored under `$HOME/.config/quickmedia`.\
Cache is stored under `$HOME/.cache/quickmedia`.
@@ -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, manga, manganelo, manganelos, mangatown, mangakatana, mangadex, readm, 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, readm, youtube, spotify, soundcloud, nyaa.si, matrix, saucenao, 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
@@ -53,7 +53,7 @@ Press `I` to begin writing a message in a matrix room, press `ESC` to cancel.\
Press `R` to reply to a message on matrix, press `ESC` to cancel.\
Press `E` to edit a message on matrix, press `ESC` to cancel. Currently only works for your own messages.\
Press `Ctrl + D` to delete a message on matrix. Currently deleting a message only deletes the event, so if you delete an edit then the original message wont be deleted.\
-Press `Ctrl + C` to copy the message of the selected item in matrix to the clipboard.\
+Press `Ctrl + C` to copy the text of the selected item to the clipboard.\
Press `U` in matrix or in a 4chan thread to bring up the file manager to choose a file to upload.\
Press `Ctrl + V` to upload media to room in matrix if the clipboard contains a valid absolute filepath.\
Press `Ctrl + D` to remove the file that was previously selected with `U` in a 4chan thread.\
diff --git a/depends/html-search b/depends/html-search
-Subproject 0578bfd08637d3e113d28507ea73fa9a649f2f2
+Subproject 3408efcc9d379d8ce8eb8c29db327e436ee5adb
diff --git a/include/QuickMedia.hpp b/include/QuickMedia.hpp
index 492003f..cea9b88 100644
--- a/include/QuickMedia.hpp
+++ b/include/QuickMedia.hpp
@@ -7,6 +7,8 @@
#include "Tab.hpp"
#include "MessageQueue.hpp"
#include "AsyncTask.hpp"
+#include "../plugins/Plugin.hpp"
+#include "../plugins/FileManager.hpp"
#include <vector>
#include <memory>
#include <SFML/Graphics/Font.hpp>
@@ -17,7 +19,6 @@
#include <future>
#include <thread>
#include <stack>
-#include "../plugins/Plugin.hpp"
#include <X11/Xlib.h>
#include <X11/Xatom.h>
@@ -99,7 +100,7 @@ namespace QuickMedia {
Json::Value load_video_history_json();
private:
void init(Window parent_window);
- void load_plugin_by_name(std::vector<Tab> &tabs, const char *start_dir, int &start_tab_index);
+ void load_plugin_by_name(std::vector<Tab> &tabs, const char *start_dir, int &start_tab_index, FileManagerMimeType fm_mime_type);
// Returns true if the window was closed
bool handle_window_close();
void base_event_handler(sf::Event &event, PageType previous_page, Body *body, SearchBar *search_bar, bool handle_key_press = true, bool handle_searchbar = true);
diff --git a/plugins/Saucenao.hpp b/plugins/Saucenao.hpp
new file mode 100644
index 0000000..a5aadf9
--- /dev/null
+++ b/plugins/Saucenao.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "Page.hpp"
+
+namespace QuickMedia {
+ class SaucenaoPage : public LazyFetchPage {
+ public:
+ SaucenaoPage(Program *program, const std::string &upload_filepath) : LazyFetchPage(program), upload_filepath(upload_filepath) {}
+ const char* get_title() const override { return "SauceNAO"; }
+ PluginResult submit(const std::string&, const std::string&, std::vector<Tab>&) override {
+ return PluginResult::OK;
+ }
+ PluginResult lazy_fetch(BodyItems &result_items) override;
+ bool is_single_page() const override { return true; }
+ private:
+ std::string upload_filepath;
+ };
+} \ No newline at end of file
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index 594b93a..c9789cf 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -13,6 +13,7 @@
#include "../plugins/Soundcloud.hpp"
#include "../plugins/FileManager.hpp"
#include "../plugins/Pipe.hpp"
+#include "../plugins/Saucenao.hpp"
#include "../include/Scale.hpp"
#include "../include/Program.hpp"
#include "../include/VideoPlayer.hpp"
@@ -76,7 +77,8 @@ static const std::pair<const char*, const char*> valid_plugins[] = {
std::make_pair("mastodon", "pleroma_logo.png"),
std::make_pair("pleroma", "pleroma_logo.png"),
std::make_pair("file-manager", nullptr),
- std::make_pair("stdin", nullptr)
+ std::make_pair("stdin", nullptr),
+ std::make_pair("saucenao", nullptr)
};
static const char* get_plugin_logo_name(const char *plugin_name) {
@@ -301,12 +303,12 @@ 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, manga, manganelo, manganelos, mangatown, mangakatana, mangadex, readm, youtube, spotify, soundcloud, nyaa.si, matrix, 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, youtube, spotify, soundcloud, nyaa.si, matrix, saucenao, 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, " --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");
fprintf(stderr, " --upscale-images-always Upscale manga pages using waifu2x-ncnn-vulkan, no matter what the original image resolution is. Disabled by default\n");
- fprintf(stderr, " --dir <directory> Set the start directory when using file-manager\n");
+ fprintf(stderr, " --dir <directory> Set the start directory when using file-manager. Default is the user home directory\n");
fprintf(stderr, " -e <window> Embed QuickMedia into another window\n");
fprintf(stderr, "EXAMPLES:\n");
fprintf(stderr, " quickmedia launcher\n");
@@ -450,10 +452,20 @@ namespace QuickMedia {
return -1;
}
+ Path home_dir = get_home_dir();
+ if(!start_dir)
+ start_dir = home_dir.data.c_str();
+
int start_tab_index = 0;
+ FileManagerMimeType fm_mine_type = FILE_MANAGER_MIME_TYPE_ALL;
init(parent_window);
- load_plugin_by_name(tabs, start_dir, start_tab_index);
+ bool is_saucenao = (strcmp(plugin_name, "saucenao") == 0);
+ if(is_saucenao) {
+ plugin_name = "file-manager";
+ fm_mine_type = FILE_MANAGER_MIME_TYPE_IMAGE;
+ }
+ load_plugin_by_name(tabs, start_dir, start_tab_index, fm_mine_type);
while(!tabs.empty() || matrix) {
if(matrix) {
@@ -473,7 +485,10 @@ namespace QuickMedia {
if(strcmp(plugin_name, "launcher") == 0) {
plugin_name = pipe_selected_text.c_str();
- load_plugin_by_name(tabs, start_dir, start_tab_index);
+ load_plugin_by_name(tabs, start_dir, start_tab_index, fm_mine_type);
+ } else if(strcmp(plugin_name, "file-manager") == 0 && is_saucenao && !selected_files.empty()) {
+ plugin_name = "saucenao";
+ load_plugin_by_name(tabs, start_dir, start_tab_index, fm_mine_type);
}
}
@@ -787,7 +802,7 @@ namespace QuickMedia {
.related_media_thumbnail_handler({{"//img", "src", "/thumb-"}});
}
- void Program::load_plugin_by_name(std::vector<Tab> &tabs, const char *start_dir, int &start_tab_index) {
+ void Program::load_plugin_by_name(std::vector<Tab> &tabs, const char *start_dir, int &start_tab_index, FileManagerMimeType fm_mime_type) {
if(!plugin_name || plugin_name[0] == '\0')
return;
@@ -898,7 +913,7 @@ namespace QuickMedia {
boards_page->get_boards(boards_body->items);
tabs.push_back(Tab{std::move(boards_body), std::move(boards_page), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
} else if(strcmp(plugin_name, "file-manager") == 0) {
- auto file_manager_page = std::make_unique<FileManagerPage>(this);
+ auto file_manager_page = std::make_unique<FileManagerPage>(this, fm_mime_type);
if(start_dir && !file_manager_page->set_current_directory(start_dir)) {
fprintf(stderr, "Invalid directory provided with --dir: %s\n", start_dir);
exit_code = -3;
@@ -911,6 +926,8 @@ namespace QuickMedia {
auto pipe_body = create_body();
PipePage::load_body_items_from_stdin(pipe_body->items);
tabs.push_back(Tab{std::move(pipe_body), std::make_unique<PipePage>(this), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
+ } else if(strcmp(plugin_name, "saucenao") == 0) {
+ tabs.push_back(Tab{create_body(), std::make_unique<SaucenaoPage>(this, selected_files[0]), nullptr});
} else if(strcmp(plugin_name, "youtube") == 0) {
start_tab_index = 1;
tabs.push_back(Tab{create_body(), std::make_unique<YoutubeSubscriptionsPage>(this), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
@@ -1378,7 +1395,7 @@ namespace QuickMedia {
}
if(tabs[selected_tab].page->is_single_page()) {
- tabs[selected_tab].search_bar->clear();
+ if(tabs[selected_tab].search_bar) tabs[selected_tab].search_bar->clear();
if(new_tabs.size() == 1)
tabs[selected_tab].body = std::move(new_tabs[0].body);
else
@@ -1615,6 +1632,19 @@ namespace QuickMedia {
TrackablePage *trackable_page = dynamic_cast<TrackablePage*>(tabs[selected_tab].page.get());
trackable_page->track(selected_item->get_title());
}
+ } else if(event.key.code == sf::Keyboard::C && event.key.control) {
+ BodyItem *selected_item = tabs[selected_tab].body->get_selected();
+ if(selected_item) {
+ std::string title = selected_item->get_title();
+ std::string description = selected_item->get_description();
+ std::string clipboard = title;
+ if(!clipboard.empty()) {
+ clipboard += '\n';
+ clipboard += std::move(description);
+ }
+ if(!clipboard.empty())
+ sf::Clipboard::setString(sf::String::fromUtf8(clipboard.begin(), clipboard.end()));
+ }
}
}
}
@@ -3089,6 +3119,19 @@ namespace QuickMedia {
frame_skip_text_entry = true;
} else if(event.key.code == sf::Keyboard::D && event.key.control) {
selected_file_for_upload.clear();
+ } else if(event.key.code == sf::Keyboard::C && event.key.control) {
+ BodyItem *selected_item = thread_body->get_selected();
+ if(selected_item) {
+ std::string title = selected_item->get_title();
+ std::string description = selected_item->get_description();
+ std::string clipboard = title;
+ if(!clipboard.empty()) {
+ clipboard += '\n';
+ clipboard += std::move(description);
+ }
+ if(!clipboard.empty())
+ sf::Clipboard::setString(sf::String::fromUtf8(clipboard.begin(), clipboard.end()));
+ }
}
BodyItem *selected_item = thread_body->get_selected();
diff --git a/src/plugins/Saucenao.cpp b/src/plugins/Saucenao.cpp
new file mode 100644
index 0000000..302f25e
--- /dev/null
+++ b/src/plugins/Saucenao.cpp
@@ -0,0 +1,56 @@
+#include "../../plugins/Saucenao.hpp"
+#include "../../include/StringUtils.hpp"
+#include <quickmedia/HtmlSearch.h>
+
+namespace QuickMedia {
+ PluginResult SaucenaoPage::lazy_fetch(BodyItems &result_items) {
+ std::string website_data;
+ DownloadResult download_result = download_to_string("https://saucenao.com/search.php", website_data, {{ "-F", "file=@" + upload_filepath }}, true);
+ if(download_result != DownloadResult::OK) return download_result_to_plugin_result(download_result);
+
+ QuickMediaHtmlSearch html_search;
+ int result = quickmedia_html_search_init(&html_search, website_data.c_str());
+ if(result != 0)
+ goto cleanup;
+
+ result = quickmedia_html_find_nodes_xpath(&html_search, "//td[class='resulttablecontent']",
+ [](QuickMediaHtmlNode *node, void *userdata) {
+ BodyItems *item_data = (BodyItems*)userdata;
+ const char *text = quickmedia_html_node_get_text(node);
+ if(text) {
+ std::string title = text;
+ size_t p_index = title.find("%");
+ if(p_index != std::string::npos)
+ title = title.erase(0, p_index + 1);
+ auto item = BodyItem::create(strip(title));
+ item_data->push_back(std::move(item));
+ }
+ }, &result_items);
+
+ BodyItemContext body_item_context;
+ body_item_context.body_items = &result_items;
+ body_item_context.index = 0;
+
+ quickmedia_html_find_nodes_xpath(&html_search, "//td[class='resulttableimage']//img",
+ [](QuickMediaHtmlNode *node, void *userdata) {
+ BodyItemContext *item_data = (BodyItemContext*)userdata;
+ const char *src = quickmedia_html_node_get_attribute_value(node, "src");
+ const char *data_src = quickmedia_html_node_get_attribute_value(node, "data-src");
+ const char *image_url = data_src ? data_src : src;
+ if(image_url && item_data->index < item_data->body_items->size()) {
+ (*item_data->body_items)[item_data->index]->thumbnail_url = strip(image_url);
+ (*item_data->body_items)[item_data->index]->thumbnail_size = sf::Vector2i(150, 147);
+ item_data->index++;
+ }
+ }, &body_item_context);
+
+ cleanup:
+ quickmedia_html_search_deinit(&html_search);
+ if(result != 0) {
+ result_items.clear();
+ return PluginResult::ERR;
+ }
+
+ return PluginResult::OK;
+ }
+} \ No newline at end of file