diff src/services/anilist.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 f81bed4e04ac
children
line wrap: on
line diff
--- a/src/services/anilist.cc	Fri Jul 25 10:05:23 2025 -0400
+++ b/src/services/anilist.cc	Fri Jul 25 10:16:02 2025 -0400
@@ -1,8 +1,8 @@
 #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"
@@ -70,16 +70,18 @@
 
 /* FIXME: why is this here */
 
-static std::optional<nlohmann::json> SendJSONRequest(const nlohmann::json& data) {
+static std::optional<nlohmann::json> SendJSONRequest(const nlohmann::json &data)
+{
 	std::vector<std::string> headers = {
-		"Accept: application/json",
-		"Content-Type: application/json",
+	    "Accept: application/json",
+	    "Content-Type: application/json",
 	};
 
 	if (!session.config.auth.anilist.auth_token.empty())
 		headers.push_back("Authorization: Bearer " + session.config.auth.anilist.auth_token);
 
-	const std::string response = Strings::ToUtf8String(HTTP::Request("https://graphql.anilist.co", headers, data.dump(), HTTP::Type::Post));
+	const std::string response =
+	    Strings::ToUtf8String(HTTP::Request("https://graphql.anilist.co", headers, data.dump(), HTTP::Type::Post));
 	if (response.empty()) {
 		session.SetStatusBar(Strings::Translate("AniList: JSON request returned an empty result!"));
 		return std::nullopt;
@@ -89,15 +91,16 @@
 
 	try {
 		out = nlohmann::json::parse(response);
-	} catch (const std::exception& ex) {
-		session.SetStatusBar(fmt::format(Strings::Translate("AniList: Failed to parse request JSON with error \"{}\"!"), ex.what()));
+	} catch (const std::exception &ex) {
+		session.SetStatusBar(
+		    fmt::format(Strings::Translate("AniList: Failed to parse request JSON with error \"{}\"!"), ex.what()));
 		return std::nullopt;
 	}
 
 	if (out.contains("/errors"_json_pointer) && out.at("/errors"_json_pointer).is_array()) {
-		for (const auto& error : out.at("/errors"_json_pointer))
+		for (const auto &error : out.at("/errors"_json_pointer))
 			std::cerr << "AniList: Received an error in response: "
-					  << JSON::GetString<std::string>(error, "/message"_json_pointer, "") << std::endl;
+			          << JSON::GetString<std::string>(error, "/message"_json_pointer, "") << std::endl;
 
 		session.SetStatusBar(Strings::Translate("AniList: Received an error in response!"));
 		return std::nullopt;
@@ -106,14 +109,15 @@
 	return out;
 }
 
-static void ParseListStatus(std::string status, Anime::Anime& anime) {
+static void ParseListStatus(std::string status, Anime::Anime &anime)
+{
 	static const std::unordered_map<std::string, Anime::ListStatus> map = {
-		{"CURRENT",   Anime::ListStatus::Current  },
-		{"PLANNING",  Anime::ListStatus::Planning },
-		{"COMPLETED", Anime::ListStatus::Completed},
-		{"DROPPED",   Anime::ListStatus::Dropped  },
-		{"PAUSED",    Anime::ListStatus::Paused   }
-	};
+	    {"CURRENT",   Anime::ListStatus::Current  },
+	    {"PLANNING",  Anime::ListStatus::Planning },
+	    {"COMPLETED", Anime::ListStatus::Completed},
+	    {"DROPPED",   Anime::ListStatus::Dropped  },
+	    {"PAUSED",    Anime::ListStatus::Paused   }
+    };
 
 	if (status == "REPEATING") {
 		anime.SetUserIsRewatching(true);
@@ -129,7 +133,8 @@
 	anime.SetUserStatus(map.at(status));
 }
 
-static std::string ListStatusToString(const Anime::Anime& anime) {
+static std::string ListStatusToString(const Anime::Anime &anime)
+{
 	if (anime.GetUserIsRewatching() && anime.GetUserStatus() == Anime::ListStatus::Current)
 		return "REWATCHING";
 
@@ -143,19 +148,21 @@
 	return "CURRENT";
 }
 
-static void ParseTitle(const nlohmann::json& json, Anime::Anime& anime) {
+static void ParseTitle(const nlohmann::json &json, Anime::Anime &anime)
+{
 	static const std::unordered_map<Anime::TitleLanguage, nlohmann::json::json_pointer> map = {
-		{Anime::TitleLanguage::Native, "/native"_json_pointer},
-		{Anime::TitleLanguage::English, "/english"_json_pointer},
-		{Anime::TitleLanguage::Romaji, "/romaji"_json_pointer},
+	    {Anime::TitleLanguage::Native,  "/native"_json_pointer },
+	    {Anime::TitleLanguage::English, "/english"_json_pointer},
+	    {Anime::TitleLanguage::Romaji,  "/romaji"_json_pointer },
 	};
 
-	for (const auto& [language, ptr] : map)
+	for (const auto &[language, ptr] : map)
 		if (json.contains(ptr) && json[ptr].is_string())
 			anime.SetTitle(language, json[ptr]);
 }
 
-static int ParseMediaJson(const nlohmann::json& json) {
+static int ParseMediaJson(const nlohmann::json &json)
+{
 	if (!json.contains("/id"_json_pointer) || !json["/id"_json_pointer].is_number()) {
 		session.SetStatusBar(Strings::Translate("AniList: Failed to parse anime object!"));
 		return 0;
@@ -169,7 +176,7 @@
 		return 0;
 	}
 
-	Anime::Anime& anime = Anime::db.items[id];
+	Anime::Anime &anime = Anime::db.items[id];
 	anime.SetId(id);
 	anime.SetServiceId(Anime::Service::AniList, service_id);
 
@@ -182,19 +189,20 @@
 	anime.SetFormat(Translate::AniList::ToSeriesFormat(JSON::GetString<std::string>(json, "/format"_json_pointer, "")));
 
 	anime.SetAiringStatus(
-		Translate::AniList::ToSeriesStatus(JSON::GetString<std::string>(json, "/status"_json_pointer, "")));
+	    Translate::AniList::ToSeriesStatus(JSON::GetString<std::string>(json, "/status"_json_pointer, "")));
 
 	if (json.contains("/startDate"_json_pointer) && json["/startDate"_json_pointer].is_object())
 		anime.SetStartedDate(Date(json["/startDate"_json_pointer]));
 
 	anime.SetCompletedDate(json.contains("/endDate"_json_pointer) && json["/endDate"_json_pointer].is_object()
-		? Date(json["/endDate"_json_pointer])
-		: anime.GetStartedDate());
+	                           ? Date(json["/endDate"_json_pointer])
+	                           : anime.GetStartedDate());
 
 	anime.SetPosterUrl(JSON::GetString<std::string>(json, "/coverImage/large"_json_pointer, ""));
 
 	anime.SetAudienceScore(JSON::GetNumber(json, "/averageScore"_json_pointer, 0));
-	// anime.SetSeason(Translate::AniList::ToSeriesSeason(JSON::GetString<std::string>(json, "/season"_json_pointer, "")));
+	// anime.SetSeason(Translate::AniList::ToSeriesSeason(JSON::GetString<std::string>(json, "/season"_json_pointer,
+	// "")));
 	anime.SetDuration(JSON::GetNumber(json, "/duration"_json_pointer, 0));
 
 	std::string synopsis = JSON::GetString<std::string>(json, "/description"_json_pointer, "");
@@ -208,7 +216,7 @@
 		std::vector<std::string> producers;
 
 		if (json.contains("/studios/edges"_json_pointer) && json["/studios/edges"_json_pointer].is_array())
-			for (const auto& edge : json["/studios/edges"_json_pointer])
+			for (const auto &edge : json["/studios/edges"_json_pointer])
 				if (edge.contains("/node/name"_json_pointer) && edge["/node/name"_json_pointer].is_string())
 					producers.push_back(edge["/node/name"_json_pointer].get<std::string>());
 
@@ -218,12 +226,13 @@
 	return id;
 }
 
-static int ParseListItem(const nlohmann::json& json) {
+static int ParseListItem(const nlohmann::json &json)
+{
 	int id = ParseMediaJson(json["/media"_json_pointer]);
 	if (!id)
 		return 0;
 
-	Anime::Anime& anime = Anime::db.items[id];
+	Anime::Anime &anime = Anime::db.items[id];
 
 	anime.AddToUserList();
 
@@ -240,47 +249,46 @@
 	return id;
 }
 
-static bool ParseList(const nlohmann::json& json) {
+static bool ParseList(const nlohmann::json &json)
+{
 	bool success = true;
 
-	for (const auto& entry : json["entries"].items())
+	for (const auto &entry : json["entries"].items())
 		if (!ParseListItem(entry.value()))
 			success = false;
 
 	return success;
 }
 
-int GetAnimeList() {
-	auto& auth = session.config.auth.anilist;
+int GetAnimeList()
+{
+	auto &auth = session.config.auth.anilist;
 
-	static constexpr std::string_view query =
-		"query ($id: Int) {\n"
-		"  MediaListCollection (userId: $id, type: ANIME) {\n"
-		"    lists {\n"
-		"      name\n"
-		"      entries {\n"
-		"        score\n"
-		"        notes\n"
-		"        status\n"
-		"        progress\n"
-		"        startedAt {\n"
-		"          year\n"
-		"          month\n"
-		"          day\n"
-		"        }\n"
-		"        completedAt {\n"
-		"          year\n"
-		"          month\n"
-		"          day\n"
-		"        }\n"
-		"        updatedAt\n"
-		"        media {\n"
-		MEDIA_FIELDS
-		"        }\n"
-		"      }\n"
-		"    }\n"
-		"  }\n"
-		"}\n";
+	static constexpr std::string_view query = "query ($id: Int) {\n"
+	                                          "  MediaListCollection (userId: $id, type: ANIME) {\n"
+	                                          "    lists {\n"
+	                                          "      name\n"
+	                                          "      entries {\n"
+	                                          "        score\n"
+	                                          "        notes\n"
+	                                          "        status\n"
+	                                          "        progress\n"
+	                                          "        startedAt {\n"
+	                                          "          year\n"
+	                                          "          month\n"
+	                                          "          day\n"
+	                                          "        }\n"
+	                                          "        completedAt {\n"
+	                                          "          year\n"
+	                                          "          month\n"
+	                                          "          day\n"
+	                                          "        }\n"
+	                                          "        updatedAt\n"
+	                                          "        media {\n" MEDIA_FIELDS "        }\n"
+	                                          "      }\n"
+	                                          "    }\n"
+	                                          "  }\n"
+	                                          "}\n";
 
 	// clang-format off
 	nlohmann::json request = {
@@ -299,11 +307,11 @@
 
 	Anime::db.RemoveAllUserData();
 
-	const nlohmann::json& json = response.value();
+	const nlohmann::json &json = response.value();
 
 	bool success = true;
 
-	for (const auto& list : json["data"]["MediaListCollection"]["lists"].items())
+	for (const auto &list : json["data"]["MediaListCollection"]["lists"].items())
 		if (!ParseList(list.value()))
 			success = false;
 
@@ -314,15 +322,13 @@
 }
 
 /* return is a vector of anime ids */
-std::vector<int> Search(const std::string& search) {
-	static constexpr std::string_view query =
-		"query ($search: String) {\n"
-		"  Page (page: 1, perPage: 50) {\n"
-		"    media (search: $search, type: ANIME) {\n"
-		MEDIA_FIELDS
-		"    }\n"
-		"  }\n"
-		"}\n";
+std::vector<int> Search(const std::string &search)
+{
+	static constexpr std::string_view query = "query ($search: String) {\n"
+	                                          "  Page (page: 1, perPage: 50) {\n"
+	                                          "    media (search: $search, type: ANIME) {\n" MEDIA_FIELDS "    }\n"
+	                                          "  }\n"
+	                                          "}\n";
 
 	// clang-format off
 	nlohmann::json json = {
@@ -337,55 +343,55 @@
 	if (!response)
 		return {};
 
-	const nlohmann::json& result = response.value();
+	const nlohmann::json &result = response.value();
 
 	/* FIXME: error handling here */
 	std::vector<int> ret;
 	ret.reserve(result["/data/Page/media"_json_pointer].size());
 
-	for (const auto& media : result["/data/Page/media"_json_pointer].items())
+	for (const auto &media : result["/data/Page/media"_json_pointer].items())
 		ret.push_back(ParseMediaJson(media.value()));
 
 	return ret;
 }
 
-bool GetSeason(Anime::Season season) {
+bool GetSeason(Anime::Season season)
+{
 	static constexpr std::string_view query =
-		"query ($season: MediaSeason!, $season_year: Int!, $page: Int) {\n"
-		"  Page(page: $page) {\n"
-		"    media(season: $season, seasonYear: $season_year, type: ANIME, sort: START_DATE) {\n"
-		MEDIA_FIELDS
-		"    }\n"
-		"    pageInfo {\n"
-		"      total\n"
-		"      perPage\n"
-		"      currentPage\n"
-		"      lastPage\n"
-		"      hasNextPage\n"
-		"    }\n"
-		"  }\n"
-		"}\n";
+	    "query ($season: MediaSeason!, $season_year: Int!, $page: Int) {\n"
+	    "  Page(page: $page) {\n"
+	    "    media(season: $season, seasonYear: $season_year, type: ANIME, sort: START_DATE) {\n" MEDIA_FIELDS "    }\n"
+	    "    pageInfo {\n"
+	    "      total\n"
+	    "      perPage\n"
+	    "      currentPage\n"
+	    "      lastPage\n"
+	    "      hasNextPage\n"
+	    "    }\n"
+	    "  }\n"
+	    "}\n";
 
 	int page = 0;
 	bool has_next_page = true;
 
 	while (has_next_page) {
 		nlohmann::json json = {
-			{"query", query},
-			{"variables", {
-				{"season", Translate::AniList::ToString(season.season)},
-				{"season_year", Strings::ToUtf8String(season.year)},
-				{"page", page},
-			}},
+		    {"query",     query},
+		    {"variables",
+		     {
+		         {"season", Translate::AniList::ToString(season.season)},
+		         {"season_year", Strings::ToUtf8String(season.year)},
+		         {"page", page},
+		     }		         },
 		};
 
 		const std::optional<nlohmann::json> res = SendJSONRequest(json);
 		if (!res)
 			return false;
 
-		const nlohmann::json& result = res.value();
+		const nlohmann::json &result = res.value();
 
-		for (const auto& media : result["/data/Page/media"_json_pointer].items())
+		for (const auto &media : result["/data/Page/media"_json_pointer].items())
 			ParseMediaJson(media.value());
 
 		has_next_page = JSON::GetBoolean(result, "/data/Page/pageInfo/hasNextPage"_json_pointer, false);
@@ -396,8 +402,9 @@
 	return true;
 }
 
-int UpdateAnimeEntry(int id) {
-	Anime::Anime& anime = Anime::db.items[id];
+int UpdateAnimeEntry(int id)
+{
+	Anime::Anime &anime = Anime::db.items[id];
 	if (!anime.IsInUserList())
 		return 0;
 
@@ -406,13 +413,13 @@
 		return 0;
 
 	static constexpr std::string_view query =
-		"mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, $score: Int, $notes: String,"
-		"     $start: FuzzyDateInput, $comp: FuzzyDateInput, $repeat: Int) {\n"
-		"  SaveMediaListEntry (mediaId: $media_id, progress: $progress, status: $status, scoreRaw: $score,"
-		"        notes: $notes, startedAt: $start, completedAt: $comp, repeat: $repeat) {\n"
-		"    id\n"
-		"  }\n"
-		"}\n";
+	    "mutation ($media_id: Int, $progress: Int, $status: MediaListStatus, $score: Int, $notes: String,"
+	    "     $start: FuzzyDateInput, $comp: FuzzyDateInput, $repeat: Int) {\n"
+	    "  SaveMediaListEntry (mediaId: $media_id, progress: $progress, status: $status, scoreRaw: $score,"
+	    "        notes: $notes, startedAt: $start, completedAt: $comp, repeat: $repeat) {\n"
+	    "    id\n"
+	    "  }\n"
+	    "}\n";
 	// clang-format off
 	nlohmann::json json = {
 		{"query", query},
@@ -433,30 +440,32 @@
 	if (!res)
 		return 0;
 
-	const nlohmann::json& result = res.value();
+	const nlohmann::json &result = res.value();
 
 	session.SetStatusBar(Strings::Translate("AniList: Anime entry updated successfully!"));
 
 	return JSON::GetNumber(result, "/data/SaveMediaListEntry/id"_json_pointer, 0);
 }
 
-static int ParseUser(const nlohmann::json& json) {
-	auto& auth = session.config.auth.anilist;
+static int ParseUser(const nlohmann::json &json)
+{
+	auto &auth = session.config.auth.anilist;
 
 	return auth.user_id = JSON::GetNumber(json, "/id"_json_pointer, 0);
 }
 
-bool AuthorizeUser() {
-	auto& auth = session.config.auth.anilist;
+bool AuthorizeUser()
+{
+	auto &auth = session.config.auth.anilist;
 
 	/* Prompt for PIN */
-	QDesktopServices::openUrl(QUrl(Strings::ToQString("https://anilist.co/api/v2/oauth/authorize?client_id=" +
-													  std::string(CLIENT_ID) + "&response_type=token")));
+	QDesktopServices::openUrl(QUrl(Strings::ToQString(
+	    "https://anilist.co/api/v2/oauth/authorize?client_id=" + std::string(CLIENT_ID) + "&response_type=token")));
 
 	bool ok;
 	QString token = QInputDialog::getText(
-		0, "Credentials needed!", "Please enter the code given to you after logging in to AniList:", QLineEdit::Normal,
-		"", &ok);
+	    0, "Credentials needed!", "Please enter the code given to you after logging in to AniList:", QLineEdit::Normal,
+	    "", &ok);
 
 	if (!ok || token.isEmpty())
 		return false;
@@ -465,29 +474,28 @@
 
 	session.SetStatusBar(Strings::Translate("AniList: Requesting user ID..."));
 
-	static constexpr std::string_view query =
-		"query {\n"
-		"  Viewer {\n"
-		"    id\n"
-		"  }\n"
-		"}\n";
+	static constexpr std::string_view query = "query {\n"
+	                                          "  Viewer {\n"
+	                                          "    id\n"
+	                                          "  }\n"
+	                                          "}\n";
 
 	nlohmann::json json = {
-		{"query", query}
-	};
+	    {"query", query}
+    };
 
 	/* SendJSONRequest handles status errors */
 	const std::optional<nlohmann::json> ret = SendJSONRequest(json);
 	if (!ret)
 		return 0;
 
-	const nlohmann::json& result = ret.value();
+	const nlohmann::json &result = ret.value();
 
 	if (ParseUser(result["data"]["Viewer"]))
 		session.SetStatusBar(Strings::Translate("AniList: Successfully retrieved user data!"));
 	else
 		session.SetStatusBar(Strings::Translate("AniList: Failed to retrieve user ID!"));
-	
+
 	return true;
 }