added twitch module

This commit is contained in:
Jann Pächnatz 2023-12-03 23:17:05 +01:00
parent 3e4508ea70
commit f15f804fe8
6 changed files with 264 additions and 60 deletions

5
MODULES.md Normal file
View File

@ -0,0 +1,5 @@
# Modules
## Twitch
Enabled by default: ✅

88
bot.go
View File

@ -1,7 +1,6 @@
package main
import (
"encoding/json"
"fmt"
"os"
"os/signal"
@ -13,19 +12,6 @@ import (
badger "github.com/dgraph-io/badger/v4"
)
type CookieConfig struct {
Token string `json:"token"`
GuildID string `json:"guild_id"`
OpenWeatherMapAPIKey string `json:"openweathermap_api_key"`
}
type PermsConfig struct {
Roles []struct {
RoleID string `json:"role_id"`
Permissions []string `json:"permissions"`
} `json:"roles"`
}
func CheckInstallationFolder(path string) {
if info, err := os.Stat(path); err != nil {
if info == nil {
@ -42,60 +28,21 @@ func CheckInstallationFolder(path string) {
}
}
var (
config CookieConfig
)
func Init() CookieConfig {
CheckInstallationFolder("db")
CheckInstallationFolder("backup")
CheckInstallationFolder("data")
hasConfig, configFolder := FileExists("data/config.json")
if hasConfig {
// load config
data, err := os.ReadFile("data/config.json")
if err != nil {
log.Fatal(fmt.Sprintf("Couldn't read data/config.json. (File). Reason: %s", err.Error()))
}
config := CookieConfig{}
err = json.Unmarshal(data, &config)
if err != nil {
log.Fatal(fmt.Sprintf("Couldn't read data/config.json. (JSON Unmarshal). Reason: %s", err.Error()))
}
return config
} else {
if !configFolder {
// create new
config := &CookieConfig{}
log.Info("Creating new config.")
token := SecretPrompt("Please enter your token > ")
config.Token = token
fmt.Println(strings.Repeat("*", len(token)))
guildID := SecretPrompt("Please enter your guild id > ")
fmt.Println(strings.Repeat("*", len(guildID)))
config.GuildID = guildID
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("data/config.json", 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 data/config.json")
}
}
log.Fatal("No config could be returned!")
return CookieConfig{}
CheckInstallationFolder("data/modules")
return ConfigCheck()
}
func main() {
ourConfig := Init()
twitchConfig = Twitch_ConfigCheck()
config = ourConfig
db, err := badger.Open(badger.DefaultOptions("db/"))
db, err := badger.Open(badger.DefaultOptions("db/").WithIndexCacheSize(100 << 20).WithBlockCacheSize(50 << 20))
time.Sleep(1 * time.Second)
if err != nil {
log.Fatal(err)
}
@ -106,7 +53,7 @@ func main() {
log.Fatal(err)
}
// session.
// session
session.AddHandler(messageCreate)
session.Identify.Intents = discordgo.IntentsAllWithoutPrivileged
@ -116,6 +63,9 @@ func main() {
fmt.Println("error opening connection,", err)
return
}
go Twitch_Task(session)
log.Info(fmt.Sprintf("CookieMod 🍪 is running as user %s#%s. Press CTRL-C to exit.", session.State.User.Username, session.State.User.Discriminator))
sc := make(chan os.Signal, 1)
signal.Notify(sc, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
@ -138,6 +88,24 @@ func messageCreate(s *discordgo.Session, m *discordgo.MessageCreate) {
cmd = strings.Split(m.Content, " ")[0]
}
switch strings.TrimPrefix(cmd, botPrefix) {
case "uptime":
days := 0
hours := 0
mins := 0
secs := int(time.Since(started).Seconds())
for secs >= 60 {
mins++
secs -= 60
}
for mins >= 60 {
hours++
mins -= 60
}
for hours >= 24 {
days++
secs -= 24
}
s.ChannelMessageSend(m.ChannelID, fmt.Sprintf("I'm running for %d days, %d hours, %d minutes and %d seconds.", days, hours, mins, secs))
case "time":
now := time.Now()
hour, min, sec := now.Hour(), now.Minute(), now.Second()

72
config.go Normal file
View File

@ -0,0 +1,72 @@
package main
import (
"encoding/json"
"fmt"
"os"
"strings"
"time"
)
type CookieConfig struct {
Token string `json:"token"`
GuildID string `json:"guild_id"`
// config for modules
OpenWeatherMapAPIKey string `json:"openweathermap_api_key"`
}
type PermsConfig struct {
Roles []struct {
RoleID string `json:"role_id"`
Permissions []string `json:"permissions"`
} `json:"roles"`
}
var (
config CookieConfig
twitchConfig Twitch_Config
started time.Time = time.Now()
)
func ConfigCheck() CookieConfig {
hasMainConfig, configFolder := FileExists("data/config.json")
if hasMainConfig {
// load config
data, err := os.ReadFile("data/config.json")
if err != nil {
log.Fatal(fmt.Sprintf("Couldn't read data/config.json. (File). Reason: %s", err.Error()))
}
config := CookieConfig{}
err = json.Unmarshal(data, &config)
if err != nil {
log.Fatal(fmt.Sprintf("Couldn't read data/config.json. (JSON Unmarshal). Reason: %s", err.Error()))
}
return config
} else {
if !configFolder {
// create new
config := &CookieConfig{}
log.Info("Creating new config.")
token := SecretPrompt("Please enter your token > ")
config.Token = token
fmt.Println(strings.Repeat("*", len(token)))
guildID := SecretPrompt("Please enter your guild id > ")
fmt.Println(strings.Repeat("*", len(guildID)))
config.GuildID = guildID
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("data/config.json", 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 data/config.json")
}
}
log.Fatal("No config could be returned!")
return CookieConfig{}
}

2
go.mod
View File

@ -6,6 +6,7 @@ require (
github.com/bwmarrin/discordgo v0.27.1
github.com/dgraph-io/badger/v4 v4.2.0
github.com/fatih/color v1.16.0
github.com/nicklaw5/helix v1.25.0
golang.org/x/term v0.5.0
)
@ -14,6 +15,7 @@ require (
github.com/dgraph-io/ristretto v0.1.1 // indirect
github.com/dustin/go-humanize v1.0.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang-jwt/jwt v3.2.1+incompatible // indirect
github.com/golang/glog v1.0.0 // indirect
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6 // indirect
github.com/golang/protobuf v1.5.2 // indirect

4
go.sum
View File

@ -21,6 +21,8 @@ github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
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/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/glog v1.0.0 h1:nfP3RFugxnNRyKgeWd4oI1nYvXpxrx8ck8ZrcizshdQ=
github.com/golang/glog v1.0.0/go.mod h1:EWib/APOK0SL3dFbYqvxE3UYd8E6s1ouQ7iEp/0LWV4=
@ -50,6 +52,8 @@ github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovk
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
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/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=

153
twitch.go Normal file
View File

@ -0,0 +1,153 @@
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 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{}
}