comparison src/services/anilist.cc @ 325:78929794e7d8

pages/seasons: run seasons search in a separate thread
author Paper <paper@paper.us.eu.org>
date Thu, 13 Jun 2024 00:36:41 -0400
parents 5d3c9b31aa6e
children b5d6c27c308f
comparison
equal deleted inserted replaced
324:5d3c9b31aa6e 325:78929794e7d8
21 #include <exception> 21 #include <exception>
22 #include <string_view> 22 #include <string_view>
23 23
24 #include <iostream> 24 #include <iostream>
25 25
26 /* This file really sucks because it was made when I was first
27 * really "learning" C++ */
28
29 using namespace nlohmann::literals::json_literals;
30
31 namespace Services { 26 namespace Services {
32 namespace AniList { 27 namespace AniList {
33 28
34 static constexpr std::string_view CLIENT_ID = "13706"; 29 static constexpr std::string_view CLIENT_ID = "13706";
30
31 /* This is used in multiple queries, so just put it here I guess. */
35 #define MEDIA_FIELDS \ 32 #define MEDIA_FIELDS \
36 "coverImage {\n" \ 33 "coverImage {\n" \
37 " large\n" \ 34 " large\n" \
38 "}\n" \ 35 "}\n" \
39 "id\n" \ 36 "id\n" \
196 Translate::AniList::ToSeriesStatus(JSON::GetString<std::string>(json, "/status"_json_pointer, ""))); 193 Translate::AniList::ToSeriesStatus(JSON::GetString<std::string>(json, "/status"_json_pointer, "")));
197 194
198 if (json.contains("/startDate"_json_pointer) && json["/startDate"_json_pointer].is_object()) 195 if (json.contains("/startDate"_json_pointer) && json["/startDate"_json_pointer].is_object())
199 anime.SetStartedDate(Date(json["/startDate"_json_pointer])); 196 anime.SetStartedDate(Date(json["/startDate"_json_pointer]));
200 197
201 if (json.contains("/endDate"_json_pointer) && json["/endDate"_json_pointer].is_object()) 198 anime.SetCompletedDate(json.contains("/endDate"_json_pointer) && json["/endDate"_json_pointer].is_object()
202 anime.SetCompletedDate(Date(json["/endDate"_json_pointer])); 199 ? Date(json["/endDate"_json_pointer])
203 else 200 : anime.GetStartedDate());
204 anime.SetCompletedDate(anime.GetStartedDate());
205 201
206 anime.SetPosterUrl(JSON::GetString<std::string>(json, "/coverImage/large"_json_pointer, "")); 202 anime.SetPosterUrl(JSON::GetString<std::string>(json, "/coverImage/large"_json_pointer, ""));
207 203
208 anime.SetAudienceScore(JSON::GetNumber(json, "/averageScore"_json_pointer, 0)); 204 anime.SetAudienceScore(JSON::GetNumber(json, "/averageScore"_json_pointer, 0));
209 // anime.SetSeason(Translate::AniList::ToSeriesSeason(JSON::GetString<std::string>(json, "/season"_json_pointer, ""))); 205 // anime.SetSeason(Translate::AniList::ToSeriesSeason(JSON::GetString<std::string>(json, "/season"_json_pointer, "")));
263 } 259 }
264 260
265 int GetAnimeList() { 261 int GetAnimeList() {
266 auto& auth = session.config.auth.anilist; 262 auto& auth = session.config.auth.anilist;
267 263
268 /* NOTE: these really ought to be in the qrc file */ 264 static constexpr std::string_view query =
269 constexpr std::string_view query = "query ($id: Int) {\n" 265 "query ($id: Int) {\n"
270 " MediaListCollection (userId: $id, type: ANIME) {\n" 266 " MediaListCollection (userId: $id, type: ANIME) {\n"
271 " lists {\n" 267 " lists {\n"
272 " name\n" 268 " name\n"
273 " entries {\n" 269 " entries {\n"
274 " score\n" 270 " score\n"
275 " notes\n" 271 " notes\n"
276 " status\n" 272 " status\n"
277 " progress\n" 273 " progress\n"
278 " startedAt {\n" 274 " startedAt {\n"
279 " year\n" 275 " year\n"
280 " month\n" 276 " month\n"
281 " day\n" 277 " day\n"
282 " }\n" 278 " }\n"
283 " completedAt {\n" 279 " completedAt {\n"
284 " year\n" 280 " year\n"
285 " month\n" 281 " month\n"
286 " day\n" 282 " day\n"
287 " }\n" 283 " }\n"
288 " updatedAt\n" 284 " updatedAt\n"
289 " media {\n" 285 " media {\n"
290 MEDIA_FIELDS 286 MEDIA_FIELDS
291 " }\n" 287 " }\n"
292 " }\n" 288 " }\n"
293 " }\n" 289 " }\n"
294 " }\n" 290 " }\n"
295 "}\n"; 291 "}\n";
292
296 // clang-format off 293 // clang-format off
297 nlohmann::json request = { 294 nlohmann::json request = {
298 {"query", query}, 295 {"query", query},
299 {"variables", { 296 {"variables", {
300 {"id", auth.user_id} 297 {"id", auth.user_id}
324 return 1; 321 return 1;
325 } 322 }
326 323
327 /* return is a vector of anime ids */ 324 /* return is a vector of anime ids */
328 std::vector<int> Search(const std::string& search) { 325 std::vector<int> Search(const std::string& search) {
329 constexpr std::string_view query = "query ($search: String) {\n" 326 static constexpr std::string_view query =
330 " Page (page: 1, perPage: 50) {\n" 327 "query ($search: String) {\n"
331 " media (search: $search, type: ANIME) {\n" 328 " Page (page: 1, perPage: 50) {\n"
332 MEDIA_FIELDS 329 " media (search: $search, type: ANIME) {\n"
333 " }\n" 330 MEDIA_FIELDS
334 " }\n" 331 " }\n"
335 "}\n"; 332 " }\n"
333 "}\n";
336 334
337 // clang-format off 335 // clang-format off
338 nlohmann::json json = { 336 nlohmann::json json = {
339 {"query", query}, 337 {"query", query},
340 {"variables", { 338 {"variables", {
357 ret.push_back(ParseMediaJson(media.value())); 355 ret.push_back(ParseMediaJson(media.value()));
358 356
359 return ret; 357 return ret;
360 } 358 }
361 359
362 std::vector<int> GetSeason(Anime::SeriesSeason season, Date::Year year) { 360 bool GetSeason(Anime::SeriesSeason season, Date::Year year) {
363 constexpr std::string_view query = "query ($season: MediaSeason!, $season_year: Int!, $page: Int) {\n" 361 static constexpr std::string_view query =
364 " Page(page: $page) {\n" 362 "query ($season: MediaSeason!, $season_year: Int!, $page: Int) {\n"
365 " media(season: $season, seasonYear: $season_year, type: ANIME, sort: START_DATE) {\n" 363 " Page(page: $page) {\n"
366 MEDIA_FIELDS 364 " media(season: $season, seasonYear: $season_year, type: ANIME, sort: START_DATE) {\n"
367 " }\n" 365 MEDIA_FIELDS
368 " pageInfo {\n" 366 " }\n"
369 " total\n" 367 " pageInfo {\n"
370 " perPage\n" 368 " total\n"
371 " currentPage\n" 369 " perPage\n"
372 " lastPage\n" 370 " currentPage\n"
373 " hasNextPage\n" 371 " lastPage\n"
374 " }\n" 372 " hasNextPage\n"
375 " }\n" 373 " }\n"
376 "}\n"; 374 " }\n"
377 std::vector<int> ret; 375 "}\n";
378 376
379 int page = 0; 377 int page = 0;
380 bool has_next_page = true; 378 bool has_next_page = true;
379
381 while (has_next_page) { 380 while (has_next_page) {
382 nlohmann::json json = { 381 nlohmann::json json = {
383 {"query", query}, 382 {"query", query},
384 {"variables", { 383 {"variables", {
385 {"season", Translate::AniList::ToString(season)}, 384 {"season", Translate::AniList::ToString(season)},
386 {"season_year", Strings::ToUtf8String(year)}, 385 {"season_year", Strings::ToUtf8String(year)},
387 {"page", page} 386 {"page", page},
388 }} 387 }},
389 }; 388 };
390 389
391 const std::optional<nlohmann::json> res = SendJSONRequest(json); 390 const std::optional<nlohmann::json> res = SendJSONRequest(json);
392 if (!res) 391 if (!res)
393 return {}; 392 return false;
394 393
395 const nlohmann::json& result = res.value(); 394 const nlohmann::json& result = res.value();
396 395
397 ret.reserve(ret.capacity() + result["data"]["Page"]["media"].size()); 396 for (const auto& media : result["/data/Page/media"_json_pointer].items())
398 397 ParseMediaJson(media.value());
399 for (const auto& media : result["data"]["Page"]["media"].items())
400 ret.push_back(ParseMediaJson(media.value()));
401 398
402 has_next_page = JSON::GetBoolean(result, "/data/Page/pageInfo/hasNextPage"_json_pointer, false); 399 has_next_page = JSON::GetBoolean(result, "/data/Page/pageInfo/hasNextPage"_json_pointer, false);
403 if (has_next_page) 400 if (has_next_page)
404 page++; 401 page++;
405 } 402 }
406 403
407 return ret; 404 return true;
408 } 405 }
409 406
410 int UpdateAnimeEntry(int id) { 407 int UpdateAnimeEntry(int id) {
411 /**
412 * possible values:
413 *
414 * int mediaId,
415 * MediaListStatus status,
416 * float score,
417 * int scoreRaw,
418 * int progress,
419 * int progressVolumes, // manga-specific.
420 * int repeat, // rewatch
421 * int priority,
422 * bool private,
423 * string notes,
424 * bool hiddenFromStatusLists,
425 * string[] customLists,
426 * float[] advancedScores,
427 * Date startedAt,
428 * Date completedAt
429 **/
430 Anime::Anime& anime = Anime::db.items[id]; 408 Anime::Anime& anime = Anime::db.items[id];
431 if (!anime.IsInUserList()) 409 if (!anime.IsInUserList())
432 return 0; 410 return 0;
433 411
434 std::optional<std::string> service_id = anime.GetServiceId(Anime::Service::AniList); 412 std::optional<std::string> service_id = anime.GetServiceId(Anime::Service::AniList);
435 if (!service_id) 413 if (!service_id)
436 return 0; 414 return 0;
437 415
438 session.SetStatusBar("AniList: Updating anime entry..."); 416 static constexpr std::string_view query =
439 417 "mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, $score: Int, $notes: String,"
440 constexpr std::string_view query = 418 " $start: FuzzyDateInput, $comp: FuzzyDateInput, $repeat: Int) {\n"
441 "mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, $score: Int, $notes: String, $start: " 419 " SaveMediaListEntry (mediaId: $media_id, progress: $progress, status: $status, scoreRaw: $score,"
442 "FuzzyDateInput, $comp: FuzzyDateInput, $repeat: Int) {\n" 420 " notes: $notes, startedAt: $start, completedAt: $comp, repeat: $repeat) {\n"
443 " SaveMediaListEntry (mediaId: $media_id, progress: $progress, status: $status, scoreRaw: $score, notes: "
444 "$notes, startedAt: $start, completedAt: $comp, repeat: $repeat) {\n"
445 " id\n" 421 " id\n"
446 " }\n" 422 " }\n"
447 "}\n"; 423 "}\n";
448 // clang-format off 424 // clang-format off
449 nlohmann::json json = { 425 nlohmann::json json = {
495 471
496 auth.auth_token = Strings::ToUtf8String(token); 472 auth.auth_token = Strings::ToUtf8String(token);
497 473
498 session.SetStatusBar("AniList: Requesting user ID..."); 474 session.SetStatusBar("AniList: Requesting user ID...");
499 475
500 constexpr std::string_view query = "query {\n" 476 static constexpr std::string_view query =
501 " Viewer {\n" 477 "query {\n"
502 " id\n" 478 " Viewer {\n"
503 " }\n" 479 " id\n"
504 "}\n"; 480 " }\n"
481 "}\n";
482
505 nlohmann::json json = { 483 nlohmann::json json = {
506 {"query", query} 484 {"query", query}
507 }; 485 };
508 486
509 /* SendJSONRequest handles status errors */ 487 /* SendJSONRequest handles status errors */