Mercurial > minori
comparison src/services/anilist.cc @ 315:34347fd2a2de
session: allow printing status messages
...!
| author | Paper <paper@paper.us.eu.org> |
|---|---|
| date | Tue, 11 Jun 2024 14:16:40 -0400 |
| parents | 91ac90a34003 |
| children | b1f4d1867ab1 |
comparison
equal
deleted
inserted
replaced
| 314:76d7315504c4 | 315:34347fd2a2de |
|---|---|
| 72 std::vector<std::string> headers = {"Authorization: Bearer " + account.AuthToken(), "Accept: application/json", | 72 std::vector<std::string> headers = {"Authorization: Bearer " + account.AuthToken(), "Accept: application/json", |
| 73 "Content-Type: application/json"}; | 73 "Content-Type: application/json"}; |
| 74 return Strings::ToUtf8String(HTTP::Request("https://graphql.anilist.co", headers, data, HTTP::Type::Post)); | 74 return Strings::ToUtf8String(HTTP::Request("https://graphql.anilist.co", headers, data, HTTP::Type::Post)); |
| 75 } | 75 } |
| 76 | 76 |
| 77 static nlohmann::json SendJSONRequest(const nlohmann::json& data) { | 77 static bool SendJSONRequest(const nlohmann::json& data, nlohmann::json& out) { |
| 78 std::string request = SendRequest(data.dump()); | 78 std::string request = SendRequest(data.dump()); |
| 79 if (request.empty()) { | 79 if (request.empty()) { |
| 80 std::cerr << "[AniList] JSON Request returned an empty result!" << std::endl; | 80 session.SetStatusBar("AniList: JSON request returned an empty result!"); |
| 81 return {}; | 81 return false; |
| 82 } | 82 } |
| 83 | 83 |
| 84 auto ret = nlohmann::json::parse(request, nullptr, false); | 84 out = nlohmann::json::parse(request, nullptr, false); |
| 85 if (ret.is_discarded()) { | 85 if (out.is_discarded()) { |
| 86 std::cerr << "[AniList] Failed to parse request JSON!" << std::endl; | 86 session.SetStatusBar("AniList: Failed to parse request JSON!"); |
| 87 return {}; | 87 return false; |
| 88 } | 88 } |
| 89 | 89 |
| 90 if (ret.contains("/errors"_json_pointer) && ret.at("/errors"_json_pointer).is_array()) { | 90 if (out.contains("/errors"_json_pointer) && out.at("/errors"_json_pointer).is_array()) { |
| 91 for (const auto& error : ret.at("/errors"_json_pointer)) | 91 for (const auto& error : out.at("/errors"_json_pointer)) |
| 92 std::cerr << "[AniList] Received an error in response: " | 92 std::cerr << "[AniList] Received an error in response: " |
| 93 << JSON::GetString<std::string>(error, "/message"_json_pointer, "") << std::endl; | 93 << JSON::GetString<std::string>(error, "/message"_json_pointer, "") << std::endl; |
| 94 | 94 |
| 95 return {}; | 95 session.SetStatusBar("AniList: Received an error in response!"); |
| 96 } | 96 return false; |
| 97 | 97 } |
| 98 return ret; | 98 |
| 99 return true; | |
| 99 } | 100 } |
| 100 | 101 |
| 101 static void ParseListStatus(std::string status, Anime::Anime& anime) { | 102 static void ParseListStatus(std::string status, Anime::Anime& anime) { |
| 102 static const std::unordered_map<std::string, Anime::ListStatus> map = { | 103 static const std::unordered_map<std::string, Anime::ListStatus> map = { |
| 103 {"CURRENT", Anime::ListStatus::Current }, | 104 {"CURRENT", Anime::ListStatus::Current }, |
| 210 return 1; | 211 return 1; |
| 211 } | 212 } |
| 212 | 213 |
| 213 int GetAnimeList() { | 214 int GetAnimeList() { |
| 214 if (!account.IsValid()) { | 215 if (!account.IsValid()) { |
| 215 std::cerr << "AniList: Account isn't valid!" << std::endl; | 216 session.SetStatusBar("AniList: Account isn't valid!"); |
| 216 return 0; | 217 return 0; |
| 217 } | 218 } |
| 219 | |
| 220 session.SetStatusBar("AniList: Retrieving anime list..."); | |
| 218 | 221 |
| 219 /* NOTE: these really ought to be in the qrc file */ | 222 /* NOTE: these really ought to be in the qrc file */ |
| 220 constexpr std::string_view query = "query ($id: Int) {\n" | 223 constexpr std::string_view query = "query ($id: Int) {\n" |
| 221 " MediaListCollection (userId: $id, type: ANIME) {\n" | 224 " MediaListCollection (userId: $id, type: ANIME) {\n" |
| 222 " lists {\n" | 225 " lists {\n" |
| 251 {"id", account.UserId()} | 254 {"id", account.UserId()} |
| 252 }} | 255 }} |
| 253 }; | 256 }; |
| 254 // clang-format on | 257 // clang-format on |
| 255 | 258 |
| 256 auto res = SendJSONRequest(json); | 259 session.SetStatusBar("AniList: Parsing anime list..."); |
| 257 | 260 |
| 258 for (const auto& list : res["data"]["MediaListCollection"]["lists"].items()) | 261 nlohmann::json result; |
| 262 const bool res = SendJSONRequest(json, result); | |
| 263 if (!res) | |
| 264 return 0; | |
| 265 | |
| 266 for (const auto& list : result["data"]["MediaListCollection"]["lists"].items()) | |
| 259 ParseList(list.value()); | 267 ParseList(list.value()); |
| 268 | |
| 269 session.SetStatusBar("AniList: Retrieved anime list successfully!"); | |
| 260 | 270 |
| 261 return 1; | 271 return 1; |
| 262 } | 272 } |
| 263 | 273 |
| 264 /* return is a vector of anime ids */ | 274 /* return is a vector of anime ids */ |
| 278 {"search", search} | 288 {"search", search} |
| 279 }} | 289 }} |
| 280 }; | 290 }; |
| 281 // clang-format on | 291 // clang-format on |
| 282 | 292 |
| 283 auto res = SendJSONRequest(json); | 293 nlohmann::json result; |
| 294 const bool res = SendJSONRequest(json, result); | |
| 295 if (!res) | |
| 296 return {}; | |
| 284 | 297 |
| 285 /* FIXME: error handling here */ | 298 /* FIXME: error handling here */ |
| 286 std::vector<int> ret; | 299 std::vector<int> ret; |
| 287 ret.reserve(res["data"]["Page"]["media"].size()); | 300 ret.reserve(result["/data/Page/media"_json_pointer].size()); |
| 288 | 301 |
| 289 for (const auto& media : res["data"]["Page"]["media"].items()) | 302 for (const auto& media : result["/data/Page/media"_json_pointer].items()) |
| 290 ret.push_back(ParseMediaJson(media.value())); | 303 ret.push_back(ParseMediaJson(media.value())); |
| 291 | 304 |
| 292 return ret; | 305 return ret; |
| 293 } | 306 } |
| 294 | 307 |
| 319 {"season_year", Strings::ToUtf8String(year)}, | 332 {"season_year", Strings::ToUtf8String(year)}, |
| 320 {"page", page} | 333 {"page", page} |
| 321 }} | 334 }} |
| 322 }; | 335 }; |
| 323 | 336 |
| 324 auto res = SendJSONRequest(json); | 337 nlohmann::json result; |
| 325 ret.reserve(ret.capacity() + res["data"]["Page"]["media"].size()); | 338 const bool res = SendJSONRequest(json, result); |
| 326 | 339 if (!res) |
| 327 for (const auto& media : res["data"]["Page"]["media"].items()) | 340 return {}; |
| 341 | |
| 342 ret.reserve(ret.capacity() + result["data"]["Page"]["media"].size()); | |
| 343 | |
| 344 for (const auto& media : result["data"]["Page"]["media"].items()) | |
| 328 ret.push_back(ParseMediaJson(media.value())); | 345 ret.push_back(ParseMediaJson(media.value())); |
| 329 | 346 |
| 330 has_next_page = JSON::GetBoolean(res, "/data/Page/pageInfo/hasNextPage"_json_pointer, false); | 347 has_next_page = JSON::GetBoolean(result, "/data/Page/pageInfo/hasNextPage"_json_pointer, false); |
| 331 if (has_next_page) | 348 if (has_next_page) |
| 332 page++; | 349 page++; |
| 333 } | 350 } |
| 334 | 351 |
| 335 return ret; | 352 return ret; |
| 360 return 0; | 377 return 0; |
| 361 | 378 |
| 362 std::optional<std::string> service_id = anime.GetServiceId(Anime::Service::AniList); | 379 std::optional<std::string> service_id = anime.GetServiceId(Anime::Service::AniList); |
| 363 if (!service_id) | 380 if (!service_id) |
| 364 return 0; | 381 return 0; |
| 382 | |
| 383 session.SetStatusBar("AniList: Updating anime entry..."); | |
| 365 | 384 |
| 366 constexpr std::string_view query = | 385 constexpr std::string_view query = |
| 367 "mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, $score: Int, $notes: String, $start: " | 386 "mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, $score: Int, $notes: String, $start: " |
| 368 "FuzzyDateInput, $comp: FuzzyDateInput, $repeat: Int) {\n" | 387 "FuzzyDateInput, $comp: FuzzyDateInput, $repeat: Int) {\n" |
| 369 " SaveMediaListEntry (mediaId: $media_id, progress: $progress, status: $status, scoreRaw: $score, notes: " | 388 " SaveMediaListEntry (mediaId: $media_id, progress: $progress, status: $status, scoreRaw: $score, notes: " |
| 385 {"repeat", anime.GetUserRewatchedTimes()} | 404 {"repeat", anime.GetUserRewatchedTimes()} |
| 386 }} | 405 }} |
| 387 }; | 406 }; |
| 388 // clang-format on | 407 // clang-format on |
| 389 | 408 |
| 390 auto ret = SendJSONRequest(json); | 409 nlohmann::json result; |
| 391 | 410 const bool ret = SendJSONRequest(json, result); |
| 392 return JSON::GetNumber(ret, "/data/SaveMediaListEntry/id"_json_pointer, 0); | 411 if (!ret) |
| 412 return 0; | |
| 413 | |
| 414 session.SetStatusBar("AniList: Anime entry updated successfully!"); | |
| 415 | |
| 416 return JSON::GetNumber(result, "/data/SaveMediaListEntry/id"_json_pointer, 0); | |
| 393 } | 417 } |
| 394 | 418 |
| 395 static int ParseUser(const nlohmann::json& json) { | 419 static int ParseUser(const nlohmann::json& json) { |
| 396 account.SetUserId(JSON::GetNumber(json, "/id"_json_pointer, 0)); | 420 account.SetUserId(JSON::GetNumber(json, "/id"_json_pointer, 0)); |
| 397 return account.UserId(); | 421 return account.UserId(); |
| 409 | 433 |
| 410 if (!ok || token.isEmpty()) | 434 if (!ok || token.isEmpty()) |
| 411 return false; | 435 return false; |
| 412 | 436 |
| 413 account.SetAuthToken(Strings::ToUtf8String(token)); | 437 account.SetAuthToken(Strings::ToUtf8String(token)); |
| 438 | |
| 439 session.SetStatusBar("AniList: Requesting user ID..."); | |
| 414 | 440 |
| 415 constexpr std::string_view query = "query {\n" | 441 constexpr std::string_view query = "query {\n" |
| 416 " Viewer {\n" | 442 " Viewer {\n" |
| 417 " id\n" | 443 " id\n" |
| 418 " name\n" | 444 " name\n" |
| 423 "}\n"; | 449 "}\n"; |
| 424 nlohmann::json json = { | 450 nlohmann::json json = { |
| 425 {"query", query} | 451 {"query", query} |
| 426 }; | 452 }; |
| 427 | 453 |
| 428 auto ret = SendJSONRequest(json); | 454 /* SendJSONRequest handles status errors */ |
| 455 nlohmann::json result; | |
| 456 const bool ret = SendJSONRequest(json, result); | |
| 457 if (!ret) | |
| 458 return 0; | |
| 459 | |
| 460 session.SetStatusBar("AniList: Successfully retrieved user data!"); | |
| 429 | 461 |
| 430 ParseUser(ret["data"]["Viewer"]); | 462 ParseUser(ret["data"]["Viewer"]); |
| 431 return true; | 463 return true; |
| 432 } | 464 } |
| 433 | 465 |
