Mercurial > minori
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 */ |
