diff options
| author | moderndevslulw <moderndevslulw@alright.party> | 2025-04-04 01:12:56 +0500 |
|---|---|---|
| committer | moderndevslulw <moderndevslulw@alright.party> | 2025-04-04 01:12:56 +0500 |
| commit | b19cee38da6bcdbaa8cd3a4115c0f24e7dadc9cd (patch) | |
| tree | bab265f888a37838607eb688924fb87640ef26ab | |
| parent | ee132dc6c326708706e0c88ba234a90aec7ee936 (diff) | |
feat: 7TV websocket client
| -rw-r--r-- | include/emotespp/seventv.hpp | 25 | ||||
| -rw-r--r-- | src/seventv.cpp | 162 |
2 files changed, 184 insertions, 3 deletions
diff --git a/include/emotespp/seventv.hpp b/include/emotespp/seventv.hpp index 8a4149d..cce8ae7 100644 --- a/include/emotespp/seventv.hpp +++ b/include/emotespp/seventv.hpp @@ -1,7 +1,28 @@ #pragma once +#include <nlohmann/json.hpp> +#include <string> +#include <vector> + +#include "emotespp/emotes.hpp" +#include "ixwebsocket/IXWebSocket.h" + namespace emotespp { - class SevenTVEmoteListener { - SevenTVEmoteListener(); + class SevenTVWebsocketClient : public RetrieveEmoteWebsocket<Emote> { + public: + SevenTVWebsocketClient(); + + void subscribe_emote_set(const std::string &emote_set_id); + void unsubscribe_emote_set(const std::string &emote_set_id); + + void start(); + + private: + Emote create_emote(const nlohmann::json &data); + + std::vector<std::string> ids; + ix::WebSocket websocket; + + bool is_connected = false; }; }
\ No newline at end of file diff --git a/src/seventv.cpp b/src/seventv.cpp index 1fae55e..51c306c 100644 --- a/src/seventv.cpp +++ b/src/seventv.cpp @@ -1,5 +1,165 @@ #include "emotespp/seventv.hpp" +#include <algorithm> +#include <nlohmann/json.hpp> +#include <optional> + namespace emotespp { - SevenTVEmoteListener::SevenTVEmoteListener() {} + SevenTVWebsocketClient::SevenTVWebsocketClient() { + this->websocket.setUrl("wss://events.7tv.io/v3"); + this->websocket.enableAutomaticReconnection(); + + this->websocket.setOnMessageCallback( + [this](const ix::WebSocketMessagePtr &msg) { + switch (msg->type) { + case ix::WebSocketMessageType::Message: { + nlohmann::json j = nlohmann::json::parse(msg->str); + + int opcode = j["op"].get<int>(); + + // hello opcode + if (opcode == 1) { + this->is_connected = true; + std::for_each(this->ids.begin(), this->ids.end(), + [this](const std::string &id) { + this->subscribe_emote_set(id); + }); + return; + } else if (opcode != 0) { + return; + } + + nlohmann::json data = j["d"]; + + std::string type = data["type"]; + if (type != "emote_set.update") { + return; + } + + data = data["body"]; + + std::string channel_id = data["id"]; + + nlohmann::json actor = data["actor"]; + std::string actor_id = actor["id"]; + + if (data.contains("pushed") && this->emote_create.has_value()) { + for (const nlohmann::json &d : data["pushed"]) { + nlohmann::json emote = d["value"]; + this->emote_create.value()(channel_id, actor_id, + this->create_emote(emote)); + } + } + + if (data.contains("pulled") && this->emote_delete.has_value()) { + for (const nlohmann::json &d : data["pulled"]) { + nlohmann::json emote = d["old_value"]; + this->emote_delete.value()(channel_id, actor_id, + this->create_emote(emote)); + } + } + + if (data.contains("updated") && this->emote_update.has_value()) { + for (const nlohmann::json &d : data["updated"]) { + nlohmann::json old_emote = d["old_value"]; + nlohmann::json emote = d["value"]; + + std::string id = old_emote["id"]; + std::string code = emote["name"]; + + std::optional<std::string> original_code = old_emote["name"]; + if (code == original_code) { + original_code = std::nullopt; + } + + Emote emote_data{id, code, original_code}; + + this->emote_update.value()(channel_id, actor_id, emote_data); + } + } + + break; + } + case ix::WebSocketMessageType::Close: + case ix::WebSocketMessageType::Error: { + this->is_connected = false; + break; + } + case ix::WebSocketMessageType::Open: + case ix::WebSocketMessageType::Ping: + case ix::WebSocketMessageType::Pong: + case ix::WebSocketMessageType::Fragment: + break; + } + }); + } + + void SevenTVWebsocketClient::subscribe_emote_set( + const std::string &emote_set_id) { + if (!std::any_of(this->ids.begin(), this->ids.end(), + [&emote_set_id](const std::string &id) { + return id == emote_set_id; + })) { + this->ids.push_back(emote_set_id); + } + + if (this->is_connected) { + nlohmann::json j; + j["op"] = 35; + + nlohmann::json d; + + nlohmann::json c; + c["object_id"] = emote_set_id; + + d["type"] = "emote_set.update"; + d["condition"] = c; + + j["d"] = d; + + this->websocket.sendUtf8Text(j.dump()); + } + } + + void SevenTVWebsocketClient::unsubscribe_emote_set( + const std::string &emote_set_id) { + if (this->is_connected) { + nlohmann::json j; + j["op"] = 36; + + nlohmann::json d; + + nlohmann::json c; + c["object_id"] = emote_set_id; + + d["type"] = "emote_set.update"; + d["condition"] = c; + + j["d"] = d; + + this->websocket.sendUtf8Text(j.dump()); + } + + auto it = std::find_if( + this->ids.begin(), this->ids.end(), + [&emote_set_id](const std::string &x) { return x == emote_set_id; }); + + if (it != this->ids.end()) { + this->ids.erase(it); + } + } + + void SevenTVWebsocketClient::start() { this->websocket.start(); } + + Emote SevenTVWebsocketClient::create_emote(const nlohmann::json &data) { + std::string id = data["id"]; + std::string code = data["name"]; + std::optional<std::string> original_code = data["data"]["name"]; + + if (code == original_code) { + original_code = std::nullopt; + } + + return {id, code, original_code}; + } }
\ No newline at end of file |
