diff --git a/src/backend/auth/twitch-auth.ts b/src/backend/auth/twitch-auth.ts index 584d2cb18..1f8495af1 100644 --- a/src/backend/auth/twitch-auth.ts +++ b/src/backend/auth/twitch-auth.ts @@ -67,8 +67,11 @@ class TwitchAuthProviders { 'moderator:manage:shield_mode', 'moderator:manage:shoutouts', 'moderator:manage:unban_requests', + 'moderator:manage:warnings', 'moderator:read:automod_settings', + 'moderator:read:banned_users', 'moderator:read:blocked_terms', + 'moderator:read:chat_messages', 'moderator:read:chat_settings', 'moderator:read:chatters', 'moderator:read:followers', @@ -77,6 +80,7 @@ class TwitchAuthProviders { 'moderator:read:shoutouts', 'moderator:read:unban_requests', 'moderator:read:vips', + 'moderator:read:warnings', 'user:edit:broadcast', 'user:manage:blocked_users', 'user:manage:whispers', diff --git a/src/backend/events/builtin/twitch-event-source.js b/src/backend/events/builtin/twitch-event-source.js index e4d9c48bf..87dcd0cb8 100644 --- a/src/backend/events/builtin/twitch-event-source.js +++ b/src/backend/events/builtin/twitch-event-source.js @@ -627,7 +627,7 @@ module.exports = { subscribers: "Subscribers Only", followers: "Followers", slow: "Slow", - r9kbeta: "Unique Chat" + uniquechat: "Unique Chat" }, value: "emoteonly" }, diff --git a/src/backend/events/filters/builtin/twitch/chat-mode.ts b/src/backend/events/filters/builtin/twitch/chat-mode.ts index b68235302..7e5f25a48 100644 --- a/src/backend/events/filters/builtin/twitch/chat-mode.ts +++ b/src/backend/events/filters/builtin/twitch/chat-mode.ts @@ -29,27 +29,29 @@ const filter: EventFilter = { display: "Slow" }, { - value: "r9kbeta", + value: "uniquechat", display: "Unique Chat" } ]; }, getSelectedValueDisplay: async (filterSettings) => { return (await filter.presetValues()) - .find(pv => pv.value === filterSettings.value)?.display ?? "[Not Set]"; + .find(pv => pv.value === filterSettings.value || (filterSettings.value === "r9kbeta" && pv.value === "uniquechat"))?.display ?? "[Not Set]"; }, predicate: async (filterSettings, eventData) => { const { comparisonType, value } = filterSettings; const { eventMeta } = eventData; + // Unique chat previously used 'r9kbeta' on PubSub; became 'uniquechat' on EventSub. + const ucValue = value === "r9kbeta" ? "uniquechat" : value; const chatModes = eventMeta.chatMode as string; switch (comparisonType) { case ComparisonType.IS: - return chatModes.includes(value); + return chatModes.includes(ucValue); case ComparisonType.IS_NOT: - return !chatModes.includes(value); + return !chatModes.includes(ucValue); default: return false; } diff --git a/src/backend/twitch-api/eventsub/eventsub-client.ts b/src/backend/twitch-api/eventsub/eventsub-client.ts index 250e8c5be..8a554598f 100644 --- a/src/backend/twitch-api/eventsub/eventsub-client.ts +++ b/src/backend/twitch-api/eventsub/eventsub-client.ts @@ -472,22 +472,6 @@ class TwitchEventSubClient { }); this._subscriptions.push(channelUpdateSubscription); - // Moderator added - const channelModeratorAddSubscription = this._eventSubListener.onChannelModeratorAdd(streamer.userId, (event) => { - chatRolesManager.addModeratorToModeratorsList({ - id: event.userId, - username: event.userName, - displayName: event.userDisplayName - }); - }); - this._subscriptions.push(channelModeratorAddSubscription); - - // Moderator removed - const channelModeratorRemoveSubscription = this._eventSubListener.onChannelModeratorRemove(streamer.userId, (event) => { - chatRolesManager.removeModeratorFromModeratorsList(event.userId); - }); - this._subscriptions.push(channelModeratorRemoveSubscription); - // Ad break start/end const channelAdBreakBeginSubscription = this._eventSubListener.onChannelAdBreakBegin(streamer.userId, (event) => { twitchEventsHandler.ad.triggerAdBreakStart( @@ -513,6 +497,77 @@ class TwitchEventSubClient { }, adBreakEndTime.getTime() - (new Date()).getTime()); }); this._subscriptions.push(channelAdBreakBeginSubscription); + + // Channel Moderate + const channelModerateSubscription = this._eventSubListener.onChannelModerate(streamer.userId, streamer.userId, (event) => { + switch (event.moderationAction) { + case "clear": + frontendCommunicator.send("twitch:chat:clear-feed", event.moderatorName); + twitchEventsHandler.chat.triggerChatCleared(event.moderatorName, event.moderatorId); + break; + case "mod": + chatRolesManager.addModeratorToModeratorsList({ + id: event.userId, + username: event.userName, + displayName: event.userDisplayName + }); + break; + case "unmod": + chatRolesManager.removeModeratorFromModeratorsList(event.userId); + break; + case "vip": + chatRolesManager.addVipToVipList({ + id: event.userId, + username: event.userName, + displayName: event.userDisplayName + }); + break; + case "unvip": + chatRolesManager.removeVipFromVipList(event.userId); + break; + + // chat modes + case "emoteonly": + case "emoteonlyoff": + case "subscribers": + case "subscribersoff": + case "followers": + case "followersoff": + case "slow": + case "slowoff": + case "uniquechat": + case "uniquechatoff": + twitchEventsHandler.chatModeChanged.triggerChatModeChanged( + event.moderationAction, + event.moderationAction.includes("off") ? "disabled" : "enabled", + event.moderatorName, + event.moderationAction === "slow" ? event.waitTimeSeconds : null + ); + break; + + // Reserving; already handled in bespoke events; less expensive to move those here. + case "ban": + case "unban": + case "raid": + case "unraid": + case "timeout": + case "untimeout": + break; + + // Available for future use: + case "add_blocked_term": + case "add_permitted_term": + case "approve_unban_request": + case "deny_unban_request": + case "delete": + case "remove_blocked_term": + case "remove_permitted_term": + case "warn": + default: + break; + } + }); + this._subscriptions.push(channelModerateSubscription); } async createClient(): Promise { diff --git a/src/backend/twitch-api/pubsub/pubsub-client.js b/src/backend/twitch-api/pubsub/pubsub-client.js index d546bdc74..6dc05211d 100644 --- a/src/backend/twitch-api/pubsub/pubsub-client.js +++ b/src/backend/twitch-api/pubsub/pubsub-client.js @@ -3,7 +3,6 @@ const logger = require("../../logwrapper"); const accountAccess = require("../../common/account-access"); const frontendCommunicator = require("../../common/frontend-communicator"); const firebotDeviceAuthProvider = require("../../auth/firebot-device-auth-provider"); -const chatRolesManager = require("../../roles/chat-roles-manager"); const { PubSubClient } = require("@twurple/pubsub"); const chatCommandHandler = require("../../chat/commands/chat-command-handler"); @@ -116,49 +115,6 @@ async function createClient() { }); listeners.push(autoModListener); - const modListener = pubSubClient.onModAction(streamer.userId, streamer.userId, (message) => { - const frontendCommunicator = require("../../common/frontend-communicator"); - - switch (message.type) { - case "vip_added": - chatRolesManager.addVipToVipList({ - id: message.targetUserId, - username: message.targetUserName - }); - break; - default: - switch (message.action) { - case "clear": { - const { userName, userId } = message; - frontendCommunicator.send("twitch:chat:clear-feed", userName); - twitchEventsHandler.chat.triggerChatCleared(userName, userId); - break; - } - case "emoteonly": - case "emoteonlyoff": - case "subscribers": - case "subscribersoff": - case "followers": - case "followersoff": - case "slow": - case "slowoff": - case "r9kbeta": // Unique Chat - case "r9kbetaoff": - twitchEventsHandler.chatModeChanged.triggerChatModeChanged( - message.action, - message.action.includes("off") ? "disabled" : "enabled", - message.userName, - message.args ? parseInt(message.args[0]) : null - ); - break; - default: - return; - } - break; - } - }); - listeners.push(modListener); - const chatRoomListener = pubSubClient.onCustomTopic(streamer.userId, "stream-chat-room-v1", async (event) => { const message = event?.data; if (message?.type === "extension_message") { diff --git a/src/backend/variables/builtin/twitch/chat/mode/chat-mode.ts b/src/backend/variables/builtin/twitch/chat/mode/chat-mode.ts index 873134252..fb92cfd9e 100644 --- a/src/backend/variables/builtin/twitch/chat/mode/chat-mode.ts +++ b/src/backend/variables/builtin/twitch/chat/mode/chat-mode.ts @@ -28,8 +28,8 @@ const model : ReplaceVariable = { case "slow": case "slowoff": return "Slow"; - case "r9kbeta": - case "r9kbetaoff": + case "uniquechat": + case "uniquechatoff": return "Unique Chat"; default: return "";