Files
tg-spam-guard/handlers/spam.py
T
2026-07-06 19:26:00 +08:00

101 lines
3.3 KiB
Python

"""垃圾消息检测 handler"""
import asyncio
import logging
from datetime import datetime, timedelta
from telegram import Update
from telegram.ext import ContextTypes, MessageHandler, filters
import config
from db.models import Message, Ban, Action
from services.spam_detector import detect
logger = logging.getLogger("spam_guard")
# 简单的防刷屏缓存:user_id -> [(timestamp, msg_id)]
_flood_cache: dict[int, list] = {}
async def handle_message(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""处理群消息:防刷屏 + 垃圾检测"""
msg = update.effective_message
if not msg or not msg.text:
return
user = update.effective_user
if not user or user.is_bot:
return
username = user.username or ""
first_name = user.first_name or ""
text = msg.text
# === 防刷屏 ===
now = datetime.now().timestamp()
if user.id not in _flood_cache:
_flood_cache[user.id] = []
_flood_cache[user.id].append((now, msg.message_id))
# 清理过期
_flood_cache[user.id] = [
(t, mid) for t, mid in _flood_cache[user.id]
if now - t < config.RATE_LIMIT_WINDOW
]
if len(_flood_cache[user.id]) > config.RATE_LIMIT_MESSAGES:
try:
await msg.delete()
except Exception:
pass
logger.warning(f"⚡ 防刷屏: @{username} ({user.id}) {len(_flood_cache[user.id])}条/{config.RATE_LIMIT_WINDOW}s")
return
# 记录消息
await Message.create(
msg_id=msg.message_id,
chat_id=update.effective_chat.id,
user_id=user.id,
username=username,
first_name=first_name,
text=text[:500],
)
# === 垃圾检测 ===
is_spam, reason = await detect(text, username, first_name)
if is_spam:
logger.warning(f"🚨 垃圾消息 [{username}]: {reason}")
# 删消息
try:
await msg.delete()
await Action.create(action="DELETE", user_id=user.id, username=username, details={"reason": reason, "text": text[:120]})
except Exception as e:
logger.error(f"❌ 删除消息失败: {e}")
# 封禁
try:
unban_at = datetime.now() + timedelta(minutes=config.BAN_DURATION_MINUTES)
until_date = int(unban_at.timestamp())
await update.effective_chat.ban_member(user_id=user.id, until_date=until_date)
ban_record = {
"user_id": user.id,
"username": username,
"first_name": first_name,
"reason": reason,
"method": "auto",
"duration_minutes": config.BAN_DURATION_MINUTES,
"unban_at": unban_at,
}
await Ban.create(**ban_record)
await Action.create(action="BAN", user_id=user.id, username=username, details={"reason": reason})
logger.info(f"🔨 已封禁 [{username}] {config.BAN_DURATION_MINUTES} 分钟")
except Exception as e:
logger.error(f"❌ 封禁失败: {e}")
# 标记为垃圾
await Message.filter(msg_id=msg.message_id).update(is_spam=True, spam_reason=reason)
def register_spam(app):
app.add_handler(MessageHandler(filters.TEXT & filters.ChatType.GROUPS & ~filters.COMMAND, handle_message))