From 19c58ef32be910c5c0c9f37740d0601e37eaafa7 Mon Sep 17 00:00:00 2001 From: dec05eba Date: Wed, 6 Apr 2022 06:55:08 +0200 Subject: Youtube: fix search, channel page, related videos and comments For these pages, the json response root is not longer an array. It's instead the first json object in the array. --- src/plugins/Lbry.cpp | 4 + src/plugins/Youtube.cpp | 282 ++++++++++++++++++++++-------------------------- 2 files changed, 135 insertions(+), 151 deletions(-) diff --git a/src/plugins/Lbry.cpp b/src/plugins/Lbry.cpp index feac2c5..92532cb 100644 --- a/src/plugins/Lbry.cpp +++ b/src/plugins/Lbry.cpp @@ -83,6 +83,8 @@ namespace QuickMedia { std::string description; if(is_channel) { + // TODO: Followers + const Json::Value &meta_json = result_json["meta"]; if(meta_json.isObject()) { const Json::Value &claims_in_channel_json = meta_json["claims_in_channel"]; @@ -98,6 +100,8 @@ namespace QuickMedia { description += name_json.asString(); } } else { + // TODO: Views + const Json::Value ×tamp_json = result_json["timestamp"]; if(timestamp_json.isInt64()) description = seconds_to_relative_time_str(time_now - timestamp_json.asInt64()); diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp index 1cbf477..c32e22e 100644 --- a/src/plugins/Youtube.cpp +++ b/src/plugins/Youtube.cpp @@ -678,89 +678,85 @@ namespace QuickMedia { static BodyItems parse_channel_videos(const Json::Value &json_root, std::string &continuation_token, std::unordered_set &added_videos) { BodyItems body_items; - if(!json_root.isArray()) + + if(!json_root.isObject()) + return body_items; + + const Json::Value &response_json = json_root["response"]; + if(!response_json.isObject()) + return body_items; + + const Json::Value &contents_json = response_json["contents"]; + if(!contents_json.isObject()) + return body_items; + + const Json::Value &tcbrr_json = contents_json["twoColumnBrowseResultsRenderer"]; + if(!tcbrr_json.isObject()) + return body_items; + + const Json::Value &tabs_json = tcbrr_json["tabs"]; + if(!tabs_json.isArray()) return body_items; std::string new_continuation_token; - for(const Json::Value &json_item : json_root) { - if(!json_item.isObject()) + for(const Json::Value &tab_json : tabs_json) { + if(!tab_json.isObject()) continue; - const Json::Value &response_json = json_item["response"]; - if(!response_json.isObject()) + const Json::Value &tab_renderer_json = tab_json["tabRenderer"]; + if(!tab_renderer_json.isObject()) continue; - - const Json::Value &contents_json = response_json["contents"]; - if(!contents_json.isObject()) + + const Json::Value &content_json = tab_renderer_json["content"]; + if(!content_json.isObject()) continue; - const Json::Value &tcbrr_json = contents_json["twoColumnBrowseResultsRenderer"]; - if(!tcbrr_json.isObject()) + const Json::Value §ion_list_renderer = content_json["sectionListRenderer"]; + if(!section_list_renderer.isObject()) continue; - const Json::Value &tabs_json = tcbrr_json["tabs"]; - if(!tabs_json.isArray()) + const Json::Value &contents2_json = section_list_renderer["contents"]; + if(!contents2_json.isArray()) continue; - - for(const Json::Value &tab_json : tabs_json) { - if(!tab_json.isObject()) - continue; - - const Json::Value &tab_renderer_json = tab_json["tabRenderer"]; - if(!tab_renderer_json.isObject()) + + for(const Json::Value &content_item_json : contents2_json) { + if(!content_item_json.isObject()) continue; - const Json::Value &content_json = tab_renderer_json["content"]; - if(!content_json.isObject()) + const Json::Value &item_section_renderer_json = content_item_json["itemSectionRenderer"]; + if(!item_section_renderer_json.isObject()) continue; - const Json::Value §ion_list_renderer = content_json["sectionListRenderer"]; - if(!section_list_renderer.isObject()) + const Json::Value &item_contents_json = item_section_renderer_json["contents"]; + if(!item_contents_json.isArray()) continue; - const Json::Value &contents2_json = section_list_renderer["contents"]; - if(!contents2_json.isArray()) - continue; - - for(const Json::Value &content_item_json : contents2_json) { - if(!content_item_json.isObject()) + for(const Json::Value &content_json : item_contents_json) { + if(!content_json.isObject()) continue; - - const Json::Value &item_section_renderer_json = content_item_json["itemSectionRenderer"]; - if(!item_section_renderer_json.isObject()) + + const Json::Value &grid_renderer_json = content_json["gridRenderer"]; + if(!grid_renderer_json.isObject()) continue; - const Json::Value &item_contents_json = item_section_renderer_json["contents"]; - if(!item_contents_json.isArray()) + const Json::Value &items_json = grid_renderer_json["items"]; + if(!items_json.isArray()) continue; - for(const Json::Value &content_json : item_contents_json) { - if(!content_json.isObject()) + for(const Json::Value &item_json : items_json) { + if(!item_json.isObject()) continue; - const Json::Value &grid_renderer_json = content_json["gridRenderer"]; - if(!grid_renderer_json.isObject()) - continue; + if(new_continuation_token.empty()) + new_continuation_token = item_section_renderer_get_continuation_token(item_json); - const Json::Value &items_json = grid_renderer_json["items"]; - if(!items_json.isArray()) + const Json::Value &grid_video_renderer = item_json["gridVideoRenderer"]; + if(!grid_video_renderer.isObject()) continue; - for(const Json::Value &item_json : items_json) { - if(!item_json.isObject()) - continue; - - if(new_continuation_token.empty()) - new_continuation_token = item_section_renderer_get_continuation_token(item_json); - - const Json::Value &grid_video_renderer = item_json["gridVideoRenderer"]; - if(!grid_video_renderer.isObject()) - continue; - - auto body_item = parse_common_video_item(grid_video_renderer, added_videos); - if(body_item) - body_items.push_back(std::move(body_item)); - } + auto body_item = parse_common_video_item(grid_video_renderer, added_videos); + if(body_item) + body_items.push_back(std::move(body_item)); } } } @@ -901,31 +897,26 @@ namespace QuickMedia { 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_plugin_result(result); - if(!json_root.isArray()) + if(!json_root.isObject()) return PluginResult::ERR; - for(const Json::Value &json_item : json_root) { - if(!json_item.isObject()) - continue; - - const Json::Value &response_json = json_item["response"]; - if(!response_json.isObject()) - continue; + const Json::Value &response_json = json_root["response"]; + if(!response_json.isObject()) + return PluginResult::OK; - const Json::Value &contents_json = response_json["contents"]; - if(!contents_json.isObject()) - continue; + const Json::Value &contents_json = response_json["contents"]; + if(!contents_json.isObject()) + return PluginResult::OK; - const Json::Value &tcsrr_json = contents_json["twoColumnSearchResultsRenderer"]; - if(!tcsrr_json.isObject()) - continue; + const Json::Value &tcsrr_json = contents_json["twoColumnSearchResultsRenderer"]; + if(!tcsrr_json.isObject()) + return PluginResult::OK; - const Json::Value &primary_contents_json = tcsrr_json["primaryContents"]; - if(!primary_contents_json.isObject()) - continue; + const Json::Value &primary_contents_json = tcsrr_json["primaryContents"]; + if(!primary_contents_json.isObject()) + return PluginResult::OK; - parse_section_list_renderer(primary_contents_json["sectionListRenderer"], continuation_token, result_items, added_videos); - } + parse_section_list_renderer(primary_contents_json["sectionListRenderer"], continuation_token, result_items, added_videos); return PluginResult::OK; } @@ -956,49 +947,44 @@ namespace QuickMedia { DownloadResult result = download_json(json_root, next_url, std::move(additional_args), true); if(result != DownloadResult::OK) return download_result_to_plugin_result(result); - if(!json_root.isArray()) + if(!json_root.isObject()) return PluginResult::ERR; + const Json::Value &response_json = json_root["response"]; + if(!response_json.isObject()) + return PluginResult::OK; + + const Json::Value &on_response_received_commands_json = response_json["onResponseReceivedCommands"]; + if(!on_response_received_commands_json.isArray()) + return PluginResult::OK; + std::string new_continuation_token; - for(const Json::Value &json_item : json_root) { - if(!json_item.isObject()) + for(const Json::Value &response_received_command : on_response_received_commands_json) { + if(!response_received_command.isObject()) continue; - const Json::Value &response_json = json_item["response"]; - if(!response_json.isObject()) + const Json::Value &append_continuation_items_action_json = response_received_command["appendContinuationItemsAction"]; + if(!append_continuation_items_action_json.isObject()) continue; - const Json::Value &on_response_received_commands_json = response_json["onResponseReceivedCommands"]; - if(!on_response_received_commands_json.isArray()) + const Json::Value &continuation_items_json = append_continuation_items_action_json["continuationItems"]; + if(!continuation_items_json.isArray()) continue; - for(const Json::Value &response_received_command : on_response_received_commands_json) { - if(!response_received_command.isObject()) + for(const Json::Value &continuation_item : continuation_items_json) { + if(!continuation_item.isObject()) continue; - const Json::Value &append_continuation_items_action_json = response_received_command["appendContinuationItemsAction"]; - if(!append_continuation_items_action_json.isObject()) - continue; + if(new_continuation_token.empty()) { + // Note: item_section_renderer is compatible with continuation_item + new_continuation_token = item_section_renderer_get_continuation_token(continuation_item); + } - const Json::Value &continuation_items_json = append_continuation_items_action_json["continuationItems"]; - if(!continuation_items_json.isArray()) + const Json::Value &item_section_renderer_json = continuation_item["itemSectionRenderer"]; + if(!item_section_renderer_json.isObject()) continue; - for(const Json::Value &continuation_item : continuation_items_json) { - if(!continuation_item.isObject()) - continue; - - if(new_continuation_token.empty()) { - // Note: item_section_renderer is compatible with continuation_item - new_continuation_token = item_section_renderer_get_continuation_token(continuation_item); - } - - const Json::Value &item_section_renderer_json = continuation_item["itemSectionRenderer"]; - if(!item_section_renderer_json.isObject()) - continue; - - parse_item_section_renderer(item_section_renderer_json, added_videos, result_items); - } + parse_item_section_renderer(item_section_renderer_json, added_videos, result_items); } } @@ -1911,66 +1897,60 @@ namespace QuickMedia { DownloadResult download_result = download_json(json_root, "https://www.youtube.com/watch?v=" + video_id + "&pbj=1&gl=US&hl=en", additional_args, true); if(download_result != DownloadResult::OK) return result_items; - if(!json_root.isArray()) + if(!json_root.isObject()) return result_items; - std::unordered_set added_videos; + const Json::Value &response_json = json_root["response"]; + if(!response_json.isObject()) + return result_items; - for(const Json::Value &json_item : json_root) { - if(!json_item.isObject()) - continue; + const Json::Value &contents_json = response_json["contents"]; + if(!contents_json.isObject()) + return result_items; - const Json::Value &response_json = json_item["response"]; - if(!response_json.isObject()) - continue; + const Json::Value &tcwnr_json = contents_json["twoColumnWatchNextResults"]; + if(!tcwnr_json.isObject()) + return result_items; - const Json::Value &contents_json = response_json["contents"]; - if(!contents_json.isObject()) - return result_items; + if(comments_continuation_token.empty()) + comments_continuation_token = two_column_watch_next_results_get_comments_continuation_token(tcwnr_json); - 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; - if(comments_continuation_token.empty()) - comments_continuation_token = two_column_watch_next_results_get_comments_continuation_token(tcwnr_json); + 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; - const Json::Value &secondary_results_json = tcwnr_json["secondaryResults"]; - if(!secondary_results_json.isObject()) - return result_items; + std::unordered_set added_videos; + for(const Json::Value &item_json : results_json) { + if(!item_json.isObject()) + continue; - const Json::Value &secondary_results2_json = secondary_results_json["secondaryResults"]; - if(!secondary_results2_json.isObject()) - return result_items; + auto body_item = parse_compact_video_renderer_json(item_json, added_videos); + if(body_item) + result_items.push_back(std::move(body_item)); - 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()) + 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; - - auto body_item = parse_compact_video_renderer_json(item_json, added_videos); + + auto body_item = parse_compact_video_renderer_json(content_item_json, added_videos); 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; - - auto body_item = parse_compact_video_renderer_json(content_item_json, added_videos); - if(body_item) - result_items.push_back(std::move(body_item)); - } } } -- cgit v1.2.3