diff --git a/actions_example.json b/actions_example.json new file mode 100644 index 0000000..2c29d22 --- /dev/null +++ b/actions_example.json @@ -0,0 +1,3 @@ +{ + "ready": "https://somesitewithurl.com" +} diff --git a/main.go b/main.go index bb55533..4130984 100644 --- a/main.go +++ b/main.go @@ -6,12 +6,18 @@ import ( "strings" "encoding/json" "time" + "net/http" + "net/url" + "fmt" + "flag" "github.com/gempir/go-twitch-irc/v4" ) type Secret struct { + ClientID string ClientSecret string + AccessToken string RefreshToken string } @@ -24,9 +30,18 @@ type Config struct { ClientNick string Channel string Commands map[string]string + Actions map[string]string Periodic []Periodic } +type TwitchTokenResponse struct { + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` + ExpiresIn int `json:"expires_in"` + Scope []string `json:"scope"` + TokenType string `json:"token_type"` +} + func LoadJSON[T any](file string) T { data, err := os.ReadFile(file) if err != nil { log.Fatal(err) } @@ -45,23 +60,82 @@ func RunPeriodic(message Periodic, channel string, client *twitch.Client) { } } +func RefreshToken(secrets* Secret) { + api_url := "https://id.twitch.tv/oauth2/token" + data := url.Values{} + data.Set("client_id", secrets.ClientID) + data.Set("client_secret", secrets.ClientSecret) + data.Set("grant_type", "refresh_token") + data.Set("refresh_token", secrets.RefreshToken) + + encoded := strings.NewReader(data.Encode()) + resp, err := http.Post(api_url,"application/x-www-form-urlencoded", encoded) + + if err != nil { log.Fatal(err) } + + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + log.Fatal(fmt.Sprintf("Invalid status code: %v.", resp.StatusCode)) + } + + var token_resp TwitchTokenResponse + err = json.NewDecoder(resp.Body).Decode(&token_resp) + if err != nil { log.Fatal(err) } + + secrets.AccessToken = fmt.Sprintf("oauth:%s", token_resp.AccessToken); +} + +func LoadConfigs() (Secret, Config) { + var secrets_file string + var config_file string + var action_file string + + flag.StringVar(&secrets_file, "secrets", "secret.json", "Your secrets file. KEEP PRIVATE!") + flag.StringVar(&config_file, "config", "config.json", "Your config.json. Can be public.") + flag.StringVar(&action_file, "actions", "actions.json", "Your URL actions. KEEP PRIVATE!") + flag.Parse() + + log.Println("Loading secrets from", secrets_file) + log.Println("Loading config from", config_file) + log.Println("Loading actions from", action_file) + + secrets := LoadJSON[Secret](secrets_file) + config := LoadJSON[Config](config_file) + config.Actions = LoadJSON[map[string]string](action_file) + + return secrets, config +} + func main() { - SECRETS := LoadJSON[Secret]("secret.json") - CONFIG := LoadJSON[Config]("config.json") + SECRETS, CONFIG := LoadConfigs() + + RefreshToken(&SECRETS) // or client := twitch.NewAnonymousClient() for an anonymous user (no write capabilities) - client := twitch.NewClient(CONFIG.ClientNick, SECRETS.ClientSecret) + client := twitch.NewClient(CONFIG.ClientNick, SECRETS.AccessToken) client.OnPrivateMessage(func(message twitch.PrivateMessage) { + // not sure if this is good enough for auth + cmd, found := strings.CutPrefix(message.Message, "!") + if !found { return } + + // see if it's a valid action + action, is_action := CONFIG.Actions[strings.ToLower(cmd)] + + if is_action && message.User.IsBroadcaster { + log.Println("Hitting URL", action) + return; + } + + // see if it's a normal command 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.") - } + 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.") } }) diff --git a/secret_example.json b/secret_example.json new file mode 100644 index 0000000..2764b08 --- /dev/null +++ b/secret_example.json @@ -0,0 +1,5 @@ +{ + "ClientID": "DOES_NOT_HAVE_OAUTH_IN_FRONT", + "ClientSecret": "GET FROM TWITCH CLI CONFIG", + "RefreshToken": "SAME" +} diff --git a/secret_sample.json b/secret_sample.json deleted file mode 100644 index f8a53eb..0000000 --- a/secret_sample.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "ClientSecret": "oauth:MUST_HAVE_oauth_IN_FRONT", - "RefreshToken": "GET THIS FROM twitch-cli" -}