- 即时通讯
- 后端
- AI 应用
【免费下载链接】wechatferry
-
本文围绕 wechatferry 项目中的群聊禁言插件wechatyPluginRoomMute展开:微信本身不支持按人禁言群友,该插件通过自建禁言状态记录,结合MUTE/UNMUTE管理命令,在禁言者发言时将其移出群聊。读完本篇,你将掌握该插件的安装配置、命令用法、状态存储机制,并能从 插件源码 层面理解其完整的消息处理链路。
为什么需要"群聊禁言"插件
微信的群管理能力中并不支持针对某个群友单独禁言(原始文档 的开宗明义)。wechatyPluginRoomMute的思路是:插件自己维护一份禁言状态,记录每个被禁言成员的解封时间戳;当该成员在禁言期内再次发言时,机器人先发送警告消息,再调用群踢人接口将其移出群聊。
该插件由@wechatferry/plugins包提供(当前包版本为0.0.26,见 包清单),在 插件入口 中统一导出,属于 wechatferry 自 v0.0.9 起逐步提供的基于 Wechaty Plugins 机制的插件族之一。
适用前提:wechatferry 依赖 Windows 64 位系统与特定版本微信(当前要求 3.9.12.17,见 指南),本插件运行在其 Wechaty Puppet 集成之上。
安装
安装方式与 插件总览文档 一致:
# pnpm pnpm add -D @wechatferry/plugins # yarn yarn add -D @wechatferry/plugins # npm npm install -D @wechatferry/plugins在 wechatferry 场景下,机器人需使用WechatferryPuppet构建(参考 Wechaty 集成文档),插件通过bot.use()挂到 bot 实例上。
配置插件并启动
原始文档 给出的最小示例如下:
import { WechatyBuilder } from 'wechaty' import { wechatyPluginRoomMute } from '@wechatferry/plugins' const bot = WechatyBuilder.build() bot .use(wechatyPluginRoomMute({ admin: [], room: [], })) bot.start()完整的配置项定义在 源码的 RoomMuteOptions 接口中:
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
room | matchers.RoomMatcherOptions | 是 | 启用的群聊范围,只有命中的群才会执行禁言逻辑 |
admin | matchers.ContactMatcherOptions | 是 | 管理员列表,只有管理员能发出MUTE/UNMUTE命令;注释明确"管理员不能互相禁言" |
driver | unstorage 的Driver(如 redis、fs) | 否 | 可选。传入后机器人重启也能保留禁言记录 |
room与admin都交给wechaty-plugin-contrib的matchers做匹配(源码第 26-27 行 分别用roomMatcher和contactMatcher包装配置)。实际使用时应把room/admin填为具体的群 wxid、用户 wxid 数组或正则匹配器,例如:
bot.use(wechatyPluginRoomMute({ room: ['12345678@chatroom'], // 指定生效的群 admin: ['admin-wxid-1', /管理员\d+/], // 指定管理员 }))MUTE / UNMUTE 命令与实际效果
命令由管理员在群内 @ 目标用户后跟关键字触发。命令的正则定义在 源码第 12 行:
const BLOCK_COMMAND_REGEX = /(MUTE|UNMUTE)\s?(\d+)?/g由此得到命令格式:
@User MUTE:禁言,时长缺省为5 分钟(源码第 54-55 行 注释"默认封 5 分钟");@User MUTE 30:禁言 30 分钟,数值单位为分钟;@User UNMUTE:立即解除禁言。
原始文档 记录的实际使用效果如下:
RoomName Admin: MUTE @User Bot: @User 已被禁言 5 分钟,将于 12:35:25 后解封,期间发言将被移出群聊。 User: 🤡 Bot: @User 你在被禁言期间发言。现将你移出群聊✈️\n欢迎冷静后再次进群。\n请大家理性交流,谢谢!这三段文案并非硬编码拼串,而是 源码第 28-30 行 用wechaty-plugin-contrib的talkers.roomTalker()构建的群聊消息模板,其中禁言提醒支持{{ muteDuration }}与{{ unmuteTime }}两个占位变量,解封时间由dayjs(unmuteTime).format('HH:mm:ss')格式化得出。
源码级工作原理
消息过滤链路
插件注册在 bot 的message事件上(源码第 32-41 行),每条消息依次经过以下过滤:
message.self()为真则直接返回——机器人自己的消息不触发任何逻辑;message.room()为空则返回——私聊消息被忽略,插件只作用于群聊;isManagedRoom(room)不命中则返回——非配置群不处理。
通过过滤后,按发送者身份分两条分支处理。
分支一:管理员发出命令
管理员分支(源码第 44-72 行)要求较严格:
- 消息类型必须是文本(
types.Message.Text),图片、文件等一律忽略; message.mentionList()必须非空——即必须 @ 到具体成员,否则不执行;- 对
message.mentionText()(去掉 @ 前缀后的文本)执行BLOCK_COMMAND_REGEX.exec(),未匹配到MUTE或UNMUTE则忽略。
匹配成功后的处理:
const unmuteTime = Date.now() + Number(muteDuration) * 60 * 1000 if (command === 'UNMUTE') { await store.removeItem(mentionList[0].id) // 只解除第一个被 @ 的成员 await talkUnmuteWarn(room, mentionList, view) } else if (command === 'MUTE') { for (const member of mentionList) { // 对每个被 @ 的成员写入禁言记录 await store.setItem(member.id, { unmuteTime }) } await talkMuteWarn(room, mentionList, view) }从源码可以确认两个容易忽略的行为差异:MUTE支持一次禁言多个被 @ 的成员(遍历整个mentionList写入记录),而UNMUTE只解除第一个被 @ 的成员(仅取mentionList[0].id删除记录)。
分支二:被禁言成员发言
非管理员分支(源码第 74-86 行)是"禁言"真正生效的地方:
else if (await store.hasItem(talker.id)) { const { unmuteTime } = (await store.getItem(talker.id))! if (unmuteTime > Date.now()) { // 解封前发言:先警告,再移出群聊 await talkKick(room, talker) await bot.sleep(1000) await room.remove(talker) } else { // 已过期:清理记录,正常放行 await store.removeItem(talker.id) } }三个要点:
- 踢人动作是真实调用 Wechaty 的
room.remove()群移除接口,wechatferry 的 特性列表 中"群聊 - 踢人"正是该插件的底层能力来源;踢人前bot.sleep(1000)等待 1 秒,先让警告消息发出去; - 到期自动清理:成员在解封时间之后发言时,插件只是删除状态记录并放行,不产生任何群内消息——被禁言者无感知地"自动解封";
- 从分支结构看,禁言检查只位于非管理员的
else if中,管理员的发言永远不会触发踢出逻辑,即使其 id 恰好存在于状态记录里。
禁言状态存储
状态通过unstorage的createStorage管理(源码第 23-25 行),以成员 id 为 key、{ unmuteTime: 毫秒时间戳 }为 value:
const store = createStorage<{ unmuteTime: number }>({ driver: config.driver, })默认(不传driver)时 unstorage 使用内存存储,机器人重启后禁言记录会丢失;配置项注释(源码第 18-19 行)建议传入 redis 或 fs 驱动的Driver,例如unstorage提供的redisDriver/fsDriver,即可跨重启保持封禁状态。
与同类插件的对照
同一个@wechatferry/plugins包中还有一组群管理插件,理解它们有助于选型:
- 群聊踢人(
wechatyPluginRoomKick,源码):使用BAN/KICK命令立即踢人,并额外支持blackListMessage关键字匹配自动踢人。与 room-mute 的关键区别在于:room-kick 在踢人前显式跳过管理员(if (!await isAdmin(member))),是"即时惩罚";room-mute 则是"缓冲惩罚",给禁言者一个整改窗口,仅在其继续发言时才执行踢人; - 安全模式(
createSafeModePuppet):对 puppet 的messageSend方法做代理节流。room-mute 的警告消息与踢人动作都经由 puppet 发送,若群内操作频繁,可考虑用安全模式包裹 puppet 来控制发送频率。
实践要点小结
- 命令必须是文本消息 + @ 具体成员,且发送者在
admin匹配范围内、消息位于room匹配的群中,否则不会响应; MUTE的时长参数为可选整数,单位是分钟,缺省 5 分钟;UNMUTE只解除第一个被 @ 的成员,多目标解封需分开执行;- 需要跨重启保留禁言记录时,务必传入
driver(redis/fs); - 插件对消息的过滤链路(self 消息 → 私聊 → 非管理群 → 非文本 → 无 @)决定了它在群内"话不多",只在你期望的时机发声;
- 若 @ 文本中同时包含其他词(如
MUTE 10 something),正则只会校验首个匹配结果(exec单次匹配),后续内容不影响判定。
以上行为均可在 room-mute 插件源码 中逐行核对,配合 plugins 包说明 与 插件文档目录 可进一步扩展到其他群管理场景。
- 即时通讯
- 后端
- AI 应用
【免费下载链接】wechatferry
-
相关推荐
LLOneBot群管理功能全解析:禁言、踢人、改群名片等10大操作
LLOneBot群管理功能全解析:禁言、踢人、改群名片等10大操作 想要轻松管理QQ群聊?LLOneBot让你的NTQQ支持OneBot11协议,实现自动化群管
即时通讯后端Wechatferry room-kick 插件:微信机器人实现 BAN/KICK 命令式与关键字自动踢人
Wechatferry room kick 插件:微信机器人实现 BAN/KICK 命令式与关键字自动踢人 wechatferry 提供了 @wechatfer
即时通讯后端AI 应用SpacetimeDB 实时房间权限实战:踢人、禁言与管理员晋升的即时生效实现
SpacetimeDB 实时房间权限实战:踢人、禁言与管理员晋升的即时生效实现 实时权限(Real Time Permissions)是多人实时应用中最棘手的需
数据库关系型数据库后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考