如何修复Discord Bot的/playmusic斜杠命令,实现语音频道播放音频
解决方案
核心错误修复
报错的根本原因是你错误地从ctx.response(交互回复对象)中获取用户信息,正确的做法是从ctx.user(交互发起用户)中获取。除此之外还需要补充意图权限、错误处理和播放逻辑优化,以下是完整修复后的代码:
import os, discord from discord.ext import commands import ffmpeg import asyncio DISCORD_TOKEN = os.getenv("DISCORD_TOKEN") # 开启必要的意图,包括语音状态获取 intents = discord.Intents.default() intents.message_content = True intents.voice_states = True # 新增:获取用户语音状态所需 client = commands.Bot(command_prefix='/', intents=intents) @client.event async def on_ready(): await client.tree.sync() print(f'登录为 {client.user}') @client.event async def on_message(message): print(f"收到消息: {message.content}") if message.author == client.user: return lowered_msg = message.content.lower() if lowered_msg in ('i love baguettes!', 'i love baguettes'): role = message.guild.get_role(1085983212855115887) await message.author.add_roles(role, reason="触发魔法口令", atomic=True) await message.channel.send('我也是!已为你添加法棍小队角色!') @client.tree.command(name="kill", description="尝试关闭机器人") async def kill_bot(ctx: discord.Interaction): await ctx.response.send_message(content="你敢碰我试试!") @client.tree.command(name="give-lollipop", description="给机器人一根棒棒糖") async def give_lollipop(ctx: discord.Interaction): await ctx.response.send_message(content="谢谢你的棒棒糖!😋") @client.tree.command(name="playmusic", description="在你所在的语音频道播放音乐") async def play_music(ctx: discord.Interaction): # 1. 检查用户是否在语音频道 voice_state = ctx.user.voice if not voice_state or not voice_state.channel: await ctx.response.send_message("请先加入一个语音频道再使用此命令!") return voice_channel = voice_state.channel # 2. 处理机器人的语音连接状态 voice_client = ctx.guild.voice_client if voice_client: if voice_client.channel != voice_channel: await voice_client.move_to(voice_channel) await ctx.response.send_message(f"已切换到频道 {voice_channel.name},开始播放音乐!") else: await ctx.response.send_message(f"已在 {voice_channel.name},开始播放音乐!") else: voice_client = await voice_channel.connect() await ctx.response.send_message(f"已加入频道 {voice_channel.name},开始播放音乐!") # 3. 处理音频播放(若ffmpeg不在系统PATH,需指定executable路径,比如executable='C:/ffmpeg/bin/ffmpeg.exe') try: source = discord.PCMVolumeTransformer(discord.FFmpegPCMAudio('sample-15s.mp3')) # 播放结束后自动断开语音的回调函数 def after_play(error): if error: print(f"播放错误: {error}") # 异步执行断开操作 asyncio.run_coroutine_threadsafe(voice_client.disconnect(), client.loop) voice_client.play(source, after=after_play) except Exception as e: await ctx.followup.send(f"播放失败: {str(e)}") if voice_client.is_connected(): await voice_client.disconnect() def start(): client.run(DISCORD_TOKEN)
关键修改点说明
- 意图权限补充:添加
intents.voice_states = True,确保机器人能获取用户的语音频道信息,否则无法检测用户是否在语音频道。 - 用户信息获取修正:将
ctx.response.author改为ctx.user,ctx是交互上下文对象,直接通过它获取发起命令的用户。 - 语音连接逻辑优化:检查机器人是否已在语音频道,若在不同频道则移动过去,避免重复连接。
- 命令超时处理:斜杠命令要求3秒内回复,所以先发送提示消息,避免触发超时错误。
- 播放后自动断开:使用
after回调函数处理播放结束后的断开操作,避免阻塞命令执行线程。 - 错误处理:添加用户不在频道、播放失败等场景的错误提示,提升用户体验。
额外注意事项
- 确保
ffmpeg已安装且添加到系统环境变量PATH中,若未添加,需在FFmpegPCMAudio中指定executable参数(如Windows系统:executable='C:/ffmpeg/bin/ffmpeg.exe')。 - 音频文件
sample-15s.mp3需放在机器人代码的同一目录下,或指定完整文件路径。
内容的提问来源于stack exchange,提问作者Tyler
相关产品推荐
相关产品推荐

