diff options
author | dec05eba <dec05eba@protonmail.com> | 2021-08-09 18:22:43 +0200 |
---|---|---|
committer | dec05eba <dec05eba@protonmail.com> | 2021-08-09 18:22:43 +0200 |
commit | 44bc399ccbd7e37107ae754db7da3d918229422d (patch) | |
tree | cf989a2699c7638328f292bcde49ed66ac013640 /src/plugins | |
parent | c2efd1e6587223cf9fff302fbc0ef80fcb4340e2 (diff) |
Youtube: show search suggestions instead of immediate search
Fix save file dialog not showing all files after navigating to another
directory if the search is not empty.
Fix matrix system message deletion reverting back to use message (for
avatar) and text color.
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/MediaGeneric.cpp | 8 | ||||
-rw-r--r-- | src/plugins/Youtube.cpp | 139 |
2 files changed, 102 insertions, 45 deletions
diff --git a/src/plugins/MediaGeneric.cpp b/src/plugins/MediaGeneric.cpp index c829a33..d536a09 100644 --- a/src/plugins/MediaGeneric.cpp +++ b/src/plugins/MediaGeneric.cpp @@ -191,9 +191,11 @@ namespace QuickMedia { return result_items; } - std::unique_ptr<Page> MediaGenericVideoPage::create_search_page(Program*, int &search_delay) { - search_delay = 500; // TODO: Make configurable? - return std::make_unique<MediaGenericSearchPage>(*search_page); + bool MediaGenericVideoPage::create_search_page(Program*, Tab &tab) { + tab.body = create_body(false, true); + tab.page = std::make_unique<MediaGenericSearchPage>(*search_page); + tab.search_bar = create_search_bar("Search...", 500); // TODO: Make search delay configurable? + return true; } std::unique_ptr<RelatedVideosPage> MediaGenericVideoPage::create_related_videos_page(Program *program) { diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index ea72f03..5b0591c 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -764,12 +764,98 @@ namespace QuickMedia { } SearchResult YoutubeSearchPage::search(const std::string &str, BodyItems &result_items) { + if(str.empty()) + return SearchResult::OK; + + // TODO: Find this search url from youtube.com/... searchbox.js, and the url to that script from youtube.com/ html + std::string url = "https://suggestqueries-clients6.youtube.com/complete/search?client=youtube&hl=en&gl=us&sugexp=rdcfrc%2Ccfro%3D1%2Cfp.cfr%3D1&gs_rn=64&gs_ri=youtube&ds=yt&cp=4&gs_id=f&xhr=t&xssi=t&q="; + url += url_param_encode(str); + if(!video_id.empty()) + url += "&video_id=" + video_id; + + std::vector<CommandArg> additional_args = { + { "-H", "origin: https://www.youtube.com" }, + { "-H", "referer: https://www.youtube.com/" } + }; + + std::vector<CommandArg> cookies = get_cookies(); + additional_args.insert(additional_args.end(), cookies.begin(), cookies.end()); + + std::string website_data; + DownloadResult result = download_to_string(url, website_data, std::move(additional_args), true); + if(result != DownloadResult::OK) return download_result_to_search_result(result); + + const size_t json_start_index = website_data.find('['); + if(json_start_index == std::string::npos) + return SearchResult::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[json_start_index], &website_data[website_data.size()], &json_root, &json_errors)) { + fprintf(stderr, "youtube search error: %s\n", json_errors.c_str()); + return SearchResult::ERR; + } + + if(!json_root.isArray() || json_root.size() < 2) + return SearchResult::ERR; + + const Json::Value &search_result_list_json = json_root[1]; + if(!search_result_list_json.isArray()) + return SearchResult::ERR; + + for(const Json::Value &json_item : search_result_list_json) { + if(!json_item.isArray() || json_item.size() == 0) + continue; + + const Json::Value &search_result_json = json_item[0]; + if(!search_result_json.isString()) + continue; + + auto body_item = BodyItem::create(search_result_json.asString()); + body_item->url = body_item->get_title(); + result_items.push_back(std::move(body_item)); + } + + if(result_items.empty() || !strcase_equals(str.c_str(), result_items.front()->get_title().c_str())) { + auto body_item = BodyItem::create(str); + body_item->url = str; + result_items.insert(result_items.begin(), std::move(body_item)); + } + + return SearchResult::OK; + } + + PluginResult YoutubeSearchPage::get_page(const std::string&, int page, BodyItems &result_items) { + while(current_page < page) { + PluginResult plugin_result = search_get_continuation(search_url, continuation_token, result_items); + if(plugin_result != PluginResult::OK) return plugin_result; + ++current_page; + } + return PluginResult::OK; + } + + PluginResult YoutubeSearchPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) { + if(url.empty()) + return PluginResult::OK; + + if(strncmp(url.c_str(), "https://www.youtube.com/channel/", 32) == 0) { + // TODO: Make all pages (for all services) lazy fetch in a similar manner! + result_tabs.push_back(Tab{create_body(false, true), std::make_unique<YoutubeChannelPage>(program, url, "", title), create_search_bar("Search...", 350)}); + } else { + result_tabs.push_back(Tab{nullptr, std::make_unique<YoutubeVideoPage>(program, url), nullptr}); + } + return PluginResult::OK; + } + + PluginResult YoutubeSearchPage::submit_suggestion(const std::string&, const std::string &url, BodyItems &result_items) { continuation_token.clear(); current_page = 0; added_videos.clear(); search_url = "https://www.youtube.com/results?search_query="; - search_url += url_param_encode(str); + search_url += url_param_encode(url); std::vector<CommandArg> additional_args = { { "-H", "x-spf-referer: " + search_url }, @@ -783,10 +869,10 @@ namespace QuickMedia { Json::Value json_root; DownloadResult result = download_json(json_root, search_url + "&pbj=1&gl=US&hl=en", std::move(additional_args), true); - if(result != DownloadResult::OK) return download_result_to_search_result(result); + if(result != DownloadResult::OK) return download_result_to_plugin_result(result); if(!json_root.isArray()) - return SearchResult::ERR; + return PluginResult::ERR; for(const Json::Value &json_item : json_root) { if(!json_item.isObject()) @@ -811,28 +897,6 @@ namespace QuickMedia { parse_section_list_renderer(primary_contents_json["sectionListRenderer"], continuation_token, result_items, added_videos); } - return SearchResult::OK; - } - - PluginResult YoutubeSearchPage::get_page(const std::string&, int page, BodyItems &result_items) { - while(current_page < page) { - PluginResult plugin_result = search_get_continuation(search_url, continuation_token, result_items); - if(plugin_result != PluginResult::OK) return plugin_result; - ++current_page; - } - return PluginResult::OK; - } - - PluginResult YoutubeSearchPage::submit(const std::string &title, const std::string &url, std::vector<Tab> &result_tabs) { - if(url.empty()) - return PluginResult::OK; - - if(strncmp(url.c_str(), "https://www.youtube.com/channel/", 32) == 0) { - // TODO: Make all pages (for all services) lazy fetch in a similar manner! - result_tabs.push_back(Tab{create_body(false, true), std::make_unique<YoutubeChannelPage>(program, url, "", title), create_search_bar("Search...", 350)}); - } else { - result_tabs.push_back(Tab{nullptr, std::make_unique<YoutubeVideoPage>(program, url), nullptr}); - } return PluginResult::OK; } @@ -2061,9 +2125,14 @@ namespace QuickMedia { return result_items; } - std::unique_ptr<Page> YoutubeVideoPage::create_search_page(Program *program, int &search_delay) { - search_delay = 350; - return std::make_unique<YoutubeSearchPage>(program); + bool YoutubeVideoPage::create_search_page(Program *program, Tab &tab) { + std::string video_id; + youtube_url_extract_id(url, video_id); + + tab.body = create_body(false, false); + tab.page = std::make_unique<YoutubeSearchPage>(program, std::move(video_id)); + tab.search_bar = create_search_bar("Search...", 100); + return true; } std::unique_ptr<Page> YoutubeVideoPage::create_comments_page(Program *program) { @@ -2095,20 +2164,6 @@ namespace QuickMedia { return result; } - static std::string url_extract_param(const std::string &url, const std::string ¶m) { - std::string param_s = param + "="; - size_t index = url.find(param_s); - if(index == std::string::npos) - return ""; - - index += param_s.size(); - size_t end = url.find('&', index); - if(end == std::string::npos) - end = url.size(); - - return url.substr(index, end - index); - } - static const YoutubeVideoFormat* get_highest_resolution_mp4_non_av1(const std::vector<YoutubeVideoFormat> &video_formats, int max_height) { for(const YoutubeVideoFormat &video_format : video_formats) { if(video_format.height <= max_height && video_format.base.mime_type.find("mp4") != std::string::npos && video_format.base.mime_type.find("av01") == std::string::npos) |