package discord import ( "context" "log/slog" "github.com/disgoorg/disgo/bot" "github.com/disgoorg/disgo/events" "github.com/disgoorg/disgolink/v4/disgolink" "discord-music-bot/internal/music" ) type VoiceForwarder struct { client *bot.Client lavalink *disgolink.Client music *music.Manager logger *slog.Logger } func NewVoiceForwarder(client *bot.Client, lavalinkClient *disgolink.Client, musicManager *music.Manager, logger *slog.Logger) *VoiceForwarder { return &VoiceForwarder{ client: client, lavalink: lavalinkClient, music: musicManager, logger: logger, } } func (f *VoiceForwarder) OnVoiceStateUpdate(event *events.GuildVoiceStateUpdate) { if event.VoiceState.UserID == f.client.ApplicationID { f.lavalink.OnVoiceStateUpdate(context.Background(), event.VoiceState.GuildID, event.VoiceState.ChannelID, event.VoiceState.SessionID) return } f.leaveIfNowAlone(event) } func (f *VoiceForwarder) leaveIfNowAlone(event *events.GuildVoiceStateUpdate) { oldChannelID := event.OldVoiceState.ChannelID if oldChannelID == nil { return } if newChannelID := event.VoiceState.ChannelID; newChannelID != nil && *newChannelID == *oldChannelID { return } guildID := event.VoiceState.GuildID botState, ok := f.client.Caches.VoiceState(guildID, f.client.ApplicationID) if !ok || botState.ChannelID == nil || *botState.ChannelID != *oldChannelID { return } for state := range f.client.Caches.VoiceStates(guildID) { if state.UserID != f.client.ApplicationID && state.ChannelID != nil && *state.ChannelID == *oldChannelID { return } } ctx := context.Background() if err := f.music.Guild(guildID).Stop(ctx); err != nil { f.logger.ErrorContext(ctx, "failed to stop playback after being left alone", slog.String("guild_id", guildID.String()), slog.Any("err", err)) } if err := f.client.UpdateVoiceState(ctx, guildID, nil, false, false); err != nil { f.logger.ErrorContext(ctx, "failed to leave voice channel after being left alone", slog.String("guild_id", guildID.String()), slog.Any("err", err)) } } func (f *VoiceForwarder) OnVoiceServerUpdate(event *events.VoiceServerUpdate) { if event.Endpoint == nil { f.logger.Warn("received voice server update without an endpoint", slog.String("guild_id", event.GuildID.String())) return } f.lavalink.OnVoiceServerUpdate(context.Background(), event.GuildID, event.Token, *event.Endpoint) }