Compare commits

..
Author SHA1 Message Date
FernandoJVideiraandClaude Sonnet 5.5 88fc915f3b Music: only /music remove and /music move are commands
Pause, skip, repeat and stop are already buttons on the now-playing message.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
2026-10-23 12:16:20 +01:00
FernandoJVideira 92c9f6b686 Merge pull request 'Help: fall back to a private message in the channel when DMs fail' (#33) from fix/help-dms-off into dev
Reviewed-on: #33
2026-10-23 11:05:20 +00:00
FernandoJVideira 12a3cadcf7 Merge pull request 'Help: wide and short' (#32) from ft/help-columns into dev
Reviewed-on: #32
2026-10-23 11:05:13 +00:00
5 changed files with 10 additions and 65 deletions

No files matched your search

+1 -5
View File
@@ -60,14 +60,10 @@ Anyone can use these. `/rps`, `/rpsstats` and `/rpsleaderboard` work in servers
| `/queue` | | **DJ** role | Shows the queue |
| `/volume` | `value`* (0 to 150) | **DJ** role | Sets the volume |
| `/music toggle` | | Manage Server | Turns music on or off in this server |
| `/music skip` | | **DJ** role | Skips the current song |
| `/music pause`, `/music resume` | | **DJ** role | Pauses or resumes |
| `/music stop` | | **DJ** role | Stops and clears the queue |
| `/music repeat` | `mode`* (off, song, queue) | **DJ** role | Repeats the song, the queue, or nothing |
| `/music remove` | `position`* (its number in `/queue`) | **DJ** role | Removes a queued song |
| `/music move` | `from`*, `to`* | **DJ** role | Moves a queued song |
Requires Lavalink. See [Getting started](getting-started.md#optional-music-with-lavalink).
Pause, skip, repeat and stop are buttons on the now-playing message. Requires Lavalink. See [Getting started](getting-started.md#optional-music-with-lavalink).
## Meeting rooms
+1 -1
View File
@@ -68,7 +68,7 @@ Lavalink-powered playback. Code: `internal/music`, commands in `internal/command
- `/play` takes a name or a URL, `/queue` shows the queue, `/volume` sets 0 to 150 percent. These need a role called **DJ**.
- The now-playing message has buttons for playback and repeat. Buttons also check for the DJ role.
- `/music toggle` (Manage Server) turns music on or off in a server. `/music skip`, `pause`, `resume`, `stop`, `repeat`, `remove` and `move` control playback and the queue (DJ role).
- `/music toggle` (Manage Server) turns music on or off in a server. `/music remove` and `/music move` edit the queue (DJ role).
- The queue and now-playing state are kept in the database, and playback can also be controlled by writing to the `music_commands` table. The hosted Velox dashboard uses this (see [Database](database.md)); you never need it, the commands above do the same.
- Music needs a Lavalink server. Without `LAVALINK_HOST` the rest of the bot works and music does not.
+1 -1
View File
@@ -44,7 +44,7 @@ func fields() []*discordgo.MessageEmbedField {
col("Fun",
"`/ping` `/joke` `/coinflip`", "`/dice` `/rps` `/rpsstats`", "`/rpsleaderboard`"),
col("Music (DJ role)",
"`/play` `/queue` `/volume`", "`/music skip` `pause` `resume`", "`/music stop` `repeat`", "`/music remove` `move`", "`/music toggle` (Manage Server)"),
"`/play` `/queue` `/volume`", "`/music remove` `move`", "`/music toggle` (Manage Server)"),
col("Sessions and time",
"`/schedule create`", "`/schedule list`", "`/schedule reschedule`", "`/timezone set` `show`"),
col("Tickets",
+7 -41
View File
@@ -10,10 +10,10 @@ import (
"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.
// 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{
@@ -27,15 +27,6 @@ func playerOptions() []*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")),
@@ -57,44 +48,19 @@ 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.
// 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
}
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)
-17
View File
@@ -686,23 +686,6 @@ func ToggleRepeatQueue(guildID string) (bool, bool) {
return repeatSong, repeatQueue
}
// RepeatFlags reports whether the current song or the whole queue repeats.
func RepeatFlags(guildID string) (song, queue bool) { return repeatFlags(guildID) }
// SetRepeat sets the repeat mode directly. At most one of the two applies;
// asking for both repeats the song.
func SetRepeat(guildID string, song, queue bool) {
if manager == nil {
return
}
gp := getOrCreateGuildPlayer(guildID)
manager.mu.Lock()
gp.RepeatSong = song
gp.RepeatQueue = queue && !song
manager.mu.Unlock()
syncState(guildID)
}
func repeatFlags(guildID string) (bool, bool) {
if manager == nil {
return false, false