Androz2091 / discord-player

🎧 Complete framework to simplify the implementation of music commands using discord.js v14
https://discord-player.js.org/
MIT License
603 stars 190 forks source link

Bot doesn't disconnect from empty voice channel if user has moved from it #1326

Closed Olebeh closed 1 year ago

Olebeh commented 2 years ago

Whenever someone moves from queue channel to another (not disconnecting during this, just directly joining another voice channel) or when user is moved to server AFK channel, and the queue channel is now empty, the bot doesn't leave and doesn't stop playing music. I don't know is it either a feature or a bug, but it doesn't look like a feature

frizzyfysh commented 2 years ago

I also had this issue with my bot, I fixed it with this hacky workaround by listening to the voiceStateUpdate event and checking manually:

import { getVoiceConnection } from '@discordjs/voice'
import { QueueRepeatMode, Util } from 'discord-player'
import { clientId } from '../config'
import { EventHandler } from '../types/Events'
import { logger } from '../utils/logger'

export default {
    name: 'voiceStateUpdate',
    async run (oldState, newState) {
        try {
            const queue = this.musicPlayer.getQueue(oldState.guild.id)

            if (!queue || !queue.connection || !queue.connection.channel) {
                return
            }

            if (newState.channelId !== queue.connection.channel.id) {
                // user left music channel

                if (!Util.isVoiceEmpty(queue.connection.channel)) {
                    // music channel not empty
                    return
                }
                else if (queue._cooldownsTimeout.get(`empty_${oldState.guild.id}`)) {
                    // empty timeout already running
                    return
                }

                // start empty timeout because user disconnected from voice channel and noone else is there to listen
                const timeout = setTimeout(() => {
                    if (!Util.isVoiceEmpty(queue.connection.channel)) {
                        return
                    }
                    if (!this.musicPlayer.queues.has(queue.guild.id)) {
                        return
                    }
                    if (queue.options.leaveOnEmpty) {
                        queue.repeatMode = QueueRepeatMode.OFF
                        queue.destroy()
                    }
                    this.musicPlayer.emit('channelEmpty', queue)
                }, queue.options.leaveOnEmptyCooldown || 0).unref()
                queue._cooldownsTimeout.set(`empty_${oldState.guild.id}`, timeout)
            }
            else if (newState.channelId === queue.connection.channel.id && newState.member?.id !== clientId) {
                // user joined channel with bot
                const emptyTimeout = queue._cooldownsTimeout.get(`empty_${oldState.guild.id}`)
                if (emptyTimeout) {
                    // cancel empty timer because user joined voice channel with bot
                    clearTimeout(emptyTimeout)
                    queue._cooldownsTimeout.delete(`empty_${oldState.guild.id}`)
                }
            }
        }
        catch (err) {
            logger.error(err)
        }
    }
} as EventHandler<'voiceStateUpdate'>

hope this helps you or helps someone make a better solution

Olebeh commented 2 years ago

I also had this issue with my bot, I fixed it with this hacky workaround by listening to the voiceStateUpdate event and checking manually: ... hope this helps you or helps someone make a better solution

Thanks for code. I actually realize how to make it, but just wanted to report a bug to note developers. By the way, consider making a pr