如何实现Discord.py中歌曲循环启停的切换命令?
解决Discord.py歌曲循环命令问题
原代码存在的问题
- 函数内部的
loop变量与函数名重名,导致变量引用逻辑混乱 while True死循环会直接阻塞Discord.py的事件循环,bot完全卡死,后续的循环状态判断和break永远无法执行- 循环状态未用持久化的外部变量存储,每次调用命令都会重置变量状态
- 缺少语音客户端未连接、无播放歌曲的边界情况处理
正确实现方案
先定义全局变量存储循环状态和当前循环的歌曲路径,再利用vc.play的after回调函数实现非阻塞式循环播放,同时在命令中完成循环状态的切换:
# 全局变量:记录循环状态和当前循环的歌曲路径 is_looping = False current_loop_song = None ffmpeg_options = { 'options': '-vn' # 可根据你的实际需求调整FFmpeg参数 } @client.command() @commands.is_owner() async def loop(ctx): global is_looping, current_loop_song vc = ctx.voice_client # 检查是否已加入语音频道 if not vc or not vc.is_connected(): await ctx.send("我还没加入任何语音频道!") return # 检查是否有可循环的歌曲 if not vc.is_playing() and current_loop_song is None: await ctx.send("当前没有正在播放的歌曲,无法开启循环!") return # 切换循环状态 if not is_looping: # 记录当前要循环的歌曲(正在播放则取队列首歌,否则用之前循环的歌曲) current_loop_song = queuee[0] if vc.is_playing() else current_loop_song is_looping = True await ctx.send(f"已开启循环:{songs[0]}") # 定义播放完成后的回调函数,自动重播循环歌曲 def after_playing(error): if error: print(f"播放出错:{error}") # 仅在循环开启且有循环歌曲时继续播放 if is_looping and current_loop_song: player = discord.FFmpegPCMAudio(current_loop_song, **ffmpeg_options) vc.play(player, after=after_playing) # 如果当前没有在播放,直接启动循环播放 if not vc.is_playing(): player = discord.FFmpegPCMAudio(current_loop_song, **ffmpeg_options) vc.play(player, after=after_playing) else: # 关闭循环,清空循环歌曲记录 is_looping = False current_loop_song = None await ctx.send("已关闭歌曲循环")
关键说明
- 用全局变量
is_looping和current_loop_song持久化循环状态,避免每次调用命令重置状态 - 利用
vc.play的after参数实现播放结束后的自动回调,不会阻塞bot的事件循环 - 增加了语音连接状态、可循环歌曲的边界检查,避免无效操作
- 单次调用切换一次循环状态,完全符合“运行一次开启、再次运行关闭”的需求
内容的提问来源于stack exchange,提问作者TheRealKurumi
相关产品推荐
相关产品推荐

