feat(eventsub): add automod.message.* and channel.suspicious_user.* (#6003)

This commit is contained in:
nerix
2025-02-27 21:53:48 +01:00
committed by GitHub
parent d2c158098d
commit 95b97f42e6
38 changed files with 2357 additions and 748 deletions
@@ -1,10 +1,14 @@
#pragma once
#include "twitch-eventsub-ws/messages/metadata.hpp"
#include "twitch-eventsub-ws/payloads/automod-message-hold-v2.hpp"
#include "twitch-eventsub-ws/payloads/automod-message-update-v2.hpp"
#include "twitch-eventsub-ws/payloads/channel-ban-v1.hpp"
#include "twitch-eventsub-ws/payloads/channel-chat-message-v1.hpp"
#include "twitch-eventsub-ws/payloads/channel-chat-notification-v1.hpp"
#include "twitch-eventsub-ws/payloads/channel-moderate-v2.hpp"
#include "twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.hpp"
#include "twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.hpp"
#include "twitch-eventsub-ws/payloads/channel-update-v1.hpp"
#include "twitch-eventsub-ws/payloads/session-welcome.hpp"
#include "twitch-eventsub-ws/payloads/stream-offline-v1.hpp"
@@ -53,6 +57,23 @@ public:
const messages::Metadata &metadata,
const payload::channel_moderate::v2::Payload &payload) = 0;
virtual void onAutomodMessageHold(
const messages::Metadata &metadata,
const payload::automod_message_hold::v2::Payload &payload) = 0;
virtual void onAutomodMessageUpdate(
const messages::Metadata &metadata,
const payload::automod_message_update::v2::Payload &payload) = 0;
virtual void onChannelSuspiciousUserMessage(
const messages::Metadata &metadata,
const payload::channel_suspicious_user_message::v1::Payload
&payload) = 0;
virtual void onChannelSuspiciousUserUpdate(
const messages::Metadata &metadata,
const payload::channel_suspicious_user_update::v1::Payload
&payload) = 0;
// Add your new subscription types above this line
};
@@ -0,0 +1,42 @@
#pragma once
#include "twitch-eventsub-ws/payloads/automod-message.hpp"
#include "twitch-eventsub-ws/payloads/structured-message.hpp"
#include "twitch-eventsub-ws/payloads/subscription.hpp"
#include <boost/json.hpp>
#include <string>
namespace chatterino::eventsub::lib::payload::automod_message_hold::v2 {
struct Event {
// Broadcaster of the channel the message was sent in
std::string broadcasterUserID;
std::string broadcasterUserLogin;
std::string broadcasterUserName;
// User who sent the message
std::string userID;
std::string userLogin;
std::string userName;
std::string messageID;
chat::Message message;
// TODO: use chrono?
std::string heldAt;
/// json_tag=reason
std::variant<automod::AutomodReason, automod::BlockedTermReason> reason;
};
struct Payload {
subscription::Subscription subscription;
Event event;
};
#include "twitch-eventsub-ws/payloads/automod-message-hold-v2.inc"
} // namespace chatterino::eventsub::lib::payload::automod_message_hold::v2
@@ -0,0 +1,5 @@
boost::json::result_for<Event, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Event>, const boost::json::value &jvRoot);
boost::json::result_for<Payload, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Payload>, const boost::json::value &jvRoot);
@@ -0,0 +1,50 @@
#pragma once
#include "twitch-eventsub-ws/payloads/automod-message.hpp"
#include "twitch-eventsub-ws/payloads/structured-message.hpp"
#include "twitch-eventsub-ws/payloads/subscription.hpp"
#include <boost/json.hpp>
#include <string>
namespace chatterino::eventsub::lib::payload::automod_message_update::v2 {
struct Event {
// Broadcaster of the channel the message was sent in
std::string broadcasterUserID;
std::string broadcasterUserLogin;
std::string broadcasterUserName;
// User who sent the message
std::string userID;
std::string userLogin;
std::string userName;
// Moderator who updated the message (possibly empty)
std::string moderatorUserID;
std::string moderatorUserLogin;
std::string moderatorUserName;
std::string messageID;
chat::Message message;
// "Approved", "Denied", or "Expired"
std::string status;
// TODO: use chrono?
std::string heldAt;
/// json_tag=reason
std::variant<automod::AutomodReason, automod::BlockedTermReason> reason;
};
struct Payload {
subscription::Subscription subscription;
Event event;
};
#include "twitch-eventsub-ws/payloads/automod-message-update-v2.inc"
} // namespace chatterino::eventsub::lib::payload::automod_message_update::v2
@@ -0,0 +1,5 @@
boost::json::result_for<Event, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Event>, const boost::json::value &jvRoot);
boost::json::result_for<Payload, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Payload>, const boost::json::value &jvRoot);
@@ -0,0 +1,41 @@
#pragma once
#include "twitch-eventsub-ws/string.hpp"
#include <boost/json.hpp>
#include <string>
#include <vector>
namespace chatterino::eventsub::lib::automod {
struct Boundary {
int startPos;
int endPos;
};
struct AutomodReason {
static constexpr std::string_view TAG = "automod";
String category;
int level;
std::vector<Boundary> boundaries;
};
struct FoundTerm {
std::string termID;
Boundary boundary;
std::string ownerBroadcasterUserID;
std::string ownerBroadcasterUserLogin;
std::string ownerBroadcasterUserName;
};
struct BlockedTermReason {
static constexpr std::string_view TAG = "blocked_term";
std::vector<FoundTerm> termsFound;
};
#include "twitch-eventsub-ws/payloads/automod-message.inc"
} // namespace chatterino::eventsub::lib::automod
@@ -0,0 +1,13 @@
boost::json::result_for<Boundary, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Boundary>, const boost::json::value &jvRoot);
boost::json::result_for<AutomodReason, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<AutomodReason>,
const boost::json::value &jvRoot);
boost::json::result_for<FoundTerm, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<FoundTerm>, const boost::json::value &jvRoot);
boost::json::result_for<BlockedTermReason, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<BlockedTermReason>,
const boost::json::value &jvRoot);
@@ -1,5 +1,6 @@
#pragma once
#include "twitch-eventsub-ws/payloads/structured-message.hpp"
#include "twitch-eventsub-ws/payloads/subscription.hpp"
#include <boost/json.hpp>
@@ -60,38 +61,6 @@ struct Badge {
std::string info;
};
struct Cheermote {
std::string prefix;
int bits;
int tier;
};
struct Emote {
std::string id;
std::string emoteSetID;
std::string ownerID;
std::vector<std::string> format;
};
struct Mention {
std::string userID;
std::string userName;
std::string userLogin;
};
struct MessageFragment {
std::string type;
std::string text;
std::optional<Cheermote> cheermote;
std::optional<Emote> emote;
std::optional<Mention> mention;
};
struct Message {
std::string text;
std::vector<MessageFragment> fragments;
};
struct Cheer {
int bits;
};
@@ -127,7 +96,7 @@ struct Event {
std::string messageID;
std::string messageType;
Message message;
chat::Message message;
std::optional<Cheer> cheer;
std::optional<Reply> reply;
@@ -1,22 +1,6 @@
boost::json::result_for<Badge, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Badge>, const boost::json::value &jvRoot);
boost::json::result_for<Cheermote, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Cheermote>, const boost::json::value &jvRoot);
boost::json::result_for<Emote, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Emote>, const boost::json::value &jvRoot);
boost::json::result_for<Mention, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Mention>, const boost::json::value &jvRoot);
boost::json::result_for<MessageFragment, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<MessageFragment>,
const boost::json::value &jvRoot);
boost::json::result_for<Message, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Message>, const boost::json::value &jvRoot);
boost::json::result_for<Cheer, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Cheer>, const boost::json::value &jvRoot);
@@ -1,5 +1,6 @@
#pragma once
#include "twitch-eventsub-ws/payloads/structured-message.hpp"
#include "twitch-eventsub-ws/payloads/subscription.hpp"
#include <boost/json.hpp>
@@ -16,33 +17,6 @@ struct Badge {
std::string info;
};
struct Cheermote {
std::string prefix;
int bits;
int tier;
};
struct Emote {
std::string id;
std::string emoteSetID;
std::string ownerID;
std::vector<std::string> format;
};
struct Mention {
std::string userID;
std::string userName;
std::string userLogin;
};
struct MessageFragment {
std::string type;
std::string text;
std::optional<Cheermote> cheermote;
std::optional<Emote> emote;
std::optional<Mention> mention;
};
struct Subcription {
static constexpr std::string_view TAG = "sub";
@@ -153,11 +127,6 @@ struct BitsBadgeTier {
int tier;
};
struct Message {
std::string text;
std::vector<MessageFragment> fragments;
};
struct Event {
std::string broadcasterUserID;
std::string broadcasterUserLogin;
@@ -170,7 +139,7 @@ struct Event {
std::vector<Badge> badges;
std::string systemMessage;
std::string messageID;
Message message;
chat::Message message;
/// json_tag=notice_type
std::variant<Subcription, //
Resubscription, //
@@ -1,19 +1,6 @@
boost::json::result_for<Badge, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Badge>, const boost::json::value &jvRoot);
boost::json::result_for<Cheermote, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Cheermote>, const boost::json::value &jvRoot);
boost::json::result_for<Emote, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Emote>, const boost::json::value &jvRoot);
boost::json::result_for<Mention, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Mention>, const boost::json::value &jvRoot);
boost::json::result_for<MessageFragment, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<MessageFragment>,
const boost::json::value &jvRoot);
boost::json::result_for<Subcription, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Subcription>,
const boost::json::value &jvRoot);
@@ -64,9 +51,6 @@ boost::json::result_for<BitsBadgeTier, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<BitsBadgeTier>,
const boost::json::value &jvRoot);
boost::json::result_for<Message, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Message>, const boost::json::value &jvRoot);
boost::json::result_for<Event, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Event>, const boost::json::value &jvRoot);
@@ -0,0 +1,46 @@
#pragma once
#include "twitch-eventsub-ws/payloads/structured-message.hpp"
#include "twitch-eventsub-ws/payloads/subscription.hpp"
#include <boost/json.hpp>
#include <string>
namespace chatterino::eventsub::lib::payload::channel_suspicious_user_message::
v1 {
struct Event {
// Broadcaster of the channel the message was sent in
std::string broadcasterUserID;
std::string broadcasterUserLogin;
std::string broadcasterUserName;
// User who sent the message
std::string userID;
std::string userLogin;
std::string userName;
// "none", "active_monitoring", "restricted"
std::string lowTrustStatus;
std::vector<std::string> sharedBanChannelIds;
// "manual", "ban_evader_detector", or "shared_channel_ban"
std::vector<std::string> types;
// "unknown", "possible", "likely"
std::string banEvasionEvaluation;
// this event also has the ID in this message (hopefully we don't need it)
chat::Message message;
};
struct Payload {
subscription::Subscription subscription;
Event event;
};
#include "twitch-eventsub-ws/payloads/channel-suspicious-user-message-v1.inc"
} // namespace chatterino::eventsub::lib::payload::channel_suspicious_user_message::v1
@@ -0,0 +1,5 @@
boost::json::result_for<Event, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Event>, const boost::json::value &jvRoot);
boost::json::result_for<Payload, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Payload>, const boost::json::value &jvRoot);
@@ -0,0 +1,40 @@
#pragma once
#include "twitch-eventsub-ws/payloads/subscription.hpp"
#include <boost/json.hpp>
#include <string>
namespace chatterino::eventsub::lib::payload::channel_suspicious_user_update::
v1 {
struct Event {
// Broadcaster of the channel
std::string broadcasterUserID;
std::string broadcasterUserLogin;
std::string broadcasterUserName;
// Affected user
std::string userID;
std::string userLogin;
std::string userName;
// Moderator who updated the user
std::string moderatorUserID;
std::string moderatorUserLogin;
std::string moderatorUserName;
// "none", "active_monitoring", or "restricted"
std::string lowTrustStatus;
};
struct Payload {
subscription::Subscription subscription;
Event event;
};
#include "twitch-eventsub-ws/payloads/channel-suspicious-user-update-v1.inc"
} // namespace chatterino::eventsub::lib::payload::channel_suspicious_user_update::v1
@@ -0,0 +1,5 @@
boost::json::result_for<Event, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Event>, const boost::json::value &jvRoot);
boost::json::result_for<Payload, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Payload>, const boost::json::value &jvRoot);
@@ -0,0 +1,54 @@
#pragma once
#include "twitch-eventsub-ws/string.hpp"
#include <string_view>
#include <variant>
#include <vector>
namespace chatterino::eventsub::lib::chat {
struct Cheermote {
static constexpr std::string_view TAG = "cheermote";
String prefix;
int bits;
int tier;
};
struct Emote {
static constexpr std::string_view TAG = "emote";
String id;
String emoteSetID;
// XXX: this isn't included in automod-ish messages and we don't have a
// need for it right now
// String ownerID;
};
struct Mention {
static constexpr std::string_view TAG = "mention";
String userID;
String userName;
String userLogin;
};
struct Text {
static constexpr std::string_view TAG = "text";
};
struct MessageFragment {
String text;
/// json_tag=type
std::variant<Text, Cheermote, Emote, Mention> inner;
};
struct Message {
String text;
std::vector<MessageFragment> fragments;
};
#include "twitch-eventsub-ws/payloads/structured-message.inc"
} // namespace chatterino::eventsub::lib::chat
@@ -0,0 +1,18 @@
boost::json::result_for<Cheermote, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Cheermote>, const boost::json::value &jvRoot);
boost::json::result_for<Emote, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Emote>, const boost::json::value &jvRoot);
boost::json::result_for<Mention, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Mention>, const boost::json::value &jvRoot);
boost::json::result_for<Text, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Text>, const boost::json::value &jvRoot);
boost::json::result_for<MessageFragment, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<MessageFragment>,
const boost::json::value &jvRoot);
boost::json::result_for<Message, boost::json::value>::type tag_invoke(
boost::json::try_value_to_tag<Message>, const boost::json::value &jvRoot);