This commit is contained in:
pajlada 2024-11-03 14:48:09 +01:00 committed by GitHub
commit 32fc3c13f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 88 additions and 35 deletions

View file

@ -36,6 +36,7 @@
- Minor: Added `--login <username>` CLI argument to specify which account to start logged in as. (#5626) - Minor: Added `--login <username>` CLI argument to specify which account to start logged in as. (#5626)
- Minor: When blocking a channel, Chatterino will now warn you about that action. (#5615) - Minor: When blocking a channel, Chatterino will now warn you about that action. (#5615)
- Minor: Indicate when subscriptions and resubscriptions are for multiple months. (#5642) - Minor: Indicate when subscriptions and resubscriptions are for multiple months. (#5642)
- Minor: Added a setting to control whether or not to show "Blocked Term" automod messages. (#5690)
- Minor: Proxy URL information is now included in the `/debug-env` command. (#5648) - Minor: Proxy URL information is now included in the `/debug-env` command. (#5648)
- Minor: Make raid entry message usernames clickable. (#5651) - Minor: Make raid entry message usernames clickable. (#5651)
- Minor: Tabs unhighlight when their content is read in other tabs. (#5649) - Minor: Tabs unhighlight when their content is read in other tabs. (#5649)

View file

@ -6,6 +6,10 @@
#include <QSize> #include <QSize>
#include <QString> #include <QString>
#include <memory>
#include <string>
#include <type_traits>
namespace chatterino { namespace chatterino {
void _registerSetting(std::weak_ptr<pajlada::Settings::SettingData> setting); void _registerSetting(std::weak_ptr<pajlada::Settings::SettingData> setting);
@ -148,6 +152,9 @@ struct IsChatterinoSettingT : std::false_type {
template <typename T> template <typename T>
struct IsChatterinoSettingT<ChatterinoSetting<T>> : std::true_type { struct IsChatterinoSettingT<ChatterinoSetting<T>> : std::true_type {
}; };
template <typename T>
struct IsChatterinoSettingT<EnumStringSetting<T>> : std::true_type {
};
template <typename T> template <typename T>
concept IsChatterinoSetting = IsChatterinoSettingT<T>::value; concept IsChatterinoSetting = IsChatterinoSettingT<T>::value;

View file

@ -26,6 +26,7 @@
#include "providers/twitch/api/Helix.hpp" #include "providers/twitch/api/Helix.hpp"
#include "providers/twitch/ChannelPointReward.hpp" #include "providers/twitch/ChannelPointReward.hpp"
#include "providers/twitch/PubSubActions.hpp" #include "providers/twitch/PubSubActions.hpp"
#include "providers/twitch/pubsubmessages/AutoMod.hpp"
#include "providers/twitch/TwitchAccount.hpp" #include "providers/twitch/TwitchAccount.hpp"
#include "providers/twitch/TwitchBadge.hpp" #include "providers/twitch/TwitchBadge.hpp"
#include "providers/twitch/TwitchBadges.hpp" #include "providers/twitch/TwitchBadges.hpp"
@ -1637,6 +1638,12 @@ std::pair<MessagePtr, MessagePtr> MessageBuilder::makeAutomodMessage(
{ {
MessageBuilder builder, builder2; MessageBuilder builder, builder2;
if (action.reasonCode == PubSubAutoModQueueMessage::Reason::BlockedTerm)
{
builder.message().flags.set(MessageFlag::AutoModBlockedTerm);
builder2.message().flags.set(MessageFlag::AutoModBlockedTerm);
}
// //
// Builder for AutoMod message with explanation // Builder for AutoMod message with explanation
builder.message().id = "automod_" + action.msgID; builder.message().id = "automod_" + action.msgID;

View file

@ -52,6 +52,8 @@ enum class MessageFlag : std::int64_t {
Action = (1LL << 36), Action = (1LL << 36),
/// The message is sent in a different source channel as part of a Shared Chat session /// The message is sent in a different source channel as part of a Shared Chat session
SharedMessage = (1LL << 37), SharedMessage = (1LL << 37),
/// AutoMod message that showed up due to containing a blocked term in the channel
AutoModBlockedTerm = (1LL << 38),
}; };
using MessageFlags = FlagsEnum<MessageFlag>; using MessageFlags = FlagsEnum<MessageFlag>;

View file

@ -141,6 +141,9 @@ void MessageLayout::actuallyLayout(const MessageLayoutContext &ctx)
bool hideModerated = getSettings()->hideModerated; bool hideModerated = getSettings()->hideModerated;
bool hideModerationActions = getSettings()->hideModerationActions; bool hideModerationActions = getSettings()->hideModerationActions;
bool hideBlockedTermAutomodMessages =
getSettings()->showBlockedTermAutomodMessages.getEnum() ==
ShowModerationState::Never;
bool hideSimilar = getSettings()->hideSimilar; bool hideSimilar = getSettings()->hideSimilar;
bool hideReplies = !ctx.flags.has(MessageElementFlag::RepliedMessage); bool hideReplies = !ctx.flags.has(MessageElementFlag::RepliedMessage);
@ -154,9 +157,21 @@ void MessageLayout::actuallyLayout(const MessageLayoutContext &ctx)
continue; continue;
} }
if (hideBlockedTermAutomodMessages &&
this->message_->flags.has(MessageFlag::AutoModBlockedTerm))
{
// NOTE: This hides the message but it will make the message re-appear if moderation message hiding is no longer active, and the layout is re-laid-out.
// This is only the case for the moderation messages that don't get filtered during creation.
// We should decide which is the correct method & apply that everywhere
continue;
}
if (this->message_->flags.has(MessageFlag::Timeout) || if (this->message_->flags.has(MessageFlag::Timeout) ||
this->message_->flags.has(MessageFlag::Untimeout)) this->message_->flags.has(MessageFlag::Untimeout))
{ {
// NOTE: This hides the message but it will make the message re-appear if moderation message hiding is no longer active, and the layout is re-laid-out.
// This is only the case for the moderation messages that don't get filtered during creation.
// We should decide which is the correct method & apply that everywhere
if (hideModerationActions || if (hideModerationActions ||
(getSettings()->streamerModeHideModActions && (getSettings()->streamerModeHideModActions &&
getApp()->getStreamerMode()->isEnabled())) getApp()->getStreamerMode()->isEnabled()))

View file

@ -1,5 +1,7 @@
#pragma once #pragma once
#include "providers/twitch/pubsubmessages/AutoMod.hpp"
#include <QColor> #include <QColor>
#include <QDebug> #include <QDebug>
#include <QJsonObject> #include <QJsonObject>
@ -143,6 +145,7 @@ struct AutomodAction : PubSubAction {
QString message; QString message;
QString reason; QString reason;
PubSubAutoModQueueMessage::Reason reasonCode;
QString msgID; QString msgID;
}; };

View file

@ -349,40 +349,6 @@ PubSub::PubSub(const QString &host, std::chrono::seconds pingInterval)
this->moderation.raidCanceled.invoke(action); this->moderation.raidCanceled.invoke(action);
}; };
/*
// This handler is no longer required as we use the automod-queue topic now
this->moderationActionHandlers["automod_rejected"] =
[this](const auto &data, const auto &roomID) {
AutomodAction action(data, roomID);
action.source.id = data.value("created_by_user_id").toString();
action.source.login = data.value("created_by").toString();
action.target.id = data.value("target_user_id").toString();
const auto args = data.value("args").toArray();
if (args.isEmpty())
{
return;
}
action.msgID = data.value("msg_id").toString();
if (action.msgID.isEmpty())
{
// Missing required msg_id parameter
return;
}
action.target.login = args[0].toString();
action.message = args[1].toString(); // May be omitted
action.reason = args[2].toString(); // May be omitted
this->moderation.autoModMessageBlocked.invoke(action);
};
*/
this->moderationActionHandlers["automod_message_rejected"] = this->moderationActionHandlers["automod_message_rejected"] =
[this](const auto &data, const auto &roomID) { [this](const auto &data, const auto &roomID) {
AutomodInfoAction action(data, roomID); AutomodInfoAction action(data, roomID);

View file

@ -494,6 +494,7 @@ void TwitchIrcServer::initialize()
action.msgID = msg.messageID; action.msgID = msg.messageID;
action.message = msg.messageText; action.message = msg.messageText;
action.reasonCode = msg.reason;
// this message also contains per-word automod data, which could be implemented // this message also contains per-word automod data, which could be implemented

View file

@ -15,6 +15,10 @@ PubSubAutoModQueueMessage::PubSubAutoModQueueMessage(const QJsonObject &root)
this->type = oType.value(); this->type = oType.value();
} }
this->reason =
qmagicenum::enumCast<Reason>(data.value("reason_code").toString())
.value_or(Reason::INVALID);
auto contentClassification = auto contentClassification =
data.value("content_classification").toObject(); data.value("content_classification").toObject();

View file

@ -13,15 +13,24 @@ struct PubSubAutoModQueueMessage {
INVALID, INVALID,
}; };
enum class Reason {
AutoMod,
BlockedTerm,
INVALID,
};
QString typeString; QString typeString;
Type type = Type::INVALID; Type type = Type::INVALID;
Reason reason = Reason::INVALID;
QJsonObject data; QJsonObject data;
QString status; QString status;
QString contentCategory; QString contentCategory;
int contentLevel; int contentLevel{};
QString messageID; QString messageID;
QString messageText; QString messageText;
@ -51,3 +60,20 @@ constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name<
return default_tag; return default_tag;
} }
} }
template <>
constexpr magic_enum::customize::customize_t magic_enum::customize::enum_name<
chatterino::PubSubAutoModQueueMessage::Reason>(
chatterino::PubSubAutoModQueueMessage::Reason value) noexcept
{
switch (value)
{
case chatterino::PubSubAutoModQueueMessage::Reason::AutoMod:
return "AutoModCaughtMessageReason";
case chatterino::PubSubAutoModQueueMessage::Reason::BlockedTerm:
return "BlockedTermCaughtMessageReason";
default:
return default_tag;
}
}

View file

@ -69,6 +69,13 @@ enum class ChatSendProtocol : int {
Helix = 2, Helix = 2,
}; };
enum class ShowModerationState : int {
// Always show this moderation-related item
Always = 0,
// Never show this moderation-related item
Never = 1,
};
enum StreamerModeSetting { enum StreamerModeSetting {
Disabled = 0, Disabled = 0,
Enabled = 1, Enabled = 1,
@ -345,6 +352,10 @@ public:
IntSetting timeoutStackStyle = { IntSetting timeoutStackStyle = {
"/moderation/timeoutStackStyle", "/moderation/timeoutStackStyle",
static_cast<int>(TimeoutStackStyle::Default)}; static_cast<int>(TimeoutStackStyle::Default)};
EnumStringSetting<ShowModerationState> showBlockedTermAutomodMessages = {
"/moderation/showBlockedTermAutomodMessages",
ShowModerationState::Always,
};
/// Highlighting /// Highlighting
// BoolSetting enableHighlights = {"/highlighting/enabled", true}; // BoolSetting enableHighlights = {"/highlighting/enabled", true};

View file

@ -140,6 +140,8 @@ WindowManager::WindowManager(const Paths &paths, Settings &settings,
this->forceLayoutChannelViewsListener.add(settings.enableRedeemedHighlight); this->forceLayoutChannelViewsListener.add(settings.enableRedeemedHighlight);
this->forceLayoutChannelViewsListener.add(settings.colorUsernames); this->forceLayoutChannelViewsListener.add(settings.colorUsernames);
this->forceLayoutChannelViewsListener.add(settings.boldUsernames); this->forceLayoutChannelViewsListener.add(settings.boldUsernames);
this->forceLayoutChannelViewsListener.add(
settings.showBlockedTermAutomodMessages);
this->layoutChannelViewsListener.add(settings.timestampFormat); this->layoutChannelViewsListener.add(settings.timestampFormat);
this->layoutChannelViewsListener.add(fonts.fontChanged); this->layoutChannelViewsListener.add(fonts.fontChanged);

View file

@ -1167,6 +1167,14 @@ void GeneralPage::initLayout(GeneralPageView &layout)
layout.addIntInput("Usercard scrollback limit (requires restart)", layout.addIntInput("Usercard scrollback limit (requires restart)",
s.scrollbackUsercardLimit, 100, 100000, 100); s.scrollbackUsercardLimit, 100, 100000, 100);
layout.addDropdownEnumClass<ShowModerationState>(
"Show blocked term automod messages",
qmagicenum::enumNames<ShowModerationState>(),
s.showBlockedTermAutomodMessages,
"Show messages that are blocked by AutoMod for containing a public "
"blocked term in the current channel.",
{});
layout.addDropdown<int>( layout.addDropdown<int>(
"Stack timeouts", {"Stack", "Stack until timeout", "Don't stack"}, "Stack timeouts", {"Stack", "Stack until timeout", "Don't stack"},
s.timeoutStackStyle, s.timeoutStackStyle,