Discord私人音乐机器人使用ytdl搜索歌曲时出现KeyError: 'formats'问题求助
问题修复方案
嗨,我来帮你搞定这两个问题,你的代码目前有两个核心问题导致了异常:
1. 多关键词搜索只识别第一个词
你的play命令参数定义是async def play(ctx, url):,Discord.py的命令参数默认是按空格分割的单个位置参数,所以当你输入-play Rick Astley - Never Gonna Give You Up时,url只会拿到第一个词"Rick",剩下的参数会直接被忽略。
修复方法:
把参数改成async def play(ctx, *, url):,这里的*表示将所有后续输入作为一个完整的字符串传递给url参数,这样就能正确接收完整的歌曲名称了。
2. 搜索歌曲时抛出KeyError: 'formats'
当你使用搜索关键词而非直接视频URL时,youtube-dl返回的info结构和解析单个URL不一样:搜索结果会被包装成一个播放列表,包含entries字段,真正的视频信息藏在这个列表里,而不是直接在顶层有formats字段。
修复方法:
在获取formats之前,先检查info中是否存在entries,如果存在就取第一个条目作为实际的视频信息;同时增加基础的存在性检查,避免因字段缺失崩溃:
with youtube_dl.YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(url, download=False) # 处理搜索结果的播放列表结构 if 'entries' in info: info = info['entries'][0] # 确保formats存在再访问 if 'formats' in info: url2 = info['formats'][0]['url'] source = await discord.FFmpegOpusAudio.from_probe(url2, **ffmpeg_opts) vc.play(source) else: await ctx.send("抱歉,找不到可播放的音频格式!")
另外,我还建议加上一些基础的错误处理,比如用户不在语音频道、搜索无结果的情况,避免机器人莫名崩溃。
完整修改后的代码
@client.command() async def play(ctx, *, url): # 检查用户是否在语音频道 if not ctx.author.voice: await ctx.send("你需要先加入一个语音频道才能播放音乐!") return channel = ctx.author.voice.channel voice = discord.utils.get(client.voice_clients, guild=ctx.guild) if voice and voice.is_connected(): # 如果已经连接,自动切换到用户所在频道(可选,可根据需求删除) await voice.move_to(channel) else: voice = await channel.connect() ffmpeg_opts = {'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', 'options': '-vn'} ydl_opts = {'format': "bestaudio/best", 'default_search': 'auto'} vc = ctx.voice_client try: with youtube_dl.YoutubeDL(ydl_opts) as ydl: info = ydl.extract_info(url, download=False) # 处理搜索结果的播放列表结构 if 'entries' in info: info = info['entries'][0] # 检查formats是否存在 if not 'formats' in info: await ctx.send("无法获取音频格式,请尝试其他关键词或URL!") return url2 = info['formats'][0]['url'] source = await discord.FFmpegOpusAudio.from_probe(url2, **ffmpeg_opts) vc.play(source) await ctx.send(f"正在播放:{info.get('title', '未知歌曲')}") except Exception as e: await ctx.send(f"播放出错了:{str(e)}") print(f"Error: {e}")
这个修改后的代码解决了你的两个核心问题,还增加了用户提示和错误捕获,让机器人更稳定友好。
内容的提问来源于stack exchange,提问作者Mondumkreisung
相关产品推荐
相关产品推荐

