Implement slash commands for playback control
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
package commands
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/disgoorg/disgo/bot"
|
||||
"github.com/disgoorg/disgo/discord"
|
||||
"github.com/disgoorg/disgo/events"
|
||||
"github.com/disgoorg/disgolink/v4/lavalink"
|
||||
"github.com/disgoorg/snowflake/v2"
|
||||
)
|
||||
|
||||
func guildID(event *events.ApplicationCommandInteractionCreate) (snowflake.ID, bool) {
|
||||
id := event.GuildID()
|
||||
if id == nil {
|
||||
return 0, false
|
||||
}
|
||||
return *id, true
|
||||
}
|
||||
|
||||
func memberVoiceChannel(discordClient *bot.Client, guild snowflake.ID, userID snowflake.ID) (snowflake.ID, bool) {
|
||||
state, ok := discordClient.Caches.VoiceState(guild, userID)
|
||||
if !ok || state.ChannelID == nil {
|
||||
return 0, false
|
||||
}
|
||||
return *state.ChannelID, true
|
||||
}
|
||||
|
||||
func ensureCanControlPlayback(discordClient *bot.Client, guild snowflake.ID, userID snowflake.ID) (bool, string) {
|
||||
botChannelID, botConnected := memberVoiceChannel(discordClient, guild, discordClient.ApplicationID)
|
||||
if !botConnected {
|
||||
return true, ""
|
||||
}
|
||||
|
||||
userChannelID, userConnected := memberVoiceChannel(discordClient, guild, userID)
|
||||
if !userConnected || userChannelID != botChannelID {
|
||||
return false, fmt.Sprintf("I'm currently active in <#%s>. Join that channel to control playback.", botChannelID)
|
||||
}
|
||||
return true, ""
|
||||
}
|
||||
|
||||
func requirePlaybackAccess(discordClient *bot.Client, event *events.ApplicationCommandInteractionCreate) (snowflake.ID, error) {
|
||||
gid, ok := guildID(event)
|
||||
if !ok {
|
||||
return 0, guildOnlyError(event)
|
||||
}
|
||||
|
||||
if allowed, reason := ensureCanControlPlayback(discordClient, gid, event.User().ID); !allowed {
|
||||
return 0, rejectEphemeral(event, reason)
|
||||
}
|
||||
|
||||
return gid, nil
|
||||
}
|
||||
|
||||
func reply(event *events.ApplicationCommandInteractionCreate, content string) error {
|
||||
return event.CreateMessage(discord.NewMessageCreate().WithContent(content))
|
||||
}
|
||||
|
||||
func replyEphemeral(event *events.ApplicationCommandInteractionCreate, content string) error {
|
||||
return event.CreateMessage(discord.NewMessageCreate().WithContent(content).WithEphemeral(true))
|
||||
}
|
||||
|
||||
func guildOnlyError(event *events.ApplicationCommandInteractionCreate) error {
|
||||
return rejectEphemeral(event, "This command only works inside a server.")
|
||||
}
|
||||
|
||||
func rejectEphemeral(event *events.ApplicationCommandInteractionCreate, content string) error {
|
||||
if err := replyEphemeral(event, content); err != nil {
|
||||
return err
|
||||
}
|
||||
return errors.New(content)
|
||||
}
|
||||
|
||||
func replyWithError(event *events.ApplicationCommandInteractionCreate, userMessage string, cause error) error {
|
||||
if err := replyEphemeral(event, userMessage); err != nil {
|
||||
return err
|
||||
}
|
||||
return fmt.Errorf("%s: %w", userMessage, cause)
|
||||
}
|
||||
|
||||
func intPtr(v int) *int {
|
||||
return &v
|
||||
}
|
||||
|
||||
func parsePosition(raw string) (lavalink.Duration, error) {
|
||||
parts := strings.Split(raw, ":")
|
||||
if len(parts) == 0 || len(parts) > 3 {
|
||||
return 0, errors.New("expected seconds, mm:ss or hh:mm:ss")
|
||||
}
|
||||
|
||||
segments := make([]int64, len(parts))
|
||||
for i, part := range parts {
|
||||
n, err := strconv.ParseInt(strings.TrimSpace(part), 10, 64)
|
||||
if err != nil || n < 0 {
|
||||
return 0, errors.New("expected seconds, mm:ss or hh:mm:ss")
|
||||
}
|
||||
segments[i] = n
|
||||
}
|
||||
|
||||
var totalSeconds int64
|
||||
for _, segment := range segments {
|
||||
totalSeconds = totalSeconds*60 + segment
|
||||
}
|
||||
|
||||
return lavalink.Duration(totalSeconds) * lavalink.Second, nil
|
||||
}
|
||||
Reference in New Issue
Block a user