Discord bot command stops working after first execution - need help

I built a Discord bot in Python that should join voice channels and play random audio files when users type a specific command. The bot works perfectly the first time someone uses the command, but then it completely stops responding to that same command afterwards.

The bot is supposed to join the user’s voice channel, pick a random audio file from a directory, play it, and then leave the channel automatically. I can still use other commands to manually summon the bot, but the main audio command becomes unresponsive.

def disconnect_bot(self, ctx):
    current_state = self.get_voice_state(ctx.message.server)
    disconnect_task = current_state.voice.disconnect()
    future_task = asyncio.run_coroutine_threadsafe(disconnect_task, current_state.voice.loop)
    try:
        future_task.result()
    except:
        pass

@commands.command(pass_context=True, no_pm=True)
async def playaudio(self, ctx):
    current_state = self.get_voice_state(ctx.message.server)
    settings = {
        'default_search': 'auto',
        'quiet': True,
    }

    if current_state.voice is None:
        join_success = await ctx.invoke(self.summon)
        if not join_success:
            return

    try:
        audio_file = audio_folder + "\\" + random.choice(os.listdir(audio_folder))
        audio_player = current_state.voice.create_ffmpeg_player(audio_file, after=lambda: self.disconnect_bot(ctx))
        audio_player.start()
    except Exception as error:
        error_msg = 'Something went wrong: ```py\n{}: {}\n```'
        await self.bot.send_message(ctx.message.channel, error_msg.format(type(error).__name__, error))

What could be causing this one-time execution issue? Is there something wrong with how I’m handling the voice connection or the cleanup process?

The issue seems to stem from the use of asyncio.run_coroutine_threadsafe in the after callback of your audio player. These callbacks should ideally consist of straightforward functions, as adding async handling can lead to threading conflicts, disrupting subsequent commands. From my experience, it’s more effective to allow the audio playback to finish on its own and then manage disconnections separately. You could either eliminate the after parameter and handle disconnections manually after playback or use a simple lambda expression that merely sets a flag. It’s important to keep the voice connection cleanup within your main command flow rather than embedding it within callbacks, as this approach helps avoid race conditions that may hinder future commands.

Your issue is probably how you’re handling voice state after disconnection. When the audio finishes and your disconnect callback runs, it’s leaving the voice state object messed up, which blocks future commands. I had the same problem - the voice client wasn’t getting cleared properly after disconnecting. That asyncio.run_coroutine_threadsafe in your disconnect function might be causing race conditions or blocking issues that mess with future commands. Try cleaning up the voice state after disconnecting or use a simpler disconnect method. Set current_state.voice = None after disconnecting to reset the state properly. Also try using await current_state.voice.disconnect() directly instead of the threadsafe approach if you can make the callback async.

i think ur disconnect callback is messing things up. the after in create_ffmpeg_player runs when play ends, but ur function might be interfering with the voice state. try removing that callback for now and see if it works multiple times. cleanup needs to b handled differently, i guess.