You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Discord.py中member.move_to执行MoveVoice2时致用户断开连接问题

问题描述
  • 开发的Discord机器人具备两项功能:
    1. 收到用户gamerjy发送的MoveVoice1消息时,将所有成员移至通用语音频道
    2. 收到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
问题排查与修复方案

核心问题原因

  1. 频道ID类型不匹配:从JSON文件读取的频道ID是字符串类型,但discord.Guild.get_channel()方法需要传入整数类型的ID。当传入字符串时,get_channel()会返回None,调用member.move_to(None)会直接将成员从当前语音频道断开,这就是你被踢出语音的核心原因。
  2. 未过滤非语音成员:遍历所有角色成员时,会对当前不在语音频道的成员执行move_to操作,可能引发不必要的错误。
  3. 重复移动风险:如果某个成员拥有多个在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 05:02:53