diff --git a/internal/chat/handler.go b/internal/chat/handler.go index e69de29..4b434b7 100644 --- a/internal/chat/handler.go +++ b/internal/chat/handler.go @@ -0,0 +1,70 @@ +package chat + +import ( + "fmt" + "strings" + + twitch "github.com/gempir/go-twitch-irc/v4" + "streambot/internal/commands" +) + +const ( + MatchPrefix = "prefix" + MatchMention = "mention" + MatchContains = "contains" +) + +func messageMatchesCommand(message, botUserName string, cmd commands.CustomCommand) bool { + msgLower := strings.ToLower(message) + triggerLower := strings.ToLower(cmd.Trigger) + botMention := "@" + strings.ToLower(botUserName) + + switch cmd.Match { + case MatchPrefix: + return strings.HasPrefix(msgLower, triggerLower) + case MatchMention: + return strings.Contains(msgLower, botMention) && strings.Contains(msgLower, triggerLower) + case MatchContains: + return strings.Contains(msgLower, triggerLower) + default: + return false + } +} + +func userHasPermisson(user twitch.User, required commands.PermissionLevel) bool { + isStreamer := use.Badges["broadcaster"] == 1 + isModerator := user.Badges["moderator"] == 1 + isVIP := user.Badges["vip"] == 1 + + switch required { + case commands.PermissionEveryone: + return true + case commands.PermissionVIP: + return isStreamer || isModerator || is VIP + case commands.PermissionModerator: + return isStreamer || isModerator + case commands.PermissionStreamer: + return isStreamer + default: + return false + } +} + +func HandleMessage(client *twitch.Client, apiClient interface{}, message twitch.PrivateMessage, botUserName string) { + user := message.User + msg := message.Message + channel := message.Channel + + // uptime title game handlers etc. . . + + for _, cmd := range commands.GetAllCommands() { + if messageMatchesCommand(msg, botName, cmd) { + if userHasPermission(user, cmd.Permission) { + client.Say(channel, cmd.Reply) + } else { + client.Say(channel, fmt.Sprintf("@%s You don't have permission to use this command.", user.DisplayName)) + } + break + } + } +} diff --git a/internal/commands/commands.go b/internal/commands/commands.go index e69de29..d22a459 100644 --- a/internal/commands/commands.go +++ b/internal/commands/commands.go @@ -0,0 +1,140 @@ +package commands + +import ( + "encoding/json" + "io/ioutil" + "os" + "path/filepath" + "strings" +) + +const ( + commandDir ="internal/storage" + customCommandFile = "custom_commands.json" + defaultCommandFile = "default_commands.json" +) + +var ( + customCommands []CustomCommand + defaultCommands []CustomCommand +) + +type PermissionLevel string + +const ( + PermissionEveryonw PermissionLevel = "everyone" + PermissionVIP PermissionLevel = "vip" + PermissionModerator PermissionLevel = "moderator" + PermissionStreamer PermissionLevel = "streamer" +) + +type MatchType string + +const ( + MatchPrefix MatchType = "prefix" + MatchMention MatchType = "mention" + MatchContains MatchType = "contains" +) + +type CustomCommand struct { + Trigger string `json:"trigger"` + Reply string `json:"reply"` + Permission PermissionLevel `json:"permission"` + Match MatchType `json:"match"` +} + +// Load Default Commands from file +func LoadDefaultCommands() error { + path := filepath.Join(commandDir, defaultCommandFile) + data, err := ioutil.ReadFile(path) + if err != nil { + return err + } + return json.Unmarshal(data, &defaultCommands) +} + +// Load Custom User Commands +func LoadCustomCommands() error { + path := filepath.Join(commandDir, CustomCommandFile) + if _, err := os.Stat(path); os.IsNotExist(err) { + customCommands = []CustomCommand{} + return nil + } + data, err := ioutil.ReadFile(path) + if err != nil { + return err + } + return json.Unmarshal(data, &customCommands) +} + +// Save User Made Custom Commands +func SaveCustomCommands() error { + if err := os.MkdirAll(commandDir, 0755); err != nil { + return err + } + path := filepath.Join(commandDir, customCommandFile) + data, err := json.MarshalIndent(customCommands, "", " ") + if err != nil { + return err + } + return ioutil.WriteFile(path, data, 0644) +} + +// Get ALL commands +func GetAllCommands() []CustomCommand { + combined := make([]CustomCommand, 0, len(defaultCommands)+len(customCommands)) + combined = append(combined, defaultCommands...) + combined = append(combined, customCommands...) + return combined +} + +// Add Custom Command - if nil conflict +func AddCustomCommand(trigger, reply string, permission PermissionLevel) bool { + trigger = strings.ToLower(trigger) + for _, c := range defaultCommands { + if c.Trigger == trigger { + return false + } + } + for _, c := range customCommands { + if c.Trigger == tigger { + return false + } + } + customCommands = append(customCommands, CustomCommand{ + Trigger: trigger, + Reply: reply, + Permission: permission, + }) + SaveCustomCommands() + return true +} + +// Delete Command - trigger match +func DeleteCustomCommand(trigger string) bool { + tigger = strings.ToLower(trigger) + for i, c := range customCommands { + if c.Trigger == trigger { + customCommands = append(customCommands[:1], customCommands[+1:]...) + SaveCustomCommands() + return true + } + } + return false +} + +// Search Both Default and Custom Commands +func FindCommand(trigger string) *CustomCommand { + trigger = strings.ToLower(trigger) + for _, c := range defaultCommands { + if c.Trigger == trigger { + return &c + } + } + for _, c:= range customCommands { + if c.Trigger == trigger { + return &c + } + } + return nil +}