Add option to check if users leave or join Twitch chat

This commit is contained in:
WarmUpTill
2024-10-06 15:12:13 +02:00
committed by WarmUpTill
parent 62ce83a7f6
commit 0fd5f47982
5 changed files with 123 additions and 5 deletions

View File

@@ -713,6 +713,8 @@ AdvSceneSwitcher.condition.twitch.type.chat.properties.color="Color matches"
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.type.chat.userJoined="User joined the chat"
AdvSceneSwitcher.condition.twitch.type.chat.userLeft="User left the chat"
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}}"
@@ -1765,6 +1767,12 @@ AdvSceneSwitcher.tempVar.twitch.is_turbo.chatReceive.description="'true' if the
AdvSceneSwitcher.tempVar.twitch.is_vip.chatReceive="Is chatter a VIP"
AdvSceneSwitcher.tempVar.twitch.is_vip.chatReceive.description="'true' if the chatter is a VIP in the channel, 'false' otherwise."
AdvSceneSwitcher.tempVar.twitch.user_login.chatJoin="User login"
AdvSceneSwitcher.tempVar.twitch.user_login.chatJoin.description="The user login of the person who joined the chat room."
AdvSceneSwitcher.tempVar.twitch.user_login.chatLeave="User login"
AdvSceneSwitcher.tempVar.twitch.user_login.chatLeave.description="The user login of the person who left the chat room."
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."
AdvSceneSwitcher.tempVar.twitch.from_broadcaster_user_login.raid="Raid creator user login"

View File

@@ -181,8 +181,6 @@ static void parseCommand(const std::string &rawCommandComponent,
return;
} else if (message.command.command == "PING" ||
message.command.command == "001" ||
message.command.command == "JOIN" ||
message.command.command == "PART" ||
message.command.command == "NOTICE" ||
message.command.command == "CLEARCHAT" ||
message.command.command == "HOSTTARGET" ||
@@ -191,6 +189,18 @@ static void parseCommand(const std::string &rawCommandComponent,
return;
}
message.command.parameters = commandParts[1];
} else if (message.command.command == "JOIN") {
if (commandParts.size() < 2) {
return;
}
message.properties.joinedChannel = true;
message.command.parameters = commandParts[1];
} else if (message.command.command == "PART") {
if (commandParts.size() < 2) {
return;
}
message.properties.leftChannel = true;
message.command.parameters = commandParts[1];
} else if (message.command.command == "GLOBALUSERSTATE" ||
message.command.command == "USERSTATE" ||
message.command.command == "ROOMSTATE" ||
@@ -504,12 +514,34 @@ void TwitchChatConnection::JoinChannel(const std::string &channelName)
Send("JOIN #" + channelName);
}
static bool nickMatchesTokenUser(const std::string &nick, TwitchToken &token)
{
auto tokenUserName = token.GetName();
std::transform(tokenUserName.begin(), tokenUserName.end(),
tokenUserName.begin(),
[](unsigned char c) { return std::tolower(c); });
return nick == tokenUserName;
}
void TwitchChatConnection::HandleJoin(const IRCMessage &message)
{
if (!nickMatchesTokenUser(message.source.nick, _token)) {
_messageDispatcher.DispatchMessage(message);
return;
}
_joinedChannelName = std::get<std::string>(message.command.parameters);
vblog(LOG_INFO, "Twitch chat join was successful!");
}
void TwitchChatConnection::HandlePart(const IRCMessage &message)
{
if (!nickMatchesTokenUser(message.source.nick, _token)) {
_messageDispatcher.DispatchMessage(message);
return;
}
vblog(LOG_INFO, "Left Twitch chat!");
}
void TwitchChatConnection::HandleNewMessage(const IRCMessage &message)
{
_messageDispatcher.DispatchMessage(message);
@@ -571,7 +603,8 @@ void TwitchChatConnection::OnMessage(
{
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 joinCommand = "JOIN";
static constexpr std::string_view partCommand = "PART";
static constexpr std::string_view noticeCommand = "NOTICE";
static constexpr std::string_view reconnectCommand = "RECONNECT";
static constexpr std::string_view newMessageCommand = "PRIVMSG";
@@ -596,8 +629,10 @@ void TwitchChatConnection::OnMessage(
} else if (message.command.command == pingCommand) {
Send("PONG " +
std::get<std::string>(message.command.parameters));
} else if (message.command.command == joinOKCommand) {
} else if (message.command.command == joinCommand) {
HandleJoin(message);
} else if (message.command.command == partCommand) {
HandlePart(message);
} else if (message.command.command == newMessageCommand) {
HandleNewMessage(message);
} else if (message.command.command == whisperCommand) {

View File

@@ -44,6 +44,8 @@ struct IRCMessage {
std::string userId;
std::string userType;
bool isVIP = false;
bool joinedChannel = false;
bool leftChannel = false;
} properties;
struct {
@@ -95,6 +97,7 @@ private:
void Authenticate();
void JoinChannel(const std::string &);
void HandleJoin(const IRCMessage &);
void HandlePart(const IRCMessage &);
void HandleNewMessage(const IRCMessage &);
void HandleWhisper(const IRCMessage &);
void HandleNotice(const IRCMessage &) const;

View File

@@ -121,6 +121,10 @@ const static std::map<MacroConditionTwitch::Condition, std::string> conditionTyp
"AdvSceneSwitcher.condition.twitch.type.polling.channel.category"},
{MacroConditionTwitch::Condition::CHAT_MESSAGE_RECEIVED,
"AdvSceneSwitcher.condition.twitch.type.chat.message"},
{MacroConditionTwitch::Condition::CHAT_USER_JOINED,
"AdvSceneSwitcher.condition.twitch.type.chat.userJoined"},
{MacroConditionTwitch::Condition::CHAT_USER_LEFT,
"AdvSceneSwitcher.condition.twitch.type.chat.userLeft"},
};
const static std::map<MacroConditionTwitch::Condition, std::string> eventIdentifiers = {
@@ -385,6 +389,12 @@ bool MacroConditionTwitch::CheckChatMessages(TwitchToken &token)
continue;
}
// Join and leave message don't have any message data
if (message->properties.leftChannel ||
message->properties.joinedChannel) {
continue;
}
if (!_chatMessagePattern.Matches(*message)) {
continue;
}
@@ -443,6 +453,41 @@ bool MacroConditionTwitch::CheckChatMessages(TwitchToken &token)
return false;
}
bool MacroConditionTwitch::CheckChatUserJoinOrLeave(TwitchToken &token)
{
if (!_chatConnection) {
_chatConnection = TwitchChatConnection::GetChatConnection(
token, _channel);
if (!_chatConnection) {
return false;
}
_chatBuffer = _chatConnection->RegisterForMessages();
return false;
}
while (!_chatBuffer->Empty()) {
auto message = _chatBuffer->ConsumeMessage();
if (!message) {
continue;
}
if ((_condition == Condition::CHAT_USER_JOINED &&
!message->properties.joinedChannel) ||
(_condition == Condition::CHAT_USER_LEFT &&
!message->properties.leftChannel)) {
continue;
}
SetTempVarValue("user_login", message->source.nick);
if (_clearBufferOnMatch) {
_eventBuffer->Clear();
}
return true;
}
return false;
}
void MacroConditionTwitch::SetTempVarValues(const ChannelLiveInfo &info)
{
SetTempVarValue("broadcaster_user_id", info.user_id);
@@ -625,6 +670,14 @@ bool MacroConditionTwitch::CheckCondition()
}
return CheckChatMessages(*token);
}
case Condition::CHAT_USER_JOINED:
case Condition::CHAT_USER_LEFT: {
auto token = _token.lock();
if (!token) {
return false;
}
return CheckChatUserJoinOrLeave(*token);
}
default:
break;
}
@@ -773,6 +826,10 @@ bool MacroConditionTwitch::ConditionIsSupportedByToken()
{Condition::CATEGORY_POLLING, {}},
{Condition::CHAT_MESSAGE_RECEIVED,
{{"chat:read"}, {"chat:edit"}}},
{Condition::CHAT_USER_JOINED,
{{"chat:read"}, {"chat:edit"}}},
{Condition::CHAT_USER_LEFT,
{{"chat:read"}, {"chat:edit"}}},
};
auto token = _token.lock();
@@ -967,6 +1024,8 @@ void MacroConditionTwitch::SetupTempVars()
};
if (_condition != Condition::CHAT_MESSAGE_RECEIVED &&
_condition != Condition::CHAT_USER_JOINED &&
_condition != Condition::CHAT_USER_LEFT &&
_condition != Condition::RAID_INBOUND_EVENT &&
_condition != Condition::RAID_OUTBOUND_EVENT) {
setupTempVarHelper("broadcaster_user_id");
@@ -1303,6 +1362,12 @@ void MacroConditionTwitch::SetupTempVars()
setupTempVarHelper("is_turbo", ".chatReceive");
setupTempVarHelper("is_vip", ".chatReceive");
break;
case Condition::CHAT_USER_JOINED:
setupTempVarHelper("user_login", ".chatJoin");
break;
case Condition::CHAT_USER_LEFT:
setupTempVarHelper("user_login", ".chatLeave");
break;
default:
break;
}
@@ -1546,7 +1611,11 @@ void MacroConditionTwitchEdit::SetWidgetVisibility()
_clearBufferOnMatch->setVisible(
_entryData->IsUsingEventSubCondition() ||
_entryData->GetCondition() ==
MacroConditionTwitch::Condition::CHAT_MESSAGE_RECEIVED);
MacroConditionTwitch::Condition::CHAT_MESSAGE_RECEIVED ||
_entryData->GetCondition() ==
MacroConditionTwitch::Condition::CHAT_USER_JOINED ||
_entryData->GetCondition() ==
MacroConditionTwitch::Condition::CHAT_USER_LEFT);
if (condition == MacroConditionTwitch::Condition::TITLE_POLLING) {
RemoveStretchIfPresent(_layout);

View File

@@ -74,6 +74,8 @@ public:
// Chat
CHAT_MESSAGE_RECEIVED = 500000,
CHAT_USER_JOINED = 500100,
CHAT_USER_LEFT = 500200,
// Polling
LIVE_POLLING = 1000000,
@@ -110,6 +112,7 @@ private:
bool CheckChannelGenericEvents();
bool CheckChannelLiveEvents();
bool CheckChatMessages(TwitchToken &token);
bool CheckChatUserJoinOrLeave(TwitchToken &token);
void RegisterEventSubscription();
void ResetSubscription();