Mercurial > minori
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> ¶ms = {}, | 159 const std::map<std::string, std::string> ¶ms = {}, 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? |
