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...)}), } }