diff --git a/packages/discord-player/src/DefaultVoiceStateHandler.ts b/packages/discord-player/src/DefaultVoiceStateHandler.ts index 2665c4ce3..08506bce6 100644 --- a/packages/discord-player/src/DefaultVoiceStateHandler.ts +++ b/packages/discord-player/src/DefaultVoiceStateHandler.ts @@ -1,119 +1,105 @@ -import { GuildQueue, GuildQueueEvent } from './queue'; +import { ChannelType, GatewayVoiceState } from 'discord-api-types/v10'; +import { Channel } from './clientadapter/IClientAdapter'; import { Player } from './Player'; +import { GuildQueue, GuildQueueEvent } from './queue'; import { Util } from './utils/Util'; -import { GatewayVoiceState } from 'discord-api-types/v9'; -import { VoiceBasedChannel } from './clientadapter/IClientAdapter'; -import { ChannelType } from 'discord-api-types/v10'; export async function defaultVoiceStateHandler(player: Player, queue: GuildQueue, oldState: GatewayVoiceState, newState: GatewayVoiceState) { if (!queue || !queue.connection || !queue.channel) return; const clientUserId = player.clientAdapter.getClientUserId(); + handleDisconnection(clientUserId, oldState, newState, queue, player); + handlePauseOnEmptyState(queue); + handleVoiceChannelUpdates(player, clientUserId, oldState, newState, queue); + handleChannelPopulationAndDeletion(oldState, newState, queue, player); +} + +function handleDisconnection(clientUserId: string, oldState: GatewayVoiceState, newState: GatewayVoiceState, queue: GuildQueue, player: Player) { if (oldState.channel_id && !newState.channel_id && newState.member?.user?.id === clientUserId) { try { queue.delete(); } catch { Util.noop(); } - return void player.events.emit(GuildQueueEvent.disconnect, queue); + player.events.emit(GuildQueueEvent.disconnect, queue); } +} +function handlePauseOnEmptyState(queue: GuildQueue) { if (queue.options.pauseOnEmpty) { - const isEmpty = Util.isVoiceEmpty(queue.channel); + const isEmpty = Util.isVoiceEmpty(queue.channel!); + const isPausedOnEmpty = Reflect.get(queue, '__pausedOnEmpty'); if (isEmpty) { queue.node.setPaused(true); Reflect.set(queue, '__pausedOnEmpty', true); - if (queue.hasDebugger) { - queue.debug('Voice channel is empty and options#pauseOnEmpty is true, pausing...'); - } - } else { - if (Reflect.get(queue, '__pausedOnEmpty')) { - queue.node.setPaused(false); - Reflect.set(queue, '__pausedOnEmpty', false); - if (queue.hasDebugger) { - queue.debug('Voice channel is not empty and options#pauseOnEmpty is true, resuming...'); - } - } + debugLog(queue, 'pausing'); + } else if (isPausedOnEmpty) { + queue.node.setPaused(false); + Reflect.set(queue, '__pausedOnEmpty', false); + debugLog(queue, 'resuming'); } } +} +function handleVoiceChannelUpdates(player: Player, clientUserId: string, oldState: GatewayVoiceState, newState: GatewayVoiceState, queue: GuildQueue) { const newStateChannel = player.clientAdapter.getChannel(newState.channel_id!); + if (!newStateChannel) return; + if (!oldState.channel_id && newState.channel_id && newState.member?.user?.id === clientUserId) { - if (newState.mute != null && oldState.mute !== newState.mute) { - queue.node.setPaused(newState.mute); - } else if (newStateChannel?.type === ChannelType.GuildStageVoice && newState.suppress != null && oldState.suppress !== newState.suppress) { - queue.node.setPaused(newState.suppress); - if (newState.suppress) { - newStateChannel.clientUser.requestToSpeak().catch(Util.noop); - } + handleMuteAndSuppressChanges(oldState, newState, queue, newStateChannel); + } +} + +function handleMuteAndSuppressChanges(oldState: GatewayVoiceState, newState: GatewayVoiceState, queue: GuildQueue, newStateChannel: Channel) { + if (newState.mute != null && oldState.mute !== newState.mute) { + queue.node.setPaused(newState.mute); + } else if (newStateChannel?.type === ChannelType.GuildStageVoice && newState.suppress != null && oldState.suppress !== newState.suppress) { + queue.node.setPaused(newState.suppress); + if (newState.suppress) { + newStateChannel.clientUser.requestToSpeak().catch(Util.noop); } } +} - if (!newState.channel_id && oldState.channel_id === queue.channel.id) { - if (!Util.isVoiceEmpty(queue.channel)) return; - const timeout = setTimeout(() => { - if (!Util.isVoiceEmpty(queue.channel!)) return; - if (!player.nodes.has(queue.guild.id)) return; - if (queue.options.leaveOnEmpty) queue.delete(); - player.events.emit(GuildQueueEvent.emptyChannel, queue); - }, queue.options.leaveOnEmptyCooldown || 0).unref(); - queue.timeouts.set(`empty_${oldState.guild_id}`, timeout); +function handleChannelPopulationAndDeletion(oldState: GatewayVoiceState, newState: GatewayVoiceState, queue: GuildQueue, player: Player) { + manageTimeoutsOnChannelChange(oldState, newState, queue, player); +} + +function manageTimeoutsOnChannelChange(oldState: GatewayVoiceState, newState: GatewayVoiceState, queue: GuildQueue, player: Player) { + const channelEmpty = Util.isVoiceEmpty(queue.channel!); + + if (!newState.channel_id && oldState.channel_id === queue.channel!.id && channelEmpty) { + setEmptyTimeout(queue, oldState, player); + } else if (newState.channel_id && newState.channel_id === queue.channel!.id) { + clearEmptyTimeout(queue, oldState, player); } +} - if (newState.channel_id && newState.channel_id === queue.channel.id) { - const emptyTimeout = queue.timeouts.get(`empty_${oldState.guild_id}`); - const channelEmpty = Util.isVoiceEmpty(queue.channel); - if (!channelEmpty && emptyTimeout) { - clearTimeout(emptyTimeout); - queue.timeouts.delete(`empty_${oldState.guild_id}`); - player.events.emit(GuildQueueEvent.channelPopulate, queue); +function setEmptyTimeout(queue: GuildQueue, oldState: GatewayVoiceState, player: Player) { + const timeout = setTimeout(() => { + if (Util.isVoiceEmpty(queue.channel!) && player.nodes.has(queue.guild.id) && queue.options.leaveOnEmpty) { + queue.delete(); + player.events.emit(GuildQueueEvent.emptyChannel, queue); } + }, queue.options.leaveOnEmptyCooldown || 0).unref(); + const timeoutKey = `empty_${oldState.guild_id}`; + queue.timeouts.set(timeoutKey, timeout); +} + +function clearEmptyTimeout(queue: GuildQueue, oldState: GatewayVoiceState, player: Player) { + const timeoutKey = `empty_${oldState.guild_id}`; + const emptyTimeout = queue.timeouts.get(timeoutKey); + if (emptyTimeout) { + clearTimeout(emptyTimeout); + queue.timeouts.delete(timeoutKey); + player.events.emit(GuildQueueEvent.channelPopulate, queue); } +} - if (oldState.channel_id && newState.channel_id && oldState.channel_id !== newState.channel_id) { - if (newState.member?.user?.id === clientUserId) { - if (queue.connection && newState.member?.user?.id === clientUserId) { - const newQueueChannel = player.clientAdapter.getChannel(newState.channel_id); - queue.channel! = newQueueChannel as VoiceBasedChannel; - } - const emptyTimeout = queue.timeouts.get(`empty_${oldState.guild_id}`); - const channelEmpty = Util.isVoiceEmpty(queue.channel!); - if (!channelEmpty && emptyTimeout) { - clearTimeout(emptyTimeout); - queue.timeouts.delete(`empty_${oldState.guild_id}`); - player.events.emit(GuildQueueEvent.channelPopulate, queue); - } else { - const timeout = setTimeout(() => { - if (queue.connection && !Util.isVoiceEmpty(queue.channel!)) return; - if (!player.nodes.has(queue.guild.id)) return; - if (queue.options.leaveOnEmpty) queue.delete(); - player.events.emit(GuildQueueEvent.emptyChannel, queue); - }, queue.options.leaveOnEmptyCooldown || 0).unref(); - queue.timeouts.set(`empty_${oldState.guild_id}`, timeout); - } - } else { - if (newState.channel_id !== queue.channel.id) { - const channelEmpty = Util.isVoiceEmpty(queue.channel!); - if (!channelEmpty) return; - if (queue.timeouts.has(`empty_${oldState.guild_id}`)) return; - const timeout = setTimeout(() => { - if (!Util.isVoiceEmpty(queue.channel!)) return; - if (!player.nodes.has(queue.guild.id)) return; - if (queue.options.leaveOnEmpty) queue.delete(); - player.events.emit(GuildQueueEvent.emptyChannel, queue); - }, queue.options.leaveOnEmptyCooldown || 0).unref(); - queue.timeouts.set(`empty_${oldState.guild_id}`, timeout); - } else { - const emptyTimeout = queue.timeouts.get(`empty_${oldState.guild_id}`); - const channelEmpty = Util.isVoiceEmpty(queue.channel!); - if (!channelEmpty && emptyTimeout) { - clearTimeout(emptyTimeout); - queue.timeouts.delete(`empty_${oldState.guild_id}`); - player.events.emit(GuildQueueEvent.channelPopulate, queue); - } - } - } +function debugLog(queue: GuildQueue, message: string) { + if (queue.hasDebugger) { + queue.debug(`Voice channel state change: ${message}`); } }