Mercurial > minori
comparison src/services/anilist.cc @ 291:9a88e1725fd2
*: refactor lots of stuff
I forgot to put this into different commits, oops!
anyway, it doesn't really matter *that* much since this is an
unfinished hobby project anyway. once it starts getting stable
commit history will be more important, but for now it's not
that big of a deal
author | Paper <paper@paper.us.eu.org> |
---|---|
date | Sun, 12 May 2024 16:31:07 -0400 |
parents | 53e3c015a973 |
children | 2115488eb302 |
comparison
equal
deleted
inserted
replaced
290:9347e2eaf6e5 | 291:9a88e1725fd2 |
---|---|
16 #include <QMessageBox> | 16 #include <QMessageBox> |
17 #include <QUrl> | 17 #include <QUrl> |
18 | 18 |
19 #include <chrono> | 19 #include <chrono> |
20 #include <exception> | 20 #include <exception> |
21 #include <string_view> | |
21 | 22 |
22 #include <iostream> | 23 #include <iostream> |
23 | 24 |
24 using namespace nlohmann::literals::json_literals; | 25 using namespace nlohmann::literals::json_literals; |
25 | 26 |
26 namespace Services { | 27 namespace Services { |
27 namespace AniList { | 28 namespace AniList { |
28 | 29 |
29 static constexpr int CLIENT_ID = 13706; | 30 static constexpr std::string_view CLIENT_ID = "13706"; |
30 | 31 |
31 class Account { | 32 class Account { |
32 public: | 33 public: |
33 int UserId() const { return session.config.auth.anilist.user_id; } | 34 int UserId() const { return session.config.auth.anilist.user_id; } |
34 void SetUserId(const int id) { session.config.auth.anilist.user_id = id; } | 35 void SetUserId(const int id) { session.config.auth.anilist.user_id = id; } |
40 bool IsValid() const { return UserId() && Authenticated(); } | 41 bool IsValid() const { return UserId() && Authenticated(); } |
41 }; | 42 }; |
42 | 43 |
43 static Account account; | 44 static Account account; |
44 | 45 |
45 std::string SendRequest(std::string data) { | 46 static std::string SendRequest(const std::string& data) { |
46 std::vector<std::string> headers = {"Authorization: Bearer " + account.AuthToken(), "Accept: application/json", | 47 std::vector<std::string> headers = {"Authorization: Bearer " + account.AuthToken(), "Accept: application/json", |
47 "Content-Type: application/json"}; | 48 "Content-Type: application/json"}; |
48 return Strings::ToUtf8String(HTTP::Post("https://graphql.anilist.co", data, headers)); | 49 return Strings::ToUtf8String(HTTP::Request("https://graphql.anilist.co", headers, data, HTTP::Type::Post)); |
49 } | 50 } |
50 | 51 |
51 nlohmann::json SendJSONRequest(nlohmann::json data) { | 52 static nlohmann::json SendJSONRequest(const nlohmann::json& data) { |
52 std::string request = SendRequest(data.dump()); | 53 std::string request = SendRequest(data.dump()); |
53 if (request.empty()) { | 54 if (request.empty()) { |
54 std::cerr << "[AniList] JSON Request returned an empty result!" << std::endl; | 55 std::cerr << "[AniList] JSON Request returned an empty result!" << std::endl; |
55 return {}; | 56 return {}; |
56 } | 57 } |
70 } | 71 } |
71 | 72 |
72 return ret; | 73 return ret; |
73 } | 74 } |
74 | 75 |
75 void ParseListStatus(std::string status, Anime::Anime& anime) { | 76 static void ParseListStatus(std::string status, Anime::Anime& anime) { |
76 static const std::unordered_map<std::string, Anime::ListStatus> map = { | 77 static const std::unordered_map<std::string, Anime::ListStatus> map = { |
77 {"CURRENT", Anime::ListStatus::Current }, | 78 {"CURRENT", Anime::ListStatus::Current }, |
78 {"PLANNING", Anime::ListStatus::Planning }, | 79 {"PLANNING", Anime::ListStatus::Planning }, |
79 {"COMPLETED", Anime::ListStatus::Completed}, | 80 {"COMPLETED", Anime::ListStatus::Completed}, |
80 {"DROPPED", Anime::ListStatus::Dropped }, | 81 {"DROPPED", Anime::ListStatus::Dropped }, |
93 } | 94 } |
94 | 95 |
95 anime.SetUserStatus(map.at(status)); | 96 anime.SetUserStatus(map.at(status)); |
96 } | 97 } |
97 | 98 |
98 std::string ListStatusToString(const Anime::Anime& anime) { | 99 static std::string ListStatusToString(const Anime::Anime& anime) { |
99 if (anime.GetUserIsRewatching() && anime.GetUserStatus() == Anime::ListStatus::Current) | 100 if (anime.GetUserIsRewatching() && anime.GetUserStatus() == Anime::ListStatus::Current) |
100 return "REWATCHING"; | 101 return "REWATCHING"; |
101 | 102 |
102 switch (anime.GetUserStatus()) { | 103 switch (anime.GetUserStatus()) { |
103 case Anime::ListStatus::Planning: return "PLANNING"; | 104 case Anime::ListStatus::Planning: return "PLANNING"; |
107 default: break; | 108 default: break; |
108 } | 109 } |
109 return "CURRENT"; | 110 return "CURRENT"; |
110 } | 111 } |
111 | 112 |
112 void ParseTitle(const nlohmann::json& json, Anime::Anime& anime) { | 113 static void ParseTitle(const nlohmann::json& json, Anime::Anime& anime) { |
113 nlohmann::json::json_pointer g = "/native"_json_pointer; | 114 nlohmann::json::json_pointer g = "/native"_json_pointer; |
114 if (json.contains(g) && json[g].is_string()) | 115 if (json.contains(g) && json[g].is_string()) |
115 anime.SetTitle(Anime::TitleLanguage::Native, json[g]); | 116 anime.SetTitle(Anime::TitleLanguage::Native, json[g]); |
116 | 117 |
117 g = "/english"_json_pointer; | 118 g = "/english"_json_pointer; |
121 g = "/romaji"_json_pointer; | 122 g = "/romaji"_json_pointer; |
122 if (json.contains(g) && json[g].is_string()) | 123 if (json.contains(g) && json[g].is_string()) |
123 anime.SetTitle(Anime::TitleLanguage::Romaji, json[g]); | 124 anime.SetTitle(Anime::TitleLanguage::Romaji, json[g]); |
124 } | 125 } |
125 | 126 |
126 int ParseMediaJson(const nlohmann::json& json) { | 127 static int ParseMediaJson(const nlohmann::json& json) { |
127 int id = JSON::GetNumber(json, "/id"_json_pointer); | 128 int id = JSON::GetNumber(json, "/id"_json_pointer); |
128 if (!id) | 129 if (!id) |
129 return 0; | 130 return 0; |
130 | 131 |
131 Anime::Anime& anime = Anime::db.items[id]; | 132 Anime::Anime& anime = Anime::db.items[id]; |
157 anime.SetTitleSynonyms(JSON::GetArray<std::vector<std::string>>(json, "/synonyms"_json_pointer, {})); | 158 anime.SetTitleSynonyms(JSON::GetArray<std::vector<std::string>>(json, "/synonyms"_json_pointer, {})); |
158 | 159 |
159 return id; | 160 return id; |
160 } | 161 } |
161 | 162 |
162 int ParseListItem(const nlohmann::json& json) { | 163 static int ParseListItem(const nlohmann::json& json) { |
163 int id = ParseMediaJson(json["media"]); | 164 int id = ParseMediaJson(json["media"]); |
164 | 165 |
165 Anime::Anime& anime = Anime::db.items[id]; | 166 Anime::Anime& anime = Anime::db.items[id]; |
166 | 167 |
167 anime.AddToUserList(); | 168 anime.AddToUserList(); |
177 anime.SetUserTimeUpdated(JSON::GetNumber(json, "/updatedAt"_json_pointer, 0)); | 178 anime.SetUserTimeUpdated(JSON::GetNumber(json, "/updatedAt"_json_pointer, 0)); |
178 | 179 |
179 return id; | 180 return id; |
180 } | 181 } |
181 | 182 |
182 int ParseList(const nlohmann::json& json) { | 183 static int ParseList(const nlohmann::json& json) { |
183 for (const auto& entry : json["entries"].items()) { | 184 for (const auto& entry : json["entries"].items()) { |
184 ParseListItem(entry.value()); | 185 ParseListItem(entry.value()); |
185 } | 186 } |
186 return 1; | 187 return 1; |
187 } | 188 } |
334 **/ | 335 **/ |
335 Anime::Anime& anime = Anime::db.items[id]; | 336 Anime::Anime& anime = Anime::db.items[id]; |
336 if (!anime.IsInUserList()) | 337 if (!anime.IsInUserList()) |
337 return 0; | 338 return 0; |
338 | 339 |
340 std::optional<std::string> service_id = anime.GetServiceId(Anime::Service::AniList); | |
341 if (!service_id) | |
342 return 0; | |
343 | |
339 constexpr std::string_view query = | 344 constexpr std::string_view query = |
340 "mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, $score: Int, $notes: String, $start: " | 345 "mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, $score: Int, $notes: String, $start: " |
341 "FuzzyDateInput, $comp: FuzzyDateInput, $repeat: Int) {\n" | 346 "FuzzyDateInput, $comp: FuzzyDateInput, $repeat: Int) {\n" |
342 " SaveMediaListEntry (mediaId: $media_id, progress: $progress, status: $status, scoreRaw: $score, notes: " | 347 " SaveMediaListEntry (mediaId: $media_id, progress: $progress, status: $status, scoreRaw: $score, notes: " |
343 "$notes, startedAt: $start, completedAt: $comp, repeat: $repeat) {\n" | 348 "$notes, startedAt: $start, completedAt: $comp, repeat: $repeat) {\n" |
346 "}\n"; | 351 "}\n"; |
347 // clang-format off | 352 // clang-format off |
348 nlohmann::json json = { | 353 nlohmann::json json = { |
349 {"query", query}, | 354 {"query", query}, |
350 {"variables", { | 355 {"variables", { |
351 {"media_id", anime.GetId()}, | 356 {"media_id", Strings::ToInt<int64_t>(service_id.value())}, |
352 {"progress", anime.GetUserProgress()}, | 357 {"progress", anime.GetUserProgress()}, |
353 {"status", ListStatusToString(anime)}, | 358 {"status", ListStatusToString(anime)}, |
354 {"score", anime.GetUserScore()}, | 359 {"score", anime.GetUserScore()}, |
355 {"notes", anime.GetUserNotes()}, | 360 {"notes", anime.GetUserNotes()}, |
356 {"start", anime.GetUserDateStarted().GetAsAniListJson()}, | 361 {"start", anime.GetUserDateStarted().GetAsAniListJson()}, |
363 auto ret = SendJSONRequest(json); | 368 auto ret = SendJSONRequest(json); |
364 | 369 |
365 return JSON::GetNumber(ret, "/data/SaveMediaListEntry/id"_json_pointer, 0); | 370 return JSON::GetNumber(ret, "/data/SaveMediaListEntry/id"_json_pointer, 0); |
366 } | 371 } |
367 | 372 |
368 int ParseUser(const nlohmann::json& json) { | 373 static int ParseUser(const nlohmann::json& json) { |
369 account.SetUserId(JSON::GetNumber(json, "/id"_json_pointer, 0)); | 374 account.SetUserId(JSON::GetNumber(json, "/id"_json_pointer, 0)); |
370 return account.UserId(); | 375 return account.UserId(); |
371 } | 376 } |
372 | 377 |
373 bool AuthorizeUser() { | 378 bool AuthorizeUser() { |
374 /* Prompt for PIN */ | 379 /* Prompt for PIN */ |
375 QDesktopServices::openUrl(QUrl(Strings::ToQString("https://anilist.co/api/v2/oauth/authorize?client_id=" + | 380 QDesktopServices::openUrl(QUrl(Strings::ToQString("https://anilist.co/api/v2/oauth/authorize?client_id=" + |
376 Strings::ToUtf8String(CLIENT_ID) + "&response_type=token"))); | 381 std::string(CLIENT_ID) + "&response_type=token"))); |
377 | 382 |
378 bool ok; | 383 bool ok; |
379 QString token = QInputDialog::getText( | 384 QString token = QInputDialog::getText( |
380 0, "Credentials needed!", "Please enter the code given to you after logging in to AniList:", QLineEdit::Normal, | 385 0, "Credentials needed!", "Please enter the code given to you after logging in to AniList:", QLineEdit::Normal, |
381 "", &ok); | 386 "", &ok); |