Added custom FrankerFaceZ VIP badges (#2628)

Co-authored-by: pajlada <rasmus.karlsson@pajlada.com>
This commit is contained in:
Paweł
2021-04-17 14:42:30 +02:00
committed by GitHub
parent 2f906c5504
commit ed7d1a88d0
8 changed files with 85 additions and 21 deletions
+1
View File
@@ -2,6 +2,7 @@
## Unversioned ## Unversioned
- Major: Added custom FrankerFaceZ VIP Badges. (#2628)
- Minor: Added `in:<channels>` search filter to find messages sent in specific channels. (#2299, #2634) - Minor: Added `in:<channels>` search filter to find messages sent in specific channels. (#2299, #2634)
- Minor: Allow for built-in Chatterino commands to be used in custom commands. (#2632) - Minor: Allow for built-in Chatterino commands to be used in custom commands. (#2632)
- Bugfix: Fix crash that could occur when the user changed the "Custom stream player URI Scheme" setting if the user had closed down and splits in the application runtime. (#2592) - Bugfix: Fix crash that could occur when the user changed the "Custom stream player URI Scheme" setting if the user had closed down and splits in the application runtime. (#2592)
+16
View File
@@ -253,6 +253,22 @@ MessageLayoutElement *ModBadgeElement::makeImageLayoutElement(
return element; return element;
} }
// VIP BADGE
VipBadgeElement::VipBadgeElement(const EmotePtr &data,
MessageElementFlags flags_)
: BadgeElement(data, flags_)
{
}
MessageLayoutElement *VipBadgeElement::makeImageLayoutElement(
const ImagePtr &image, const QSize &size)
{
auto element =
(new ImageLayoutElement(*this, image, size))->setLink(this->getLink());
return element;
}
// FFZ Badge // FFZ Badge
FfzBadgeElement::FfzBadgeElement(const EmotePtr &data, FfzBadgeElement::FfzBadgeElement(const EmotePtr &data,
MessageElementFlags flags_, QColor &color) MessageElementFlags flags_, QColor &color)
+11
View File
@@ -60,6 +60,7 @@ enum class MessageElementFlag : int64_t {
BadgeGlobalAuthority = (1LL << 14), BadgeGlobalAuthority = (1LL << 14),
// Slot 2: Twitch // Slot 2: Twitch
// - VIP badge
// - Moderator badge // - Moderator badge
// - Broadcaster badge // - Broadcaster badge
BadgeChannelAuthority = (1LL << 15), BadgeChannelAuthority = (1LL << 15),
@@ -275,6 +276,16 @@ protected:
const QSize &size) override; const QSize &size) override;
}; };
class VipBadgeElement : public BadgeElement
{
public:
VipBadgeElement(const EmotePtr &data, MessageElementFlags flags_);
protected:
MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image,
const QSize &size) override;
};
class FfzBadgeElement : public BadgeElement class FfzBadgeElement : public BadgeElement
{ {
public: public:
+31 -21
View File
@@ -86,34 +86,36 @@ namespace {
return {Success, std::move(emotes)}; return {Success, std::move(emotes)};
} }
boost::optional<EmotePtr> parseModBadge(const QJsonObject &jsonRoot) boost::optional<EmotePtr> parseAuthorityBadge(const QJsonObject &badgeUrls,
const QString tooltip)
{ {
boost::optional<EmotePtr> modBadge; boost::optional<EmotePtr> authorityBadge;
auto room = jsonRoot.value("room").toObject(); qDebug() << badgeUrls;
auto modUrls = room.value("mod_urls").toObject(); if (!badgeUrls.isEmpty())
if (!modUrls.isEmpty())
{ {
auto modBadge1x = getEmoteLink(modUrls, "1"); auto authorityBadge1x = getEmoteLink(badgeUrls, "1");
auto modBadge2x = getEmoteLink(modUrls, "2"); auto authorityBadge2x = getEmoteLink(badgeUrls, "2");
auto modBadge3x = getEmoteLink(modUrls, "4"); auto authorityBadge3x = getEmoteLink(badgeUrls, "4");
auto modBadgeImageSet = ImageSet{ auto authorityBadgeImageSet = ImageSet{
Image::fromUrl(modBadge1x, 1), Image::fromUrl(authorityBadge1x, 1),
modBadge2x.string.isEmpty() ? Image::getEmpty() authorityBadge2x.string.isEmpty()
: Image::fromUrl(modBadge2x, 0.5), ? Image::getEmpty()
modBadge3x.string.isEmpty() ? Image::getEmpty() : Image::fromUrl(authorityBadge2x, 0.5),
: Image::fromUrl(modBadge3x, 0.25), authorityBadge3x.string.isEmpty()
? Image::getEmpty()
: Image::fromUrl(authorityBadge3x, 0.25),
}; };
modBadge = std::make_shared<Emote>(Emote{ authorityBadge = std::make_shared<Emote>(Emote{
{""}, {""},
modBadgeImageSet, authorityBadgeImageSet,
Tooltip{"Moderator"}, Tooltip{tooltip},
modBadge1x, authorityBadge1x,
}); });
} }
return modBadge; return authorityBadge;
} }
EmoteMap parseChannelEmotes(const QJsonObject &jsonRoot) EmoteMap parseChannelEmotes(const QJsonObject &jsonRoot)
@@ -199,6 +201,7 @@ void FfzEmotes::loadChannel(
std::weak_ptr<Channel> channel, const QString &channelId, std::weak_ptr<Channel> channel, const QString &channelId,
std::function<void(EmoteMap &&)> emoteCallback, std::function<void(EmoteMap &&)> emoteCallback,
std::function<void(boost::optional<EmotePtr>)> modBadgeCallback, std::function<void(boost::optional<EmotePtr>)> modBadgeCallback,
std::function<void(boost::optional<EmotePtr>)> vipBadgeCallback,
bool manualRefresh) bool manualRefresh)
{ {
qCDebug(chatterinoFfzemotes) qCDebug(chatterinoFfzemotes)
@@ -208,16 +211,23 @@ void FfzEmotes::loadChannel(
.timeout(20000) .timeout(20000)
.onSuccess([emoteCallback = std::move(emoteCallback), .onSuccess([emoteCallback = std::move(emoteCallback),
modBadgeCallback = std::move(modBadgeCallback), channel, modBadgeCallback = std::move(modBadgeCallback),
vipBadgeCallback = std::move(vipBadgeCallback), channel,
manualRefresh](auto result) -> Outcome { manualRefresh](auto result) -> Outcome {
auto json = result.parseJson(); auto json = result.parseJson();
auto emoteMap = parseChannelEmotes(json); auto emoteMap = parseChannelEmotes(json);
auto modBadge = parseModBadge(json); auto modBadge = parseAuthorityBadge(
json.value("room").toObject().value("mod_urls").toObject(),
"Moderator");
auto vipBadge = parseAuthorityBadge(
json.value("room").toObject().value("vip_badge").toObject(),
"VIP");
bool hasEmotes = !emoteMap.empty(); bool hasEmotes = !emoteMap.empty();
emoteCallback(std::move(emoteMap)); emoteCallback(std::move(emoteMap));
modBadgeCallback(std::move(modBadge)); modBadgeCallback(std::move(modBadge));
vipBadgeCallback(std::move(vipBadge));
if (auto shared = channel.lock(); manualRefresh) if (auto shared = channel.lock(); manualRefresh)
{ {
if (hasEmotes) if (hasEmotes)
+1
View File
@@ -27,6 +27,7 @@ public:
std::weak_ptr<Channel> channel, const QString &channelId, std::weak_ptr<Channel> channel, const QString &channelId,
std::function<void(EmoteMap &&)> emoteCallback, std::function<void(EmoteMap &&)> emoteCallback,
std::function<void(boost::optional<EmotePtr>)> modBadgeCallback, std::function<void(boost::optional<EmotePtr>)> modBadgeCallback,
std::function<void(boost::optional<EmotePtr>)> vipBadgeCallback,
bool manualRefresh); bool manualRefresh);
private: private:
+11
View File
@@ -269,6 +269,12 @@ void TwitchChannel::refreshFFZChannelEmotes(bool manualRefresh)
this->ffzCustomModBadge_.set(std::move(modBadge)); this->ffzCustomModBadge_.set(std::move(modBadge));
} }
}, },
[this, weak = weakOf<Channel>(this)](auto &&vipBadge) {
if (auto shared = weak.lock())
{
this->ffzCustomVipBadge_.set(std::move(vipBadge));
}
},
manualRefresh); manualRefresh);
} }
@@ -1067,6 +1073,11 @@ boost::optional<EmotePtr> TwitchChannel::ffzCustomModBadge() const
return this->ffzCustomModBadge_.get(); return this->ffzCustomModBadge_.get();
} }
boost::optional<EmotePtr> TwitchChannel::ffzCustomVipBadge() const
{
return this->ffzCustomVipBadge_.get();
}
boost::optional<CheerEmote> TwitchChannel::cheerEmote(const QString &string) boost::optional<CheerEmote> TwitchChannel::cheerEmote(const QString &string)
{ {
auto sets = this->cheerEmoteSets_.access(); auto sets = this->cheerEmoteSets_.access();
+2
View File
@@ -100,6 +100,7 @@ public:
// Badges // Badges
boost::optional<EmotePtr> ffzCustomModBadge() const; boost::optional<EmotePtr> ffzCustomModBadge() const;
boost::optional<EmotePtr> ffzCustomVipBadge() const;
boost::optional<EmotePtr> twitchBadge(const QString &set, boost::optional<EmotePtr> twitchBadge(const QString &set,
const QString &version) const; const QString &version) const;
@@ -171,6 +172,7 @@ protected:
Atomic<std::shared_ptr<const EmoteMap>> bttvEmotes_; Atomic<std::shared_ptr<const EmoteMap>> bttvEmotes_;
Atomic<std::shared_ptr<const EmoteMap>> ffzEmotes_; Atomic<std::shared_ptr<const EmoteMap>> ffzEmotes_;
Atomic<boost::optional<EmotePtr>> ffzCustomModBadge_; Atomic<boost::optional<EmotePtr>> ffzCustomModBadge_;
Atomic<boost::optional<EmotePtr>> ffzCustomVipBadge_;
private: private:
// Badges // Badges
@@ -1128,6 +1128,18 @@ void TwitchMessageBuilder::appendTwitchBadges()
continue; continue;
} }
} }
else if (badge.key_ == "vip")
{
if (auto customVipBadge = this->twitchChannel->ffzCustomVipBadge())
{
this->emplace<VipBadgeElement>(
customVipBadge.get(),
MessageElementFlag::BadgeChannelAuthority)
->setTooltip((*customVipBadge)->tooltip.string);
// early out, since we have to add a custom badge element here
continue;
}
}
else if (badge.flag_ == MessageElementFlag::BadgeSubscription) else if (badge.flag_ == MessageElementFlag::BadgeSubscription)
{ {
auto badgeInfoIt = badgeInfos.find(badge.key_); auto badgeInfoIt = badgeInfos.find(badge.key_);