#include "emotespp/seventv.hpp" #include #include #include namespace emotespp { 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(); // 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 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 original_code = data["data"]["name"]; if (code == original_code) { original_code = std::nullopt; } return {id, code, original_code}; } }