Discord.py开发:将已删除分类下的频道迁移至新克隆分类问题求助
问题根源
当on_guild_channel_delete事件触发时,你拿到的channel对象对应的分类已经被Discord正式删除,服务器内原属于该分类的频道要么被同步删除,要么已经被移出该分类、解除了和原分类的关联,所以此时调用channel.channels必然返回空列表,这个是Discord API的限制,并非代码逻辑错误。
可行解决方法
你需要提前缓存服务器内每个分类对应的下属频道ID列表,缓存可以用字典结构实时维护,具体实现步骤如下:
- 机器人启动时,遍历所有服务器的所有频道,初始化缓存:以分类ID为键,对应下属频道ID列表为值
- 监听
on_guild_channel_create、on_guild_channel_update事件,每当频道的所属分类变动时更新缓存 - 监听
on_guild_channel_delete事件时,如果删除的是分类,直接从缓存里拿对应下属频道ID列表,再去服务器里找对应的频道对象,修改所属分类到新克隆的分类即可
示例代码
# 初始化缓存,结构为 {分类ID: [子频道ID1, 子频道ID2, ...]} category_channel_cache = {} # 机器人启动时初始化缓存 @bot.event async def on_ready(): for guild in bot.guilds: for category in guild.categories: category_channel_cache[category.id] = [c.id for c in category.channels] print("缓存初始化完成") # 频道更新时维护缓存 @bot.event async def on_guild_channel_update(before, after): # 处理所属分类变更的情况 if before.category != after.category: # 从旧分类缓存移除 if before.category: if before.category.id in category_channel_cache and before.id in category_channel_cache[before.category.id]: category_channel_cache[before.category.id].remove(before.id) # 加入新分类缓存 if after.category: if after.category.id not in category_channel_cache: category_channel_cache[after.category.id] = [] category_channel_cache[after.category.id].append(after.id) # 频道创建时维护缓存 @bot.event async def on_guild_channel_create(channel): if channel.category: if channel.category.id not in category_channel_cache: category_channel_cache[channel.category.id] = [] category_channel_cache[channel.category.id].append(channel.id) # 修改原有事件逻辑 @commands.Cog.listener() async def on_guild_channel_delete(self, channel): # 只处理删除的是分类的情况 if not isinstance(channel, discord.CategoryChannel): return try: logs = await channel.guild.audit_logs(limit=1, action=discord.AuditLogAction.channel_delete).flatten() logs = logs[0] if logs.user != channel.guild.owner and logs.user.id != 891409650287796295: new_category = await channel.clone(reason="Anti Nuke Protection") # 从缓存拿子频道ID列表 if channel.id in category_channel_cache: for channel_id in category_channel_cache[channel.id]: child_channel = channel.guild.get_channel(channel_id) if child_channel: try: await child_channel.edit(category=new_category) except Exception as e: print(f"移动频道失败: {e}") # 清理已删除分类的缓存 del category_channel_cache[channel.id] except Exception as e: print(f"事件处理出错: {e}")
注:如果用户删除分类时选择了「同时删除所有子频道」,则缓存中拿到的频道ID对应对象已不存在,属于正常业务场景无需额外处理。
内容的提问来源于stack exchange,提问作者a e
相关产品推荐
相关产品推荐

