Files

110 lines
3.1 KiB
Go

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
}