aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2020-06-27 22:30:30 +0200
committerdec05eba <dec05eba@protonmail.com>2020-06-27 22:30:30 +0200
commitaf60cf05e6917a3f50bba870368ff10a6113f592 (patch)
tree6efcb81657b92f6eaf0e2aef3e3798d7057d3b69 /src
parent9e014aead36adf6ca936dd7f355c1ce5dc18139b (diff)
Fix youtube search not working sometimes
Diffstat (limited to 'src')
-rw-r--r--src/plugins/Youtube.cpp256
1 files changed, 252 insertions, 4 deletions
diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp
index 3660810..4ddc549 100644
--- a/src/plugins/Youtube.cpp
+++ b/src/plugins/Youtube.cpp
@@ -34,7 +34,7 @@ namespace QuickMedia {
url += url_param_encode(text);
std::string server_response;
- if(download_to_string(url, server_response) != DownloadResult::OK)
+ if(download_to_string(url, server_response, {}, use_tor, true) != DownloadResult::OK)
return SuggestionResult::NET_ERR;
size_t json_start = server_response.find_first_of('(');
@@ -70,12 +70,12 @@ namespace QuickMedia {
if(!found_search_text)
result_items.insert(result_items.begin(), std::make_unique<BodyItem>(text));
return SuggestionResult::OK;
- #endif
+ #elif 0
std::string url = "https://youtube.com/results?search_query=";
url += url_param_encode(text);
std::string website_data;
- if(download_to_string(url, website_data, {}, use_tor) != DownloadResult::OK)
+ if(download_to_string(url, website_data, {}, use_tor, true) != DownloadResult::OK)
return SuggestionResult::NET_ERR;
struct ItemData {
@@ -125,6 +125,119 @@ namespace QuickMedia {
cleanup:
quickmedia_html_search_deinit(&html_search);
return result == 0 ? SuggestionResult::OK : SuggestionResult::ERR;
+ #else
+ std::string url = "https://youtube.com/results?search_query=";
+ url += url_param_encode(text);
+
+ std::string website_data;
+ if(download_to_string(url, website_data, {}, use_tor, true) != DownloadResult::OK)
+ return SuggestionResult::NET_ERR;
+
+ size_t data_start = website_data.find("window[\"ytInitialData\"] = {");
+ if(data_start == std::string::npos)
+ return SuggestionResult::ERR;
+
+ data_start = data_start + 26;
+ size_t data_end = 0;
+ int brace_count = 0;
+ for(size_t i = data_start; i < website_data.size(); ++i) {
+ char c = website_data[i];
+ if(c == '{')
+ ++brace_count;
+ else if(c == '}') {
+ --brace_count;
+ if(brace_count == 0) {
+ data_end = i + 1;
+ break;
+ }
+ }
+ }
+
+ if(data_end == 0)
+ return SuggestionResult::ERR;
+
+ 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(&website_data[data_start], &website_data[data_end], &json_root, &json_errors)) {
+ fprintf(stderr, "Youtube search json error: %s\n", json_errors.c_str());
+ return SuggestionResult::ERR;
+ }
+
+ const Json::Value &contents_json = json_root["contents"];
+ if(!contents_json.isObject())
+ return SuggestionResult::ERR;
+
+ const Json::Value &tcsrr_json = contents_json["twoColumnSearchResultsRenderer"];
+ if(!tcsrr_json.isObject())
+ return SuggestionResult::ERR;
+
+ const Json::Value &primary_contents_json = tcsrr_json["primaryContents"];
+ if(!primary_contents_json.isObject())
+ return SuggestionResult::ERR;
+
+ const Json::Value &section_list_renderer_json = primary_contents_json["sectionListRenderer"];
+ if(!section_list_renderer_json.isObject())
+ return SuggestionResult::ERR;
+
+ const Json::Value &contents2_json = section_list_renderer_json["contents"];
+ if(!contents2_json.isArray())
+ return SuggestionResult::ERR;
+
+ for(const Json::Value &item_json : contents2_json) {
+ if(!item_json.isObject())
+ continue;
+
+ const Json::Value &item_section_renderer_json = item_json["itemSectionRenderer"];
+ if(!item_section_renderer_json.isObject())
+ continue;
+
+ const Json::Value &item_contents_json = item_section_renderer_json["contents"];
+ if(!item_contents_json.isArray())
+ continue;
+
+ for(const Json::Value &content_item_json : item_contents_json) {
+ if(!content_item_json.isObject())
+ continue;
+
+ const Json::Value &video_renderer_json = content_item_json["videoRenderer"];
+ if(!video_renderer_json.isObject())
+ continue;
+
+ const Json::Value &video_id_json = video_renderer_json["videoId"];
+ if(!video_id_json.isString())
+ continue;
+
+ std::string video_id_str = video_id_json.asString();
+ std::string thumbnail_url = "https://img.youtube.com/vi/" + video_id_str + "/hqdefault.jpg";
+
+ const char *title = nullptr;
+ const Json::Value &title_json = video_renderer_json["title"];
+ if(title_json.isObject()) {
+ const Json::Value &runs_json = title_json["runs"];
+ if(runs_json.isArray() && runs_json.size() > 0) {
+ const Json::Value &first_runs_json = runs_json[0];
+ if(first_runs_json.isObject()) {
+ const Json::Value &text_json = first_runs_json["text"];
+ if(text_json.isString())
+ title = text_json.asCString();
+ }
+ }
+ }
+
+ if(!title)
+ continue;
+
+ auto body_item = std::make_unique<BodyItem>(title);
+ body_item->url = "https://www.youtube.com/watch?v=" + video_id_str;
+ body_item->thumbnail_url = std::move(thumbnail_url);
+ result_items.push_back(std::move(body_item));
+ }
+ }
+
+ return SuggestionResult::OK;
+ #endif
}
static std::string get_playlist_id_from_url(const std::string &url) {
@@ -143,9 +256,40 @@ namespace QuickMedia {
return result.substr(0, index);
}
+ static std::unique_ptr<BodyItem> parse_compact_video_renderer_json(const Json::Value &item_json) {
+ const Json::Value &compact_video_renderer_json = item_json["compactVideoRenderer"];
+ if(!compact_video_renderer_json.isObject())
+ return nullptr;
+
+ const Json::Value &video_id_json = compact_video_renderer_json["videoId"];
+ if(!video_id_json.isString())
+ return nullptr;
+
+ std::string video_id_str = video_id_json.asString();
+ std::string thumbnail_url = "https://img.youtube.com/vi/" + video_id_str + "/hqdefault.jpg";
+
+ const char *title = nullptr;
+ const Json::Value &title_json = compact_video_renderer_json["title"];
+ if(title_json.isObject()) {
+ const Json::Value &simple_text_json = title_json["simpleText"];
+ if(simple_text_json.isString()) {
+ title = simple_text_json.asCString();
+ }
+ }
+
+ if(!title)
+ return nullptr;
+
+ auto body_item = std::make_unique<BodyItem>(title);
+ body_item->url = "https://www.youtube.com/watch?v=" + video_id_str;
+ body_item->thumbnail_url = std::move(thumbnail_url);
+ return body_item;
+ }
+
// TODO: Make this faster by using string search instead of parsing html.
// TODO: If the result is a play
BodyItems Youtube::get_related_media(const std::string &url) {
+ #if 0
BodyItems result_items;
struct ItemData {
BodyItems &result_items;
@@ -164,7 +308,7 @@ namespace QuickMedia {
}
std::string website_data;
- if(download_to_string(modified_url, website_data, {}, use_tor) != DownloadResult::OK)
+ if(download_to_string(modified_url, website_data, {}, use_tor, false) != DownloadResult::OK)
return result_items;
QuickMediaHtmlSearch html_search;
@@ -223,5 +367,109 @@ namespace QuickMedia {
last_related_media_playlist_id = playlist_id;
quickmedia_html_search_deinit(&html_search);
return result_items;
+ #elif 1
+ 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)
+ return result_items;
+
+ size_t data_start = website_data.find("window[\"ytInitialData\"] = {");
+ if(data_start == std::string::npos)
+ return result_items;
+
+ data_start = data_start + 26;
+ size_t data_end = 0;
+ int brace_count = 0;
+ for(size_t i = data_start; i < website_data.size(); ++i) {
+ char c = website_data[i];
+ if(c == '{')
+ ++brace_count;
+ else if(c == '}') {
+ --brace_count;
+ if(brace_count == 0) {
+ data_end = i + 1;
+ break;
+ }
+ }
+ }
+
+ if(data_end == 0)
+ return result_items;
+
+ 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(&website_data[data_start], &website_data[data_end], &json_root, &json_errors)) {
+ fprintf(stderr, "Youtube search json error: %s\n", json_errors.c_str());
+ return result_items;
+ }
+
+ FILE *ff = fopen("related.json", "wb");
+ fwrite(&website_data[data_start], 1, data_end - data_start, ff);
+ fclose(ff);
+
+ const Json::Value &contents_json = json_root["contents"];
+ if(!contents_json.isObject())
+ return result_items;
+
+ const Json::Value &tcwnr_json = contents_json["twoColumnWatchNextResults"];
+ if(!tcwnr_json.isObject())
+ return result_items;
+
+ const Json::Value &secondary_results_json = tcwnr_json["secondaryResults"];
+ if(!secondary_results_json.isObject())
+ return result_items;
+
+ const Json::Value &secondary_results2_json = secondary_results_json["secondaryResults"];
+ if(!secondary_results2_json.isObject())
+ return result_items;
+
+ const Json::Value &results_json = secondary_results2_json["results"];
+ if(!results_json.isArray())
+ return result_items;
+
+ for(const Json::Value &item_json : results_json) {
+ if(!item_json.isObject())
+ continue;
+
+ auto body_item = parse_compact_video_renderer_json(item_json);
+ if(body_item)
+ result_items.push_back(std::move(body_item));
+
+ const Json::Value &compact_autoplay_renderer_json = item_json["compactAutoplayRenderer"];
+ if(!compact_autoplay_renderer_json.isObject())
+ continue;
+
+ const Json::Value &item_contents_json = compact_autoplay_renderer_json["contents"];
+ if(!item_contents_json.isArray())
+ continue;
+
+ for(const Json::Value &content_item_json : item_contents_json) {
+ if(!content_item_json.isObject())
+ continue;
+
+ const Json::Value &compact_video_renderer_json = content_item_json["compactVideoRenderer"];
+ if(!compact_video_renderer_json.isObject())
+ continue;
+
+ auto body_item = parse_compact_video_renderer_json(content_item_json);
+ result_items.push_back(std::move(body_item));
+ }
+ }
+
+ return result_items;
+ #endif
}
} \ No newline at end of file