如何使用Node.js获取Discord已有频道权限并创建同权限频道
discord.js v13 动态语音频道同权限克隆实现
核心实现逻辑
要复刻频道完整权限,不需要手动计算每一项权限位,直接读取目标频道的权限覆盖缓存即可:
- 语音频道实例下的
permissionOverwrites.cache存储了该频道所有角色、成员的单独权限配置(允许/拒绝的权限位) - 创建新频道时直接传入该权限配置数组,同时同步原频道的所属分类、比特率、用户上限等属性,即可生成权限完全一致的新频道
- 注意修复原代码中
querychannelcount函数缺失闭合大括号的语法错误
补全后可运行代码
// 请根据自身项目逻辑引入mysql、logger、数据库连接实例con等依赖 const { VoiceChannel } = require('discord.js'); module.exports = { name: "voiceStateUpdate", async execute(oldState, newState) { try { const newStateChannelId = newState.channelId; const oldStateChannelId = oldState.channelId; // 用户加入语音频道分支 if (oldStateChannelId === null && newStateChannelId !== null) { const joinChannel = newState.channel; const emptyChannelCount = joinChannel.parent.children.cache .filter(c => c.type === 'GUILD_VOICE' && c.members.size === 0 && isDynamicChannel(c.id)).size; // 空频道不足1个时触发扩容创建 if (emptyChannelCount < 1) await channelCreate(joinChannel); console.log("join " + toString(await querychannelcount(newStateChannelId))); } // 用户离开语音频道分支 else if (oldStateChannelId !== null && newStateChannelId === null) { const leaveChannel = oldState.channel; // 清理多余空频道,始终仅保留1个空频道 const emptyChannels = leaveChannel.parent.children.cache .filter(c => c.type === 'GUILD_VOICE' && c.members.size === 0 && isDynamicChannel(c.id)); if (emptyChannels.size > 1) { emptyChannels.slice(1).forEach(c => c.delete('清理多余空动态频道')); } console.log("leave " + toString(await querychannelcount(oldStateChannelId))); } // 用户切换语音频道分支 else if (oldStateChannelId !== null && newStateChannelId !== null && oldStateChannelId !== newStateChannelId) { const newJoinChannel = newState.channel; const emptyChannelCount = newJoinChannel.parent.children.cache .filter(c => c.type === 'GUILD_VOICE' && c.members.size === 0 && isDynamicChannel(c.id)).size; if (emptyChannelCount < 1) await channelCreate(newJoinChannel); // 处理旧频道侧的空频道清理 const oldLeaveChannel = oldState.channel; const oldEmptyChannels = oldLeaveChannel.parent.children.cache .filter(c => c.type === 'GUILD_VOICE' && c.members.size === 0 && isDynamicChannel(c.id)); if (oldEmptyChannels.size > 1) oldEmptyChannels.slice(1).forEach(c => c.delete('清理多余空动态频道')); channelCreate(newState); console.log("change " + toString(await querychannelcount(newStateChannelId))); } // 麦克风静音/闭麦/开直播等状态变更不做处理 else if (oldStateChannelId === newStateChannelId) { return; } else { logger.warn("voiceStateUpdate 触发未覆盖的异常分支"); } } catch (error) { logger.warn("voiceStateUpdate 事件执行出错"); console.log(error); } }, }; // 频道类型校验:判断频道是否属于配置的动态频道组,可结合自身数据库逻辑修改 function isDynamicChannel(channelId) { return true; } function querychannelcount(channelId) { try { var sql = "SELECT COUNT(id)*10 FROM channels Where id = ?"; var Inserts = [channelId]; sql = mysql.format(sql, Inserts); return new Promise((resolve, reject) => { con.query(sql, (err, result) => { return err ? reject(err) : resolve(result); }); }); } catch (error) { logger.error(`Error performing "SELECT" in database ${cascadingChannels_DB_database} in event voiceStateUpdate.`); } } // 原代码缺失该闭合大括号,已补全 function toString(object) { let result = JSON.stringify(object).length - 20; return result; } async function channelCreate(templateChannel) { try { if (!(templateChannel instanceof VoiceChannel)) return; // 拉取模板频道全量权限配置 const permissionOverwrites = templateChannel.permissionOverwrites.cache.map(overwrite => { return { id: overwrite.id, type: overwrite.type, allow: overwrite.allow.bitfield, deny: overwrite.deny.bitfield } }); // 新频道命名规则可自行修改 const newChannelName = `${templateChannel.name} 动态房`; // 创建与模板频道配置完全一致的新语音频道 const newChannel = await templateChannel.guild.channels.create(newChannelName, { type: 'GUILD_VOICE', parent: templateChannel.parentId, bitrate: templateChannel.bitrate, userLimit: templateChannel.userLimit, position: templateChannel.position + 1, permissionOverwrites: permissionOverwrites, reason: '动态扩容创建新语音频道' }); // 此处可添加数据库写入逻辑,将新频道ID存入动态频道表 return newChannel; } catch (error) { console.log('创建动态频道出错:', error); } }
注意事项
- 代码中
isDynamicChannel函数需要结合自身业务逻辑修改,避免在非动态频道下误触发克隆逻辑 - 直接读取
allow.bitfield和deny.bitfield是discord.js v13版本的正确权限传参方式,不需要手动做权限位转换 - 空频道清理逻辑已经内置到加入、离开、切换频道的分支中,可保证同分类下动态频道组始终仅保留1个空频道
内容的提问来源于stack exchange,提问作者xCesir
相关产品推荐
相关产品推荐

