[core] Add outbound_raid event

Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
Knut Ahlers 2022-10-29 15:16:30 +02:00
parent 231704f8b3
commit c52ce80bdc
Signed by: luzifer
GPG key ID: D91C3E91E4CAD6F5
4 changed files with 95 additions and 40 deletions

View file

@ -27,6 +27,7 @@ var (
eventTypeGiftPaidUpgrade = ptrStr("giftpaidupgrade") eventTypeGiftPaidUpgrade = ptrStr("giftpaidupgrade")
eventTypeHost = ptrStr("host") eventTypeHost = ptrStr("host")
eventTypeJoin = ptrStr("join") eventTypeJoin = ptrStr("join")
eventTypeOutboundRaid = ptrStr("outbound_raid")
eventTypePart = ptrStr("part") eventTypePart = ptrStr("part")
eventTypePermit = ptrStr("permit") eventTypePermit = ptrStr("permit")
eventTypeRaid = ptrStr("raid") eventTypeRaid = ptrStr("raid")
@ -54,6 +55,7 @@ var (
eventTypeGiftPaidUpgrade, eventTypeGiftPaidUpgrade,
eventTypeHost, eventTypeHost,
eventTypeJoin, eventTypeJoin,
eventTypeOutboundRaid,
eventTypePart, eventTypePart,
eventTypePermit, eventTypePermit,
eventTypeRaid, eventTypeRaid,

View file

@ -44,6 +44,7 @@ const (
// eventSubStatusVerificationFailed = "webhook_callback_verification_failed" // eventSubStatusVerificationFailed = "webhook_callback_verification_failed"
EventSubEventTypeChannelFollow = "channel.follow" EventSubEventTypeChannelFollow = "channel.follow"
EventSubEventTypeChannelRaid = "channel.raid"
EventSubEventTypeChannelUpdate = "channel.update" EventSubEventTypeChannelUpdate = "channel.update"
EventSubEventTypeStreamOffline = "stream.offline" EventSubEventTypeStreamOffline = "stream.offline"
EventSubEventTypeStreamOnline = "stream.online" EventSubEventTypeStreamOnline = "stream.online"
@ -118,6 +119,16 @@ type (
FollowedAt time.Time `json:"followed_at"` FollowedAt time.Time `json:"followed_at"`
} }
EventSubEventRaid struct {
FromBroadcasterUserID string `json:"from_broadcaster_user_id"`
FromBroadcasterUserLogin string `json:"from_broadcaster_user_login"`
FromBroadcasterUserName string `json:"from_broadcaster_user_name"`
ToBroadcasterUserID string `json:"to_broadcaster_user_id"`
ToBroadcasterUserLogin string `json:"to_broadcaster_user_login"`
ToBroadcasterUserName string `json:"to_broadcaster_user_name"`
Viewers int64 `json:"viewers"`
}
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

@ -12,6 +12,14 @@ import (
) )
type ( type (
topicRegistration struct {
Topic string
Condition twitch.EventSubCondition
RequiredScopes []string
AnyScope bool
Hook func(json.RawMessage) error
}
twitchChannelState struct { twitchChannelState struct {
Category string Category string
IsLive bool IsLive bool
@ -94,6 +102,48 @@ func (t *twitchWatcher) RemoveChannel(channel string) error {
return nil return nil
} }
func (t *twitchWatcher) getTopicRegistrations(userID string) []topicRegistration {
return []topicRegistration{
{
Topic: twitch.EventSubEventTypeChannelUpdate,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: nil,
Hook: t.handleEventSubChannelUpdate,
},
{
Topic: twitch.EventSubEventTypeStreamOffline,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: nil,
Hook: t.handleEventSubStreamOnOff(false),
},
{
Topic: twitch.EventSubEventTypeStreamOnline,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: nil,
Hook: t.handleEventSubStreamOnOff(true),
},
{
Topic: twitch.EventSubEventTypeChannelFollow,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: nil,
Hook: t.handleEventSubChannelFollow,
},
{
Topic: twitch.EventSubEventTypeChannelRaid,
Condition: twitch.EventSubCondition{FromBroadcasterUserID: userID},
RequiredScopes: nil,
Hook: t.handleEventSubChannelOutboundRaid,
},
{
Topic: twitch.EventSubEventTypeChannelPointCustomRewardRedemptionAdd,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: []string{twitch.ScopeChannelReadRedemptions, twitch.ScopeChannelManageRedemptions},
AnyScope: true,
Hook: t.handleEventSubChannelPointCustomRewardRedemptionAdd,
},
}
}
func (t *twitchWatcher) handleEventSubChannelFollow(m json.RawMessage) error { func (t *twitchWatcher) handleEventSubChannelFollow(m json.RawMessage) error {
var payload twitch.EventSubEventFollow var payload twitch.EventSubEventFollow
if err := json.Unmarshal(m, &payload); err != nil { if err := json.Unmarshal(m, &payload); err != nil {
@ -136,6 +186,25 @@ func (t *twitchWatcher) handleEventSubChannelPointCustomRewardRedemptionAdd(m js
return nil return nil
} }
func (t *twitchWatcher) handleEventSubChannelOutboundRaid(m json.RawMessage) error {
var payload twitch.EventSubEventRaid
if err := json.Unmarshal(m, &payload); err != nil {
return errors.Wrap(err, "unmarshalling event")
}
fields := plugins.FieldCollectionFromData(map[string]interface{}{
"channel": "#" + payload.FromBroadcasterUserLogin,
"to_id": payload.ToBroadcasterUserID,
"to": payload.ToBroadcasterUserLogin,
"viewers": payload.Viewers,
})
log.WithFields(log.Fields(fields.Data())).Info("Outbound raid detected")
go handleMessage(ircHdl.Client(), nil, eventTypeOutboundRaid, fields)
return nil
}
func (t *twitchWatcher) handleEventSubChannelUpdate(m json.RawMessage) error { func (t *twitchWatcher) handleEventSubChannelUpdate(m json.RawMessage) error {
var payload twitch.EventSubEventChannelUpdate var payload twitch.EventSubEventChannelUpdate
if err := json.Unmarshal(m, &payload); err != nil { if err := json.Unmarshal(m, &payload); err != nil {
@ -233,46 +302,8 @@ func (t *twitchWatcher) registerEventSubCallbacks(channel string) (func(), error
} }
var ( var (
topicRegistrations = []struct { topicRegistrations = t.getTopicRegistrations(userID)
Topic string unsubHandlers []func()
Condition twitch.EventSubCondition
RequiredScopes []string
AnyScope bool
Hook func(json.RawMessage) error
}{
{
Topic: twitch.EventSubEventTypeChannelUpdate,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: nil,
Hook: t.handleEventSubChannelUpdate,
},
{
Topic: twitch.EventSubEventTypeStreamOffline,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: nil,
Hook: t.handleEventSubStreamOnOff(false),
},
{
Topic: twitch.EventSubEventTypeStreamOnline,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: nil,
Hook: t.handleEventSubStreamOnOff(true),
},
{
Topic: twitch.EventSubEventTypeChannelFollow,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: nil,
Hook: t.handleEventSubChannelFollow,
},
{
Topic: twitch.EventSubEventTypeChannelPointCustomRewardRedemptionAdd,
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
RequiredScopes: []string{twitch.ScopeChannelReadRedemptions, twitch.ScopeChannelManageRedemptions},
AnyScope: true,
Hook: t.handleEventSubChannelPointCustomRewardRedemptionAdd,
},
}
unsubHandlers []func()
) )
for _, tr := range topicRegistrations { for _, tr := range topicRegistrations {

View file

@ -98,6 +98,17 @@ Fields:
- `channel` - The channel the event occurred in - `channel` - The channel the event occurred in
- `user` - The login-name of the user who joined - `user` - The login-name of the user who joined
## `outbound_raid`
The channel has raided another channel. (The event is issued in the moment the raid is executed, not when the raid timer starts!)
Fields:
- `channel` - The channel the raid originated at
- `to` - The login-name of the channel the viewers are sent to
- `to_id` - The ID of the channel the viewers are sent to
- `viewers` - The number of viewers included in the raid
## `part` ## `part`
User left the channel-chat. This is **NOT** an indicator they are no longer viewing, the event is **NOT** reliably sent when the user really leaves the chat. The event will be sent with some delay after they leave the chat and is sometimes repeated multiple times during their stay. So this does **NOT** mean they do no longer read the chat! User left the channel-chat. This is **NOT** an indicator they are no longer viewing, the event is **NOT** reliably sent when the user really leaves the chat. The event will be sent with some delay after they leave the chat and is sometimes repeated multiple times during their stay. So this does **NOT** mean they do no longer read the chat!