mirror of
https://github.com/Chatterino/chatterino2.git
synced 2024-11-13 19:49:51 +01:00
Add support FrankerFaceZ badges. (#2101)
On startup, we poll https://api.frankerfacez.com/v1/badges/ids and store the mappings of user IDs to badges for the remainder of the applications lifetime.
This commit is contained in:
parent
ec94869480
commit
3ee08b9ffd
|
@ -2,6 +2,7 @@
|
|||
|
||||
## Unversioned
|
||||
|
||||
- Minor: Added support for FrankerFaceZ badges. (#2101, part of #1658)
|
||||
- Minor: Added a navigation list to the settings and reordered them.
|
||||
- Major: Added "Channel Filters". See https://wiki.chatterino.com/Filters/ for how they work or how to configure them. (#1748, #2083)
|
||||
- Major: Added Streamer Mode configuration (under `Settings -> General`), where you can select which features of Chatterino should behave differently when you are in Streamer Mode. (#2001)
|
||||
|
|
|
@ -170,6 +170,7 @@ SOURCES += \
|
|||
src/providers/chatterino/ChatterinoBadges.cpp \
|
||||
src/providers/colors/ColorProvider.cpp \
|
||||
src/providers/emoji/Emojis.cpp \
|
||||
src/providers/ffz/FfzBadges.cpp \
|
||||
src/providers/ffz/FfzEmotes.cpp \
|
||||
src/providers/irc/AbstractIrcServer.cpp \
|
||||
src/providers/irc/Irc2.cpp \
|
||||
|
@ -396,6 +397,7 @@ HEADERS += \
|
|||
src/providers/chatterino/ChatterinoBadges.hpp \
|
||||
src/providers/colors/ColorProvider.hpp \
|
||||
src/providers/emoji/Emojis.hpp \
|
||||
src/providers/ffz/FfzBadges.hpp \
|
||||
src/providers/ffz/FfzEmotes.hpp \
|
||||
src/providers/irc/AbstractIrcServer.hpp \
|
||||
src/providers/irc/Irc2.hpp \
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "messages/MessageBuilder.hpp"
|
||||
#include "providers/bttv/BttvEmotes.hpp"
|
||||
#include "providers/chatterino/ChatterinoBadges.hpp"
|
||||
#include "providers/ffz/FfzBadges.hpp"
|
||||
#include "providers/ffz/FfzEmotes.hpp"
|
||||
#include "providers/irc/Irc2.hpp"
|
||||
#include "providers/twitch/PubsubClient.hpp"
|
||||
|
@ -55,6 +56,7 @@ Application::Application(Settings &_settings, Paths &_paths)
|
|||
, notifications(&this->emplace<NotificationController>())
|
||||
, twitch2(&this->emplace<TwitchIrcServer>())
|
||||
, chatterinoBadges(&this->emplace<ChatterinoBadges>())
|
||||
, ffzBadges(&this->emplace<FfzBadges>())
|
||||
, logging(&this->emplace<Logging>())
|
||||
{
|
||||
this->instance = this;
|
||||
|
|
|
@ -26,6 +26,7 @@ class Settings;
|
|||
class Fonts;
|
||||
class Toasts;
|
||||
class ChatterinoBadges;
|
||||
class FfzBadges;
|
||||
|
||||
class Application
|
||||
{
|
||||
|
@ -57,6 +58,7 @@ public:
|
|||
NotificationController *const notifications{};
|
||||
TwitchIrcServer *const twitch2{};
|
||||
ChatterinoBadges *const chatterinoBadges{};
|
||||
FfzBadges *const ffzBadges{};
|
||||
|
||||
/*[[deprecated]]*/ Logging *const logging{};
|
||||
|
||||
|
|
|
@ -253,6 +253,24 @@ MessageLayoutElement *ModBadgeElement::makeImageLayoutElement(
|
|||
return element;
|
||||
}
|
||||
|
||||
// FFZ Badge
|
||||
FfzBadgeElement::FfzBadgeElement(const EmotePtr &data,
|
||||
MessageElementFlags flags_, QColor &color)
|
||||
: BadgeElement(data, flags_)
|
||||
{
|
||||
this->color = color;
|
||||
}
|
||||
|
||||
MessageLayoutElement *FfzBadgeElement::makeImageLayoutElement(
|
||||
const ImagePtr &image, const QSize &size)
|
||||
{
|
||||
auto element =
|
||||
(new ImageWithBackgroundLayoutElement(*this, image, size, this->color))
|
||||
->setLink(this->getLink());
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
// TEXT
|
||||
TextElement::TextElement(const QString &text, MessageElementFlags flags,
|
||||
const MessageColor &color, FontStyle style)
|
||||
|
|
|
@ -26,91 +26,99 @@ using ImagePtr = std::shared_ptr<Image>;
|
|||
struct Emote;
|
||||
using EmotePtr = std::shared_ptr<const Emote>;
|
||||
|
||||
enum class MessageElementFlag {
|
||||
None = 0,
|
||||
Misc = (1 << 0),
|
||||
Text = (1 << 1),
|
||||
enum class MessageElementFlag : int64_t {
|
||||
None = 0LL,
|
||||
Misc = (1LL << 0),
|
||||
Text = (1LL << 1),
|
||||
|
||||
Username = (1 << 2),
|
||||
Timestamp = (1 << 3),
|
||||
Username = (1LL << 2),
|
||||
Timestamp = (1LL << 3),
|
||||
|
||||
TwitchEmoteImage = (1 << 4),
|
||||
TwitchEmoteText = (1 << 5),
|
||||
TwitchEmoteImage = (1LL << 4),
|
||||
TwitchEmoteText = (1LL << 5),
|
||||
TwitchEmote = TwitchEmoteImage | TwitchEmoteText,
|
||||
BttvEmoteImage = (1 << 6),
|
||||
BttvEmoteText = (1 << 7),
|
||||
BttvEmoteImage = (1LL << 6),
|
||||
BttvEmoteText = (1LL << 7),
|
||||
BttvEmote = BttvEmoteImage | BttvEmoteText,
|
||||
|
||||
ChannelPointReward = (1 << 8),
|
||||
ChannelPointReward = (1LL << 8),
|
||||
ChannelPointRewardImage = ChannelPointReward | TwitchEmoteImage,
|
||||
|
||||
FfzEmoteImage = (1 << 10),
|
||||
FfzEmoteText = (1 << 11),
|
||||
FfzEmoteImage = (1LL << 10),
|
||||
FfzEmoteText = (1LL << 11),
|
||||
FfzEmote = FfzEmoteImage | FfzEmoteText,
|
||||
EmoteImages = TwitchEmoteImage | BttvEmoteImage | FfzEmoteImage,
|
||||
EmoteText = TwitchEmoteText | BttvEmoteText | FfzEmoteText,
|
||||
|
||||
BitsStatic = (1 << 12),
|
||||
BitsAnimated = (1 << 13),
|
||||
BitsStatic = (1LL << 12),
|
||||
BitsAnimated = (1LL << 13),
|
||||
|
||||
// Slot 1: Twitch
|
||||
// - Staff badge
|
||||
// - Admin badge
|
||||
// - Global Moderator badge
|
||||
BadgeGlobalAuthority = (1 << 14),
|
||||
BadgeGlobalAuthority = (1LL << 14),
|
||||
|
||||
// Slot 2: Twitch
|
||||
// - Moderator badge
|
||||
// - Broadcaster badge
|
||||
BadgeChannelAuthority = (1 << 15),
|
||||
BadgeChannelAuthority = (1LL << 15),
|
||||
|
||||
// Slot 3: Twitch
|
||||
// - Subscription badges
|
||||
BadgeSubscription = (1 << 16),
|
||||
BadgeSubscription = (1LL << 16),
|
||||
|
||||
// Slot 4: Twitch
|
||||
// - Turbo badge
|
||||
// - Prime badge
|
||||
// - Bit badges
|
||||
// - Game badges
|
||||
BadgeVanity = (1 << 17),
|
||||
BadgeVanity = (1LL << 17),
|
||||
|
||||
// Slot 5: Chatterino
|
||||
// - Chatterino developer badge
|
||||
// - Chatterino donator badge
|
||||
// - Chatterino top donator badge
|
||||
BadgeChatterino = (1 << 18),
|
||||
BadgeChatterino = (1LL << 18),
|
||||
|
||||
// Slot 6: FrankerFaceZ
|
||||
// - FFZ developer badge
|
||||
// - FFZ bot badge
|
||||
// - FFZ donator badge
|
||||
BadgeFfz = (1LL << 32),
|
||||
|
||||
Badges = BadgeGlobalAuthority | BadgeChannelAuthority | BadgeSubscription |
|
||||
BadgeVanity | BadgeChatterino,
|
||||
BadgeVanity | BadgeChatterino | BadgeFfz,
|
||||
|
||||
ChannelName = (1 << 19),
|
||||
ChannelName = (1LL << 19),
|
||||
|
||||
BitsAmount = (1 << 20),
|
||||
BitsAmount = (1LL << 20),
|
||||
|
||||
ModeratorTools = (1 << 21),
|
||||
ModeratorTools = (1LL << 21),
|
||||
|
||||
EmojiImage = (1 << 23),
|
||||
EmojiText = (1 << 24),
|
||||
EmojiImage = (1LL << 23),
|
||||
EmojiText = (1LL << 24),
|
||||
EmojiAll = EmojiImage | EmojiText,
|
||||
|
||||
AlwaysShow = (1 << 25),
|
||||
AlwaysShow = (1LL << 25),
|
||||
|
||||
// used in the ChannelView class to make the collapse buttons visible if
|
||||
// needed
|
||||
Collapsed = (1 << 26),
|
||||
Collapsed = (1LL << 26),
|
||||
|
||||
// used for dynamic bold usernames
|
||||
BoldUsername = (1 << 27),
|
||||
NonBoldUsername = (1 << 28),
|
||||
BoldUsername = (1LL << 27),
|
||||
NonBoldUsername = (1LL << 28),
|
||||
|
||||
// for links
|
||||
LowercaseLink = (1 << 29),
|
||||
OriginalLink = (1 << 30),
|
||||
LowercaseLink = (1LL << 29),
|
||||
OriginalLink = (1LL << 30),
|
||||
|
||||
// ZeroWidthEmotes are emotes that are supposed to overlay over any pre-existing emotes
|
||||
// e.g. BTTV's SoSnowy during christmas season
|
||||
ZeroWidthEmote = (1 << 31),
|
||||
ZeroWidthEmote = (1LL << 31),
|
||||
|
||||
// (1LL << 32) is used by BadgeFfz, it is next to BadgeChatterino
|
||||
|
||||
Default = Timestamp | Badges | Username | BitsStatic | FfzEmoteImage |
|
||||
BttvEmoteImage | TwitchEmoteImage | BitsAmount | Text |
|
||||
|
@ -267,6 +275,18 @@ protected:
|
|||
const QSize &size) override;
|
||||
};
|
||||
|
||||
class FfzBadgeElement : public BadgeElement
|
||||
{
|
||||
public:
|
||||
FfzBadgeElement(const EmotePtr &data, MessageElementFlags flags_,
|
||||
QColor &color);
|
||||
|
||||
protected:
|
||||
MessageLayoutElement *makeImageLayoutElement(const ImagePtr &image,
|
||||
const QSize &size) override;
|
||||
QColor color;
|
||||
};
|
||||
|
||||
// contains a text, formated depending on the preferences
|
||||
class TimestampElement : public MessageElement
|
||||
{
|
||||
|
|
|
@ -17,7 +17,7 @@ struct Selection;
|
|||
struct MessageLayoutContainer;
|
||||
class MessageLayoutElement;
|
||||
|
||||
enum class MessageElementFlag;
|
||||
enum class MessageElementFlag : int64_t;
|
||||
using MessageElementFlags = FlagsEnum<MessageElementFlag>;
|
||||
|
||||
enum class MessageLayoutFlag : uint8_t {
|
||||
|
|
89
src/providers/ffz/FfzBadges.cpp
Normal file
89
src/providers/ffz/FfzBadges.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
#include "FfzBadges.hpp"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QThread>
|
||||
#include "common/NetworkRequest.hpp"
|
||||
#include "common/Outcome.hpp"
|
||||
#include "messages/Emote.hpp"
|
||||
|
||||
#include <QUrl>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
void FfzBadges::initialize(Settings &settings, Paths &paths)
|
||||
{
|
||||
this->loadFfzBadges();
|
||||
}
|
||||
|
||||
boost::optional<EmotePtr> FfzBadges::getBadge(const UserId &id)
|
||||
{
|
||||
auto it = this->badgeMap.find(id.string);
|
||||
if (it != this->badgeMap.end())
|
||||
{
|
||||
return this->badges[it->second];
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
boost::optional<QColor> FfzBadges::getBadgeColor(const UserId &id)
|
||||
{
|
||||
auto badgeIt = this->badgeMap.find(id.string);
|
||||
if (badgeIt != this->badgeMap.end())
|
||||
{
|
||||
auto colorIt = this->colorMap.find(badgeIt->second);
|
||||
if (colorIt != this->colorMap.end())
|
||||
{
|
||||
return colorIt->second;
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
void FfzBadges::loadFfzBadges()
|
||||
{
|
||||
static QUrl url("https://api.frankerfacez.com/v1/badges/ids");
|
||||
|
||||
NetworkRequest(url)
|
||||
.onSuccess([this](auto result) -> Outcome {
|
||||
auto jsonRoot = result.parseJson();
|
||||
int index = 0;
|
||||
for (const auto &jsonBadge_ : jsonRoot.value("badges").toArray())
|
||||
{
|
||||
auto jsonBadge = jsonBadge_.toObject();
|
||||
auto jsonUrls = jsonBadge.value("urls").toObject();
|
||||
|
||||
auto emote = Emote{
|
||||
EmoteName{},
|
||||
ImageSet{
|
||||
Url{QString("https:") + jsonUrls.value("1").toString()},
|
||||
Url{QString("https:") + jsonUrls.value("2").toString()},
|
||||
Url{QString("https:") +
|
||||
jsonUrls.value("4").toString()}},
|
||||
Tooltip{jsonBadge.value("title").toString()}, Url{}};
|
||||
|
||||
this->badges.push_back(
|
||||
std::make_shared<const Emote>(std::move(emote)));
|
||||
this->colorMap[index] =
|
||||
QColor(jsonBadge.value("color").toString());
|
||||
|
||||
auto badgeId = QString::number(jsonBadge.value("id").toInt());
|
||||
for (const auto &user : jsonRoot.value("users")
|
||||
.toObject()
|
||||
.value(badgeId)
|
||||
.toArray())
|
||||
{
|
||||
this->badgeMap[QString::number(user.toInt())] = index;
|
||||
}
|
||||
++index;
|
||||
}
|
||||
|
||||
return Success;
|
||||
})
|
||||
.execute();
|
||||
}
|
||||
|
||||
} // namespace chatterino
|
32
src/providers/ffz/FfzBadges.hpp
Normal file
32
src/providers/ffz/FfzBadges.hpp
Normal file
|
@ -0,0 +1,32 @@
|
|||
#pragma once
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <common/Singleton.hpp>
|
||||
|
||||
#include "common/Aliases.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace chatterino {
|
||||
|
||||
struct Emote;
|
||||
using EmotePtr = std::shared_ptr<const Emote>;
|
||||
|
||||
class FfzBadges : public Singleton
|
||||
{
|
||||
public:
|
||||
virtual void initialize(Settings &settings, Paths &paths) override;
|
||||
FfzBadges() = default;
|
||||
|
||||
boost::optional<EmotePtr> getBadge(const UserId &id);
|
||||
boost::optional<QColor> getBadgeColor(const UserId &id);
|
||||
|
||||
private:
|
||||
void loadFfzBadges();
|
||||
std::map<QString, int> badgeMap;
|
||||
std::vector<EmotePtr> badges;
|
||||
std::map<int, QColor> colorMap;
|
||||
};
|
||||
|
||||
} // namespace chatterino
|
|
@ -6,6 +6,7 @@
|
|||
#include "controllers/ignores/IgnorePhrase.hpp"
|
||||
#include "messages/Message.hpp"
|
||||
#include "providers/chatterino/ChatterinoBadges.hpp"
|
||||
#include "providers/ffz/FfzBadges.hpp"
|
||||
#include "providers/twitch/TwitchBadges.hpp"
|
||||
#include "providers/twitch/TwitchChannel.hpp"
|
||||
#include "providers/twitch/TwitchCommon.hpp"
|
||||
|
@ -255,6 +256,7 @@ MessagePtr TwitchMessageBuilder::build()
|
|||
this->appendTwitchBadges();
|
||||
|
||||
this->appendChatterinoBadges();
|
||||
this->appendFfzBadges();
|
||||
|
||||
this->appendUsername();
|
||||
|
||||
|
@ -1090,6 +1092,18 @@ void TwitchMessageBuilder::appendChatterinoBadges()
|
|||
}
|
||||
}
|
||||
|
||||
void TwitchMessageBuilder::appendFfzBadges()
|
||||
{
|
||||
if (auto badge = getApp()->ffzBadges->getBadge({this->userId_}))
|
||||
{
|
||||
if (auto color = getApp()->ffzBadges->getBadgeColor({this->userId_}))
|
||||
{
|
||||
this->emplace<FfzBadgeElement>(*badge, MessageElementFlag::BadgeFfz,
|
||||
color.get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Outcome TwitchMessageBuilder::tryParseCheermote(const QString &string)
|
||||
{
|
||||
if (this->bitsLeft == 0)
|
||||
|
|
|
@ -75,6 +75,7 @@ private:
|
|||
|
||||
void appendTwitchBadges();
|
||||
void appendChatterinoBadges();
|
||||
void appendFfzBadges();
|
||||
Outcome tryParseCheermote(const QString &string);
|
||||
|
||||
QString roomID_;
|
||||
|
|
|
@ -127,6 +127,7 @@ public:
|
|||
true};
|
||||
BoolSetting showBadgesVanity = {"/appearance/badges/vanity", true};
|
||||
BoolSetting showBadgesChatterino = {"/appearance/badges/chatterino", true};
|
||||
BoolSetting showBadgesFfz = {"/appearance/badges/ffz", true};
|
||||
|
||||
/// Behaviour
|
||||
BoolSetting allowDuplicateMessages = {"/behaviour/allowDuplicateMessages",
|
||||
|
|
|
@ -93,6 +93,7 @@ WindowManager::WindowManager()
|
|||
this->wordFlagsListener_.addSetting(settings->showBadgesSubscription);
|
||||
this->wordFlagsListener_.addSetting(settings->showBadgesVanity);
|
||||
this->wordFlagsListener_.addSetting(settings->showBadgesChatterino);
|
||||
this->wordFlagsListener_.addSetting(settings->showBadgesFfz);
|
||||
this->wordFlagsListener_.addSetting(settings->enableEmoteImages);
|
||||
this->wordFlagsListener_.addSetting(settings->boldUsernames);
|
||||
this->wordFlagsListener_.addSetting(settings->lowercaseDomains);
|
||||
|
@ -156,6 +157,7 @@ void WindowManager::updateWordTypeMask()
|
|||
flags.set(settings->showBadgesVanity ? MEF::BadgeVanity : MEF::None);
|
||||
flags.set(settings->showBadgesChatterino ? MEF::BadgeChatterino
|
||||
: MEF::None);
|
||||
flags.set(settings->showBadgesFfz ? MEF::BadgeFfz : MEF::None);
|
||||
|
||||
// username
|
||||
flags.set(MEF::Username);
|
||||
|
|
|
@ -14,7 +14,7 @@ class Paths;
|
|||
class Window;
|
||||
class SplitContainer;
|
||||
|
||||
enum class MessageElementFlag;
|
||||
enum class MessageElementFlag : int64_t;
|
||||
using MessageElementFlags = FlagsEnum<MessageElementFlag>;
|
||||
enum class WindowType;
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ using MessageFlags = FlagsEnum<MessageFlag>;
|
|||
class MessageLayout;
|
||||
using MessageLayoutPtr = std::shared_ptr<MessageLayout>;
|
||||
|
||||
enum class MessageElementFlag;
|
||||
enum class MessageElementFlag : int64_t;
|
||||
using MessageElementFlags = FlagsEnum<MessageElementFlag>;
|
||||
|
||||
class Scrollbar;
|
||||
|
|
|
@ -496,6 +496,8 @@ void GeneralPage::initLayout(GeneralPageView &layout)
|
|||
layout.addCheckbox("Vanity (prime, bits, subgifter)",
|
||||
getSettings()->showBadgesVanity);
|
||||
layout.addCheckbox("Chatterino", getSettings()->showBadgesChatterino);
|
||||
layout.addCheckbox("FrankerFaceZ (Bot, FFZ Supporter, FFZ Developer)",
|
||||
getSettings()->showBadgesFfz);
|
||||
|
||||
layout.addSubtitle("Miscellaneous");
|
||||
|
||||
|
|
Loading…
Reference in a new issue