150 lines
3.5 KiB
Go
150 lines
3.5 KiB
Go
|
package main
|
||
|
|
||
|
import (
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"regexp"
|
||
|
"strconv"
|
||
|
"strings"
|
||
|
|
||
|
"github.com/pkg/errors"
|
||
|
"github.com/sirupsen/logrus"
|
||
|
|
||
|
"github.com/Luzifer/rconfig/v2"
|
||
|
"github.com/Luzifer/twitch-bot/v3/plugins"
|
||
|
)
|
||
|
|
||
|
var (
|
||
|
cfg = struct {
|
||
|
Listen string `flag:"listen" default:":3000" description:"Port/IP to listen on"`
|
||
|
LogLevel string `flag:"log-level" default:"info" description:"Log level (debug, info, warn, error, fatal)"`
|
||
|
VersionAndExit bool `flag:"version" default:"false" description:"Prints current version and exits"`
|
||
|
}{}
|
||
|
|
||
|
categories = map[string]string{
|
||
|
"A": "Aggressive Content",
|
||
|
"I": "Identity-Based Hate",
|
||
|
"P": "Profane Content",
|
||
|
"S": "Sexual Content",
|
||
|
}
|
||
|
|
||
|
flagParse = regexp.MustCompile(`([0-9]+)\-([0-9]+):((?:[AIPS]\.[0-9]+/?)+)`)
|
||
|
flagLevelParse = regexp.MustCompile(`([AIPS])\.([0-9]+)`)
|
||
|
|
||
|
version = "dev"
|
||
|
)
|
||
|
|
||
|
func initApp() error {
|
||
|
rconfig.AutoEnv(true)
|
||
|
if err := rconfig.ParseAndValidate(&cfg); err != nil {
|
||
|
return errors.Wrap(err, "parsing cli options")
|
||
|
}
|
||
|
|
||
|
if cfg.VersionAndExit {
|
||
|
fmt.Printf("automod-debug %s\n", version)
|
||
|
os.Exit(0)
|
||
|
}
|
||
|
|
||
|
l, err := logrus.ParseLevel(cfg.LogLevel)
|
||
|
if err != nil {
|
||
|
return errors.Wrap(err, "parsing log-level")
|
||
|
}
|
||
|
logrus.SetLevel(l)
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func main() {
|
||
|
var err error
|
||
|
if err = initApp(); err != nil {
|
||
|
logrus.WithError(err).Fatal("initializing app")
|
||
|
}
|
||
|
|
||
|
var input struct {
|
||
|
Message string `json:"message"`
|
||
|
Tags struct {
|
||
|
Flags string `json:"flags"`
|
||
|
} `json:"tags"`
|
||
|
}
|
||
|
|
||
|
if err = json.NewDecoder(os.Stdin).Decode(&input); err != nil {
|
||
|
logrus.WithError(err).Fatal("parsing input")
|
||
|
}
|
||
|
|
||
|
if err = json.NewEncoder(os.Stdout).Encode(flagsToResponse(input.Message, input.Tags.Flags)); err != nil {
|
||
|
logrus.WithError(err).Fatal("encoding response")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func flagsToResponse(msg, flags string) (out []plugins.RuleAction) {
|
||
|
if flags == "" {
|
||
|
return []plugins.RuleAction{respondMessage("AutoMod is fine with your message! SeemsGood")}
|
||
|
}
|
||
|
|
||
|
var (
|
||
|
issues = strings.Split(flags, ",")
|
||
|
idx = 0
|
||
|
)
|
||
|
|
||
|
for _, issue := range issues {
|
||
|
fields := flagParse.FindStringSubmatch(issue)
|
||
|
if len(fields) != 4 {
|
||
|
continue
|
||
|
}
|
||
|
|
||
|
startIdx, _ := strconv.Atoi(fields[1])
|
||
|
endIdx, _ := strconv.Atoi(fields[2])
|
||
|
|
||
|
var excerpt string
|
||
|
|
||
|
switch {
|
||
|
case startIdx == 0:
|
||
|
case startIdx <= 5:
|
||
|
excerpt += strings.TrimLeft(msg[0:startIdx], " ")
|
||
|
default:
|
||
|
excerpt += "…" + strings.TrimLeft(msg[startIdx-5:startIdx], " ")
|
||
|
}
|
||
|
|
||
|
excerpt += fmt.Sprintf("[[%s]]", msg[startIdx:endIdx+1])
|
||
|
|
||
|
switch {
|
||
|
case len(msg)-endIdx == 0:
|
||
|
case len(msg)-endIdx <= 6:
|
||
|
excerpt += strings.TrimRight(msg[endIdx+1:], " ")
|
||
|
default:
|
||
|
excerpt += strings.TrimRight(msg[endIdx+1:endIdx+6], " ") + "…"
|
||
|
}
|
||
|
|
||
|
for _, flag := range strings.Split(fields[3], "/") {
|
||
|
idx++
|
||
|
cat, lvl := parseLevel(flag)
|
||
|
out = append(out, respondMessage("[%.02d] %s Level %d: %s", idx, cat, lvl, excerpt))
|
||
|
}
|
||
|
}
|
||
|
|
||
|
out = append([]plugins.RuleAction{respondMessage("AutoMod found %d issue(s) with that message! D:", idx)}, out...)
|
||
|
|
||
|
return out
|
||
|
}
|
||
|
|
||
|
func parseLevel(flag string) (cat string, lvl int) {
|
||
|
pts := flagLevelParse.FindStringSubmatch(flag)
|
||
|
if len(pts) != 3 {
|
||
|
logrus.WithField("flag", flag).Warn("flag format does not match expectation")
|
||
|
return cat, lvl
|
||
|
}
|
||
|
|
||
|
cat = categories[pts[1]]
|
||
|
lvl, _ = strconv.Atoi(pts[2])
|
||
|
|
||
|
return cat, lvl
|
||
|
}
|
||
|
|
||
|
func respondMessage(message string, vars ...any) plugins.RuleAction {
|
||
|
return plugins.RuleAction{
|
||
|
Type: "respond",
|
||
|
Attributes: plugins.FieldCollectionFromData(map[string]any{"message": fmt.Sprintf(message, vars...)}),
|
||
|
}
|
||
|
}
|