aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2023-01-17 19:05:15 +0100
committerdec05eba <dec05eba@protonmail.com>2023-01-17 19:05:15 +0100
commitd203aba86d89c8dd6184146454396e48d39a8fb5 (patch)
tree584fa3856ca7ab534a111f43e0fc93564116a8d9
parent454f09ac14a76a46335eed60d4e242c446ae28be (diff)
NyaaSi: add ctrl+t to track anime with automedia
-rw-r--r--README.md6
-rw-r--r--TODO4
m---------depends/mglpp0
-rw-r--r--plugins/NyaaSi.hpp14
-rw-r--r--plugins/utils/EpisodeNameParser.hpp9
-rw-r--r--src/QuickMedia.cpp9
-rw-r--r--src/plugins/NyaaSi.cpp83
-rw-r--r--src/plugins/utils/EpisodeNameParser.cpp19
8 files changed, 126 insertions, 18 deletions
diff --git a/README.md b/README.md
index ccf33ae..bf6f112 100644
--- a/README.md
+++ b/README.md
@@ -38,7 +38,7 @@ Installing `lld` (the LLVM linker) can improve compile times.
`noto-fonts-cjk` needs to be installed to view chinese, japanese and korean characters (when `use_system_fonts` config is not set to `true`).\
`youtube-dl` needs to be installed to play/download xxx videos.\
`notify-send` (which is part of `libnotify`) needs to be installed to show notifications (on Linux and other systems that uses d-bus notification system).\
-[automedia](https://git.dec05eba.com/AutoMedia/) needs to be installed when tracking manga with `Ctrl + T`.\
+[automedia](https://git.dec05eba.com/AutoMedia/) needs to be installed when tracking anime/manga with `Ctrl + T`.\
`waifu2x-ncnn-vulkan` needs to be installed when using the `--upscale-images` or `--upscale-images-always` option.\
`xdg-utils` which provides `xdg-open` needs to be installed when downloading torrents with `nyaa.si` plugin.\
`ffmpeg (and ffprobe which is included in ffmpeg)` needs to be installed to display webp thumbnails, to upload videos with thumbnails on matrix or to merge video and audio when downloading youtube videos.\
@@ -108,6 +108,10 @@ Type text and then wait and QuickMedia will automatically search.\
`I`: Switch to page view.
### Manga chapters controls
`Ctrl+T`: Start tracking the manga after the selected chapter ([AutoMedia](https://git.dec05eba.com/AutoMedia/) needs to be installed).
+### NyaaSi search page controls
+`Ctrl+T`: Start tracking the anime after the selected episode ([AutoMedia](https://git.dec05eba.com/AutoMedia/) needs to be installed).
+### NyaaSi torrent page controls
+`Ctrl+T`: Start tracking the anime after the selected episode ([AutoMedia](https://git.dec05eba.com/AutoMedia/) needs to be installed).
### Matrix controls
#### Login page controls
`Tab`: Switch between username, password and homeserver fields.\
diff --git a/TODO b/TODO
index 53a3d93..25c0d45 100644
--- a/TODO
+++ b/TODO
@@ -252,4 +252,6 @@ Add option to open youtube/4chan links in a new instance of quickmedia (maybe wi
AAAAA Resizing 4chan post with no images but with replies (reactions) gives incorrect body item height compared to the rendered height.
Some mangadex chapter images are .webp files, such as the images for chapter 0 for "the lolicon killer". Quickmedia doesn't work for that because quickmedia doesn't support manga webp files. Fix that.
Fully support all emoji, including the minimally-qualified ones. Sometimes twemoji doesn't have the correct sequence images.
-@room in rooms do not currently work (for show as notifications in quickmedia matrix). This is because quickmedia matrix doesn't fetch power level states and doesn't parse them. Quickmedia has code to parse room events power levels but it doesn't actually fetch the data so that part is never used. \ No newline at end of file
+@room in rooms do not currently work (for show as notifications in quickmedia matrix). This is because quickmedia matrix doesn't fetch power level states and doesn't parse them. Quickmedia has code to parse room events power levels but it doesn't actually fetch the data so that part is never used.
+Support NicoNicoDouga and BiliBili (user request).
+Support arabic/hebrew text. Use Text class for all text rendering. \ No newline at end of file
diff --git a/depends/mglpp b/depends/mglpp
-Subproject abc3ff63805f86af3ecc45b23aaf4e49ff9a3d6
+Subproject 6096469348d8d94ed0a92a6123983eba772cf34
diff --git a/plugins/NyaaSi.hpp b/plugins/NyaaSi.hpp
index 3236fc5..103fea7 100644
--- a/plugins/NyaaSi.hpp
+++ b/plugins/NyaaSi.hpp
@@ -29,7 +29,7 @@ namespace QuickMedia {
DOWNLOADS_ASC
};
- class NyaaSiSearchPage : public Page {
+ class NyaaSiSearchPage : public Page, public TrackablePage {
public:
NyaaSiSearchPage(Program *program, std::string category_name, std::string category_id, std::string domain);
const char* get_title() const override { return title.c_str(); }
@@ -38,6 +38,9 @@ namespace QuickMedia {
PluginResult get_page(const std::string &str, int page, BodyItems &result_items) override;
PluginResult submit(const SubmitArgs &args, std::vector<Tab> &result_tabs) override;
+ TrackResult track(const std::string &str) override;
+ bool is_trackable() const override { return true; }
+
void set_sort_type(NyaaSiSortType sort_type);
const std::string category_name;
@@ -59,11 +62,14 @@ namespace QuickMedia {
NyaaSiSearchPage *search_page;
};
- class NyaaSiTorrentPage : public Page {
+ class NyaaSiTorrentPage : public Page, public TrackablePage {
public:
- NyaaSiTorrentPage(Program *program) : Page(program) {}
- const char* get_title() const override { return "Torrent"; }
+ NyaaSiTorrentPage(Program *program, std::string title) : Page(program), TrackablePage(std::move(title), "") {}
+ const char* get_title() const override { return content_title.c_str(); }
PluginResult submit(const SubmitArgs &args, std::vector<Tab> &result_tabs) override;
bool submit_is_async() const override { return false; }
+
+ TrackResult track(const std::string &str) override;
+ bool is_trackable() const override { return true; }
};
} \ No newline at end of file
diff --git a/plugins/utils/EpisodeNameParser.hpp b/plugins/utils/EpisodeNameParser.hpp
index 1ec847a..7976cdc 100644
--- a/plugins/utils/EpisodeNameParser.hpp
+++ b/plugins/utils/EpisodeNameParser.hpp
@@ -5,10 +5,11 @@
namespace QuickMedia {
struct EpisodeNameParts {
- std::string_view group; // optional
- std::string_view anime; // required
- std::string_view season; // optional
- std::string_view episode; // required
+ std::string_view group; // optional
+ std::string_view anime; // required
+ std::string_view season; // optional
+ std::string_view episode; // required
+ std::string_view resolution; // optional
};
std::optional<EpisodeNameParts> episode_name_extract_parts(std::string_view episode_name);
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index c2b2b95..447b863 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -699,6 +699,10 @@ namespace QuickMedia {
XSetErrorHandler(x_error_handler);
XSetIOErrorHandler(x_io_error_handler);
+ // Initialize config and theme early to prevent possible race condition on initialize
+ get_config();
+ get_theme();
+
mgl::vec2i monitor_size;
mgl::vec2i focused_monitor_center = get_focused_monitor_center(disp, monitor_size);
@@ -719,6 +723,7 @@ namespace QuickMedia {
}
window_create_params.hidden = no_dialog;
window_create_params.parent_window = parent_window;
+ window_create_params.background_color = get_theme().background_color;
if(!window.create("QuickMedia", std::move(window_create_params))) {
show_notification("QuickMedia", "Failed to create opengl window", Urgency::CRITICAL);
abort();
@@ -732,10 +737,6 @@ 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());
init_body_themes();
diff --git a/src/plugins/NyaaSi.cpp b/src/plugins/NyaaSi.cpp
index cd80997..739032b 100644
--- a/src/plugins/NyaaSi.cpp
+++ b/src/plugins/NyaaSi.cpp
@@ -5,9 +5,80 @@
#include "../../include/StringUtils.hpp"
#include "../../include/NetUtils.hpp"
#include "../../include/Utils.hpp"
+#include "../../plugins/utils/EpisodeNameParser.hpp"
#include <quickmedia/HtmlSearch.h>
namespace QuickMedia {
+ static std::string combine_strings(const std::initializer_list<std::string_view> items, char divider) {
+ std::string result;
+ for(const auto &item : items) {
+ if(item.empty())
+ continue;
+
+ if(!result.empty())
+ result += divider;
+
+ result += item;
+ }
+ return result;
+ }
+
+ static TrackResult track(const std::string &str) {
+ std::optional<EpisodeNameParts> episode_parts = episode_name_extract_parts(str);
+ if(!episode_parts) {
+ show_notification("QuickMedia", "Failed to extract episode name from torrent name. Please add the rss manually with automedia", Urgency::CRITICAL);
+ return TrackResult::ERR;
+ }
+
+ const std::string track_name = combine_strings({ episode_parts->group, episode_parts->anime, episode_parts->episode, episode_parts->season, episode_parts->resolution }, ' ');
+
+ std::string url = "https://nyaa.si/?page=rss&q=" + url_param_encode(track_name) + "&c=0_0&f=0";
+ if(!episode_parts->group.empty())
+ url += "&u=" + url_param_decode(std::string(episode_parts->group));
+
+ std::string website_data;
+ if(download_to_string(url, website_data, {}, true) != DownloadResult::OK) {
+ show_notification("QuickMedia", "Invalid rss. Please add the rss manually with automedia", Urgency::CRITICAL);
+ return TrackResult::ERR;
+ }
+ struct HtmlFindUserdata {
+ const std::string &str;
+ bool found_title = false;
+ };
+ HtmlFindUserdata userdata{ str, false };
+
+ QuickMediaHtmlSearch html_search;
+ int result = quickmedia_html_search_init(&html_search, website_data.c_str(), website_data.size());
+ if(result != 0)
+ goto cleanup;
+
+ result = quickmedia_html_find_nodes_xpath(&html_search, "//channel/item/title",
+ [](QuickMediaMatchNode *node, void *userdata) {
+ HtmlFindUserdata &userdata_typed = *(HtmlFindUserdata*)userdata;
+ QuickMediaStringView text = quickmedia_html_node_get_text(node);
+ if(text.data && text.size == userdata_typed.str.size() && memcmp(text.data, userdata_typed.str.data(), text.size) == 0) {
+ userdata_typed.found_title = true;
+ }
+ return 0;
+ }, &userdata);
+
+ cleanup:
+ quickmedia_html_search_deinit(&html_search);
+ if(result != 0 || !userdata.found_title) {
+ show_notification("QuickMedia", "The item you tried to track was not found in the rss feed. Please add the rss manually with automedia", Urgency::CRITICAL);
+ return TrackResult::ERR;
+ }
+
+ const char *args[] = { "automedia", "add", "rss", url.c_str(), "--start-after", str.c_str(), "--name", track_name.c_str(), nullptr };
+ if(exec_program(args, nullptr, nullptr) == 0) {
+ show_notification("QuickMedia", "You are now tracking \"" + track_name + "\" after \"" + str + "\"", Urgency::LOW);
+ return TrackResult::OK;
+ } else {
+ show_notification("QuickMedia", "Failed to track media \"" + track_name + "\", episode: \"" + str + "\"", Urgency::CRITICAL);
+ return TrackResult::ERR;
+ }
+ }
+
// Return end of td tag, or std::string::npos
static size_t find_td_get_value(const std::string &str, size_t start_index, size_t end_index, std::string &result) {
size_t td_begin = str.find("<td", start_index);
@@ -310,7 +381,7 @@ namespace QuickMedia {
}
NyaaSiSearchPage::NyaaSiSearchPage(Program *program, std::string category_name, std::string category_id, std::string domain) :
- Page(program), category_name(std::move(category_name)), category_id(std::move(category_id)), domain(std::move(domain))
+ Page(program), TrackablePage("", ""), category_name(std::move(category_name)), category_id(std::move(category_id)), domain(std::move(domain))
{
set_sort_type(NyaaSiSortType::UPLOAD_DATE_DESC);
}
@@ -493,10 +564,14 @@ namespace QuickMedia {
auto body = create_body();
body->set_items(std::move(result_items));
- result_tabs.push_back(Tab{std::move(body), std::make_unique<NyaaSiTorrentPage>(program), nullptr});
+ result_tabs.push_back(Tab{std::move(body), std::make_unique<NyaaSiTorrentPage>(program, args.title), nullptr});
return PluginResult::OK;
}
+ TrackResult NyaaSiSearchPage::track(const std::string &str) {
+ return QuickMedia::track(str);
+ }
+
void NyaaSiSearchPage::set_sort_type(NyaaSiSortType sort_type) {
this->sort_type = sort_type;
title = category_name + " | " + sort_type_names[(size_t)sort_type];
@@ -524,4 +599,8 @@ namespace QuickMedia {
}
return PluginResult::OK;
}
+
+ TrackResult NyaaSiTorrentPage::track(const std::string&) {
+ return QuickMedia::track(content_title);
+ }
} \ No newline at end of file
diff --git a/src/plugins/utils/EpisodeNameParser.cpp b/src/plugins/utils/EpisodeNameParser.cpp
index de2b8ac..a381cca 100644
--- a/src/plugins/utils/EpisodeNameParser.cpp
+++ b/src/plugins/utils/EpisodeNameParser.cpp
@@ -71,7 +71,7 @@ namespace QuickMedia {
return episode_name_extract_anime(episode_name);
}
- static bool is_num_real_char(char c) {
+ static bool is_real_num(char c) {
return (c >= '0' && c <= '9') || c == '.';
}
@@ -79,7 +79,7 @@ namespace QuickMedia {
episode_name = strip_left(episode_name);
size_t i = 0;
for(; i < episode_name.size(); ++i) {
- if(!is_num_real_char(episode_name[i]))
+ if(!is_real_num(episode_name[i]))
break;
}
@@ -107,6 +107,21 @@ namespace QuickMedia {
if(name_parts.episode.empty())
return std::nullopt;
+ if(episode_name.find("480p") != std::string_view::npos)
+ name_parts.resolution = "480p";
+ else if(episode_name.find("720p") != std::string_view::npos)
+ name_parts.resolution = "720p";
+ else if(episode_name.find("1080p") != std::string_view::npos)
+ name_parts.resolution = "1080p";
+ else if(episode_name.find("2160p") != std::string_view::npos)
+ name_parts.resolution = "2160p";
+ else if(episode_name.find("1280x720") != std::string_view::npos)
+ name_parts.resolution = "1280x720";
+ else if(episode_name.find("1920x1080") != std::string_view::npos)
+ name_parts.resolution = "1920x1080";
+ else if(episode_name.find("3840x2160") != std::string_view::npos)
+ name_parts.resolution = "3840x2160";
+
return name_parts;
}
} \ No newline at end of file