feat: add filter for external badges (#6709)

Co-authored-by: Ava Chow <github@achow101.com>
Reviewed-by: Nerixyz <nerixdev@outlook.de>
This commit is contained in:
pajlada
2026-01-05 16:20:21 +01:00
committed by GitHub
parent 25ea6b9214
commit 327dc0ebcb
186 changed files with 554 additions and 40 deletions
+8 -5
View File
@@ -12,6 +12,7 @@ namespace chatterino::filters {
const QMap<QString, Type> MESSAGE_TYPING_CONTEXT{
{"author.badges", Type::StringList},
{"author.external_badges", Type::StringList},
{"author.color", Type::Color},
{"author.name", Type::String},
{"author.user_id", Type::String},
@@ -49,16 +50,17 @@ ContextMap buildContextMap(const MessagePtr &m, chatterino::Channel *channel)
{
auto watchingChannel = getApp()->getTwitch()->getWatchingChannel().get();
/*
* Looking to add a new identifier to filters? Here's what to do:
* 1. Update validIdentifiersMap in Tokenizer.cpp
/*
* Looking to add a new identifier to filters? Here's what to do:
* 1. Update VALID_IDENTIFIERS_MAP in Tokenizer.cpp
* 2. Add the identifier to the list below
* 3. Add the type of the identifier to MESSAGE_TYPING_CONTEXT in Filter.hpp
* 3. Add the type of the identifier to MESSAGE_TYPING_CONTEXT at the top of this file
* 4. Add the value for the identifier to the ContextMap returned by this function
*
*
* List of identifiers:
*
* author.badges
* author.external_badges
* author.color
* author.name
* author.user_id
@@ -121,6 +123,7 @@ ContextMap buildContextMap(const MessagePtr &m, chatterino::Channel *channel)
}
ContextMap vars = {
{"author.badges", std::move(badges)},
{"author.external_badges", m->externalBadges},
{"author.color", m->usernameColor},
{"author.name", m->displayName},
{"author.user_id", m->userID},
@@ -18,6 +18,7 @@ namespace chatterino::filters {
const QMap<QString, QString> VALID_IDENTIFIERS_MAP{
{"author.badges", "author badges"},
{"author.external_badges", "author external badges"},
{"author.color", "author color"},
{"author.name", "author name"},
{"author.user_id", "author user id"},
+2
View File
@@ -132,6 +132,8 @@ QJsonObject Message::toJson() const
}
msg["twitchBadgeInfos"_L1] = twitchBadgeInfos;
msg["externalBadges"_L1] = QJsonArray::fromStringList(this->externalBadges);
if (this->highlightColor)
{
msg["highlightColor"_L1] = this->highlightColor->name(QColor::HexArgb);
+7
View File
@@ -61,6 +61,13 @@ struct Message {
/// Map of extra data associated with each Twitch badge
std::unordered_map<QString, QString> twitchBadgeInfos;
/// List of external badges associated with this message
/// The badge should follow the following format: "provider:badgename". e.g.:
/// - betterttv:pro
/// - frankerfacez:mod
/// - 7tv:sub
QStringList externalBadges;
std::shared_ptr<QColor> highlightColor;
// Each reply holds a reference to the thread. When every reply is dropped,
// the reply thread will be cleaned up by the TwitchChannel.
+15
View File
@@ -2472,6 +2472,9 @@ void MessageBuilder::appendChatterinoBadges(const QString &userID)
{
this->emplace<BadgeElement>(*badge,
MessageElementFlag::BadgeChatterino);
/// e.g. "chatterino:Chatterino Top donator"
this->message().externalBadges.emplace_back((*badge)->name.string);
}
}
@@ -2482,6 +2485,9 @@ void MessageBuilder::appendFfzBadges(TwitchChannel *twitchChannel,
{
this->emplace<FfzBadgeElement>(
badge.emote, MessageElementFlag::BadgeFfz, badge.color);
/// e.g. "frankerfacez:subwoofer"
this->message().externalBadges.emplace_back(badge.emote->name.string);
}
if (twitchChannel == nullptr)
@@ -2493,6 +2499,9 @@ void MessageBuilder::appendFfzBadges(TwitchChannel *twitchChannel,
{
this->emplace<FfzBadgeElement>(
badge.emote, MessageElementFlag::BadgeFfz, badge.color);
/// e.g. "frankerfacez:subwoofer"
this->message().externalBadges.emplace_back(badge.emote->name.string);
}
}
@@ -2501,6 +2510,9 @@ void MessageBuilder::appendBttvBadges(const QString &userID)
if (auto badge = getApp()->getBttvBadges()->getBadge({userID}))
{
this->emplace<BadgeElement>(*badge, MessageElementFlag::BadgeBttv);
/// e.g. "betterttv:Pro Subscriber"
this->message().externalBadges.emplace_back((*badge)->name.string);
}
}
@@ -2509,6 +2521,9 @@ void MessageBuilder::appendSeventvBadges(const QString &userID)
if (auto badge = getApp()->getSeventvBadges()->getBadge({userID}))
{
this->emplace<BadgeElement>(*badge, MessageElementFlag::BadgeSevenTV);
/// e.g. "7tv:NNYS 2024"
this->message().externalBadges.emplace_back((*badge)->name.string);
}
}
+4 -2
View File
@@ -3,6 +3,8 @@
#include "messages/Emote.hpp"
#include "messages/Image.hpp"
using namespace Qt::StringLiterals;
namespace chatterino {
QString BttvBadges::idForBadge(const QJsonObject &badgeJson) const
@@ -11,10 +13,10 @@ QString BttvBadges::idForBadge(const QJsonObject &badgeJson) const
}
EmotePtr BttvBadges::createBadge(const QString &id,
const QJsonObject & /* badgeJson */) const
const QJsonObject & /*badgeJson*/) const
{
auto emote = Emote{
.name = EmoteName{},
.name = EmoteName{u"betterttv:pro"_s},
.images = ImageSet(Image::fromUrl(Url{id}, 18.0 / 72.0)),
.tooltip = Tooltip{"BTTV Pro"},
.homePage = Url{},
@@ -48,8 +48,9 @@ void ChatterinoBadges::loadChatterinoBadges()
// The sizes for the images are only an estimation, there might
// be badges with different sizes.
constexpr QSize baseSize(18, 18);
auto tooltip = jsonBadge.value("tooltip").toString();
auto emote = Emote{
.name = EmoteName{},
.name = EmoteName{u"chatterino:" % tooltip},
.images =
ImageSet{
Image::fromUrl(
@@ -62,7 +63,7 @@ void ChatterinoBadges::loadChatterinoBadges()
Url{jsonBadge.value("image3").toString()}, 0.25,
baseSize * 4),
},
.tooltip = Tooltip{jsonBadge.value("tooltip").toString()},
.tooltip = Tooltip{tooltip},
.homePage = Url{},
};
+7 -5
View File
@@ -66,7 +66,11 @@ void FfzBadges::load()
jsonBadge["height"].toInt(18));
auto emote = Emote{
.name = EmoteName{},
.name =
EmoteName{
u"frankerfacez:" %
jsonBadge.value("name").toString(),
},
.images =
ImageSet{
Image::fromUrl(
@@ -82,13 +86,11 @@ void FfzBadges::load()
.homePage = Url{},
};
Badge badge;
int badgeID = jsonBadge.value("id").toInt();
this->badges[badgeID] = Badge{
std::make_shared<const Emote>(std::move(emote)),
QColor(jsonBadge.value("color").toString()),
.emote = std::make_shared<const Emote>(std::move(emote)),
.color = QColor(jsonBadge.value("color").toString()),
};
// Find users with this badge
+1
View File
@@ -4,6 +4,7 @@
#include "util/ThreadGuard.hpp"
#include <QColor>
#include <QString>
#include <memory>
#include <optional>
+4 -2
View File
@@ -1,7 +1,7 @@
#include "providers/seventv/SeventvBadges.hpp"
#include "messages/Emote.hpp"
#include "messages/Image.hpp"
#include "messages/Image.hpp" // IWYU pragma: keep
#include "providers/seventv/SeventvEmotes.hpp"
namespace chatterino {
@@ -15,7 +15,9 @@ EmotePtr SeventvBadges::createBadge(const QString &id,
const QJsonObject &badgeJson) const
{
auto emote = Emote{
.name = EmoteName{},
// We utilize the "emote" "name" for filtering badges, and expect
// the format to be "7tv:badge name" (e.g. "7tv:NNYS 2024")
.name = EmoteName{u"7tv:" % badgeJson["name"].toString()},
.images = SeventvEmotes::createImageSet(badgeJson, true),
.tooltip = Tooltip{badgeJson["tooltip"].toString()},
.homePage = Url{},