| 项目 | 信息 |
|---|---|
| 原作者 | CMLiussss |
| 原项目 | CF-Workers-TGUnbanBot |
| 二改作者 | 匿名 |
本项目所有核心思想、架构设计与初始实现,100% 归功于原作者 CMLiussss。
没有原作者无私的开源分享,就没有本项目存在的可能。本项目仅是站在原作者打下的坚实基础之上,做了一些小幅度的功能扩展与代码加固,绝不敢居功。原作者的设计思路与代码质量是本项目的根基。
特别鸣谢原作者 CMLiussss 设计的源代码支持 🌟
本项目沿用原项目 MIT License,原作者的版权声明完整保留在 LICENSE 文件中。如果你认可这套自助解封机器人,请优先访问并 Star 原项目:github.com/cmliu/CF-Workers-TGUnbanBot 🌟
基于 Cloudflare Workers 的 Telegram 群组自助解封机器人。机器人通过 Telegram Webhook 接收消息,帮助被封禁或被禁言的用户在私聊中完成自助解封流程,同时提供管理员黑名单、封禁记录查询、按钮一键代发、新机器人风控等能力。
相对原项目(CMLiussss/CF-Workers-TGUnbanBot),本项目主要变更:
- 解封确认严格整句匹配:用户必须复制粘贴完整提示语才能触发解封,禁止夹带任何额外字符(防广告号绕过)。
- 多群组支持:
GROUP_ID环境变量支持逗号分隔多个群组,自助解封流程会遍历每个配置群分别处理;管理员鉴权采取「任一群管理员即可」的策略。 - 黑名单结构升级(向后兼容):从
["123","456"]裸数组升级为[{id, reason, by, at}]对象数组,记录封禁原因、操作人、时间。旧裸数组数据自动归一化升级,零迁移。 - D1 数据库(唯一存储后端):完全基于 Cloudflare D1 数据库,免费层每天 10 万次写入不会溢出。黑名单、广告词库、学习样本、消息缓存、批量任务全部存 D1。
/blacklist命令:管理员私聊查看当前黑名单(最多 30 条)。/ban/spam/unban支持批量:分隔符兼容半角逗号 / 全角逗号 / 空格 / 换行,也支持[123,456,789]数组外壳。/ban/spam小操作量即时执行;当 TGID 达到 20 个,或TGID 数量 × 配置群数量超过安全操作预算时,自动进入 D1 批量任务模式并按安全分片执行;/unban保持单次最多 50 个。单条用法完全保持原样。- 黑名单导出接口:
GET /{TOKEN}/export浏览器直接看 HTML 表格(带搜索过滤),?format=json/?format=csv下载完整数据,CSV 自带 BOM 让 Excel 不乱码。 - 全局黑名单真踢人闭环:
/ban/spam加黑后会立即遍历所有 GROUP_IDS 把人踢出群(之前只写库不踢人);/spam还会删除被回复的垃圾消息;黑名单用户在群里发言会被实时拦截删消息+踢人;被人拉回群也会立即被踢回去;新增/{TOKEN}/purge//{TOKEN}/purge/run默认分批清扫/ban+/spam存量数据。 /ban/unban/spam群内可用 + 闪屏 + 私聊详情:原项目/ban/unban强制只能私聊,本项目允许群内直接发命令;/spam也升级为同款双通道。群内执行时机器人发短闪屏提示(5 秒自动撤回)+ 按OWNER_IDS规则私聊完整详情,既快又不污染群消息流;授权管理员在群内发送/ban/spam后,机器人会自动撤回该命令消息本身。详情含命令来源 / 作用范围 / 执行原因 / 群名 / 群 ID / 失败原因 / 解决建议(Telegram 英文错误自动翻译为中文)。- 主人/副主人通知系统(可选
OWNER_IDS启用):OWNER_IDS第一个 TGID 是主人,后续 TGID 是副主人。主人收到全部通知;副主人只收到/ban、/spam这类加黑踢出通知。OWNER_IDS 留空 → 全局禁用通知,保持原行为。 - 广告自动检测(可选
AD_FILTER_ENABLED启用):普通成员发的疑似广告 → 自动删消息 + 加黑 + 全群踢出 + 通知主人,零人工。采用多维度加权评分 + 强特征直杀双机制:强特征(发言人名字命中词库/学习样本精确匹配/名片显示名命中词库)单独命中即处置;金融/色情/诈骗分类词库加权评分,达阈值才判定(降低误杀)。检测覆盖消息文本/图片说明/用户名字/内嵌链接/联系人名片。不检测 emoji(避免误杀正常用户发的表情包)。管理员豁免,默认关闭。 - 名片广告检测(本版重点):广告号常用分享联系人名片的形式发广告(名片显示名写"假钞交流群"),名片本身无
text/caption,旧版完全漏检(只删消息不加黑不踢)。本版把名片内容(显示名/电话号/vcard)纳入检测:名片显示名命中词库 → 直接秒杀(强特征,不用凑分。正常人名片名字是"张三/小明",几乎不可能含"假钞/承兑/约炮",误杀面极低);正常分享联系人名片不误杀(名字无敏感词,只 +1 分不达阈值)。名片广告也会被缓存供/recent//learnlast学习。- 关于"头像/图片里的广告文字":经评估暂不实现。原因:(a) Telegram 名片(contact)字段里根本没有头像,截图里的"一手假钞"红色图标是 vCard 内嵌 logo 或预览占位图,Bot API 拿不到原图;(b) 识别图片里的字需要 OCR,而 Cloudflare Worker 环境没有 OCR 能力、CPU 时间也不够,必须接外部 OCR API(额外开通、付费、每张图增加几百毫秒延迟)。若将来确有需要,可接 Cloudflare Workers AI 的图像模型对"用户直接发的图片消息"做 OCR——这是独立增量功能,需单独开通评估。当前策略:把基于文字的名字/词库检测做到极致,覆盖绝大多数名片广告。
- 发言人名字检测(抓"名字本身是广告"的号):有些广告号消息正文是正常内容(甚至蹭"chatgpt plus"这类正经词),但名字本身就是广告(如名字写
出租淫妻性奴、博彩网赌)。本版只检测发言人的身份字段(名字/用户名),且只匹配明确的广告词,不碰消息正文:名字/用户名含身份广告词(色情/赌博露骨词)→ 直接秒杀,零 API 成本每条都查。身份广告词可/addword identity <词>热更新,或/importdefault一键导入。代码无硬编码词库(GitHub 零敏感词),所有词完全由 D1 管理。⚠️ 绝不把"链接/@提及/域名"当广告(防误杀的核心):正常用户名字里放双向机器人@xxxBot、github 链接、个人频道t.me/xxx都极其普遍。本版只看露骨广告词判定,光有链接/@/域名一律放行——技术讨论群、双向 bot 用户完全安全。- 重要区分:
chatgpt/plus/codex等是正经 AI 名字,绝不会被加进广告词;身份检测抓的是"名字写出租淫妻/博彩网赌"这种正常用户绝不会有的露骨词。
- 链接智能识别(防链接误判):区分正常链接与广告链接,正常链接绝不误杀。两层防护:① 正常域名白名单——内置 github/google/youtube/gitlab/stackoverflow/bilibili 等几十个常见正常站点,命中的链接不计分、不参与样本匹配;主人可用
/addword whitelist example.com热更新加自己的域名(改完即时生效,不用重部署)。② 含 URL 的样本只精确匹配——学过某条广告链接后,只有一字不差的同一条链接才会被杀,绝不因同域名前缀连带误杀(如学过spam.xyz/abc后,spam.xyz/abc/x不会被误判)。 - 广告词库存 D1 + 主人热更新:为隐私起见,代码内置词库默认全部清空(GitHub 公开仓库零敏感词),词库存在 D1 里。主人用 Telegram 命令热更新,改词不用重新部署:
/importdefault一键导入推荐词库、/addword加词、/delword删词、/listwords查看。仅 OWNER_IDS 中的主人/副主人可改(词库是全局配置,误加影响所有群)。 /spam上报学习 → 精准查杀(参考 GKY 神膠bot 的穿透上报系统):主人回复一条漏检广告发/spam,系统在加黑+踢+删之外,还会把广告整句指纹学习入库(归一化后,以后相同广告精确秒杀,抗加空格/标点/全半角变体)。普通管理员/spam只加黑踢不学习。主人用/listsamples/delsample/clearsamples管理样本库(无人为上限)。学习只写整句指纹,不再自动往词库加词(根因修复,见下);自动提取的特征词仅作为"建议"显示在回执里,由主人手动决定是否/addword。/learn/recent/learnlast应对"已删消息"(两步私聊复核):GKY 等机器人会删广告,导致无法/spam回复。三个命令配合:①/learn <粘贴广告文本>主人直接粘贴文字学习指纹,不依赖回复 ② bot 自动缓存最近"疑似广告"群消息(含链接/@提及/长数字/长文本) ③ 群里发/recent把缓存冻结成带序号的快照推送到主人私聊,主人核对后私聊发/learnlast 序号学习。/learnlast强制私聊、只从冻结快照读(序号永不漂移)、只学指纹入库不踢人——要踢发广告的人,用回执给出的 TGID 手动/ban。缓存只存真正疑似广告(含链接/@/长数字/名片),用ctx.waitUntil异步不阻塞。- 学习模块根因加固(防误踢正常人):① 只做精确匹配——归一化后完全相等(≥6字)才秒杀,不做子串包含,学了短广告也绝不会炸到"碰巧含这几个字"的正常长消息。② 停止词库污染——旧版把广告里自动提取的词(含正常词)写进词库 +2 分,导致正常消息分数虚高被误判;现在学习只写整句指纹,提取词改为仅建议。③ 学习强制私聊二次确认——群内禁止
/learnlast,杜绝手忙脚乱点错序号误伤。④ 学习一律不踢人,加黑踢人改为主人手动/ban,彻底解耦。⑤ 指纹口径统一——/spam/learn/learnlast与检测比对都只用正文(不含发送者用户名),保证同一条广告不同人发也能精确命中。 /helpOWNER_IDS 专属帮助(隐藏指令展开):OWNER_IDS 中的主人/副主人私聊发/help可展开查看全部隐藏指令清单。主人可私聊发/admins查看当前主人/副主人/超级管理员权限名单。所有 OWNER_IDS 专属命令(词库/样本/学习/权限名单)对普通用户、群管理员、超级管理员完全无反应(群内静默、私聊提示权限不足且不泄漏指令内容)。这些命令本就不注册到 BotFather 命令菜单,天然隐藏。- 一键代发后回查解封结果(本版重点):旧版超管/主人点「✅ 同意(一键代发)」按钮后,只弹个转瞬即逝的气泡"已代发",看不到 GKY 那边到底加白/移黑成功没有。本版代发
GKYbotSave后,会自动回查该 TGID 的最新封禁状态并把结果发到操作人私聊(+主人审计):① 先发"⏳ 已代发,正在确认结果…";② 立即回查 → 已无封禁记录 则回"✅ 解封成功,已移出黑名单/加白",仍有记录(GKY 还没处理完)则回"⚠️ 请稍后用/check 用户ID复查"作兜底。再也不用猜解封到底成没成。 - 代发有效性双重预警(防"假成功"):GKY 的解封是按原封禁群定位的,发到错误的群会"显示已代发、实际没生效"。本版加两道预警:① GKYbot 在场检测——代发前查目标群管理员里有没有 GKYbot(username 含 GKY,覆盖
GKYxxxxBot双bot变体),没有就警告"目标群未发现 GKYbot,指令可能无人处理";② 原群封禁检测——若该用户的封禁记录属于非配置群(原始封禁群),在二次审核消息和回查里都明确提示"此封禁属于原群 xxx,GKYbotSave 发到本群很可能无效,建议用 GKY 官方网页(banlist 页面的「解鎖 Unban」按钮)解封"。两道预警都只警告不阻断,保留手动处理余地。 chat_member事件订阅:管理员手动封/解封时机器人自动同步 D1 黑名单。callback_query按钮交互:二次审核结果带「✅ 同意(一键代发)」按钮,超级管理员一键代发 GKYbotSave 指令到目标群,无需复制粘贴。- 超级管理员权限分级:新增可选
SUPER_ADMINS环境变量。普通群管理员能用所有命令但不能点按钮,按钮仅限超管使用,避免群内多名管理员误操作。 - 去除作者私群硬编码回退:原项目在群信息查询失败时会回退到作者私群名称
CM技术交流群/@CMLiussss,本项目改为中性默认值。 - 修复
/check群内回复时响应错发到主群的 bug:现在响应回到当前群。
全局黑名单语义:D1 中的黑名单是永久全局黑名单,命中后自助解封流程第一道闸即拒绝,机器人的任何流程都不会清除(包括 GKYbotSave 按钮代发)。只有管理员主动
/unban 用户ID才能从黑名单移除。
/start、/unban:向用户展示自助解封说明。- 复制粘贴指定整句确认文本:自动检查用户在每个配置群内的状态,分别尝试
unbanChatMember/restrictChatMember,并返回逐群结果。 - 用户存在 GKY 封禁记录时,自动在主群 @管理员 进行二次审核。
| 命令 | 使用位置 | 说明 |
|---|---|---|
/ban 用户ID [原因] |
私聊 / 群内 | 加入 D1 黑名单(reason=manual)+ 遍历所有 GROUP_IDS 真踢出群。支持单个、批量与原因:/ban 123 广告引流、/ban 123,456 批量广告、/ban [123,456,789]。小操作量即时执行;20 个及以上 TGID,或多群下总操作量过大时,自动创建 D1 批量任务。群内授权管理员发送后,机器人会撤回命令消息本身,并发闪屏 + 私聊详情。 |
/unban 用户ID |
私聊 / 群内 | 从 D1 黑名单移除。支持批量:/unban 123,456,789 或 /unban [123,456,789](半角 / 全角逗号 / 空格 / 换行均可,单次最多 50 个)。群内执行时同样发闪屏 + 私聊详情。 |
/spam [用户ID] [原因] |
群内回复 / 私聊 / 群内直接输入 | 回复消息时把被回复用户加入 D1 黑名单(reason=spam)+ 遍历所有 GROUP_IDS 真踢出群 + 删除被回复的垃圾消息,回复后面的文本作为原因,例如回复广告发 /spam 广告引流。也支持直接输入 TGID:/spam 123 广告引流、/spam 123,456 批量广告、/spam [123,456,789];20 个及以上 TGID,或多群下总操作量过大时,自动创建 D1 批量任务。 |
/job 任务ID |
私聊 / 群内 | 查询 /ban /spam 自动创建的 D1 批量任务状态。群内查询会发闪屏并按通知规则私聊详情。 |
/jobrun 任务ID |
私聊 / 群内 | 手动补跑未完成的大批量任务。正常情况下 D1 批量任务会自动分阶段续接到完成,/jobrun 仅作兜底。 |
/check |
群内回复 / 私聊 | 查询用户的 GKY 封禁记录,返回带按钮的二次审核。两种用法:群内回复某条消息发 /check 查该用户;或 /check TGID(私聊或群内均可)直接查指定 TGID,如 /check 993005028 |
/blacklist |
私聊 | 查看当前 D1 黑名单(最多显示 30 条) |
/start check_用户ID |
私聊深链 | 二次审核入口,由机器人自动生成链接 |
说明:
[123,456,789]数组外壳只用于粘贴批量 TGID,里面不解析原因;需要写原因时使用普通格式,例如/ban 123,456 批量广告。/job与/jobrun可直接发送使用,但不注册到 BotFather 命令菜单。
SUPER_ADMINS 环境变量配置的 TGID。除拥有群管理员所有命令外,可点击二次审核结果中的「✅ 同意(一键代发)」按钮:机器人自动代发 GKYbotSave\n用户ID 指令到目标群(GKYbot 据此处理白名单/移出黑名单),并在原消息追加操作记录。普通群管理员看到按钮但点击会被拒绝。
安全默认:未配置
SUPER_ADMINS时按钮存在但无人能点,仅复制按钮可用。
仅 OWNER_IDS 配置的主人/副主人可用。对普通用户、群管理员、超级管理员完全无反应(群内静默、私聊提示权限不足),且这些命令不注册到 BotFather 命令菜单,天然隐藏。主人/副主人私聊机器人发 /help 可随时展开下表。词库/样本存在 D1,改动无需重新部署,立即生效:
| 命令 | 位置 | 说明 |
|---|---|---|
/help |
私聊 | 展开全部 OWNER_IDS 专属隐藏指令清单 |
/admins |
仅主人私聊 | 查看当前 OWNER_IDS / SUPER_ADMINS 权限名单,显示 TGID、昵称、用户名、群内身份;群内不支持且静默 |
/importdefault |
私聊 | 一键导入推荐词库(金融/色情/引流/诈骗四类)到 D1,与现有词去重合并 |
/addword [分类] 词1 词2 ... |
私聊 | 加词。分类可选:finance/porn/spam/fraud/general/whitelist,默认 general。例:/addword fraud 杀猪盘 刷信誉 |
/delword 词1 词2 ... |
私聊 | 从所有分类删除指定词 |
/listwords |
私聊 | 查看当前 D1 词库全部内容(分类 + 数量) |
/listsamples |
私聊 | 查看学习的广告样本指纹(最近 50 条 + 总数) |
/delsample 序号或关键词 |
私聊 | 删除某条学习样本(序号见 /listsamples,或按关键词匹配删) |
/clearsamples confirm |
私聊 | 清空全部学习样本(需带 confirm 二次确认) |
/learn 广告文本 |
私聊 | 直接粘贴广告文字学习指纹(不需要回复消息,不踢人)。解决 GKY 已删消息无法 /spam 的痛点 |
/recent [N] |
群内 / 私聊 | 读取疑似广告缓存并冻结成带序号快照推送到主人私聊(最多 50 条)。群内=本群,私聊=全部群 |
/learnlast 序号 |
仅私聊 | 按 /recent 冻结快照的固定序号学习指纹(只入库,不踢人)。如 /learnlast 1,3。群内发会被拒,引导到私聊 |
/spam |
群内回复 | 主人版额外学习被回复广告的指纹(只入库,不污染词库);普通管理员 /spam 只加黑踢不学习 |
词库是全局配置,影响所有群的广告检测,所以仅限主人改。代码内置词库默认为空(GitHub 零敏感词),首次启用广告检测后建议先
/importdefault导入推荐词库。两步私聊复核学习流程(防误踢正常人):群里发
/recent→ 列表冻结快照推到主人私聊 → 主人核对序号 → 私聊发/learnlast 序号学习(只入库不踢人) → 需要踢人时用回执给的 TGID 手动/ban。/learnlast只从冻结快照读,序号永不漂移,即使期间有新消息进来挤动实时缓存也不影响。学习只写整句指纹,不再自动往词库加词(根因修复):旧版会把广告里自动提取的词——包括夹带的正常词——写进词库 +2 分,导致正常消息分数虚高被误判。现在提取的词仅在回执里建议,由主人手动决定是否
/addword。指纹只做精确匹配:归一化后完全相等(≥6 字)才秒杀,不做子串包含。学了短广告也绝不会炸到"碰巧含这几个字"的正常长消息。
- 新机器人风控:所有配置群中,新加入的「其它机器人」若不是管理员则被自动全权限禁言。具体规则:
- ✅ 触发:群里有人新拉入一个机器人,且该机器人不是群管理员
- ❌ 不触发:群里已存在的旧机器人(不会回溯处理已在群成员)
- ❌ 不触发:本机器人自己被加入群(不会自禁)
- ❌ 不触发:新加入的机器人已经是管理员(拉进群之前就设为管理员可绕过禁言)
- ❌ 不触发:新加入的是普通用户(非机器人)
- 用途:防止有人偷偷把广告 / 拉群 / 转发类机器人拉进群里发广告,争取时间让群主决定是否踢掉
- 管理员手动操作同步:群管理员手动 ban/unban 操作时,机器人通过
chat_member事件自动同步 D1 黑名单(被踢即加黑、解禁即移黑)。 - 黑名单用户群消息拦截:已在 D1 全局黑名单的用户,在任一配置群发言时机器人会实时删除消息并踢出群。管理员豁免(避免误加黑导致管理员被踢)。
- 黑名单用户复入群拦截:已在黑名单的用户被人拉回群 / 自己加回群时(
chat_member事件 status 变为 member),机器人会立即把他再踢出去,无需人工介入。
.
├── _worker.js # Worker 主程序
├── wrangler.toml # Cloudflare Wrangler 配置
├── test_batch.mjs # 批量解析与黑名单写入离线测试(43 项)
├── test_export.mjs # 导出接口离线测试(41 项)
├── test_kick.mjs # 真踢人闭环 + 广告学习 + 大批量任务离线测试(333 项)
├── README.md
└── LICENSE
- 一个 Telegram Bot Token,通过 @BotFather 创建。
- 一个 Cloudflare 账号,启用 Workers。
- 本地安装 Node.js 和 Wrangler,或直接使用 Cloudflare 控制台部署。
- 机器人需要被加入目标群组并设为管理员。
建议给机器人以下权限:
- 封禁用户或解除封禁
- 管理员权限或限制成员权限
- 读取群成员状态
- 发送消息
chat_member事件订阅要求机器人是群管理员,否则收不到该事件 — 但本来部署就要求管理员权限,无需额外配置。
配置优先级:环境变量 >
_worker.js顶部=可修改=区段的硬编码默认值。 也就是说,你既可以直接改源码顶部默认值,也可以在 Cloudflare 后台填环境变量临时覆盖;两者同时存在时环境变量胜出。
| 变量名 | 说明 |
|---|---|
TOKEN |
初始化入口密钥。访问 https://你的Worker域名/{TOKEN} 注册 Webhook + 注册命令;访问 https://你的Worker域名/{TOKEN}/export 导出黑名单;访问 https://你的Worker域名/{TOKEN}/purge/run 默认分批清扫 /ban + /spam 存量黑名单仍在群里的人。建议用随机长字符串。 |
BOT_TOKEN |
Telegram Bot Token,从 @BotFather 取。 |
GROUP_ID |
目标 Telegram 群组 ID,支持逗号分隔多群组(半角 , 与全角 , 都兼容)。例如 -1001234567890 或 -1001234567890,-1009876543210。第一个群作为「主群」,二次审核提醒等会发到主群。 |
| 变量名 | 默认 | 说明 |
|---|---|---|
SUPER_ADMINS |
空数组 | 超级管理员 TGID 白名单,环境变量为字符串形式,逗号分隔多个(半角 , 与全角 , 都兼容),例如 123456,789012。仅这些用户能点击「✅ 同意(一键代发)」按钮。未配置时按钮存在但无人能点(安全默认)。也可在 _worker.js 顶部 DEFAULT_SUPER_ADMINS 数组中硬编码。 |
OWNER_IDS |
空数组 | 主人/副主人 TGID 列表,逗号分隔。第一个是主人,收到全部通知;第二个及以后是副主人,只收到 /ban、/spam 这类加黑踢出通知。前提:对应账号必须先私聊过 bot 一次(任意 /start 即可),否则 Telegram 不允许 bot 主动发私信。留空 → 全局禁用,行为退化为只发群闪屏。也可在 _worker.js 顶部 DEFAULT_OWNER_IDS 数组中硬编码。 |
AD_FILTER_ENABLED |
false |
广告自动检测总开关。设为 true 启用。命中广告 → 自动删消息+加黑+全群踢+通知主人。默认关闭,建议先调好词库再开,避免误伤。 |
AD_SCORE_THRESHOLD |
3 |
广告评分阈值。各维度加权分总和 ≥ 阈值即判广告。调高 → 更保守(漏检多);调低 → 更激进(误杀多)。强特征(名字命中/样本精确匹配/名片名字命中)绕过评分直接判定。 |
AD_KEYWORDS |
空 | 追加自定义广告词,逗号分隔(半角/全角逗号都兼容),命中权重 +2。与 D1 分类词库合并生效。 |
AD_WHITELIST |
空 | 白名单词,逗号分隔。命中的词不计分,用于避免特定话题群误伤(如币圈群把 usdt 加白名单)。 |
| 域名白名单 | 内置 | github/google/youtube/gitlab/bilibili 等几十个正常站点链接永不被杀。内置在 _worker.js 顶部 DEFAULT_URL_WHITELIST;主人可用 /addword whitelist 域名.com 热更新追加(命中的域名链接放行,不计分、不参与样本匹配)。 |
| 身份广告词 | D1管理 | 只检测发言人名字/用户名(不碰消息正文)的广告词(色情/赌博露骨词)。代码无硬编码词库(GitHub 零敏感词),通过 /importdefault 导入或 /addword identity <词> 热更新。正常聊"chatgpt plus"等正文不受影响。 |
MSG_CACHE_ENABLED |
true |
消息缓存总开关。开启后 bot 自动缓存最近"疑似广告"群消息,供 /learnlast 学习被 GKY 删掉的广告。活跃群写入 D1(用 ctx.waitUntil 异步,不阻塞),D1 免费层每天 10 万次写入完全够用。 |
MSG_CACHE_SIZE |
50 |
消息缓存环形缓冲保留最近多少条(1-500)。多群高活跃时建议调大(如 200),避免本群疑似广告被别群消息挤出,/recent 拉不到。 |
SELF_UNBAN_KEYWORD |
我不是广告狗,我是误封的,希望可以解封。 |
自助解封确认整句。用户必须完整逐字粘贴才会触发解封流程。 |
SELF_UNBAN_PROMPT |
见源码 | /start /unban 命令收到时返回的欢迎/检查清单。支持 HTML 子集。占位符:{userId} {title} {keyword} 会自动替换。 |
SELF_UNBAN_APPROVED |
见源码 | 用户输入正确确认句、解封请求被同意时回复的提示。占位符:{username}(主群 @用户名 或主群 ID)。 |
BLACKLIST_PAGE_LIMIT |
30 |
/blacklist 命令单次最多展示多少条(按时间倒序,最新在前)。值必须是正整数。 |
BLACKLIST_REASON_LABELS |
见源码 | /blacklist 列表中"原因"字段的中文映射,JSON 字符串形式。例:{"spam":"群内举报","manual":"管理员添加","manual_ban":"自动同步"}。非法 JSON 时自动回退默认。 |
GKY_BANLIST_ENDPOINT |
https://gkybot.gmeow.cc/banlist |
GKY 封禁记录查询后端。改动者请确保返回 HTML 与 parseBanlistHTML 兼容。 |
_worker.js 文件最顶部有一段被 =可修改= 与 =结束= 标注的常量区,包含上述全部可选项的默认值。如果你不想用环境变量、希望直接改源码,只改这一段即可,其它代码无需触碰。
// =可修改= 项目内置文案与参数
// 优先级:环境变量 > 这里的硬编码默认值
const DEFAULT_SELF_UNBAN_KEYWORD = '我不是广告狗,我是误封的,希望可以解封。';
const DEFAULT_SELF_UNBAN_PROMPT = `...`;
const DEFAULT_SELF_UNBAN_APPROVED = `...`;
const DEFAULT_BLACKLIST_PAGE_LIMIT = 30;
const DEFAULT_BLACKLIST_REASON_LABELS = { spam: '...', manual: '...', manual_ban: '...' };
const DEFAULT_GKY_BANLIST_ENDPOINT = 'https://gkybot.gmeow.cc/banlist';
const DEFAULT_SUPER_ADMINS = ['123456', '789012']; // 数组形式,多个 TGID
const DEFAULT_OWNER_IDS = ['123456', '789012']; // 第一个主人,后续副主人;空数组禁用审计通知
// =结束=| 绑定 | binding 名 | 用途 |
|---|---|---|
| D1 Database | DB |
唯一存储后端。黑名单、广告词库、学习样本、消息缓存、批量任务全部存 D1。表结构由代码自动建立,首次写入自动建表。 |
未绑定 D1 时,自助解封仍可用,但
/ban/spam/blacklist等命令会提示未绑定存储空间。
npm install -g wrangler
wrangler loginwrangler d1 create tg-unban-bot-plus把输出的 database_id 写到 wrangler.toml 的 D1 配置中(取消注释 [[d1_databases]] 段)。表结构由代码自动建立,无需手动执行 SQL。
当前代码会自动创建以下 D1 表:
| 表名 | 用途 |
|---|---|
blacklist |
全局黑名单,保存 TGID、写入来源、操作人和时间 |
ad_keywords |
广告词库与白名单词 |
ad_samples |
/spam /learn /learnlast 学习到的广告指纹 |
recent_messages |
最近疑似广告消息缓存,供 /recent 使用 |
learn_snapshot |
/recent 冻结快照,供 /learnlast 二次复核 |
batch_jobs |
/ban /spam 自动创建的 D1 批量任务状态、进度、统计和失败记录 |
参考 wrangler.toml 中的 [observability] 配置段。建议至少开启 logs,因为 Worker 会输出 Telegram 更新、权限检查、API 返回等调试信息。
wrangler secret put TOKEN
wrangler secret put BOT_TOKEN
wrangler secret put GROUP_ID
wrangler secret put SUPER_ADMINS # 可选
# 以下全部可选;不填则使用 _worker.js 顶部 =可修改= 区段的默认值
# wrangler secret put SELF_UNBAN_KEYWORD
# wrangler secret put SELF_UNBAN_PROMPT
# wrangler secret put SELF_UNBAN_APPROVED
# wrangler secret put BLACKLIST_PAGE_LIMIT
# wrangler secret put BLACKLIST_REASON_LABELS
# wrangler secret put GKY_BANLIST_ENDPOINT也可以在 Cloudflare Dashboard 的 Worker 设置页中添加同名变量。
wrangler deploy部署后记录 Worker 域名,例如:
https://tg-unban-bot-plus.example.workers.dev
访问下面的地址:
https://你的Worker域名/你的TOKEN
成功后会自动完成:
- 设置 Telegram Webhook 到 Worker 根路径
/ - 订阅
message/chat_member/callback_query三类更新 - 设置机器人命令:
/unban/ban/spam/check/blacklist
返回 JSON 中 成功: true 即表示初始化完成。
/job//jobrun是大批量任务辅助命令,可直接发送使用,但不会注册到 BotFather 命令菜单。
-
用户私聊机器人发送
/start或/unban。 -
机器人返回自助解封说明,包含一段
<code>提示语供复制。 -
用户完整复制粘贴以下整句(多/少标点、夹带任何字符均会被拒绝):
我不是广告狗,我是误封的,希望可以解封。 -
机器人遍历每个配置群,检查用户在该群的状态:
kicked→unbanChatMember解封restricted或发言权被关闭 →restrictChatMember恢复发言- 已是正常成员 → 提示无明显限制
-
全部群处理完后返回逐群结果。
-
若用户存在 GKY 封禁记录,会在主群 @管理员 进行二次审核(含「同意」按钮 + 复制按钮)。
管理员收到二次审核提醒(来自 /check 命令、/start check_用户ID 深链或自助解封触发)时,消息底部有两个按钮:
- ✅ 同意 移出黑名单/添加白名单(一键代发):仅
SUPER_ADMINS可点。点击后机器人自动代发GKYbotSave\n用户ID到目标群,原消息追加「已由超级管理员 X 一键代发」记录。 - 📋 点击复制 移出黑名单/添加白名单 代码:所有人可点,复制后手动粘贴到群里发送。这是兜底路径,超管不在线时使用。
注意:按钮和复制都仅触发 GKYbotSave 指令给 GKYbot 处理,不会操作本项目维护的 D1 黑名单 — 全局黑名单需要管理员显式 /unban 用户ID 才能移除。
GET /banlist?tgid=用户ID示例:
curl "https://你的Worker域名/banlist?tgid=123456789"返回示例:
{
"success": true,
"banned": false,
"tgid": "123456789",
"message": "此TG帳號并沒有封鎖記錄 / This TG account has no ban record"
}存在封禁记录时返回字段还可能包含 chatId、msgId、reason、info、recordedDate。
GET /{TOKEN}/export # 默认:HTML 表格,浏览器直接看
GET /{TOKEN}/export?format=json # 下载 JSON 文件(带 attachment 头)
GET /{TOKEN}/export?format=csv # 下载 CSV 文件(含 UTF-8 BOM,Excel 中文不乱码)特点:
- 数据源:D1 数据库
- HTML 视图:表格 + 顶部下载按钮 + 实时搜索框(按 TGID / 原因 / 操作人过滤)
- 时间倒序:最新封禁的排在最前面
- 文件名带时间戳:
blacklist-2026-05-24T10-00-00-000Z.json - TOKEN 保护:URL 必须带正确的 TOKEN,路由不匹配返回 405
- HTML 注入防护:所有用户输入字段都通过
escapeHtml转义
示例:
# 浏览器直接打开看表格
open https://你的Worker域名/你的TOKEN/export
# 命令行下载 JSON 备份
curl -o blacklist.json "https://你的Worker域名/你的TOKEN/export?format=json"
# 下载 CSV 给运营/财务
curl -o blacklist.csv "https://你的Worker域名/你的TOKEN/export?format=csv"GET /{TOKEN}/purge
GET /{TOKEN}/purge?limit=20&cursor=0
GET /{TOKEN}/purge?reasons=all
GET /{TOKEN}/purge/groups
GET /{TOKEN}/purge/run默认扫描当前 D1 黑名单中由 /ban 写入的 manual 和由 /spam 写入的 spam 记录 × 所有 GROUP_IDS,对每个仍在群里的人调 banChatMember 真踢出群。群管理员、超级管理员、主人、副主人执行 /ban / /spam 写入的记录都会被清扫,因为清扫只按 reason 判断,不按操作者 by_user 判断。Telegram 状态为 kicked / left 的会跳过。
为避免 Cloudflare Worker 单次请求的子请求限制,/{TOKEN}/purge 默认只处理 20 个“用户 × 群组”组合,limit 最大会被压到 20,批内最多 5 并发。返回的 next_url 不为空时,继续请求它即可跑下一批。浏览器直接打开 /{TOKEN}/purge/run 会先预检 bot 在各群是否具备封禁权限,只清扫有权限的群,然后自动按批次续跑,适合几千条黑名单的大清扫。
如果确实要把 ad_auto / manual_ban 等其它来源也全量清扫,可手动使用 /{TOKEN}/purge/run?reasons=all 或 /{TOKEN}/purge?reasons=all。
{
"成功": true,
"清扫范围": "/ban + /spam",
"reasons": "manual,spam",
"黑名单总数": 33,
"配置群组数": 2,
"参与群组数": 2,
"参与群组列表": ["-1001234567890", "-1009876543210"],
"总任务数": 66,
"本批开始游标": 0,
"本批结束游标": 20,
"下批游标": 20,
"本批处理上限": 20,
"本批计划处理": 20,
"本批已处理": 20,
"剩余任务数": 46,
"已完成": false,
"done": false,
"next_cursor": 20,
"next_url": "https://你的Worker域名/你的TOKEN/purge?limit=20&cursor=20",
"已踢出": 5,
"不在群": 14,
"失败": 1,
"详情": [
{ "用户ID": "123", "群ID": "-1001234567890", "旧状态": "member", "结果": "已踢" },
{ "用户ID": "456", "群ID": "-1001234567890", "旧状态": "member", "结果": "失败", "错误": "Bad Request: not enough rights to restrict/unrestrict chat member" }
]
}用途:当你从原项目升级(原项目只写黑名单不踢人)或修复了 bot 权限后,打开 /purge/run 把早期通过 /ban / /spam 加黑但还在群里的用户清扫掉。幂等可重复触发。
原因:环境变量 TOKEN / BOT_TOKEN / GROUP_ID 三项缺一不可,缺失会直接返回 500。
解决:
- 用
wrangler secret list或在 Cloudflare Dashboard 检查三项变量是否都填了。 TOKEN不是 Telegram Bot Token,而是你自定义的初始化入口密钥(建议随机长字符串)。BOT_TOKEN才是 @BotFather 给的 Token。GROUP_ID必须是机器人所在的目标群组 ID(负数,例如-1001234567890)。
原因:本项目要求完整逐字粘贴才放行,多/少标点、夹带任何字符都会被拒绝(用于阻止广告号绕过)。 解决:
- 用户必须直接复制
<code>标签里的整句,不能手打。 - 若你修改了
SELF_UNBAN_KEYWORD,欢迎语里的<code>提示语会自动同步,但用户必须用当前生效的整句,不是旧的。 - 检查用户是否在 D1 全局黑名单(这是永久封禁,第一道闸就被拦下,必须由管理员手动
/unban才能解除)。
原因:chat_member 事件需要机器人本身是群管理员才能收到。
解决:
- 把机器人设为目标群组的管理员。
- 重新访问
https://你的Worker域名/{TOKEN}让机器人重新订阅 webhook。 - 检查 Cloudflare Worker 日志:每次有
chat_member事件时会打印[chat_member] 同步加黑/移黑日志。
原因:当前点击者不在 SUPER_ADMINS 白名单中。SUPER_ADMINS 的优先级是「环境变量 > 顶部 DEFAULT_SUPER_ADMINS 数组」。
解决:
- 检查
SUPER_ADMINS环境变量是否填了点击者的 TGID(多个用逗号分隔,例如123456,789012)。 - 或者改
_worker.js顶部DEFAULT_SUPER_ADMINS数组并重新部署。 - 注意:环境变量一旦填写就完全覆盖硬编码默认值,不会合并。
- 普通群管理员看到按钮但无法点击属于正常行为,他们应该用「📋 点击复制 ... 代码」按钮手动粘贴。
原因:本项目只读取 D1。D1 表结构会由代码自动创建,但已有数据必须已经写入对应 D1 表。新部署后如果还没有创建过 /ban /spam D1 批量任务,batch_jobs 没有任务数据属于正常情况。
解决:确认 wrangler.toml 或 Cloudflare Dashboard 已绑定 DB,并检查 D1 中的 blacklist、ad_keywords、ad_samples、recent_messages、learn_snapshot、batch_jobs 表数据是否存在。绑定正确后无需额外接口,重新部署或重新访问 bot 即可使用 D1 数据。
原因:/banlist 依赖外部服务 https://gkybot.gmeow.cc/banlist,外部不可用时查询会失败。
解决:
- 等外部服务恢复,或换一个 GKY 兼容的后端:设置
GKY_BANLIST_ENDPOINT环境变量。 - 注意:如果换后端,新后端返回的 HTML 必须与
parseBanlistHTML的正则匹配,否则即使联通也解析不出。
原因:环境变量优先级高于顶部硬编码。如果 Cloudflare 后台已经填了同名环境变量,会覆盖你改的源码。 解决:
- 检查 Cloudflare Dashboard 是否填了同名环境变量。
- 如果填了,要么删掉环境变量、要么直接修改环境变量的值(环境变量更方便)。
- 修改源码后必须
wrangler deploy重新部署才生效。
原因:管理员鉴权策略是「调用者必须是任一配置群(GROUP_ID 列表中的任意一个)的管理员」。 解决:
- 确认你是
GROUP_ID中至少一个群的管理员或群主。 /ban/unban可私聊或群内发送;/blacklist需要私聊机器人发送。/spam可回复消息发送,也可直接/spam 用户ID;回复消息时会额外删除被回复的垃圾消息,回复后面的文本会作为执行原因。/check有两种用法:群内回复某条消息发/check;或/check TGID(私聊或群内均可,如/check 993005028)。私聊发不带参数的/check会提示正确用法。/job 任务ID用于查询/ban/spam自动创建的 D1 批量任务;正常情况下任务会自动分阶段续接到完成,/jobrun 任务ID仅用于异常中断后的手动补跑。- 检查 Worker 日志中的「权限状态: xxx」行,能看到机器人查到的你当前角色。
原因:默认情况下 wrangler deploy 会用本地 wrangler.toml 覆盖远端配置。
解决:本项目 wrangler.toml 里已设置 keep_vars = true,部署时会保留 Cloudflare Dashboard 中已有的环境变量。如果你 fork 后改了这个配置,记得改回来。
原因:本机器人解封流程只调用 Telegram 的 unbanChatMember / restrictChatMember,恢复账号在群里的「能否发言」状态。但有些场景仍可能受限:
- 用户没重新加入群组(
kicked状态解封后用户需要重新点链接加群)。 - 用户被其它机器人/反垃圾系统单独标记限言(与本机器人无关)。
- 用户在 GKY 全局黑名单中 — 这种情况会触发主群二次审核提醒,需要管理员处理 GKY 那边的封禁。
- 用户在 D1 本项目的全局黑名单中 — 这个永远拦在第一道闸,必须管理员
/unban才能放行。
原因:当前有两套批量路径:/ban /spam 小操作量走即时流程;当 TGID 达到 20 个,或 TGID 数量 × 配置群数量 超过安全操作预算时,自动创建 D1 批量任务。/unban 不走 D1 批量任务,仍受 _worker.js 的 BATCH_LIMIT = 50 限制。
解决:
/ban/spam大名单可以直接粘贴,例如/ban [100,101,102,...]或/spam 100,101,102,... 批量广告。进入 D1 批量任务后会保存到batch_jobs,按每轮最多 24 个“用户 × 群组”操作预算自动切片,最多 3 并发,并自动续接下一阶段,避免 Cloudflare Worker 单次子请求超限。- 任务创建后会返回任务 ID;用
/job 任务ID查询进度。正常情况下不需要手动续跑,若自动续接被外部异常打断,可用/jobrun 任务ID补跑。 /unban仍需按每批最多 50 个拆分,例如/unban 100,101,...,149一批,/unban 150,151,...,199又一批。- 分隔符可混用:半角
,/ 全角,/ 空格 / 换行,也支持[123,456]数组外壳,便于从其它表格 / 聊天记录直接粘贴。 - 批量过程中重复 ID 会自动去重,已在黑名单的会单独标记,不会让整批失败。
原因:原项目没有导出接口,本项目新增 GET /{TOKEN}/export,支持浏览器查看 / JSON 下载 / CSV 下载(Excel 友好)。
安全性:
- 受
TOKEN保护,URL 必须带正确 TOKEN,否则路由不匹配返回 405。 - 所有用户输入字段(TGID / 原因 / 操作人 / 时间)通过
escapeHtml转义,HTML 视图无注入风险。 Cache-Control: no-store头确保中间代理不会缓存敏感数据。
使用方式:
| 场景 | URL |
|---|---|
| 浏览器查看(带搜索过滤) | /{TOKEN}/export |
| 下载 JSON 备份 | /{TOKEN}/export?format=json |
| 下载 CSV 给 Excel | /{TOKEN}/export?format=csv |
注意:
- TOKEN 不要泄漏(同时也是 webhook 初始化密钥),泄漏即等于黑名单可被任何人查看下载。
- 导出量不受
BLACKLIST_PAGE_LIMIT限制 — 那是/blacklist命令的展示上限,导出永远全量返回。
原因:踢人需要 bot 在目标群拥有"封禁用户"权限。bot 不是群管理员,或者管理员权限里关闭了"封禁用户"开关时,Telegram 会拒绝 banChatMember 请求。
解决:
- 进入目标群组 → 群设置 → 管理员 → 找到本机器人 → 打开"封禁用户"权限。
- 确认开关:封禁用户(Ban Users)、删除消息(Delete Messages) 这两项必须打开。
- 改完后无需重启 Worker,下次触发
/ban/spam立即生效。 - 如果想清扫之前因权限不足"加黑了但没踢"的存量用户:浏览器访问
https://你的Worker域名/{TOKEN}/purge/run自动分批扫描清扫。
原因:本项目调用的 banChatMember API 带 revoke_messages: true,Telegram 会自动撤回该用户最近 48 小时内在该群发的所有消息。这是 Telegram 平台规则,48 小时之外的消息无法撤回。
解决:
- 自动撤回 48 小时内消息已是 Telegram 上限,本项目无法做更多。
- 如需删除更早的消息,只能群管理员手动逐条删,或群管理员用 Telegram 客户端的"清除全部消息"功能(针对单个用户)。
/spam命令额外删除被回复那条具体的垃圾消息,不受 48 小时限制(因为是按message_id直接删)。
原因:本项目 /ban /spam /unban 在群内执行时,机器人会先发 5 秒闪屏;私聊详情按 OWNER_IDS 通知规则投递。Telegram 平台规则:bot 不能主动给从未交互过的用户发私信。如果主人/副主人从未私聊过这个机器人,私聊投递会失败;如果没有配置 OWNER_IDS,群内场景只保留闪屏。
解决:
- 主人/副主人分别私聊机器人发一次
/start(或任意消息)即可建立会话,之后机器人就能给对应账号发私信。 - 检查
OWNER_IDS是否正确配置;第一个是主人,后续是副主人。 - 群内授权管理员发送
/ban/spam后,机器人会撤回命令消息本身;普通用户无权限命令不会被撤回,也不会执行。 - 如果只想看到私聊详情、不想群里有任何痕迹,依然可以直接私聊机器人发
/ban/spam/unban(向后完全兼容,行为不变)。
原因:闪屏自动撤回靠 deleteMessage API,bot 必须有"删除消息"权限。如果 bot 不是群管理员或权限不足,闪屏会留在群里不撤回。
解决:
- 进入目标群组 → 群设置 → 管理员 → 找到本机器人 → 打开"删除消息"权限。
- 主流程不受影响:加黑、踢人、私聊详情都已经完成,只是闪屏没自动撤回。
- 群管理员可以手动删那条闪屏消息。
原因:本项目设计了"主人/副主人审计通知"机制 — 一旦配置 OWNER_IDS,群内命令详情不再发给每个触发管理员,而是按固定规则投递:
OWNER_IDS[0]是主人,收到全部通知OWNER_IDS[1..]是副主人,只收到/ban、/spam的加黑踢出通知- 其他管理员/超管在群里看到闪屏知道执行结果即可,不接收私聊详情
/ban/spam通知详情会包含命令来源、作用范围、执行原因;群内执行会显示具体群名和群 ID,私聊执行会显示来源为私聊
如果你希望恢复"每个管理员各自收到自己的详情"老行为:
- 不配置
OWNER_IDS(留空) → 退化为只发群闪屏,不发任何私聊详情(简化模式) - 想要"每个人都收自己的"老行为,本项目当前不支持。如果你需要,可以提 issue 提议加
BROADCAST_TO_TRIGGER开关
原因:Telegram 平台规则 — bot 不能主动给从未交互过的用户发私信。如果你设了 OWNER_IDS 但对应账号从未私聊过 bot,通知投递会失败。
解决:
- 主人/副主人账号分别私聊 bot 发一次
/start(任意消息都行),建立会话 - Worker 日志会显示
[审计通知] 私聊主人...失败:Forbidden: bot can't initiate conversation— 凡是看到这条日志,就是该账号没建立私聊 - 检查 OWNER_IDS 是否填了正确的纯数字 TGID(不要填 username)
- 临时禁用通知 → 把 OWNER_IDS 留空,Worker 自动退化
原因:本项目按以下优先级判定操作人角色(用于审计通知标签):
- 如果操作人 TGID 等于
OWNER_IDS[0]→ 标"主人" - 如果操作人 TGID 在
OWNER_IDS[1..]→ 标"副主人" - 否则如果在 SUPER_ADMINS 名单 → 标"超级管理员"
- 否则按调用上下文兜底(chat_member 同步标"群管理员",命令鉴权后默认"管理员")
示例:
- 你自己(主人)
/ban 123→ 私聊收到"🔔 主人操作通知" - 副主人
/spam或/ban 123→ 主人和副主人收到加黑踢出通知 - 名单中的超管 X
/ban 123→ 主人收到"🔔 超级管理员操作通知\n操作人:X(超级管理员)" - 群管理员 Y
/ban 123→ 主人收到"🔔 群管理员操作通知\n操作人:Y(群管理员)"
原因:评分阈值太低,或某个正常话题词恰好命中词库。 解决(任选):
- 调高阈值:
AD_SCORE_THRESHOLD设大一点(如4或5),需要更多广告特征叠加才判定。 - 加白名单:把被误判的词加进
AD_WHITELIST(逗号分隔),该词命中不计分。例如币圈讨论群:AD_WHITELIST=usdt,承兑,搬砖。 - 临时全关:
AD_FILTER_ENABLED=false立即停用,排查后再开。 - 手动恢复被误杀的用户:私聊 bot 发
/unban 用户TGID把他从黑名单移除(注意:踢出群后用户需要重新加群)。 - 查 Worker 日志的
[广告检测] 命中行,能看到具体命中了哪些特征,据此调整。
原因:广告用了词库没有的变体,或评分没达阈值。 解决:
- 导入推荐词库:首次启用先私聊机器人发
/importdefault,把推荐词库写入 D1。 - 加自定义词:私聊发
/addword 分类 词,命中权重 +2(诈骗/金融/色情)或 +1(引流)。 - 调低阈值:
AD_SCORE_THRESHOLD设为2,更激进(但误杀风险上升)。 - 强特征最稳:带 t.me/+ 邀请链接、国际电话号的广告一定会被秒杀,无视阈值和词库。
- 持续遇到新变体就
/addword加进去,改词立即生效不用重新部署。
原因:为隐私起见,代码内置词库默认为空(GitHub 公开仓库不出现敏感词),所以刚开 AD_FILTER_ENABLED=true 时,只有强特征(t.me 邀请链接/国际电话号)生效,关键词检测是空的。
解决(主人私聊机器人操作):
- 一键导入推荐词库:发
/importdefault,机器人把内置推荐词库(金融/色情/引流/诈骗四类)写入 D1,立即生效。 - 手动加词:
/addword fraud 杀猪盘 刷信誉(分类可选,默认 general)。 - 查看现状:
/listwords看当前 D1 里有哪些词。 - 删词:
/delword 某词(从所有分类删)。 - 注意:这些命令仅 OWNER_IDS 中的主人/副主人可用,且需在私聊机器人时发送(群里发会被静默忽略)。词库存 D1,改完即时生效,无需
wrangler deploy。
场景:有条广告词库没覆盖,这次漏检了。你想让机器人"记住"它,以后自动杀。 做法(主人操作):
- 在群里回复那条广告消息,发
/spam。机器人会:加黑+全群踢该用户、删消息,并把广告整句指纹学习入库。 - 只学整句指纹:归一化后存库(去掉空格/标点/大小写/全半角差异)。以后任何人发相同广告(哪怕加了空格、标点、emoji 变体),都会被精确秒杀。
- 不再自动往词库加词(根因修复):旧版会把广告里自动提取的词写进词库
general,但这些词常夹带正常词,导致正常消息分数虚高被误判。现在提取的词只在回执里建议,你看了觉得合适再手动/addword general 词。 - 只有主人
/spam会学习。普通群管理员/spam仍然加黑+踢,但不入库(避免管理员之间口径不一污染样本库)。 - 管理样本库:
/listsamples看学了哪些、/delsample 序号删错学的、/clearsamples confirm清空。 - 防误杀(分级匹配):归一化后 <6 字的太短样本不参与匹配;子串包含要求指纹和消息双方都 ≥16 字,短广告只能精确相等命中,绝不会因子串炸到"碰巧含这几个字"的正常长消息。
- 样本无人为上限(D1 单行存储容量充足,可存几十万条),不用担心存满。
痛点:GKY 神膠bot 检测到广告会立刻删消息,Telegram"已删除消息无法回复",/spam 失效。
两个解法(都是 OWNER_IDS 专属,学习一律只入库不踢人):
① /learn 粘贴文本 — 最直接,不依赖回复:
/learn 世界杯足球红单推荐 天天收米 日赚3千 @laohe61bot
把广告文字(从截图打字、记忆、任何来源)直接粘给命令,立即学习整句指纹(不踢人)。
② /recent + /learnlast(两步私聊复核) — bot 自动缓存,核对序号后学:
- bot 会自动缓存最近的"疑似广告"群消息(含链接 / @提及 / 长数字 / 长文本的),正常闲聊不缓存
- GKY 删完广告后,主人在群里发
/recent→ bot 把缓存冻结成带序号的快照,推到主人私聊 - 主人在私聊里核对序号,发
/learnlast 序号学习(如/learnlast 1,3)。只从冻结快照读,序号永不漂移;群内发/learnlast会被拒绝,引导到私聊 - 学习只入库,不踢人。要踢发广告的人,用回执给出的 TGID 手动
/ban TGID - 快照空时提示先发
/recent - 学错了:
/delsample 关键词删样本
原理:你的 bot 其实也收到了那条广告原文(Telegram 推给群里所有 bot),GKY 删消息是它事后的动作。所以 bot 早就缓存下来了,GKY 删不掉你 D1 里的缓存。
为什么强制私聊 + 不踢人:群内手忙脚乱点错序号会误踢正常人;拆成"群里拉快照 / 私聊核对学习 / 手动决定踢谁"三步,每一步都给主人留了复核窗口,把误操作风险降到最低。
配置:
MSG_CACHE_ENABLED(默认true)— 消息缓存总开关MSG_CACHE_SIZE(默认50)— 环形缓冲保留最近多少条。多群高活跃时建议调大(如200),避免本群广告被别群消息挤出
是的,这是有意设计。OWNER_IDS 专属命令(/help /importdefault /addword /delword /listwords /listsamples /delsample /clearsamples /learn /recent /learnlast /admins)的鉴权规则:
- 一般隐藏指令只有
OWNER_IDS中的主人/副主人能用。/admins更敏感,只允许OWNER_IDS[0]主人私聊使用。 - 非主人在群内:完全静默,连"权限不足"都不回,避免暴露命令存在。
- 非主人在私聊:回"权限不足",但不泄漏命令的具体功能(
/help对非主人也只回权限不足,不展开清单)。 - 不注册到命令菜单:这些命令不在
setMyCommands里(只注册了/unban/ban/spam/check/blacklist),所以用户在 Telegram 输入框敲/看不到它们,天然隐藏。 - 主人想随时查看全部隐藏指令:私聊发
/help;想查看当前主人/副主人/超级管理员名单:私聊发/admins。
先搞清楚:链接被杀几乎都不是因为"它是链接",而是匹配上了之前学习过的样本指纹(看拦截通知的"判定依据",写"学习样本"就是这种)。本项目不会因为"消息含链接"就判广告——含链接的检测只在"链接是可疑短链"或"已学过的样本"时才触发。
本版已内置三层防护,正常链接绝不误杀:
- 正常域名白名单:github/google/youtube/gitlab/stackoverflow/bilibili 等几十个常见站点的链接永不被杀。想加自己的域名,主人私聊发
/addword whitelist 你的域名.com,即时生效不用重部署。 - 含 URL 的样本只精确匹配:学过某条广告链接后,只有一字不差的同一条会被杀,同域名其它路径的正常链接绝不连带误伤。
- 可疑短链才加分:只有 bit.ly / tinyurl / b23.tv 这类短链才单独加分,且需配合其它特征。
如果某条链接还是被误杀了(说明它被误学进了样本库):
- 主人私聊发
/listsamples查看已学样本,找到那条链接的指纹序号。 - 发
/delsample 序号(或/delsample 域名关键词)删掉这条误学样本,立即止血。 - 把该域名永久加白:
/addword whitelist 域名.com,以后该域名所有链接都放行。 - 查 Worker 日志
[广告检测] 命中行,能看到具体命中了哪条特征,据此判断是样本还是词库的问题。
原因:广告号常用分享联系人名片(Contact)的形式发广告——名片显示名写"假钞交流群"、电话填国际号、还带"发送信息/添加好友"按钮。这种消息的 text/caption 是空的,广告内容全藏在 contact 字段里。旧版检测只读文字消息,完全漏掉名片,所以名片广告只被群里别的 bot 删了消息,本项目不加黑不踢。
本版已修:检测会把名片内容(显示名/电话号/vcard)一并识别,任一命中即杀:
- 名片显示名命中词库 → 直接秒杀(强特征,不用凑分)。名字含"假钞/承兑/约炮"等任意词库词,立即删+黑+全群踢。正常人名片名字是"张三/小明/John",几乎不可能命中,误杀面极低。
- 名片含国际电话号(带
+国家码,排除 +86 中国号)→ 强特征直杀。截图里+1 870 337 4069就属于这种,不依赖词库。 - 正常分享本地联系人不误杀:中国号(+86)+ 名字无敏感词的名片只 +1 分,不达阈值(默认 3),正常用户分享联系人不受影响。
- 名片广告也会被缓存,可用
/recent看到、/learnlast学习指纹。
前提:① AD_FILTER_ENABLED=true 开启检测;② 想靠"显示名敏感词"判定的,先 /importdefault 导入词库或 /addword 加词(纯国际电话号的名片不依赖词库,直接强特征杀)。
当前不支持,这是技术取舍,如实说明:
- 名片(contact)拿不到头像:Telegram 的
message.contact字段只有名字、电话、user_id、vcard,没有头像图。你截图里那个"一手假钞"红色图标是 vCard 内嵌的 logo 或名片预览占位图,Bot API 取不到原图。 - Worker 跑不了 OCR:识别图片里的字需要 OCR(光学字符识别),Cloudflare Worker 没有图像处理能力、CPU 时间也只有几十毫秒,塞不下。要做必须接外部 OCR API(如 Cloudflare Workers AI 图像模型),需单独开通、付费、每张图增加几百毫秒延迟。
- "发图片让 AI 学习"的误区:开发时 AI 能看图,但部署后运行的是独立的 Cloudflare Worker,它不是 AI 本体。线上 bot 要"看懂图"必须自己接 OCR 服务,不是开发时喂几张图就能学会的。
- 当前策略:把基于文字的检测(名片名字 / 电话号 / 词库 / 学习样本 / 链接)做到极致,已能覆盖绝大多数名片广告——因为广告号为了让人能搜到/加到,名字和电话几乎一定是文字可读的,纯靠一张图片做广告反而没法引流。
- 若将来确实需要图片 OCR,可作为独立增量功能评估接入 Workers AI,对"用户直接发的图片消息"做识别(名片头像受 API 限制仍可能拿不到)。
本项目沿用原项目 MIT License。
原作者:CMLiussss — Copyright (c) 2026 原项目:CF-Workers-TGUnbanBot
再次特别鸣谢原作者 CMLiussss 设计的源代码支持 🙏
详见 LICENSE 文件。