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

Rust serenity框架下如何从Discord语音频道获取成员列表?

从Discord语音频道获取成员列表的Rust(serenity框架)实现方案

背景说明

你此前使用Python的discord.py库实现了从Discord语音频道拉取成员的功能,原Python实现代码如下:

# Python
def getDiscordUsers():
    json = {name: [] for name in names}

    for i in range(0, 3):
        channel = bot.get_channel(channels[i])
        members = channel.members
        for member in members:
            # selfMuted = member.voice.self_mute
            if member.bot:
                continue
            if member.nick == None:
                json[names[i]].append(member.name)
            else:
                json[names[i]].append(member.nick)

    return json

现在需要在Rust的serenity框架中实现同等功能,以下是完整实现方案:


实现逻辑

和discord.py的逻辑对应,serenity中实现的核心步骤如下:

  • 接收上下文Context和指定的语音频道ID作为入参
  • 校验频道类型,确认传入ID对应频道是公会语音频道
  • 从频道所属公会中拉取所有语音状态,筛选出当前在目标语音频道的用户
  • 过滤机器人账号,优先返回用户公会昵称,无昵称则返回全局用户名

完整可运行代码

use serenity::model::prelude::*;
use serenity::prelude::*;
use std::error::Error;

// 核心方法:传入ctx和语音频道ID,返回该频道内非机器人用户的展示名列表(优先返回昵称)
pub async fn get_users_from_voice(ctx: &Context, channel_id: u64) -> Result<Vec<String>, Box<dyn Error>> {
    let channel = ctx.http.get_channel(channel_id).await?;
    
    // 校验频道类型是否为公会语音频道
    let guild_channel = match channel {
        Channel::Guild(chan) => chan,
        _ => return Err("指定ID不属于公会频道".into())
    };
    if guild_channel.kind != ChannelType::Voice {
        return Err("指定频道不是语音频道".into())
    }

    let guild_id = guild_channel.guild_id;
    // 从缓存拉取公会内所有用户的语音状态
    let voice_states = guild_id.voice_states(&ctx.cache).await?;
    
    let mut user_names = Vec::new();
    for state in voice_states {
        // 筛选当前在目标语音频道的用户
        if state.channel_id != Some(ChannelId::new(channel_id)) {
            continue;
        }
        // 获取成员完整信息
        let member = guild_id.member(&ctx.http, state.user_id).await?;
        // 过滤机器人账号
        if member.user.bot {
            continue;
        }
        // 优先取昵称,没有昵称则取用户名
        let display_name = member.nick.unwrap_or(member.user.name);
        user_names.push(display_name);
    }

    Ok(user_names)
}

// 调用示例
pub async fn call_me(ctx: &Context) -> Result<Vec<String>, Box<dyn Error>> {
    // 替换为你实际的语音频道ID
    let members = get_users_from_voice(ctx, 123456789012345).await?;
    // 遍历打印成员名示例
    for name in &members {
        println!("{}", name);
    }
    Ok(members)
}

// 序列化返回JSON示例
async fn some(ctx: &Context) -> Result<serde_json::Value, Box<dyn Error>> {
    let members = call_me(ctx).await?;
    Ok(serde_json::json!(members))
}

注意事项

  • 必须在Bot初始化时开启GUILD_VOICE_STATES和GUILD_MEMBERS网关意图,否则无法获取语音状态和成员信息,意图开启示例:
let intents = GatewayIntents::GUILDS 
    | GatewayIntents::GUILD_VOICE_STATES 
    | GatewayIntents::GUILD_MEMBERS;
let mut client = Client::builder("你的Bot Token", intents)
    .event_handler(Handler)
    .await
    .expect("客户端创建失败");
  • 生产环境建议替换所有直接unwrap()的逻辑为自定义错误处理,避免Bot意外崩溃
  • 如果需要实现原Python代码的多频道批量获取功能,只需要传入频道ID和对应名称的列表,循环调用get_users_from_voice拼接结果即可

内容的提问来源于stack exchange,提问作者alfex4936

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 21:39:01