diff options
author | dec05eba <dec05eba@protonmail.com> | 2019-08-09 05:13:38 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2019-08-09 05:13:41 +0200 |
commit | afc8c731bdf482e87304d2f5df6cfc55018806b6 (patch) | |
tree | ada70b28a1d5ebc89cfb0e0e733847279427bc39 | |
parent | 1e1960a14ae40c6743ea12dc0f9efe5e714e4bff (diff) |
Add pornhub plugin
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | plugins/Pornhub.hpp | 16 | ||||
-rw-r--r-- | src/QuickMedia.cpp | 5 | ||||
-rw-r--r-- | src/plugins/Pornhub.cpp | 139 |
4 files changed, 161 insertions, 2 deletions
@@ -1,5 +1,6 @@ # QuickMedia -Native clients of websites with fast access to what you want to see. [Demo with manga](https://beta.lbry.tv/quickmedia_manga-2019-08-05_21.20.46/7). +Native clients of websites with fast access to what you want to see. [Demo with manga](https://beta.lbry.tv/quickmedia_manga-2019-08-05_21.20.46/7).\ +Currently supported websites: `youtube`, `manganelo` and `pornhub`. ## Controls Press `ESC` to go back to the previous menu.\ Press `Ctrl + T` when hovering over a manga chapter to start tracking manga after that chapter. This only works if AutoMedia is installed and diff --git a/plugins/Pornhub.hpp b/plugins/Pornhub.hpp new file mode 100644 index 0000000..edbfdab --- /dev/null +++ b/plugins/Pornhub.hpp @@ -0,0 +1,16 @@ +#pragma once + +#include "Plugin.hpp" + +namespace QuickMedia { + class Pornhub : public Plugin { + public: + SuggestionResult update_search_suggestions(const std::string &text, BodyItems &result_items) override; + BodyItems get_related_media(const std::string &url) override; + bool search_suggestions_has_thumbnails() const override { return true; } + bool search_results_has_thumbnails() const override { return false; } + int get_search_delay() const override { return 500; } + bool search_suggestion_is_search() const override { return true; } + Page get_page_after_search() const override { return Page::VIDEO_CONTENT; } + }; +}
\ No newline at end of file diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp index 4b3698d..691b62b 100644 --- a/src/QuickMedia.cpp +++ b/src/QuickMedia.cpp @@ -1,6 +1,7 @@ #include "../include/QuickMedia.hpp" #include "../plugins/Manganelo.hpp" #include "../plugins/Youtube.hpp" +#include "../plugins/Pornhub.hpp" #include "../include/Scale.hpp" #include "../include/Program.h" #include "../include/VideoPlayer.hpp" @@ -72,7 +73,7 @@ namespace QuickMedia { static void usage() { fprintf(stderr, "usage: QuickMedia <plugin>\n"); fprintf(stderr, "OPTIONS:\n"); - fprintf(stderr, "plugin The plugin to use. Should be either manganelo or youtube\n"); + fprintf(stderr, "plugin The plugin to use. Should be either manganelo, youtube or pornhub\n"); } int Program::run(int argc, char **argv) { @@ -85,6 +86,8 @@ namespace QuickMedia { current_plugin = new Manganelo(); else if(strcmp(argv[1], "youtube") == 0) current_plugin = new Youtube(); + else if(strcmp(argv[1], "pornhub") == 0) + current_plugin = new Pornhub(); else { usage(); return -1; diff --git a/src/plugins/Pornhub.cpp b/src/plugins/Pornhub.cpp new file mode 100644 index 0000000..4955efd --- /dev/null +++ b/src/plugins/Pornhub.cpp @@ -0,0 +1,139 @@ +#include "../../plugins/Pornhub.hpp" +#include <quickmedia/HtmlSearch.h> +#include <json/reader.h> +#include <string.h> + +namespace QuickMedia { + static bool begins_with(const char *str, const char *begin_with) { + return strncmp(str, begin_with, strlen(begin_with)) == 0; + } + + static bool contains(const char *str, const char *substr) { + return strstr(str, substr); + } + + static void iterate_suggestion_result(const Json::Value &value, BodyItems &result_items, int &iterate_count) { + ++iterate_count; + if(value.isArray()) { + for(const Json::Value &child : value) { + iterate_suggestion_result(child, result_items, iterate_count); + } + } else if(value.isString() && iterate_count > 2) { + std::string title = value.asString(); + auto item = std::make_unique<BodyItem>(title); + result_items.push_back(std::move(item)); + } + } + + // TODO: Speed this up by using string.find instead of parsing html + SuggestionResult Pornhub::update_search_suggestions(const std::string &text, BodyItems &result_items) { + std::string url = "https://www.pornhub.com/video/search?search="; + url += url_param_encode(text); + + std::string website_data; + if(download_to_string(url, website_data) != DownloadResult::OK) + return SuggestionResult::NET_ERR; + + struct ItemData { + BodyItems *result_items; + size_t index; + }; + ItemData item_data = { &result_items, 0 }; + + 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='phimage']//a", + [](QuickMediaHtmlNode *node, void *userdata) { + auto *result_items = (BodyItems*)userdata; + const char *href = quickmedia_html_node_get_attribute_value(node, "href"); + const char *title = quickmedia_html_node_get_attribute_value(node, "title"); + if(href && title && begins_with(href, "/view_video.php?viewkey")) { + auto item = std::make_unique<BodyItem>(strip(title)); + item->url = std::string("https://www.pornhub.com") + href; + result_items->push_back(std::move(item)); + } + }, &result_items); + if(result != 0) + goto cleanup; + + result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='phimage']//img", + [](QuickMediaHtmlNode *node, void *userdata) { + ItemData *item_data = (ItemData*)userdata; + if(item_data->index >= item_data->result_items->size()) + return; + + const char *data_src = quickmedia_html_node_get_attribute_value(node, "data-src"); + if(data_src && contains(data_src, "phncdn.com/videos")) { + (*item_data->result_items)[item_data->index]->thumbnail_url = data_src; + ++item_data->index; + } + }, &item_data); + + // Attempt to skip promoted videos (that are not related to the search term) + if(result_items.size() >= 4) { + result_items.erase(result_items.begin(), result_items.begin() + 4); + } + + cleanup: + quickmedia_html_search_deinit(&html_search); + return result == 0 ? SuggestionResult::OK : SuggestionResult::ERR; + } + + BodyItems Pornhub::get_related_media(const std::string &url) { + BodyItems result_items; + + std::string website_data; + if(download_to_string(url, website_data) != DownloadResult::OK) + return result_items; + + struct ItemData { + BodyItems *result_items; + size_t index; + }; + ItemData item_data = { &result_items, 0 }; + + 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='phimage']//a", + [](QuickMediaHtmlNode *node, void *userdata) { + auto *result_items = (BodyItems*)userdata; + const char *href = quickmedia_html_node_get_attribute_value(node, "href"); + const char *title = quickmedia_html_node_get_attribute_value(node, "title"); + if(href && title && begins_with(href, "/view_video.php?viewkey")) { + auto item = std::make_unique<BodyItem>(strip(title)); + item->url = std::string("https://www.pornhub.com") + href; + result_items->push_back(std::move(item)); + } + }, &result_items); + if(result != 0) + goto cleanup; + + result = quickmedia_html_find_nodes_xpath(&html_search, "//div[class='phimage']//img", + [](QuickMediaHtmlNode *node, void *userdata) { + ItemData *item_data = (ItemData*)userdata; + if(item_data->index >= item_data->result_items->size()) + return; + + const char *src = quickmedia_html_node_get_attribute_value(node, "src"); + if(src && contains(src, "phncdn.com/videos")) { + (*item_data->result_items)[item_data->index]->thumbnail_url = src; + ++item_data->index; + } + }, &item_data); + + // Attempt to skip promoted videos (that are not related to the search term) + if(result_items.size() >= 4) { + result_items.erase(result_items.begin(), result_items.begin() + 4); + } + + cleanup: + quickmedia_html_search_deinit(&html_search); + return result_items; + } +}
\ No newline at end of file |