如何在discord.py中实现YouTube搜索而非仅用URL播放?
Discord音乐机器人Play命令搜索功能修复
问题核心
你的Play命令支持YouTube URL但搜索功能失效,报错KeyError: 'formats',原因是ytsearch返回的数据结构和直接解析URL不同:搜索结果的视频详情嵌套在entries数组里,你直接从顶层data取formats字段自然找不到。
修复后的代码
@commands.command(pass_context=True) async def play(self, ctx, *, info): try: voice_channel = ctx.author.voice.channel channel = ctx.message.author.voice.channel VOICE_CHANNELS[channel.id] = ctx.channel except AttributeError: return await ctx.send("Dush! Please Join a Channel.") voice_client = ctx.guild.voice_client if not voice_client: await voice_channel.connect() voice_client = discord.utils.get(self.bot.voice_clients, guild=ctx.guild) loop = asyncio.get_event_loop() data = None try: # 先尝试解析为URL data = await loop.run_in_executor(None, lambda: ytdl.extract_info(info, download=False)) except KeyError: # URL解析失败,触发YouTube搜索 data = await loop.run_in_executor(None, lambda: ytdl.extract_info(f"ytsearch:{info}", download=False)) # 搜索结果取第一个视频 if "entries" in data and len(data["entries"]) > 0: data = data["entries"][0] except Exception as e: return await ctx.send(f"搜索出错:{str(e)}") # 处理播放列表(如果是URL传入的 playlist) if "entries" in data and len(data["entries"]) > 0: data = data["entries"][0] # 从正确的层级提取播放链接和标题 try: song = data["url"] if "url" in data else data["formats"][0]["url"] title = data["title"] except KeyError as e: return await ctx.send(f"无法提取视频信息:缺少{str(e)}字段") try: voice_client.play(discord.FFmpegPCMAudio(source=song, **ffmpeg_options, executable="ffmpeg")) except Exception as e: print(e) return await ctx.send(f"播放失败:{str(e)}") await ctx.send(f'**Now playing:** {title}')
关键修改说明
- 精准异常捕获:把原来的
except Exception改成except KeyError,只捕获URL解析时的字段缺失问题,避免误吞其他错误 - 搜索结果处理:搜索后先从
entries数组中取出第一个视频的详情数据,后续操作都基于这个子数据 - 统一字段提取逻辑:通过判断字段是否存在,兼容URL和搜索结果的不同数据结构,确保能正确拿到播放链接和标题
- 增加错误反馈:给用户返回明确的错误提示,方便调试和使用
内容的提问来源于stack exchange,提问作者iflookscouldkill
相关产品推荐
相关产品推荐

