package public import ( "fmt" "strings" "velox-bot/internal/commands/music/shared" "velox-bot/internal/music" "github.com/bwmarrin/discordgo" ) // The player controls. Everything a dashboard can do to the queue (skip, pause, // resume, stop, repeat, remove and move a track) is also a command, so a // server never needs 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("skip", "Skip the current song (DJ)"), sub("pause", "Pause playback (DJ)"), sub("resume", "Resume playback (DJ)"), sub("stop", "Stop playback and clear the queue (DJ)"), sub("repeat", "Repeat the current song, the whole queue, or nothing (DJ)", &discordgo.ApplicationCommandOption{ Type: discordgo.ApplicationCommandOptionString, Name: "mode", Description: "What repeats", Required: true, Choices: []*discordgo.ApplicationCommandOptionChoice{{Name: "off", Value: "off"}, {Name: "song", Value: "song"}, {Name: "queue", Value: "queue"}}, }), 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 player subcommand. The caller has checked that music is // on and that the member has the DJ role. 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 } current, _ := music.GetQueue(g) needsPlayer := sub.Name != "repeat" && sub.Name != "remove" && sub.Name != "move" if needsPlayer && current == nil { shared.RespondEphemeral(s, i, "Nothing is playing.") return } var err error var msg string switch sub.Name { case "skip": err, msg = music.Skip(g), "Skipped." case "pause": err, msg = music.Pause(g, true), "Paused. `/music resume` continues." case "resume": err, msg = music.Pause(g, false), "Resumed." case "stop": err, msg = music.Stop(g), "Stopped, and the queue is cleared." case "repeat": switch args["mode"].StringValue() { case "song": music.SetRepeat(g, true, false) msg = "The current song repeats." case "queue": music.SetRepeat(g, false, true) msg = "The whole queue repeats." default: music.SetRepeat(g, false, false) msg = "Nothing repeats." } 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) }