[eventsub] Add shoutout_received event

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2023-02-11 23:00:15 +01:00
parent a5460453b7
commit 8eaf676b13
Signed by: luzifer
GPG key ID: D91C3E91E4CAD6F5
6 changed files with 60 additions and 8 deletions

View file

@ -32,6 +32,7 @@ var (
eventTypePermit = ptrStr("permit") eventTypePermit = ptrStr("permit")
eventTypeRaid = ptrStr("raid") eventTypeRaid = ptrStr("raid")
eventTypeResub = ptrStr("resub") eventTypeResub = ptrStr("resub")
eventTypeShoutoutReceived = ptrStr("shoutout_received")
eventTypeSubgift = ptrStr("subgift") eventTypeSubgift = ptrStr("subgift")
eventTypeSubmysterygift = ptrStr("submysterygift") eventTypeSubmysterygift = ptrStr("submysterygift")
eventTypeSub = ptrStr("sub") eventTypeSub = ptrStr("sub")
@ -60,6 +61,7 @@ var (
eventTypePermit, eventTypePermit,
eventTypeRaid, eventTypeRaid,
eventTypeResub, eventTypeResub,
eventTypeShoutoutReceived,
eventTypeSub, eventTypeSub,
eventTypeSubgift, eventTypeSubgift,
eventTypeSubmysterygift, eventTypeSubmysterygift,

View file

@ -43,15 +43,14 @@ const (
// eventSubStatusUserRemoved = "user_removed" // eventSubStatusUserRemoved = "user_removed"
// eventSubStatusVerificationFailed = "webhook_callback_verification_failed" // eventSubStatusVerificationFailed = "webhook_callback_verification_failed"
EventSubEventTypeChannelFollow = "channel.follow" EventSubEventTypeChannelFollow = "channel.follow"
EventSubEventTypeChannelRaid = "channel.raid"
EventSubEventTypeChannelUpdate = "channel.update"
EventSubEventTypeStreamOffline = "stream.offline"
EventSubEventTypeStreamOnline = "stream.online"
EventSubEventTypeChannelPointCustomRewardRedemptionAdd = "channel.channel_points_custom_reward_redemption.add" EventSubEventTypeChannelPointCustomRewardRedemptionAdd = "channel.channel_points_custom_reward_redemption.add"
EventSubEventTypeChannelRaid = "channel.raid"
EventSubEventTypeUserAuthorizationRevoke = "user.authorization.revoke" EventSubEventTypeChannelShoutoutReceive = "channel.shoutout.receive"
EventSubEventTypeChannelUpdate = "channel.update"
EventSubEventTypeStreamOffline = "stream.offline"
EventSubEventTypeStreamOnline = "stream.online"
EventSubEventTypeUserAuthorizationRevoke = "user.authorization.revoke"
EventSubTopicVersion1 = "1" EventSubTopicVersion1 = "1"
EventSubTopicVersion2 = "2" EventSubTopicVersion2 = "2"
@ -81,6 +80,7 @@ type (
RewardID string `json:"reward_id,omitempty"` RewardID string `json:"reward_id,omitempty"`
ToBroadcasterUserID string `json:"to_broadcaster_user_id,omitempty"` ToBroadcasterUserID string `json:"to_broadcaster_user_id,omitempty"`
UserID string `json:"user_id,omitempty"` UserID string `json:"user_id,omitempty"`
ModeratorUserID string `json:"moderator_user_id,omitempty"`
} }
EventSubEventChannelPointCustomRewardRedemptionAdd struct { EventSubEventChannelPointCustomRewardRedemptionAdd struct {
@ -133,6 +133,17 @@ type (
Viewers int64 `json:"viewers"` Viewers int64 `json:"viewers"`
} }
EventSubEventShoutoutReceived struct {
BroadcasterUserID string `json:"broadcaster_user_id"`
BroadcasterUserLogin string `json:"broadcaster_user_login"`
BroadcasterUserName string `json:"broadcaster_user_name"`
FromBroadcasterUserID string `json:"from_broadcaster_user_id"`
FromBroadcasterUserLogin string `json:"from_broadcaster_user_login"`
FromBroadcasterUserName string `json:"from_broadcaster_user_name"`
ViewerCount int64 `json:"viewer_count"`
StartedAt time.Time `json:"started_at"`
}
EventSubEventStreamOffline struct { EventSubEventStreamOffline struct {
BroadcasterUserID string `json:"broadcaster_user_id"` BroadcasterUserID string `json:"broadcaster_user_id"`
BroadcasterUserLogin string `json:"broadcaster_user_login"` BroadcasterUserLogin string `json:"broadcaster_user_login"`

View file

@ -19,6 +19,7 @@ const (
ScopeModeratorManageShieldMode = "moderator:manage:shield_mode" ScopeModeratorManageShieldMode = "moderator:manage:shield_mode"
ScopeModeratorManageShoutouts = "moderator:manage:shoutouts" ScopeModeratorManageShoutouts = "moderator:manage:shoutouts"
ScopeModeratorReadFollowers = "moderator:read:followers" ScopeModeratorReadFollowers = "moderator:read:followers"
ScopeModeratorReadShoutouts = "moderator:read:shoutouts"
ScopeUserManageChatColor = "user:manage:chat_color" ScopeUserManageChatColor = "user:manage:chat_color"
// Deprecated v5 scope but used in chat // Deprecated v5 scope but used in chat

View file

@ -12,6 +12,7 @@ var (
twitch.ScopeChannelManageVIPS: "manage VIPs", twitch.ScopeChannelManageVIPS: "manage VIPs",
twitch.ScopeChannelReadRedemptions: "see channel-point redemptions", twitch.ScopeChannelReadRedemptions: "see channel-point redemptions",
twitch.ScopeModeratorReadFollowers: "see who follows this channel", twitch.ScopeModeratorReadFollowers: "see who follows this channel",
twitch.ScopeModeratorReadShoutouts: "see shoutouts received",
} }
botDefaultScopes = []string{ botDefaultScopes = []string{

View file

@ -143,6 +143,13 @@ func (t *twitchWatcher) getTopicRegistrations(userID string) []topicRegistration
AnyScope: true, AnyScope: true,
Hook: t.handleEventSubChannelPointCustomRewardRedemptionAdd, Hook: t.handleEventSubChannelPointCustomRewardRedemptionAdd,
}, },
{
Topic: twitch.EventSubEventTypeChannelShoutoutReceive,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID, ModeratorUserID: userID},
RequiredScopes: []string{twitch.ScopeModeratorManageShoutouts, twitch.ScopeModeratorReadShoutouts},
AnyScope: true,
Hook: t.handleEventSubShoutoutReceived,
},
} }
} }
@ -218,6 +225,25 @@ func (t *twitchWatcher) handleEventSubChannelUpdate(m json.RawMessage) error {
return nil return nil
} }
func (t *twitchWatcher) handleEventSubShoutoutReceived(m json.RawMessage) error {
var payload twitch.EventSubEventShoutoutReceived
if err := json.Unmarshal(m, &payload); err != nil {
return errors.Wrap(err, "unmarshalling event")
}
fields := plugins.FieldCollectionFromData(map[string]any{
"channel": "#" + payload.FromBroadcasterUserLogin,
"from_id": payload.FromBroadcasterUserID,
"from": payload.FromBroadcasterUserLogin,
"viewers": payload.ViewerCount,
})
log.WithFields(log.Fields(fields.Data())).Info("Shoutout received")
go handleMessage(ircHdl.Client(), nil, eventTypeShoutoutReceived, fields)
return nil
}
func (t *twitchWatcher) handleEventSubStreamOnOff(isOnline bool) func(json.RawMessage) error { func (t *twitchWatcher) handleEventSubStreamOnOff(isOnline bool) func(json.RawMessage) error {
return func(m json.RawMessage) error { return func(m json.RawMessage) error {
var payload twitch.EventSubEventFollow var payload twitch.EventSubEventFollow

View file

@ -149,6 +149,17 @@ Fields:
- `subscribed_months` - How long have they been subscribed - `subscribed_months` - How long have they been subscribed
- `username` - The login-name of the user who resubscribed - `username` - The login-name of the user who resubscribed
## `shoutout_received`
The channel received a (Twitch native) shoutout by another channel.
Fields:
- `channel` - The channel the event occurred in
- `from_id` - The ID of the channel who issued the shoutout
- `from` - The login-name of the channel who issued the shoutout
- `viewers` - The amount of viewers the shoutout was shown to
## `stream_offline` ## `stream_offline`
The channels stream went offline. (This event has some delay to the real category change!) The channels stream went offline. (This event has some delay to the real category change!)