aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/QuickMedia.cpp61
-rw-r--r--src/plugins/Youtube.cpp106
2 files changed, 77 insertions, 90 deletions
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index 8c3f5b6..3b059d9 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -187,16 +187,54 @@ namespace QuickMedia {
Page *search_page;
};
+ static Path get_recommended_filepath(const char *plugin_name) {
+ Path video_history_dir = get_storage_dir().join("recommended");
+ if(create_directory_recursive(video_history_dir) != 0) {
+ std::string err_msg = "Failed to create recommended directory ";
+ err_msg += video_history_dir.data;
+ show_notification("QuickMedia", err_msg.c_str(), Urgency::CRITICAL);
+ exit(1);
+ }
+
+ Path video_history_filepath = video_history_dir;
+ return video_history_filepath.join(plugin_name).append(".json");
+ }
+
// TODO: Make asynchronous
- static void fill_recommended_items_from_json(const Json::Value &recommended_json, BodyItems &body_items) {
+ static void fill_recommended_items_from_json(const char *plugin_name, const Json::Value &recommended_json, BodyItems &body_items) {
assert(recommended_json.isObject());
+ const int64_t recommendations_autodelete_period = 60*60*24*20; // 20 days
+ time_t time_now = time(NULL);
+ int num_items_deleted = 0;
+
std::vector<std::pair<std::string, Json::Value>> recommended_items(recommended_json.size());
/* TODO: Optimize member access */
for(auto &member_name : recommended_json.getMemberNames()) {
Json::Value recommended_item = recommended_json[member_name];
- if(recommended_item.isObject())
- recommended_items.push_back(std::make_pair(member_name, std::move(recommended_item)));
+ if(recommended_item.isObject()) {
+ Json::Value recommended_timestamp_json = recommended_item.get("recommended_timestamp", Json::Value::nullSingleton());
+ Json::Value watched_timestamp_json = recommended_item.get("watched_timestamp", Json::Value::nullSingleton());
+ if(watched_timestamp_json.isNumeric() && time_now - watched_timestamp_json.asInt64() >= recommendations_autodelete_period) {
+ ++num_items_deleted;
+ } else if(recommended_timestamp_json.isNumeric() && time_now - recommended_timestamp_json.asInt64() >= recommendations_autodelete_period) {
+ ++num_items_deleted;
+ } else if(recommended_timestamp_json.isNull() && watched_timestamp_json.isNull()) {
+ ++num_items_deleted;
+ } else {
+ recommended_items.push_back(std::make_pair(member_name, std::move(recommended_item)));
+ }
+ }
+ }
+
+ if(num_items_deleted > 0) {
+ // TODO: Is there a better way?
+ Json::Value new_recommendations(Json::objectValue);
+ for(auto &recommended : recommended_items) {
+ new_recommendations[recommended.first] = recommended.second;
+ }
+ fprintf(stderr, "Number of old recommendations to delete: %d\n", num_items_deleted);
+ save_json_to_file_atomic(get_recommended_filepath(plugin_name), new_recommendations);
}
/* TODO: Better algorithm for recommendations */
@@ -567,7 +605,7 @@ namespace QuickMedia {
auto recommended_body = create_body();
recommended_body->draw_thumbnails = true;
- fill_recommended_items_from_json(load_recommended_json(), recommended_body->items);
+ fill_recommended_items_from_json(plugin_name, load_recommended_json(), recommended_body->items);
tabs.push_back(Tab{std::move(recommended_body), std::make_unique<RecommendedPage>(this, tabs.front().page.get()), create_search_bar("Search...", SEARCH_DELAY_FILTER)});
} else if(strcmp(plugin_name, "pornhub") == 0) {
auto search_body = create_body();
@@ -727,19 +765,6 @@ namespace QuickMedia {
return video_history_filepath.join(plugin_name).append(".json");
}
- static Path get_recommended_filepath(const char *plugin_name) {
- Path video_history_dir = get_storage_dir().join("recommended");
- if(create_directory_recursive(video_history_dir) != 0) {
- std::string err_msg = "Failed to create recommended directory ";
- err_msg += video_history_dir.data;
- show_notification("QuickMedia", err_msg.c_str(), Urgency::CRITICAL);
- exit(1);
- }
-
- Path video_history_filepath = video_history_dir;
- return video_history_filepath.join(plugin_name).append(".json");
- }
-
// This is not cached because we could have multiple instances of QuickMedia running the same plugin!
// TODO: Find a way to optimize this
Json::Value Program::load_video_history_json() {
@@ -1705,7 +1730,7 @@ namespace QuickMedia {
current_page = previous_page;
break;
} else if(update_err != VideoPlayer::Error::OK) {
- show_notification("Video player", "The video player failed to play the video", Urgency::CRITICAL);
+ show_notification("Video player", "The video player failed to play the video (error code " + std::to_string((int)update_err) + ")", Urgency::CRITICAL);
current_page = previous_page;
break;
}
diff --git a/src/plugins/Youtube.cpp b/src/plugins/Youtube.cpp
index 9e84903..a9a2811 100644
--- a/src/plugins/Youtube.cpp
+++ b/src/plugins/Youtube.cpp
@@ -4,15 +4,8 @@
#include <unordered_set>
namespace QuickMedia {
- static std::shared_ptr<BodyItem> parse_content_video_renderer(const Json::Value &content_item_json, std::unordered_set<std::string> &added_videos) {
- if(!content_item_json.isObject())
- return nullptr;
-
- const Json::Value &video_renderer_json = content_item_json["videoRenderer"];
- if(!video_renderer_json.isObject())
- return nullptr;
-
- const Json::Value &video_id_json = video_renderer_json["videoId"];
+ static std::shared_ptr<BodyItem> parse_common_video_item(const Json::Value &video_item_json, std::unordered_set<std::string> &added_videos) {
+ const Json::Value &video_id_json = video_item_json["videoId"];
if(!video_id_json.isString())
return nullptr;
@@ -23,7 +16,7 @@ namespace QuickMedia {
std::string thumbnail_url = "https://img.youtube.com/vi/" + video_id_str + "/hqdefault.jpg";
const char *date = nullptr;
- const Json::Value &published_time_text_json = video_renderer_json["publishedTimeText"];
+ const Json::Value &published_time_text_json = video_item_json["publishedTimeText"];
if(published_time_text_json.isObject()) {
const Json::Value &text_json = published_time_text_json["simpleText"];
if(text_json.isString())
@@ -31,7 +24,7 @@ namespace QuickMedia {
}
const char *length = nullptr;
- const Json::Value &length_text_json = video_renderer_json["lengthText"];
+ const Json::Value &length_text_json = video_item_json["lengthText"];
if(length_text_json.isObject()) {
const Json::Value &text_json = length_text_json["simpleText"];
if(text_json.isString())
@@ -39,15 +32,25 @@ namespace QuickMedia {
}
const char *title = nullptr;
- const Json::Value &title_json = video_renderer_json["title"];
+ const Json::Value &title_json = video_item_json["title"];
if(title_json.isObject()) {
- const Json::Value &runs_json = title_json["runs"];
- if(runs_json.isArray() && !runs_json.empty()) {
- 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();
+ const Json::Value &simple_text_json = title_json["simpleText"];
+ if(simple_text_json.isString()) {
+ title = simple_text_json.asCString();
+ }
+ }
+
+ if(!title) {
+ const Json::Value &title_json = video_item_json["title"];
+ if(title_json.isObject()) {
+ const Json::Value &runs_json = title_json["runs"];
+ if(runs_json.isArray() && !runs_json.empty()) {
+ 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();
+ }
}
}
}
@@ -72,6 +75,17 @@ namespace QuickMedia {
return body_item;
}
+ static std::shared_ptr<BodyItem> parse_content_video_renderer(const Json::Value &content_item_json, std::unordered_set<std::string> &added_videos) {
+ if(!content_item_json.isObject())
+ return nullptr;
+
+ const Json::Value &video_renderer_json = content_item_json["videoRenderer"];
+ if(!video_renderer_json.isObject())
+ return nullptr;
+
+ return parse_common_video_item(video_renderer_json, added_videos);
+ }
+
// Returns empty string if continuation token can't be found
static std::string item_section_renderer_get_continuation_token(const Json::Value &item_section_renderer_json) {
const Json::Value &continuations_json = item_section_renderer_json["continuations"];
@@ -150,60 +164,8 @@ namespace QuickMedia {
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();
- if(added_videos.find(video_id_str) != added_videos.end())
- return nullptr;
-
- std::string thumbnail_url = "https://img.youtube.com/vi/" + video_id_str + "/hqdefault.jpg";
-
- const char *date = nullptr;
- const Json::Value &published_time_text_json = compact_video_renderer_json["publishedTimeText"];
- if(published_time_text_json.isObject()) {
- const Json::Value &text_json = published_time_text_json["simpleText"];
- if(text_json.isString())
- date = text_json.asCString();
- }
-
- const char *length = nullptr;
- const Json::Value &length_text_json = compact_video_renderer_json["lengthText"];
- if(length_text_json.isObject()) {
- const Json::Value &text_json = length_text_json["simpleText"];
- if(text_json.isString())
- length = text_json.asCString();
- }
-
- 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 = BodyItem::create(title);
- /* TODO: Make date a different color */
- std::string date_str;
- if(date)
- date_str += date;
- if(length) {
- if(!date_str.empty())
- date_str += '\n';
- date_str += length;
- }
- body_item->set_description(std::move(date_str));
- body_item->url = "https://www.youtube.com/watch?v=" + video_id_str;
- body_item->thumbnail_url = std::move(thumbnail_url);
- added_videos.insert(video_id_str);
- return body_item;
+ return parse_common_video_item(compact_video_renderer_json, added_videos);
}
SearchResult YoutubeSearchPage::search(const std::string &str, BodyItems &result_items) {