aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/Mangatown.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/Mangatown.cpp')
-rw-r--r--src/plugins/Mangatown.cpp207
1 files changed, 207 insertions, 0 deletions
diff --git a/src/plugins/Mangatown.cpp b/src/plugins/Mangatown.cpp
new file mode 100644
index 0000000..90db349
--- /dev/null
+++ b/src/plugins/Mangatown.cpp
@@ -0,0 +1,207 @@
+#include "../../plugins/Mangatown.hpp"
+#include "../../include/Notification.hpp"
+#include <quickmedia/HtmlSearch.h>
+#include <json/reader.h>
+
+static const std::string mangatown_url = "https://www.mangatown.com";
+
+namespace QuickMedia {
+ SearchResult Mangatown::search(const std::string &url, BodyItems &result_items) {
+ std::string website_data;
+ if(download_to_string(url, website_data, {}, use_tor, true) != DownloadResult::OK)
+ return SearchResult::NET_ERR;
+
+ 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, "//ul[class='chapter_list']//a",
+ [](QuickMediaHtmlNode *node, void *userdata) {
+ auto *item_data = (BodyItems*)userdata;
+ const char *href = quickmedia_html_node_get_attribute_value(node, "href");
+ const char *text = quickmedia_html_node_get_text(node);
+ if(href && text && strncmp(href, "/manga/", 7) == 0) {
+ auto item = std::make_unique<BodyItem>(strip(text));
+ item->url = mangatown_url + href;
+ item_data->push_back(std::move(item));
+ }
+ }, &result_items);
+
+ cleanup:
+ quickmedia_html_search_deinit(&html_search);
+ return result == 0 ? SearchResult::OK : SearchResult::ERR;
+ }
+
+ SuggestionResult Mangatown::update_search_suggestions(const std::string &text, BodyItems &result_items) {
+ std::string url = "https://www.mangatown.com/ajax/search/?query=";
+ url += url_param_encode(text);
+
+ std::string server_response;
+ if(download_to_string(url, server_response, {}, use_tor, true) != DownloadResult::OK)
+ return SuggestionResult::NET_ERR;
+
+ if(server_response.empty())
+ return SuggestionResult::OK;
+
+ Json::Value json_root;
+ Json::CharReaderBuilder json_builder;
+ std::unique_ptr<Json::CharReader> json_reader(json_builder.newCharReader());
+ std::string json_errors;
+ if(!json_reader->parse(&server_response[0], &server_response[server_response.size()], &json_root, &json_errors)) {
+ fprintf(stderr, "Mangatown suggestions json error: %s\n", json_errors.c_str());
+ return SuggestionResult::ERR;
+ }
+
+ if(!json_root.isObject())
+ return SuggestionResult::OK;
+
+ Json::Value &json_data = json_root["data"];
+ Json::Value &json_suggestions = json_root["suggestions"];
+ if(!json_data.isArray() || !json_suggestions.isArray())
+ return SuggestionResult::OK;
+
+ for(const Json::Value &child : json_suggestions) {
+ if(!child.isString()) {
+ result_items.push_back(std::make_unique<BodyItem>(""));
+ continue;
+ }
+ result_items.push_back(std::make_unique<BodyItem>(child.asString()));
+ }
+
+ size_t index = 0;
+ for(const Json::Value &child : json_data) {
+ BodyItem *body_item = nullptr;
+ if(index < result_items.size()) {
+ body_item = result_items[index].get();
+ } else {
+ result_items.push_back(std::make_unique<BodyItem>(""));
+ body_item = result_items.back().get();
+ }
+
+ ++index;
+
+ if(!child.isString())
+ continue;
+
+ body_item->url = mangatown_url + child.asString();
+ }
+
+ return SuggestionResult::OK;
+ }
+
+ static bool is_number_with_zero_fill(const char *str) {
+ while(*str == '0') { ++str; }
+ return atoi(str) != 0;
+ }
+
+ ImageResult Mangatown::get_number_of_images(const std::string &url, int &num_images) {
+ std::lock_guard<std::mutex> lock(image_urls_mutex);
+
+ num_images = last_num_pages;
+ if(url == last_chapter_url_num_images)
+ return ImageResult::OK;
+
+ last_num_pages = 0;
+
+ std::string website_data;
+ if(download_to_string(url, website_data, {}, use_tor, true) != DownloadResult::OK)
+ return ImageResult::NET_ERR;
+
+ 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, "//div[class='page_select']//option",
+ [](QuickMediaHtmlNode *node, void *userdata) {
+ int *last_num_pages = (int*)userdata;
+ const char *value = quickmedia_html_node_get_attribute_value(node, "value");
+ const char *text = quickmedia_html_node_get_text(node);
+ if(value && strncmp(value, "/manga/", 7) == 0) {
+ if(is_number_with_zero_fill(text)) {
+ (*last_num_pages)++;
+ }
+ }
+ }, &last_num_pages);
+
+ last_num_pages /= 2;
+ num_images = last_num_pages;
+
+ cleanup:
+ quickmedia_html_search_deinit(&html_search);
+
+ if(result == 0)
+ last_chapter_url_num_images = url;
+ if(last_num_pages == 0) {
+ last_chapter_url_num_images.clear();
+ return ImageResult::ERR;
+ }
+ return result == 0 ? ImageResult::OK : ImageResult::ERR;
+ }
+
+ ImageResult Mangatown::for_each_page_in_chapter(const std::string &chapter_url, PageCallback callback) {
+ int num_pages;
+ ImageResult image_result = get_number_of_images(chapter_url, num_pages);
+ if(image_result != ImageResult::OK)
+ return image_result;
+
+ int result = 0;
+ int page_index = 1;
+
+ while(true) {
+ std::string image_src;
+ std::string website_data;
+ std::string full_url = chapter_url + std::to_string(page_index++) + ".html";
+ if(download_to_string(full_url, website_data, {}, use_tor, true) != DownloadResult::OK)
+ break;
+
+ QuickMediaHtmlSearch html_search;
+ result = quickmedia_html_search_init(&html_search, website_data.c_str());
+ if(result != 0)
+ goto cleanup;
+
+ result = quickmedia_html_find_nodes_xpath(&html_search, "//div[id='viewer']//img",
+ [](QuickMediaHtmlNode *node, void *userdata) {
+ std::string *image_src = (std::string*)userdata;
+ const char *src = quickmedia_html_node_get_attribute_value(node, "src");
+ if(src && strstr(src, "/store/manga/")) {
+ if(strncmp(src, "//", 2) == 0)
+ *image_src = src + 2;
+ else
+ *image_src = src;
+ }
+ }, &image_src);
+
+ cleanup:
+ quickmedia_html_search_deinit(&html_search);
+
+ if(result != 0)
+ return ImageResult::ERR;
+
+ if(image_src.empty())
+ break;
+
+ if(!callback(image_src))
+ break;
+ }
+
+ return ImageResult::OK;
+ }
+
+ bool Mangatown::extract_id_from_url(const std::string &url, std::string &manga_id) {
+ size_t start_index = url.find("/manga/");
+ if(start_index == std::string::npos)
+ return false;
+
+ start_index += 7;
+ size_t end_index = url.find("/", start_index);
+ if(end_index == std::string::npos) {
+ manga_id = url.substr(start_index);
+ return true;
+ }
+
+ manga_id = url.substr(start_index, end_index - start_index);
+ return true;
+ }
+} \ No newline at end of file