Mercurial > minori
comparison src/core/anime_db.cc @ 177:122fad646f81
anime/db: upgrade to c++17 style, make things easier to read
author | Paper <mrpapersonic@gmail.com> |
---|---|
date | Fri, 01 Dec 2023 13:32:29 -0500 |
parents | 121c2d5b321f |
children | 9613d72b097e |
comparison
equal
deleted
inserted
replaced
176:121c2d5b321f | 177:122fad646f81 |
---|---|
12 #include <iostream> | 12 #include <iostream> |
13 #include <exception> | 13 #include <exception> |
14 | 14 |
15 namespace Anime { | 15 namespace Anime { |
16 | 16 |
17 int Database::GetTotalAnimeAmount() { | 17 size_t Database::GetTotalAnimeAmount() { |
18 int total = 0; | 18 size_t total = 0; |
19 for (const auto& a : items) { | 19 |
20 if (a.second.IsInUserList()) | 20 for (const auto& [id, anime] : items) |
21 if (anime.IsInUserList()) | |
21 total++; | 22 total++; |
22 } | 23 |
23 return total; | 24 return total; |
24 } | 25 } |
25 | 26 |
26 int Database::GetListsAnimeAmount(ListStatus status) { | 27 size_t Database::GetListsAnimeAmount(ListStatus status) { |
27 if (status == ListStatus::NOT_IN_LIST) | 28 if (status == ListStatus::NOT_IN_LIST) |
28 return 0; | 29 return 0; |
29 int total = 0; | 30 |
30 for (const auto& a : items) { | 31 size_t total = 0; |
31 if (a.second.IsInUserList() && a.second.GetUserStatus() == status) | 32 |
33 for (const auto& [id, anime] : items) | |
34 if (anime.IsInUserList() && anime.GetUserStatus() == status) | |
32 total++; | 35 total++; |
33 } | 36 |
34 return total; | 37 return total; |
35 } | 38 } |
36 | 39 |
37 int Database::GetTotalEpisodeAmount() { | 40 size_t Database::GetTotalEpisodeAmount() { |
38 int total = 0; | 41 size_t total = 0; |
39 for (const auto& a : items) { | 42 |
40 if (a.second.IsInUserList()) { | 43 for (const auto& [id, anime] : items) |
41 total += a.second.GetUserRewatchedTimes() * a.second.GetEpisodes(); | 44 if (anime.IsInUserList()) |
42 total += a.second.GetUserProgress(); | 45 total += anime.GetUserRewatchedTimes() * anime.GetEpisodes() + anime.GetUserProgress(); |
43 } | 46 |
44 } | |
45 return total; | 47 return total; |
46 } | 48 } |
47 | 49 |
48 /* Returns the total watched amount in minutes. */ | 50 /* Returns the total watched amount in minutes. */ |
49 int Database::GetTotalWatchedAmount() { | 51 size_t Database::GetTotalWatchedAmount() { |
50 int total = 0; | 52 size_t total = 0; |
51 for (const auto& a : items) { | 53 |
52 if (a.second.IsInUserList()) { | 54 for (const auto& [id, anime] : items) |
53 total += a.second.GetDuration() * a.second.GetUserProgress(); | 55 if (anime.IsInUserList()) |
54 total += a.second.GetEpisodes() * a.second.GetDuration() * a.second.GetUserRewatchedTimes(); | 56 total += anime.GetDuration() * anime.GetUserProgress() |
55 } | 57 + anime.GetEpisodes() * anime.GetDuration() * anime.GetUserRewatchedTimes(); |
56 } | 58 |
57 return total; | 59 return total; |
58 } | 60 } |
59 | 61 |
60 /* Returns the total planned amount in minutes. | 62 /* Returns the total planned amount in minutes. |
61 Note that we should probably limit progress to the | 63 Note that we should probably limit progress to the |
62 amount of episodes, as AniList will let you | 64 amount of episodes, as AniList will let you |
63 set episode counts up to 32768. But that should | 65 set episode counts up to 32768. But that should |
64 rather be handled elsewhere. */ | 66 rather be handled elsewhere. */ |
65 int Database::GetTotalPlannedAmount() { | 67 size_t Database::GetTotalPlannedAmount() { |
66 int total = 0; | 68 size_t total = 0; |
67 for (const auto& a : items) { | 69 |
68 if (a.second.IsInUserList()) | 70 for (const auto& [id, anime] : items) |
69 total += a.second.GetDuration() * (a.second.GetEpisodes() - a.second.GetUserProgress()); | 71 if (anime.IsInUserList()) |
70 } | 72 total += anime.GetDuration() * (anime.GetEpisodes() - anime.GetUserProgress()); |
71 return total; | 73 |
72 } | 74 return total; |
73 | 75 } |
74 /* In Taiga this is called a mean, but "average" is | 76 |
77 /* In Taiga this is called the mean, but "average" is | |
75 what's primarily used in conversation, at least | 78 what's primarily used in conversation, at least |
76 in the U.S. */ | 79 in the U.S. */ |
77 double Database::GetAverageScore() { | 80 double Database::GetAverageScore() { |
78 double avg = 0; | 81 double avg = 0; |
79 int amt = 0; | 82 size_t amt = 0; |
80 for (const auto& a : items) { | 83 |
81 if (a.second.IsInUserList() && a.second.GetUserScore()) { | 84 for (const auto& [id, anime] : items) { |
82 avg += a.second.GetUserScore(); | 85 if (anime.IsInUserList() && anime.GetUserScore()) { |
86 avg += anime.GetUserScore(); | |
83 amt++; | 87 amt++; |
84 } | 88 } |
85 } | 89 } |
86 return avg / amt; | 90 return avg / amt; |
87 } | 91 } |
88 | 92 |
89 double Database::GetScoreDeviation() { | 93 double Database::GetScoreDeviation() { |
90 double squares_sum = 0, avg = GetAverageScore(); | 94 double squares_sum = 0, avg = GetAverageScore(); |
91 int amt = 0; | 95 size_t amt = 0; |
92 for (const auto& a : items) { | 96 |
93 if (a.second.IsInUserList() && a.second.GetUserScore()) { | 97 for (const auto& [id, anime] : items) { |
94 squares_sum += std::pow(static_cast<double>(a.second.GetUserScore()) - avg, 2); | 98 if (anime.IsInUserList() && anime.GetUserScore()) { |
99 squares_sum += std::pow(static_cast<double>(anime.GetUserScore()) - avg, 2); | |
95 amt++; | 100 amt++; |
96 } | 101 } |
97 } | 102 } |
103 | |
98 return (amt > 0) ? std::sqrt(squares_sum / amt) : 0; | 104 return (amt > 0) ? std::sqrt(squares_sum / amt) : 0; |
99 } | 105 } |
100 | 106 |
101 template <typename T, typename U> | 107 template<typename T, typename U> |
102 static T get_lowest_in_map(const std::unordered_map<T, U>& map) { | 108 static T get_lowest_in_map(const std::unordered_map<T, U>& map) { |
103 if (map.size() <= 0) | 109 if (map.size() <= 0) |
104 return 0; | 110 return 0; |
105 | 111 |
106 T id = 0; | 112 T id = 0; |
159 | 165 |
160 static bool GetListDataAsJSON(const Anime& anime, nlohmann::json& json) { | 166 static bool GetListDataAsJSON(const Anime& anime, nlohmann::json& json) { |
161 if (!anime.IsInUserList()) | 167 if (!anime.IsInUserList()) |
162 return false; | 168 return false; |
163 | 169 |
170 // clang-format off | |
164 json = { | 171 json = { |
165 {"status", Translate::ToString(anime.GetUserStatus())}, | 172 {"status", Translate::ToString(anime.GetUserStatus())}, |
166 {"progress", anime.GetUserProgress()}, | 173 {"progress", anime.GetUserProgress()}, |
167 {"score", anime.GetUserScore()}, | 174 {"score", anime.GetUserScore()}, |
168 {"started", anime.GetUserDateStarted().GetAsAniListJson()}, | 175 {"started", anime.GetUserDateStarted().GetAsAniListJson()}, |
171 {"rewatched_times", anime.GetUserRewatchedTimes()}, | 178 {"rewatched_times", anime.GetUserRewatchedTimes()}, |
172 {"rewatching", anime.GetUserIsRewatching()}, | 179 {"rewatching", anime.GetUserIsRewatching()}, |
173 {"updated", anime.GetUserTimeUpdated()}, | 180 {"updated", anime.GetUserTimeUpdated()}, |
174 {"notes", anime.GetUserNotes()} | 181 {"notes", anime.GetUserNotes()} |
175 }; | 182 }; |
183 // clang-format on | |
176 | 184 |
177 return true; | 185 return true; |
178 } | 186 } |
179 | 187 |
180 static bool GetAnimeAsJSON(const Anime& anime, nlohmann::json& json) { | 188 static bool GetAnimeAsJSON(const Anime& anime, nlohmann::json& json) { |
189 // clang-format off | |
181 json = { | 190 json = { |
182 {"id", anime.GetId()}, | 191 {"id", anime.GetId()}, |
183 {"title", { | 192 {"title", { |
184 {"native", anime.GetNativeTitle()}, | 193 {"native", anime.GetNativeTitle()}, |
185 {"romaji", anime.GetRomajiTitle()}, | 194 {"romaji", anime.GetRomajiTitle()}, |
196 {"audience_score", anime.GetAudienceScore()}, | 205 {"audience_score", anime.GetAudienceScore()}, |
197 {"synopsis", anime.GetSynopsis()}, | 206 {"synopsis", anime.GetSynopsis()}, |
198 {"duration", anime.GetDuration()}, | 207 {"duration", anime.GetDuration()}, |
199 {"poster_url", anime.GetPosterUrl()} | 208 {"poster_url", anime.GetPosterUrl()} |
200 }; | 209 }; |
210 // clang-format on | |
201 | 211 |
202 nlohmann::json user; | 212 nlohmann::json user; |
203 if (GetListDataAsJSON(anime, user)) | 213 if (GetListDataAsJSON(anime, user)) |
204 json.push_back({"list_data", user}); | 214 json.push_back({"list_data", user}); |
205 | 215 |
248 anime.SetUserNotes(JSON::GetString<std::string>(json, "/notes"_json_pointer, "")); | 258 anime.SetUserNotes(JSON::GetString<std::string>(json, "/notes"_json_pointer, "")); |
249 | 259 |
250 return true; | 260 return true; |
251 } | 261 } |
252 | 262 |
253 bool Database::ParseAnimeInfoJSON(const nlohmann::json& json) { | 263 static bool ParseAnimeInfoJSON(const nlohmann::json& json, Database& database) { |
254 int id = JSON::GetNumber(json, "/id"_json_pointer, 0); | 264 int id = JSON::GetNumber(json, "/id"_json_pointer, 0); |
255 if (!id) | 265 if (!id) |
256 return false; | 266 return false; |
257 | 267 |
258 Anime& anime = items[id]; | 268 Anime& anime = database.items[id]; |
259 | 269 |
260 anime.SetId(id); | 270 anime.SetId(id); |
261 anime.SetNativeTitle(JSON::GetString<std::string>(json, "/title/native"_json_pointer, "")); | 271 anime.SetNativeTitle(JSON::GetString<std::string>(json, "/title/native"_json_pointer, "")); |
262 anime.SetRomajiTitle(JSON::GetString<std::string>(json, "/title/romaji"_json_pointer, "")); | 272 anime.SetRomajiTitle(JSON::GetString<std::string>(json, "/title/romaji"_json_pointer, "")); |
263 anime.SetEnglishTitle(JSON::GetString<std::string>(json, "/title/english"_json_pointer, "")); | 273 anime.SetEnglishTitle(JSON::GetString<std::string>(json, "/title/english"_json_pointer, "")); |
280 return true; | 290 return true; |
281 } | 291 } |
282 | 292 |
283 bool Database::ParseDatabaseJSON(const nlohmann::json& json) { | 293 bool Database::ParseDatabaseJSON(const nlohmann::json& json) { |
284 for (const auto& anime_json : json) | 294 for (const auto& anime_json : json) |
285 ParseAnimeInfoJSON(anime_json); | 295 ParseAnimeInfoJSON(anime_json, *this); |
286 | 296 |
287 return true; | 297 return true; |
288 } | 298 } |
289 | 299 |
290 bool Database::LoadDatabaseFromFile() { | 300 bool Database::LoadDatabaseFromDisk() { |
291 std::filesystem::path db_path = Filesystem::GetAnimeDBPath(); | 301 std::filesystem::path db_path = Filesystem::GetAnimeDBPath(); |
292 Filesystem::CreateDirectories(db_path); | 302 Filesystem::CreateDirectories(db_path); |
293 | 303 |
294 std::ifstream db_file(db_path); | 304 std::ifstream db_file(db_path); |
295 if (!db_file) | 305 if (!db_file) |