strimertul/twitch/commands.go

182 lines
4.8 KiB
Go

package twitch
import (
"bytes"
"github.com/Masterminds/sprig/v3"
"math/rand"
"strconv"
"strings"
"text/template"
"time"
irc "github.com/gempir/go-twitch-irc/v4"
"github.com/nicklaw5/helix/v2"
"go.uber.org/zap"
)
type AccessLevelType string
const (
ALTEveryone AccessLevelType = "everyone"
ALTSubscribers AccessLevelType = "subscriber"
ALTVIP AccessLevelType = "vip"
ALTModerators AccessLevelType = "moderators"
ALTStreamer AccessLevelType = "streamer"
)
var accessLevels = map[AccessLevelType]int{
ALTEveryone: 0,
ALTSubscribers: 1,
ALTVIP: 2,
ALTModerators: 3,
ALTStreamer: 999,
}
type BotCommandHandler func(bot *Bot, message irc.PrivateMessage)
type BotCommand struct {
Description string
Usage string
AccessLevel AccessLevelType
Handler BotCommandHandler
Enabled bool
}
func cmdCustom(bot *Bot, cmd string, data BotCustomCommand, message irc.PrivateMessage) {
// Check access level
accessLevel := getUserAccessLevel(message.User)
// Ensure that access level is high enough
if accessLevels[accessLevel] < accessLevels[data.AccessLevel] {
return
}
var buf bytes.Buffer
tpl, ok := bot.customTemplates.GetKey(cmd)
if !ok {
return
}
if err := tpl.Execute(&buf, message); err != nil {
bot.logger.Error("Failed to execute custom command template", zap.Error(err))
return
}
switch data.ResponseType {
case ResponseTypeDefault, ResponseTypeChat:
bot.Client.Say(message.Channel, buf.String())
case ResponseTypeReply:
bot.Client.Reply(message.Channel, message.ID, buf.String())
case ResponseTypeWhisper:
client, err := bot.api.GetUserClient(false)
reply, err := client.SendUserWhisper(&helix.SendUserWhisperParams{
FromUserID: bot.api.User.ID,
ToUserID: message.User.ID,
Message: buf.String(),
})
if reply.Error != "" {
bot.logger.Error("Failed to send whisper", zap.String("code", reply.Error), zap.String("message", reply.ErrorMessage))
}
if err != nil {
bot.logger.Error("Failed to send whisper", zap.Error(err))
}
case ResponseTypeAnnounce:
client, err := bot.api.GetUserClient(false)
reply, err := client.SendChatAnnouncement(&helix.SendChatAnnouncementParams{
BroadcasterID: bot.api.User.ID,
ModeratorID: bot.api.User.ID,
Message: buf.String(),
})
if reply.Error != "" {
bot.logger.Error("Failed to send announcement", zap.String("code", reply.Error), zap.String("message", reply.ErrorMessage))
}
if err != nil {
bot.logger.Error("Failed to send announcement", zap.Error(err))
}
}
}
func (b *Bot) MakeTemplate(message string) (*template.Template, error) {
return template.New("").Funcs(sprig.TxtFuncMap()).Funcs(b.customFunctions).Parse(message)
}
var TestMessageData = irc.PrivateMessage{
User: irc.User{
ID: "603448316",
Name: "ashkeelvt",
DisplayName: "AshKeelVT",
Color: "#EC2B87",
Badges: map[string]int{
"subscriber": 0,
"moments": 1,
"broadcaster": 1,
},
},
Type: 1,
Tags: map[string]string{
"emotes": "",
"first-msg": "0",
"id": "e6b80ab3-d068-4226-83b2-a991da9c0cc3",
"turbo": "0",
"user-id": "603448316",
"badges": "broadcaster/1,subscriber/0,moments/1",
"color": "#EC2B87",
"user-type": "",
"room-id": "603448316",
"tmi-sent-ts": "1684345559394",
"flags": "",
"mod": "0",
"returning-chatter": "0",
"badge-info": "subscriber/21",
"display-name": "AshKeelVT",
"subscriber": "1",
},
Message: "!test",
Channel: "ashkeelvt",
RoomID: "603448316",
ID: "e6b80ab3-d068-4226-83b2-a991da9c0cc3",
Time: time.Now(),
Emotes: nil,
Bits: 0,
Action: false,
}
func (b *Bot) setupFunctions() {
b.customFunctions = template.FuncMap{
"user": func(message irc.PrivateMessage) string {
return message.User.DisplayName
},
"param": func(num int, message irc.PrivateMessage) string {
parts := strings.Split(message.Message, " ")
if num >= len(parts) {
return parts[len(parts)-1]
}
return parts[num]
},
"randomInt": func(min int, max int) int {
return rand.Intn(max-min) + min
},
"game": func(channel string) string {
channel = strings.TrimLeft(channel, "@")
info, err := b.api.API.SearchChannels(&helix.SearchChannelsParams{Channel: channel, First: 1, LiveOnly: false})
if err != nil {
return "unknown"
}
return info.Data.Channels[0].GameName
},
"count": func(name string) int {
counterKey := BotCounterPrefix + name
counter := 0
if byt, err := b.api.db.GetKey(counterKey); err == nil {
counter, _ = strconv.Atoi(byt)
}
counter += 1
err := b.api.db.PutKey(counterKey, strconv.Itoa(counter))
if err != nil {
b.logger.Error("Error saving key", zap.Error(err), zap.String("key", counterKey))
}
return counter
},
}
}