aboutsummaryrefslogtreecommitdiff
path: root/src/plugins
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-07-03 16:55:19 +0200
committerdec05eba <dec05eba@protonmail.com>2020-07-03 16:55:19 +0200
commit18467b4cd333ab0b7aa10b1c1acd83942c583e60 (patch)
treebeb77bd217a9530bd2ed057f67a5412ba3f8a1e3 /src/plugins
parent2d796243ad157f52d33a5b9d4f449e3845cf1649 (diff)
Add tab autocomplete for youtube
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/Youtube.cpp70
1 files changed, 54 insertions, 16 deletions
diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp
index c0180d8..3ab405c 100644
--- a/src/plugins/Youtube.cpp
+++ b/src/plugins/Youtube.cpp
@@ -3,6 +3,60 @@
#include <string.h>
namespace QuickMedia {
+ static void iterate_suggestion_result(const Json::Value &value, std::vector<std::string> &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) {
+ result_items.push_back(value.asString());
+ }
+ }
+
+ std::string Youtube::autocomplete_search(const std::string &query) {
+ // Return the last result if the query is a substring of the autocomplete result
+ if(last_autocomplete_result.size() >= query.size() && memcmp(query.data(), last_autocomplete_result.data(), query.size()) == 0)
+ return last_autocomplete_result;
+
+ std::string url = "https://clients1.google.com/complete/search?client=youtube&hl=en&gs_rn=64&gs_ri=youtube&ds=yt&cp=7&gs_id=x&q=";
+ url += url_param_encode(query);
+
+ std::string server_response;
+ if(download_to_string(url, server_response, {}, use_tor, true) != DownloadResult::OK)
+ return query;
+
+ size_t json_start = server_response.find_first_of('(');
+ if(json_start == std::string::npos)
+ return query;
+ ++json_start;
+
+ size_t json_end = server_response.find_last_of(')');
+ if(json_end == std::string::npos)
+ return query;
+
+ if(json_end == 0 || json_start >= json_end)
+ return query;
+
+ 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[json_start], &server_response[json_end], &json_root, &json_errors)) {
+ fprintf(stderr, "Youtube autocomplete search json error: %s\n", json_errors.c_str());
+ return query;
+ }
+
+ int iterate_count = 0;
+ std::vector<std::string> result_items;
+ iterate_suggestion_result(json_root, result_items, iterate_count);
+ if(result_items.empty())
+ return query;
+
+ last_autocomplete_result = result_items[0];
+ return result_items[0];
+ }
+
static size_t find_end_of_json(const std::string &website_data, size_t data_start) {
int brace_count = 0;
char string_char = '\0';
@@ -228,14 +282,6 @@ namespace QuickMedia {
}
}
- static std::string get_playlist_id_from_url(const std::string &url) {
- std::string playlist_id = url;
- size_t list_index = playlist_id.find("&list=");
- if(list_index == std::string::npos)
- return playlist_id;
- return playlist_id.substr(list_index);
- }
-
static std::string remove_index_from_playlist_url(const std::string &url) {
std::string result = url;
size_t index = result.rfind("&index=");
@@ -280,14 +326,6 @@ namespace QuickMedia {
BodyItems result_items;
std::string modified_url = remove_index_from_playlist_url(url);
- std::string playlist_id = get_playlist_id_from_url(modified_url);
- if(playlist_id == last_related_media_playlist_id) {
- result_items.reserve(last_playlist_data.size());
- for(auto &data : last_playlist_data) {
- result_items.push_back(std::make_unique<BodyItem>(*data));
- }
- return result_items;
- }
std::string website_data;
if(download_to_string(modified_url, website_data, {}, use_tor, true) != DownloadResult::OK)