package public import ( "fmt" "strings" "velox-bot/internal/commands/music/shared" "velox-bot/internal/music" "github.com/bwmarrin/discordgo" ) // Queue editing. Pausing, skipping, repeating and stopping are buttons on the // now-playing message, so the only queue controls that need commands are // removing a song and moving one. They need the DJ role, like /play, /queue // and /volume. Turning music on or off needs Manage Server. func positionOption(name, desc string) *discordgo.ApplicationCommandOption { return &discordgo.ApplicationCommandOption{ Type: discordgo.ApplicationCommandOptionInteger, Name: name, Description: desc, Required: true, MinValue: ptrFloat(1), MaxValue: 1000, } } func playerOptions() []*discordgo.ApplicationCommandOption { sub := func(name, desc string, o ...*discordgo.ApplicationCommandOption) *discordgo.ApplicationCommandOption { return &discordgo.ApplicationCommandOption{Type: discordgo.ApplicationCommandOptionSubCommand, Name: name, Description: desc, Options: o} } return []*discordgo.ApplicationCommandOption{ sub("remove", "Remove a song from the queue (DJ)", positionOption("position", "Its number in /queue")), sub("move", "Move a song to another place in the queue (DJ)", positionOption("from", "Its number in /queue"), positionOption("to", "The number it should have")), } } // queueEntry returns the queued song at position n (1 is the first one after // the song that is playing), as /queue numbers them. func queueEntry(guildID string, n int) (*music.TrackEntry, int) { _, rest := music.GetQueue(guildID) if n < 1 || n > len(rest) { return nil, len(rest) } e := rest[n-1] return &e, len(rest) } func title(e *music.TrackEntry) string { return strings.TrimSpace(e.Track.Info.Title) } // handlePlayer runs a queue subcommand. The caller has checked that music is // on and that the member has the DJ role. Pause, skip, repeat and stop are // buttons on the now-playing message, so only what has no button is a command. func handlePlayer(s *discordgo.Session, i *discordgo.InteractionCreate, sub *discordgo.ApplicationCommandInteractionDataOption) { g := i.GuildID args := map[string]*discordgo.ApplicationCommandInteractionDataOption{} for _, o := range sub.Options { args[o.Name] = o } var err error var msg string switch sub.Name { case "remove": n := int(args["position"].IntValue()) e, size := queueEntry(g, n) if e == nil { shared.RespondEphemeral(s, i, fmt.Sprintf("There is no song number %d in the queue (it has %d).", n, size)) return } err, msg = music.RemoveFromQueue(g, e.QueueID), fmt.Sprintf("Removed **%s**.", title(e)) case "move": from, to := int(args["from"].IntValue()), int(args["to"].IntValue()) e, size := queueEntry(g, from) if e == nil { shared.RespondEphemeral(s, i, fmt.Sprintf("There is no song number %d in the queue (it has %d).", from, size)) return } if to > size { to = size } err, msg = music.Reorder(g, e.QueueID, to), fmt.Sprintf("Moved **%s** to number %d.", title(e), to) default: shared.RespondEphemeral(s, i, "Unknown subcommand.") return } if err != nil { shared.RespondEphemeral(s, i, "That didn't work: "+err.Error()) return } shared.RespondEphemeral(s, i, msg) }