diff --git a/discord/handler.go b/discord/handler.go new file mode 100644 index 0000000..1299493 --- /dev/null +++ b/discord/handler.go @@ -0,0 +1,106 @@ +package discord + +import ( + "encoding/base64" + "fmt" + "github.com/bwmarrin/discordgo" + "os" + "path/filepath" + "strings" +) + +var ( + dmPermission = false + defaultMemberPermissions int64 = discordgo.PermissionAdministrator + + Commands = []*discordgo.ApplicationCommand{ + { + Name: "list-emotes", + Description: "List emotes", + DefaultMemberPermissions: &defaultMemberPermissions, + DMPermission: &dmPermission, + }, + { + Name: "create-emotes", + Description: "Create emotes", + DefaultMemberPermissions: &defaultMemberPermissions, + DMPermission: &dmPermission, + }, + } + + CommandHandlers = map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){ + "list-emotes": listEmotes, + "create-emotes": createEmotes, + } +) + +func listEmotes(s *discordgo.Session, i *discordgo.InteractionCreate) { + var emotesList strings.Builder + + guildEmotes, _ := s.GuildEmojis(i.GuildID) + + emotesList.WriteString("```") + for _, emote := range guildEmotes { + emotesList.WriteString(fmt.Sprintf("<:%s:%s>\n", emote.Name, emote.ID)) + } + emotesList.WriteString("```") + + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: emotesList.String(), + Flags: discordgo.MessageFlagsEphemeral, + }, + }) +} + +func createEmotes(s *discordgo.Session, i *discordgo.InteractionCreate) { + emotesDir := "emojis" + var output strings.Builder + + files, err := os.ReadDir(emotesDir) + if err != nil { + fmt.Println("Error reading emotes directory:", err) + return + } + + // fetch existing emotes + guildEmotes, _ := s.GuildEmojis(i.GuildID) + existingEmotes := make(map[string]bool) + for _, emote := range guildEmotes { + existingEmotes[emote.Name] = true + } + + output.WriteString("```") + // check and upload every emote we have under emotesDir + for _, file := range files { + emoteName := strings.TrimSuffix(file.Name(), ".png") + + if _, exists := existingEmotes[emoteName]; exists { + output.WriteString(fmt.Sprintf("%s - already there\n", emoteName)) + continue + } + emoteFile, err := os.ReadFile(filepath.Join(emotesDir, file.Name())) + encodedImage := base64.StdEncoding.EncodeToString(emoteFile) + dataURI := fmt.Sprintf("data:image/png;base64,%s", encodedImage) + + _, err = s.GuildEmojiCreate(i.GuildID, &discordgo.EmojiParams{ + Name: emoteName, + Image: dataURI, + }) + if err != nil { + output.WriteString(fmt.Sprintf("%s - upload error: %s\n", emoteName, err)) + continue + } + output.WriteString(fmt.Sprintf("%s - success\n", emoteName)) + } + output.WriteString("```") + + _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ + Type: discordgo.InteractionResponseChannelMessageWithSource, + Data: &discordgo.InteractionResponseData{ + Content: output.String(), + Flags: discordgo.MessageFlagsEphemeral, + }, + }) +} diff --git a/main.go b/main.go index 76de894..f8a5d2e 100644 --- a/main.go +++ b/main.go @@ -133,44 +133,71 @@ func gatherStats(db *sqlx.DB, config config.Config) (discord.GatheredStats, erro } func main() { - var config config.Config - if err := config.ParseConfig(); err != nil { + var c config.Config + if err := c.ParseConfig(); err != nil { panic(err) } messageIDs := loadMessageIDs("messageIDs.json") - dg, err := discordgo.New("Bot " + config.Discord.Token) + dg, err := discordgo.New("Bot " + c.Discord.Token) + defer dg.Close() + if err != nil { fmt.Println("error creating Discord session,", err) return } + fmt.Println("Add slash commands handlers") + dg.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) { + if h, ok := discord.CommandHandlers[i.ApplicationCommandData().Name]; ok { + h(s, i) + } + }) + + fmt.Println("Open Discord connection") + err = dg.Open() + if err != nil { + fmt.Println("error opening connection,", err) + return + } + + fmt.Println("Register commands") + registeredCommands := make([]*discordgo.ApplicationCommand, len(discord.Commands)) + for i, v := range discord.Commands { + cmd, err := dg.ApplicationCommandCreate(dg.State.User.ID, "", v) + if err != nil { + fmt.Printf("Cannot create '%v' command: %v\n", v.Name, err) + } + registeredCommands[i] = cmd + } + + fmt.Println("Start loop") go func() { for { - db, err := database.DbConn(config) + db, err := database.DbConn(c) if err != nil { fmt.Println("error connecting to MariaDB,", err) - time.Sleep(time.Duration(config.Config.ErrorRefreshInterval) * time.Second) + time.Sleep(time.Duration(c.Config.ErrorRefreshInterval) * time.Second) continue } - gathered, err := gatherStats(db, config) + gathered, err := gatherStats(db, c) db.Close() if err != nil { fmt.Println("failed to fetch stats,", err) - time.Sleep(time.Duration(config.Config.ErrorRefreshInterval) * time.Second) + time.Sleep(time.Duration(c.Config.ErrorRefreshInterval) * time.Second) continue } - fields := discord.GenerateFields(gathered, config) + fields := discord.GenerateFields(gathered, c) embed := &discordgo.MessageEmbed{ - Title: config.Config.EmbedTitle, + Title: c.Config.EmbedTitle, Fields: fields, Timestamp: time.Now().Format(time.RFC3339), } - for _, channelID := range config.Discord.ChannelIDs { + for _, channelID := range c.Discord.ChannelIDs { var msg *discordgo.Message var err error var msgID string @@ -194,16 +221,10 @@ func main() { } } - time.Sleep(time.Duration(config.Config.RefreshInterval) * time.Second) + time.Sleep(time.Duration(c.Config.RefreshInterval) * time.Second) } }() - err = dg.Open() - if err != nil { - fmt.Println("error opening connection,", err) - return - } - fmt.Println("Porygon is now running. Press CTRL-C to exit.") <-make(chan struct{}) return