twitch-bot/automessage.go
Knut Ahlers 5d44822a27
Support templating in automessages
Signed-off-by: Knut Ahlers <knut@ahlers.me>
2021-05-06 15:19:24 +02:00

140 lines
2.9 KiB
Go

package main
import (
"crypto/sha256"
"fmt"
"strings"
"sync"
"time"
"github.com/go-irc/irc"
"github.com/pkg/errors"
"github.com/robfig/cron/v3"
log "github.com/sirupsen/logrus"
)
var cronParser = cron.NewParser(cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow)
type autoMessage struct {
Channel string `yaml:"channel"`
Message string `yaml:"message"`
UseAction bool `yaml:"use_action"`
Cron string `yaml:"cron"`
MessageInterval int64 `yaml:"message_interval"`
OnlyOnLive bool `yaml:"only_on_live"`
TimeInterval time.Duration `yaml:"time_interval"`
disabled bool
lastMessageSent time.Time
linesSinceLastMessage int64
lock sync.RWMutex
}
func (a *autoMessage) CanSend() bool {
if a.disabled || !a.IsValid() {
return false
}
a.lock.RLock()
defer a.lock.RUnlock()
switch {
case a.MessageInterval > a.linesSinceLastMessage:
// Not enough chatted lines
return false
case a.TimeInterval > 0 && a.lastMessageSent.Add(a.TimeInterval).After(time.Now()):
// Simple timer is not yet expired
return false
case a.Cron != "":
sched, _ := cronParser.Parse(a.Cron)
if sched.Next(a.lastMessageSent).After(time.Now()) {
// Cron timer is not yet expired
return false
}
}
if a.OnlyOnLive {
streamLive, err := twitch.HasLiveStream(strings.TrimLeft(a.Channel, "#"))
if err != nil {
log.WithError(err).Error("Unable to determine channel live status")
return false
}
if !streamLive {
// Timer is only to be triggered during stream being live,
// reset the timer in order not to spam all messages on stream-start
a.lastMessageSent = time.Now()
return false
}
}
return true
}
func (a *autoMessage) CountMessage(channel string) {
if strings.TrimLeft(channel, "#") != strings.TrimLeft(a.Channel, "#") {
return
}
a.lock.Lock()
defer a.lock.Unlock()
a.linesSinceLastMessage++
}
func (a *autoMessage) ID() string {
sum := sha256.New()
fmt.Fprintf(sum, "channel:%q", a.Channel)
fmt.Fprintf(sum, "message:%q", a.Message)
fmt.Fprintf(sum, "action:%v", a.UseAction)
return fmt.Sprintf("sha256:%x", sum.Sum(nil))
}
func (a *autoMessage) IsValid() bool {
if a.Cron != "" {
if _, err := cronParser.Parse(a.Cron); err != nil {
return false
}
}
if a.MessageInterval == 0 && a.TimeInterval == 0 && a.Cron == "" {
return false
}
return true
}
func (a *autoMessage) Send(c *irc.Client) error {
a.lock.Lock()
defer a.lock.Unlock()
msg, err := formatMessage(a.Message, nil, nil, nil)
if err != nil {
return errors.Wrap(err, "preparing message")
}
if a.UseAction {
msg = fmt.Sprintf("\001ACTION %s\001", msg)
}
if err := c.WriteMessage(&irc.Message{
Command: "PRIVMSG",
Params: []string{
fmt.Sprintf("#%s", strings.TrimLeft(a.Channel, "#")),
msg,
},
}); err != nil {
return errors.Wrap(err, "sending auto-message")
}
a.lastMessageSent = time.Now()
a.linesSinceLastMessage = 0
return nil
}