mirror of
https://git.sr.ht/~ashkeel/strimertul
synced 2024-09-30 02:40:33 +00:00
209 lines
7.1 KiB
Go
209 lines
7.1 KiB
Go
package alerts
|
|
|
|
import (
|
|
"encoding/json"
|
|
"math/rand"
|
|
"text/template"
|
|
|
|
"git.sr.ht/~ashkeel/strimertul/twitch/chat"
|
|
"github.com/nicklaw5/helix/v2"
|
|
)
|
|
|
|
func (m *Module) onEventSubEvent(_ string, value string) {
|
|
var ev eventSubNotification
|
|
if err := json.Unmarshal([]byte(value), &ev); err != nil {
|
|
m.logger.Warn("Error parsing webhook payload", "error", err)
|
|
return
|
|
}
|
|
switch ev.Subscription.Type {
|
|
case helix.EventSubTypeChannelFollow:
|
|
// Only process if we care about follows
|
|
if !m.Config.Follow.Enabled {
|
|
return
|
|
}
|
|
// Parse as a follow event
|
|
var followEv helix.EventSubChannelFollowEvent
|
|
if err := json.Unmarshal(ev.Event, &followEv); err != nil {
|
|
m.logger.Warn("Error parsing follow event", "error", err)
|
|
return
|
|
}
|
|
// Pick a random message
|
|
messageID := rand.Intn(len(m.Config.Follow.Messages))
|
|
// Pick compiled template or fallback to plain text
|
|
tpl, ok := m.templates[templateTypeFollow][m.Config.Follow.Messages[messageID]]
|
|
if !ok {
|
|
chat.WriteMessage(m.db, m.logger, chat.WriteMessageRequest{
|
|
Message: m.Config.Follow.Messages[messageID],
|
|
Announce: m.Config.Follow.Announce,
|
|
})
|
|
return
|
|
}
|
|
m.writeTemplate(tpl, &followEv, m.Config.Follow.Announce)
|
|
// Compile template and send
|
|
case helix.EventSubTypeChannelRaid:
|
|
// Only process if we care about raids
|
|
if !m.Config.Raid.Enabled {
|
|
return
|
|
}
|
|
// Parse as raid event
|
|
var raidEv helix.EventSubChannelRaidEvent
|
|
|
|
if err := json.Unmarshal(ev.Event, &raidEv); err != nil {
|
|
m.logger.Warn("Error parsing raid event", "error", err)
|
|
return
|
|
}
|
|
// Pick a random message from base set
|
|
messageID := rand.Intn(len(m.Config.Raid.Messages))
|
|
tpl, ok := m.templates[templateTypeRaid][m.Config.Raid.Messages[messageID]]
|
|
if !ok {
|
|
// Broken template!
|
|
chat.WriteMessage(m.db, m.logger, chat.WriteMessageRequest{
|
|
Message: m.Config.Raid.Messages[messageID],
|
|
Announce: m.Config.Raid.Announce,
|
|
})
|
|
return
|
|
}
|
|
// If we have variations, get the available variations and pick the one with the highest minimum viewers that are met
|
|
if len(m.Config.Raid.Variations) > 0 {
|
|
variation := getBestValidVariation(m.Config.Raid.Variations, func(variation raidVariation) int {
|
|
if variation.MinViewers != nil && raidEv.Viewers >= *variation.MinViewers {
|
|
return *variation.MinViewers
|
|
}
|
|
return 0
|
|
})
|
|
tpl = m.replaceWithVariation(tpl, templateTypeRaid, variation.Messages)
|
|
}
|
|
// Compile template and send
|
|
m.writeTemplate(tpl, &raidEv, m.Config.Raid.Announce)
|
|
case helix.EventSubTypeChannelCheer:
|
|
// Only process if we care about bits
|
|
if !m.Config.Cheer.Enabled {
|
|
return
|
|
}
|
|
// Parse as cheer event
|
|
var cheerEv helix.EventSubChannelCheerEvent
|
|
if err := json.Unmarshal(ev.Event, &cheerEv); err != nil {
|
|
m.logger.Warn("Error parsing cheer event", "error", err)
|
|
return
|
|
}
|
|
// Pick a random message from base set
|
|
messageID := rand.Intn(len(m.Config.Cheer.Messages))
|
|
tpl, ok := m.templates[templateTypeCheer][m.Config.Cheer.Messages[messageID]]
|
|
if !ok {
|
|
// Broken template!
|
|
chat.WriteMessage(m.db, m.logger, chat.WriteMessageRequest{
|
|
Message: m.Config.Cheer.Messages[messageID],
|
|
Announce: m.Config.Cheer.Announce,
|
|
})
|
|
return
|
|
}
|
|
// If we have variations, get the available variations and pick the one with the highest minimum amount that is met
|
|
if len(m.Config.Cheer.Variations) > 0 {
|
|
variation := getBestValidVariation(m.Config.Cheer.Variations, func(variation cheerVariation) int {
|
|
if variation.MinAmount != nil && cheerEv.Bits >= *variation.MinAmount {
|
|
return *variation.MinAmount
|
|
}
|
|
return 0
|
|
})
|
|
tpl = m.replaceWithVariation(tpl, templateTypeCheer, variation.Messages)
|
|
}
|
|
// Compile template and send
|
|
m.writeTemplate(tpl, &cheerEv, m.Config.Cheer.Announce)
|
|
case helix.EventSubTypeChannelSubscription:
|
|
// Only process if we care about subscriptions
|
|
if !m.Config.Subscription.Enabled {
|
|
return
|
|
}
|
|
// Parse as subscription event
|
|
var subEv helix.EventSubChannelSubscribeEvent
|
|
if err := json.Unmarshal(ev.Event, &subEv); err != nil {
|
|
m.logger.Warn("Error parsing new subscription event", "error", err)
|
|
return
|
|
}
|
|
m.addMixedEvent(subEv)
|
|
case helix.EventSubTypeChannelSubscriptionMessage:
|
|
// Only process if we care about subscriptions
|
|
if !m.Config.Subscription.Enabled {
|
|
return
|
|
}
|
|
// Parse as subscription event
|
|
var subEv helix.EventSubChannelSubscriptionMessageEvent
|
|
err := json.Unmarshal(ev.Event, &subEv)
|
|
if err != nil {
|
|
m.logger.Warn("Error parsing returning subscription event", "error", err)
|
|
return
|
|
}
|
|
m.addMixedEvent(subEv)
|
|
case helix.EventSubTypeChannelSubscriptionGift:
|
|
// Only process if we care about gifted subs
|
|
if !m.Config.GiftSub.Enabled {
|
|
return
|
|
}
|
|
// Parse as gift event
|
|
var giftEv helix.EventSubChannelSubscriptionGiftEvent
|
|
if err := json.Unmarshal(ev.Event, &giftEv); err != nil {
|
|
m.logger.Warn("Error parsing subscription gifted event", "error", err)
|
|
return
|
|
}
|
|
// Pick a random message from base set
|
|
messageID := rand.Intn(len(m.Config.GiftSub.Messages))
|
|
tpl, ok := m.templates[templateTypeGift][m.Config.GiftSub.Messages[messageID]]
|
|
if !ok {
|
|
// Broken template!
|
|
chat.WriteMessage(m.db, m.logger, chat.WriteMessageRequest{
|
|
Message: m.Config.GiftSub.Messages[messageID],
|
|
Announce: m.Config.GiftSub.Announce,
|
|
})
|
|
return
|
|
}
|
|
// If we have variations, loop through all the available variations and pick the one with the highest minimum cumulative total that are met
|
|
if len(m.Config.GiftSub.Variations) > 0 {
|
|
if giftEv.IsAnonymous {
|
|
variation := getBestValidVariation(m.Config.GiftSub.Variations, func(variation giftSubVariation) int {
|
|
if variation.IsAnonymous != nil && *variation.IsAnonymous {
|
|
return 1
|
|
}
|
|
return 0
|
|
})
|
|
tpl = m.replaceWithVariation(tpl, templateTypeGift, variation.Messages)
|
|
} else if giftEv.CumulativeTotal > 0 {
|
|
variation := getBestValidVariation(m.Config.GiftSub.Variations, func(variation giftSubVariation) int {
|
|
if variation.MinCumulative != nil && *variation.MinCumulative > giftEv.CumulativeTotal {
|
|
return *variation.MinCumulative
|
|
}
|
|
return 0
|
|
})
|
|
tpl = m.replaceWithVariation(tpl, templateTypeGift, variation.Messages)
|
|
}
|
|
}
|
|
// Compile template and send
|
|
m.writeTemplate(tpl, &giftEv, m.Config.GiftSub.Announce)
|
|
}
|
|
}
|
|
|
|
func (m *Module) replaceWithVariation(tpl *template.Template, templateType templateType, messages []string) *template.Template {
|
|
if messages != nil {
|
|
messageID := rand.Intn(len(messages))
|
|
// Make sure the template is valid
|
|
if temp, ok := m.templates[templateType][messages[messageID]]; ok {
|
|
return temp
|
|
}
|
|
}
|
|
return tpl
|
|
}
|
|
|
|
// For variations, some variations are better than others, this function returns the best one
|
|
// by using a provided score function. The score is 0 or less if the variation is not valid,
|
|
// and 1 or more if it is valid. The variation with the highest score is returned.
|
|
func getBestValidVariation[T any](variations []T, filterFunc func(T) int) T {
|
|
var best T
|
|
var bestScore int
|
|
for _, variation := range variations {
|
|
score := filterFunc(variation)
|
|
if score > bestScore {
|
|
best = variation
|
|
bestScore = score
|
|
}
|
|
}
|
|
return best
|
|
}
|