168 lines
6.1 KiB
Python
168 lines
6.1 KiB
Python
import logging
|
|
import asyncio
|
|
import aiohttp
|
|
import os
|
|
from datetime import datetime
|
|
from dotenv import load_dotenv
|
|
from telegram import Update
|
|
from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler, MessageHandler, filters
|
|
|
|
# Chargement des variables d'environnement
|
|
load_dotenv()
|
|
|
|
# Configuration du logging
|
|
logging.basicConfig(
|
|
format='%(asctime)s - %(levelname)s - %(message)s',
|
|
level=logging.INFO
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# Config NocoDB & Telegram
|
|
NOCODB_BASE_URL = os.getenv("NOCODB_BASE_URL")
|
|
TABLE_BANNIES_ID = os.getenv("TABLE_BANNIES_ID")
|
|
TABLE_HISTORY_ID = os.getenv("TABLE_HISTORY_ID")
|
|
NOCODB_TOKEN = os.getenv("NOCODB_TOKEN")
|
|
API_TOKEN = os.getenv("API_TOKEN")
|
|
|
|
if not API_TOKEN:
|
|
logger.error("❌ API_TOKEN manquant dans le fichier .env !")
|
|
exit(1)
|
|
|
|
# Liste globale des mots bannis
|
|
BANNED_KEYWORDS = []
|
|
|
|
async def fetch_banned_keywords():
|
|
"""Récupère les mots depuis NocoDB"""
|
|
global BANNED_KEYWORDS
|
|
url = f"{NOCODB_BASE_URL}{TABLE_BANNIES_ID}/records"
|
|
headers = {"xc-token": NOCODB_TOKEN}
|
|
params = {"limit": 100}
|
|
|
|
try:
|
|
async with aiohttp.ClientSession() as session:
|
|
async with session.get(url, headers=headers, params=params) as response:
|
|
if response.status == 200:
|
|
data = await response.json()
|
|
new_keywords = [
|
|
row["MotBannies"].strip().lower()
|
|
for row in data.get("list", [])
|
|
if row.get("MotBannies")
|
|
]
|
|
BANNED_KEYWORDS = new_keywords
|
|
logger.info(f"✅ Liste des mots bannis mise à jour ({len(BANNED_KEYWORDS)} mots)")
|
|
return True
|
|
else:
|
|
logger.error(f"❌ Erreur NocoDB : {response.status}")
|
|
return False
|
|
except Exception as e:
|
|
logger.error(f"❌ Erreur connexion NocoDB : {e}")
|
|
return False
|
|
|
|
async def log_to_history(update: Update, action: str):
|
|
"""Enregistre l'action dans la table History de NocoDB"""
|
|
url = f"{NOCODB_BASE_URL}{TABLE_HISTORY_ID}/records"
|
|
headers = {"xc-token": NOCODB_TOKEN}
|
|
|
|
# On récupère l'objet message ou channel_post
|
|
msg = update.message or update.channel_post
|
|
if not msg:
|
|
return
|
|
|
|
# Identification de l'auteur
|
|
user_name = "Utilisateur Inconnu"
|
|
user_id = "N/A"
|
|
logger.info(f"🎯 get info : msg '{msg}'")
|
|
if msg.from_user:
|
|
# Cas classique (Groupe/Privé)
|
|
user_full_name = msg.from_user.full_name
|
|
user_username = msg.from_user.username
|
|
user_name = f"{user_full_name} (@{user_username or 'N/A'})"
|
|
user_id = str(msg.from_user.id)
|
|
|
|
elif msg.author_signature:
|
|
# Cas Canal avec signature
|
|
user_name = f"Admin: {msg.author_signature}"
|
|
user_id = "Canal (Anonyme)"
|
|
elif msg.sender_chat:
|
|
# Cas Canal ou Groupe anonyme
|
|
user_name = f"Chat: {msg.sender_chat.title}"
|
|
user_id = str(msg.sender_chat.id)
|
|
|
|
payload = {
|
|
"Title": f"Mod-{datetime.now().strftime('%H%M%S')}",
|
|
"Message": msg.text or "[Média]",
|
|
"User": user_name,
|
|
"UserID": user_id,
|
|
"Timestamp": datetime.now().isoformat(),
|
|
"Action": action,
|
|
"Channel": f"{msg.chat.title or 'Privé'} ({msg.chat.id})"
|
|
}
|
|
|
|
try:
|
|
async with aiohttp.ClientSession() as session:
|
|
async with session.post(url, headers=headers, json=payload) as response:
|
|
if response.status in [200, 201]:
|
|
logger.info(f"📊 Historique enregistré pour {user_name}")
|
|
else:
|
|
logger.error(f"❌ Échec archivage ({response.status})")
|
|
except Exception as e:
|
|
logger.error(f"❌ Erreur lors de l'archivage : {e}")
|
|
|
|
async def filter_logic(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|
"""Analyse les messages et applique la modération"""
|
|
msg = update.message or update.channel_post
|
|
if not msg or not msg.text:
|
|
return
|
|
|
|
text_lower = msg.text.lower()
|
|
|
|
# Log radar pour la console
|
|
source = "Inconnu"
|
|
if msg.from_user:
|
|
source = f"@{msg.from_user.username or msg.from_user.full_name}"
|
|
elif msg.chat:
|
|
source = f"ID:{msg.chat.id} ({msg.chat.title})"
|
|
|
|
logger.info(f"📩 Message de [{source}] : {msg.text}")
|
|
|
|
for word in BANNED_KEYWORDS:
|
|
if word in text_lower:
|
|
try:
|
|
# Suppression du message
|
|
await msg.delete()
|
|
# Avertissement (dans les groupes/privé uniquement)
|
|
if update.message:
|
|
await context.bot.send_message(
|
|
chat_id=msg.chat.id,
|
|
text="🚫 Mot interdit détecté et supprimé."
|
|
)
|
|
|
|
logger.info(f"🎯 Action : Suppression du mot '{word}'")
|
|
await log_to_history(update, f"Suppression (Mot: {word})")
|
|
except Exception as e:
|
|
logger.error(f"❌ Erreur lors de la modération : {e}")
|
|
return
|
|
|
|
async def refresh(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|
"""Rafraîchit la liste des mots depuis la commande /refresh"""
|
|
if await fetch_banned_keywords():
|
|
await update.message.reply_text(f"✅ Liste mise à jour ! {len(BANNED_KEYWORDS)} mots actifs.")
|
|
else:
|
|
await update.message.reply_text("❌ Échec du rafraîchissement.")
|
|
|
|
async def post_init(application):
|
|
"""Effectue les tâches d'initialisation après le démarrage du bot"""
|
|
await fetch_banned_keywords()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
# Initialisation de l'application
|
|
application = ApplicationBuilder().token(API_TOKEN).post_init(post_init).build()
|
|
|
|
# Ajout des handlers
|
|
application.add_handler(CommandHandler("refresh", refresh))
|
|
# Filtre pour capturer tous les messages textes (Groupes ET Canaux)
|
|
application.add_handler(MessageHandler(filters.TEXT & (~filters.COMMAND), filter_logic))
|
|
|
|
logger.info("🚀 Bot démarré avec python-telegram-bot...")
|
|
application.run_polling() |