package controller import ( "arimelody-web/model" "bytes" "encoding/json" "fmt" "net/http" "net/url" "time" ) const TWITCH_API_BASE = "https://api.twitch.tv/helix/" func TwitchSetup(app *model.AppState) error { app.Twitch = &model.TwitchState{} err := RefreshTwitchToken(app) return err } func RefreshTwitchToken(app *model.AppState) error { if app.Twitch != nil && app.Twitch.Token != nil && time.Now().UTC().After(app.Twitch.Token.ExpiresAt) { return nil } requestUrl, _ := url.Parse("https://id.twitch.tv/oauth2/token") req, _ := http.NewRequest(http.MethodPost, requestUrl.String(), bytes.NewBuffer([]byte(url.Values{ "client_id": []string{ app.Config.Twitch.ClientID }, "client_secret": []string{ app.Config.Twitch.Secret }, "grant_type": []string{ "client_credentials" }, }.Encode()))) res, err := http.DefaultClient.Do(req) if err != nil { return err } type TwitchOAuthToken struct { AccessToken string `json:"access_token"` ExpiresIn int `json:"expires_in"` TokenType string `json:"token_type"` } oauthResponse := TwitchOAuthToken{} err = json.NewDecoder(res.Body).Decode(&oauthResponse) if err != nil { return err } app.Twitch.Token = &model.TwitchOAuthToken{ AccessToken: oauthResponse.AccessToken, ExpiresAt: time.Now().UTC().Add(time.Second * time.Duration(oauthResponse.ExpiresIn)).UTC(), TokenType: oauthResponse.TokenType, } return nil } var lastStreamState *model.TwitchStreamInfo var lastStreamStateAt time.Time func GetTwitchStatus(app *model.AppState, broadcaster string) (*model.TwitchStreamInfo, error) { if lastStreamState != nil && time.Now().UTC().Before(lastStreamStateAt.Add(time.Minute)) { return lastStreamState, nil } fmt.Print("MAKING COSTLY REQUEST TO TWITCH.TV API...\n") requestUrl, _ := url.Parse(TWITCH_API_BASE + "streams") requestUrl.RawQuery = url.Values{ "user_login": []string{ broadcaster }, }.Encode() req, _ := http.NewRequest(http.MethodGet, requestUrl.String(), nil) req.Header.Set("Client-Id", app.Config.Twitch.ClientID) req.Header.Set("Authorization", "Bearer " + app.Twitch.Token.AccessToken) res, err := http.DefaultClient.Do(req) if err != nil { return nil, err } type StreamsResponse struct { Data []model.TwitchStreamInfo `json:"data"` } streamInfo := StreamsResponse{} err = json.NewDecoder(res.Body).Decode(&streamInfo) if err != nil { return nil, err } if len(streamInfo.Data) == 0 { return nil, nil } lastStreamState = &streamInfo.Data[0] lastStreamStateAt = time.Now().UTC() return lastStreamState, nil }