diff src/services/kitsu.cc @ 389:1e5d922fe82b

kitsu: implement UpdateAnimeEntry yay... i guess
author Paper <paper@tflc.us>
date Thu, 06 Nov 2025 12:21:35 -0500
parents 83aa0ddd1a46
children a72d6d7b3568
line wrap: on
line diff
--- a/src/services/kitsu.cc	Thu Nov 06 09:53:06 2025 -0500
+++ b/src/services/kitsu.cc	Thu Nov 06 12:21:35 2025 -0500
@@ -139,7 +139,9 @@
 /* ----------------------------------------------------------------------------- */
 
 static std::optional<nlohmann::json> SendJSONAPIRequest(const std::string &path,
-                                                        const std::map<std::string, std::string> &params = {})
+                                                        const std::map<std::string, std::string> &params = {},
+                                                        const std::string &data = "",
+                                                        HTTP::Type type = HTTP::Type::Get)
 {
 	std::optional<std::string> token = AccountAccessToken();
 	if (!token)
@@ -151,7 +153,7 @@
 
 	const std::string url = HTTP::EncodeParamsList(std::string(BASE_API_PATH) + path, params);
 
-	const std::string response = Strings::ToUtf8String(HTTP::Request(url, headers, "", HTTP::Type::Get));
+	const std::string response = Strings::ToUtf8String(HTTP::Request(url, headers, data, type));
 	if (response.empty())
 		return std::nullopt;
 
@@ -165,9 +167,12 @@
 	}
 
 	if (json.contains("/errors"_json_pointer)) {
+		std::cout << json["/errors"_json_pointer] << '\n';
+#if 0
 		for (const auto &item : json["/errors"])
 			std::cerr << "Kitsu: API returned error \"" << json["/errors/title"_json_pointer] << "\" with detail \""
 			          << json["/errors/detail"] << std::endl;
+#endif
 
 		session.SetStatusBar(Strings::Translate("Kitsu: Request failed with errors!"));
 		return std::nullopt;
@@ -608,9 +613,91 @@
 	return true;
 }
 
+static std::string UserStatusToString(Anime::ListStatus status)
+{
+	switch (status) {
+		case Anime::ListStatus::Planning: return "planned";
+		case Anime::ListStatus::Completed: return "completed";
+		case Anime::ListStatus::Dropped: return "dropped";
+		case Anime::ListStatus::Paused: return "on_hold";
+		default: break;
+	}
+
+	return "current";
+}
+
 int UpdateAnimeEntry(int id)
 {
-	return 0;
+	const Anime::Anime &anime = Anime::db.items[id];
+	int score;
+
+	if (!anime.IsInUserList())
+		return 0; /* WTF */
+
+	nlohmann::json json = {
+		{"data", {
+			{"type", "libraryEntries"},
+			{"attributes", {
+				{"status", UserStatusToString(anime.GetUserStatus())},
+				{"progress", anime.GetUserProgress()},
+				{"reconsuming", anime.GetUserIsRewatching()},
+				{"reconsumeCount", anime.GetUserRewatchedTimes()},
+				{"notes", anime.GetUserNotes()},
+				{"private", anime.GetUserIsPrivate()},
+				// WTF is reactionSkipped?
+				{"startedAt", anime.GetUserDateStarted().GetAsISO8601()},
+				{"finishedAt", anime.GetUserDateCompleted().GetAsISO8601()},
+			}},
+			{"relationships", {
+				{"anime", {
+					{"data", {
+						{"type", "anime"},
+						{"id", anime.GetServiceId(Anime::Service::Kitsu)},
+					}}
+				}},
+				{"user", {
+					{"data", {
+						{"type", "users"},
+						{"id", session.config.auth.kitsu.user_id},
+					}}
+				}}
+			}}
+		}}
+	};
+
+	nlohmann::json &attributes = json["data"]["attributes"];
+
+	score = anime.GetUserScore() / 5;
+	if (score > 0) {
+		attributes["ratingTwenty"] = score;
+	} else {
+		attributes["ratingTwenty"] = nullptr;
+	}
+
+	/* I really don't like this */
+	std::string uid = anime.GetUserId();
+
+	std::string path = "/library-entries";
+	HTTP::Type type;
+
+	if (!uid.empty()) {
+		json["data"]["id"] = uid;
+		path = path + "/" + uid;
+		type = HTTP::Type::Patch;
+	} else {
+		type = HTTP::Type::Post;
+	}
+
+	std::optional<nlohmann::json> res = SendJSONAPIRequest(path, {}, json.dump(), type);
+	if (!res)
+		return 0;
+
+	/* TODO parse result; can reduces races */
+
+	session.SetStatusBar(Strings::Translate("Kitsu: Anime entry updated successfully!"));
+
+	/* I guess? */
+	return Strings::ToInt<int>(anime.GetUserId());
 }
 
 bool AuthorizeUser(const std::string &email, const std::string &password)