package public import ( "context" "log" "strconv" "strings" "velox-bot/internal/db/services" "github.com/bwmarrin/discordgo" ) var Config = &discordgo.ApplicationCommand{ Name: "config", Description: "Server configuration", Options: []*discordgo.ApplicationCommandOption{ { Type: discordgo.ApplicationCommandOptionSubCommand, Name: "addstreamer", Description: "Add a Twitch streamer for live notifications", Options: []*discordgo.ApplicationCommandOption{ { Type: discordgo.ApplicationCommandOptionString, Name: "username", Description: "Twitch username (without https://)", Required: true, }, }, }, { Type: discordgo.ApplicationCommandOptionSubCommand, Name: "removestreamer", Description: "Remove a Twitch streamer from live notifications", Options: []*discordgo.ApplicationCommandOption{ { Type: discordgo.ApplicationCommandOptionString, Name: "username", Description: "Twitch username to remove", Required: true, }, }, }, { Type: discordgo.ApplicationCommandOptionSubCommand, Name: "settwitchnotificationchannel", Description: "Set the channel for Twitch live notifications", Options: []*discordgo.ApplicationCommandOption{ { Type: discordgo.ApplicationCommandOptionChannel, Name: "channel", Description: "Text channel for notifications", Required: true, ChannelTypes: []discordgo.ChannelType{discordgo.ChannelTypeGuildText, discordgo.ChannelTypeGuildNews}, }, }, }, }, } func ConfigHandler(s *discordgo.Session, i *discordgo.InteractionCreate) { if i.GuildID == "" { respondEphemeral(s, i, "This command can only be used in a server.") return } if i.Member == nil || (i.Member.Permissions&discordgo.PermissionManageGuild) == 0 { respondEphemeral(s, i, "You need the **Manage Server** permission to use this.") return } if services.Global == nil || services.Global.Twitch == nil { respondEphemeral(s, i, "Twitch configuration is not available.") return } data := i.ApplicationCommandData() if len(data.Options) == 0 { respondEphemeral(s, i, "Missing subcommand.") return } switch data.Options[0].Name { case "addstreamer": log.Printf("twitch: /config addstreamer invoked by %s in guild %s", i.Member.User.ID, i.GuildID) handleAddStreamer(s, i) case "removestreamer": log.Printf("twitch: /config removestreamer invoked by %s in guild %s", i.Member.User.ID, i.GuildID) handleRemoveStreamer(s, i) case "settwitchnotificationchannel": log.Printf("twitch: /config settwitchnotificationchannel invoked by %s in guild %s", i.Member.User.ID, i.GuildID) handleSetChannel(s, i) default: respondEphemeral(s, i, "Unknown subcommand.") } } func handleAddStreamer(s *discordgo.Session, i *discordgo.InteractionCreate) { guildID, err := strconv.ParseInt(i.GuildID, 10, 64) if err != nil { respondEphemeral(s, i, "Invalid guild ID.") return } opt := i.ApplicationCommandData().Options[0] var username string for _, o := range opt.Options { if o.Name == "username" { username = strings.TrimSpace(o.StringValue()) } } username = strings.TrimPrefix(username, "https://www.twitch.tv/") username = strings.TrimPrefix(username, "http://www.twitch.tv/") username = strings.TrimPrefix(username, "twitch.tv/") username = strings.TrimSpace(username) if username == "" { respondEphemeral(s, i, "Username cannot be empty.") return } if err := services.Global.Twitch.UpsertStreamer(context.Background(), guildID, username); err != nil { respondEphemeral(s, i, "Failed to add streamer.") return } respondEphemeral(s, i, "Added `"+username+"` for Twitch live notifications.") } func handleRemoveStreamer(s *discordgo.Session, i *discordgo.InteractionCreate) { guildID, err := strconv.ParseInt(i.GuildID, 10, 64) if err != nil { respondEphemeral(s, i, "Invalid guild ID.") return } opt := i.ApplicationCommandData().Options[0] var username string for _, o := range opt.Options { if o.Name == "username" { username = strings.TrimSpace(o.StringValue()) } } username = strings.TrimSpace(username) if username == "" { respondEphemeral(s, i, "Username cannot be empty.") return } if err := services.Global.Twitch.RemoveStreamer(context.Background(), guildID, username); err != nil { respondEphemeral(s, i, "Failed to remove streamer.") return } respondEphemeral(s, i, "Removed `"+username+"` from Twitch live notifications.") } func handleSetChannel(s *discordgo.Session, i *discordgo.InteractionCreate) { guildID, err := strconv.ParseInt(i.GuildID, 10, 64) if err != nil { respondEphemeral(s, i, "Invalid guild ID.") return } opt := i.ApplicationCommandData().Options[0] var chOpt *discordgo.ApplicationCommandInteractionDataOption for _, o := range opt.Options { if o.Name == "channel" { chOpt = o break } } if chOpt == nil { respondEphemeral(s, i, "Missing channel option.") return } ch := chOpt.ChannelValue(s) if ch == nil { respondEphemeral(s, i, "Invalid channel.") return } chID, err := strconv.ParseInt(ch.ID, 10, 64) if err != nil { respondEphemeral(s, i, "Invalid channel ID.") return } if err := services.Global.Twitch.SetNotificationChannel(context.Background(), guildID, chID); err != nil { respondEphemeral(s, i, "Failed to set notification channel.") return } respondEphemeral(s, i, "Twitch notifications will be sent to "+ch.Mention()+".") } func respondEphemeral(s *discordgo.Session, i *discordgo.InteractionCreate, msg string) { _ = s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{ Type: discordgo.InteractionResponseChannelMessageWithSource, Data: &discordgo.InteractionResponseData{ Content: msg, Flags: discordgo.MessageFlagsEphemeral, }, }) }