package main import ( "encoding/json" "fmt" "os" "time" "github.com/bwmarrin/discordgo" "github.com/nicklaw5/helix" ) type Twitch_Config struct { Token string `json:"token"` ClientID string `json:"client_id"` AppAccessToken string `json:"app_access_token"` NotifyChannels []string `json:"notify_channels"` TwitchChannels []string `json:"twitch_channels"` } func Twitch_Task(session *discordgo.Session) { alreadyOnline := make(map[string]bool) for _, user := range twitchConfig.TwitchChannels { alreadyOnline[user] = false } for { for _, user := range twitchConfig.TwitchChannels { isLive, stream, profileImage := Twitch_IsLive(user) if isLive { if alreadyOnline[user] { // already live continue } // just live alreadyOnline[user] = true for _, channel := range twitchConfig.NotifyChannels { Twitch_SendNotification(session, *stream, channel, profileImage) } } else { if alreadyOnline[user] { // was live continue } } time.Sleep(60 * time.Second) } } } // returns isLive, stream, profilePictureURL func Twitch_IsLive(user string) (bool, *helix.Stream, string) { client, err := helix.NewClient(&helix.Options{ ClientID: twitchConfig.ClientID, AppAccessToken: twitchConfig.AppAccessToken, }) if err != nil { log.Fatal(err) } resp, err := client.GetUsers(&helix.UsersParams{ Logins: []string{user}, }) if err != nil { log.Fatal(err) } userIDs := make([]string, 0) profileImageURL := "" for _, user := range resp.Data.Users { profileImageURL = user.ProfileImageURL userIDs = append(userIDs, user.ID) } streamsResp, err := client.GetStreams(&helix.StreamsParams{ UserIDs: userIDs, }) // if streamer is live -> get poll data -> send notification if err != nil { log.Fatal(err) } for _, stream := range streamsResp.Data.Streams { return true, &stream, profileImageURL } return false, nil, "" } func Twitch_SendNotification(session *discordgo.Session, stream helix.Stream, channelID, profileImage string) { session.ChannelMessageSendEmbed(channelID, &discordgo.MessageEmbed{ Color: int(0x5c32a8), // #5c32a8 Title: fmt.Sprintf("%s is now live on Twitch!", stream.UserName), Description: stream.Title, Fields: []*discordgo.MessageEmbedField{ { Name: "Game 🎮", Value: fmt.Sprint(stream.GameName), Inline: true, }, { Name: "Viewers 👀", Value: fmt.Sprint(stream.ViewerCount), Inline: true, }, }, Type: discordgo.EmbedTypeArticle, Image: &discordgo.MessageEmbedImage{ URL: profileImage, }, }) } func Twitch_ConfigCheck() Twitch_Config { path := "data/modules/twitch.json" hasMainConfig, configFolder := FileExists(path) if hasMainConfig { // load config data, err := os.ReadFile(path) if err != nil { log.Fatal(fmt.Sprintf("Couldn't read %s. (File). Reason: %s", path, err.Error())) } config := Twitch_Config{} err = json.Unmarshal(data, &config) if err != nil { log.Fatal(fmt.Sprintf("Couldn't read %sn. (JSON Unmarshal). Reason: %s", path, err.Error())) } return config } else { if !configFolder { // create new config := &Twitch_Config{ Token: "YOUR_TOKEN", ClientID: "YOUR_CLIENT_ID", AppAccessToken: "YOUR_APP_ACCESS_TOKEN", NotifyChannels: []string{""}, } data, err := json.Marshal(config) if err != nil { log.Fatal(fmt.Sprintf("Couldn't save the config! (JSON Marshal). Reason: %s", err.Error())) } err = os.WriteFile(path, data, 0777) if err != nil { log.Fatal(fmt.Sprintf("Couldn't save the config! (File). Reason: %s", err.Error())) } log.Info("First time configuration done! Please restart!") os.Exit(0) } else { log.Fatal("Please remove the folder at " + path) } } log.Fatal("No twitch config could be returned!") return Twitch_Config{} }