Skip to content

xtgm/TGUnbanBot-Plus

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

76 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

CF-Workers-TGUnbanBot-Plus

🙏 致敬原作者

项目 信息
原作者 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 管理。
    • ⚠️ 绝不把"链接/@提及/域名"当广告(防误杀的核心):正常用户名字里放双向机器人 @xxxBotgithub 链接个人频道 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 与检测比对都只用正文(不含发送者用户名),保证同一条广告不同人发也能精确命中。
  • /help OWNER_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)— 隐藏指令

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 后台填环境变量临时覆盖;两者同时存在时环境变量胜出

必填(缺失会返回 500)

变量名 说明
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 等命令会提示未绑定存储空间。

部署

1. 安装 Wrangler

npm install -g wrangler
wrangler login

2. 创建 D1 数据库

wrangler 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 批量任务状态、进度、统计和失败记录

3. 启用 Observability(可选)

参考 wrangler.toml 中的 [observability] 配置段。建议至少开启 logs,因为 Worker 会输出 Telegram 更新、权限检查、API 返回等调试信息。

4. 设置环境变量

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 设置页中添加同名变量。

5. 部署 Worker

wrangler deploy

部署后记录 Worker 域名,例如:

https://tg-unban-bot-plus.example.workers.dev

6. 初始化 Webhook

访问下面的地址:

https://你的Worker域名/你的TOKEN

成功后会自动完成:

  • 设置 Telegram Webhook 到 Worker 根路径 /
  • 订阅 message / chat_member / callback_query 三类更新
  • 设置机器人命令:/unban /ban /spam /check /blacklist

返回 JSON 中 成功: true 即表示初始化完成。

/job / /jobrun 是大批量任务辅助命令,可直接发送使用,但不会注册到 BotFather 命令菜单。

使用方法

用户自助解封

  1. 用户私聊机器人发送 /start/unban

  2. 机器人返回自助解封说明,包含一段 <code> 提示语供复制。

  3. 用户完整复制粘贴以下整句(多/少标点、夹带任何字符均会被拒绝):

    我不是广告狗,我是误封的,希望可以解封。
    
  4. 机器人遍历每个配置群,检查用户在该群的状态:

    • kickedunbanChatMember 解封
    • restricted 或发言权被关闭 → restrictChatMember 恢复发言
    • 已是正常成员 → 提示无明显限制
  5. 全部群处理完后返回逐群结果。

  6. 若用户存在 GKY 封禁记录,会在主群 @管理员 进行二次审核(含「同意」按钮 + 复制按钮)。

二次审核流程

管理员收到二次审核提醒(来自 /check 命令、/start check_用户ID 深链或自助解封触发)时,消息底部有两个按钮:

  • ✅ 同意 移出黑名单/添加白名单(一键代发):仅 SUPER_ADMINS 可点。点击后机器人自动代发 GKYbotSave\n用户ID 到目标群,原消息追加「已由超级管理员 X 一键代发」记录。
  • 📋 点击复制 移出黑名单/添加白名单 代码:所有人可点,复制后手动粘贴到群里发送。这是兜底路径,超管不在线时使用。

注意:按钮和复制都仅触发 GKYbotSave 指令给 GKYbot 处理,不会操作本项目维护的 D1 黑名单 — 全局黑名单需要管理员显式 /unban 用户ID 才能移除。

HTTP 接口

查询封禁记录(公开)

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"
}

存在封禁记录时返回字段还可能包含 chatIdmsgIdreasoninforecordedDate

黑名单导出(受 TOKEN 保护)

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"

黑名单清扫入口(受 TOKEN 保护)

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 加黑但还在群里的用户清扫掉。幂等可重复触发。

常见问题

Q1:访问 /{TOKEN} 返回 500,或部署后 Webhook 不工作

原因:环境变量 TOKEN / BOT_TOKEN / GROUP_ID 三项缺一不可,缺失会直接返回 500。 解决

  1. wrangler secret list 或在 Cloudflare Dashboard 检查三项变量是否都填了。
  2. TOKEN 不是 Telegram Bot Token,而是你自定义的初始化入口密钥(建议随机长字符串)。
  3. BOT_TOKEN 才是 @BotFather 给的 Token。
  4. GROUP_ID 必须是机器人所在的目标群组 ID(负数,例如 -1001234567890)。

Q2:用户在私聊发了正确确认句却没被解封

原因:本项目要求完整逐字粘贴才放行,多/少标点、夹带任何字符都会被拒绝(用于阻止广告号绕过)。 解决

  1. 用户必须直接复制 <code> 标签里的整句,不能手打。
  2. 若你修改了 SELF_UNBAN_KEYWORD,欢迎语里的 <code> 提示语会自动同步,但用户必须用当前生效的整句,不是旧的。
  3. 检查用户是否在 D1 全局黑名单(这是永久封禁,第一道闸就被拦下,必须由管理员手动 /unban 才能解除)。

Q3:机器人收不到群里管理员手动封/解封的同步信号

原因chat_member 事件需要机器人本身是群管理员才能收到。 解决

  1. 把机器人设为目标群组的管理员。
  2. 重新访问 https://你的Worker域名/{TOKEN} 让机器人重新订阅 webhook。
  3. 检查 Cloudflare Worker 日志:每次有 chat_member 事件时会打印 [chat_member] 同步加黑/移黑 日志。

Q4:超级管理员点了「✅ 同意(一键代发)」按钮被拒

原因:当前点击者不在 SUPER_ADMINS 白名单中。SUPER_ADMINS 的优先级是「环境变量 > 顶部 DEFAULT_SUPER_ADMINS 数组」。 解决

  1. 检查 SUPER_ADMINS 环境变量是否填了点击者的 TGID(多个用逗号分隔,例如 123456,789012)。
  2. 或者改 _worker.js 顶部 DEFAULT_SUPER_ADMINS 数组并重新部署。
  3. 注意:环境变量一旦填写就完全覆盖硬编码默认值,不会合并。
  4. 普通群管理员看到按钮但无法点击属于正常行为,他们应该用「📋 点击复制 ... 代码」按钮手动粘贴。

Q5:D1 绑定后黑名单、词库、学习样本或批量任务为空

原因:本项目只读取 D1。D1 表结构会由代码自动创建,但已有数据必须已经写入对应 D1 表。新部署后如果还没有创建过 /ban /spam D1 批量任务,batch_jobs 没有任务数据属于正常情况。 解决:确认 wrangler.toml 或 Cloudflare Dashboard 已绑定 DB,并检查 D1 中的 blacklistad_keywordsad_samplesrecent_messageslearn_snapshotbatch_jobs 表数据是否存在。绑定正确后无需额外接口,重新部署或重新访问 bot 即可使用 D1 数据。

Q6:/banlist?tgid=... 返回失败或无数据

原因/banlist 依赖外部服务 https://gkybot.gmeow.cc/banlist,外部不可用时查询会失败。 解决

  1. 等外部服务恢复,或换一个 GKY 兼容的后端:设置 GKY_BANLIST_ENDPOINT 环境变量。
  2. 注意:如果换后端,新后端返回的 HTML 必须与 parseBanlistHTML 的正则匹配,否则即使联通也解析不出。

Q7:修改了 _worker.js 顶部的 DEFAULT_* 默认值,但没生效

原因:环境变量优先级高于顶部硬编码。如果 Cloudflare 后台已经填了同名环境变量,会覆盖你改的源码。 解决

  1. 检查 Cloudflare Dashboard 是否填了同名环境变量。
  2. 如果填了,要么删掉环境变量、要么直接修改环境变量的值(环境变量更方便)。
  3. 修改源码后必须 wrangler deploy 重新部署才生效。

Q8:管理员命令(/ban /spam /check /blacklist)没反应

原因:管理员鉴权策略是「调用者必须是任一配置群(GROUP_ID 列表中的任意一个)的管理员」。 解决

  1. 确认你是 GROUP_ID 中至少一个群的管理员或群主。
  2. /ban /unban 可私聊或群内发送;/blacklist 需要私聊机器人发送。
  3. /spam 可回复消息发送,也可直接 /spam 用户ID;回复消息时会额外删除被回复的垃圾消息,回复后面的文本会作为执行原因。
  4. /check 有两种用法:群内回复某条消息/check;/check TGID(私聊或群内均可,如 /check 993005028)。私聊发不带参数的 /check 会提示正确用法。
  5. /job 任务ID 用于查询 /ban /spam 自动创建的 D1 批量任务;正常情况下任务会自动分阶段续接到完成,/jobrun 任务ID 仅用于异常中断后的手动补跑。
  6. 检查 Worker 日志中的「权限状态: xxx」行,能看到机器人查到的你当前角色。

Q9:部署后环境变量被意外重置

原因:默认情况下 wrangler deploy 会用本地 wrangler.toml 覆盖远端配置。 解决:本项目 wrangler.toml 里已设置 keep_vars = true,部署时会保留 Cloudflare Dashboard 中已有的环境变量。如果你 fork 后改了这个配置,记得改回来。

Q10:自助解封通过后,用户为什么还是不能在群里发言

原因:本机器人解封流程只调用 Telegram 的 unbanChatMember / restrictChatMember,恢复账号在群里的「能否发言」状态。但有些场景仍可能受限:

  1. 用户没重新加入群组(kicked 状态解封后用户需要重新点链接加群)。
  2. 用户被其它机器人/反垃圾系统单独标记限言(与本机器人无关)。
  3. 用户在 GKY 全局黑名单中 — 这种情况会触发主群二次审核提醒,需要管理员处理 GKY 那边的封禁。
  4. 用户在 D1 本项目的全局黑名单中 — 这个永远拦在第一道闸,必须管理员 /unban 才能放行。

Q11:/ban /spam /unban 批量超过 50 个怎么办

原因:当前有两套批量路径:/ban /spam 小操作量走即时流程;当 TGID 达到 20 个,或 TGID 数量 × 配置群数量 超过安全操作预算时,自动创建 D1 批量任务。/unban 不走 D1 批量任务,仍受 _worker.jsBATCH_LIMIT = 50 限制。 解决

  1. /ban /spam 大名单可以直接粘贴,例如 /ban [100,101,102,...]/spam 100,101,102,... 批量广告。进入 D1 批量任务后会保存到 batch_jobs,按每轮最多 24 个“用户 × 群组”操作预算自动切片,最多 3 并发,并自动续接下一阶段,避免 Cloudflare Worker 单次子请求超限。
  2. 任务创建后会返回任务 ID;用 /job 任务ID 查询进度。正常情况下不需要手动续跑,若自动续接被外部异常打断,可用 /jobrun 任务ID 补跑。
  3. /unban 仍需按每批最多 50 个拆分,例如 /unban 100,101,...,149 一批,/unban 150,151,...,199 又一批。
  4. 分隔符可混用:半角 , / 全角 / 空格 / 换行,也支持 [123,456] 数组外壳,便于从其它表格 / 聊天记录直接粘贴。
  5. 批量过程中重复 ID 会自动去重,已在黑名单的会单独标记,不会让整批失败。

Q12:/{TOKEN}/export 接口怎么用,安不安全

原因:原项目没有导出接口,本项目新增 GET /{TOKEN}/export,支持浏览器查看 / JSON 下载 / CSV 下载(Excel 友好)。 安全性

  1. TOKEN 保护,URL 必须带正确 TOKEN,否则路由不匹配返回 405。
  2. 所有用户输入字段(TGID / 原因 / 操作人 / 时间)通过 escapeHtml 转义,HTML 视图无注入风险。
  3. Cache-Control: no-store 头确保中间代理不会缓存敏感数据。

使用方式

场景 URL
浏览器查看(带搜索过滤) /{TOKEN}/export
下载 JSON 备份 /{TOKEN}/export?format=json
下载 CSV 给 Excel /{TOKEN}/export?format=csv

注意

  1. TOKEN 不要泄漏(同时也是 webhook 初始化密钥),泄漏即等于黑名单可被任何人查看下载。
  2. 导出量不受 BLACKLIST_PAGE_LIMIT 限制 — 那是 /blacklist 命令的展示上限,导出永远全量返回。

Q13:/ban /spam 显示"全部群踢人失败"怎么办

原因:踢人需要 bot 在目标群拥有"封禁用户"权限。bot 不是群管理员,或者管理员权限里关闭了"封禁用户"开关时,Telegram 会拒绝 banChatMember 请求。 解决

  1. 进入目标群组 → 群设置 → 管理员 → 找到本机器人 → 打开"封禁用户"权限。
  2. 确认开关:封禁用户(Ban Users)删除消息(Delete Messages) 这两项必须打开。
  3. 改完后无需重启 Worker,下次触发 /ban /spam 立即生效。
  4. 如果想清扫之前因权限不足"加黑了但没踢"的存量用户:浏览器访问 https://你的Worker域名/{TOKEN}/purge/run 自动分批扫描清扫。

Q14:黑名单用户的旧消息怎么办,会被自动删吗

原因:本项目调用的 banChatMember API 带 revoke_messages: true,Telegram 会自动撤回该用户最近 48 小时内在该群发的所有消息。这是 Telegram 平台规则,48 小时之外的消息无法撤回解决

  1. 自动撤回 48 小时内消息已是 Telegram 上限,本项目无法做更多。
  2. 如需删除更早的消息,只能群管理员手动逐条删,或群管理员用 Telegram 客户端的"清除全部消息"功能(针对单个用户)。
  3. /spam 命令额外删除被回复那条具体的垃圾消息,不受 48 小时限制(因为是按 message_id 直接删)。

Q15:群里发了 /ban 或 /spam 但没收到私聊详情

原因:本项目 /ban /spam /unban 在群内执行时,机器人会先发 5 秒闪屏;私聊详情按 OWNER_IDS 通知规则投递。Telegram 平台规则:bot 不能主动给从未交互过的用户发私信。如果主人/副主人从未私聊过这个机器人,私聊投递会失败;如果没有配置 OWNER_IDS,群内场景只保留闪屏。 解决

  1. 主人/副主人分别私聊机器人发一次 /start(或任意消息)即可建立会话,之后机器人就能给对应账号发私信。
  2. 检查 OWNER_IDS 是否正确配置;第一个是主人,后续是副主人。
  3. 群内授权管理员发送 /ban /spam 后,机器人会撤回命令消息本身;普通用户无权限命令不会被撤回,也不会执行。
  4. 如果只想看到私聊详情、不想群里有任何痕迹,依然可以直接私聊机器人发 /ban /spam /unban(向后完全兼容,行为不变)。

Q16:群里 /ban 闪屏 5 秒自动撤回,但闪屏没消失

原因:闪屏自动撤回靠 deleteMessage API,bot 必须有"删除消息"权限。如果 bot 不是群管理员或权限不足,闪屏会留在群里不撤回。 解决

  1. 进入目标群组 → 群设置 → 管理员 → 找到本机器人 → 打开"删除消息"权限。
  2. 主流程不受影响:加黑、踢人、私聊详情都已经完成,只是闪屏没自动撤回。
  3. 群管理员可以手动删那条闪屏消息。

Q17:群管理员 / 其他超管在群里发命令,他们自己收不到私聊详情

原因:本项目设计了"主人/副主人审计通知"机制 — 一旦配置 OWNER_IDS,群内命令详情不再发给每个触发管理员,而是按固定规则投递:

  • OWNER_IDS[0] 是主人,收到全部通知
  • OWNER_IDS[1..] 是副主人,只收到 /ban/spam 的加黑踢出通知
  • 其他管理员/超管在群里看到闪屏知道执行结果即可,不接收私聊详情
  • /ban /spam 通知详情会包含命令来源、作用范围、执行原因;群内执行会显示具体群名和群 ID,私聊执行会显示来源为私聊

如果你希望恢复"每个管理员各自收到自己的详情"老行为:

  • 不配置 OWNER_IDS(留空) → 退化为只发群闪屏,不发任何私聊详情(简化模式)
  • 想要"每个人都收自己的"老行为,本项目当前不支持。如果你需要,可以提 issue 提议加 BROADCAST_TO_TRIGGER 开关

Q18:配置了 OWNER_IDS 但主人/副主人收不到通知

原因:Telegram 平台规则 — bot 不能主动给从未交互过的用户发私信。如果你设了 OWNER_IDS 但对应账号从未私聊过 bot,通知投递会失败。

解决

  1. 主人/副主人账号分别私聊 bot 发一次 /start(任意消息都行),建立会话
  2. Worker 日志会显示 [审计通知] 私聊主人...失败:Forbidden: bot can't initiate conversation — 凡是看到这条日志,就是该账号没建立私聊
  3. 检查 OWNER_IDS 是否填了正确的纯数字 TGID(不要填 username)
  4. 临时禁用通知 → 把 OWNER_IDS 留空,Worker 自动退化

Q19:操作人标签会显示"主人"/"超级管理员"/"群管理员",怎么判断

原因:本项目按以下优先级判定操作人角色(用于审计通知标签):

  1. 如果操作人 TGID 等于 OWNER_IDS[0] → 标"主人"
  2. 如果操作人 TGID 在 OWNER_IDS[1..] → 标"副主人"
  3. 否则如果在 SUPER_ADMINS 名单 → 标"超级管理员"
  4. 否则按调用上下文兜底(chat_member 同步标"群管理员",命令鉴权后默认"管理员")

示例

  • 你自己(主人) /ban 123 → 私聊收到"🔔 主人操作通知"
  • 副主人 /spam/ban 123 → 主人和副主人收到加黑踢出通知
  • 名单中的超管 X /ban 123 → 主人收到"🔔 超级管理员操作通知\n操作人:X(超级管理员)"
  • 群管理员 Y /ban 123 → 主人收到"🔔 群管理员操作通知\n操作人:Y(群管理员)"

Q20:广告自动检测误杀了正常用户怎么办

原因:评分阈值太低,或某个正常话题词恰好命中词库。 解决(任选):

  1. 调高阈值AD_SCORE_THRESHOLD 设大一点(如 45),需要更多广告特征叠加才判定。
  2. 加白名单:把被误判的词加进 AD_WHITELIST(逗号分隔),该词命中不计分。例如币圈讨论群:AD_WHITELIST=usdt,承兑,搬砖
  3. 临时全关AD_FILTER_ENABLED=false 立即停用,排查后再开。
  4. 手动恢复被误杀的用户:私聊 bot 发 /unban 用户TGID 把他从黑名单移除(注意:踢出群后用户需要重新加群)。
  5. 查 Worker 日志的 [广告检测] 命中 行,能看到具体命中了哪些特征,据此调整。

Q21:广告漏检了(没杀掉)怎么调

原因:广告用了词库没有的变体,或评分没达阈值。 解决:

  1. 导入推荐词库:首次启用先私聊机器人发 /importdefault,把推荐词库写入 D1。
  2. 加自定义词:私聊发 /addword 分类 词,命中权重 +2(诈骗/金融/色情)或 +1(引流)。
  3. 调低阈值AD_SCORE_THRESHOLD 设为 2,更激进(但误杀风险上升)。
  4. 强特征最稳:带 t.me/+ 邀请链接、国际电话号的广告一定会被秒杀,无视阈值和词库。
  5. 持续遇到新变体就 /addword 加进去,改词立即生效不用重新部署。

Q22:刚启用广告检测,怎么初始化词库

原因:为隐私起见,代码内置词库默认为空(GitHub 公开仓库不出现敏感词),所以刚开 AD_FILTER_ENABLED=true 时,只有强特征(t.me 邀请链接/国际电话号)生效,关键词检测是空的。 解决(主人私聊机器人操作):

  1. 一键导入推荐词库:发 /importdefault,机器人把内置推荐词库(金融/色情/引流/诈骗四类)写入 D1,立即生效。
  2. 手动加词:/addword fraud 杀猪盘 刷信誉(分类可选,默认 general)。
  3. 查看现状:/listwords 看当前 D1 里有哪些词。
  4. 删词:/delword 某词(从所有分类删)。
  5. 注意:这些命令仅 OWNER_IDS 中的主人/副主人可用,且需在私聊机器人时发送(群里发会被静默忽略)。词库存 D1,改完即时生效,无需 wrangler deploy

Q23:怎么用 /spam 上报学习,让漏检的广告以后被自动杀

场景:有条广告词库没覆盖,这次漏检了。你想让机器人"记住"它,以后自动杀。 做法(主人操作):

  1. 在群里回复那条广告消息,发 /spam。机器人会:加黑+全群踢该用户、删消息,并把广告整句指纹学习入库
  2. 只学整句指纹:归一化后存库(去掉空格/标点/大小写/全半角差异)。以后任何人发相同广告(哪怕加了空格、标点、emoji 变体),都会被精确秒杀。
  3. 不再自动往词库加词(根因修复):旧版会把广告里自动提取的词写进词库 general,但这些词常夹带正常词,导致正常消息分数虚高被误判。现在提取的词只在回执里建议,你看了觉得合适再手动 /addword general 词
  4. 只有主人 /spam 会学习。普通群管理员 /spam 仍然加黑+踢,但不入库(避免管理员之间口径不一污染样本库)。
  5. 管理样本库:/listsamples 看学了哪些、/delsample 序号 删错学的、/clearsamples confirm 清空。
  6. 防误杀(分级匹配):归一化后 <6 字的太短样本不参与匹配;子串包含要求指纹和消息双方都 ≥16 字,短广告只能精确相等命中,绝不会因子串炸到"碰巧含这几个字"的正常长消息。
  7. 样本无人为上限(D1 单行存储容量充足,可存几十万条),不用担心存满。

Q24:GKY 等机器人把广告删了,我没法 /spam 回复,怎么学习这条广告

痛点: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),避免本群广告被别群消息挤出

Q25:隐藏指令对其他人真的完全无反应吗

是的,这是有意设计。OWNER_IDS 专属命令(/help /importdefault /addword /delword /listwords /listsamples /delsample /clearsamples /learn /recent /learnlast /admins)的鉴权规则:

  1. 一般隐藏指令只有 OWNER_IDS 中的主人/副主人能用/admins 更敏感,只允许 OWNER_IDS[0] 主人私聊使用。
  2. 非主人在群内:完全静默,连"权限不足"都不回,避免暴露命令存在。
  3. 非主人在私聊:回"权限不足",但不泄漏命令的具体功能(/help 对非主人也只回权限不足,不展开清单)。
  4. 不注册到命令菜单:这些命令不在 setMyCommands 里(只注册了 /unban /ban /spam /check /blacklist),所以用户在 Telegram 输入框敲 / 看不到它们,天然隐藏。
  5. 主人想随时查看全部隐藏指令:私聊/help;想查看当前主人/副主人/超级管理员名单:私聊/admins

Q26:正常链接(github/google 等)被误判成广告了怎么办

先搞清楚:链接被杀几乎都不是因为"它是链接",而是匹配上了之前学习过的样本指纹(看拦截通知的"判定依据",写"学习样本"就是这种)。本项目不会因为"消息含链接"就判广告——含链接的检测只在"链接是可疑短链"或"已学过的样本"时才触发。

本版已内置三层防护,正常链接绝不误杀:

  1. 正常域名白名单:github/google/youtube/gitlab/stackoverflow/bilibili 等几十个常见站点的链接永不被杀。想加自己的域名,主人私聊/addword whitelist 你的域名.com,即时生效不用重部署。
  2. 含 URL 的样本只精确匹配:学过某条广告链接后,只有一字不差的同一条会被杀,同域名其它路径的正常链接绝不连带误伤
  3. 可疑短链才加分:只有 bit.ly / tinyurl / b23.tv 这类短链才单独加分,且需配合其它特征。

如果某条链接还是被误杀了(说明它被误学进了样本库):

  1. 主人私聊发 /listsamples 查看已学样本,找到那条链接的指纹序号。
  2. /delsample 序号(或 /delsample 域名关键词)删掉这条误学样本,立即止血。
  3. 把该域名永久加白:/addword whitelist 域名.com,以后该域名所有链接都放行。
  4. 查 Worker 日志 [广告检测] 命中 行,能看到具体命中了哪条特征,据此判断是样本还是词库的问题。

Q27:广告号发的"联系人名片"(假钞交流群那种)为什么以前杀不掉

原因:广告号常用分享联系人名片(Contact)的形式发广告——名片显示名写"假钞交流群"、电话填国际号、还带"发送信息/添加好友"按钮。这种消息的 text/caption空的,广告内容全藏在 contact 字段里。旧版检测只读文字消息,完全漏掉名片,所以名片广告只被群里别的 bot 删了消息,本项目不加黑不踢。

本版已修:检测会把名片内容(显示名/电话号/vcard)一并识别,任一命中即杀:

  1. 名片显示名命中词库 → 直接秒杀(强特征,不用凑分)。名字含"假钞/承兑/约炮"等任意词库词,立即删+黑+全群踢。正常人名片名字是"张三/小明/John",几乎不可能命中,误杀面极低。
  2. 名片含国际电话号(带 +国家码,排除 +86 中国号)→ 强特征直杀。截图里 +1 870 337 4069 就属于这种,不依赖词库。
  3. 正常分享本地联系人不误杀:中国号(+86)+ 名字无敏感词的名片只 +1 分,不达阈值(默认 3),正常用户分享联系人不受影响。
  4. 名片广告也会被缓存,可用 /recent 看到、/learnlast 学习指纹。

前提:① AD_FILTER_ENABLED=true 开启检测;② 想靠"显示名敏感词"判定的,先 /importdefault 导入词库或 /addword 加词(纯国际电话号的名片不依赖词库,直接强特征杀)。

Q28:能不能识别名片头像/图片里的广告文字

当前不支持,这是技术取舍,如实说明:

  1. 名片(contact)拿不到头像:Telegram 的 message.contact 字段只有名字、电话、user_id、vcard,没有头像图。你截图里那个"一手假钞"红色图标是 vCard 内嵌的 logo 或名片预览占位图,Bot API 取不到原图。
  2. Worker 跑不了 OCR:识别图片里的字需要 OCR(光学字符识别),Cloudflare Worker 没有图像处理能力、CPU 时间也只有几十毫秒,塞不下。要做必须接外部 OCR API(如 Cloudflare Workers AI 图像模型),需单独开通、付费、每张图增加几百毫秒延迟。
  3. "发图片让 AI 学习"的误区:开发时 AI 能看图,但部署后运行的是独立的 Cloudflare Worker,它不是 AI 本体。线上 bot 要"看懂图"必须自己接 OCR 服务,不是开发时喂几张图就能学会的。
  4. 当前策略:把基于文字的检测(名片名字 / 电话号 / 词库 / 学习样本 / 链接)做到极致,已能覆盖绝大多数名片广告——因为广告号为了让人能搜到/加到,名字和电话几乎一定是文字可读的,纯靠一张图片做广告反而没法引流。
  5. 若将来确实需要图片 OCR,可作为独立增量功能评估接入 Workers AI,对"用户直接发的图片消息"做识别(名片头像受 API 限制仍可能拿不到)。

License

本项目沿用原项目 MIT License。

原作者:CMLiussss — Copyright (c) 2026 原项目:CF-Workers-TGUnbanBot

再次特别鸣谢原作者 CMLiussss 设计的源代码支持 🙏

详见 LICENSE 文件。

About

Telegram 群组自助解封机器人 | 基于 Cloudflare Workers + D1 | 多群管理 / 广告检测 / 黑名单导出 / GKY联查 / 314条离线测试 | Fork of CF-Workers-TGUnbanBot【项目取用cmliu/TGUnbanBot】

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors