From b13a4343a744785ea2cc6285098bd1b97a60cfd8 Mon Sep 17 00:00:00 2001 From: A-iko Date: Thu, 26 Mar 2026 22:42:14 +0100 Subject: [PATCH] fix: 3462 - Update subscriber tier on subscription event. --- .../chat-listeners/twitch-chat-listeners.js | 7 ++++ src/backend/roles/twitch-roles-manager.ts | 40 +++++++++++++++++++ .../twitch/api/eventsub/eventsub-client.ts | 25 ++++++++++++ 3 files changed, 72 insertions(+) diff --git a/src/backend/chat/chat-listeners/twitch-chat-listeners.js b/src/backend/chat/chat-listeners/twitch-chat-listeners.js index e38aaf7e5..d93190166 100644 --- a/src/backend/chat/chat-listeners/twitch-chat-listeners.js +++ b/src/backend/chat/chat-listeners/twitch-chat-listeners.js @@ -169,6 +169,13 @@ exports.setupChatListeners = (streamerChatClient, botChatClient) => { }); streamerChatClient.onResub(async (_channel, _user, subInfo, msg) => { + twitchRolesManager.upsertSubscriber({ + id: subInfo.userId, + username: msg.userInfo.userName, + displayName: msg.userInfo.displayName, + subTier: subInfo.plan + }); + try { if (subInfo.message != null && subInfo.message.length > 0) { const firebotChatMessage = await chatHelpers.buildFirebotChatMessage(msg, subInfo.message); diff --git a/src/backend/roles/twitch-roles-manager.ts b/src/backend/roles/twitch-roles-manager.ts index 3bcb7245f..43c20d03b 100644 --- a/src/backend/roles/twitch-roles-manager.ts +++ b/src/backend/roles/twitch-roles-manager.ts @@ -98,9 +98,49 @@ class TwitchRolesManager extends TypedEmitter { return this._subscribers; } + upsertSubscriber(subscriber: Subscriber): void { + if (!subscriber?.id) { + return; + } + + const normalizedSubscriber: Subscriber = { + id: subscriber.id, + username: subscriber.username, + displayName: subscriber.displayName, + subTier: this.getRoleForSubTier(subscriber.subTier) + }; + + const existingSubscriber = this._subscribers.find(s => s.id === subscriber.id); + + if (existingSubscriber == null) { + this._subscribers.push(normalizedSubscriber); + this.emit("viewer-role-updated", subscriber.id, "sub", "added"); + if (normalizedSubscriber.subTier) { + this.emit("viewer-role-updated", subscriber.id, normalizedSubscriber.subTier, "added"); + } + return; + } + + const previousSubTier = existingSubscriber.subTier; + existingSubscriber.username = normalizedSubscriber.username; + existingSubscriber.displayName = normalizedSubscriber.displayName; + existingSubscriber.subTier = normalizedSubscriber.subTier; + + if (previousSubTier !== normalizedSubscriber.subTier) { + if (previousSubTier) { + this.emit("viewer-role-updated", subscriber.id, previousSubTier, "removed"); + } + + if (normalizedSubscriber.subTier) { + this.emit("viewer-role-updated", subscriber.id, normalizedSubscriber.subTier, "added"); + } + } + } + private getRoleForSubTier(tier: string): string { let role = ""; switch (tier) { + case "Prime": case "1000": role = "tier1"; break; diff --git a/src/backend/streaming-platforms/twitch/api/eventsub/eventsub-client.ts b/src/backend/streaming-platforms/twitch/api/eventsub/eventsub-client.ts index 657ee7c5b..56dffcc50 100644 --- a/src/backend/streaming-platforms/twitch/api/eventsub/eventsub-client.ts +++ b/src/backend/streaming-platforms/twitch/api/eventsub/eventsub-client.ts @@ -804,6 +804,12 @@ class TwitchEventSubClient { case "resub": case "sub": + twitchRolesManager.upsertSubscriber({ + id: event.chatterId, + username: event.chatterName, + displayName: event.chatterDisplayName, + subTier: event.isPrime ? "Prime" : event.tier + }); TwitchEventHandlers.sub.triggerSub( event.chatterName, event.chatterId, @@ -826,6 +832,12 @@ class TwitchEventSubClient { break; case "sub_gift": + twitchRolesManager.upsertSubscriber({ + id: event.recipientId, + username: event.recipientName, + displayName: event.recipientDisplayName, + subTier: event.tier + }); await TwitchEventHandlers.giftSub.triggerSubGift( event.chatterDisplayName ?? "An Anonymous Gifter", event.chatterName, @@ -845,6 +857,13 @@ class TwitchEventSubClient { // IRC chat included this in the event payload. EventSub does not. const upgradeTier = (await (await event.getBroadcaster()).getSubscriber(event.chatterId)).tier; + twitchRolesManager.upsertSubscriber({ + id: event.chatterId, + username: event.chatterName, + displayName: event.chatterDisplayName, + subTier: upgradeTier + }); + TwitchEventHandlers.giftSub.triggerSubGiftUpgrade( event.chatterName, event.chatterId, @@ -857,6 +876,12 @@ class TwitchEventSubClient { break; case "prime_paid_upgrade": + twitchRolesManager.upsertSubscriber({ + id: event.chatterId, + username: event.chatterName, + displayName: event.chatterDisplayName, + subTier: event.tier + }); TwitchEventHandlers.sub.triggerPrimeUpgrade( event.chatterName, event.chatterId,