#ifdef BUILD_BETTERTTV #include "emotespp/betterttv.hpp" #include #include #include #include #include #include #include "emotespp/emotes.hpp" namespace emotespp { BetterTTVWebsocketClient::BetterTTVWebsocketClient() { this->websocket.setUrl("wss://sockets.betterttv.net/ws"); 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); std::string name = j["name"]; nlohmann::json d = j["data"]; std::string channel = d["channel"]; std::vector &cache = this->ids.at(channel); if (name == "emote_create") { nlohmann::json e = d["emote"]; Emote emote{e["id"], e["code"], std::nullopt}; cache.push_back(emote); if (this->emote_create.has_value()) { this->emote_create.value()(channel, std::nullopt, emote); } } else if (name == "emote_update") { nlohmann::json e = d["emote"]; Emote emote{e["id"], e["code"], std::nullopt}; auto cache_e = std::find_if( cache.begin(), cache.end(), [&emote](const Emote &e) { return emote.id == e.id; }); if (cache_e != cache.end()) { emote.original_code = cache_e->code; cache_e->code = emote.code; } else { cache.push_back(emote); } if (this->emote_update.has_value()) { this->emote_update.value()(channel, std::nullopt, emote); } } else if (name == "emote_delete") { std::string emote_id = d["emoteId"]; Emote emote{emote_id, "-", std::nullopt}; auto cache_e = std::find_if( cache.begin(), cache.end(), [&emote](const Emote &e) { return emote.id == e.id; }); if (cache_e != cache.end()) { emote.code = cache_e->code; emote.original_code = cache_e->original_code; cache.erase(cache_e); } if (this->emote_delete.has_value()) { this->emote_delete.value()(channel, std::nullopt, emote); } } break; } case ix::WebSocketMessageType::Error: case ix::WebSocketMessageType::Close: { this->is_connected = false; break; } case ix::WebSocketMessageType::Open: { this->is_connected = true; std::for_each(this->ids.begin(), this->ids.end(), [this](const auto &pair) { this->subscribe_emote_set(pair.first); }); break; } case ix::WebSocketMessageType::Ping: case ix::WebSocketMessageType::Pong: case ix::WebSocketMessageType::Fragment: break; } }); } void BetterTTVWebsocketClient::subscribe_emote_set( const std::string &emote_set_id) { if (!std::any_of(this->ids.begin(), this->ids.end(), [&emote_set_id](const auto &pair) { return pair.first == emote_set_id; })) { this->ids.insert({emote_set_id, {}}); } if (this->is_connected) { nlohmann::json j; j["name"] = "join_channel"; nlohmann::json d; d["name"] = emote_set_id; j["data"] = d; this->websocket.sendUtf8Text(j.dump()); } } void BetterTTVWebsocketClient::unsubscribe_emote_set( const std::string &emote_set_id) { if (this->is_connected) { nlohmann::json j; j["name"] = "part_channel"; nlohmann::json d; d["name"] = emote_set_id; j["data"] = d; this->websocket.sendUtf8Text(j.dump()); } auto it = std::find_if(this->ids.begin(), this->ids.end(), [&emote_set_id](const auto &pair) { return pair.first == emote_set_id; }); if (it != this->ids.end()) { this->ids.erase(it); } } void BetterTTVWebsocketClient::start() { this->websocket.start(); } const std::map> & BetterTTVWebsocketClient::get_ids() const { return this->ids; } Emote BetterTTVAPIClient::parse_emote(const nlohmann::json &value) const { return {value["id"], value["code"], std::nullopt}; } } #endif