Fixed it so that the bot will go refresh its token when it starts. Added the start of a streamer controlled actions list.

master
Zed A. Shaw 1 month ago
parent d97167d8ee
commit 8512090ae6
  1. 3
      actions_example.json
  2. 84
      main.go
  3. 5
      secret_example.json
  4. 4
      secret_sample.json

@ -0,0 +1,3 @@
{
"ready": "https://somesitewithurl.com"
}

@ -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,24 +60,83 @@ 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.")
}
}
})
client.OnSelfJoinMessage(func (message twitch.UserJoinMessage) {

@ -0,0 +1,5 @@
{
"ClientID": "DOES_NOT_HAVE_OAUTH_IN_FRONT",
"ClientSecret": "GET FROM TWITCH CLI CONFIG",
"RefreshToken": "SAME"
}

@ -1,4 +0,0 @@
{
"ClientSecret": "oauth:MUST_HAVE_oauth_IN_FRONT",
"RefreshToken": "GET THIS FROM twitch-cli"
}
Loading…
Cancel
Save