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