aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordec05eba <dec05eba@protonmail.com>2023-09-27 23:46:06 +0200
committerdec05eba <dec05eba@protonmail.com>2023-09-27 23:46:06 +0200
commitac01d918e5cfda3dd202b641cd38a7f554e5ae52 (patch)
tree2943f6b9c367ee9b8872ab388bb485e26058bcdb
parentd14f96048d30b0f536f59b70bf999d4d6e9bb0d0 (diff)
Add support for invidious popular feed (new config option)
-rw-r--r--example-config.json5
-rw-r--r--include/Config.hpp1
-rw-r--r--src/Config.cpp6
-rw-r--r--src/plugins/Youtube.cpp66
4 files changed, 73 insertions, 5 deletions
diff --git a/example-config.json b/example-config.json
index 5c220ec..a802dfa 100644
--- a/example-config.json
+++ b/example-config.json
@@ -42,7 +42,10 @@
},
"youtube": {
// If true, resume playback where you left off in youtube videos
- "load_progress": true
+ "load_progress": true,
+ // The invidious instance to use. This is currently only used to show a video feed.
+ // If not set, then local recommendations are used instead.
+ "invidious_instance": ""
},
"matrix": {
// List of homeservers to display in the "Room directory" tab
diff --git a/include/Config.hpp b/include/Config.hpp
index 44cde39..7b77577 100644
--- a/include/Config.hpp
+++ b/include/Config.hpp
@@ -46,6 +46,7 @@ namespace QuickMedia {
struct YoutubeConfig {
bool load_progress = true;
+ std::string invidious_instance;
};
struct MatrixConfig {
diff --git a/src/Config.cpp b/src/Config.cpp
index 474e6a9..54aa21e 100644
--- a/src/Config.cpp
+++ b/src/Config.cpp
@@ -57,6 +57,8 @@ namespace QuickMedia {
std::string result;
if(!path.empty() && path[0] == '~')
result = get_home_dir().data + path.substr(1);
+ else if(path.size() >= 5 && strncmp(path.c_str(), "$HOME", 5) == 0)
+ result = get_home_dir().data + path.substr(5);
else
result = path;
return result;
@@ -210,8 +212,10 @@ namespace QuickMedia {
}
const Json::Value &youtube_json = json_root["youtube"];
- if(youtube_json.isObject())
+ if(youtube_json.isObject()) {
get_json_value(youtube_json, "load_progress", config->youtube.load_progress);
+ get_json_value(youtube_json, "invidious_instance", config->youtube.invidious_instance);
+ }
bool has_known_matrix_homeservers_config = false;
const Json::Value &matrix_json = json_root["matrix"];
diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp
index f7cfb09..474d3a2 100644
--- a/src/plugins/Youtube.cpp
+++ b/src/plugins/Youtube.cpp
@@ -945,14 +945,74 @@ namespace QuickMedia {
}
}
+ static SearchResult invidious_get_popular_feed(Page *page, const std::string &invidious_instance, BodyItems &result_items) {
+ Json::Value json_root;
+ std::string err_msg;
+ DownloadResult download_result = page->download_json(json_root, invidious_instance + "/api/v1/popular", {});
+ if(download_result != DownloadResult::OK) return download_result_to_search_result(download_result);
+
+ if(!json_root.isArray())
+ return SearchResult::ERR;
+
+ for(const Json::Value &item_json : json_root) {
+ if(!item_json.isObject())
+ continue;
+
+ const Json::Value &title_json = item_json["title"];
+ const Json::Value &video_id_json = item_json["videoId"];
+ const Json::Value &length_seconds_json = item_json["lengthSeconds"];
+ const Json::Value &author_json = item_json["author"];
+ const Json::Value &published_text_json = item_json["publishedText"];
+ const Json::Value &view_count_json = item_json["viewCount"];
+
+ if(!title_json.isString() || !video_id_json.isString())
+ continue;
+
+ std::string video_id_str = video_id_json.asString();
+ auto body_item = BodyItem::create(title_json.asString());
+ std::string desc;
+ if(view_count_json.isInt64())
+ desc += std::to_string(view_count_json.asInt64()) + " view" + (view_count_json.asInt64() == 1 ? "" : "s");
+ if(published_text_json.isString()) {
+ if(!desc.empty())
+ desc += " • ";
+ desc += published_text_json.asString();
+ }
+ if(length_seconds_json.isInt64()) {
+ if(!desc.empty())
+ desc += '\n';
+ desc += seconds_to_duration(length_seconds_json.asInt64());
+ }
+ if(author_json.isString()) {
+ if(!desc.empty())
+ desc += '\n';
+ desc += author_json.asString();
+ }
+ body_item->set_description(std::move(desc));
+ body_item->set_description_color(get_theme().faded_text_color);
+ body_item->url = "https://www.youtube.com/watch?v=" + video_id_str;
+
+ body_item->thumbnail_url = "https://img.youtube.com/vi/" + video_id_str + "/mqdefault.jpg";
+ body_item->thumbnail_size = mgl::vec2i(192, 108);
+ result_items.push_back(std::move(body_item));
+ }
+
+ return SearchResult::OK;
+ }
+
SearchResult YoutubeSearchPage::search(const std::string &str, BodyItems &result_items) {
continuation_token.clear();
current_page = 0;
added_videos.clear();
if(str.empty()) {
- program->fill_recommended_items_from_json("youtube", program->load_recommended_json("youtube"), result_items);
- return SearchResult::OK;
+ const std::string &invidious_instance = get_config().youtube.invidious_instance;
+ if(invidious_instance.empty()) {
+ program->fill_recommended_items_from_json("youtube", program->load_recommended_json("youtube"), result_items);
+ return SearchResult::OK;
+ } else {
+ return invidious_get_popular_feed(this, invidious_instance, result_items);
+ }
}
// TODO: Find this search url from youtube.com/... searchbox.js, and the url to that script from youtube.com/ html
@@ -1101,7 +1161,7 @@ namespace QuickMedia {
continuation_token.clear();
current_page = 0;
added_videos.clear();
- program->fill_recommended_items_from_json("youtube", program->load_recommended_json("youtube"), result_items);
+ search("", result_items);
get_cookies();
return PluginResult::OK;
}