为什么我的Discord机器人会重复播放歌曲且skip命令需要触发两次?
问题原因排查
1. 歌曲自动重复播放原因
- 队列操作逻辑错误:你采用了二维数组结构存储
musicQueue,当前代码仅删除内层列表的第一个元素del self.musicQueue[0][0],但内层列表删空后,外层列表对应的空元素仍然存在,导致len(self.musicQueue) > 0判断始终为真,循环触发播放时会重复读取残留的旧歌曲数据。 - 若你原本设计的是一维队列,大概率是添加歌曲时错误嵌套了列表,导致每次删除操作都没有真正清除已播放的歌曲项。
2. skip命令异常原因
- 重复播放请求冲突:调用
self.vc.stop()时,会自动触发vc.play()绑定的after回调(也就是playNext()方法),同时你的代码又主动调用了await self.playMusic(),同一时间发起两个播放请求,因此抛出already playing music twice报错。首次触发skip实际生效的是回调的播放逻辑,并没有完成切歌,因此需要触发第二次才能生效。 VoiceChannel object not subscriptable错误:你使用self.vc != ""判断vc状态的逻辑错误,vc是VoiceChannel对象,未初始化时默认值为None,和空字符串比较永远返回True,当vc未正确连接时仍然执行stop操作,异常状态下可能误将vc对象写入musicQueue,后续读取队列尝试对vc对象取下标就会抛出该错误。
修复方案
1. 修正playNext方法逻辑
如果你的队列不需要二维结构,直接改为一维队列操作即可:
def playNext(self): if len(self.musicQueue) > 0: self.isPlaying = True # 一维队列直接读取第一个元素 mURL = self.musicQueue[0]['source'] # 直接弹出队列第一个元素,避免残留 del self.musicQueue[0] self.vc.play(discord.FFmpegPCMAudio(mURL, **self.FFMPEG_OPTIONS), after=lambda e: self.playNext()) else: self.isPlaying = False
如果确实需要二维数组结构,删除内层元素后新增判断,内层为空时同步删除外层元素:
def playNext(self): if len(self.musicQueue) > 0: self.isPlaying = True mURL = self.musicQueue[0][0]['source'] del self.musicQueue[0][0] # 内层列表为空时同步删除外层元素 if len(self.musicQueue[0]) == 0: del self.musicQueue[0] self.vc.play(discord.FFmpegPCMAudio(mURL, **self.FFMPEG_OPTIONS), after=lambda e: self.playNext()) else: self.isPlaying = False
提示:原代码中
FFEMPEG_OPTIONS变量名存在拼写错误,已修正为标准的FFMPEG_OPTIONS,避免编码器加载失败。
2. 修正skip命令逻辑
去掉主动调用playMusic的逻辑,依靠stop触发的after回调自动播放下一首,同时修正vc状态判断逻辑:
@commands.command(aliases=['skip']) async def s(self, ctx): # 修正vc状态判断,仅在vc已连接且正在播放时执行切歌 if self.vc is not None and self.vc.is_playing(): self.vc.stop() await ctx.send("已跳过当前歌曲") else: await ctx.send("当前没有正在播放的歌曲")
内容的提问来源于stack exchange,提问作者Ledip Ledip
相关产品推荐
相关产品推荐

