feat: Live Emote Updates for 7TV (#4090)

Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
nerix
2022-11-13 12:07:41 +01:00
committed by GitHub
parent 8fa89b4073
commit 39f7d8ac4c
35 changed files with 1833 additions and 54 deletions
+209 -1
View File
@@ -11,6 +11,7 @@
#include "providers/bttv/BttvEmotes.hpp"
#include "providers/bttv/LoadBttvChannelEmote.hpp"
#include "providers/seventv/SeventvEmotes.hpp"
#include "providers/seventv/SeventvEventAPI.hpp"
#include "providers/twitch/IrcMessageHandler.hpp"
#include "providers/twitch/PubSubManager.hpp"
#include "providers/twitch/TwitchCommon.hpp"
@@ -104,6 +105,11 @@ TwitchChannel::TwitchChannel(const QString &name)
this->loadRecentMessagesReconnect();
});
this->destroyed.connect([this]() {
getApp()->twitch->dropSeventvChannel(this->seventvUserID_,
this->seventvEmoteSetID_);
});
this->messageRemovedFromStart.connect([this](MessagePtr &msg) {
if (msg->replyThread)
{
@@ -237,11 +243,16 @@ void TwitchChannel::refreshSevenTVChannelEmotes(bool manualRefresh)
SeventvEmotes::loadChannelEmotes(
weakOf<Channel>(this), this->roomId(),
[this, weak = weakOf<Channel>(this)](auto &&emoteMap) {
[this, weak = weakOf<Channel>(this)](auto &&emoteMap,
auto channelInfo) {
if (auto shared = weak.lock())
{
this->seventvEmotes_.set(std::make_shared<EmoteMap>(
std::forward<decltype(emoteMap)>(emoteMap)));
this->updateSeventvData(channelInfo.userID,
channelInfo.emoteSetID);
this->seventvUserTwitchConnectionIndex_ =
channelInfo.twitchConnectionIndex;
}
},
manualRefresh);
@@ -589,6 +600,203 @@ std::shared_ptr<const EmoteMap> TwitchChannel::seventvEmotes() const
return this->seventvEmotes_.get();
}
const QString &TwitchChannel::seventvUserID() const
{
return this->seventvUserID_;
}
const QString &TwitchChannel::seventvEmoteSetID() const
{
return this->seventvEmoteSetID_;
}
void TwitchChannel::addSeventvEmote(
const SeventvEventAPIEmoteAddDispatch &dispatch)
{
if (!SeventvEmotes::addEmote(this->seventvEmotes_, dispatch))
{
return;
}
this->addOrReplaceLiveUpdatesAddRemove(
true, "7TV", dispatch.actorName, dispatch.emoteJson["name"].toString());
}
void TwitchChannel::updateSeventvEmote(
const SeventvEventAPIEmoteUpdateDispatch &dispatch)
{
if (!SeventvEmotes::updateEmote(this->seventvEmotes_, dispatch))
{
return;
}
auto builder =
MessageBuilder(liveUpdatesUpdateEmoteMessage, "7TV", dispatch.actorName,
dispatch.emoteName, dispatch.oldEmoteName);
this->addMessage(builder.release());
}
void TwitchChannel::removeSeventvEmote(
const SeventvEventAPIEmoteRemoveDispatch &dispatch)
{
auto removed = SeventvEmotes::removeEmote(this->seventvEmotes_, dispatch);
if (!removed)
{
return;
}
this->addOrReplaceLiveUpdatesAddRemove(false, "7TV", dispatch.actorName,
removed.get()->name.string);
}
void TwitchChannel::updateSeventvUser(
const SeventvEventAPIUserConnectionUpdateDispatch &dispatch)
{
if (dispatch.connectionIndex != this->seventvUserTwitchConnectionIndex_)
{
// A different connection was updated
return;
}
updateSeventvData(this->seventvUserID_, dispatch.emoteSetID);
SeventvEmotes::getEmoteSet(
dispatch.emoteSetID,
[this, weak = weakOf<Channel>(this), dispatch](auto &&emotes,
const auto &name) {
postToThread([this, weak, dispatch, emotes, name]() {
if (auto shared = weak.lock())
{
this->seventvEmotes_.set(
std::make_shared<EmoteMap>(emotes));
auto builder =
MessageBuilder(liveUpdatesUpdateEmoteSetMessage, "7TV",
dispatch.actorName, name);
this->addMessage(builder.release());
}
});
},
[this, weak = weakOf<Channel>(this)](const auto &reason) {
postToThread([this, weak, reason]() {
if (auto shared = weak.lock())
{
this->seventvEmotes_.set(EMPTY_EMOTE_MAP);
this->addMessage(makeSystemMessage(
QString("Failed updating 7TV emote set (%1).")
.arg(reason)));
}
});
});
}
void TwitchChannel::updateSeventvData(const QString &newUserID,
const QString &newEmoteSetID)
{
if (this->seventvUserID_ == newUserID &&
this->seventvEmoteSetID_ == newEmoteSetID)
{
return;
}
boost::optional<QString> oldUserID = boost::make_optional(
!this->seventvUserID_.isEmpty() && this->seventvUserID_ != newUserID,
this->seventvUserID_);
boost::optional<QString> oldEmoteSetID =
boost::make_optional(!this->seventvEmoteSetID_.isEmpty() &&
this->seventvEmoteSetID_ != newEmoteSetID,
this->seventvEmoteSetID_);
this->seventvUserID_ = newUserID;
this->seventvEmoteSetID_ = newEmoteSetID;
runInGuiThread([this, oldUserID, oldEmoteSetID]() {
if (getApp()->twitch->seventvEventAPI)
{
getApp()->twitch->seventvEventAPI->subscribeUser(
this->seventvUserID_, this->seventvEmoteSetID_);
if (oldUserID || oldEmoteSetID)
{
getApp()->twitch->dropSeventvChannel(
oldUserID.get_value_or(QString()),
oldEmoteSetID.get_value_or(QString()));
}
}
});
}
void TwitchChannel::addOrReplaceLiveUpdatesAddRemove(bool isEmoteAdd,
const QString &platform,
const QString &actor,
const QString &emoteName)
{
if (this->tryReplaceLastLiveUpdateAddOrRemove(
isEmoteAdd ? MessageFlag::LiveUpdatesAdd
: MessageFlag::LiveUpdatesRemove,
platform, actor, emoteName))
{
return;
}
this->lastLiveUpdateEmoteNames_ = {emoteName};
MessagePtr msg;
if (isEmoteAdd)
{
msg = MessageBuilder(liveUpdatesAddEmoteMessage, platform, actor,
this->lastLiveUpdateEmoteNames_)
.release();
}
else
{
msg = MessageBuilder(liveUpdatesRemoveEmoteMessage, platform, actor,
this->lastLiveUpdateEmoteNames_)
.release();
}
this->lastLiveUpdateEmotePlatform_ = platform;
this->lastLiveUpdateMessage_ = msg;
this->lastLiveUpdateEmoteActor_ = actor;
this->addMessage(msg);
}
bool TwitchChannel::tryReplaceLastLiveUpdateAddOrRemove(
MessageFlag op, const QString &platform, const QString &actor,
const QString &emoteName)
{
if (this->lastLiveUpdateEmotePlatform_ != platform)
{
return false;
}
auto last = this->lastLiveUpdateMessage_.lock();
if (!last || !last->flags.has(op) ||
last->parseTime < QTime::currentTime().addSecs(-5) ||
last->loginName != actor)
{
return false;
}
// Update the message
this->lastLiveUpdateEmoteNames_.push_back(emoteName);
MessageBuilder replacement;
if (op == MessageFlag::LiveUpdatesAdd)
{
replacement =
MessageBuilder(liveUpdatesAddEmoteMessage, platform,
last->loginName, this->lastLiveUpdateEmoteNames_);
}
else // op == RemoveEmoteMessage
{
replacement =
MessageBuilder(liveUpdatesRemoveEmoteMessage, platform,
last->loginName, this->lastLiveUpdateEmoteNames_);
}
replacement->flags = last->flags;
auto msg = replacement.release();
this->lastLiveUpdateMessage_ = msg;
this->replaceMessage(last, msg);
return true;
}
const QString &TwitchChannel::subscriptionUrl()
{
return this->subscriptionUrl_;