如何用discord.py的on_voice_state_update事件仅响应用户加入语音频道
Discord.py on_voice_state_update 事件错误解决及自动欢迎功能实现
我来帮你搞定这个问题!你的代码里有几个关键问题导致了报错,咱们一步步拆解解决:
问题1:事件处理器的参数顺序错误
on_voice_state_update 事件的正确参数顺序是 member, before, after,而你写的是 before, after。这会导致你拿到的第一个参数其实是用户对象,而不是之前的语音状态,完全打乱了后续的逻辑判断。
问题2:client.say() 不能在事件处理器里直接用
client.say() 是为命令上下文设计的(比如在 @client.command() 装饰的函数里),它需要依赖命令调用时的上下文来确定发送消息的目标频道。在事件处理器里没有这个上下文,所以直接调用会导致目标频道为 None,也就是你看到的 InvalidArgument: Destination must be Channel... Received NoneType 错误。
问题3:没有过滤「用户加入语音频道」的场景
你的当前代码会在所有语音状态变化时触发(比如用户静音、切换频道、离开频道),这不符合你只在用户加入机器人所在语音频道时发送消息的需求。
正确的实现代码
下面是修正后的完整代码,我会标注每一部分的作用:
from discord.ext.commands import Bot client = Bot(command_prefix="!") @client.event async def on_ready(): print(f"Logged in as {client.user.name}") # 确认机器人成功上线 @client.event async def on_voice_state_update(member, before, after): # 跳过机器人自己的状态变化,避免循环触发消息 if member == client.user: return # 判断用户是否从「不在任何语音频道」变为「加入了某个语音频道」 if before.channel is None and after.channel is not None: # 检查用户加入的频道是否是机器人当前所在的语音频道 bot_voice_channel = client.voice_client.channel if client.voice_client else None if after.channel == bot_voice_channel: # 选择发送消息的目标频道:这里用服务器的默认文本频道,你也可以指定具体频道ID target_channel = member.guild.system_channel if target_channel: await target_channel.send(f"欢迎 {member.mention} 加入语音频道!") client.run("你的机器人Token")
代码细节解释
- 参数修正:把事件参数改成
member, before, after,这样能正确获取到状态变化的用户、变化前的语音状态和变化后的语音状态。 - 跳过机器人自身:避免机器人自己加入频道时触发消息,造成不必要的循环。
- 判断加入动作:通过
before.channel is None and after.channel is not None确认用户是刚加入语音频道,而不是切换频道或调整静音状态。 - 匹配机器人所在频道:通过
client.voice_client获取机器人当前的语音连接,判断用户加入的频道是否和机器人一致。 - 指定消息目标:用服务器的默认文本频道(
member.guild.system_channel)发送欢迎消息,你也可以替换成特定频道的ID,比如:target_channel = client.get_channel(1234567890)(把数字换成你的目标频道ID)。
额外提示
- 确保机器人有发送消息到目标频道的权限,不然会出现权限相关的报错。
- 如果机器人可能同时加入多个语音频道,你可能需要调整逻辑来匹配对应的频道,但大部分单频道场景下上面的代码足够用。
内容的提问来源于stack exchange,提问作者Sbrunner32
相关产品推荐
相关产品推荐

