Compare commits

...

2 Commits

Author SHA1 Message Date
bryce
b82d5dd0d4 random commit 2025-07-14 20:46:35 +12:00
bryce
5b286926a3 random commit 2025-07-14 20:46:12 +12:00
6 changed files with 58 additions and 47 deletions

2
go.mod
View File

@@ -7,4 +7,4 @@ require (
github.com/nicklaw5/helix v1.25.0 github.com/nicklaw5/helix v1.25.0
) )
require github.com/golang-jwt/jwt v3.2.1+incompatible // indirect require github.com/golang-jwt/jwt v3.2.2+incompatible // indirect

3
go.sum
View File

@@ -1,6 +1,7 @@
github.com/gempir/go-twitch-irc/v4 v4.2.0 h1:OCeff+1aH4CZIOxgKOJ8dQjh+1ppC6sLWrXOcpGZyq4= github.com/gempir/go-twitch-irc/v4 v4.2.0 h1:OCeff+1aH4CZIOxgKOJ8dQjh+1ppC6sLWrXOcpGZyq4=
github.com/gempir/go-twitch-irc/v4 v4.2.0/go.mod h1:QsOMMAk470uxQ7EYD9GJBGAVqM/jDrXBNbuePfTauzg= github.com/gempir/go-twitch-irc/v4 v4.2.0/go.mod h1:QsOMMAk470uxQ7EYD9GJBGAVqM/jDrXBNbuePfTauzg=
github.com/golang-jwt/jwt v3.2.1+incompatible h1:73Z+4BJcrTC+KczS6WvTPvRGOp1WmfEP4Q1lOd9Z/+c=
github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= github.com/golang-jwt/jwt v3.2.1+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/nicklaw5/helix v1.25.0 h1:Mrz537izZVsGdM3I46uGAAlslj61frgkhS/9xQqyT/M= github.com/nicklaw5/helix v1.25.0 h1:Mrz537izZVsGdM3I46uGAAlslj61frgkhS/9xQqyT/M=
github.com/nicklaw5/helix v1.25.0/go.mod h1:yvXZFapT6afIoxnAvlWiJiUMsYnoHl7tNs+t0bloAMw= github.com/nicklaw5/helix v1.25.0/go.mod h1:yvXZFapT6afIoxnAvlWiJiUMsYnoHl7tNs+t0bloAMw=

View File

@@ -44,7 +44,7 @@ func StartOAuthServer(addr string) error {
return http.ListenAndServe(addr, nil) return http.ListenAndServe(addr, nil)
} }
func HandleIndex(w http.ResponseWriter, r *http.Request) { func handleIndex(w http.ResponseWriter, r *http.Request) {
authURL := fmt.Sprintf( authURL := fmt.Sprintf(
"https://id.twitch.tv/oauth2/authorize?response_type=code&client_id=%s&redirect_uri=%s&scope=%s", "https://id.twitch.tv/oauth2/authorize?response_type=code&client_id=%s&redirect_uri=%s&scope=%s",
url.QueryEscape(clientID), url.QueryEscape(clientID),
@@ -63,10 +63,10 @@ func HandleIndex(w http.ResponseWriter, r *http.Request) {
w.Write([]byte(html)) w.Write([]byte(html))
} }
func handleCallback(w http.ResponseWriter, r &http.Request) { func handleCallback(w http.ResponseWriter, r *http.Request) {
code := r.URL.Query().Get("code") code := r.URL.Query().Get("code")
if code == "" { if code == "" {
http.Error(w, "Missing code in query", https.StatusBadRequest) http.Error(w, "Missing code in query", http.StatusBadRequest)
return return
} }
@@ -76,15 +76,15 @@ func handleCallback(w http.ResponseWriter, r &http.Request) {
return return
} }
jsonData, _ := json.MarshalIndent(token, "", " ") jsonData, _ := json.MarshalIndent(token, "", " ")
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.Write([jsonData]) w.Write(jsonData)
} }
func exchangeCodeForToken(code string) (*TokenResponse, error) { func exchangeCodeForToken(code string) (*TokenResponse, error) {
data := url.Values{} data := url.Values{}
data.Set("client_id", clientID) data.Set("client_id", clientID)
data.Set("client_Secret", clientSecret) data.Set("client_secret", clientSecret)
data.Set("code", code) data.Set("code", code)
data.Set("grant_type", "authorization_code") data.Set("grant_type", "authorization_code")
data.Set("redirect_uri", redirectURI) data.Set("redirect_uri", redirectURI)

View File

@@ -37,7 +37,7 @@ const (
) )
type CustomCommand struct { type CustomCommand struct {
Triggers string `json:"triggers"` Triggers []string `json:"triggers"`
Reply string `json:"reply"` Reply string `json:"reply"`
Permission PermissionLevel `json:"permission"` Permission PermissionLevel `json:"permission"`
Match MatchType `json:"match"` Match MatchType `json:"match"`
@@ -55,7 +55,7 @@ func LoadDefaultCommands() error {
// Load Custom User Commands // Load Custom User Commands
func LoadCustomCommands() error { func LoadCustomCommands() error {
path := filepath.Join(commandDir, CustomCommandFile) path := filepath.Join(commandDir, customCommandFile)
if _, err := os.Stat(path); os.IsNotExist(err) { if _, err := os.Stat(path); os.IsNotExist(err) {
customCommands = []CustomCommand{} customCommands = []CustomCommand{}
return nil return nil
@@ -92,12 +92,12 @@ func GetAllCommands() []CustomCommand {
func AddCustomCommand(trigger, reply string, permission PermissionLevel) bool { func AddCustomCommand(trigger, reply string, permission PermissionLevel) bool {
trigger = strings.ToLower(trigger) trigger = strings.ToLower(trigger)
for _, c := range defaultCommands { for _, c := range defaultCommands {
if c.Trigger == trigger { if c.Triggers == trigger {
return false return false
} }
} }
for _, c := range customCommands { for _, c := range customCommands {
if c.Trigger == tigger { if c.Triggers == trigger {
return false return false
} }
} }
@@ -114,7 +114,7 @@ func AddCustomCommand(trigger, reply string, permission PermissionLevel) bool {
func DeleteCustomCommand(trigger string) bool { func DeleteCustomCommand(trigger string) bool {
tigger = strings.ToLower(trigger) tigger = strings.ToLower(trigger)
for i, c := range customCommands { for i, c := range customCommands {
if c.Trigger == trigger { if c.Triggers == trigger {
customCommands = append(customCommands[:1], customCommands[+1:]...) customCommands = append(customCommands[:1], customCommands[+1:]...)
SaveCustomCommands() SaveCustomCommands()
return true return true
@@ -127,12 +127,12 @@ func DeleteCustomCommand(trigger string) bool {
func FindCommand(trigger string) *CustomCommand { func FindCommand(trigger string) *CustomCommand {
trigger = strings.ToLower(trigger) trigger = strings.ToLower(trigger)
for _, c := range defaultCommands { for _, c := range defaultCommands {
if c.Trigger == trigger { if c.Triggers == trigger {
return &c return &c
} }
} }
for _, c:= range customCommands { for _, c:= range customCommands {
if c.Trigger == trigger { if c.Triggers == trigger {
return &c return &c
} }
} }

View File

@@ -7,16 +7,28 @@ import (
"time" "time"
twitch "github.com/gempir/go-twitch-irc/v4" twitch "github.com/gempir/go-twitch-irc/v4"
helix "github.com/nicklaw5/helix"
twitchapi "streambot_twitch/internal/twitchapi" twitchapi "streambot_twitch/internal/twitchapi"
) )
// check Twitch API connectivity // check Twitch API connectivity
func TestTwitchAPI(client *twitchapi.Client, streamerChannel string) error { func TestTwitchAPI(client *twitchapi.Client, streamerChannel string) error {
_, err := client.GetUserID(streamerChannel) userID, err := client.GetUserID(streamerChannel)
if err != nil { if err != nil {
return fmt.Errorf("Twitch API test failed: %w", err) return fmt.Errorf("failed to get Usre ID: %w", err)
} }
log.Println("Twitch API connection successful") resp, err := client.api.GetChannelInformation(&helix.GetChannelInformationParams{
BroadcasterID: userID,
})
if err != nil {
return fmt.Errorf("failed to get channel information: %w", err)
}
if len(resp.Data.Channels) == 0 {
return fmt.Errorf("no channel information found")
}
log.Printf("Twitch API connection Test Successful for channel: %s", streamerChannel)
return nil return nil
} }

View File

@@ -11,28 +11,28 @@ type Client struct {
api *helix.Client api *helix.Client
} }
func NewClient(clientID, ClientSecret string) (*Client, error) { func NewClient(clientID, clientSecret string) (*Client, error) {
apiClient, err := helix.NewClient(&helix.Options{ apiClient, err := helix.NewClient(&helix.Options{
ClientID: clientID, ClientID: clientID,
ClientSecret: clientSecret, ClientSecret: clientSecret,
}) })
if err != nil { if err != nil {
return nill, err return nil, err
} }
resp, err := apiClient.RequestAppAccessToken([]string{}) resp, err := apiClient.RequestAppAccessToken([]string{})
if err != nil || resp.StatusCode != 200 { if err != nil || resp.StatusCode != 200 {
return nil, fmt.Errorf("Failed to get app access token: %v", err) return nil, fmt.Errorf("Failed to get app access token: %v", err)
} }
apiClient.SetUserAccessToken(resp.Data.AcessToken) apiClient.SetUserAccessToken(resp.Data.AccessToken)
return &Client{api: apiClient}, nil return &Client{api: apiClient}, nil
} }
// Twitch API helpers // Twitch API helpers
func getUserID(client *helix.Client, login String) (string, error) { func (c *Client) GetUserID(login string) (string, error) {
resp, err := client.GetUsers(&helix.UsersParams{ resp, err := c.api.GetUsers(&helix.UsersParams{
Logins: []string{login}, Logins: []string{login},
}) })
if err != nil { if err != nil {
@@ -44,8 +44,8 @@ func getUserID(client *helix.Client, login String) (string, error) {
return resp.Data.Users[0].ID, nil return resp.Data.Users[0].ID, nil
} }
func getStreamInfo(client *helix.Client, userID string) (*helix.Stream, error) { func (c *Client) GetStreamInfo(userID string) (*helix.Stream, error) {
resp, err := clinet.GetStreams(&helix.StreamsParams{ rep, err := c.api.GetStreams(&helix.StreamsParams{
UserIDs: []string{userID}, UserIDs: []string{userID},
}) })
if err != nil { if err != nil {
@@ -57,29 +57,27 @@ func getStreamInfo(client *helix.Client, userID string) (*helix.Stream, error) {
return &resp.Data.Streams[0], nil return &resp.Data.Streams[0], nil
} }
func getStreamUptime(client *helix.Client, channel string) (string, error) { func (c *Client) GetStreamUptime(channel string) (string, error) {
userID, err := getUserID(client, channel) userID, err := c.GetUserId(channel)
if err != nil { if err != nil {
return "", err return "", err
} }
stream, err := getStreamInfo(client, userID) stream, err := c.GetStreamInfo(userID)
if err != nil {
return "", err
}
startedAt, err := time.Parse(time.RFC3339, stream.StartedAt)
if err != nil { if err != nil {
return "", err return "", err
} }
startedAt := stream.StartedAt
uptime := time.Since(startedAt).Round(time.Second) uptime := time.Since(startedAt).Round(time.Second)
return uptime.String(), nil return uptime.String(), nil
} }
func getStreamTitle(client *helix.Client, channel string) (string, error) { func (c *Client) GetStreamTitle(channel string) (string, error) {
userID, err := getUserID(client, channel) userID, err := C. GetUserID(channel)
if err != nil { if err != nil {
return "", err return "", err
} }
resp, err := client.GetChannels(&helix.GetChannelsParams{ resp, err := c.api.GetChannelInformation(&helix.GetChannelInformationParams{
BroadcasterID: userID, BroadcasterID: userID,
}) })
if err != nil { if err != nil {
@@ -91,24 +89,24 @@ func getStreamTitle(client *helix.Client, channel string) (string, error) {
return resp.Data.Channels[0].Title, nil return resp.Data.Channels[0].Title, nil
} }
func setStreamTitle(client *helix.Client, channel, newTitle string) error { func (c *Client) SetStreamTitle(channel, newTitle string) error {
userID, err := getUserID(client, channel) userID, err := c.GetUserID(channel)
if err!= nil { if err!= nil {
return err return err
} }
_, err = client.UpdateChannelInformation(&helix.UpdateChannelInformationParams { _, err = c.api.EditChannelInformation(&helix.EditChannelInformationParams {
BroadcasterID: userID, BroadcasterID: userID,
Title: newTitle, Title: newTitle,
}) })
return err return err
} }
func getStreamCategory(client *helix.Client, channel string) (srting, error) { func (c *Client) GetStreamCategory(channel string) (string, error) {
userID, er := getUserID(client, channel) userID, err := c.GetUserID(channel)
if err != nil { if err != nil {
return "", err return "", err
} }
resp, err := client.GetChannels(&helix.GetChannelsParams{ resp, err := c.api.GetChannelInformation(&helix.GetChannelInformationParams{
BroadcasterID: userID, BroadcasterID: userID,
}) })
if err != nil { if err != nil {
@@ -120,17 +118,17 @@ func getStreamCategory(client *helix.Client, channel string) (srting, error) {
return resp.Data.Channels[0].GameName, nil return resp.Data.Channels[0].GameName, nil
} }
func setStreamCategory(client *helix.Client, channel,, newCategory string) error { func setStreamCategory(client *helix.Client, channel, newCategory string) error {
userID, err := getUserID(client, channel) userID, err := GetUserID(client, channel)
if err != nil { if err != nil {
return err return err
} }
// get Twitch GameID by Name from API // get Twitch GameID by Name from API
gameID, err := getUserIDByName(client, newCategory) gameID, err := getGameIDByName(client, newCategory)
if err != nil { if err != nil {
return err return err
} }
_, err = client.UpdateChannelInformation(&helix.UpdateChannelInformationParams{ _, err = client.EditChannelInformation(&helix.EditChannelInformationParams{
BroadcasterID: userID, BroadcasterID: userID,
GameID: gameID, GameID: gameID,
}) })
@@ -138,7 +136,7 @@ func setStreamCategory(client *helix.Client, channel,, newCategory string) error
} }
func getGameIDByName(client *helix.Client, name string) (string, error) { func getGameIDByName(client *helix.Client, name string) (string, error) {
resp, err := client.GetGames(&helix.GamesParams{ resp, err := GetGames(&helix.GamesParams{
Names: []string{name}, Names: []string{name},
}) })
if err != nil { if err != nil {