10
+ − 1 #include "core/anime_db.h"
+ − 2 #include "core/anime.h"
64
+ − 3 #include "core/strings.h"
+ − 4 #include <QDebug>
10
+ − 5
+ − 6 namespace Anime {
+ − 7
+ − 8 int Database::GetTotalAnimeAmount() {
+ − 9 int total = 0;
11
+ − 10 for (const auto& a : items) {
+ − 11 if (a.second.IsInUserList())
10
+ − 12 total++;
+ − 13 }
+ − 14 return total;
+ − 15 }
+ − 16
+ − 17 int Database::GetListsAnimeAmount(ListStatus status) {
+ − 18 if (status == ListStatus::NOT_IN_LIST)
+ − 19 return 0;
+ − 20 int total = 0;
11
+ − 21 for (const auto& a : items) {
+ − 22 if (a.second.IsInUserList() && a.second.GetUserStatus() == status)
10
+ − 23 total++;
+ − 24 }
+ − 25 return total;
+ − 26 }
+ − 27
+ − 28 int Database::GetTotalEpisodeAmount() {
+ − 29 int total = 0;
11
+ − 30 for (const auto& a : items) {
+ − 31 if (a.second.IsInUserList()) {
+ − 32 total += a.second.GetUserRewatchedTimes() * a.second.GetEpisodes();
+ − 33 total += a.second.GetUserProgress();
10
+ − 34 }
+ − 35 }
+ − 36 return total;
+ − 37 }
+ − 38
+ − 39 /* Returns the total watched amount in minutes. */
+ − 40 int Database::GetTotalWatchedAmount() {
+ − 41 int total = 0;
11
+ − 42 for (const auto& a : items) {
+ − 43 if (a.second.IsInUserList()) {
+ − 44 total += a.second.GetDuration() * a.second.GetUserProgress();
+ − 45 total += a.second.GetEpisodes() * a.second.GetDuration() * a.second.GetUserRewatchedTimes();
10
+ − 46 }
+ − 47 }
+ − 48 return total;
+ − 49 }
+ − 50
+ − 51 /* Returns the total planned amount in minutes.
+ − 52 Note that we should probably limit progress to the
+ − 53 amount of episodes, as AniList will let you
+ − 54 set episode counts up to 32768. But that should
+ − 55 rather be handled elsewhere. */
+ − 56 int Database::GetTotalPlannedAmount() {
+ − 57 int total = 0;
11
+ − 58 for (const auto& a : items) {
+ − 59 if (a.second.IsInUserList())
+ − 60 total += a.second.GetDuration() * (a.second.GetEpisodes() - a.second.GetUserProgress());
10
+ − 61 }
+ − 62 return total;
+ − 63 }
+ − 64
83
+ − 65 /* In Taiga this is called a mean, but "average" is
+ − 66 what's primarily used in conversation, at least
+ − 67 in the U.S. */
10
+ − 68 double Database::GetAverageScore() {
+ − 69 double avg = 0;
+ − 70 int amt = 0;
11
+ − 71 for (const auto& a : items) {
+ − 72 if (a.second.IsInUserList() && a.second.GetUserScore()) {
+ − 73 avg += a.second.GetUserScore();
10
+ − 74 amt++;
+ − 75 }
+ − 76 }
+ − 77 return avg / amt;
+ − 78 }
+ − 79
+ − 80 double Database::GetScoreDeviation() {
+ − 81 double squares_sum = 0, avg = GetAverageScore();
+ − 82 int amt = 0;
11
+ − 83 for (const auto& a : items) {
+ − 84 if (a.second.IsInUserList() && a.second.GetUserScore()) {
64
+ − 85 squares_sum += std::pow(static_cast<double>(a.second.GetUserScore()) - avg, 2);
10
+ − 86 amt++;
+ − 87 }
+ − 88 }
+ − 89 return (amt > 0) ? std::sqrt(squares_sum / amt) : 0;
+ − 90 }
+ − 91
83
+ − 92 template <typename T, typename U>
+ − 93 static T get_lowest_in_map(const std::unordered_map<T, U>& map) {
+ − 94 if (map.size() <= 0)
+ − 95 return 0;
+ − 96 T id;
+ − 97 U ret = std::numeric_limits<U>::max();
+ − 98 for (const auto& t : map) {
+ − 99 if (t.second < ret) {
+ − 100 ret = t.second;
+ − 101 id = t.first;
+ − 102 }
+ − 103 }
+ − 104 return id;
+ − 105 }
+ − 106
+ − 107 /* This is really fugly but WHO CARES :P
+ − 108
+ − 109 This sort of ""advanced"" algorithm is only in effect because
+ − 110 there are some special cases, e.g. Another and Re:ZERO, where
+ − 111 we get the wrong match, so we have to create Advanced Techniques
+ − 112 to solve this
+ − 113
+ − 114 This algorithm:
+ − 115 1. searches each anime item for a match to the preferred title
+ − 116 AND all synonyms and marks those matches with
+ − 117 `synonym.length() - (synonym.find(needle) + needle.length());`
+ − 118 which, on a title that exactly matches, will be 0
+ − 119 2. returns the id of the match that is the lowest, which will most
+ − 120 definitely match anything that exactly matches the title of the
+ − 121 filename */
+ − 122 int Database::GetAnimeFromTitle(const std::string& title) {
64
+ − 123 if (title.empty())
+ − 124 return 0;
83
+ − 125 std::unordered_map<int, long long> map;
64
+ − 126 for (const auto& a : items) {
83
+ − 127 long long ret = a.second.GetUserPreferredTitle().find(title);
+ − 128 if (ret != static_cast<long long>(std::string::npos)) {
+ − 129 map[a.second.GetId()] = a.second.GetUserPreferredTitle().length() - (ret + title.length());
+ − 130 continue;
+ − 131 }
+ − 132 for (const auto& synonym : a.second.GetTitleSynonyms()) {
+ − 133 ret = synonym.find(title);
+ − 134 if (ret != static_cast<long long>(std::string::npos)) {
+ − 135 map[a.second.GetId()] = synonym.length() - (ret + title.length());
+ − 136 continue;
64
+ − 137 }
+ − 138 }
+ − 139 }
83
+ − 140 return get_lowest_in_map(map);
64
+ − 141 }
+ − 142
11
+ − 143 Database db;
+ − 144
9
+ − 145 } // namespace Anime