Discord.py机器人已加入语音频道,调用play时触发未连接错误
问题解决方案
一、解决ClientException: Not connected to voice错误
这个问题核心是你调用的是语音频道对象的play方法,而非实际的语音连接客户端(VoiceClient)的方法,且未正确保存/获取连接实例:
- 确保
join命令中保存VoiceClient实例
调用channel.connect()会返回一个VoiceClient对象,这才是真正管理语音连接的实例,需要将其存储或通过bot.voice_clients列表获取。 play命令必须调用VoiceClient的play方法
不能直接用VoiceChannel对象调用play,要先获取对应服务器的活跃VoiceClient,再调用其方法。- 调用前检查连接状态
在执行播放前,先验证VoiceClient是否存在且处于连接状态。
二、解决脚本终止后机器人残留、重启join无法识别连接的问题
脚本意外终止会导致Discord服务器认为机器人仍在频道(僵尸连接),重启后的bot无法关联这个无效连接,需要主动清理:
join命令先检查已有连接
每次执行join时,先查找当前服务器是否存在活跃的VoiceClient,存在则复用或先断开再重连。- 脚本退出时主动断开所有连接
通过信号处理函数,在脚本收到终止信号时,遍历所有连接并断开,避免残留。
完整修正代码示例
from discord.ext import commands from discord import FFmpegPCMAudio from discord.utils import get import signal import asyncio bot = commands.Bot(command_prefix="!") @bot.command() async def join(ctx): # 检查用户是否在语音频道 if not ctx.author.voice: await ctx.send("你先加入一个语音频道再喊我!") return # 查找当前服务器的已有语音连接 existing_vc = get(bot.voice_clients, guild=ctx.guild) if existing_vc: if existing_vc.is_connected(): await ctx.send("我已经在语音频道里了!") return else: # 清理无效连接 await existing_vc.disconnect() # 连接到用户所在频道并保存实例 target_channel = ctx.author.voice.channel vc = await target_channel.connect() await ctx.send(f"已加入频道:{target_channel.name}") @bot.command() async def play(ctx, audio_path: str): # 获取当前服务器的活跃语音连接 vc = get(bot.voice_clients, guild=ctx.guild) if not vc or not vc.is_connected(): await ctx.send("先输入!join让我加入语音频道啊!") return # 加载音频源(示例用本地文件,可替换为FFmpeg拉取网络资源) audio_source = FFmpegPCMAudio(audio_path) # 调用VoiceClient的play方法 vc.play(audio_source) await ctx.send("开始播放音频!") # 处理脚本终止信号,主动断开所有语音连接 def handle_shutdown(signal_num, frame): asyncio.create_task(cleanup_connections()) async def cleanup_connections(): for vc in bot.voice_clients: await vc.disconnect() await bot.close() signal.signal(signal.SIGINT, handle_shutdown) bot.run("你的机器人TOKEN")
关键说明
- 始终通过
bot.voice_clients列表获取对应服务器的VoiceClient,而非直接操作频道对象。 - 脚本退出时的信号处理能避免机器人留在频道形成僵尸连接。
join命令的前置检查能处理重启后残留的无效连接问题。
内容的提问来源于stack exchange,提问作者AudibleDruid
相关产品推荐
相关产品推荐

