From 3c9bcd581af16f0a77f1ab868df28353363280de Mon Sep 17 00:00:00 2001 From: pphop <1um6okote@gmail.com> Date: Fri, 26 Oct 2018 00:53:03 +0500 Subject: [PATCH] custom ffz moderator badges (#827) --- chatterino.pro | 6 +- src/providers/ffz/FfzModBadge.cpp | 86 +++++++++++++++++++ src/providers/ffz/FfzModBadge.hpp | 25 ++++++ src/providers/twitch/TwitchChannel.cpp | 10 +++ src/providers/twitch/TwitchChannel.hpp | 3 + src/providers/twitch/TwitchMessageBuilder.cpp | 9 +- 6 files changed, 136 insertions(+), 3 deletions(-) create mode 100644 src/providers/ffz/FfzModBadge.cpp create mode 100644 src/providers/ffz/FfzModBadge.hpp diff --git a/chatterino.pro b/chatterino.pro index a3053f543..c804e99e2 100644 --- a/chatterino.pro +++ b/chatterino.pro @@ -263,7 +263,8 @@ SOURCES += \ src/common/UsernameSet.cpp \ src/widgets/settingspages/AdvancedPage.cpp \ src/util/IncognitoBrowser.cpp \ - src/widgets/splits/ClosedSplits.cpp + src/widgets/splits/ClosedSplits.cpp \ + src/providers/ffz/FfzModBadge.cpp HEADERS += \ src/Application.hpp \ @@ -466,7 +467,8 @@ HEADERS += \ src/common/UsernameSet.hpp \ src/widgets/settingspages/AdvancedPage.hpp \ src/util/IncognitoBrowser.hpp \ - src/widgets/splits/ClosedSplits.hpp + src/widgets/splits/ClosedSplits.hpp \ + src/providers/ffz/FfzModBadge.hpp RESOURCES += \ resources/resources.qrc \ diff --git a/src/providers/ffz/FfzModBadge.cpp b/src/providers/ffz/FfzModBadge.cpp new file mode 100644 index 000000000..af08bb60f --- /dev/null +++ b/src/providers/ffz/FfzModBadge.cpp @@ -0,0 +1,86 @@ +#include "FfzModBadge.hpp" + +#include +#include +#include +#include +#include + +#include "common/NetworkRequest.hpp" +#include "common/Outcome.hpp" +#include "messages/Emote.hpp" + +namespace chatterino { + +FfzModBadge::FfzModBadge(const QString &channelName) + : channelName_(channelName) +{ +} + +void FfzModBadge::loadCustomModBadge() +{ + static QString partialUrl("https://api.frankerfacez.com/v1/_room/"); + + QString url = partialUrl + channelName_; + NetworkRequest req(url); + req.setCaller(QThread::currentThread()); + req.onSuccess([this](auto result) -> Outcome { + auto root = result.parseJson(); + + auto modBadgeUrlField = + root.value("room").toObject().value("moderator_badge"); + if (modBadgeUrlField.isNull()) + return Failure; + + auto badgeUrl = "https:" + modBadgeUrlField.toString(); + /* doesnt work for some reason + auto badgeOverlay = + Image::fromUrl({"https:" + modBadgeUrlField.toString()}); + auto badgeOverlayPixmap = badgeOverlay->pixmap(); + if (!badgeOverlayPixmap) + return Failure; + */ + NetworkRequest getBadge(badgeUrl); + getBadge.setCaller(QThread::currentThread()); + getBadge.onSuccess([this, &badgeUrl](auto result) -> Outcome { + auto data = result.getData(); + + QBuffer buffer(const_cast(&data)); + buffer.open(QIODevice::ReadOnly); + QImageReader reader(&buffer); + if (reader.imageCount() == 0) + return Failure; + auto badgeOverlay = QPixmap::fromImageReader(&reader); + + QPixmap badgePixmap(18, 18); + // the default mod badge green color + badgePixmap.fill(QColor("#34AE0A")); + + QPainter painter(&badgePixmap); + QRectF rect(0, 0, 18, 18); + painter.drawPixmap(rect, badgeOverlay, rect); + + auto emote = Emote{{""}, + ImageSet{Image::fromPixmap(badgePixmap)}, + Tooltip{"Twitch Channel Moderator"}, + Url{badgeUrl}}; + + this->badge_ = std::make_shared(emote); + + return Success; + }); + + getBadge.execute(); + + return Success; + }); + + req.execute(); +} + +EmotePtr FfzModBadge::badge() const +{ + return this->badge_; +} + +} // namespace chatterino diff --git a/src/providers/ffz/FfzModBadge.hpp b/src/providers/ffz/FfzModBadge.hpp new file mode 100644 index 000000000..859cb1a10 --- /dev/null +++ b/src/providers/ffz/FfzModBadge.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include + +namespace chatterino { + +struct Emote; +using EmotePtr = std::shared_ptr; + +class FfzModBadge +{ +public: + FfzModBadge(const QString &channelName); + + void loadCustomModBadge(); + + EmotePtr badge() const; + +private: + const QString channelName_; + EmotePtr badge_; +}; + +} // namespace chatterino diff --git a/src/providers/twitch/TwitchChannel.cpp b/src/providers/twitch/TwitchChannel.cpp index e983c8a42..ecee718ae 100644 --- a/src/providers/twitch/TwitchChannel.cpp +++ b/src/providers/twitch/TwitchChannel.cpp @@ -91,6 +91,7 @@ TwitchChannel::TwitchChannel(const QString &name, , globalFfz_(ffz) , bttvEmotes_(std::make_shared()) , ffzEmotes_(std::make_shared()) + , ffzCustomModBadge_(name) , mod_(false) { log("[TwitchChannel:{}] Opened", name); @@ -143,6 +144,7 @@ void TwitchChannel::initialize() { this->refreshChatters(); this->refreshChannelEmotes(); + this->ffzCustomModBadge_.loadCustomModBadge(); } bool TwitchChannel::isEmpty() const @@ -783,4 +785,12 @@ boost::optional TwitchChannel::twitchBadge( return boost::none; } +boost::optional TwitchChannel::ffzCustomModBadge() const +{ + if (auto badge = this->ffzCustomModBadge_.badge()) + return badge; + + return boost::none; +} + } // namespace chatterino diff --git a/src/providers/twitch/TwitchChannel.hpp b/src/providers/twitch/TwitchChannel.hpp index edc6b7af2..15ec0c476 100644 --- a/src/providers/twitch/TwitchChannel.hpp +++ b/src/providers/twitch/TwitchChannel.hpp @@ -6,6 +6,7 @@ #include "common/Outcome.hpp" #include "common/UniqueAccess.hpp" #include "common/UsernameSet.hpp" +#include "providers/ffz/FfzModBadge.hpp" #include "providers/twitch/TwitchEmotes.hpp" #include @@ -84,6 +85,7 @@ public: void refreshChannelEmotes(); // Badges + boost::optional ffzCustomModBadge() const; boost::optional twitchBadge(const QString &set, const QString &version) const; @@ -141,6 +143,7 @@ private: UniqueAccess>> badgeSets_; // "subscribers": { "0": ... "3": ... "6": ... UniqueAccess> cheerEmoteSets_; + FfzModBadge ffzCustomModBadge_; bool mod_ = false; UniqueAccess roomID_; diff --git a/src/providers/twitch/TwitchMessageBuilder.cpp b/src/providers/twitch/TwitchMessageBuilder.cpp index 1f17728ca..cdf41093f 100644 --- a/src/providers/twitch/TwitchMessageBuilder.cpp +++ b/src/providers/twitch/TwitchMessageBuilder.cpp @@ -1107,7 +1107,14 @@ void TwitchMessageBuilder::appendTwitchBadges() } else if (badge == "moderator/1") { - // TODO: Implement custom FFZ moderator badge + if (auto customModBadge = this->twitchChannel->ffzCustomModBadge()) + { + this->emplace( + customModBadge.get(), + MessageElementFlag::BadgeChannelAuthority) + ->setTooltip((*customModBadge)->tooltip.string); + continue; + } this->emplace( Image::fromPixmap(app->resources->twitch.moderator), MessageElementFlag::BadgeChannelAuthority)