Mercurial > minori
diff src/services/kitsu.cc @ 369:47c9f8502269
*: clang-format all the things
I've edited the formatting a bit. Now pointer asterisks (and reference
ampersands) are on the variable instead of the type, as well as having
newlines for function braces (but nothing else)
author | Paper <paper@tflc.us> |
---|---|
date | Fri, 25 Jul 2025 10:16:02 -0400 |
parents | 7e97c566cce4 |
children |
line wrap: on
line diff
--- a/src/services/kitsu.cc Fri Jul 25 10:05:23 2025 -0400 +++ b/src/services/kitsu.cc Fri Jul 25 10:16:02 2025 -0400 @@ -1,14 +1,14 @@ -#include "services/anilist.h" #include "core/anime.h" #include "core/anime_db.h" +#include "core/config.h" #include "core/date.h" -#include "core/config.h" #include "core/http.h" #include "core/json.h" #include "core/session.h" #include "core/strings.h" #include "core/time.h" #include "gui/translate/anilist.h" +#include "services/anilist.h" #include <QByteArray> #include <QDate> @@ -35,12 +35,12 @@ namespace Kitsu { /* This nifty little function basically handles authentication AND reauthentication. */ -static bool SendAuthRequest(const nlohmann::json& data) { - static const std::vector<std::string> headers = { - {"Content-Type: application/json"} - }; +static bool SendAuthRequest(const nlohmann::json &data) +{ + static const std::vector<std::string> headers = {{"Content-Type: application/json"}}; - const std::string ret = Strings::ToUtf8String(HTTP::Request(std::string(OAUTH_PATH), headers, data.dump(), HTTP::Type::Post)); + const std::string ret = + Strings::ToUtf8String(HTTP::Request(std::string(OAUTH_PATH), headers, data.dump(), HTTP::Type::Post)); if (ret.empty()) { session.SetStatusBar(Strings::Translate("Kitsu: Request returned empty data!")); return false; @@ -49,26 +49,23 @@ nlohmann::json result; try { result = nlohmann::json::parse(ret, nullptr, false); - } catch (const std::exception& ex) { - session.SetStatusBar(fmt::format(Strings::Translate("Kitsu: Failed to parse authorization data with error \"{}\""), ex.what())); + } catch (const std::exception &ex) { + session.SetStatusBar( + fmt::format(Strings::Translate("Kitsu: Failed to parse authorization data with error \"{}\""), ex.what())); return false; } if (result.contains("/error"_json_pointer)) { - session.SetStatusBar(fmt::format(Strings::Translate("Kitsu: Failed with error \"{}\"!"), result["/error"_json_pointer].get<std::string>())); + session.SetStatusBar(fmt::format(Strings::Translate("Kitsu: Failed with error \"{}\"!"), + result["/error"_json_pointer].get<std::string>())); return false; } const std::vector<nlohmann::json::json_pointer> required = { - "/access_token"_json_pointer, - "/created_at"_json_pointer, - "/expires_in"_json_pointer, - "/refresh_token"_json_pointer, - "/scope"_json_pointer, - "/token_type"_json_pointer - }; + "/access_token"_json_pointer, "/created_at"_json_pointer, "/expires_in"_json_pointer, + "/refresh_token"_json_pointer, "/scope"_json_pointer, "/token_type"_json_pointer}; - for (const auto& ptr : required) { + for (const auto &ptr : required) { if (!result.contains(ptr)) { session.SetStatusBar(Strings::Translate("Kitsu: Authorization request returned bad data!")); return false; @@ -76,9 +73,8 @@ } session.config.auth.kitsu.access_token = result["/access_token"_json_pointer].get<std::string>(); - session.config.auth.kitsu.access_token_expiration - = result["/created_at"_json_pointer].get<Time::Timestamp>() - + result["/expires_in"_json_pointer].get<Time::Timestamp>(); + session.config.auth.kitsu.access_token_expiration = result["/created_at"_json_pointer].get<Time::Timestamp>() + + result["/expires_in"_json_pointer].get<Time::Timestamp>(); session.config.auth.kitsu.refresh_token = result["/refresh_token"_json_pointer].get<std::string>(); /* the next two are not that important */ @@ -86,10 +82,11 @@ return true; } -static bool RefreshAccessToken(void) { +static bool RefreshAccessToken(void) +{ const nlohmann::json request = { - {"grant_type", "refresh_token"}, - {"refresh_token", session.config.auth.kitsu.refresh_token}, + {"grant_type", "refresh_token" }, + {"refresh_token", session.config.auth.kitsu.refresh_token}, }; if (!SendAuthRequest(request)) @@ -100,8 +97,9 @@ /* ----------------------------------------------------------------------------- */ -static std::optional<std::string> AccountAccessToken() { - auto& auth = session.config.auth.kitsu; +static std::optional<std::string> AccountAccessToken() +{ + auto &auth = session.config.auth.kitsu; if (Time::GetSystemTime() >= session.config.auth.kitsu.access_token_expiration) if (!RefreshAccessToken()) @@ -112,20 +110,12 @@ /* ----------------------------------------------------------------------------- */ -static void AddAnimeFilters(std::map<std::string, std::string>& map) { +static void AddAnimeFilters(std::map<std::string, std::string> &map) +{ static const std::vector<std::string> fields = { - "abbreviatedTitles", - "averageRating", - "episodeCount", - "episodeLength", - "posterImage", - "startDate", - "status", - "subtype", - "titles", - "categories", - "synopsis", - "animeProductions", + "abbreviatedTitles", "averageRating", "episodeCount", "episodeLength", "posterImage", + "startDate", "status", "subtype", "titles", "categories", + "synopsis", "animeProductions", }; static const std::string imploded = Strings::Implode(fields, ","); @@ -135,18 +125,11 @@ map["fields[producers]"] = "name"; } -static void AddLibraryEntryFilters(std::map<std::string, std::string>& map) { +static void AddLibraryEntryFilters(std::map<std::string, std::string> &map) +{ static const std::vector<std::string> fields = { - "anime", - "startedAt", - "finishedAt", - "notes", - "progress", - "ratingTwenty", - "reconsumeCount", - "reconsuming", - "status", - "updatedAt", + "anime", "startedAt", "finishedAt", "notes", "progress", + "ratingTwenty", "reconsumeCount", "reconsuming", "status", "updatedAt", }; static const std::string imploded = Strings::Implode(fields, ","); @@ -155,16 +138,16 @@ /* ----------------------------------------------------------------------------- */ -static std::optional<nlohmann::json> SendJSONAPIRequest(const std::string& path, const std::map<std::string, std::string>& params = {}) { +static std::optional<nlohmann::json> SendJSONAPIRequest(const std::string &path, + const std::map<std::string, std::string> ¶ms = {}) +{ std::optional<std::string> token = AccountAccessToken(); if (!token) return std::nullopt; - const std::vector<std::string> headers = { - "Accept: application/vnd.api+json", - "Authorization: Bearer " + token.value(), - "Content-Type: application/vnd.api+json" - }; + const std::vector<std::string> headers = {"Accept: application/vnd.api+json", + "Authorization: Bearer " + token.value(), + "Content-Type: application/vnd.api+json"}; const std::string url = HTTP::EncodeParamsList(std::string(BASE_API_PATH) + path, params); @@ -175,14 +158,16 @@ nlohmann::json json; try { json = nlohmann::json::parse(response); - } catch (const std::exception& ex) { - session.SetStatusBar(fmt::format(Strings::Translate("Kitsu: Failed to parse response with error \"{}\""), ex.what())); + } catch (const std::exception &ex) { + session.SetStatusBar( + fmt::format(Strings::Translate("Kitsu: Failed to parse response with error \"{}\""), ex.what())); return std::nullopt; } if (json.contains("/errors"_json_pointer)) { - for (const auto& item : json["/errors"]) - std::cerr << "Kitsu: API returned error \"" << json["/errors/title"_json_pointer] << "\" with detail \"" << json["/errors/detail"] << std::endl; + for (const auto &item : json["/errors"]) + std::cerr << "Kitsu: API returned error \"" << json["/errors/title"_json_pointer] << "\" with detail \"" + << json["/errors/detail"] << std::endl; session.SetStatusBar(Strings::Translate("Kitsu: Request failed with errors!")); return std::nullopt; @@ -191,27 +176,29 @@ return json; } -static void ParseTitleJson(Anime::Anime& anime, const nlohmann::json& json) { +static void ParseTitleJson(Anime::Anime &anime, const nlohmann::json &json) +{ static const std::map<std::string, Anime::TitleLanguage> lookup = { - {"en", Anime::TitleLanguage::English}, - {"en_jp", Anime::TitleLanguage::Romaji}, - {"ja_jp", Anime::TitleLanguage::Native} - }; + {"en", Anime::TitleLanguage::English}, + {"en_jp", Anime::TitleLanguage::Romaji }, + {"ja_jp", Anime::TitleLanguage::Native } + }; - for (const auto& [string, title] : lookup) + for (const auto &[string, title] : lookup) if (json.contains(string)) anime.SetTitle(title, json[string].get<std::string>()); } -static void ParseSubtype(Anime::Anime& anime, const std::string& str) { +static void ParseSubtype(Anime::Anime &anime, const std::string &str) +{ static const std::map<std::string, Anime::SeriesFormat> lookup = { - {"ONA", Anime::SeriesFormat::Ona}, - {"OVA", Anime::SeriesFormat::Ova}, - {"TV", Anime::SeriesFormat::Tv}, - {"movie", Anime::SeriesFormat::Movie}, - {"music", Anime::SeriesFormat::Music}, - {"special", Anime::SeriesFormat::Special} - }; + {"ONA", Anime::SeriesFormat::Ona }, + {"OVA", Anime::SeriesFormat::Ova }, + {"TV", Anime::SeriesFormat::Tv }, + {"movie", Anime::SeriesFormat::Movie }, + {"music", Anime::SeriesFormat::Music }, + {"special", Anime::SeriesFormat::Special} + }; if (lookup.find(str) == lookup.end()) return; @@ -219,14 +206,15 @@ anime.SetFormat(lookup.at(str)); } -static void ParseListStatus(Anime::Anime& anime, const std::string& str) { +static void ParseListStatus(Anime::Anime &anime, const std::string &str) +{ static const std::map<std::string, Anime::ListStatus> lookup = { - {"completed", Anime::ListStatus::Completed}, - {"current", Anime::ListStatus::Current}, - {"dropped", Anime::ListStatus::Dropped}, - {"on_hold", Anime::ListStatus::Paused}, - {"planned", Anime::ListStatus::Planning} - }; + {"completed", Anime::ListStatus::Completed}, + {"current", Anime::ListStatus::Current }, + {"dropped", Anime::ListStatus::Dropped }, + {"on_hold", Anime::ListStatus::Paused }, + {"planned", Anime::ListStatus::Planning } + }; if (lookup.find(str) == lookup.end()) return; @@ -234,13 +222,14 @@ anime.SetUserStatus(lookup.at(str)); } -static void ParseSeriesStatus(Anime::Anime& anime, const std::string& str) { +static void ParseSeriesStatus(Anime::Anime &anime, const std::string &str) +{ static const std::map<std::string, Anime::SeriesStatus> lookup = { - {"current", Anime::SeriesStatus::Releasing}, - {"finished", Anime::SeriesStatus::Finished}, - {"tba", Anime::SeriesStatus::Hiatus}, // is this right? - {"unreleased", Anime::SeriesStatus::Cancelled}, - {"upcoming", Anime::SeriesStatus::NotYetReleased}, + {"current", Anime::SeriesStatus::Releasing }, + {"finished", Anime::SeriesStatus::Finished }, + {"tba", Anime::SeriesStatus::Hiatus }, // is this right? + {"unreleased", Anime::SeriesStatus::Cancelled }, + {"upcoming", Anime::SeriesStatus::NotYetReleased}, }; if (lookup.find(str) == lookup.end()) @@ -249,7 +238,8 @@ anime.SetAiringStatus(lookup.at(str)); } -static int ParseAnimeJson(const nlohmann::json& json) { +static int ParseAnimeJson(const nlohmann::json &json) +{ const std::string FAILED_TO_PARSE = Strings::Translate("Kitsu: Failed to parse anime object! {}"); const std::string service_id = json["/id"_json_pointer].get<std::string>(); @@ -263,11 +253,11 @@ return 0; } - const auto& attributes = json["/attributes"_json_pointer]; + const auto &attributes = json["/attributes"_json_pointer]; int id = Anime::db.LookupServiceIdOrUnused(Anime::Service::Kitsu, service_id); - Anime::Anime& anime = Anime::db.items[id]; + Anime::Anime &anime = Anime::db.items[id]; anime.SetId(id); anime.SetServiceId(Anime::Service::Kitsu, service_id); @@ -278,8 +268,9 @@ if (attributes.contains("/titles"_json_pointer) && attributes["/titles"_json_pointer].is_object()) ParseTitleJson(anime, attributes["/titles"_json_pointer]); - if (attributes.contains("/abbreviatedTitles"_json_pointer) && attributes["/abbreviatedTitles"_json_pointer].is_array()) - for (const auto& title : attributes["/abbreviatedTitles"_json_pointer]) + if (attributes.contains("/abbreviatedTitles"_json_pointer) && + attributes["/abbreviatedTitles"_json_pointer].is_array()) + for (const auto &title : attributes["/abbreviatedTitles"_json_pointer]) anime.AddTitleSynonym(title.get<std::string>()); if (attributes.contains("/averageRating"_json_pointer) && attributes["/averageRating"_json_pointer].is_string()) @@ -288,9 +279,10 @@ if (attributes.contains("/startDate"_json_pointer) && attributes["/startDate"_json_pointer].is_string()) anime.SetStartedDate(attributes["/startDate"_json_pointer].get<std::string>()); - anime.SetCompletedDate(attributes.contains("/endDate"_json_pointer) && attributes["/endDate"_json_pointer].is_string() - ? attributes["/endDate"_json_pointer].get<std::string>() - : anime.GetStartedDate()); + anime.SetCompletedDate(attributes.contains("/endDate"_json_pointer) && + attributes["/endDate"_json_pointer].is_string() + ? attributes["/endDate"_json_pointer].get<std::string>() + : anime.GetStartedDate()); if (attributes.contains("/subtype"_json_pointer) && attributes["/subtype"_json_pointer].is_string()) ParseSubtype(anime, attributes["/subtype"_json_pointer].get<std::string>()); @@ -298,7 +290,8 @@ if (attributes.contains("/status"_json_pointer) && attributes["/status"_json_pointer].is_string()) ParseSeriesStatus(anime, attributes["/status"_json_pointer].get<std::string>()); - if (attributes.contains("/posterImage/original"_json_pointer) && attributes["/posterImage/original"_json_pointer].is_string()) + if (attributes.contains("/posterImage/original"_json_pointer) && + attributes["/posterImage/original"_json_pointer].is_string()) anime.SetPosterUrl(attributes["/posterImage/original"_json_pointer].get<std::string>()); if (attributes.contains("/episodeCount"_json_pointer) && attributes["/episodeCount"_json_pointer].is_number()) @@ -310,16 +303,18 @@ return id; } -static int ParseLibraryJson(const nlohmann::json& json) { +static int ParseLibraryJson(const nlohmann::json &json) +{ static const std::vector<nlohmann::json::json_pointer> required = { - "/id"_json_pointer, - "/relationships/anime/data/id"_json_pointer, - "/attributes"_json_pointer, + "/id"_json_pointer, + "/relationships/anime/data/id"_json_pointer, + "/attributes"_json_pointer, }; - for (const auto& ptr : required) { + for (const auto &ptr : required) { if (!json.contains(ptr)) { - session.SetStatusBar(fmt::format(Strings::Translate("Kitsu: Failed to parse library object! (missing {})"), ptr.to_string())); + session.SetStatusBar(fmt::format(Strings::Translate("Kitsu: Failed to parse library object! (missing {})"), + ptr.to_string())); return 0; } } @@ -332,11 +327,11 @@ int id = Anime::db.LookupServiceIdOrUnused(Anime::Service::Kitsu, service_id); - const auto& attributes = json["/attributes"_json_pointer]; + const auto &attributes = json["/attributes"_json_pointer]; const std::string library_id = json["/id"_json_pointer].get<std::string>(); - Anime::Anime& anime = Anime::db.items[id]; + Anime::Anime &anime = Anime::db.items[id]; anime.AddToUserList(); @@ -346,10 +341,12 @@ anime.SetUserId(library_id); if (attributes.contains("/startedAt"_json_pointer) && attributes["/startedAt"_json_pointer].is_string()) - anime.SetUserDateStarted(Date(Time::ParseISO8601Time(attributes["/startedAt"_json_pointer].get<std::string>()))); + anime.SetUserDateStarted( + Date(Time::ParseISO8601Time(attributes["/startedAt"_json_pointer].get<std::string>()))); if (attributes.contains("/finishedAt"_json_pointer) && attributes["/finishedAt"_json_pointer].is_string()) - anime.SetUserDateCompleted(Date(Time::ParseISO8601Time(attributes["/finishedAt"_json_pointer].get<std::string>()))); + anime.SetUserDateCompleted( + Date(Time::ParseISO8601Time(attributes["/finishedAt"_json_pointer].get<std::string>()))); if (attributes.contains("/notes"_json_pointer) && attributes["/notes"_json_pointer].is_string()) anime.SetUserNotes(attributes["/notes"_json_pointer].get<std::string>()); @@ -378,11 +375,12 @@ return id; } -static void ParseMetadataJson(Anime::Anime& anime, const nlohmann::json& json) { +static void ParseMetadataJson(Anime::Anime &anime, const nlohmann::json &json) +{ std::vector<std::string> categories; std::vector<std::string> producers; - for (const auto& item : json) { + for (const auto &item : json) { std::string variant; { static const nlohmann::json::json_pointer p = "/type"_json_pointer; @@ -415,10 +413,12 @@ anime.SetProducers(producers); } -static bool ParseAnyJson(const nlohmann::json& json) { +static bool ParseAnyJson(const nlohmann::json &json) +{ static const nlohmann::json::json_pointer required = "/type"_json_pointer; if (!json.contains(required) && !json[required].is_string()) { - session.SetStatusBar(fmt::format(Strings::Translate("Kitsu: Failed to generic object! (missing {})"), required.to_string())); + session.SetStatusBar( + fmt::format(Strings::Translate("Kitsu: Failed to generic object! (missing {})"), required.to_string())); return 0; } @@ -437,10 +437,11 @@ return true; } -int GetAnimeList() { +int GetAnimeList() +{ static constexpr int LIBRARY_MAX_SIZE = 500; - const auto& auth = session.config.auth.kitsu; + const auto &auth = session.config.auth.kitsu; if (auth.user_id.empty()) { session.SetStatusBar(Strings::Translate("Kitsu: User ID is unavailable!")); @@ -451,12 +452,12 @@ bool have_next_page = true; std::map<std::string, std::string> params = { - {"filter[user_id]", auth.user_id}, - {"filter[kind]", "anime"}, - {"include", "anime"}, - {"page[offset]", Strings::ToUtf8String(page)}, - {"page[limit]", Strings::ToUtf8String(LIBRARY_MAX_SIZE)} - }; + {"filter[user_id]", auth.user_id }, + {"filter[kind]", "anime" }, + {"include", "anime" }, + {"page[offset]", Strings::ToUtf8String(page) }, + {"page[limit]", Strings::ToUtf8String(LIBRARY_MAX_SIZE)} + }; AddAnimeFilters(params); AddLibraryEntryFilters(params); @@ -469,19 +470,20 @@ if (!response) return 0; - const nlohmann::json& root = response.value(); + const nlohmann::json &root = response.value(); if (root.contains("/next"_json_pointer) && root["/next"_json_pointer].is_number()) { page += root["/next"_json_pointer].get<int>(); if (page <= 0) have_next_page = false; - } else have_next_page = false; + } else + have_next_page = false; - for (const auto& item : root["/data"_json_pointer]) + for (const auto &item : root["/data"_json_pointer]) if (!ParseLibraryJson(item)) success = false; - for (const auto& variant : root["/included"_json_pointer]) + for (const auto &variant : root["/included"_json_pointer]) if (!ParseAnyJson(variant)) success = false; @@ -494,9 +496,10 @@ return 1; } -bool RetrieveAnimeMetadata(int id) { +bool RetrieveAnimeMetadata(int id) +{ /* TODO: the genres should *probably* be a std::optional */ - Anime::Anime& anime = Anime::db.items[id]; + Anime::Anime &anime = Anime::db.items[id]; if (anime.GetGenres().size() > 0 && anime.GetProducers().size()) return false; @@ -507,21 +510,23 @@ session.SetStatusBar(Strings::Translate("Kitsu: Retrieving anime metadata...")); static const std::map<std::string, std::string> params = { - {"include", Strings::Implode({ - "categories", - "animeProductions", - "animeProductions.producer", - }, ",")} - }; + {"include", Strings::Implode( + { + "categories", + "animeProductions", + "animeProductions.producer", + }, ",")} + }; std::optional<nlohmann::json> response = SendJSONAPIRequest("/anime/" + service_id.value(), params); if (!response) return false; - const auto& json = response.value(); + const auto &json = response.value(); if (!json.contains("/included"_json_pointer) || !json["/included"_json_pointer].is_array()) { - session.SetStatusBar(Strings::Translate("Kitsu: Server returned bad data when trying to retrieve anime metadata!")); + session.SetStatusBar( + Strings::Translate("Kitsu: Server returned bad data when trying to retrieve anime metadata!")); return false; } @@ -533,37 +538,41 @@ } /* unimplemented for now */ -std::vector<int> Search(const std::string& search) { +std::vector<int> Search(const std::string &search) +{ return {}; } -bool GetSeason(Anime::Season season) { +bool GetSeason(Anime::Season season) +{ return false; } -int UpdateAnimeEntry(int id) { +int UpdateAnimeEntry(int id) +{ return 0; } -bool AuthorizeUser(const std::string& email, const std::string& password) { +bool AuthorizeUser(const std::string &email, const std::string &password) +{ const nlohmann::json body = { - {"grant_type", "password"}, - {"username", email}, - {"password", HTTP::UrlEncode(password)} - }; + {"grant_type", "password" }, + {"username", email }, + {"password", HTTP::UrlEncode(password)} + }; if (!SendAuthRequest(body)) return false; static const std::map<std::string, std::string> params = { - {"filter[self]", "true"} - }; + {"filter[self]", "true"} + }; std::optional<nlohmann::json> response = SendJSONAPIRequest("/users", params); if (!response) return false; // whuh? - const nlohmann::json& json = response.value(); + const nlohmann::json &json = response.value(); if (!json.contains("/data/0/id"_json_pointer)) { session.SetStatusBar(Strings::Translate("Kitsu: Failed to retrieve user ID!"));