added twitch module
This commit is contained in:
parent
3e4508ea70
commit
f15f804fe8
|
@ -0,0 +1,5 @@
|
|||
# Modules
|
||||
|
||||
## Twitch
|
||||
|
||||
Enabled by default: ✅
|
88
bot.go
88
bot.go
|
@ -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()
|
||||
|
|
|
@ -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
2
go.mod
|
@ -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
4
go.sum
|
@ -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=
|
||||
|
|
|
@ -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{}
|
||||
}
|
Loading…
Reference in New Issue