mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Fixed newly uploaded subscriber emotes not being available (#2992)
Co-authored-by: Felanbird <41973452+Felanbird@users.noreply.github.com> Co-authored-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
parent
91ab8b90a0
commit
7e13564c24
|
@ -2,6 +2,7 @@
|
|||
|
||||
## Unversioned
|
||||
|
||||
- Major: Newly uploaded Twitch emotes are once again present in emote picker and can be autocompleted with Tab as well. (#2992)
|
||||
- Minor: Added autocompletion in /whispers for Twitch emotes, Global Bttv/Ffz emotes and emojis. (#2999)
|
||||
- Bugfix: Fixed "smiley" emotes being unable to be "Tabbed" with autocompletion, introduced in v2.3.3. (#3010)
|
||||
- Dev: Ubuntu packages are now available (#2936)
|
||||
|
|
|
@ -35,7 +35,8 @@ void IvrApi::getSubage(QString userName, QString channelName,
|
|||
|
||||
void IvrApi::getBulkEmoteSets(QString emoteSetList,
|
||||
ResultCallback<QJsonArray> successCallback,
|
||||
IvrFailureCallback failureCallback)
|
||||
IvrFailureCallback failureCallback,
|
||||
std::function<void()> finallyCallback)
|
||||
{
|
||||
QUrlQuery urlQuery;
|
||||
urlQuery.addQueryItem("set_id", emoteSetList);
|
||||
|
@ -54,6 +55,7 @@ void IvrApi::getBulkEmoteSets(QString emoteSetList,
|
|||
<< QString(result.getData());
|
||||
failureCallback();
|
||||
})
|
||||
.finally(std::move(finallyCallback))
|
||||
.execute();
|
||||
}
|
||||
|
||||
|
|
|
@ -81,10 +81,11 @@ public:
|
|||
ResultCallback<IvrSubage> resultCallback,
|
||||
IvrFailureCallback failureCallback);
|
||||
|
||||
// https://api.ivr.fi/docs#tag/Twitch/paths/~1twitch~1emoteset/get
|
||||
// https://api.ivr.fi/v2/docs/static/index.html#/Twitch/get_twitch_emotes_sets
|
||||
void getBulkEmoteSets(QString emoteSetList,
|
||||
ResultCallback<QJsonArray> successCallback,
|
||||
IvrFailureCallback failureCallback);
|
||||
IvrFailureCallback failureCallback,
|
||||
std::function<void()> finallyCallback);
|
||||
|
||||
static void initialize();
|
||||
|
||||
|
|
|
@ -497,7 +497,7 @@ void IrcMessageHandler::handleUserStateMessage(Communi::IrcMessage *message)
|
|||
|
||||
if (emoteSetsChanged)
|
||||
{
|
||||
currentUser->loadUserstateEmotes();
|
||||
currentUser->loadUserstateEmotes([] {});
|
||||
}
|
||||
|
||||
QString channelName;
|
||||
|
@ -512,6 +512,7 @@ void IrcMessageHandler::handleUserStateMessage(Communi::IrcMessage *message)
|
|||
return;
|
||||
}
|
||||
|
||||
// Checking if currentUser is a VIP or staff member
|
||||
QVariant _badges = message->tag("badges");
|
||||
if (_badges.isValid())
|
||||
{
|
||||
|
@ -524,6 +525,7 @@ void IrcMessageHandler::handleUserStateMessage(Communi::IrcMessage *message)
|
|||
}
|
||||
}
|
||||
|
||||
// Checking if currentUser is a moderator
|
||||
QVariant _mod = message->tag("mod");
|
||||
if (_mod.isValid())
|
||||
{
|
||||
|
@ -535,6 +537,24 @@ void IrcMessageHandler::handleUserStateMessage(Communi::IrcMessage *message)
|
|||
}
|
||||
}
|
||||
|
||||
// This will emit only once and right after user logs in to IRC - reset emote data and reload emotes
|
||||
void IrcMessageHandler::handleGlobalUserStateMessage(
|
||||
Communi::IrcMessage *message)
|
||||
{
|
||||
auto currentUser = getApp()->accounts->twitch.getCurrent();
|
||||
|
||||
// set received emote-sets, this time used to initially load emotes
|
||||
// NOTE: this should always return true unless we reconnect
|
||||
auto emoteSetsChanged = currentUser->setUserstateEmoteSets(
|
||||
message->tag("emote-sets").toString().split(","));
|
||||
|
||||
// We should always attempt to reload emotes even on reconnections where
|
||||
// emoteSetsChanged, since we want to trigger emote reloads when
|
||||
// "currentUserChanged" signal is emitted
|
||||
qCDebug(chatterinoTwitch) << emoteSetsChanged << message->toData();
|
||||
currentUser->loadEmotes();
|
||||
}
|
||||
|
||||
void IrcMessageHandler::handleWhisperMessage(Communi::IrcMessage *message)
|
||||
{
|
||||
MessageParseArgs args;
|
||||
|
|
|
@ -30,6 +30,7 @@ public:
|
|||
void handleClearChatMessage(Communi::IrcMessage *message);
|
||||
void handleClearMessageMessage(Communi::IrcMessage *message);
|
||||
void handleUserStateMessage(Communi::IrcMessage *message);
|
||||
void handleGlobalUserStateMessage(Communi::IrcMessage *message);
|
||||
void handleWhisperMessage(Communi::IrcMessage *message);
|
||||
|
||||
// parseUserNoticeMessage parses a single IRC USERNOTICE message into 0+
|
||||
|
|
|
@ -21,6 +21,35 @@
|
|||
#include "util/QStringHash.hpp"
|
||||
#include "util/RapidjsonHelpers.hpp"
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<QStringList> getEmoteSetBatches(QStringList emoteSetKeys)
|
||||
{
|
||||
// splitting emoteSetKeys to batches of 100, because Ivr API endpoint accepts a maximum of 100 emotesets at once
|
||||
constexpr int batchSize = 100;
|
||||
|
||||
int batchCount = (emoteSetKeys.size() / batchSize) + 1;
|
||||
|
||||
std::vector<QStringList> batches;
|
||||
batches.reserve(batchCount);
|
||||
|
||||
for (int i = 0; i < batchCount; i++)
|
||||
{
|
||||
QStringList batch;
|
||||
|
||||
int last = std::min(batchSize, emoteSetKeys.size() - batchSize * i);
|
||||
for (int j = 0; j < last; j++)
|
||||
{
|
||||
batch.push_back(emoteSetKeys.at(j + (batchSize * i)));
|
||||
}
|
||||
batches.emplace_back(batch);
|
||||
}
|
||||
|
||||
return batches;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace chatterino {
|
||||
TwitchAccount::TwitchAccount(const QString &username, const QString &oauthToken,
|
||||
const QString &oauthClient, const QString &userID)
|
||||
|
@ -116,7 +145,7 @@ void TwitchAccount::loadBlocks()
|
|||
}
|
||||
},
|
||||
[] {
|
||||
qDebug() << "Fetching blocks failed!";
|
||||
qCWarning(chatterinoTwitch) << "Fetching blocks failed!";
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -196,77 +225,25 @@ void TwitchAccount::loadEmotes()
|
|||
|
||||
if (this->getOAuthClient().isEmpty() || this->getOAuthToken().isEmpty())
|
||||
{
|
||||
qCDebug(chatterinoTwitch) << "Missing Client ID and/or OAuth token";
|
||||
qCDebug(chatterinoTwitch)
|
||||
<< "Aborted loadEmotes due to missing Client ID and/or OAuth token";
|
||||
return;
|
||||
}
|
||||
|
||||
// Getting subscription emotes from kraken
|
||||
getKraken()->getUserEmotes(
|
||||
this,
|
||||
[this](KrakenEmoteSets data) {
|
||||
// no emotes available
|
||||
if (data.emoteSets.isEmpty())
|
||||
{
|
||||
qCWarning(chatterinoTwitch)
|
||||
<< "\"emoticon_sets\" either empty or not present in "
|
||||
"Kraken::getUserEmotes response";
|
||||
return;
|
||||
}
|
||||
{
|
||||
auto emoteData = this->emotes_.access();
|
||||
emoteData->emoteSets.clear();
|
||||
emoteData->emotes.clear();
|
||||
qCDebug(chatterinoTwitch) << "Cleared emotes!";
|
||||
}
|
||||
|
||||
{
|
||||
// Clearing emote data
|
||||
auto emoteData = this->emotes_.access();
|
||||
emoteData->emoteSets.clear();
|
||||
emoteData->emotes.clear();
|
||||
|
||||
for (auto emoteSetIt = data.emoteSets.begin();
|
||||
emoteSetIt != data.emoteSets.end(); ++emoteSetIt)
|
||||
{
|
||||
auto emoteSet = std::make_shared<EmoteSet>();
|
||||
|
||||
emoteSet->key = emoteSetIt.key();
|
||||
this->loadEmoteSetData(emoteSet);
|
||||
|
||||
for (const auto emoteArrObj : emoteSetIt.value().toArray())
|
||||
{
|
||||
if (!emoteArrObj.isObject())
|
||||
{
|
||||
qCWarning(chatterinoTwitch)
|
||||
<< QString(
|
||||
"Emote value from set %1 was invalid")
|
||||
.arg(emoteSet->key);
|
||||
continue;
|
||||
}
|
||||
KrakenEmote krakenEmote(emoteArrObj.toObject());
|
||||
|
||||
auto id = EmoteId{krakenEmote.id};
|
||||
auto code = EmoteName{
|
||||
TwitchEmotes::cleanUpEmoteCode(krakenEmote.code)};
|
||||
|
||||
emoteSet->emotes.emplace_back(TwitchEmote{id, code});
|
||||
|
||||
if (!emoteSet->local)
|
||||
{
|
||||
auto emote =
|
||||
getApp()->emotes->twitch.getOrCreateEmote(id,
|
||||
code);
|
||||
emoteData->emotes.emplace(code, emote);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(emoteSet->emotes.begin(), emoteSet->emotes.end(),
|
||||
[](const TwitchEmote &l, const TwitchEmote &r) {
|
||||
return l.name.string < r.name.string;
|
||||
});
|
||||
emoteData->emoteSets.emplace_back(emoteSet);
|
||||
}
|
||||
}
|
||||
// Getting userstate emotes from Ivr
|
||||
this->loadUserstateEmotes();
|
||||
},
|
||||
[] {
|
||||
// kraken request failed
|
||||
});
|
||||
// TODO(zneix): Once Helix adds Get User Emotes we could remove this hacky solution
|
||||
// For now, this is necessary as Kraken's equivalent doesn't return all emotes
|
||||
// See: https://twitch.uservoice.com/forums/310213-developers/suggestions/43599900
|
||||
this->loadUserstateEmotes([=] {
|
||||
// Fill up emoteData with emote sets that were returned in a Kraken call, but aren't present in emoteData.
|
||||
this->loadKrakenEmotes();
|
||||
});
|
||||
}
|
||||
|
||||
bool TwitchAccount::setUserstateEmoteSets(QStringList newEmoteSets)
|
||||
|
@ -284,10 +261,11 @@ bool TwitchAccount::setUserstateEmoteSets(QStringList newEmoteSets)
|
|||
return true;
|
||||
}
|
||||
|
||||
void TwitchAccount::loadUserstateEmotes()
|
||||
void TwitchAccount::loadUserstateEmotes(std::function<void()> callback)
|
||||
{
|
||||
if (this->userstateEmoteSets_.isEmpty())
|
||||
{
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -303,7 +281,7 @@ void TwitchAccount::loadUserstateEmotes()
|
|||
}
|
||||
|
||||
// filter out emote sets from userstate message, which are not in fetched emote set list
|
||||
for (const auto &emoteSetKey : this->userstateEmoteSets_)
|
||||
for (const auto &emoteSetKey : qAsConst(this->userstateEmoteSets_))
|
||||
{
|
||||
if (!krakenEmoteSetKeys.contains(emoteSetKey))
|
||||
{
|
||||
|
@ -314,54 +292,50 @@ void TwitchAccount::loadUserstateEmotes()
|
|||
// return if there are no new emote sets
|
||||
if (newEmoteSetKeys.isEmpty())
|
||||
{
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
qCDebug(chatterinoTwitch) << QString("Loading %1 emotesets from IVR: %2")
|
||||
.arg(newEmoteSetKeys.size())
|
||||
.arg(newEmoteSetKeys.join(", "));
|
||||
|
||||
// splitting newEmoteSetKeys to batches of 100, because Ivr API endpoint accepts a maximum of 100 emotesets at once
|
||||
constexpr int batchSize = 100;
|
||||
|
||||
std::vector<QStringList> batches;
|
||||
int batchCount = (newEmoteSetKeys.size() / batchSize) + 1;
|
||||
|
||||
batches.reserve(batchCount);
|
||||
|
||||
for (int i = 0; i < batchCount; i++)
|
||||
{
|
||||
QStringList batch;
|
||||
|
||||
int last = std::min(batchSize, newEmoteSetKeys.size() - batchSize * i);
|
||||
for (int j = batchSize * i; j < last; j++)
|
||||
{
|
||||
batch.push_back(newEmoteSetKeys.at(j));
|
||||
}
|
||||
batches.emplace_back(batch);
|
||||
}
|
||||
|
||||
// requesting emotes
|
||||
for (const auto &batch : batches)
|
||||
auto batches = getEmoteSetBatches(newEmoteSetKeys);
|
||||
for (int i = 0; i < batches.size(); i++)
|
||||
{
|
||||
qCDebug(chatterinoTwitch)
|
||||
<< QString(
|
||||
"Loading %1 emotesets from IVR; batch %2/%3 (%4 sets): %5")
|
||||
.arg(newEmoteSetKeys.size())
|
||||
.arg(i + 1)
|
||||
.arg(batches.size())
|
||||
.arg(batches.at(i).size())
|
||||
.arg(batches.at(i).join(","));
|
||||
getIvr()->getBulkEmoteSets(
|
||||
batch.join(","),
|
||||
batches.at(i).join(","),
|
||||
[this](QJsonArray emoteSetArray) {
|
||||
auto emoteData = this->emotes_.access();
|
||||
auto localEmoteData = this->localEmotes_.access();
|
||||
for (auto emoteSet : emoteSetArray)
|
||||
for (auto emoteSet_ : emoteSetArray)
|
||||
{
|
||||
auto newUserEmoteSet = std::make_shared<EmoteSet>();
|
||||
auto emoteSet = std::make_shared<EmoteSet>();
|
||||
|
||||
IvrEmoteSet ivrEmoteSet(emoteSet.toObject());
|
||||
IvrEmoteSet ivrEmoteSet(emoteSet_.toObject());
|
||||
|
||||
newUserEmoteSet->key = ivrEmoteSet.setId;
|
||||
QString setKey = ivrEmoteSet.setId;
|
||||
emoteSet->key = setKey;
|
||||
|
||||
auto name = ivrEmoteSet.login;
|
||||
name.detach();
|
||||
name[0] = name[0].toUpper();
|
||||
// check if the emoteset is already in emoteData
|
||||
auto isAlreadyFetched =
|
||||
std::find_if(emoteData->emoteSets.begin(),
|
||||
emoteData->emoteSets.end(),
|
||||
[setKey](std::shared_ptr<EmoteSet> set) {
|
||||
return (set->key == setKey);
|
||||
});
|
||||
if (isAlreadyFetched != emoteData->emoteSets.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
newUserEmoteSet->text = name;
|
||||
newUserEmoteSet->channelName = ivrEmoteSet.login;
|
||||
emoteSet->channelName = ivrEmoteSet.login;
|
||||
emoteSet->text = ivrEmoteSet.displayName;
|
||||
|
||||
for (const auto &emoteObj : ivrEmoteSet.emotes)
|
||||
{
|
||||
|
@ -371,8 +345,7 @@ void TwitchAccount::loadUserstateEmotes()
|
|||
auto code = EmoteName{
|
||||
TwitchEmotes::cleanUpEmoteCode(ivrEmote.code)};
|
||||
|
||||
newUserEmoteSet->emotes.push_back(
|
||||
TwitchEmote{id, code});
|
||||
emoteSet->emotes.push_back(TwitchEmote{id, code});
|
||||
|
||||
auto emote =
|
||||
getApp()->emotes->twitch.getOrCreateEmote(id, code);
|
||||
|
@ -380,7 +353,7 @@ void TwitchAccount::loadUserstateEmotes()
|
|||
// Follower emotes can be only used in their origin channel
|
||||
if (ivrEmote.emoteType == "FOLLOWER")
|
||||
{
|
||||
newUserEmoteSet->local = true;
|
||||
emoteSet->local = true;
|
||||
|
||||
// EmoteMap for target channel wasn't initialized yet, doing it now
|
||||
if (localEmoteData->find(ivrEmoteSet.channelId) ==
|
||||
|
@ -398,16 +371,25 @@ void TwitchAccount::loadUserstateEmotes()
|
|||
emoteData->emotes.emplace(code, emote);
|
||||
}
|
||||
}
|
||||
std::sort(newUserEmoteSet->emotes.begin(),
|
||||
newUserEmoteSet->emotes.end(),
|
||||
std::sort(emoteSet->emotes.begin(), emoteSet->emotes.end(),
|
||||
[](const TwitchEmote &l, const TwitchEmote &r) {
|
||||
return l.name.string < r.name.string;
|
||||
});
|
||||
emoteData->emoteSets.emplace_back(newUserEmoteSet);
|
||||
emoteData->emoteSets.emplace_back(emoteSet);
|
||||
}
|
||||
},
|
||||
[] {
|
||||
// fetching emotes failed, ivr API might be down
|
||||
},
|
||||
[=] {
|
||||
// XXX(zneix): We check if this is the last iteration and if so, call the callback
|
||||
if (i + 1 == batches.size())
|
||||
{
|
||||
qCDebug(chatterinoTwitch)
|
||||
<< "Finished loading emotes from IVR, attempting to "
|
||||
"load Kraken emotes now";
|
||||
callback();
|
||||
}
|
||||
});
|
||||
};
|
||||
}
|
||||
|
@ -517,6 +499,79 @@ void TwitchAccount::autoModDeny(const QString msgID, ChannelPtr channel)
|
|||
});
|
||||
}
|
||||
|
||||
void TwitchAccount::loadKrakenEmotes()
|
||||
{
|
||||
getKraken()->getUserEmotes(
|
||||
this,
|
||||
[this](KrakenEmoteSets data) {
|
||||
// no emotes available
|
||||
if (data.emoteSets.isEmpty())
|
||||
{
|
||||
qCWarning(chatterinoTwitch)
|
||||
<< "\"emoticon_sets\" either empty or not present in "
|
||||
"Kraken::getUserEmotes response";
|
||||
return;
|
||||
}
|
||||
|
||||
auto emoteData = this->emotes_.access();
|
||||
|
||||
for (auto emoteSetIt = data.emoteSets.begin();
|
||||
emoteSetIt != data.emoteSets.end(); ++emoteSetIt)
|
||||
{
|
||||
auto emoteSet = std::make_shared<EmoteSet>();
|
||||
|
||||
QString setKey = emoteSetIt.key();
|
||||
emoteSet->key = setKey;
|
||||
this->loadEmoteSetData(emoteSet);
|
||||
|
||||
// check if the emoteset is already in emoteData
|
||||
auto isAlreadyFetched = std::find_if(
|
||||
emoteData->emoteSets.begin(), emoteData->emoteSets.end(),
|
||||
[setKey](std::shared_ptr<EmoteSet> set) {
|
||||
return (set->key == setKey);
|
||||
});
|
||||
if (isAlreadyFetched != emoteData->emoteSets.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto emoteArrObj : emoteSetIt->toArray())
|
||||
{
|
||||
if (!emoteArrObj.isObject())
|
||||
{
|
||||
qCWarning(chatterinoTwitch)
|
||||
<< QString("Emote value from set %1 was invalid")
|
||||
.arg(emoteSet->key);
|
||||
continue;
|
||||
}
|
||||
KrakenEmote krakenEmote(emoteArrObj.toObject());
|
||||
|
||||
auto id = EmoteId{krakenEmote.id};
|
||||
auto code = EmoteName{
|
||||
TwitchEmotes::cleanUpEmoteCode(krakenEmote.code)};
|
||||
|
||||
emoteSet->emotes.emplace_back(TwitchEmote{id, code});
|
||||
|
||||
if (!emoteSet->local)
|
||||
{
|
||||
auto emote =
|
||||
getApp()->emotes->twitch.getOrCreateEmote(id, code);
|
||||
emoteData->emotes.emplace(code, emote);
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(emoteSet->emotes.begin(), emoteSet->emotes.end(),
|
||||
[](const TwitchEmote &l, const TwitchEmote &r) {
|
||||
return l.name.string < r.name.string;
|
||||
});
|
||||
emoteData->emoteSets.emplace_back(emoteSet);
|
||||
}
|
||||
},
|
||||
[] {
|
||||
// kraken request failed
|
||||
});
|
||||
}
|
||||
|
||||
void TwitchAccount::loadEmoteSetData(std::shared_ptr<EmoteSet> emoteSet)
|
||||
{
|
||||
if (!emoteSet)
|
||||
|
@ -546,7 +601,7 @@ void TwitchAccount::loadEmoteSetData(std::shared_ptr<EmoteSet> emoteSet)
|
|||
if (emoteSetData.ownerId.isEmpty() ||
|
||||
emoteSetData.setId != emoteSet->key)
|
||||
{
|
||||
qCWarning(chatterinoTwitch)
|
||||
qCDebug(chatterinoTwitch)
|
||||
<< QString("Failed to fetch emoteSetData for %1, assuming "
|
||||
"Twitch is the owner")
|
||||
.arg(emoteSet->key);
|
||||
|
|
|
@ -115,7 +115,7 @@ public:
|
|||
void loadEmotes();
|
||||
// loadUserstateEmotes loads emote sets that are part of the USERSTATE emote-sets key
|
||||
// this function makes sure not to load emote sets that have already been loaded
|
||||
void loadUserstateEmotes();
|
||||
void loadUserstateEmotes(std::function<void()> callback);
|
||||
// setUserStateEmoteSets sets the emote sets that were parsed from the USERSTATE emote-sets key
|
||||
// Returns true if the newly inserted emote sets differ from the ones previously saved
|
||||
[[nodiscard]] bool setUserstateEmoteSets(QStringList newEmoteSets);
|
||||
|
@ -128,6 +128,7 @@ public:
|
|||
void autoModDeny(const QString msgID, ChannelPtr channel);
|
||||
|
||||
private:
|
||||
void loadKrakenEmotes();
|
||||
void loadEmoteSetData(std::shared_ptr<EmoteSet> emoteSet);
|
||||
|
||||
QString oauthClient_;
|
||||
|
|
|
@ -60,6 +60,19 @@ void TwitchIrcServer::initializeConnection(IrcConnection *connection,
|
|||
|
||||
qCDebug(chatterinoTwitch) << "logging in as" << account->getUserName();
|
||||
|
||||
// twitch.tv/tags enables IRCv3 tags on messages. See https://dev.twitch.tv/docs/irc/tags
|
||||
// twitch.tv/commands enables a bunch of miscellaneous command capabilities. See https://dev.twitch.tv/docs/irc/commands
|
||||
// twitch.tv/membership enables the JOIN/PART/NAMES commands. See https://dev.twitch.tv/docs/irc/membership
|
||||
// This is enabled so we receive USERSTATE messages when joining channels / typing messages, along with the other command capabilities
|
||||
QStringList caps{"twitch.tv/tags", "twitch.tv/commands"};
|
||||
if (type != ConnectionType::Write)
|
||||
{
|
||||
caps.push_back("twitch.tv/membership");
|
||||
}
|
||||
|
||||
connection->network()->setSkipCapabilityValidation(true);
|
||||
connection->network()->setRequestedCapabilities(caps);
|
||||
|
||||
QString username = account->getUserName();
|
||||
QString oauthToken = account->getOAuthToken();
|
||||
|
||||
|
@ -169,6 +182,10 @@ void TwitchIrcServer::readConnectionMessageReceived(
|
|||
"Twitch Servers requested us to reconnect, reconnecting");
|
||||
this->connect();
|
||||
}
|
||||
else if (command == "GLOBALUSERSTATE")
|
||||
{
|
||||
handler.handleGlobalUserStateMessage(message);
|
||||
}
|
||||
}
|
||||
|
||||
void TwitchIrcServer::writeConnectionMessageReceived(
|
||||
|
@ -219,28 +236,6 @@ void TwitchIrcServer::writeConnectionMessageReceived(
|
|||
}
|
||||
}
|
||||
|
||||
void TwitchIrcServer::onReadConnected(IrcConnection *connection)
|
||||
{
|
||||
// twitch.tv/tags enables IRCv3 tags on messages. See https://dev.twitch.tv/docs/irc/tags/
|
||||
// twitch.tv/membership enables the JOIN/PART/MODE/NAMES commands. See https://dev.twitch.tv/docs/irc/membership/
|
||||
// twitch.tv/commands enables a bunch of miscellaneous command capabilities. See https://dev.twitch.tv/docs/irc/commands/
|
||||
// This is enabled here so we receive USERSTATE messages when joining channels
|
||||
connection->sendRaw(
|
||||
"CAP REQ :twitch.tv/tags twitch.tv/membership twitch.tv/commands");
|
||||
|
||||
AbstractIrcServer::onReadConnected(connection);
|
||||
}
|
||||
|
||||
void TwitchIrcServer::onWriteConnected(IrcConnection *connection)
|
||||
{
|
||||
// twitch.tv/tags enables IRCv3 tags on messages. See https://dev.twitch.tv/docs/irc/tags/
|
||||
// twitch.tv/commands enables a bunch of miscellaneous command capabilities. See https://dev.twitch.tv/docs/irc/commands/
|
||||
// This is enabled here so we receive USERSTATE messages when typing messages, along with the other command capabilities
|
||||
connection->sendRaw("CAP REQ :twitch.tv/tags twitch.tv/commands");
|
||||
|
||||
AbstractIrcServer::onWriteConnected(connection);
|
||||
}
|
||||
|
||||
std::shared_ptr<Channel> TwitchIrcServer::getCustomChannel(
|
||||
const QString &channelName)
|
||||
{
|
||||
|
|
|
@ -56,9 +56,6 @@ protected:
|
|||
virtual void writeConnectionMessageReceived(
|
||||
Communi::IrcMessage *message) override;
|
||||
|
||||
virtual void onReadConnected(IrcConnection *connection) override;
|
||||
virtual void onWriteConnected(IrcConnection *connection) override;
|
||||
|
||||
virtual std::shared_ptr<Channel> getCustomChannel(
|
||||
const QString &channelname) override;
|
||||
|
||||
|
|
|
@ -11,10 +11,6 @@ Emotes::Emotes()
|
|||
|
||||
void Emotes::initialize(Settings &settings, Paths &paths)
|
||||
{
|
||||
getApp()->accounts->twitch.currentUserChanged.connect([] {
|
||||
getApp()->accounts->twitch.getCurrent()->loadEmotes();
|
||||
});
|
||||
|
||||
this->emojis.load();
|
||||
|
||||
this->gifTimer.initialize();
|
||||
|
|
Loading…
Reference in a new issue