diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c05a82 --- /dev/null +++ b/.gitignore @@ -0,0 +1,36 @@ +# ---> Vim +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +backup +*.exe +*.dll +*.world +coverage +coverage/* +.venv +*.gz +config.toml +public +*.idx +*.sqlite3 +*.log +secret.json + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ef2f3f4 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ + + + +build: + go build . + +run: build + ./app diff --git a/commands.json b/commands.json new file mode 100644 index 0000000..100e167 --- /dev/null +++ b/commands.json @@ -0,0 +1,6 @@ +{ + "keyboard": "I use https://hhkeyboard.us/hhkb/pro-classic-type-s but I don't recommend it.", + "mic": "It's a Samson se50x https://samsontech.com/products/microphones/headworn-microphones/se50x/", + "site": "https://learncodethehardway.com/", + "help": "Available commands: !mic !keyboard !site." +} diff --git a/config.json b/config.json new file mode 100644 index 0000000..38fe392 --- /dev/null +++ b/config.json @@ -0,0 +1,28 @@ +{ + "ClientNick": "zedashaw", + "Channel": "ZedAShaw", + "Commands": { + "keyboard": "I use https://hhkeyboard.us/hhkb/pro-classic-type-s but I don't recommend it.", + "mic": "It's a Samson se50x https://samsontech.com/products/microphones/headworn-microphones/se50x/", + "site": "https://learncodethehardway.com/", + "help": "COMMANDS: !mic !keyboard !site !ai !lsp !linux !windows !neovim !gvim !vim", + "ai": "I don't use AI, or really anything, but I don't hate AI.", + "lsp": "I use only a Terminal and Vim, no LSP, AI, or many other tools.", + "linux": "I do use Linux, and I might have to totally switch if Microsoft forces Windows 11 on me.", + "windows": "I use Windows because 95% of the world uses Windows and I want to teach them to code.", + "neovim": "NeoVIM is trying too hard to be like VSCode instead of being a better Vim.", + "gvim": "I use gvim because it works on all my computers and I'm not a troglodyte who runs...vim in a terminal? Blech.", + "vim": "I'll get my vim config on my git repo in a bit.", + "instagram": "My paintings are at https://www.instagram.com/zed.a.shaw" + }, + "Periodic": [ + { + "Seconds": 1800, + "Message": "You can use !help to get help from my Twitch IRC bot." + }, + { + "Seconds": 3300, + "Message": "I run 3 minute ads once an hour. Take a break during that time." + } + ] +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..b52fd36 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module MY/app + +go 1.25.3 + +require github.com/gempir/go-twitch-irc/v4 v4.4.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..f5276a7 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/gempir/go-twitch-irc/v4 v4.4.1 h1:R1WxeDyOiwHpt6rn96yZcXTS+Bri30n7pNvIjTMH598= +github.com/gempir/go-twitch-irc/v4 v4.4.1/go.mod h1:QsOMMAk470uxQ7EYD9GJBGAVqM/jDrXBNbuePfTauzg= diff --git a/main.go b/main.go new file mode 100644 index 0000000..bb55533 --- /dev/null +++ b/main.go @@ -0,0 +1,96 @@ +package main + +import ( + "log" + "os" + "strings" + "encoding/json" + "time" + + "github.com/gempir/go-twitch-irc/v4" +) + +type Secret struct { + ClientSecret string + RefreshToken string +} + +type Periodic struct { + Seconds int + Message string +} + +type Config struct { + ClientNick string + Channel string + Commands map[string]string + Periodic []Periodic +} + +func LoadJSON[T any](file string) T { + data, err := os.ReadFile(file) + if err != nil { log.Fatal(err) } + + var config T + err = json.Unmarshal(data, &config) + if err != nil { log.Fatal(err) } + + return config +} + +func RunPeriodic(message Periodic, channel string, client *twitch.Client) { + for { + time.Sleep(time.Duration(message.Seconds) * time.Second) + client.Say(channel, message.Message) + } +} + +func main() { + SECRETS := LoadJSON[Secret]("secret.json") + CONFIG := LoadJSON[Config]("config.json") + + // or client := twitch.NewAnonymousClient() for an anonymous user (no write capabilities) + client := twitch.NewClient(CONFIG.ClientNick, SECRETS.ClientSecret) + + client.OnPrivateMessage(func(message twitch.PrivateMessage) { + cmd, found := strings.CutPrefix(message.Message, "!") + reply, valid_cmd := CONFIG.Commands[strings.ToLower(cmd)] + + if found { + if valid_cmd { + client.Reply(message.Channel, message.ID, reply) + } else if !valid_cmd { + client.Reply(message.Channel, message.ID, "Invalid command. Use !help to see what's available.") + } + } + }) + + client.OnSelfJoinMessage(func (message twitch.UserJoinMessage) { + log.Println("Join", message.Channel, "as", message.User, "successful") + }) + + client.OnConnect(func () { + log.Println("Connected. Joining", CONFIG.Channel) + client.Join(CONFIG.Channel) + }) + + client.OnPingMessage(func (message twitch.PingMessage) { + log.Println("PING!", message.Message) + }) + + client.OnPongMessage(func (message twitch.PongMessage) { + log.Println("PONG!", message.Message) + }) + + client.OnNoticeMessage(func (message twitch.NoticeMessage) { + log.Println("NOTICE", message.Channel, message.Message) + }) + + for _, perodic := range(CONFIG.Periodic) { + go RunPeriodic(perodic, CONFIG.Channel, client) + } + + log.Println("Connecting to Twitch...") + err := client.Connect() + if err != nil { log.Fatal(err) } +} diff --git a/secret_sample.json b/secret_sample.json new file mode 100644 index 0000000..f8a53eb --- /dev/null +++ b/secret_sample.json @@ -0,0 +1,4 @@ +{ + "ClientSecret": "oauth:MUST_HAVE_oauth_IN_FRONT", + "RefreshToken": "GET THIS FROM twitch-cli" +}