comparison src/services/kitsu.cc @ 413:192da585a0a8 default tip

*: fix formatting the clang-format file was broken andjust using LLVM defaults. now it's fixed and is more in line with what I actually prefer my code to look like -- esp. with regards to tabulators
author Paper <paper@tflc.us>
date Sat, 25 Jul 2026 14:54:32 -0400
parents 02a670a8e1c4
children
comparison
equal deleted inserted replaced
412:05aed03e0111 413:192da585a0a8
38 static bool SendAuthRequest(const nlohmann::json &data) 38 static bool SendAuthRequest(const nlohmann::json &data)
39 { 39 {
40 static const std::vector<std::string> headers = {{"Content-Type: application/json"}}; 40 static const std::vector<std::string> headers = {{"Content-Type: application/json"}};
41 41
42 const std::string ret = 42 const std::string ret =
43 Strings::ToUtf8String(HTTP::Request(std::string(OAUTH_PATH), headers, data.dump(), HTTP::Type::Post)); 43 Strings::ToUtf8String(HTTP::Request(std::string(OAUTH_PATH), headers, data.dump(), HTTP::Type::Post));
44 if (ret.empty()) { 44 if (ret.empty()) {
45 session.SetStatusBar(Strings::Translate("Kitsu: Request returned empty data!")); 45 session.SetStatusBar(Strings::Translate("Kitsu: Request returned empty data!"));
46 return false; 46 return false;
47 } 47 }
48 48
49 nlohmann::json result; 49 nlohmann::json result;
50 try { 50 try {
51 result = nlohmann::json::parse(ret, nullptr, false); 51 result = nlohmann::json::parse(ret, nullptr, false);
52 } catch (const std::exception &ex) { 52 } catch (const std::exception &ex) {
53 session.SetStatusBar( 53 session.SetStatusBar(
54 fmt::format(Strings::Translate("Kitsu: Failed to parse authorization data with error \"{}\""), ex.what())); 54 fmt::format(Strings::Translate("Kitsu: Failed to parse authorization data with error \"{}\""), ex.what()));
55 return false; 55 return false;
56 } 56 }
57 57
58 if (result.contains("/error"_json_pointer)) { 58 if (result.contains("/error"_json_pointer)) {
59 session.SetStatusBar(fmt::format(Strings::Translate("Kitsu: Failed with error \"{}\"!"), 59 session.SetStatusBar(fmt::format(
60 result["/error"_json_pointer].get<std::string>())); 60 Strings::Translate("Kitsu: Failed with error \"{}\"!"), result["/error"_json_pointer].get<std::string>()));
61 return false; 61 return false;
62 } 62 }
63 63
64 const std::vector<nlohmann::json::json_pointer> required = { 64 const std::vector<nlohmann::json::json_pointer> required = {"/access_token"_json_pointer,
65 "/access_token"_json_pointer, "/created_at"_json_pointer, "/expires_in"_json_pointer, 65 "/created_at"_json_pointer, "/expires_in"_json_pointer, "/refresh_token"_json_pointer, "/scope"_json_pointer,
66 "/refresh_token"_json_pointer, "/scope"_json_pointer, "/token_type"_json_pointer}; 66 "/token_type"_json_pointer};
67 67
68 for (const auto &ptr : required) { 68 for (const auto &ptr : required) {
69 if (!result.contains(ptr)) { 69 if (!result.contains(ptr)) {
70 session.SetStatusBar(Strings::Translate("Kitsu: Authorization request returned bad data!")); 70 session.SetStatusBar(Strings::Translate("Kitsu: Authorization request returned bad data!"));
71 return false; 71 return false;
72 } 72 }
73 } 73 }
74 74
75 session.config.auth.kitsu.access_token = result["/access_token"_json_pointer].get<std::string>(); 75 session.config.auth.kitsu.access_token = result["/access_token"_json_pointer].get<std::string>();
76 session.config.auth.kitsu.access_token_expiration = result["/created_at"_json_pointer].get<Time::Timestamp>() + 76 session.config.auth.kitsu.access_token_expiration = result["/created_at"_json_pointer].get<Time::Timestamp>() +
77 result["/expires_in"_json_pointer].get<Time::Timestamp>(); 77 result["/expires_in"_json_pointer].get<Time::Timestamp>();
78 session.config.auth.kitsu.refresh_token = result["/refresh_token"_json_pointer].get<std::string>(); 78 session.config.auth.kitsu.refresh_token = result["/refresh_token"_json_pointer].get<std::string>();
79 79
80 /* the next two are not that important */ 80 /* the next two are not that important */
81 81
82 return true; 82 return true;
83 } 83 }
84 84
85 static bool RefreshAccessToken(void) 85 static bool RefreshAccessToken(void)
86 { 86 {
87 const nlohmann::json request = { 87 const nlohmann::json request = {
88 {"grant_type", "refresh_token" }, 88 {"grant_type", "refresh_token" },
89 {"refresh_token", session.config.auth.kitsu.refresh_token}, 89 {"refresh_token", session.config.auth.kitsu.refresh_token},
90 }; 90 };
91 91
92 if (!SendAuthRequest(request)) 92 if (!SendAuthRequest(request))
93 return false; 93 return false;
94 94
111 /* ----------------------------------------------------------------------------- */ 111 /* ----------------------------------------------------------------------------- */
112 112
113 static void AddAnimeFilters(std::map<std::string, std::string> &map) 113 static void AddAnimeFilters(std::map<std::string, std::string> &map)
114 { 114 {
115 static const std::vector<std::string> fields = { 115 static const std::vector<std::string> fields = {
116 "abbreviatedTitles", "averageRating", "episodeCount", "episodeLength", "posterImage", 116 "abbreviatedTitles",
117 "startDate", "status", "subtype", "titles", "categories", 117 "averageRating",
118 "synopsis", "animeProductions", 118 "episodeCount",
119 "episodeLength",
120 "posterImage",
121 "startDate",
122 "status",
123 "subtype",
124 "titles",
125 "categories",
126 "synopsis",
127 "animeProductions",
119 }; 128 };
120 static const std::string imploded = Strings::Implode(fields, ","); 129 static const std::string imploded = Strings::Implode(fields, ",");
121 130
122 map["fields[anime]"] = imploded; 131 map["fields[anime]"] = imploded;
123 map["fields[animeProductions]"] = "producer"; 132 map["fields[animeProductions]"] = "producer";
126 } 135 }
127 136
128 static void AddLibraryEntryFilters(std::map<std::string, std::string> &map) 137 static void AddLibraryEntryFilters(std::map<std::string, std::string> &map)
129 { 138 {
130 static const std::vector<std::string> fields = { 139 static const std::vector<std::string> fields = {
131 "anime", "startedAt", "finishedAt", "notes", "progress", 140 "anime",
132 "ratingTwenty", "reconsumeCount", "reconsuming", "status", "updatedAt", 141 "startedAt",
142 "finishedAt",
143 "notes",
144 "progress",
145 "ratingTwenty",
146 "reconsumeCount",
147 "reconsuming",
148 "status",
149 "updatedAt",
133 }; 150 };
134 static const std::string imploded = Strings::Implode(fields, ","); 151 static const std::string imploded = Strings::Implode(fields, ",");
135 152
136 map["fields[libraryEntries]"] = imploded; 153 map["fields[libraryEntries]"] = imploded;
137 } 154 }
138 155
139 /* ----------------------------------------------------------------------------- */ 156 /* ----------------------------------------------------------------------------- */
140 157
141 static std::optional<nlohmann::json> SendJSONAPIRequest(const std::string &path, 158 static std::optional<nlohmann::json> SendJSONAPIRequest(const std::string &path,
142 const std::map<std::string, std::string> &params = {}, 159 const std::map<std::string, std::string> &params = {}, const std::string &data = "",
143 const std::string &data = "", HTTP::Type type = HTTP::Type::Get) 160 HTTP::Type type = HTTP::Type::Get)
144 { 161 {
145 std::optional<std::string> token = AccountAccessToken(); 162 std::optional<std::string> token = AccountAccessToken();
146 if (!token) 163 if (!token)
147 return std::nullopt; 164 return std::nullopt;
148 165
149 const std::vector<std::string> headers = {"Accept: application/vnd.api+json", 166 const std::vector<std::string> headers = {"Accept: application/vnd.api+json",
150 "Authorization: Bearer " + token.value(), 167 "Authorization: Bearer " + token.value(), "Content-Type: application/vnd.api+json"};
151 "Content-Type: application/vnd.api+json"};
152 168
153 const std::string url = HTTP::EncodeParamsList(std::string(BASE_API_PATH) + path, params); 169 const std::string url = HTTP::EncodeParamsList(std::string(BASE_API_PATH) + path, params);
154 170
155 const std::string response = Strings::ToUtf8String(HTTP::Request(url, headers, data, type)); 171 const std::string response = Strings::ToUtf8String(HTTP::Request(url, headers, data, type));
156 if (response.empty()) 172 if (response.empty())
159 nlohmann::json json; 175 nlohmann::json json;
160 try { 176 try {
161 json = nlohmann::json::parse(response); 177 json = nlohmann::json::parse(response);
162 } catch (const std::exception &ex) { 178 } catch (const std::exception &ex) {
163 session.SetStatusBar( 179 session.SetStatusBar(
164 fmt::format(Strings::Translate("Kitsu: Failed to parse response with error \"{}\""), ex.what())); 180 fmt::format(Strings::Translate("Kitsu: Failed to parse response with error \"{}\""), ex.what()));
165 return std::nullopt; 181 return std::nullopt;
166 } 182 }
167 183
168 if (json.contains("/errors"_json_pointer)) { 184 if (json.contains("/errors"_json_pointer)) {
169 std::cout << json["/errors"_json_pointer] << '\n'; 185 std::cout << json["/errors"_json_pointer] << '\n';
181 } 197 }
182 198
183 static void ParseTitleJson(Anime::Anime &anime, const nlohmann::json &json) 199 static void ParseTitleJson(Anime::Anime &anime, const nlohmann::json &json)
184 { 200 {
185 static const std::map<std::string, Anime::TitleLanguage> lookup = { 201 static const std::map<std::string, Anime::TitleLanguage> lookup = {
186 {"en", Anime::TitleLanguage::English}, 202 {"en", Anime::TitleLanguage::English},
187 {"en_jp", Anime::TitleLanguage::Romaji }, 203 {"en_jp", Anime::TitleLanguage::Romaji },
188 {"ja_jp", Anime::TitleLanguage::Native } 204 {"ja_jp", Anime::TitleLanguage::Native }
189 }; 205 };
190 206
191 for (const auto &[string, title] : lookup) 207 for (const auto &[string, title] : lookup)
192 if (json.contains(string)) 208 if (json.contains(string))
193 anime.SetTitle(title, json[string].get<std::string>()); 209 anime.SetTitle(title, json[string].get<std::string>());
194 } 210 }
195 211
196 static void ParseSubtype(Anime::Anime &anime, const std::string &str) 212 static void ParseSubtype(Anime::Anime &anime, const std::string &str)
197 { 213 {
198 static const std::map<std::string, Anime::SeriesFormat> lookup = { 214 static const std::map<std::string, Anime::SeriesFormat> lookup = {
199 {"ONA", Anime::SeriesFormat::Ona }, 215 {"ONA", Anime::SeriesFormat::Ona },
200 {"OVA", Anime::SeriesFormat::Ova }, 216 {"OVA", Anime::SeriesFormat::Ova },
201 {"TV", Anime::SeriesFormat::Tv }, 217 {"TV", Anime::SeriesFormat::Tv },
202 {"movie", Anime::SeriesFormat::Movie }, 218 {"movie", Anime::SeriesFormat::Movie },
203 {"music", Anime::SeriesFormat::Music }, 219 {"music", Anime::SeriesFormat::Music },
204 {"special", Anime::SeriesFormat::Special} 220 {"special", Anime::SeriesFormat::Special}
205 }; 221 };
206 222
207 if (lookup.find(str) == lookup.end()) 223 if (lookup.find(str) == lookup.end())
208 return; 224 return;
209 225
211 } 227 }
212 228
213 static void ParseListStatus(Anime::Anime &anime, const std::string &str) 229 static void ParseListStatus(Anime::Anime &anime, const std::string &str)
214 { 230 {
215 static const std::map<std::string, Anime::ListStatus> lookup = { 231 static const std::map<std::string, Anime::ListStatus> lookup = {
216 {"completed", Anime::ListStatus::Completed}, 232 {"completed", Anime::ListStatus::Completed},
217 {"current", Anime::ListStatus::Current }, 233 {"current", Anime::ListStatus::Current },
218 {"dropped", Anime::ListStatus::Dropped }, 234 {"dropped", Anime::ListStatus::Dropped },
219 {"on_hold", Anime::ListStatus::Paused }, 235 {"on_hold", Anime::ListStatus::Paused },
220 {"planned", Anime::ListStatus::Planning } 236 {"planned", Anime::ListStatus::Planning }
221 }; 237 };
222 238
223 if (lookup.find(str) == lookup.end()) 239 if (lookup.find(str) == lookup.end())
224 return; 240 return;
225 241
227 } 243 }
228 244
229 static void ParseSeriesStatus(Anime::Anime &anime, const std::string &str) 245 static void ParseSeriesStatus(Anime::Anime &anime, const std::string &str)
230 { 246 {
231 static const std::map<std::string, Anime::SeriesStatus> lookup = { 247 static const std::map<std::string, Anime::SeriesStatus> lookup = {
232 {"current", Anime::SeriesStatus::Releasing }, 248 {"current", Anime::SeriesStatus::Releasing },
233 {"finished", Anime::SeriesStatus::Finished }, 249 {"finished", Anime::SeriesStatus::Finished },
234 {"tba", Anime::SeriesStatus::Hiatus }, // is this right? 250 {"tba", Anime::SeriesStatus::Hiatus }, // is this right?
235 {"unreleased", Anime::SeriesStatus::Cancelled }, 251 {"unreleased", Anime::SeriesStatus::Cancelled },
236 {"upcoming", Anime::SeriesStatus::NotYetReleased}, 252 {"upcoming", Anime::SeriesStatus::NotYetReleased},
237 }; 253 };
238 254
239 if (lookup.find(str) == lookup.end()) 255 if (lookup.find(str) == lookup.end())
240 return; 256 return;
241 257
271 287
272 if (attributes.contains("/titles"_json_pointer) && attributes["/titles"_json_pointer].is_object()) 288 if (attributes.contains("/titles"_json_pointer) && attributes["/titles"_json_pointer].is_object())
273 ParseTitleJson(anime, attributes["/titles"_json_pointer]); 289 ParseTitleJson(anime, attributes["/titles"_json_pointer]);
274 290
275 if (attributes.contains("/abbreviatedTitles"_json_pointer) && 291 if (attributes.contains("/abbreviatedTitles"_json_pointer) &&
276 attributes["/abbreviatedTitles"_json_pointer].is_array()) 292 attributes["/abbreviatedTitles"_json_pointer].is_array())
277 for (const auto &title : attributes["/abbreviatedTitles"_json_pointer]) 293 for (const auto &title : attributes["/abbreviatedTitles"_json_pointer])
278 anime.AddTitleSynonym(title.get<std::string>()); 294 anime.AddTitleSynonym(title.get<std::string>());
279 295
280 if (attributes.contains("/averageRating"_json_pointer) && attributes["/averageRating"_json_pointer].is_string()) 296 if (attributes.contains("/averageRating"_json_pointer) && attributes["/averageRating"_json_pointer].is_string())
281 anime.SetAudienceScore(Strings::ToInt<double>(attributes["/averageRating"_json_pointer].get<std::string>())); 297 anime.SetAudienceScore(Strings::ToInt<double>(attributes["/averageRating"_json_pointer].get<std::string>()));
282 298
283 if (attributes.contains("/startDate"_json_pointer) && attributes["/startDate"_json_pointer].is_string()) 299 if (attributes.contains("/startDate"_json_pointer) && attributes["/startDate"_json_pointer].is_string())
284 anime.SetStartedDate(attributes["/startDate"_json_pointer].get<std::string>()); 300 anime.SetStartedDate(attributes["/startDate"_json_pointer].get<std::string>());
285 301
286 anime.SetCompletedDate(attributes.contains("/endDate"_json_pointer) && 302 anime.SetCompletedDate(
287 attributes["/endDate"_json_pointer].is_string() 303 attributes.contains("/endDate"_json_pointer) && attributes["/endDate"_json_pointer].is_string()
288 ? attributes["/endDate"_json_pointer].get<std::string>() 304 ? attributes["/endDate"_json_pointer].get<std::string>()
289 : anime.GetStartedDate()); 305 : anime.GetStartedDate());
290 306
291 if (attributes.contains("/subtype"_json_pointer) && attributes["/subtype"_json_pointer].is_string()) 307 if (attributes.contains("/subtype"_json_pointer) && attributes["/subtype"_json_pointer].is_string())
292 ParseSubtype(anime, attributes["/subtype"_json_pointer].get<std::string>()); 308 ParseSubtype(anime, attributes["/subtype"_json_pointer].get<std::string>());
293 309
294 if (attributes.contains("/status"_json_pointer) && attributes["/status"_json_pointer].is_string()) 310 if (attributes.contains("/status"_json_pointer) && attributes["/status"_json_pointer].is_string())
295 ParseSeriesStatus(anime, attributes["/status"_json_pointer].get<std::string>()); 311 ParseSeriesStatus(anime, attributes["/status"_json_pointer].get<std::string>());
296 312
297 if (attributes.contains("/posterImage/original"_json_pointer) && 313 if (attributes.contains("/posterImage/original"_json_pointer) &&
298 attributes["/posterImage/original"_json_pointer].is_string()) 314 attributes["/posterImage/original"_json_pointer].is_string())
299 anime.SetPosterUrl(attributes["/posterImage/original"_json_pointer].get<std::string>()); 315 anime.SetPosterUrl(attributes["/posterImage/original"_json_pointer].get<std::string>());
300 316
301 if (attributes.contains("/episodeCount"_json_pointer) && attributes["/episodeCount"_json_pointer].is_number()) 317 if (attributes.contains("/episodeCount"_json_pointer) && attributes["/episodeCount"_json_pointer].is_number())
302 anime.SetEpisodes(attributes["/episodeCount"_json_pointer].get<int>()); 318 anime.SetEpisodes(attributes["/episodeCount"_json_pointer].get<int>());
303 319
308 } 324 }
309 325
310 static int ParseLibraryJson(const nlohmann::json &json) 326 static int ParseLibraryJson(const nlohmann::json &json)
311 { 327 {
312 static const std::vector<nlohmann::json::json_pointer> required = { 328 static const std::vector<nlohmann::json::json_pointer> required = {
313 "/id"_json_pointer, 329 "/id"_json_pointer,
314 "/relationships/anime/data/id"_json_pointer, 330 "/relationships/anime/data/id"_json_pointer,
315 "/attributes"_json_pointer, 331 "/attributes"_json_pointer,
316 }; 332 };
317 333
318 for (const auto &ptr : required) { 334 for (const auto &ptr : required) {
319 if (!json.contains(ptr)) { 335 if (!json.contains(ptr)) {
320 session.SetStatusBar(fmt::format(Strings::Translate("Kitsu: Failed to parse library object! (missing {})"), 336 session.SetStatusBar(fmt::format(
321 ptr.to_string())); 337 Strings::Translate("Kitsu: Failed to parse library object! (missing {})"), ptr.to_string()));
322 return 0; 338 return 0;
323 } 339 }
324 } 340 }
325 341
326 std::string service_id = json["/relationships/anime/data/id"_json_pointer].get<std::string>(); 342 std::string service_id = json["/relationships/anime/data/id"_json_pointer].get<std::string>();
344 360
345 anime.SetUserId(library_id); 361 anime.SetUserId(library_id);
346 362
347 if (attributes.contains("/startedAt"_json_pointer) && attributes["/startedAt"_json_pointer].is_string()) 363 if (attributes.contains("/startedAt"_json_pointer) && attributes["/startedAt"_json_pointer].is_string())
348 anime.SetUserDateStarted( 364 anime.SetUserDateStarted(
349 Date(Time::ParseISO8601Time(attributes["/startedAt"_json_pointer].get<std::string>()))); 365 Date(Time::ParseISO8601Time(attributes["/startedAt"_json_pointer].get<std::string>())));
350 366
351 if (attributes.contains("/finishedAt"_json_pointer) && attributes["/finishedAt"_json_pointer].is_string()) 367 if (attributes.contains("/finishedAt"_json_pointer) && attributes["/finishedAt"_json_pointer].is_string())
352 anime.SetUserDateCompleted( 368 anime.SetUserDateCompleted(
353 Date(Time::ParseISO8601Time(attributes["/finishedAt"_json_pointer].get<std::string>()))); 369 Date(Time::ParseISO8601Time(attributes["/finishedAt"_json_pointer].get<std::string>())));
354 370
355 if (attributes.contains("/notes"_json_pointer) && attributes["/notes"_json_pointer].is_string()) 371 if (attributes.contains("/notes"_json_pointer) && attributes["/notes"_json_pointer].is_string())
356 anime.SetUserNotes(attributes["/notes"_json_pointer].get<std::string>()); 372 anime.SetUserNotes(attributes["/notes"_json_pointer].get<std::string>());
357 373
358 if (attributes.contains("/progress"_json_pointer) && attributes["/progress"_json_pointer].is_number()) 374 if (attributes.contains("/progress"_json_pointer) && attributes["/progress"_json_pointer].is_number())
420 static bool ParseAnyJson(const nlohmann::json &json) 436 static bool ParseAnyJson(const nlohmann::json &json)
421 { 437 {
422 static const nlohmann::json::json_pointer required = "/type"_json_pointer; 438 static const nlohmann::json::json_pointer required = "/type"_json_pointer;
423 if (!json.contains(required) && !json[required].is_string()) { 439 if (!json.contains(required) && !json[required].is_string()) {
424 session.SetStatusBar( 440 session.SetStatusBar(
425 fmt::format(Strings::Translate("Kitsu: Failed to generic object! (missing {})"), required.to_string())); 441 fmt::format(Strings::Translate("Kitsu: Failed to generic object! (missing {})"), required.to_string()));
426 return 0; 442 return 0;
427 } 443 }
428 444
429 std::string variant = json["/type"_json_pointer].get<std::string>(); 445 std::string variant = json["/type"_json_pointer].get<std::string>();
430 446
454 470
455 int page = 0; 471 int page = 0;
456 bool have_next_page = true; 472 bool have_next_page = true;
457 473
458 std::map<std::string, std::string> params = { 474 std::map<std::string, std::string> params = {
459 {"filter[user_id]", auth.user_id }, 475 {"filter[user_id]", auth.user_id },
460 {"filter[kind]", "anime" }, 476 {"filter[kind]", "anime" },
461 {"include", "anime" }, 477 {"include", "anime" },
462 {"page[offset]", Strings::ToUtf8String(page) }, 478 {"page[offset]", Strings::ToUtf8String(page) },
463 {"page[limit]", Strings::ToUtf8String(LIBRARY_MAX_SIZE)} 479 {"page[limit]", Strings::ToUtf8String(LIBRARY_MAX_SIZE)}
464 }; 480 };
465 AddAnimeFilters(params); 481 AddAnimeFilters(params);
466 AddLibraryEntryFilters(params); 482 AddLibraryEntryFilters(params);
467 483
468 Anime::db.RemoveAllUserData(); 484 Anime::db.RemoveAllUserData();
500 return 1; 516 return 1;
501 } 517 }
502 518
503 /* :) */ 519 /* :) */
504 static const std::map<std::string, std::string> anime_params = { 520 static const std::map<std::string, std::string> anime_params = {
505 {"include", Strings::Implode( 521 {"include", Strings::Implode(
506 { 522 {
507 "categories", 523 "categories",
508 "animeProductions", 524 "animeProductions",
509 "animeProductions.producer", 525 "animeProductions.producer",
510 }, ",")} 526 }, ",")}
511 }; 527 };
512 528
513 bool RetrieveAnimeMetadata(int id) 529 bool RetrieveAnimeMetadata(int id)
514 { 530 {
515 /* TODO: the genres should *probably* be a std::optional */ 531 /* TODO: the genres should *probably* be a std::optional */
529 545
530 const auto &json = response.value(); 546 const auto &json = response.value();
531 547
532 if (!json.contains("/included"_json_pointer) || !json["/included"_json_pointer].is_array()) { 548 if (!json.contains("/included"_json_pointer) || !json["/included"_json_pointer].is_array()) {
533 session.SetStatusBar( 549 session.SetStatusBar(
534 Strings::Translate("Kitsu: Server returned bad data when trying to retrieve anime metadata!")); 550 Strings::Translate("Kitsu: Server returned bad data when trying to retrieve anime metadata!"));
535 return false; 551 return false;
536 } 552 }
537 553
538 ParseMetadataJson(anime, json["/included"_json_pointer]); 554 ParseMetadataJson(anime, json["/included"_json_pointer]);
539 555
558 574
559 const auto &json = response.value(); 575 const auto &json = response.value();
560 576
561 if (!json.contains("/data"_json_pointer) || !json["/data"_json_pointer].is_array()) { 577 if (!json.contains("/data"_json_pointer) || !json["/data"_json_pointer].is_array()) {
562 session.SetStatusBar( 578 session.SetStatusBar(
563 Strings::Translate("Kitsu: Server returned bad data when trying to retrieve search results!")); 579 Strings::Translate("Kitsu: Server returned bad data when trying to retrieve search results!"));
564 return {}; 580 return {};
565 } 581 }
566 582
567 std::vector<int> ids; 583 std::vector<int> ids;
568 584
578 } 594 }
579 595
580 bool GetSeason(Anime::Season season) 596 bool GetSeason(Anime::Season season)
581 { 597 {
582 static const std::map<Anime::Season::Name, std::string> map = { 598 static const std::map<Anime::Season::Name, std::string> map = {
583 {Anime::Season::Name::Winter, "winter"}, 599 {Anime::Season::Name::Winter, "winter"},
584 {Anime::Season::Name::Spring, "spring"}, 600 {Anime::Season::Name::Spring, "spring"},
585 {Anime::Season::Name::Summer, "summer"}, 601 {Anime::Season::Name::Summer, "summer"},
586 {Anime::Season::Name::Autumn, "fall" }, 602 {Anime::Season::Name::Autumn, "fall" },
587 }; 603 };
588 604
589 session.SetStatusBar(Strings::Translate("Kitsu: Retrieving season data...")); 605 session.SetStatusBar(Strings::Translate("Kitsu: Retrieving season data..."));
590 606
591 std::map<std::string, std::string> params = anime_params; 607 std::map<std::string, std::string> params = anime_params;
600 616
601 const auto &json = response.value(); 617 const auto &json = response.value();
602 618
603 if (!json.contains("/data"_json_pointer) || !json["/data"_json_pointer].is_array()) { 619 if (!json.contains("/data"_json_pointer) || !json["/data"_json_pointer].is_array()) {
604 session.SetStatusBar( 620 session.SetStatusBar(
605 Strings::Translate("Kitsu: Server returned bad data when trying to retrieve search results!")); 621 Strings::Translate("Kitsu: Server returned bad data when trying to retrieve search results!"));
606 return false; 622 return false;
607 } 623 }
608 624
609 for (const auto &item : json["/data"_json_pointer]) 625 for (const auto &item : json["/data"_json_pointer])
610 ParseAnimeJson(item); 626 ParseAnimeJson(item);
707 } 723 }
708 724
709 bool AuthorizeUser(const std::string &email, const std::string &password) 725 bool AuthorizeUser(const std::string &email, const std::string &password)
710 { 726 {
711 const nlohmann::json body = { 727 const nlohmann::json body = {
712 {"grant_type", "password" }, 728 {"grant_type", "password" },
713 {"username", email }, 729 {"username", email },
714 {"password", HTTP::UrlEncode(password)} 730 {"password", HTTP::UrlEncode(password)}
715 }; 731 };
716 732
717 if (!SendAuthRequest(body)) 733 if (!SendAuthRequest(body))
718 return false; 734 return false;
719 735
720 static const std::map<std::string, std::string> params = { 736 static const std::map<std::string, std::string> params = {
721 {"filter[self]", "true"} 737 {"filter[self]", "true"}
722 }; 738 };
723 739
724 std::optional<nlohmann::json> response = SendJSONAPIRequest("/users", params); 740 std::optional<nlohmann::json> response = SendJSONAPIRequest("/users", params);
725 if (!response) 741 if (!response)
726 return false; // whuh? 742 return false; // whuh?