feat: Live Emote Updates for 7TV (#4090)
Co-authored-by: Rasmus Karlsson <rasmus.karlsson@pajlada.com>
This commit is contained in:
@@ -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_;
|
||||
|
||||
Reference in New Issue
Block a user