#include "../../plugins/WatchProgress.hpp" #include "../../include/Storage.hpp" #include "../../include/Notification.hpp" #include namespace QuickMedia { double WatchProgress::get_watch_ratio() const { if(duration_sec == 0) return 0; return (double)time_pos_sec / (double)duration_sec; } // We consider having watched the video if the user stopped watching 90% in, because they might skip the ending theme/credits (especially in anime) bool WatchProgress::has_finished_watching() const { return get_watch_ratio() >= 0.9; } bool set_watch_progress_for_plugin(const char *plugin_name, const std::string &id, int64_t time_pos_sec, int64_t duration_sec, const std::string &thumbnail_url) { Path watch_progress_dir = get_storage_dir().join("watch-progress"); if(create_directory_recursive(watch_progress_dir) != 0) { show_notification("QuickMedia", "Failed to create " + watch_progress_dir.data + " to set watch progress for " + id, Urgency::CRITICAL); return false; } Path progress_path = watch_progress_dir; progress_path.join(plugin_name); Json::Value json_root; if(!read_file_as_json(progress_path, json_root) || !json_root.isObject()) json_root = Json::Value(Json::objectValue); Json::Value watch_progress_json(Json::objectValue); watch_progress_json["time"] = (int64_t)time_pos_sec; watch_progress_json["duration"] = (int64_t)duration_sec; watch_progress_json["thumbnail_url"] = thumbnail_url; watch_progress_json["timestamp"] = (int64_t)time(nullptr); json_root[id] = std::move(watch_progress_json); if(!save_json_to_file_atomic(progress_path, json_root)) { show_notification("QuickMedia", "Failed to set watch progress for " + id, Urgency::CRITICAL); return false; } fprintf(stderr, "Set watch progress for \"%s\" to %d/%d\n", id.c_str(), (int)time_pos_sec, (int)duration_sec); return true; } std::unordered_map get_watch_progress_for_plugin(const char *plugin_name) { std::unordered_map watch_progress_map; Path progress_path = get_storage_dir().join("watch-progress").join(plugin_name); Json::Value json_root; if(!read_file_as_json(progress_path, json_root) || !json_root.isObject()) return watch_progress_map; for(Json::Value::const_iterator it = json_root.begin(); it != json_root.end(); ++it) { Json::Value key = it.key(); if(!key.isString()) continue; const Json::Value &time_json = (*it)["time"]; const Json::Value &duration_json = (*it)["duration"]; const Json::Value ×tamp_json = (*it)["timestamp"]; if(!time_json.isInt64() || !duration_json.isInt64() || !timestamp_json.isInt64()) continue; WatchProgress watch_progress; watch_progress.time_pos_sec = time_json.asInt64(); watch_progress.duration_sec = duration_json.asInt64(); watch_progress.timestamp = timestamp_json.asInt64(); const Json::Value &thumbnail_url_json = (*it)["thumbnail_url"]; if(thumbnail_url_json.isString()) watch_progress.thumbnail_url = thumbnail_url_json.asString(); watch_progress_map[key.asString()] = std::move(watch_progress); } return watch_progress_map; } bool toggle_watched_for_plugin_save_to_file(const char *plugin_name, const std::string &id, int64_t duration_sec, const std::string &thumbnail_url, WatchedStatus &watched_status) { Path local_anime_progress_path = get_storage_dir().join("watch-progress").join(plugin_name); Json::Value json_root; if(!read_file_as_json(local_anime_progress_path, json_root) || !json_root.isObject()) json_root = Json::Value(Json::objectValue); bool watched = false; Json::Value &watched_item = json_root[id]; if(watched_item.isObject()) { const Json::Value &time_json = watched_item["time"]; const Json::Value &duration_json = watched_item["duration"]; if(time_json.isInt64() && duration_json.isInt64()) { WatchProgress watch_progress; watch_progress.time_pos_sec = time_json.asInt64(); watch_progress.duration_sec = duration_json.asInt64(); watched = watch_progress.has_finished_watching(); } else { watched = false; } } else { watched_item = Json::Value(Json::objectValue); watched = false; } if(watched) { json_root.removeMember(id.c_str()); } else { watched_item["time"] = (int64_t)duration_sec; watched_item["duration"] = (int64_t)duration_sec; watched_item["thumbnail_url"] = thumbnail_url; watched_item["timestamp"] = (int64_t)time(nullptr); } if(!save_json_to_file_atomic(local_anime_progress_path, json_root)) { show_notification("QuickMedia", "Failed to mark " + id + " as " + (watched ? "not watched" : "watched"), Urgency::CRITICAL); return false; } watched_status = watched ? WatchedStatus::NOT_WATCHED : WatchedStatus::WATCHED; return true; } }