aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2019-08-09 05:13:38 +0200
committerdec05eba <dec05eba@protonmail.com>2019-08-09 05:13:41 +0200
commitafc8c731bdf482e87304d2f5df6cfc55018806b6 (patch)
treeada70b28a1d5ebc89cfb0e0e733847279427bc39
parent1e1960a14ae40c6743ea12dc0f9efe5e714e4bff (diff)
Add pornhub plugin
-rw-r--r--README.md3
-rw-r--r--plugins/Pornhub.hpp16
-rw-r--r--src/QuickMedia.cpp5
-rw-r--r--src/plugins/Pornhub.cpp139
4 files changed, 161 insertions, 2 deletions
diff --git a/README.md b/README.md
index 535a7f4..80850fc 100644
--- a/README.md
+++ b/README.md
@@ -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