Discord音乐机器人无法完整播放歌曲,请求排查代码问题
问题排查与修复方案
已确认的问题点
- FFmpeg重连配置未生效:代码中已经定义了带断流重连的
ffmpeg_options参数,但初始化FFmpegPCMAudio实例时没有传入该参数,YouTube音频流存在访问时效,中途断流后没有重连逻辑就会直接停止播放 - 代码缩进错误:
if not voice_client.is_playing()所在的代码块缩进错误,不属于play函数的作用域,实际运行时逻辑执行异常 - 异步方法调用错误:
ctx.channel.send("I'm here!")是异步方法,没有添加await关键字会抛出未捕获的异步异常,可能导致进程中断、播放停止 - 音频流地址获取方式错误:直接取
info["formats"][0]["url"]无法保证拿到稳定可用的最高音质音频流,容易拿到无效或者延迟很高的流地址 - 依赖库过时:
youtube_dl已经停止维护多年,对新版YouTube的流解析适配很差,是流不稳定的核心诱因之一
修复后的完整代码
import discord from discord.ext import commands from discord.utils import get # 建议将youtube_dl替换为yt-dlp,使用前执行pip install yt-dlp from yt_dlp import YoutubeDL bot = commands.Bot(command_prefix = ">", intents=discord.Intents.all()) @bot.event async def on_ready(): print("I'm ready for command") @bot.command() async def Help(ctx): emBed = discord.Embed(title = "How to use XXX Bot.", description = "This is every command you can use.", color = 0x03d7fc) emBed.add_field(name = ">Help" , value ="To see every command", inline = False) emBed.add_field(name = ">play" , value ="Play music", inline = False) emBed.add_field(name = ">pause" , value ="Pause music ", inline = False) emBed.add_field(name = ">skip" , value ="Stop music", inline = False) await ctx.channel.send(embed = emBed) # 播放错误回调 async def play_error(error, ctx): if error: await ctx.send(f"播放出错:{str(error)}") @bot.command() async def play(ctx, url): channel = ctx.author.voice.channel voice_client = get(bot.voice_clients, guild = ctx.guild) if voice_client == None: await ctx.channel.send("I'm here!") await channel.connect() voice_client = get(bot.voice_clients, guild = ctx.guild) YDL_OPTIONS = {"format" : "bestaudio" , "noplaylist" : True, "quiet": True} ffmpeg_options = {"options": "-vn", "before_options": "-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5" } if not voice_client.is_playing(): with YoutubeDL(YDL_OPTIONS) as ydl: info = ydl.extract_info(url, download = False) # 直接取解析后的最优流地址 stream_url = info["url"] # 传入ffmpeg配置,添加错误回调 voice_client.play(discord.FFmpegPCMAudio(stream_url, **ffmpeg_options), after=lambda e: bot.loop.create_task(play_error(e, ctx))) else: await ctx.channel.send("I'm playing right now") return bot.run("你的机器人TOKEN")
注意事项
- 运行前需确认已经安装了FFmpeg并配置到系统环境变量中
- 旧版discord.py需要开启意图权限,在Discord开发者后台的机器人设置页打开所有Privileged Gateway Intents开关
- 如果仍然使用原
youtube_dl,只需将导入语句改回即可,但还是建议尽快替换为yt-dlp保证解析稳定性
内容的提问来源于stack exchange,提问作者Yuuuuuuu
相关产品推荐
相关产品推荐

