diff --git a/chatterino.pro b/chatterino.pro index 875f98150..3416094ff 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -116,6 +116,7 @@ SOURCES += \ src/providers/twitch/pubsub.cpp \ src/providers/twitch/twitchemotes.cpp \ src/providers/bttv/bttvemotes.cpp \ + src/providers/ffz/ffzemotes.cpp \ src/singletons/commandmanager.cpp \ src/singletons/emotemanager.cpp \ src/singletons/fontmanager.cpp \ @@ -245,6 +246,7 @@ HEADERS += \ src/providers/twitch/pubsub.hpp \ src/providers/twitch/twitchemotes.hpp \ src/providers/bttv/bttvemotes.hpp \ + src/providers/ffz/ffzemotes.hpp \ src/singletons/commandmanager.hpp \ src/singletons/emotemanager.hpp \ src/singletons/fontmanager.hpp \ diff --git a/src/providers/ffz/ffzemotes.cpp b/src/providers/ffz/ffzemotes.cpp new file mode 100644 index 000000000..c60df5f82 --- /dev/null +++ b/src/providers/ffz/ffzemotes.cpp @@ -0,0 +1,146 @@ +#include "providers/ffz/ffzemotes.hpp" + +#include "debug/log.hpp" +#include "messages/image.hpp" +#include "util/urlfetch.hpp" + +namespace chatterino { +namespace providers { +namespace ffz { + +namespace { + +QString getEmoteLink(const QJsonObject &urls, const QString &emoteScale) +{ + auto emote = urls.value(emoteScale); + if (emote.isUndefined()) { + return ""; + } + + assert(emote.isString()); + + return "https:" + emote.toString(); +} + +void fillInEmoteData(const QJsonObject &urls, const QString &code, const QString &tooltip, + util::EmoteData &emoteData) +{ + QString url1x = getEmoteLink(urls, "1"); + QString url2x = getEmoteLink(urls, "2"); + QString url3x = getEmoteLink(urls, "4"); + + assert(!url1x.isEmpty()); + + emoteData.image1x = new messages::Image(url1x, 1, code, tooltip); + + if (!url2x.isEmpty()) { + emoteData.image2x = new messages::Image(url2x, 0.5, code, tooltip); + } + + if (!url3x.isEmpty()) { + emoteData.image3x = new messages::Image(url3x, 0.25, code, tooltip); + } +} + +} // namespace + +void FFZEmotes::loadChannelEmotes(const QString &channelName, std::weak_ptr _map) +{ + printf("[FFZEmotes] Reload FFZ Channel Emotes for channel %s\n", qPrintable(channelName)); + + QString url("https://api.frankerfacez.com/v1/room/" + channelName); + + util::NetworkRequest req(url); + req.setCaller(QThread::currentThread()); + req.setTimeout(3000); + req.getJSON([this, channelName, _map](QJsonObject &rootNode) { + auto map = _map.lock(); + + if (_map.expired()) { + return; + } + + map->clear(); + + auto setsNode = rootNode.value("sets").toObject(); + + std::vector codes; + for (const QJsonValue &setNode : setsNode) { + auto emotesNode = setNode.toObject().value("emoticons").toArray(); + + for (const QJsonValue &emoteNode : emotesNode) { + QJsonObject emoteObject = emoteNode.toObject(); + + // margins + int id = emoteObject.value("id").toInt(); + QString code = emoteObject.value("name").toString(); + + QJsonObject urls = emoteObject.value("urls").toObject(); + + auto emote = this->getChannelEmoteFromCaches().getOrAdd(id, [id, &code, &urls] { + util::EmoteData emoteData; + fillInEmoteData(urls, code, code + "
Channel FFZ Emote", emoteData); + emoteData.pageLink = + QString("https://www.frankerfacez.com/emoticon/%1-%2").arg(id).arg(code); + + return emoteData; + }); + + this->channelEmotes.insert(code, emote); + map->insert(code, emote); + codes.push_back(code.toStdString()); + } + + this->channelEmoteCodes[channelName.toStdString()] = codes; + } + }); +} + +util::EmoteMap &FFZEmotes::getEmotes() +{ + return this->globalEmotes; +} + +util::ConcurrentMap &FFZEmotes::getChannelEmoteFromCaches() +{ + return this->_channelEmoteFromCaches; +} + +void FFZEmotes::loadGlobalEmotes() +{ + QString url("https://api.frankerfacez.com/v1/set/global"); + + util::NetworkRequest req(url); + req.setCaller(QThread::currentThread()); + req.setTimeout(30000); + req.getJSON([this](QJsonObject &root) { + auto sets = root.value("sets").toObject(); + + std::vector codes; + for (const QJsonValue &set : sets) { + auto emoticons = set.toObject().value("emoticons").toArray(); + + for (const QJsonValue &emote : emoticons) { + QJsonObject object = emote.toObject(); + + QString code = object.value("name").toString(); + int id = object.value("id").toInt(); + QJsonObject urls = object.value("urls").toObject(); + + util::EmoteData emoteData; + fillInEmoteData(urls, code, code + "
Global FFZ Emote", emoteData); + emoteData.pageLink = + QString("https://www.frankerfacez.com/emoticon/%1-%2").arg(id).arg(code); + + this->globalEmotes.insert(code, emoteData); + codes.push_back(code.toStdString()); + } + + this->globalEmoteCodes = codes; + } + }); +} + +} // namespace ffz +} // namespace providers +} // namespace chatterino diff --git a/src/providers/ffz/ffzemotes.hpp b/src/providers/ffz/ffzemotes.hpp new file mode 100644 index 000000000..d1e71cae9 --- /dev/null +++ b/src/providers/ffz/ffzemotes.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include "signalvector.hpp" +#include "util/concurrentmap.hpp" +#include "util/emotemap.hpp" + +#include + +namespace chatterino { +namespace providers { +namespace ffz { + +class FFZEmotes +{ +public: + util::EmoteMap globalEmotes; + SignalVector globalEmoteCodes; + + util::EmoteMap channelEmotes; + std::map> channelEmoteCodes; + + void loadGlobalEmotes(); + + void loadChannelEmotes(const QString &channelName, + std::weak_ptr channelEmoteMap); + + util::EmoteMap &getEmotes(); + util::ConcurrentMap &getChannelEmoteFromCaches(); + + util::ConcurrentMap channels; + +private: + util::ConcurrentMap _channelEmoteFromCaches; +}; + +} // namespace ffz +} // namespace providers +} // namespace chatterino diff --git a/src/providers/twitch/twitchchannel.cpp b/src/providers/twitch/twitchchannel.cpp index 64bd943ad..a5fce4e8f 100644 --- a/src/providers/twitch/twitchchannel.cpp +++ b/src/providers/twitch/twitchchannel.cpp @@ -141,7 +141,7 @@ void TwitchChannel::reloadChannelEmotes() debug::Log("[TwitchChannel:{}] Reloading channel emotes", this->name); app->emotes->bttv.loadChannelEmotes(this->name, this->bttvChannelEmotes); - app->emotes->reloadFFZChannelEmotes(this->name, this->ffzChannelEmotes); + app->emotes->ffz.loadChannelEmotes(this->name, this->ffzChannelEmotes); } void TwitchChannel::sendMessage(const QString &message) diff --git a/src/providers/twitch/twitchmessagebuilder.cpp b/src/providers/twitch/twitchmessagebuilder.cpp index 8e81741cf..566868745 100644 --- a/src/providers/twitch/twitchmessagebuilder.cpp +++ b/src/providers/twitch/twitchmessagebuilder.cpp @@ -538,7 +538,7 @@ bool TwitchMessageBuilder::tryAppendEmote(QString &emoteString) this->twitchChannel->bttvChannelEmotes->tryGet(emoteString, emoteData)) { // BTTV Channel Emote return appendEmote(MessageElement::BttvEmote); - } else if (app->emotes->ffzGlobalEmotes.tryGet(emoteString, emoteData)) { + } else if (app->emotes->ffz.globalEmotes.tryGet(emoteString, emoteData)) { // FFZ Global Emote return appendEmote(MessageElement::FfzEmote); } else if (this->twitchChannel != nullptr && diff --git a/src/singletons/emotemanager.cpp b/src/singletons/emotemanager.cpp index 29d859034..d34f44ddd 100644 --- a/src/singletons/emotemanager.cpp +++ b/src/singletons/emotemanager.cpp @@ -24,42 +24,6 @@ using namespace chatterino::messages; namespace chatterino { namespace singletons { -namespace { - -QString GetFFZEmoteLink(const QJsonObject &urls, const QString &emoteScale) -{ - auto emote = urls.value(emoteScale); - if (emote.isUndefined()) { - return ""; - } - - assert(emote.isString()); - - return "https:" + emote.toString(); -} - -void FillInFFZEmoteData(const QJsonObject &urls, const QString &code, const QString &tooltip, - util::EmoteData &emoteData) -{ - QString url1x = GetFFZEmoteLink(urls, "1"); - QString url2x = GetFFZEmoteLink(urls, "2"); - QString url3x = GetFFZEmoteLink(urls, "4"); - - assert(!url1x.isEmpty()); - - emoteData.image1x = new Image(url1x, 1, code, tooltip); - - if (!url2x.isEmpty()) { - emoteData.image2x = new Image(url2x, 0.5, code, tooltip); - } - - if (!url3x.isEmpty()) { - emoteData.image3x = new Image(url3x, 0.25, code, tooltip); - } -} - -} // namespace - EmoteManager::EmoteManager() : findShortCodesRegex(":([-+\\w]+):") { @@ -76,65 +40,7 @@ void EmoteManager::initialize() this->loadEmojis(); this->bttv.loadGlobalEmotes(); - this->loadFFZEmotes(); -} - -void EmoteManager::reloadFFZChannelEmotes(const QString &channelName, - std::weak_ptr _map) -{ - printf("[EmoteManager] Reload FFZ Channel Emotes for channel %s\n", qPrintable(channelName)); - - QString url("https://api.frankerfacez.com/v1/room/" + channelName); - - util::NetworkRequest req(url); - req.setCaller(QThread::currentThread()); - req.setTimeout(3000); - req.getJSON([this, channelName, _map](QJsonObject &rootNode) { - auto map = _map.lock(); - - if (_map.expired()) { - return; - } - - map->clear(); - - auto setsNode = rootNode.value("sets").toObject(); - - std::vector codes; - for (const QJsonValue &setNode : setsNode) { - auto emotesNode = setNode.toObject().value("emoticons").toArray(); - - for (const QJsonValue &emoteNode : emotesNode) { - QJsonObject emoteObject = emoteNode.toObject(); - - // margins - int id = emoteObject.value("id").toInt(); - QString code = emoteObject.value("name").toString(); - - QJsonObject urls = emoteObject.value("urls").toObject(); - - auto emote = this->getFFZChannelEmoteFromCaches().getOrAdd(id, [id, &code, &urls] { - util::EmoteData emoteData; - FillInFFZEmoteData(urls, code, code + "
Channel FFZ Emote", emoteData); - emoteData.pageLink = - QString("https://www.frankerfacez.com/emoticon/%1-%2").arg(id).arg(code); - - return emoteData; - }); - - this->ffzChannelEmotes.insert(code, emote); - map->insert(code, emote); - codes.push_back(code.toStdString()); - } - - this->ffzChannelEmoteCodes[channelName.toStdString()] = codes; - } - }); -} - -util::EmoteMap &EmoteManager::getFFZEmotes() -{ - return ffzGlobalEmotes; + this->ffz.loadGlobalEmotes(); } util::EmoteMap &EmoteManager::getChatterinoEmotes() @@ -147,11 +53,6 @@ util::EmojiMap &EmoteManager::getEmojis() return this->emojis; } -util::ConcurrentMap &EmoteManager::getFFZChannelEmoteFromCaches() -{ - return _ffzChannelEmoteFromCaches; -} - void EmoteManager::loadEmojis() { QFile file(":/emojidata.txt"); @@ -327,41 +228,6 @@ QString EmoteManager::replaceShortCodes(const QString &text) return ret; } -void EmoteManager::loadFFZEmotes() -{ - QString url("https://api.frankerfacez.com/v1/set/global"); - - util::NetworkRequest req(url); - req.setCaller(QThread::currentThread()); - req.setTimeout(30000); - req.getJSON([this](QJsonObject &root) { - auto sets = root.value("sets").toObject(); - - std::vector codes; - for (const QJsonValue &set : sets) { - auto emoticons = set.toObject().value("emoticons").toArray(); - - for (const QJsonValue &emote : emoticons) { - QJsonObject object = emote.toObject(); - - QString code = object.value("name").toString(); - int id = object.value("id").toInt(); - QJsonObject urls = object.value("urls").toObject(); - - util::EmoteData emoteData; - FillInFFZEmoteData(urls, code, code + "
Global FFZ Emote", emoteData); - emoteData.pageLink = - QString("https://www.frankerfacez.com/emoticon/%1-%2").arg(id).arg(code); - - this->ffzGlobalEmotes.insert(code, emoteData); - codes.push_back(code.toStdString()); - } - - this->ffzGlobalEmoteCodes = codes; - } - }); -} - util::EmoteData EmoteManager::getCheerImage(long long amount, bool animated) { // TODO: fix this xD diff --git a/src/singletons/emotemanager.hpp b/src/singletons/emotemanager.hpp index c7686e577..bb2354dfd 100644 --- a/src/singletons/emotemanager.hpp +++ b/src/singletons/emotemanager.hpp @@ -5,6 +5,7 @@ #include "emojis.hpp" #include "messages/image.hpp" #include "providers/bttv/bttvemotes.hpp" +#include "providers/ffz/ffzemotes.hpp" #include "providers/twitch/twitchemotes.hpp" #include "signalvector.hpp" #include "util/concurrentmap.hpp" @@ -29,16 +30,12 @@ public: providers::twitch::TwitchEmotes twitch; providers::bttv::BTTVEmotes bttv; + providers::ffz::FFZEmotes ffz; void initialize(); - void reloadFFZChannelEmotes(const QString &channelName, - std::weak_ptr channelEmoteMap); - - util::EmoteMap &getFFZEmotes(); util::EmoteMap &getChatterinoEmotes(); util::EmojiMap &getEmojis(); - util::ConcurrentMap &getFFZChannelEmoteFromCaches(); util::EmoteData getCheerImage(long long int amount, bool animated); @@ -69,20 +66,6 @@ public: std::vector emojiShortCodes; - /// FFZ emotes - util::EmoteMap ffzChannelEmotes; - -public: - util::ConcurrentMap ffzChannels; - util::EmoteMap ffzGlobalEmotes; - SignalVector ffzGlobalEmoteCodes; - std::map> ffzChannelEmoteCodes; - -private: - util::ConcurrentMap _ffzChannelEmoteFromCaches; - - void loadFFZEmotes(); - /// Chatterino emotes util::EmoteMap _chatterinoEmotes; diff --git a/src/util/completionmodel.cpp b/src/util/completionmodel.cpp index f3c3b4735..25b30f6c8 100644 --- a/src/util/completionmodel.cpp +++ b/src/util/completionmodel.cpp @@ -38,7 +38,7 @@ void CompletionModel::refresh() } // Global: FFZ Global Emotes - std::vector &ffzGlobalEmoteCodes = app->emotes->ffzGlobalEmoteCodes; + std::vector &ffzGlobalEmoteCodes = app->emotes->ffz.globalEmoteCodes; for (const auto &m : ffzGlobalEmoteCodes) { this->addString(m, TaggedString::Type::FFZGlobalEmote); } @@ -52,7 +52,7 @@ void CompletionModel::refresh() // Channel-specific: FFZ Channel Emotes std::vector &ffzChannelEmoteCodes = - app->emotes->ffzChannelEmoteCodes[this->channelName.toStdString()]; + app->emotes->ffz.channelEmoteCodes[this->channelName.toStdString()]; for (const auto &m : ffzChannelEmoteCodes) { this->addString(m, TaggedString::Type::FFZChannelEmote); } diff --git a/src/widgets/emotepopup.cpp b/src/widgets/emotepopup.cpp index 8cca4121e..d521521c0 100644 --- a/src/widgets/emotepopup.cpp +++ b/src/widgets/emotepopup.cpp @@ -117,7 +117,7 @@ void EmotePopup::loadChannel(ChannelPtr _channel) addEmotes(app->emotes->bttv.globalEmotes, "BetterTTV Global Emotes", "BetterTTV Global Emote"); addEmotes(*channel->bttvChannelEmotes.get(), "BetterTTV Channel Emotes", "BetterTTV Channel Emote"); - addEmotes(app->emotes->ffzGlobalEmotes, "FrankerFaceZ Global Emotes", + addEmotes(app->emotes->ffz.globalEmotes, "FrankerFaceZ Global Emotes", "FrankerFaceZ Global Emote"); addEmotes(*channel->ffzChannelEmotes.get(), "FrankerFaceZ Channel Emotes", "FrankerFaceZ Channel Emote");