Discord.py中member.move_to执行MoveVoice2时致用户断开连接问题
问题描述
- 开发的Discord机器人具备两项功能:
- 收到用户
gamerjy发送的MoveVoice1消息时,将所有成员移至通用语音频道 - 收到
MoveVoice2消息时,根据JSON文件中角色与语音频道的对应关系,将成员移至对应频道
- 收到用户
- 当前问题:
MoveVoice1功能正常,但执行MoveVoice2时,发送指令的gamerjy会从当前语音频道断开连接,机器人已拥有全部所需权限
相关代码
import discord import json import time intents = discord.Intents.default() intents.message_content = True intents.members = True client = discord.Client(intents=intents) guild_id = 1176809935091281991 gen_id = 1176809935552643085 @client.event async def on_ready(): print(f'We have logged in as {client.user}!') @client.event async def on_message(message): if message.author == client.user: return if message.content != "MoveVoice1" and message.content != "MoveVoice2": return # Get the guild object guild = client.get_guild(guild_id) # If Voice 1, Move everyone to General if message.content == "MoveVoice1": general_channel = guild.get_channel(gen_id) # Replace GENERAL_CHANNEL_ID with the ID of the General voice channel for member in guild.members: await member.move_to(general_channel) print(f"Moved {member.name} to General voice channel") #If Voice 2, move everyone assigned on their roles of team if message.content == "MoveVoice2": with open("RoleToChannel.json", "r") as f: role_to_channel = json.load(f) for role, channel in role_to_channel.items(): role_object = guild.get_role(int(role)) for role_member in role_object.members: print(f"Attempting to move {role_member} to {channel}") try: await role_member.move_to(guild.get_channel(channel)) print(f"Successfully moved {role_member} to {channel}") except Exception as e: print(f"Error moving {role_member}: {e}") client.run('STACKOVERFLOW_PLACEHOLDER') # Replace YOUR_BOT_TOKEN with your bot token
问题排查与修复方案
核心问题原因
- 频道ID类型不匹配:从JSON文件读取的频道ID是字符串类型,但
discord.Guild.get_channel()方法需要传入整数类型的ID。当传入字符串时,get_channel()会返回None,调用member.move_to(None)会直接将成员从当前语音频道断开,这就是你被踢出语音的核心原因。 - 未过滤非语音成员:遍历所有角色成员时,会对当前不在语音频道的成员执行
move_to操作,可能引发不必要的错误。 - 重复移动风险:如果某个成员拥有多个在JSON中配置的角色,会被多次执行移动操作,可能导致异常。
修复后的代码
import discord import json import time intents = discord.Intents.default() intents.message_content = True intents.members = True client = discord.Client(intents=intents) guild_id = 1176809935091281991 gen_id = 1176809935552643085 authorized_user = "gamerjy" # 指定授权执行指令的用户名 @client.event async def on_ready(): print(f'We have logged in as {client.user}!') @client.event async def on_message(message): if message.author == client.user: return # 仅允许指定用户执行指令 if message.author.name != authorized_user: return if message.content not in ["MoveVoice1", "MoveVoice2"]: return guild = client.get_guild(guild_id) if not guild: print("无法获取服务器对象") return if message.content == "MoveVoice1": general_channel = guild.get_channel(gen_id) if not general_channel: print("通用语音频道不存在") return for member in guild.members: # 仅移动当前在语音频道的成员 if member.voice and member.voice.channel: await member.move_to(general_channel) print(f"Moved {member.name} to General voice channel") if message.content == "MoveVoice2": try: with open("RoleToChannel.json", "r") as f: role_to_channel = json.load(f) except FileNotFoundError: print("RoleToChannel.json 文件不存在") return except json.JSONDecodeError: print("JSON 文件格式错误") return # 记录已处理的成员,避免重复移动 moved_members = set() for role_id_str, channel_id_str in role_to_channel.items(): try: role_id = int(role_id_str) channel_id = int(channel_id_str) except ValueError: print(f"角色ID {role_id_str} 或频道ID {channel_id_str} 不是有效整数") continue role_object = guild.get_role(role_id) target_channel = guild.get_channel(channel_id) if not role_object: print(f"角色ID {role_id} 不存在") continue if not target_channel: print(f"频道ID {channel_id} 不存在") continue for role_member in role_object.members: # 跳过已处理过的成员,以及不在语音频道的成员 if role_member.id in moved_members or not (role_member.voice and role_member.voice.channel): continue try: await role_member.move_to(target_channel) print(f"Successfully moved {role_member} to {target_channel.name}") moved_members.add(role_member.id) except Exception as e: print(f"Error moving {role_member}: {e}") client.run('STACKOVERFLOW_PLACEHOLDER')
额外优化说明
- 添加了授权用户校验,仅允许
gamerjy执行指令,避免其他用户误操作 - 增加了错误处理:检查服务器、频道、角色是否存在,处理JSON文件读取异常
- 新增重复移动过滤:用集合记录已处理的成员ID,避免同一成员被多次移动
- 仅对当前在语音频道的成员执行移动操作,减少无效操作
内容的提问来源于stack exchange,提问作者Gamercoder
相关产品推荐
相关产品推荐

