Skip to content
Advertisement

I’m making a music bot with discord.py and I’m having some trouble with the play command

The bot has play command that does 3 things it joins the voice channel if it isn’t in the voice channel already, it plays songs(obviously) and it stores the songs in a dict called queues if the bot is already playing a song to then play it when the song ends. To do something like this you need the after statment on the voiceClients play command and it seems to be behaving quit weirdly. I’ve put some print commands to test the bot and it seems that the function that I put on the after statment is firing right away rather then when the song ends, I don’t know if this is a bug or if I’m doing something wrong… anyway here’s the code:

this is the function that plays after the play command

def continue(ctx):

   queues[ctx.guild.id].pop(0)

   print(f'function continue: {queues}')
    
   if len(queues[ctx.guild.id]) == 0:
       return

   Songs.play(ctx=ctx ,song=queues[ctx.guild.id][0])

and here is the play command

class Songs(commands.Cog):

   def __init__(self, bot):
       self.client = client


   @commands.command()
   async def play(self, ctx, *, song):

       if ctx.voice_client is None:
           await ctx.message.author.voice.channel.connect()
       else:
           if ctx.voice_client.channel != ctx.message.author.voice.channel:
               await ctx.send('You are not in the same channel as the bot!')
               return
    
       if ctx.guild.id in queues:
           queues[ctx.guild.id].append(song)
       else: 
           queues[ctx.guild.id] = [song]
    
       print(f'function play: {queues}')

       if ctx.voice_client.is_playing():
           await ctx.send('Song added to queue! :thumbsup:')
           return

       ydl_opts = {'format': 'bestaudio'}
       with youtube_dl.YoutubeDL(ydl_opts) as ydl:
           if musica.startswith('https'):
               info = ydl.extract_info(song, download=False)
               URL = info['formats'][0]['url']
           else:
               info = ydl.extract_info(f'ytsearch:{song}', download=False)
               URL = info['entries'][0]['formats'][0]['url']
    

       FFMPEG_OPTIONS = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'}
       ctx.message.guild.voice_client.play(discord.FFmpegPCMAudio(URL, **FFMPEG_OPTIONS), after=continue(ctx))

Advertisement

Answer

Ah, you have committed one of the classic Python blunders. Look at this line:

       ctx.message.guild.voice_client.play(discord.FFmpegPCMAudio(URL, **FFMPEG_OPTIONS), after=continue(ctx))

When that line runs, the first thing it’s going to do is call your function continue. It will then pass the RESULT of that function call to the play function. You don’t want to CALL the function, you want to pass the function object:

       ctx.message.guild.voice_client.play(discord.FFmpegPCMAudio(URL, **FFMPEG_OPTIONS), after=continue)

If you really need the context in there, you’ll have to use a lambda:

       ctx.message.guild.voice_client.play(discord.FFmpegPCMAudio(URL, **FFMPEG_OPTIONS), after=lambda: continue(ctx))
User contributions licensed under: CC BY-SA
5 People found this is helpful
Advertisement