summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormoderndevslulw <moderndevslulw@alright.party>2025-04-04 14:30:36 +0500
committermoderndevslulw <moderndevslulw@alright.party>2025-04-04 14:30:36 +0500
commita44fc682a5f2eb54dfac6705ff21d0778639af6a (patch)
treea7b3d624bf89ed5b05a6890a00c40e22d9445b45
parentb19cee38da6bcdbaa8cd3a4115c0f24e7dadc9cd (diff)
feat: 7TV API client
-rw-r--r--include/emotespp/emotes.hpp9
-rw-r--r--include/emotespp/seventv.hpp62
-rw-r--r--src/seventv.cpp93
3 files changed, 164 insertions, 0 deletions
diff --git a/include/emotespp/emotes.hpp b/include/emotespp/emotes.hpp
index 5a5e172..4f08f39 100644
--- a/include/emotespp/emotes.hpp
+++ b/include/emotespp/emotes.hpp
@@ -3,6 +3,7 @@
#include <functional>
#include <optional>
#include <string>
+#include <vector>
namespace emotespp {
struct Emote {
@@ -45,4 +46,12 @@ namespace emotespp {
std::function<void(std::string, std::optional<std::string>, T)>>
emote_update;
};
+
+ template <typename T>
+ class RetrieveEmoteAPI {
+ public:
+ virtual std::vector<T> get_channel_emotes(
+ std::string &channel_id) const = 0;
+ virtual std::vector<T> get_global_emotes() const = 0;
+ };
} \ No newline at end of file
diff --git a/include/emotespp/seventv.hpp b/include/emotespp/seventv.hpp
index cce8ae7..77db912 100644
--- a/include/emotespp/seventv.hpp
+++ b/include/emotespp/seventv.hpp
@@ -1,9 +1,12 @@
#pragma once
#include <nlohmann/json.hpp>
+#include <optional>
+#include <stdexcept>
#include <string>
#include <vector>
+#include "cpr/cpr.h"
#include "emotespp/emotes.hpp"
#include "ixwebsocket/IXWebSocket.h"
@@ -25,4 +28,63 @@ namespace emotespp {
bool is_connected = false;
};
+
+ struct User {
+ std::string alias_id, id, username, emote_set_id;
+ };
+
+ struct EmoteSet {
+ std::string id, name;
+ User owner;
+ std::vector<Emote> emotes;
+ };
+
+ class SevenTVAPIClient : public RetrieveEmoteAPI<Emote> {
+ public:
+ SevenTVAPIClient() = default;
+ ~SevenTVAPIClient() = default;
+
+ std::vector<Emote> get_channel_emotes(
+ std::string &channel_id) const override {
+ cpr::Response r =
+ cpr::Get(cpr::Url{base_url + "/users/twitch/" + channel_id});
+
+ if (r.status_code != 200) {
+ throw std::runtime_error(
+ "Failed to get channel emotes. Status code: " +
+ std::to_string(r.status_code));
+ }
+
+ nlohmann::json j = nlohmann::json::parse(r.text);
+ nlohmann::json set = j["emote_set"];
+
+ return this->parse_emoteset(set);
+ }
+
+ std::vector<Emote> get_global_emotes() const override {
+ cpr::Response r = cpr::Get(cpr::Url{base_url + "/emote-sets/global"});
+
+ if (r.status_code != 200) {
+ throw std::runtime_error(
+ "Failed to get global emotes. Status code: " +
+ std::to_string(r.status_code));
+ }
+
+ nlohmann::json j = nlohmann::json::parse(r.text);
+
+ return this->parse_emoteset(j);
+ }
+
+ std::optional<User> get_user_by_twitch_id(
+ const unsigned int &twitch_id) const;
+ std::optional<User> get_user(const std::string &id) const;
+ std::optional<EmoteSet> get_emote_set(
+ const std::string &emote_set_id) const;
+
+ private:
+ std::vector<Emote> parse_emoteset(const nlohmann::json &value) const;
+ std::optional<User> parse_user(const nlohmann::json &value) const;
+
+ const std::string base_url = "https://7tv.io/v3";
+ };
} \ No newline at end of file
diff --git a/src/seventv.cpp b/src/seventv.cpp
index 51c306c..62ea550 100644
--- a/src/seventv.cpp
+++ b/src/seventv.cpp
@@ -3,6 +3,7 @@
#include <algorithm>
#include <nlohmann/json.hpp>
#include <optional>
+#include <string>
namespace emotespp {
SevenTVWebsocketClient::SevenTVWebsocketClient() {
@@ -162,4 +163,96 @@ namespace emotespp {
return {id, code, original_code};
}
+
+ std::vector<Emote> SevenTVAPIClient::parse_emoteset(
+ const nlohmann::json &value) const {
+ std::vector<Emote> emotes;
+
+ nlohmann::json e = value["emotes"];
+
+ for (const nlohmann::json v : e) {
+ std::string id = v["id"];
+ std::string code = v["name"];
+ std::optional<std::string> original_code = v["data"]["name"];
+
+ if (code == original_code) {
+ original_code = std::nullopt;
+ }
+
+ emotes.push_back({id, code, original_code});
+ }
+
+ return emotes;
+ }
+
+ std::optional<User> SevenTVAPIClient::get_user_by_twitch_id(
+ const unsigned int &twitch_id) const {
+ cpr::Response r = cpr::Get(cpr::Url{this->base_url + "/users/twitch/" +
+ std::to_string(twitch_id)});
+
+ if (r.status_code != 200) {
+ return std::nullopt;
+ }
+
+ nlohmann::json j = nlohmann::json::parse(r.text);
+
+ std::string alias_id = j["id"];
+ std::string username = j["username"];
+ std::string emote_set_id = j["emote_set_id"];
+ std::string id = j["user"]["id"];
+
+ return (User){alias_id, id, username, emote_set_id};
+ }
+
+ std::optional<User> SevenTVAPIClient::get_user(const std::string &id) const {
+ cpr::Response r = cpr::Get(cpr::Url{this->base_url + "/users/" + id});
+
+ if (r.status_code != 200) {
+ return std::nullopt;
+ }
+
+ nlohmann::json j = nlohmann::json::parse(r.text);
+
+ return this->parse_user(j);
+ }
+
+ std::optional<EmoteSet> SevenTVAPIClient::get_emote_set(
+ const std::string &emote_set_id) const {
+ cpr::Response r =
+ cpr::Get(cpr::Url{this->base_url + "/emote-sets/" + emote_set_id});
+
+ if (r.status_code != 200) {
+ return std::nullopt;
+ }
+
+ nlohmann::json j = nlohmann::json::parse(r.text);
+
+ std::string id = j["id"];
+ std::string name = j["name"];
+ std::optional<User> owner = this->parse_user(j["owner"]);
+
+ if (!owner.has_value()) {
+ return std::nullopt;
+ }
+
+ return (EmoteSet){id, name, owner.value(), this->parse_emoteset(j)};
+ }
+
+ std::optional<User> SevenTVAPIClient::parse_user(
+ const nlohmann::json &value) const {
+ std::string id = value["id"];
+
+ nlohmann::json conns = value["connections"];
+ auto twitchconn = std::find_if(
+ conns.begin(), conns.end(),
+ [](const nlohmann::json &x) { return x["platform"] == "TWITCH"; });
+
+ if (twitchconn == conns.end()) {
+ return std::nullopt;
+ }
+
+ nlohmann::json c = *twitchconn;
+
+ return (User){c["id"], id, c["username"], c["emote_set_id"]};
+ }
} \ No newline at end of file