aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/Youtube.cpp
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2022-10-29 21:33:18 +0200
committerdec05eba <dec05eba@protonmail.com>2022-10-29 21:35:41 +0200
commit9c1d43e772efb8f5af4b7ef5562fb433c8985697 (patch)
treef675a51ab4f9ffad88d934216db6d44bafc187ad /src/plugins/Youtube.cpp
parent555f0e7e910b2231073734816727379e1276aa6c (diff)
Youtube: allow opening youtube channels directly from url. Same with ctrl+i info menu
Diffstat (limited to 'src/plugins/Youtube.cpp')
-rw-r--r--src/plugins/Youtube.cpp118
1 files changed, 82 insertions, 36 deletions
diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp
index 4dbb6c4..f2fb36e 100644
--- a/src/plugins/Youtube.cpp
+++ b/src/plugins/Youtube.cpp
@@ -91,6 +91,54 @@ namespace QuickMedia {
return false;
}
+ bool youtube_url_extract_channel_id(const std::string &youtube_url, std::string &channel_id, std::string &channel_url) {
+ size_t index = youtube_url.find("youtube.com/c/");
+ if(index != std::string::npos) {
+ index += 14;
+ size_t end_index = youtube_url.find("/", index);
+ if(end_index == std::string::npos)
+ end_index = youtube_url.size();
+ channel_id = youtube_url.substr(index, end_index - index);
+ channel_url = "https://www.youtube.com/c/" + channel_id;
+ return true;
+ }
+
+ index = youtube_url.find("youtu.be/c/");
+ if(index != std::string::npos) {
+ index += 11;
+ size_t end_index = youtube_url.find("/", index);
+ if(end_index == std::string::npos)
+ end_index = youtube_url.size();
+ channel_id = youtube_url.substr(index, end_index - index);
+ channel_url = "https://www.youtube.com/c/" + channel_id;
+ return true;
+ }
+
+ index = youtube_url.find("youtube.com/channel/");
+ if(index != std::string::npos) {
+ index += 20;
+ size_t end_index = youtube_url.find("/", index);
+ if(end_index == std::string::npos)
+ end_index = youtube_url.size();
+ channel_id = youtube_url.substr(index, end_index - index);
+ channel_url = "https://www.youtube.com/channel/" + channel_id;
+ return true;
+ }
+
+ index = youtube_url.find("youtu.be/channel/");
+ if(index != std::string::npos) {
+ index += 17;
+ size_t end_index = youtube_url.find("/", index);
+ if(end_index == std::string::npos)
+ end_index = youtube_url.size();
+ channel_id = youtube_url.substr(index, end_index - index);
+ channel_url = "https://www.youtube.com/channel/" + channel_id;
+ return true;
+ }
+
+ return false;
+ }
+
static std::mutex cookies_mutex;
static std::string cookies_filepath;
static std::string api_key;
@@ -687,10 +735,20 @@ namespace QuickMedia {
return "";
}
- static void parse_channel_videos(const Json::Value &json_root, std::string &continuation_token, std::unordered_set<std::string> &added_videos, BodyItems &body_items) {
+ static void parse_channel_videos(const Json::Value &json_root, std::string &continuation_token, std::unordered_set<std::string> &added_videos, std::string &browse_id, BodyItems &body_items) {
if(!json_root.isObject())
return;
+ const Json::Value &endpoint_json = json_root["endpoint"];
+ if(endpoint_json.isObject()) {
+ const Json::Value &browse_endpoint_json = endpoint_json["browseEndpoint"];
+ if(browse_endpoint_json.isObject()) {
+ const Json::Value &browse_id_json = browse_endpoint_json["browseId"];
+ if(browse_id_json.isString())
+ browse_id = browse_id_json.asString();
+ }
+ }
+
const Json::Value *response_json = &json_root["response"];
if(!response_json->isObject())
response_json = &json_root;
@@ -1415,19 +1473,6 @@ namespace QuickMedia {
return fetch_comments(this, video_url, continuation_token, result_items);
}
- static std::string channel_url_extract_id(const std::string &channel_url) {
- size_t index = channel_url.find("channel/");
- if(index == std::string::npos)
- return "";
-
- index += 8;
- size_t end_index = channel_url.find('/', index);
- if(end_index == std::string::npos)
- return channel_url.substr(index);
-
- return channel_url.substr(index, end_index - index);
- }
-
SearchResult YoutubeChannelPage::search(const std::string &str, BodyItems &result_items) {
added_videos.clear();
continuation_token.clear();
@@ -1435,6 +1480,13 @@ namespace QuickMedia {
if(str.empty())
return plugin_result_to_search_result(lazy_fetch(result_items));
+ std::string channel_id;
+ std::string channel_url;
+ if(!youtube_url_extract_channel_id(url, channel_id, channel_url)) {
+ fprintf(stderr, "Error: failed to extract youtube channel id from url: %s\n", url.c_str());
+ return SearchResult::ERR;
+ }
+
std::vector<CommandArg> cookies = get_cookies();
std::string next_url = "https://www.youtube.com/youtubei/v1/browse?key=" + url_param_encode(api_key) + "&gl=US&hl=en&prettyPrint=false";
@@ -1453,7 +1505,7 @@ namespace QuickMedia {
client_json["originalUrl"] = url + "/videos";
context_json["client"] = std::move(client_json);
request_json["context"] = std::move(context_json);
- request_json["browseId"] = channel_url_extract_id(url);
+ request_json["browseId"] = channel_id;
request_json["query"] = str;
request_json["params"] = "EgZzZWFyY2g%3D";
//request_json["continuation"] = current_continuation_token;
@@ -1668,35 +1720,29 @@ namespace QuickMedia {
DownloadResult result = download_json(json_root, url + "/videos?pbj=1&gl=US&hl=en", std::move(additional_args), true);
if(result != DownloadResult::OK) return download_result_to_plugin_result(result);
+ std::string browse_id;
if(json_root.isObject()) {
- search_page_submit_suggestion_handler(json_root, continuation_token, result_items, added_videos);
- parse_channel_videos(json_root, continuation_token, added_videos, result_items);
- return PluginResult::OK;
- }
-
- if(!json_root.isArray())
+ //search_page_submit_suggestion_handler(json_root, continuation_token, result_items, added_videos);
+ parse_channel_videos(json_root, continuation_token, added_videos, browse_id, result_items);
+ } else if(json_root.isArray()) {
+ for(const Json::Value &json_item : json_root) {
+ //search_page_submit_suggestion_handler(json_root, continuation_token, result_items, added_videos);
+ parse_channel_videos(json_item, continuation_token, added_videos, browse_id, result_items);
+ }
+ } else {
return PluginResult::ERR;
-
- for(const Json::Value &json_item : json_root) {
- search_page_submit_suggestion_handler(json_root, continuation_token, result_items, added_videos);
- parse_channel_videos(json_item, continuation_token, added_videos, result_items);
}
+
+ if(!browse_id.empty())
+ url = "https://www.youtube.com/channel/" + std::move(browse_id);
return PluginResult::OK;
}
TrackResult YoutubeChannelPage::track(const std::string&) {
- size_t channel_id_start = url.find("/channel/");
- if(channel_id_start == std::string::npos) {
- show_notification("QuickMedia", "Unable to get channel id from " + url, Urgency::CRITICAL);
- return TrackResult::ERR;
- }
-
- channel_id_start += 9;
- size_t channel_id_end = url.find('/', channel_id_start);
- if(channel_id_end == std::string::npos) channel_id_end = url.size();
- std::string channel_id = url.substr(channel_id_start, channel_id_end - channel_id_start);
- if(channel_id.empty()) {
+ std::string channel_id;
+ std::string channel_url;
+ if(!youtube_url_extract_channel_id(url, channel_id, channel_url)) {
show_notification("QuickMedia", "Unable to get channel id from " + url, Urgency::CRITICAL);
return TrackResult::ERR;
}