提问者:小点点

我正在用discord.py做一个音乐机器人,我在播放命令上遇到了一些问题


机器人有播放命令,可以做3件事,如果它还没有在语音通道中,它会加入语音通道,它会播放歌曲(显然),如果机器人已经在播放歌曲,它会将歌曲存储在一个名为队列的脚本中,然后在歌曲结束时播放它。要做到这一点,您需要在voiceClientsplay命令上的statment之后的,它似乎表现得很奇怪。我已经放了一些print命令来测试机器人,似乎我放在后语句上的函数正在立即触发,而不是当歌曲结束时,我不知道这是bug还是我做错了什么…无论如何,这是代码:

这是play命令后播放的函数

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])

这是播放命令

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))

共2个答案

匿名用户

啊,你犯了一个典型的Python错误。看看这句话:

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

当该行运行时,它要做的第一件事就是调用您的函数继续。然后它会将该函数调用的RESULT传递给play函数。你不想调用函数,你想传递函数对象:

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

如果你真的需要这里的上下文,你必须使用lambda:

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

匿名用户

在代码片段的最后一行:

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

关键字参数之后的需要一个可调用的。你没有给它。你正在调用一个函数继续(顺便说一句,这不是一个很好的函数名称,因为你隐藏了builtin关键字),并将返回值绑定到之后的。由于您的可调用对象必须接受参数ctx,因此快速解决方法是传入lambda:

after=lambda: continue(ctx)