Refactor ConcurrentMap

* Add operator[] to ConcurrentMap which returns a TValue reference
* BTTV/FFZ channel emotes are now stored in the Emote Manager, and each Channel object has a reference to their own BTTV/FFZ channel emote map.
* Restructure EmoteManager a bit (simplify the ConcurrentMap havoc).
* Add EmoteData struct which can store emote data (for now only messages::LazyLoadedImage*)
* Add CompletionManager that does nothing
This commit is contained in:
Rasmus Karlsson 2017-07-09 17:58:59 +02:00
parent 1f1b0d7f03
commit 5aa892e834
11 changed files with 239 additions and 139 deletions

View file

@ -95,7 +95,8 @@ SOURCES += \
src/widgets/accountpopup.cpp \ src/widgets/accountpopup.cpp \
src/messagefactory.cpp \ src/messagefactory.cpp \
src/widgets/basewidget.cpp \ src/widgets/basewidget.cpp \
src/widgets/resizingtextedit.cpp src/widgets/resizingtextedit.cpp \
src/completionmanager.cpp
HEADERS += \ HEADERS += \
src/asyncexec.hpp \ src/asyncexec.hpp \
@ -155,7 +156,8 @@ HEADERS += \
src/widgets/accountpopup.hpp \ src/widgets/accountpopup.hpp \
src/util/distancebetweenpoints.hpp \ src/util/distancebetweenpoints.hpp \
src/messagefactory.hpp \ src/messagefactory.hpp \
src/widgets/basewidget.hpp src/widgets/basewidget.hpp \
src/completionmanager.hpp
PRECOMPILED_HEADER = PRECOMPILED_HEADER =

View file

@ -7,6 +7,7 @@
#include "messagefactory.hpp" #include "messagefactory.hpp"
#include "resources.hpp" #include "resources.hpp"
#include "windowmanager.hpp" #include "windowmanager.hpp"
#include "completionmanager.hpp"
#include <QApplication> #include <QApplication>
@ -20,6 +21,7 @@ public:
int run(QApplication &qtApp); int run(QApplication &qtApp);
CompletionManager completionManager;
WindowManager windowManager; WindowManager windowManager;
ColorScheme colorScheme; ColorScheme colorScheme;
EmoteManager emoteManager; EmoteManager emoteManager;

View file

@ -26,6 +26,8 @@ Channel::Channel(WindowManager &_windowManager, EmoteManager &_emoteManager,
, emoteManager(_emoteManager) , emoteManager(_emoteManager)
, ircManager(_ircManager) , ircManager(_ircManager)
, _name((channel.length() > 0 && channel[0] == '#') ? channel.mid(1) : channel) , _name((channel.length() > 0 && channel[0] == '#') ? channel.mid(1) : channel)
, bttvChannelEmotes(this->emoteManager.bttvChannels[channel])
, ffzChannelEmotes(this->emoteManager.ffzChannels[channel])
, _subLink("https://www.twitch.tv/" + _name + "/subscribe?ref=in_chat_subscriber_link") , _subLink("https://www.twitch.tv/" + _name + "/subscribe?ref=in_chat_subscriber_link")
, _channelLink("https://twitch.tv/" + _name) , _channelLink("https://twitch.tv/" + _name)
, _popoutPlayerLink("https://player.twitch.tv/?channel=" + _name) , _popoutPlayerLink("https://player.twitch.tv/?channel=" + _name)
@ -41,14 +43,14 @@ Channel::Channel(WindowManager &_windowManager, EmoteManager &_emoteManager,
// //
// properties // properties
// //
ConcurrentMap<QString, messages::LazyLoadedImage *> &Channel::getBttvChannelEmotes() EmoteManager::EmoteMap &Channel::getBTTVChannelEmotes()
{ {
return _bttvChannelEmotes; return this->bttvChannelEmotes;
} }
ConcurrentMap<QString, messages::LazyLoadedImage *> &Channel::getFfzChannelEmotes() EmoteManager::EmoteMap &Channel::getFFZChannelEmotes()
{ {
return _ffzChannelEmotes; return this->ffzChannelEmotes;
} }
bool Channel::isEmpty() const bool Channel::isEmpty() const
@ -125,8 +127,8 @@ void Channel::addMessage(std::shared_ptr<Message> message)
void Channel::reloadChannelEmotes() void Channel::reloadChannelEmotes()
{ {
printf("[Channel:%s] Reloading channel emotes\n", qPrintable(this->_name)); printf("[Channel:%s] Reloading channel emotes\n", qPrintable(this->_name));
this->emoteManager.reloadBTTVChannelEmotes(this->_name, this->_bttvChannelEmotes); this->emoteManager.reloadBTTVChannelEmotes(this->_name);
this->emoteManager.reloadFFZChannelEmotes(this->_name, this->_ffzChannelEmotes); this->emoteManager.reloadFFZChannelEmotes(this->_name);
} }
void Channel::sendMessage(const QString &message) void Channel::sendMessage(const QString &message)

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "concurrentmap.hpp" #include "concurrentmap.hpp"
#include "emotemanager.hpp"
#include "logging/loggingchannel.hpp" #include "logging/loggingchannel.hpp"
#include "messages/lazyloadedimage.hpp" #include "messages/lazyloadedimage.hpp"
#include "messages/limitedqueue.hpp" #include "messages/limitedqueue.hpp"
@ -19,7 +20,6 @@ class Message;
} }
class WindowManager; class WindowManager;
class EmoteManager;
class IrcManager; class IrcManager;
class Channel class Channel
@ -32,8 +32,8 @@ public:
boost::signals2::signal<void(messages::SharedMessage &)> messageAppended; boost::signals2::signal<void(messages::SharedMessage &)> messageAppended;
// properties // properties
ConcurrentMap<QString, messages::LazyLoadedImage *> &getBttvChannelEmotes(); EmoteManager::EmoteMap &getBTTVChannelEmotes();
ConcurrentMap<QString, messages::LazyLoadedImage *> &getFfzChannelEmotes(); EmoteManager::EmoteMap &getFFZChannelEmotes();
bool isEmpty() const; bool isEmpty() const;
const QString &getName() const; const QString &getName() const;
@ -64,8 +64,8 @@ private:
QString _name; QString _name;
ConcurrentMap<QString, messages::LazyLoadedImage *> _bttvChannelEmotes; EmoteManager::EmoteMap &bttvChannelEmotes;
ConcurrentMap<QString, messages::LazyLoadedImage *> _ffzChannelEmotes; EmoteManager::EmoteMap &ffzChannelEmotes;
QString _subLink; QString _subLink;
QString _channelLink; QString _channelLink;

20
src/completionmanager.cpp Normal file
View file

@ -0,0 +1,20 @@
#include "completionmanager.hpp"
namespace chatterino {
CompletionManager::CompletionManager()
{
}
CompletionModel *CompletionManager::createModel(const std::string &channelName)
{
CompletionModel *ret = new CompletionModel();
return ret;
}
void CompletionManager::updateModel(CompletionModel *model, const std::string &channelName)
{
}
} // namespace chatterino

51
src/completionmanager.hpp Normal file
View file

@ -0,0 +1,51 @@
#pragma once
#include <QAbstractItemModel>
#include <string>
namespace chatterino {
class CompletionModel : public QAbstractItemModel
{
public:
virtual int columnCount(const QModelIndex & /*parent*/) const override
{
return 1;
}
virtual QVariant data(const QModelIndex &index, int role) const override
{
// TODO: Implement
return QVariant();
}
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const override
{
// TODO: Implement
return QModelIndex();
}
virtual QModelIndex parent(const QModelIndex &child) const override
{
return QModelIndex();
}
virtual int rowCount(const QModelIndex &parent) const override
{
return 1;
}
};
class CompletionManager
{
CompletionManager();
public:
CompletionModel *createModel(const std::string &channelName);
void updateModel(CompletionModel *model, const std::string &channelName);
friend class Application;
};
} // namespace chatterino

View file

@ -14,16 +14,15 @@ class ConcurrentMap
{ {
public: public:
ConcurrentMap() ConcurrentMap()
: _map()
{ {
} }
bool tryGet(const TKey &name, TValue &value) const bool tryGet(const TKey &name, TValue &value) const
{ {
QMutexLocker lock(&_mutex); QMutexLocker lock(&this->mutex);
auto a = _map.find(name); auto a = this->data.find(name);
if (a == _map.end()) { if (a == this->data.end()) {
return false; return false;
} }
@ -34,35 +33,51 @@ public:
TValue getOrAdd(const TKey &name, std::function<TValue()> addLambda) TValue getOrAdd(const TKey &name, std::function<TValue()> addLambda)
{ {
QMutexLocker lock(&_mutex); QMutexLocker lock(&this->mutex);
auto a = _map.find(name); auto a = this->data.find(name);
if (a == _map.end()) { if (a == this->data.end()) {
TValue value = addLambda(); TValue value = addLambda();
_map.insert(name, value); this->data.insert(name, value);
return value; return value;
} }
return a.value(); return a.value();
} }
TValue &operator[](const TKey &name)
{
QMutexLocker lock(&this->mutex);
return this->data[name];
}
ConcurrentMap(const ConcurrentMap &o)
{
}
ConcurrentMap &operator=(const ConcurrentMap &rhs)
{
return *this;
}
void clear() void clear()
{ {
QMutexLocker lock(&_mutex); QMutexLocker lock(&this->mutex);
_map.clear(); this->data.clear();
} }
void insert(const TKey &name, const TValue &value) void insert(const TKey &name, const TValue &value)
{ {
QMutexLocker lock(&_mutex); QMutexLocker lock(&this->mutex);
_map.insert(name, value); this->data.insert(name, value);
} }
private: private:
mutable QMutex _mutex; mutable QMutex mutex;
QMap<TKey, TValue> _map; QMap<TKey, TValue> data;
}; };
template <typename TKey, typename TValue> template <typename TKey, typename TValue>
@ -97,6 +112,13 @@ public:
return a.value(); return a.value();
} }
TValue &operator[](const TKey &name)
{
QMutexLocker lock(&_mutex);
return this->_map[name];
}
void clear() void clear()
{ {
QMutexLocker lock(&_mutex); QMutexLocker lock(&_mutex);

View file

@ -34,13 +34,14 @@ void EmoteManager::loadGlobalEmotes()
this->loadFFZEmotes(); this->loadFFZEmotes();
} }
void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName, void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName)
BTTVEmoteMap &channelEmoteMap)
{ {
printf("[EmoteManager] Reload BTTV Channel Emotes for channel %s\n", qPrintable(channelName)); printf("[EmoteManager] Reload BTTV Channel Emotes for channel %s\n", qPrintable(channelName));
QString url("https://api.betterttv.net/2/channels/" + channelName); QString url("https://api.betterttv.net/2/channels/" + channelName);
util::urlFetchJSON(url, [this, &channelEmoteMap](QJsonObject &rootNode) { util::urlFetchJSON(url, [this, channelName](QJsonObject &rootNode) {
EmoteMap &channelEmoteMap = this->bttvChannels[channelName];
channelEmoteMap.clear(); channelEmoteMap.clear();
auto emotesNode = rootNode.value("emotes").toArray(); auto emotesNode = rootNode.value("emotes").toArray();
@ -60,8 +61,8 @@ void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName,
link = link.replace("{{id}}", id).replace("{{image}}", "1x"); link = link.replace("{{id}}", id).replace("{{image}}", "1x");
auto emote = this->getBTTVChannelEmoteFromCaches().getOrAdd(id, [this, &code, &link] { auto emote = this->getBTTVChannelEmoteFromCaches().getOrAdd(id, [this, &code, &link] {
return new LazyLoadedImage(*this, this->windowManager, link, 1, code, return EmoteData(new LazyLoadedImage(*this, this->windowManager, link, 1, code,
code + "\nChannel BTTV Emote"); code + "\nChannel BTTV Emote"));
}); });
this->bttvChannelEmotes.insert(code, emote); this->bttvChannelEmotes.insert(code, emote);
@ -70,15 +71,15 @@ void EmoteManager::reloadBTTVChannelEmotes(const QString &channelName,
}); });
} }
void EmoteManager::reloadFFZChannelEmotes( void EmoteManager::reloadFFZChannelEmotes(const QString &channelName)
const QString &channelName,
ConcurrentMap<QString, messages::LazyLoadedImage *> &channelEmoteMap)
{ {
printf("[EmoteManager] Reload FFZ Channel Emotes for channel %s\n", qPrintable(channelName)); printf("[EmoteManager] Reload FFZ Channel Emotes for channel %s\n", qPrintable(channelName));
QString url("http://api.frankerfacez.com/v1/room/" + channelName); QString url("http://api.frankerfacez.com/v1/room/" + channelName);
util::urlFetchJSON(url, [this, &channelEmoteMap](QJsonObject &rootNode) { util::urlFetchJSON(url, [this, channelName](QJsonObject &rootNode) {
EmoteMap &channelEmoteMap = this->ffzChannels[channelName];
channelEmoteMap.clear(); channelEmoteMap.clear();
auto setsNode = rootNode.value("sets").toObject(); auto setsNode = rootNode.value("sets").toObject();
@ -98,8 +99,8 @@ void EmoteManager::reloadFFZChannelEmotes(
auto emote = auto emote =
this->getFFZChannelEmoteFromCaches().getOrAdd(id, [this, &code, &url1] { this->getFFZChannelEmoteFromCaches().getOrAdd(id, [this, &code, &url1] {
return new LazyLoadedImage(*this, this->windowManager, url1, 1, code, return EmoteData(new LazyLoadedImage(*this, this->windowManager, url1, 1,
code + "\nGlobal FFZ Emote"); code, code + "\nGlobal FFZ Emote"));
}); });
this->ffzChannelEmotes.insert(code, emote); this->ffzChannelEmotes.insert(code, emote);
@ -114,41 +115,36 @@ ConcurrentMap<QString, twitch::EmoteValue *> &EmoteManager::getTwitchEmotes()
return _twitchEmotes; return _twitchEmotes;
} }
ConcurrentMap<QString, messages::LazyLoadedImage *> &EmoteManager::getBTTVEmotes() EmoteManager::EmoteMap &EmoteManager::getBTTVEmotes()
{ {
return _bttvEmotes; return _bttvEmotes;
} }
ConcurrentMap<QString, messages::LazyLoadedImage *> &EmoteManager::getFFZEmotes() EmoteManager::EmoteMap &EmoteManager::getFFZEmotes()
{ {
return _ffzEmotes; return _ffzEmotes;
} }
ConcurrentMap<QString, messages::LazyLoadedImage *> &EmoteManager::getChatterinoEmotes() EmoteManager::EmoteMap &EmoteManager::getChatterinoEmotes()
{ {
return _chatterinoEmotes; return _chatterinoEmotes;
} }
ConcurrentMap<QString, messages::LazyLoadedImage *> &EmoteManager::getBTTVChannelEmoteFromCaches() EmoteManager::EmoteMap &EmoteManager::getBTTVChannelEmoteFromCaches()
{ {
return _bttvChannelEmoteFromCaches; return _bttvChannelEmoteFromCaches;
} }
ConcurrentMap<int, messages::LazyLoadedImage *> &EmoteManager::getFFZChannelEmoteFromCaches() ConcurrentMap<int, EmoteData> &EmoteManager::getFFZChannelEmoteFromCaches()
{ {
return _ffzChannelEmoteFromCaches; return _ffzChannelEmoteFromCaches;
} }
ConcurrentMap<long, messages::LazyLoadedImage *> &EmoteManager::getTwitchEmoteFromCache() ConcurrentMap<long, EmoteData> &EmoteManager::getTwitchEmoteFromCache()
{ {
return _twitchEmoteFromCache; return _twitchEmoteFromCache;
} }
ConcurrentMap<QString, messages::LazyLoadedImage *> &EmoteManager::getMiscImageFromCache()
{
return _miscImageFromCache;
}
void EmoteManager::loadEmojis() void EmoteManager::loadEmojis()
{ {
QFile file(":/emojidata.txt"); QFile file(":/emojidata.txt");
@ -199,8 +195,8 @@ void EmoteManager::loadEmojis()
} }
} }
void EmoteManager::parseEmojis( void EmoteManager::parseEmojis(std::vector<std::tuple<EmoteData, QString>> &parsedWords,
std::vector<std::tuple<messages::LazyLoadedImage *, QString>> &parsedWords, const QString &text) const QString &text)
{ {
int lastParsedEmojiEndIndex = 0; int lastParsedEmojiEndIndex = 0;
@ -270,12 +266,11 @@ void EmoteManager::parseEmojis(
// Create or fetch cached emoji image // Create or fetch cached emoji image
auto emojiImage = this->emojiCache.getOrAdd(url, [this, &url] { auto emojiImage = this->emojiCache.getOrAdd(url, [this, &url] {
return new LazyLoadedImage(*this, this->windowManager, url, 0.35); // return EmoteData(new LazyLoadedImage(*this, this->windowManager, url, 0.35)); //
}); });
// Push the emoji as a word to parsedWords // Push the emoji as a word to parsedWords
parsedWords.push_back( parsedWords.push_back(std::tuple<EmoteData, QString>(emojiImage, QString()));
std::tuple<messages::LazyLoadedImage *, QString>(emojiImage, QString()));
lastParsedEmojiEndIndex = currentParsedEmojiEndIndex; lastParsedEmojiEndIndex = currentParsedEmojiEndIndex;
@ -373,14 +368,16 @@ void EmoteManager::loadFFZEmotes()
}); });
} }
LazyLoadedImage *EmoteManager::getTwitchEmoteById(const QString &name, long id) // id is used for lookup
// emoteName is used for giving a name to the emote in case it doesn't exist
EmoteData EmoteManager::getTwitchEmoteById(long id, const QString &emoteName)
{ {
return EmoteManager::_twitchEmoteFromCache.getOrAdd(id, [this, &name, &id] { return _twitchEmoteFromCache.getOrAdd(id, [this, &emoteName, &id] {
qDebug() << "added twitch emote: " << id; qDebug() << "added twitch emote: " << id;
qreal scale; qreal scale;
QString url = getTwitchEmoteLink(id, scale); QString url = getTwitchEmoteLink(id, scale);
return new LazyLoadedImage(*this, this->windowManager, url, scale, name, return new LazyLoadedImage(*this, this->windowManager, url, scale, emoteName,
name + "\nTwitch Emote"); emoteName + "\nTwitch Emote");
}); });
} }
@ -395,27 +392,10 @@ QString EmoteManager::getTwitchEmoteLink(long id, qreal &scale)
return value.replace("{id}", QString::number(id)).replace("{scale}", "2"); return value.replace("{id}", QString::number(id)).replace("{scale}", "2");
} }
LazyLoadedImage *EmoteManager::getCheerImage(long long amount, bool animated) EmoteData EmoteManager::getCheerImage(long long amount, bool animated)
{ {
// TODO: fix this xD // TODO: fix this xD
return this->getCheerBadge(amount); return EmoteData();
}
LazyLoadedImage *EmoteManager::getCheerBadge(long long amount)
{
if (amount >= 100000) {
return this->resources.cheerBadge100000;
} else if (amount >= 10000) {
return this->resources.cheerBadge10000;
} else if (amount >= 5000) {
return this->resources.cheerBadge5000;
} else if (amount >= 1000) {
return this->resources.cheerBadge1000;
} else if (amount >= 100) {
return this->resources.cheerBadge100;
} else {
return this->resources.cheerBadge1;
}
} }
boost::signals2::signal<void()> &EmoteManager::getGifUpdateSignal() boost::signals2::signal<void()> &EmoteManager::getGifUpdateSignal()

View file

@ -18,33 +18,42 @@ namespace chatterino {
class WindowManager; class WindowManager;
class Resources; class Resources;
struct EmoteData {
EmoteData()
{
}
EmoteData(messages::LazyLoadedImage *_image)
: image(_image)
{
}
messages::LazyLoadedImage *image = nullptr;
};
class EmoteManager class EmoteManager
{ {
public: public:
using FFZEmoteMap = ConcurrentMap<QString, messages::LazyLoadedImage *>; using EmoteMap = ConcurrentMap<QString, EmoteData>;
using BTTVEmoteMap = ConcurrentMap<QString, messages::LazyLoadedImage *>;
using ChatterinoEmoteMap = ConcurrentMap<QString, messages::LazyLoadedImage *>;
EmoteManager(WindowManager &_windowManager, Resources &_resources); EmoteManager(WindowManager &_windowManager, Resources &_resources);
void loadGlobalEmotes(); void loadGlobalEmotes();
void reloadBTTVChannelEmotes(const QString &channelName, BTTVEmoteMap &channelEmoteMap); void reloadBTTVChannelEmotes(const QString &channelName);
void reloadFFZChannelEmotes(const QString &channelName, FFZEmoteMap &channelEmoteMap); void reloadFFZChannelEmotes(const QString &channelName);
ConcurrentMap<QString, twitch::EmoteValue *> &getTwitchEmotes(); ConcurrentMap<QString, twitch::EmoteValue *> &getTwitchEmotes();
ConcurrentMap<QString, messages::LazyLoadedImage *> &getBTTVEmotes(); EmoteMap &getBTTVEmotes();
ConcurrentMap<QString, messages::LazyLoadedImage *> &getFFZEmotes(); EmoteMap &getFFZEmotes();
ConcurrentMap<QString, messages::LazyLoadedImage *> &getChatterinoEmotes(); EmoteMap &getChatterinoEmotes();
ConcurrentMap<QString, messages::LazyLoadedImage *> &getBTTVChannelEmoteFromCaches(); EmoteMap &getBTTVChannelEmoteFromCaches();
ConcurrentMap<int, messages::LazyLoadedImage *> &getFFZChannelEmoteFromCaches(); ConcurrentMap<int, EmoteData> &getFFZChannelEmoteFromCaches();
ConcurrentMap<long, messages::LazyLoadedImage *> &getTwitchEmoteFromCache(); ConcurrentMap<long, EmoteData> &getTwitchEmoteFromCache();
ConcurrentMap<QString, messages::LazyLoadedImage *> &getMiscImageFromCache();
messages::LazyLoadedImage *getCheerImage(long long int amount, bool animated); EmoteData getCheerImage(long long int amount, bool animated);
messages::LazyLoadedImage *getCheerBadge(long long int amount);
messages::LazyLoadedImage *getTwitchEmoteById(const QString &name, long int id); EmoteData getTwitchEmoteById(long int id, const QString &emoteName);
int getGeneration() int getGeneration()
{ {
@ -58,6 +67,9 @@ public:
boost::signals2::signal<void()> &getGifUpdateSignal(); boost::signals2::signal<void()> &getGifUpdateSignal();
// Bit badge/emotes?
ConcurrentMap<QString, messages::LazyLoadedImage *> miscImageCache;
private: private:
WindowManager &windowManager; WindowManager &windowManager;
Resources &resources; Resources &resources;
@ -70,38 +82,44 @@ private:
QMap<QChar, QVector<EmojiData>> emojiFirstByte; QMap<QChar, QVector<EmojiData>> emojiFirstByte;
// url Emoji-one image // url Emoji-one image
ConcurrentMap<QString, messages::LazyLoadedImage *> emojiCache; EmoteMap emojiCache;
void loadEmojis(); void loadEmojis();
public: public:
void parseEmojis(std::vector<std::tuple<messages::LazyLoadedImage *, QString>> &parsedWords, void parseEmojis(std::vector<std::tuple<EmoteData, QString>> &parsedWords, const QString &text);
const QString &text);
private: private:
/// Twitch emotes /// Twitch emotes
ConcurrentMap<QString, twitch::EmoteValue *> _twitchEmotes; ConcurrentMap<QString, twitch::EmoteValue *> _twitchEmotes;
ConcurrentMap<long, messages::LazyLoadedImage *> _twitchEmoteFromCache; ConcurrentMap<long, EmoteData> _twitchEmoteFromCache;
/// BTTV emotes /// BTTV emotes
ConcurrentMap<QString, messages::LazyLoadedImage *> bttvChannelEmotes; EmoteMap bttvChannelEmotes;
ConcurrentMap<QString, messages::LazyLoadedImage *> _bttvEmotes;
ConcurrentMap<QString, messages::LazyLoadedImage *> _bttvChannelEmoteFromCaches; public:
ConcurrentMap<QString, EmoteMap> bttvChannels;
private:
EmoteMap _bttvEmotes;
EmoteMap _bttvChannelEmoteFromCaches;
void loadBTTVEmotes(); void loadBTTVEmotes();
/// FFZ emotes /// FFZ emotes
ConcurrentMap<QString, messages::LazyLoadedImage *> ffzChannelEmotes; EmoteMap ffzChannelEmotes;
ConcurrentMap<QString, messages::LazyLoadedImage *> _ffzEmotes;
ConcurrentMap<int, messages::LazyLoadedImage *> _ffzChannelEmoteFromCaches; public:
ConcurrentMap<QString, EmoteMap> ffzChannels;
private:
EmoteMap _ffzEmotes;
ConcurrentMap<int, EmoteData> _ffzChannelEmoteFromCaches;
void loadFFZEmotes(); void loadFFZEmotes();
/// Chatterino emotes /// Chatterino emotes
ConcurrentMap<QString, messages::LazyLoadedImage *> _chatterinoEmotes; EmoteMap _chatterinoEmotes;
// ???
ConcurrentMap<QString, messages::LazyLoadedImage *> _miscImageFromCache;
boost::signals2::signal<void()> _gifUpdateTimerSignal; boost::signals2::signal<void()> _gifUpdateTimerSignal;
QTimer _gifUpdateTimer; QTimer _gifUpdateTimer;

View file

@ -59,7 +59,7 @@ SharedMessage TwitchMessageBuilder::parse()
} }
// twitch emotes // twitch emotes
std::vector<std::pair<long int, LazyLoadedImage *>> twitchEmotes; std::vector<std::pair<long, EmoteData>> twitchEmotes;
iterator = this->tags.find("emotes"); iterator = this->tags.find("emotes");
if (iterator != this->tags.end()) { if (iterator != this->tags.end()) {
@ -70,8 +70,8 @@ SharedMessage TwitchMessageBuilder::parse()
} }
struct { struct {
bool operator()(const std::pair<long int, messages::LazyLoadedImage *> &lhs, bool operator()(const std::pair<long, EmoteData> &lhs,
const std::pair<long int, messages::LazyLoadedImage *> &rhs) const std::pair<long, EmoteData> &rhs)
{ {
return lhs.first < rhs.first; return lhs.first < rhs.first;
} }
@ -95,13 +95,13 @@ SharedMessage TwitchMessageBuilder::parse()
// twitch emote // twitch emote
if (currentTwitchEmote != twitchEmotes.end() && currentTwitchEmote->first == i) { if (currentTwitchEmote != twitchEmotes.end() && currentTwitchEmote->first == i) {
this->appendWord( this->appendWord(
Word(currentTwitchEmote->second, Word::TwitchEmoteImage, Word(currentTwitchEmote->second.image, Word::TwitchEmoteImage,
currentTwitchEmote->second->getName(), currentTwitchEmote->second.image->getName(),
currentTwitchEmote->second->getName() + QString("\nTwitch Emote"))); currentTwitchEmote->second.image->getName() + QString("\nTwitch Emote")));
this->appendWord( this->appendWord(
Word(currentTwitchEmote->second->getName(), Word::TwitchEmoteText, textColor, Word(currentTwitchEmote->second.image->getName(), Word::TwitchEmoteText, textColor,
currentTwitchEmote->second->getName(), currentTwitchEmote->second.image->getName(),
currentTwitchEmote->second->getName() + QString("\nTwitch Emote"))); currentTwitchEmote->second.image->getName() + QString("\nTwitch Emote")));
i += split.length() + 1; i += split.length() + 1;
currentTwitchEmote = std::next(currentTwitchEmote); currentTwitchEmote = std::next(currentTwitchEmote);
@ -110,15 +110,15 @@ SharedMessage TwitchMessageBuilder::parse()
} }
// split words // split words
std::vector<std::tuple<LazyLoadedImage *, QString>> parsed; std::vector<std::tuple<EmoteData, QString>> parsed;
// Parse emojis and take all non-emojis and put them in parsed as full text-words // Parse emojis and take all non-emojis and put them in parsed as full text-words
emoteManager.parseEmojis(parsed, split); emoteManager.parseEmojis(parsed, split);
for (const std::tuple<LazyLoadedImage *, QString> &tuple : parsed) { for (const auto &tuple : parsed) {
LazyLoadedImage *image = std::get<0>(tuple); const EmoteData &emoteData = std::get<0>(tuple);
if (image == nullptr) { // is text if (emoteData.image == nullptr) { // is text
QString string = std::get<1>(tuple); QString string = std::get<1>(tuple);
static QRegularExpression cheerRegex("cheer[1-9][0-9]*"); static QRegularExpression cheerRegex("cheer[1-9][0-9]*");
@ -153,13 +153,13 @@ SharedMessage TwitchMessageBuilder::parse()
QString bitsLink = QString bitsLink =
QString("http://static-cdn.jtvnw.net/bits/dark/static/" + color + "/1"); QString("http://static-cdn.jtvnw.net/bits/dark/static/" + color + "/1");
LazyLoadedImage *imageAnimated = emoteManager.getMiscImageFromCache().getOrAdd( LazyLoadedImage *imageAnimated = emoteManager.miscImageCache.getOrAdd(
bitsLinkAnimated, [this, &bitsLinkAnimated] { bitsLinkAnimated, [this, &bitsLinkAnimated] {
return new LazyLoadedImage(this->emoteManager, this->windowManager, return new LazyLoadedImage(this->emoteManager, this->windowManager,
bitsLinkAnimated); bitsLinkAnimated);
}); });
LazyLoadedImage *image = LazyLoadedImage *image =
emoteManager.getMiscImageFromCache().getOrAdd(bitsLink, [this, &bitsLink] { emoteManager.miscImageCache.getOrAdd(bitsLink, [this, &bitsLink] {
return new LazyLoadedImage(this->emoteManager, this->windowManager, return new LazyLoadedImage(this->emoteManager, this->windowManager,
bitsLink); bitsLink);
}); });
@ -185,21 +185,21 @@ SharedMessage TwitchMessageBuilder::parse()
} }
// bttv / ffz emotes // bttv / ffz emotes
LazyLoadedImage *bttvEmote; EmoteData emoteData;
// TODO: Implement ignored emotes // TODO: Implement ignored emotes
// Format of ignored emotes: // Format of ignored emotes:
// Emote name: "forsenPuke" - if string in ignoredEmotes // Emote name: "forsenPuke" - if string in ignoredEmotes
// Will match emote regardless of source (i.e. bttv, ffz) // Will match emote regardless of source (i.e. bttv, ffz)
// Emote source + name: "bttv:nyanPls" // Emote source + name: "bttv:nyanPls"
if (emoteManager.getBTTVEmotes().tryGet(string, bttvEmote) || if (emoteManager.getBTTVEmotes().tryGet(string, emoteData) ||
this->channel->getBttvChannelEmotes().tryGet(string, bttvEmote) || this->channel->getBTTVChannelEmotes().tryGet(string, emoteData) ||
emoteManager.getFFZEmotes().tryGet(string, bttvEmote) || emoteManager.getFFZEmotes().tryGet(string, emoteData) ||
this->channel->getFfzChannelEmotes().tryGet(string, bttvEmote) || this->channel->getFFZChannelEmotes().tryGet(string, emoteData) ||
emoteManager.getChatterinoEmotes().tryGet(string, bttvEmote)) { emoteManager.getChatterinoEmotes().tryGet(string, emoteData)) {
this->appendWord(Word(bttvEmote, Word::BttvEmoteImage, bttvEmote->getName(), this->appendWord(Word(emoteData.image, Word::BttvEmoteImage,
bttvEmote->getTooltip(), emoteData.image->getName(), emoteData.image->getTooltip(),
Link(Link::Url, bttvEmote->getUrl()))); Link(Link::Url, emoteData.image->getUrl())));
continue; continue;
} }
@ -212,8 +212,10 @@ SharedMessage TwitchMessageBuilder::parse()
} else { // is emoji } else { // is emoji
static QString emojiTooltip("Emoji"); static QString emojiTooltip("Emoji");
this->appendWord(Word(image, Word::EmojiImage, image->getName(), emojiTooltip)); this->appendWord(Word(emoteData.image, Word::EmojiImage, emoteData.image->getName(),
Word(image->getName(), Word::EmojiText, textColor, image->getName(), emojiTooltip); emojiTooltip));
Word(emoteData.image->getName(), Word::EmojiText, textColor,
emoteData.image->getName(), emojiTooltip);
} }
} }
@ -316,9 +318,10 @@ void TwitchMessageBuilder::appendModerationButtons()
buttonTimeoutTooltip, Link(Link::UserTimeout, ircMessage->account()))); buttonTimeoutTooltip, Link(Link::UserTimeout, ircMessage->account())));
} }
void TwitchMessageBuilder::appendTwitchEmote( void TwitchMessageBuilder::appendTwitchEmote(const Communi::IrcPrivateMessage *ircMessage,
const Communi::IrcPrivateMessage *ircMessage, const QString &emote, const QString &emote,
std::vector<std::pair<long int, messages::LazyLoadedImage *>> &vec, EmoteManager &emoteManager) std::vector<std::pair<long int, EmoteData>> &vec,
EmoteManager &emoteManager)
{ {
if (!emote.contains(':')) { if (!emote.contains(':')) {
return; return;
@ -350,8 +353,8 @@ void TwitchMessageBuilder::appendTwitchEmote(
QString name = ircMessage->content().mid(start, end - start + 1); QString name = ircMessage->content().mid(start, end - start + 1);
vec.push_back(std::pair<long int, LazyLoadedImage *>( vec.push_back(
start, emoteManager.getTwitchEmoteById(name, id))); std::pair<long int, EmoteData>(start, emoteManager.getTwitchEmoteById(id, name)));
} }
} }

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "emotemanager.hpp"
#include "messages/messagebuilder.hpp" #include "messages/messagebuilder.hpp"
#include "resources.hpp" #include "resources.hpp"
@ -8,7 +9,6 @@
namespace chatterino { namespace chatterino {
class EmoteManager;
class WindowManager; class WindowManager;
class Channel; class Channel;
class ColorScheme; class ColorScheme;
@ -55,7 +55,7 @@ private:
void appendModerationButtons(); void appendModerationButtons();
void appendTwitchEmote(const Communi::IrcPrivateMessage *ircMessage, const QString &emote, void appendTwitchEmote(const Communi::IrcPrivateMessage *ircMessage, const QString &emote,
std::vector<std::pair<long int, messages::LazyLoadedImage *>> &vec, std::vector<std::pair<long, EmoteData>> &vec,
EmoteManager &emoteManager); EmoteManager &emoteManager);
void parseTwitchBadges(); void parseTwitchBadges();