mirror of
https://github.com/WarmUpTill/SceneSwitcher.git
synced 2026-04-24 14:58:19 -05:00
Add option to check for addition chat message properties
This commit is contained in:
parent
d69364ec19
commit
93efc7cab3
|
|
@ -686,6 +686,16 @@ AdvSceneSwitcher.condition.twitch.type.polling.channel.live="Stream is currently
|
|||
AdvSceneSwitcher.condition.twitch.type.polling.channel.title="Current title matches"
|
||||
AdvSceneSwitcher.condition.twitch.type.polling.channel.category="Current category is"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.message="Chat message received"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties="Chat message properties:"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties.select="Select chat message property:"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties.firstMessage="Is first message"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties.emoteOnly="Is only using emotes"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties.mod="Is moderator"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties.subscriber="Is subscriber"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties.turbo="Is Turbo user"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties.displayName="Display name matches"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties.loginName="User name matches"
|
||||
AdvSceneSwitcher.condition.twitch.type.chat.properties.badge="User has badge"
|
||||
AdvSceneSwitcher.condition.twitch.categorySelectionDisabled="Cannot select category without selecting a Twitch account first!"
|
||||
AdvSceneSwitcher.condition.twitch.entry="Channel{{channel}}{{conditions}}{{pointsReward}}{{streamTitle}}{{regex}}{{category}}"
|
||||
AdvSceneSwitcher.condition.twitch.entry.account="Check using account{{account}}"
|
||||
|
|
@ -1670,9 +1680,13 @@ AdvSceneSwitcher.tempVar.twitch.user_login.removeMod.description="The user login
|
|||
AdvSceneSwitcher.tempVar.twitch.user_name.removeMod="User name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.removeMod.description="The display name of the removed moderator."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.chatter="User login"
|
||||
AdvSceneSwitcher.tempVar.twitch.chatter.description="The user login of the person who sent the chat message."
|
||||
AdvSceneSwitcher.tempVar.twitch.chat_message="Chat message"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.chatReceive="User login"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.chatReceive.description="The user login of the person who sent the chat message."
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.chatReceive="User name"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.chatReceive.description="The display name of the person who sent the chat message."
|
||||
AdvSceneSwitcher.tempVar.twitch.chat_message.chatReceive="Chat message"
|
||||
AdvSceneSwitcher.tempVar.twitch.badges.chatReceive="Chatter Badges"
|
||||
AdvSceneSwitcher.tempVar.twitch.badges.chatReceive.description="A string describing the badges available to this user and their state.\nFor example: vip/1,subscriber/42,hype-train/1"
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_id.raid="Raid creator user ID"
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_id.raid.description="The broadcaster ID that created the raid."
|
||||
|
|
|
|||
|
|
@ -1632,9 +1632,9 @@ AdvSceneSwitcher.tempVar.twitch.user_login.removeMod.description="削除され
|
|||
AdvSceneSwitcher.tempVar.twitch.user_name.removeMod="ユーザー名"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.removeMod.description="削除されたモデレーターの表示名"
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.chatter="ユーザーログイン"
|
||||
AdvSceneSwitcher.tempVar.twitch.chatter.description="チャットメッセージを送信した人のユーザーログイン情報"
|
||||
AdvSceneSwitcher.tempVar.twitch.chat_message="チャットメッセージ"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.chatReceive="ユーザーログイン"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.chatReceive.description="チャットメッセージを送信した人のユーザーログイン情報"
|
||||
AdvSceneSwitcher.tempVar.twitch.chat_message.chatReceive="チャットメッセージ"
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_id.raid="RaidクリエイターユーザーID"
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_id.raid.description="レイドを作成した配信者ID"
|
||||
|
|
|
|||
|
|
@ -1657,9 +1657,9 @@ AdvSceneSwitcher.tempVar.twitch.user_login.removeMod.description="O login do usu
|
|||
AdvSceneSwitcher.tempVar.twitch.user_name.removeMod="Nome de usuário"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_name.removeMod.description="O nome de exibição do usuário que foi removido como moderador."
|
||||
|
||||
AdvSceneSwitcher.tempVar.twitch.chatter="Nome de login do usuário"
|
||||
AdvSceneSwitcher.tempVar.twitch.chatter.description="O nome de login da pessoa que enviou a mensagem de chat."
|
||||
AdvSceneSwitcher.tempVar.twitch.chat_message="Mensagem de chat"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.chatReceive="Nome de login do usuário"
|
||||
AdvSceneSwitcher.tempVar.twitch.user_login.chatReceive.description="O nome de login da pessoa que enviou a mensagem de chat."
|
||||
AdvSceneSwitcher.tempVar.twitch.chat_message.chatReceive="Mensagem de chat"
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_id.raid="ID do usuário criador do raid"
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_id.raid.description="O ID do broadcaster que criou o raid."
|
||||
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_login.raid="Nome de login do criador do raid"
|
||||
|
|
|
|||
|
|
@ -23,13 +23,16 @@ bool MouseWheelWidgetAdjustmentGuard::eventFilter(QObject *o, QEvent *e)
|
|||
|
||||
void PreventMouseWheelAdjustWithoutFocus(QWidget *w)
|
||||
{
|
||||
// Ignore QScrollBar as there is no danger of accidentally modifying anything
|
||||
// and long expanded QComboBox would be difficult to interact with otherwise.
|
||||
// Ignore OSCMessageElementEdit to allow OSCMessageEdit list to up update
|
||||
// current index correctly.
|
||||
// Ignore QScrollBar as there is no danger of accidentally modifying
|
||||
// anything and long expanded QComboBox would be difficult to interact
|
||||
// with otherwise.
|
||||
// Ignore OSCMessageElementEdit and ChatMessagePropertyEdit to allow
|
||||
// lists to up update the current index correctly.
|
||||
if (qobject_cast<QScrollBar *>(w) ||
|
||||
QString(w->metaObject()->className()) ==
|
||||
"advss::OSCMessageElementEdit") {
|
||||
"advss::OSCMessageElementEdit" ||
|
||||
QString(w->metaObject()->className()) ==
|
||||
"advss::ChatMessagePropertyEdit") {
|
||||
return;
|
||||
}
|
||||
w->setFocusPolicy(Qt::StrongFocus);
|
||||
|
|
|
|||
|
|
@ -161,6 +161,7 @@ void TempVariableRef::Save(obs_data_t *obj, const char *name) const
|
|||
obs_data_set_int(data, "type", static_cast<int>(type));
|
||||
obs_data_set_int(data, "idx", GetIdx());
|
||||
obs_data_set_string(data, "id", _id.c_str());
|
||||
obs_data_set_int(data, "version", 1);
|
||||
obs_data_set_obj(obj, name, data);
|
||||
}
|
||||
|
||||
|
|
@ -175,6 +176,14 @@ void TempVariableRef::Load(obs_data_t *obj, Macro *macro, const char *name)
|
|||
_id = obs_data_get_string(data, "id");
|
||||
const auto type =
|
||||
static_cast<SegmentType>(obs_data_get_int(data, "type"));
|
||||
|
||||
// Backwards compatibility checks
|
||||
if (obs_data_get_int(data, "version") < 1) {
|
||||
if (_id == "chatter") {
|
||||
_id = "user_login";
|
||||
}
|
||||
}
|
||||
|
||||
AddPostLoadStep([this, idx, type, macro]() {
|
||||
this->PostLoad(idx, type, macro);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ target_sources(
|
|||
channel-selection.hpp
|
||||
chat-connection.cpp
|
||||
chat-connection.hpp
|
||||
chat-message-pattern.cpp
|
||||
chat-message-pattern.hpp
|
||||
event-sub.cpp
|
||||
event-sub.hpp
|
||||
macro-action-twitch.cpp
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@
|
|||
#include "twitch-helpers.hpp"
|
||||
|
||||
#include <log-helper.hpp>
|
||||
#include <plugin-state-helpers.hpp>
|
||||
|
||||
#undef DispatchMessage
|
||||
|
||||
|
|
@ -19,24 +18,50 @@ static const auto reconnectDelay = 15s;
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
static ParsedTags parseTags(const std::string &tags)
|
||||
static std::vector<IRCMessage::Badge> parseBadgeTag(const std::string &tag)
|
||||
{
|
||||
std::vector<std::string> badgePairs;
|
||||
size_t badgePos = 0;
|
||||
size_t badgeEndPos;
|
||||
|
||||
while ((badgeEndPos = tag.find(',', badgePos)) != std::string::npos) {
|
||||
badgePairs.push_back(
|
||||
tag.substr(badgePos, badgeEndPos - badgePos));
|
||||
badgePos = badgeEndPos + 1;
|
||||
}
|
||||
|
||||
badgePairs.push_back(tag.substr(badgePos));
|
||||
|
||||
std::vector<IRCMessage::Badge> badges;
|
||||
for (const auto &badgePair : badgePairs) {
|
||||
size_t slashPos = badgePair.find('/');
|
||||
const auto badgeName = badgePair.substr(0, slashPos);
|
||||
const auto badgeValue = (slashPos != std::string::npos)
|
||||
? badgePair.substr(slashPos + 1)
|
||||
: "";
|
||||
badges.push_back({badgeName, badgeValue != "0"});
|
||||
}
|
||||
|
||||
return badges;
|
||||
}
|
||||
|
||||
static void parseTags(const std::string &tags, IRCMessage &message)
|
||||
{
|
||||
ParsedTags parsedTags;
|
||||
static constexpr std::array<std::string_view, 2> tagsToIgnore = {
|
||||
"client-nonce", "flags"};
|
||||
|
||||
std::vector<std::string> parsedTagPairs;
|
||||
std::vector<std::string> properties;
|
||||
size_t pos = 0;
|
||||
size_t endPos;
|
||||
|
||||
while ((endPos = tags.find(';', pos)) != std::string::npos) {
|
||||
parsedTagPairs.push_back(tags.substr(pos, endPos - pos));
|
||||
properties.push_back(tags.substr(pos, endPos - pos));
|
||||
pos = endPos + 1;
|
||||
}
|
||||
|
||||
parsedTagPairs.push_back(tags.substr(pos));
|
||||
properties.push_back(tags.substr(pos));
|
||||
|
||||
for (const auto &tagPair : parsedTagPairs) {
|
||||
for (const auto &tagPair : properties) {
|
||||
size_t equalsPos = tagPair.find('=');
|
||||
std::string tagName = tagPair.substr(0, equalsPos);
|
||||
std::string tagValue = (equalsPos != std::string::npos)
|
||||
|
|
@ -49,113 +74,26 @@ static ParsedTags parseTags(const std::string &tags)
|
|||
}
|
||||
|
||||
if (tagValue.empty()) {
|
||||
parsedTags.tagMap[tagName] = {};
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tagName == "badges" || tagName == "badge-info") {
|
||||
ParsedTags::BadgeMap badgeMap;
|
||||
std::vector<std::string> badgePairs;
|
||||
size_t badgePos = 0;
|
||||
size_t badgeEndPos;
|
||||
|
||||
while ((badgeEndPos = tagValue.find(',', badgePos)) !=
|
||||
std::string::npos) {
|
||||
badgePairs.push_back(tagValue.substr(
|
||||
badgePos, badgeEndPos - badgePos));
|
||||
badgePos = badgeEndPos + 1;
|
||||
}
|
||||
|
||||
badgePairs.push_back(tagValue.substr(badgePos));
|
||||
|
||||
for (const auto &badgePair : badgePairs) {
|
||||
size_t slashPos = badgePair.find('/');
|
||||
std::string badgeName =
|
||||
badgePair.substr(0, slashPos);
|
||||
std::string badgeValue =
|
||||
(slashPos != std::string::npos)
|
||||
? badgePair.substr(slashPos + 1)
|
||||
: "";
|
||||
|
||||
badgeMap[badgeName] = badgeValue;
|
||||
}
|
||||
|
||||
parsedTags.tagMap[tagName] = badgeMap;
|
||||
|
||||
} else if (tagName == "emotes") {
|
||||
ParsedTags::EmoteMap emoteMap;
|
||||
std::vector<std::string> emotePairs;
|
||||
size_t emotePos = 0;
|
||||
size_t emoteEndPos;
|
||||
|
||||
while ((emoteEndPos = tagValue.find('/', emotePos)) !=
|
||||
std::string::npos) {
|
||||
emotePairs.push_back(tagValue.substr(
|
||||
emotePos, emoteEndPos - emotePos));
|
||||
emotePos = emoteEndPos + 1;
|
||||
}
|
||||
|
||||
emotePairs.push_back(tagValue.substr(emotePos));
|
||||
|
||||
for (const auto &emotePair : emotePairs) {
|
||||
size_t colonPos = emotePair.find(':');
|
||||
std::string emoteId =
|
||||
emotePair.substr(0, colonPos);
|
||||
std::string positions =
|
||||
(colonPos != std::string::npos)
|
||||
? emotePair.substr(colonPos + 1)
|
||||
: "";
|
||||
|
||||
std::vector<std::pair<int, int>> textPositions;
|
||||
size_t positionPos = 0;
|
||||
size_t positionEndPos;
|
||||
|
||||
while ((positionEndPos = positions.find(
|
||||
',', positionPos)) !=
|
||||
std::string::npos) {
|
||||
std::string position = positions.substr(
|
||||
positionPos,
|
||||
positionEndPos - positionPos);
|
||||
size_t dashPos = position.find('-');
|
||||
int startPos = std::stoi(
|
||||
position.substr(0, dashPos));
|
||||
int endPos = std::stoi(
|
||||
position.substr(dashPos + 1));
|
||||
textPositions.push_back(
|
||||
{startPos, endPos});
|
||||
positionPos = positionEndPos + 1;
|
||||
}
|
||||
|
||||
textPositions.push_back(
|
||||
{std::stoi(
|
||||
positions.substr(positionPos)),
|
||||
std::stoi(positions.substr(
|
||||
positionPos))});
|
||||
emoteMap[emoteId] = textPositions;
|
||||
}
|
||||
|
||||
parsedTags.tagMap[tagName] = emoteMap;
|
||||
} else if (tagName == "emote-sets") {
|
||||
ParsedTags::EmoteSet emoteSetIds;
|
||||
size_t setIdPos = 0;
|
||||
size_t setIdEndPos;
|
||||
|
||||
while ((setIdEndPos = tagValue.find(',', setIdPos)) !=
|
||||
std::string::npos) {
|
||||
emoteSetIds.push_back(tagValue.substr(
|
||||
setIdPos, setIdEndPos - setIdPos));
|
||||
setIdPos = setIdEndPos + 1;
|
||||
}
|
||||
|
||||
emoteSetIds.push_back(tagValue.substr(setIdPos));
|
||||
|
||||
parsedTags.tagMap[tagName] = emoteSetIds;
|
||||
} else {
|
||||
parsedTags.tagMap[tagName] = tagValue;
|
||||
message.properties.badges = parseBadgeTag(tagValue);
|
||||
message.properties.badgesString = tagValue;
|
||||
} else if (tagName == "display-name") {
|
||||
message.properties.displayName = tagValue;
|
||||
} else if (tagName == "first-msg") {
|
||||
message.properties.isFirstMessage = tagValue == "1";
|
||||
} else if (tagName == "emote-only") {
|
||||
message.properties.isUsingOnlyEmotes = tagValue == "1";
|
||||
} else if (tagName == "mod") {
|
||||
message.properties.isMod = tagValue == "1";
|
||||
} else if (tagName == "subscriber") {
|
||||
message.properties.isSubscriber = tagValue == "1";
|
||||
} else if (tagName == "turbo") {
|
||||
message.properties.isTurbo = tagValue == "1";
|
||||
}
|
||||
}
|
||||
|
||||
return parsedTags;
|
||||
}
|
||||
|
||||
static void parseSource(const std::string &rawSourceComponent,
|
||||
|
|
@ -273,7 +211,7 @@ static IRCMessage parseMessage(const std::string &message)
|
|||
rawMessageComponent = message.substr(idx);
|
||||
}
|
||||
|
||||
parsedMessage.tags = parseTags(rawTagsComponent);
|
||||
parseTags(rawTagsComponent, parsedMessage);
|
||||
parseSource(rawSourceComponent, parsedMessage);
|
||||
parseCommand(rawCommandComponent, parsedMessage);
|
||||
parsedMessage.message = rawMessageComponent;
|
||||
|
|
@ -594,13 +532,13 @@ void TwitchChatConnection::OnMessage(
|
|||
websocketpp::client<websocketpp::config::asio_tls_client>::message_ptr
|
||||
message)
|
||||
{
|
||||
constexpr std::string_view authOKCommand = "001";
|
||||
constexpr std::string_view pingCommand = "PING";
|
||||
constexpr std::string_view joinOKCommand = "JOIN";
|
||||
constexpr std::string_view noticeCommand = "NOTICE";
|
||||
constexpr std::string_view reconnectCommand = "RECONNECT";
|
||||
constexpr std::string_view newMessageCommand = "PRIVMSG";
|
||||
constexpr std::string_view whisperCommand = "WHISPER";
|
||||
static constexpr std::string_view authOKCommand = "001";
|
||||
static constexpr std::string_view pingCommand = "PING";
|
||||
static constexpr std::string_view joinOKCommand = "JOIN";
|
||||
static constexpr std::string_view noticeCommand = "NOTICE";
|
||||
static constexpr std::string_view reconnectCommand = "RECONNECT";
|
||||
static constexpr std::string_view newMessageCommand = "PRIVMSG";
|
||||
static constexpr std::string_view whisperCommand = "WHISPER";
|
||||
|
||||
if (!message) {
|
||||
return;
|
||||
|
|
@ -610,7 +548,7 @@ void TwitchChatConnection::OnMessage(
|
|||
}
|
||||
|
||||
std::string payload = message->get_payload();
|
||||
auto messages = parseMessages(payload);
|
||||
const auto messages = parseMessages(payload);
|
||||
|
||||
for (const auto &message : messages) {
|
||||
if (message.command.command == authOKCommand) {
|
||||
|
|
|
|||
|
|
@ -14,18 +14,21 @@ namespace advss {
|
|||
|
||||
using websocketpp::connection_hdl;
|
||||
|
||||
struct ParsedTags {
|
||||
using BadgeMap = std::unordered_map<std::string, std::string>;
|
||||
using EmoteMap = std::unordered_map<std::string,
|
||||
std::vector<std::pair<int, int>>>;
|
||||
using EmoteSet = std::vector<std::string>;
|
||||
std::unordered_map<std::string, std::variant<std::string, BadgeMap,
|
||||
EmoteMap, EmoteSet>>
|
||||
tagMap;
|
||||
};
|
||||
|
||||
struct IRCMessage {
|
||||
ParsedTags tags;
|
||||
struct Badge {
|
||||
std::string name;
|
||||
bool enabled;
|
||||
};
|
||||
struct {
|
||||
std::string badgesString;
|
||||
std::vector<Badge> badges;
|
||||
std::string displayName;
|
||||
bool isFirstMessage = false;
|
||||
bool isUsingOnlyEmotes = false;
|
||||
bool isMod = false;
|
||||
bool isSubscriber = false;
|
||||
bool isTurbo = false;
|
||||
} properties;
|
||||
struct {
|
||||
std::string nick;
|
||||
std::string host;
|
||||
|
|
|
|||
530
plugins/twitch/chat-message-pattern.cpp
Normal file
530
plugins/twitch/chat-message-pattern.cpp
Normal file
|
|
@ -0,0 +1,530 @@
|
|||
#include "chat-message-pattern.hpp"
|
||||
|
||||
#include <log-helper.hpp>
|
||||
#include <obs-module-helper.hpp>
|
||||
#include <QComboBox>
|
||||
#include <ui-helpers.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
const std::vector<ChatMessageProperty::PropertyInfo> ChatMessageProperty::_supportedProperties = {
|
||||
{"firstMessage",
|
||||
"AdvSceneSwitcher.condition.twitch.type.chat.properties.firstMessage",
|
||||
true,
|
||||
[](const IRCMessage &message, const ChatMessageProperty &property) {
|
||||
return message.properties.isFirstMessage ==
|
||||
std::get<bool>(property._value);
|
||||
}},
|
||||
{"emoteOnly",
|
||||
"AdvSceneSwitcher.condition.twitch.type.chat.properties.emoteOnly",
|
||||
true,
|
||||
[](const IRCMessage &message, const ChatMessageProperty &property) {
|
||||
return message.properties.isUsingOnlyEmotes ==
|
||||
std::get<bool>(property._value);
|
||||
}},
|
||||
{"mod", "AdvSceneSwitcher.condition.twitch.type.chat.properties.mod",
|
||||
true,
|
||||
[](const IRCMessage &message, const ChatMessageProperty &property) {
|
||||
return message.properties.isMod ==
|
||||
std::get<bool>(property._value);
|
||||
}},
|
||||
{"subscriber",
|
||||
"AdvSceneSwitcher.condition.twitch.type.chat.properties.subscriber",
|
||||
true,
|
||||
[](const IRCMessage &message, const ChatMessageProperty &property) {
|
||||
return message.properties.isSubscriber ==
|
||||
std::get<bool>(property._value);
|
||||
}},
|
||||
{"turbo",
|
||||
"AdvSceneSwitcher.condition.twitch.type.chat.properties.turbo", true,
|
||||
[](const IRCMessage &message, const ChatMessageProperty &property) {
|
||||
return message.properties.isTurbo ==
|
||||
std::get<bool>(property._value);
|
||||
}},
|
||||
{"displayName",
|
||||
"AdvSceneSwitcher.condition.twitch.type.chat.properties.displayName",
|
||||
std::string(),
|
||||
[](const IRCMessage &message, const ChatMessageProperty &property) {
|
||||
auto value = std::get<StringVariable>(property._value);
|
||||
return !property._regex.Enabled()
|
||||
? message.properties.displayName ==
|
||||
std::string(value)
|
||||
: property._regex.Matches(
|
||||
message.properties.displayName,
|
||||
value);
|
||||
}},
|
||||
{"loginName",
|
||||
"AdvSceneSwitcher.condition.twitch.type.chat.properties.loginName",
|
||||
std::string(),
|
||||
[](const IRCMessage &message, const ChatMessageProperty &property) {
|
||||
auto value = std::get<StringVariable>(property._value);
|
||||
return !property._regex.Enabled()
|
||||
? message.source.nick == std::string(value)
|
||||
: property._regex.Matches(message.source.nick,
|
||||
value);
|
||||
}},
|
||||
{"badge",
|
||||
"AdvSceneSwitcher.condition.twitch.type.chat.properties.badge",
|
||||
std::string("broadcaster"),
|
||||
[](const IRCMessage &message, const ChatMessageProperty &property) {
|
||||
auto value = std::get<StringVariable>(property._value);
|
||||
for (const auto &badge : message.properties.badges) {
|
||||
if (!badge.enabled) {
|
||||
continue;
|
||||
}
|
||||
const bool badgeNameMatches =
|
||||
!property._regex.Enabled()
|
||||
? badge.name == std::string(value)
|
||||
: property._regex.Matches(badge.name,
|
||||
value);
|
||||
if (badgeNameMatches) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
true},
|
||||
};
|
||||
|
||||
PropertySelectionDialog::PropertySelectionDialog(QWidget *parent)
|
||||
: QDialog(parent),
|
||||
_selection(new QComboBox())
|
||||
{
|
||||
setModal(true);
|
||||
setWindowModality(Qt::WindowModality::ApplicationModal);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
setMinimumWidth(350);
|
||||
setMinimumHeight(70);
|
||||
|
||||
_selection->setPlaceholderText(
|
||||
obs_module_text("AdvSceneSwitcher.item.select"));
|
||||
|
||||
for (const auto &prop : ChatMessageProperty::GetSupportedIds()) {
|
||||
_selection->addItem(
|
||||
ChatMessageProperty::GetLocale(prop.c_str()),
|
||||
prop.c_str());
|
||||
}
|
||||
|
||||
auto buttonbox = new QDialogButtonBox(QDialogButtonBox::Ok |
|
||||
QDialogButtonBox::Cancel);
|
||||
buttonbox->button(QDialogButtonBox::Ok)->setDisabled(true);
|
||||
|
||||
// Cast is required to support all versions of Qt 5
|
||||
connect(_selection,
|
||||
static_cast<void (QComboBox::*)(int)>(
|
||||
&QComboBox::currentIndexChanged),
|
||||
this, [buttonbox](int idx) {
|
||||
buttonbox->button(QDialogButtonBox::Ok)
|
||||
->setDisabled(idx == -1);
|
||||
});
|
||||
|
||||
buttonbox->setCenterButtons(true);
|
||||
connect(buttonbox, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||
connect(buttonbox, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
auto layout = new QVBoxLayout();
|
||||
layout->addWidget(new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.twitch.type.chat.properties.select")));
|
||||
layout->addWidget(_selection);
|
||||
layout->addWidget(buttonbox);
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
std::optional<ChatMessageProperty> PropertySelectionDialog::AskForPorperty(
|
||||
const std::vector<ChatMessageProperty> ¤tProperties)
|
||||
{
|
||||
PropertySelectionDialog dialog(GetSettingsWindow());
|
||||
dialog.setWindowTitle(obs_module_text("AdvSceneSwitcher.windowTitle"));
|
||||
|
||||
for (const auto ¤tProperty : currentProperties) {
|
||||
if (currentProperty.IsReusable()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int idx = dialog._selection->findText(
|
||||
currentProperty.GetLocale());
|
||||
if (idx == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
qobject_cast<QListView *>(dialog._selection->view())
|
||||
->setRowHidden(idx, true);
|
||||
}
|
||||
|
||||
if (dialog.exec() != DialogCode::Accepted) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto currentItem =
|
||||
dialog._selection->itemData(dialog._selection->currentIndex());
|
||||
const auto id = currentItem.toString().toStdString();
|
||||
return ChatMessageProperty{
|
||||
id, ChatMessageProperty::GetDefaultValue(id.c_str())};
|
||||
}
|
||||
|
||||
ChatMessageEdit::ChatMessageEdit(QWidget *parent)
|
||||
: ListEditor(parent, false),
|
||||
_message(new VariableTextEdit(this, 5, 1, 1)),
|
||||
_regex(new RegexConfigWidget(parent))
|
||||
{
|
||||
_list->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
_list->setAutoScroll(false);
|
||||
|
||||
connect(_message, &VariableTextEdit::textChanged, this,
|
||||
&ChatMessageEdit::MessageChanged);
|
||||
connect(_regex, &RegexConfigWidget::RegexConfigChanged, this,
|
||||
&ChatMessageEdit::RegexChanged);
|
||||
|
||||
auto messageLayout = new QHBoxLayout();
|
||||
messageLayout->addWidget(_message);
|
||||
messageLayout->addWidget(_regex);
|
||||
|
||||
_mainLayout->insertLayout(0, messageLayout);
|
||||
_mainLayout->insertWidget(
|
||||
1,
|
||||
new QLabel(obs_module_text(
|
||||
"AdvSceneSwitcher.condition.twitch.type.chat.properties")));
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void ChatMessageEdit::SetMessagePattern(const ChatMessagePattern &pattern)
|
||||
{
|
||||
_currentSelection = pattern;
|
||||
_message->setPlainText(pattern._message);
|
||||
_regex->SetRegexConfig(pattern._regex);
|
||||
|
||||
_list->clear();
|
||||
_currentSelection._properties.clear();
|
||||
for (const auto &property : pattern._properties) {
|
||||
InsertElement(property);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatMessageEdit::Remove()
|
||||
{
|
||||
auto item = _list->currentItem();
|
||||
int idx = _list->currentRow();
|
||||
if (!item || idx == -1) {
|
||||
return;
|
||||
}
|
||||
delete item;
|
||||
_currentSelection._properties.erase(
|
||||
_currentSelection._properties.begin() + idx);
|
||||
emit ChatMessagePatternChanged(_currentSelection);
|
||||
UpdateListSize();
|
||||
}
|
||||
|
||||
void ChatMessageEdit::PropertyChanged(const ChatMessageProperty &property)
|
||||
{
|
||||
int idx = GetIndexOfSignal();
|
||||
if (idx == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
_currentSelection._properties.at(idx) = property;
|
||||
_list->setCurrentRow(idx);
|
||||
emit ChatMessagePatternChanged(_currentSelection);
|
||||
}
|
||||
|
||||
void ChatMessageEdit::ElementFocussed()
|
||||
{
|
||||
int idx = GetIndexOfSignal();
|
||||
if (idx == -1) {
|
||||
return;
|
||||
}
|
||||
_list->setCurrentRow(idx);
|
||||
}
|
||||
|
||||
void ChatMessageEdit::MessageChanged()
|
||||
{
|
||||
_currentSelection._message = _message->toPlainText().toStdString();
|
||||
emit ChatMessagePatternChanged(_currentSelection);
|
||||
}
|
||||
|
||||
void ChatMessageEdit::RegexChanged(const RegexConfig ®ex)
|
||||
{
|
||||
_currentSelection._regex = regex;
|
||||
emit ChatMessagePatternChanged(_currentSelection);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void ChatMessageEdit::InsertElement(const ChatMessageProperty &property)
|
||||
{
|
||||
auto item = new QListWidgetItem(_list);
|
||||
_list->addItem(item);
|
||||
auto propertyEdit = new ChatMessagePropertyEdit(this, property);
|
||||
item->setSizeHint(propertyEdit->minimumSizeHint());
|
||||
_list->setItemWidget(item, propertyEdit);
|
||||
QWidget::connect(propertyEdit,
|
||||
SIGNAL(PropertyChanged(const ChatMessageProperty &)),
|
||||
this,
|
||||
SLOT(PropertyChanged(const ChatMessageProperty &)));
|
||||
QWidget::connect(propertyEdit, SIGNAL(Focussed()), this,
|
||||
SLOT(ElementFocussed()));
|
||||
_currentSelection._properties.push_back(property);
|
||||
}
|
||||
|
||||
void ChatMessageEdit::Add()
|
||||
{
|
||||
auto newProp = PropertySelectionDialog::AskForPorperty(
|
||||
_currentSelection._properties);
|
||||
if (!newProp) {
|
||||
return;
|
||||
}
|
||||
|
||||
InsertElement(*newProp);
|
||||
emit ChatMessagePatternChanged(_currentSelection);
|
||||
UpdateListSize();
|
||||
}
|
||||
|
||||
ChatMessagePropertyEdit::ChatMessagePropertyEdit(
|
||||
QWidget *parent, const ChatMessageProperty &property)
|
||||
: QWidget(parent),
|
||||
_boolValue(new QCheckBox(property.GetLocale(), this)),
|
||||
_textValue(new VariableLineEdit(this)),
|
||||
_regex(new RegexConfigWidget(this)),
|
||||
_property(property)
|
||||
{
|
||||
installEventFilter(this);
|
||||
|
||||
if (std::holds_alternative<bool>(property._value)) {
|
||||
const bool value = std::get<bool>(property._value);
|
||||
_boolValue->setChecked(value);
|
||||
} else if (std::holds_alternative<StringVariable>(property._value)) {
|
||||
const auto value = std::get<StringVariable>(property._value);
|
||||
_textValue->setText(value);
|
||||
_regex->SetRegexConfig(property._regex);
|
||||
}
|
||||
|
||||
connect(_boolValue, &QCheckBox::stateChanged, this, [this](int value) {
|
||||
_property._value = static_cast<bool>(value);
|
||||
emit PropertyChanged(_property);
|
||||
});
|
||||
connect(_textValue, &VariableLineEdit::editingFinished, this, [this]() {
|
||||
_property._value = _textValue->text().toStdString();
|
||||
emit PropertyChanged(_property);
|
||||
});
|
||||
connect(_regex, &RegexConfigWidget::RegexConfigChanged, this,
|
||||
[this](const RegexConfig ®ex) {
|
||||
_property._regex = regex;
|
||||
emit PropertyChanged(_property);
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
});
|
||||
|
||||
auto layout = new QHBoxLayout();
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(_boolValue);
|
||||
layout->addWidget(_textValue);
|
||||
if (std::holds_alternative<StringVariable>(property._value)) {
|
||||
layout->insertWidget(0, new QLabel(property.GetLocale()));
|
||||
layout->addWidget(_regex);
|
||||
}
|
||||
setLayout(layout);
|
||||
|
||||
SetVisibility();
|
||||
}
|
||||
|
||||
bool ChatMessagePropertyEdit::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::MouseButtonPress ||
|
||||
event->type() == QEvent::MouseButtonDblClick) {
|
||||
emit Focussed();
|
||||
}
|
||||
|
||||
return QWidget::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
void ChatMessagePropertyEdit::showEvent(QShowEvent *event)
|
||||
{
|
||||
QWidget::showEvent(event);
|
||||
|
||||
QWidgetList childWidgets = findChildren<QWidget *>();
|
||||
for (QWidget *childWidget : childWidgets) {
|
||||
childWidget->installEventFilter(this);
|
||||
}
|
||||
}
|
||||
|
||||
void ChatMessagePropertyEdit::SetVisibility()
|
||||
{
|
||||
auto defaultValue = _property.GetDefaultValue();
|
||||
_boolValue->setVisible(std::holds_alternative<bool>(defaultValue));
|
||||
const bool isTextValue =
|
||||
std::holds_alternative<StringVariable>(defaultValue);
|
||||
_textValue->setVisible(isTextValue);
|
||||
_regex->setVisible(isTextValue);
|
||||
}
|
||||
|
||||
void ChatMessageProperty::Save(obs_data_t *obj) const
|
||||
{
|
||||
obs_data_set_string(obj, "id", _id.c_str());
|
||||
std::visit(
|
||||
[obj, this](auto &&arg) {
|
||||
using T = std::decay_t<decltype(arg)>;
|
||||
if constexpr (std::is_same_v<T, bool>) {
|
||||
obs_data_set_bool(obj, "boolValue", arg);
|
||||
} else if constexpr (std::is_same_v<T, StringVariable>) {
|
||||
arg.Save(obj, "strValue");
|
||||
_regex.Save(obj);
|
||||
} else {
|
||||
blog(LOG_WARNING,
|
||||
"cannot save unknown chat message property");
|
||||
}
|
||||
},
|
||||
_value);
|
||||
}
|
||||
|
||||
void ChatMessageProperty::Load(obs_data_t *obj)
|
||||
{
|
||||
_id = obs_data_get_string(obj, "id");
|
||||
|
||||
if (obs_data_has_user_value(obj, "strValue")) {
|
||||
StringVariable value;
|
||||
value.Load(obj, "strValue");
|
||||
_value = value;
|
||||
_regex.Load(obj);
|
||||
} else if (obs_data_has_user_value(obj, "boolValue")) {
|
||||
bool value = obs_data_get_bool(obj, "boolValue");
|
||||
_value = value;
|
||||
} else {
|
||||
blog(LOG_WARNING, "cannot load unknown chat message property");
|
||||
}
|
||||
}
|
||||
|
||||
QString ChatMessageProperty::GetLocale(const char *id)
|
||||
{
|
||||
auto it = std::find_if(_supportedProperties.begin(),
|
||||
_supportedProperties.end(),
|
||||
[id](const PropertyInfo &pi) {
|
||||
return std::string(pi._id) == id;
|
||||
});
|
||||
if (it == _supportedProperties.end()) {
|
||||
return "";
|
||||
}
|
||||
return obs_module_text(it->_locale);
|
||||
}
|
||||
|
||||
std::variant<bool, StringVariable>
|
||||
ChatMessageProperty::GetDefaultValue(const char *id)
|
||||
{
|
||||
auto it = std::find_if(_supportedProperties.begin(),
|
||||
_supportedProperties.end(),
|
||||
[id](const PropertyInfo &pi) {
|
||||
return std::string(pi._id) == id;
|
||||
});
|
||||
if (it == _supportedProperties.end()) {
|
||||
return "";
|
||||
}
|
||||
return it->_defaultValue;
|
||||
}
|
||||
|
||||
std::variant<bool, StringVariable> ChatMessageProperty::GetDefaultValue() const
|
||||
{
|
||||
return GetDefaultValue(_id.c_str());
|
||||
}
|
||||
|
||||
const std::vector<std::string> &ChatMessageProperty::GetSupportedIds()
|
||||
{
|
||||
static std::vector<std::string> supportedIds;
|
||||
static bool setupDone = false;
|
||||
if (!setupDone) {
|
||||
for (const auto &prop : _supportedProperties) {
|
||||
supportedIds.emplace_back(prop._id);
|
||||
}
|
||||
setupDone = true;
|
||||
}
|
||||
return supportedIds;
|
||||
}
|
||||
|
||||
bool ChatMessageProperty::Matches(const IRCMessage &message) const
|
||||
{
|
||||
auto it = std::find_if(_supportedProperties.begin(),
|
||||
_supportedProperties.end(),
|
||||
[this](const PropertyInfo &pi) {
|
||||
return std::string(pi._id) == _id;
|
||||
});
|
||||
if (it == _supportedProperties.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return it->_checkForMatch(message, *this);
|
||||
}
|
||||
|
||||
bool ChatMessageProperty::IsReusable() const
|
||||
{
|
||||
auto it = std::find_if(_supportedProperties.begin(),
|
||||
_supportedProperties.end(),
|
||||
[this](const PropertyInfo &pi) {
|
||||
return std::string(pi._id) == _id;
|
||||
});
|
||||
if (it == _supportedProperties.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return it->_isReusable;
|
||||
}
|
||||
|
||||
void ChatMessagePattern::Save(obs_data_t *obj) const
|
||||
{
|
||||
OBSDataAutoRelease data = obs_data_create();
|
||||
_message.Save(data, "message");
|
||||
_regex.Save(data, "regex");
|
||||
|
||||
OBSDataArrayAutoRelease properties = obs_data_array_create();
|
||||
for (const auto &property : _properties) {
|
||||
OBSDataAutoRelease arrayObj = obs_data_create();
|
||||
property.Save(arrayObj);
|
||||
obs_data_array_push_back(properties, arrayObj);
|
||||
}
|
||||
obs_data_set_array(data, "properties", properties);
|
||||
obs_data_set_obj(obj, "chatMessagePattern", data);
|
||||
}
|
||||
|
||||
void ChatMessagePattern::Load(obs_data_t *obj)
|
||||
{
|
||||
if (!obs_data_has_user_value(obj, "chatMessagePattern")) {
|
||||
// Backward compatibility
|
||||
_message.Load(obj, "chatMessage");
|
||||
_regex.Load(obj, "regexChat");
|
||||
return;
|
||||
}
|
||||
|
||||
OBSDataAutoRelease data = obs_data_get_obj(obj, "chatMessagePattern");
|
||||
_message.Load(data, "message");
|
||||
_regex.Load(data, "regex");
|
||||
|
||||
OBSDataArrayAutoRelease properties =
|
||||
obs_data_get_array(data, "properties");
|
||||
size_t count = obs_data_array_count(properties);
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
OBSDataAutoRelease arrayObj =
|
||||
obs_data_array_item(properties, i);
|
||||
ChatMessageProperty property;
|
||||
property.Load(arrayObj);
|
||||
_properties.push_back(property);
|
||||
}
|
||||
}
|
||||
|
||||
bool ChatMessagePattern::Matches(const IRCMessage &chatMessage) const
|
||||
{
|
||||
const bool messageMatch =
|
||||
!_regex.Enabled()
|
||||
? chatMessage.message == std::string(_message)
|
||||
: _regex.Matches(chatMessage.message, _message);
|
||||
if (!messageMatch) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &property : _properties) {
|
||||
if (!property.Matches(chatMessage)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace advss
|
||||
114
plugins/twitch/chat-message-pattern.hpp
Normal file
114
plugins/twitch/chat-message-pattern.hpp
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
#pragma once
|
||||
#include "chat-connection.hpp"
|
||||
|
||||
#include <list-editor.hpp>
|
||||
#include <regex-config.hpp>
|
||||
#include <variable-text-edit.hpp>
|
||||
|
||||
namespace advss {
|
||||
|
||||
class ChatMessageProperty {
|
||||
public:
|
||||
void Save(obs_data_t *obj) const;
|
||||
void Load(obs_data_t *obj);
|
||||
|
||||
std::string _id;
|
||||
std::variant<bool, StringVariable> _value;
|
||||
RegexConfig _regex;
|
||||
|
||||
static QString GetLocale(const char *id);
|
||||
QString GetLocale() const { return GetLocale(_id.c_str()); }
|
||||
static std::variant<bool, StringVariable>
|
||||
GetDefaultValue(const char *id);
|
||||
std::variant<bool, StringVariable> GetDefaultValue() const;
|
||||
static const std::vector<std::string> &GetSupportedIds();
|
||||
bool Matches(const IRCMessage &) const;
|
||||
bool IsReusable() const;
|
||||
|
||||
private:
|
||||
struct PropertyInfo {
|
||||
const char *_id;
|
||||
const char *_locale;
|
||||
std::variant<bool, StringVariable> _defaultValue;
|
||||
std::function<bool(const IRCMessage &,
|
||||
const ChatMessageProperty &)>
|
||||
_checkForMatch;
|
||||
bool _isReusable = false;
|
||||
};
|
||||
static const std::vector<PropertyInfo> _supportedProperties;
|
||||
};
|
||||
|
||||
class ChatMessagePattern {
|
||||
public:
|
||||
void Save(obs_data_t *obj) const;
|
||||
void Load(obs_data_t *obj);
|
||||
|
||||
bool Matches(const IRCMessage &) const;
|
||||
|
||||
StringVariable _message;
|
||||
RegexConfig _regex = RegexConfig::PartialMatchRegexConfig();
|
||||
std::vector<ChatMessageProperty> _properties;
|
||||
};
|
||||
|
||||
class PropertySelectionDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PropertySelectionDialog(QWidget *parent);
|
||||
static std::optional<ChatMessageProperty> AskForPorperty(
|
||||
const std::vector<ChatMessageProperty> ¤tProperties);
|
||||
|
||||
private:
|
||||
QComboBox *_selection;
|
||||
};
|
||||
|
||||
class ChatMessagePropertyEdit : public QWidget {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ChatMessagePropertyEdit(QWidget *, const ChatMessageProperty &);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
void showEvent(QShowEvent *event) override;
|
||||
|
||||
signals:
|
||||
void PropertyChanged(const ChatMessageProperty &);
|
||||
void Focussed();
|
||||
|
||||
private:
|
||||
void SetVisibility();
|
||||
|
||||
QCheckBox *_boolValue;
|
||||
VariableLineEdit *_textValue;
|
||||
RegexConfigWidget *_regex;
|
||||
|
||||
ChatMessageProperty _property;
|
||||
};
|
||||
|
||||
class ChatMessageEdit final : public ListEditor {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ChatMessageEdit(QWidget *parent);
|
||||
void SetMessagePattern(const ChatMessagePattern &);
|
||||
|
||||
private slots:
|
||||
void MessageChanged();
|
||||
void RegexChanged(const RegexConfig &);
|
||||
void Add();
|
||||
void Remove();
|
||||
void PropertyChanged(const ChatMessageProperty &);
|
||||
void ElementFocussed();
|
||||
|
||||
signals:
|
||||
void ChatMessagePatternChanged(const ChatMessagePattern &);
|
||||
|
||||
private:
|
||||
void InsertElement(const ChatMessageProperty &);
|
||||
|
||||
VariableTextEdit *_message;
|
||||
RegexConfigWidget *_regex;
|
||||
ChatMessagePattern _currentSelection;
|
||||
};
|
||||
|
||||
} // namespace advss
|
||||
|
|
@ -384,13 +384,15 @@ bool MacroConditionTwitch::CheckChatMessages(TwitchToken &token)
|
|||
if (!message) {
|
||||
continue;
|
||||
}
|
||||
if (!stringMatches(_regexChat, message->message,
|
||||
_chatMessage)) {
|
||||
|
||||
if (!_chatMessagePattern.Matches(*message)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SetTempVarValue("chatter", message->source.nick);
|
||||
SetTempVarValue("user_login", message->source.nick);
|
||||
SetTempVarValue("user_name", message->properties.displayName);
|
||||
SetTempVarValue("chat_message", message->message);
|
||||
SetTempVarValue("badges", message->properties.badgesString);
|
||||
|
||||
if (_clearBufferOnMatch) {
|
||||
_eventBuffer->Clear();
|
||||
|
|
@ -600,8 +602,7 @@ bool MacroConditionTwitch::Save(obs_data_t *obj) const
|
|||
_pointsReward.Save(obj);
|
||||
_streamTitle.Save(obj, "streamTitle");
|
||||
_regexTitle.Save(obj, "regexTitle");
|
||||
_chatMessage.Save(obj, "chatMessage");
|
||||
_regexChat.Save(obj, "regexChat");
|
||||
_chatMessagePattern.Save(obj);
|
||||
_category.Save(obj);
|
||||
obs_data_set_bool(obj, "clearBufferOnMatch", _clearBufferOnMatch);
|
||||
obs_data_set_int(obj, "version", 1);
|
||||
|
|
@ -619,8 +620,7 @@ bool MacroConditionTwitch::Load(obs_data_t *obj)
|
|||
_pointsReward.Load(obj);
|
||||
_streamTitle.Load(obj, "streamTitle");
|
||||
_regexTitle.Load(obj, "regexTitle");
|
||||
_chatMessage.Load(obj, "chatMessage");
|
||||
_regexChat.Load(obj, "regexChat");
|
||||
_chatMessagePattern.Load(obj);
|
||||
_category.Load(obj);
|
||||
_clearBufferOnMatch = obs_data_get_bool(obj, "clearBufferOnMatch");
|
||||
if (!obs_data_has_user_value(obj, "version")) {
|
||||
|
|
@ -1236,8 +1236,10 @@ void MacroConditionTwitch::SetupTempVars()
|
|||
setupTempVarHelper("is_branded_content");
|
||||
break;
|
||||
case Condition::CHAT_MESSAGE_RECEIVED:
|
||||
setupTempVarHelper("chat_message");
|
||||
setupTempVarHelper("chatter");
|
||||
setupTempVarHelper("chat_message", ".chatReceive");
|
||||
setupTempVarHelper("user_login", ".chatReceive");
|
||||
setupTempVarHelper("user_name", ".chatReceive");
|
||||
setupTempVarHelper("badges", ".chatReceive");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
@ -1263,8 +1265,7 @@ MacroConditionTwitchEdit::MacroConditionTwitchEdit(
|
|||
_pointsReward(new TwitchPointsRewardWidget(this)),
|
||||
_streamTitle(new VariableLineEdit(this)),
|
||||
_regexTitle(new RegexConfigWidget(parent)),
|
||||
_chatMessage(new VariableTextEdit(this, 5, 1, 1)),
|
||||
_regexChat(new RegexConfigWidget(parent)),
|
||||
_chatMesageEdit(new ChatMessageEdit(this)),
|
||||
_category(new TwitchCategoryWidget(this)),
|
||||
_clearBufferOnMatch(new QCheckBox(
|
||||
obs_module_text("AdvSceneSwitcher.clearBufferOnMatch")))
|
||||
|
|
@ -1293,11 +1294,11 @@ MacroConditionTwitchEdit::MacroConditionTwitchEdit(
|
|||
QWidget::connect(_regexTitle,
|
||||
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
|
||||
SLOT(RegexTitleChanged(const RegexConfig &)));
|
||||
QWidget::connect(_chatMessage, SIGNAL(textChanged()), this,
|
||||
SLOT(ChatMessageChanged()));
|
||||
QWidget::connect(_regexChat,
|
||||
SIGNAL(RegexConfigChanged(const RegexConfig &)), this,
|
||||
SLOT(RegexChatChanged(const RegexConfig &)));
|
||||
QWidget::connect(
|
||||
_chatMesageEdit,
|
||||
SIGNAL(ChatMessagePatternChanged(const ChatMessagePattern &)),
|
||||
this,
|
||||
SLOT(ChatMessagePatternChanged(const ChatMessagePattern &)));
|
||||
QWidget::connect(_category,
|
||||
SIGNAL(CategoreyChanged(const TwitchCategory &)), this,
|
||||
SLOT(CategoreyChanged(const TwitchCategory &)));
|
||||
|
|
@ -1324,10 +1325,7 @@ MacroConditionTwitchEdit::MacroConditionTwitchEdit(
|
|||
|
||||
auto mainLayout = new QVBoxLayout();
|
||||
mainLayout->addLayout(_layout);
|
||||
auto chatLayout = new QHBoxLayout();
|
||||
chatLayout->addWidget(_chatMessage);
|
||||
chatLayout->addWidget(_regexChat);
|
||||
mainLayout->addLayout(chatLayout);
|
||||
mainLayout->addWidget(_chatMesageEdit);
|
||||
mainLayout->addLayout(accountLayout);
|
||||
mainLayout->addWidget(_tokenWarning);
|
||||
mainLayout->addWidget(_clearBufferOnMatch);
|
||||
|
|
@ -1431,10 +1429,13 @@ void MacroConditionTwitchEdit::StreamTitleChanged()
|
|||
_entryData->_streamTitle = _streamTitle->text().toStdString();
|
||||
}
|
||||
|
||||
void MacroConditionTwitchEdit::ChatMessageChanged()
|
||||
void MacroConditionTwitchEdit::ChatMessagePatternChanged(
|
||||
const ChatMessagePattern &chatMessagePattern)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_chatMessage = _chatMessage->toPlainText().toStdString();
|
||||
_entryData->_chatMessagePattern = chatMessagePattern;
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroConditionTwitchEdit::RegexTitleChanged(const RegexConfig &conf)
|
||||
|
|
@ -1446,15 +1447,6 @@ void MacroConditionTwitchEdit::RegexTitleChanged(const RegexConfig &conf)
|
|||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroConditionTwitchEdit::RegexChatChanged(const RegexConfig &conf)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
_entryData->_regexChat = conf;
|
||||
|
||||
adjustSize();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
void MacroConditionTwitchEdit::CategoreyChanged(const TwitchCategory &category)
|
||||
{
|
||||
GUARD_LOADING_AND_LOCK();
|
||||
|
|
@ -1484,10 +1476,7 @@ void MacroConditionTwitchEdit::SetWidgetVisibility()
|
|||
condition == MacroConditionTwitch::Condition::TITLE_POLLING);
|
||||
_regexTitle->setVisible(condition ==
|
||||
MacroConditionTwitch::Condition::TITLE_POLLING);
|
||||
_chatMessage->setVisible(
|
||||
condition ==
|
||||
MacroConditionTwitch::Condition::CHAT_MESSAGE_RECEIVED);
|
||||
_regexChat->setVisible(
|
||||
_chatMesageEdit->setVisible(
|
||||
condition ==
|
||||
MacroConditionTwitch::Condition::CHAT_MESSAGE_RECEIVED);
|
||||
_category->setVisible(
|
||||
|
|
@ -1525,8 +1514,7 @@ void MacroConditionTwitchEdit::UpdateEntryData()
|
|||
_pointsReward->SetPointsReward(_entryData->_pointsReward);
|
||||
_streamTitle->setText(_entryData->_streamTitle);
|
||||
_regexTitle->SetRegexConfig(_entryData->_regexTitle);
|
||||
_chatMessage->setPlainText(_entryData->_chatMessage);
|
||||
_regexChat->SetRegexConfig(_entryData->_regexChat);
|
||||
_chatMesageEdit->SetMessagePattern(_entryData->_chatMessagePattern);
|
||||
_category->SetToken(_entryData->GetToken());
|
||||
_category->SetCategory(_entryData->_category);
|
||||
_clearBufferOnMatch->setChecked(_entryData->_clearBufferOnMatch);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include "channel-selection.hpp"
|
||||
#include "points-reward-selection.hpp"
|
||||
#include "chat-connection.hpp"
|
||||
#include "chat-message-pattern.hpp"
|
||||
|
||||
#include <variable-line-edit.hpp>
|
||||
#include <variable-text-edit.hpp>
|
||||
|
|
@ -101,8 +102,7 @@ public:
|
|||
StringVariable _streamTitle = obs_module_text(
|
||||
"AdvSceneSwitcher.condition.twitch.title.title");
|
||||
RegexConfig _regexTitle = RegexConfig::PartialMatchRegexConfig();
|
||||
StringVariable _chatMessage;
|
||||
RegexConfig _regexChat = RegexConfig::PartialMatchRegexConfig();
|
||||
ChatMessagePattern _chatMessagePattern;
|
||||
TwitchCategory _category;
|
||||
bool _clearBufferOnMatch = false;
|
||||
|
||||
|
|
@ -166,9 +166,8 @@ private slots:
|
|||
void ChannelChanged(const TwitchChannel &);
|
||||
void PointsRewardChanged(const TwitchPointsReward &);
|
||||
void StreamTitleChanged();
|
||||
void ChatMessageChanged();
|
||||
void RegexTitleChanged(const RegexConfig &);
|
||||
void RegexChatChanged(const RegexConfig &);
|
||||
void ChatMessagePatternChanged(const ChatMessagePattern &);
|
||||
void CategoreyChanged(const TwitchCategory &);
|
||||
void ClearBufferOnMatchChanged(int);
|
||||
|
||||
|
|
@ -189,8 +188,7 @@ private:
|
|||
TwitchPointsRewardWidget *_pointsReward;
|
||||
VariableLineEdit *_streamTitle;
|
||||
RegexConfigWidget *_regexTitle;
|
||||
VariableTextEdit *_chatMessage;
|
||||
RegexConfigWidget *_regexChat;
|
||||
ChatMessageEdit *_chatMesageEdit;
|
||||
TwitchCategoryWidget *_category;
|
||||
QCheckBox *_clearBufferOnMatch;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user