mirror of
https://github.com/Luzifer/twitch-bot.git
synced 2024-12-20 11:51:17 +00:00
[core] Add support for Hype-Train events
Signed-off-by: Knut Ahlers <knut@ahlers.me>
This commit is contained in:
parent
e50830e509
commit
f2ac1acb17
6 changed files with 102 additions and 1 deletions
|
@ -91,6 +91,17 @@ Fields:
|
||||||
- `gifter` - The login-name of the user who gifted the subscription
|
- `gifter` - The login-name of the user who gifted the subscription
|
||||||
- `username` - The login-name of the user who upgraded their subscription
|
- `username` - The login-name of the user who upgraded their subscription
|
||||||
|
|
||||||
|
## `hypetrain_begin`, `hypetrain_end`, `hypetrain_progress`
|
||||||
|
|
||||||
|
An Hype-Train has begun, ended or progressed in the given channel.
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
|
||||||
|
- `channel` - The channel the event occurred in
|
||||||
|
- `level` - The current level of the Hype-Train
|
||||||
|
- `levelProgress` - Percentage of reached "points" in the current level to complete the level (not available on `hypetrain_end`)
|
||||||
|
- `event` - Raw Hype-Train event, see schema in [`pkg/twitch/eventsub.go#L92`](https://github.com/Luzifer/twitch-bot/blob/master/pkg/twitch/eventsub.go#L121)
|
||||||
|
|
||||||
## `join`
|
## `join`
|
||||||
|
|
||||||
User joined the channel-chat. This is **NOT** an indicator they are viewing, the event is **NOT** reliably sent when the user really joined the chat. The event will be sent with some delay after they join the chat and is sometimes repeated multiple times during their stay. So **DO NOT** use this to greet users!
|
User joined the channel-chat. This is **NOT** an indicator they are viewing, the event is **NOT** reliably sent when the user really joined the chat. The event will be sent with some delay after they join the chat and is sometimes repeated multiple times during their stay. So **DO NOT** use this to greet users!
|
||||||
|
@ -152,7 +163,7 @@ A poll was started / was ended / had changes in the given channel.
|
||||||
Fields:
|
Fields:
|
||||||
|
|
||||||
- `channel` - The channel the event occurred in
|
- `channel` - The channel the event occurred in
|
||||||
- `poll` - The poll object describing the poll, see schema in [`pkg/twitch/eventsub.go#L92`](https://github.com/Luzifer/twitch-bot/blob/master/pkg/twitch/eventsub.go#L92)
|
- `poll` - The poll object describing the poll, see schema in [`pkg/twitch/eventsub.go#L92`](https://github.com/Luzifer/twitch-bot/blob/master/pkg/twitch/eventsub.go#L152)
|
||||||
- `status` - The status of the poll (one of `completed`, `terminated` or `archived`) - only available in `poll_end`
|
- `status` - The status of the poll (one of `completed`, `terminated` or `archived`) - only available in `poll_end`
|
||||||
- `title` - The title of the poll the event was generated for
|
- `title` - The title of the poll the event was generated for
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,9 @@ var (
|
||||||
eventTypeDelete = ptrStr("delete")
|
eventTypeDelete = ptrStr("delete")
|
||||||
eventTypeFollow = ptrStr("follow")
|
eventTypeFollow = ptrStr("follow")
|
||||||
eventTypeGiftPaidUpgrade = ptrStr("giftpaidupgrade")
|
eventTypeGiftPaidUpgrade = ptrStr("giftpaidupgrade")
|
||||||
|
eventTypeHypetrainBegin = ptrStr("hypetrain_begin")
|
||||||
|
eventTypeHypetrainEnd = ptrStr("hypetrain_end")
|
||||||
|
eventTypeHypetrainProgress = ptrStr("hypetrain_progress")
|
||||||
eventTypeJoin = ptrStr("join")
|
eventTypeJoin = ptrStr("join")
|
||||||
eventKoFiDonation = ptrStr("kofi_donation")
|
eventKoFiDonation = ptrStr("kofi_donation")
|
||||||
eventTypeOutboundRaid = ptrStr("outbound_raid")
|
eventTypeOutboundRaid = ptrStr("outbound_raid")
|
||||||
|
|
|
@ -17,6 +17,9 @@ const (
|
||||||
EventSubEventTypeChannelAdBreakBegin = "channel.ad_break.begin"
|
EventSubEventTypeChannelAdBreakBegin = "channel.ad_break.begin"
|
||||||
EventSubEventTypeChannelFollow = "channel.follow"
|
EventSubEventTypeChannelFollow = "channel.follow"
|
||||||
EventSubEventTypeChannelPointCustomRewardRedemptionAdd = "channel.channel_points_custom_reward_redemption.add"
|
EventSubEventTypeChannelPointCustomRewardRedemptionAdd = "channel.channel_points_custom_reward_redemption.add"
|
||||||
|
EventSubEventTypeChannelHypetrainBegin = "channel.hype_train.begin"
|
||||||
|
EventSubEventTypeChannelHypetrainProgress = "channel.hype_train.progress"
|
||||||
|
EventSubEventTypeChannelHypetrainEnd = "channel.hype_train.end"
|
||||||
EventSubEventTypeChannelRaid = "channel.raid"
|
EventSubEventTypeChannelRaid = "channel.raid"
|
||||||
EventSubEventTypeChannelShoutoutCreate = "channel.shoutout.create"
|
EventSubEventTypeChannelShoutoutCreate = "channel.shoutout.create"
|
||||||
EventSubEventTypeChannelShoutoutReceive = "channel.shoutout.receive"
|
EventSubEventTypeChannelShoutoutReceive = "channel.shoutout.receive"
|
||||||
|
@ -112,6 +115,38 @@ type (
|
||||||
FollowedAt time.Time `json:"followed_at"`
|
FollowedAt time.Time `json:"followed_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EventSubEventHypetrain contains the payload for all three (begin,
|
||||||
|
// progress and end) hypetrain events. Certain fields are not
|
||||||
|
// available at all event types
|
||||||
|
EventSubEventHypetrain struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
BroadcasterUserID string `json:"broadcaster_user_id"`
|
||||||
|
BroadcasterUserLogin string `json:"broadcaster_user_login"`
|
||||||
|
BroadcasterUserName string `json:"broadcaster_user_name"`
|
||||||
|
Level int64 `json:"level"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
Progress int64 `json:"progress"` // Only Beginn, Progress
|
||||||
|
Goal int64 `json:"goal"` // Only Beginn, Progress
|
||||||
|
TopContributions []struct {
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
UserLogin string `json:"user_login"`
|
||||||
|
UserName string `json:"user_name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
} `json:"top_contributions"`
|
||||||
|
LastContribution *struct { // Only Begin, Progress
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
UserLogin string `json:"user_login"`
|
||||||
|
UserName string `json:"user_name"`
|
||||||
|
Type string `json:"type"`
|
||||||
|
Total int64 `json:"total"`
|
||||||
|
} `json:"last_contribution,omitempty"`
|
||||||
|
StartedAt time.Time `json:"started_at"`
|
||||||
|
ExpiresAt *time.Time `json:"expires_at,omitempty"` // Only Begin, Progress
|
||||||
|
EndedAt *time.Time `json:"ended_at,omitempty"` // Only End
|
||||||
|
CooldownEndsAt *time.Time `json:"cooldown_ends_at,omitempty"` // Only End
|
||||||
|
}
|
||||||
|
|
||||||
// EventSubEventPoll contains the payload for a poll change event
|
// EventSubEventPoll contains the payload for a poll change event
|
||||||
// (not all fields are present in all poll events, see docs!)
|
// (not all fields are present in all poll events, see docs!)
|
||||||
EventSubEventPoll struct {
|
EventSubEventPoll struct {
|
||||||
|
|
|
@ -15,6 +15,7 @@ const (
|
||||||
ScopeChannelManageVIPS = "channel:manage:vips"
|
ScopeChannelManageVIPS = "channel:manage:vips"
|
||||||
ScopeChannelManageWhispers = "user:manage:whispers"
|
ScopeChannelManageWhispers = "user:manage:whispers"
|
||||||
ScopeChannelReadAds = "channel:read:ads"
|
ScopeChannelReadAds = "channel:read:ads"
|
||||||
|
ScopeChannelReadHypetrain = "channel:read:hype_train"
|
||||||
ScopeChannelReadPolls = "channel:read:polls"
|
ScopeChannelReadPolls = "channel:read:polls"
|
||||||
ScopeChannelReadRedemptions = "channel:read:redemptions"
|
ScopeChannelReadRedemptions = "channel:read:redemptions"
|
||||||
ScopeChannelReadSubscriptions = "channel:read:subscriptions"
|
ScopeChannelReadSubscriptions = "channel:read:subscriptions"
|
||||||
|
|
|
@ -11,6 +11,7 @@ var (
|
||||||
twitch.ScopeChannelManageRaids: "start raids",
|
twitch.ScopeChannelManageRaids: "start raids",
|
||||||
twitch.ScopeChannelManageVIPS: "manage VIPs",
|
twitch.ScopeChannelManageVIPS: "manage VIPs",
|
||||||
twitch.ScopeChannelReadAds: "see when an ad-break starts",
|
twitch.ScopeChannelReadAds: "see when an ad-break starts",
|
||||||
|
twitch.ScopeChannelReadHypetrain: "see Hype-Train events",
|
||||||
twitch.ScopeChannelReadRedemptions: "see channel-point redemptions",
|
twitch.ScopeChannelReadRedemptions: "see channel-point redemptions",
|
||||||
twitch.ScopeChannelReadSubscriptions: "see subscribed users / sub count / points",
|
twitch.ScopeChannelReadSubscriptions: "see subscribed users / sub count / points",
|
||||||
twitch.ScopeClipsEdit: "create clips on behalf of this user",
|
twitch.ScopeClipsEdit: "create clips on behalf of this user",
|
||||||
|
|
|
@ -112,6 +112,7 @@ func (t *twitchWatcher) RemoveChannel(channel string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:funlen // Just a collection of topics
|
||||||
func (t *twitchWatcher) getTopicRegistrations(userID string) []topicRegistration {
|
func (t *twitchWatcher) getTopicRegistrations(userID string) []topicRegistration {
|
||||||
return []topicRegistration{
|
return []topicRegistration{
|
||||||
{
|
{
|
||||||
|
@ -130,6 +131,30 @@ func (t *twitchWatcher) getTopicRegistrations(userID string) []topicRegistration
|
||||||
Hook: t.handleEventSubChannelFollow,
|
Hook: t.handleEventSubChannelFollow,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Topic: twitch.EventSubEventTypeChannelHypetrainBegin,
|
||||||
|
Version: twitch.EventSubTopicVersion1,
|
||||||
|
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
|
||||||
|
RequiredScopes: []string{twitch.ScopeChannelReadHypetrain},
|
||||||
|
Hook: t.handleEventSubHypetrainEvent(eventTypeHypetrainBegin),
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Topic: twitch.EventSubEventTypeChannelHypetrainEnd,
|
||||||
|
Version: twitch.EventSubTopicVersion1,
|
||||||
|
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
|
||||||
|
RequiredScopes: []string{twitch.ScopeChannelReadHypetrain},
|
||||||
|
Hook: t.handleEventSubHypetrainEvent(eventTypeHypetrainEnd),
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Topic: twitch.EventSubEventTypeChannelHypetrainProgress,
|
||||||
|
Version: twitch.EventSubTopicVersion1,
|
||||||
|
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
|
||||||
|
RequiredScopes: []string{twitch.ScopeChannelReadHypetrain},
|
||||||
|
Hook: t.handleEventSubHypetrainEvent(eventTypeHypetrainProgress),
|
||||||
|
Optional: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Topic: twitch.EventSubEventTypeChannelPointCustomRewardRedemptionAdd,
|
Topic: twitch.EventSubEventTypeChannelPointCustomRewardRedemptionAdd,
|
||||||
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
|
Condition: twitch.EventSubCondition{BroadcasterUserID: userID},
|
||||||
|
@ -338,6 +363,31 @@ func (*twitchWatcher) handleEventSubChannelPollChange(event *string) func(json.R
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (*twitchWatcher) handleEventSubHypetrainEvent(eventType *string) func(json.RawMessage) error {
|
||||||
|
return func(m json.RawMessage) error {
|
||||||
|
var payload twitch.EventSubEventHypetrain
|
||||||
|
if err := json.Unmarshal(m, &payload); err != nil {
|
||||||
|
return errors.Wrap(err, "unmarshalling event")
|
||||||
|
}
|
||||||
|
|
||||||
|
fields := plugins.FieldCollectionFromData(map[string]any{
|
||||||
|
"channel": "#" + payload.BroadcasterUserLogin,
|
||||||
|
"level": payload.Level,
|
||||||
|
})
|
||||||
|
|
||||||
|
if payload.Goal > 0 {
|
||||||
|
fields.Set("levelProgress", float64(payload.Progress)/float64(payload.Goal))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.WithFields(log.Fields(fields.Data())).Info("Hypetrain event")
|
||||||
|
|
||||||
|
fields.Set("event", payload)
|
||||||
|
go handleMessage(ircHdl.Client(), nil, eventType, fields)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (*twitchWatcher) handleEventSubShoutoutCreated(m json.RawMessage) error {
|
func (*twitchWatcher) handleEventSubShoutoutCreated(m json.RawMessage) error {
|
||||||
var payload twitch.EventSubEventShoutoutCreated
|
var payload twitch.EventSubEventShoutoutCreated
|
||||||
if err := json.Unmarshal(m, &payload); err != nil {
|
if err := json.Unmarshal(m, &payload); err != nil {
|
||||||
|
|
Loading…
Reference in a new issue