Discord.py音乐机器人如何实现队列歌曲播放完成后自动依次播放下一首
实现思路
利用discord.py中VoiceClient.play()方法的after回调参数实现自动切歌:该参数会在歌曲播放完成(或播放出错)时自动执行指定函数,我们可以在该回调中触发下一首歌曲的加载和播放逻辑。
完整修改代码
1. 存储结构调整
首先将原servers字典调整为多服务器隔离的嵌套结构,避免跨服务器数据冲突:
# 全局servers初始化示例,可兼容原有逻辑 servers = {} # 每个新服务器首次使用时自动初始化结构: # servers[guild_id] = {"queue": {}, "cur_id": None, "ctx": None}
2. 命令逻辑修改
import asyncio @commands.command(pass_context=True, aliases=["aq"]) async def add_queue(self, ctx, *, url): guild_id = ctx.message.guild.id if guild_id not in servers: servers[guild_id] = {"queue": {}, "cur_id": None, "ctx": ctx} server_data = servers[guild_id] try: server_data["queue"][len(server_data["queue"])] = url user = ctx.message.author.mention await ctx.send(f'`{url}` 已被 {user} 添加到播放队列!') except: await ctx.send(f"无法将 {url} 添加到播放队列!") @commands.command(pass_context=True, aliases=["qp"], case_insensitive=True) async def pq(self,ctx, number): guild_id = ctx.message.guild.id if guild_id not in servers: await ctx.send("当前服务器无可用播放队列!") return server_data = servers[guild_id] number = int(number) if number in server_data["queue"]: source = server_data["queue"][number] server_data["cur_id"] = number server_data["ctx"] = ctx await ctx.send(f"**当前播放:** {source}") await self.transformer(ctx, source) else: await ctx.send("队列中不存在对应序号的歌曲!")
3. 播放逻辑+自动切歌实现
async def transformer(self,ctx, url): player = await YTDLSource.from_url(url, loop=self.bot.loop, stream=True) if not ctx.message.author.voice: await ctx.send("你未连接到任何语音频道!") return elif ctx.voice_client and ctx.voice_client.is_connected(): print('已连接到语音频道') pass else: channel = ctx.message.author.voice.channel await ctx.send(f'已连接到 `{channel}`') await channel.connect() # 播放完成回调函数 def after_callback(error): if error: print(f'播放出错: {error}') # 将异步切歌逻辑提交到事件循环执行 fut = asyncio.run_coroutine_threadsafe(self.play_next(ctx.guild.id), self.bot.loop) try: fut.result() except Exception as e: print(f'切歌出错: {e}') ctx.voice_client.play(player, after=after_callback) # 新增自动切歌方法 async def play_next(self, guild_id): if guild_id not in servers: return server_data = servers[guild_id] ctx = server_data["ctx"] next_id = server_data["cur_id"] + 1 if next_id in server_data["queue"]: source = server_data["queue"][next_id] server_data["cur_id"] = next_id await ctx.send(f"**自动播放下一首:** {source}") await self.transformer(ctx, source) else: await ctx.send("队列所有歌曲已播放完毕!") server_data["cur_id"] = None # 如需播放完自动断开语音连接,可取消下方注释 # if ctx.voice_client: # await ctx.voice_client.disconnect()
可选优化
如果需要支持队列插入、删除等操作,建议将队列存储格式从字典改为列表,用下标对应歌曲序号,操作效率更高。
内容的提问来源于stack exchange,提问作者xBatmanx
相关产品推荐
相关产品推荐

