Correction complète des systèmes anti-spam et anti-liens + optimisations des performances et de la mémoire
This commit is contained in:
parent
59e738c0d4
commit
343a4f879c
4 changed files with 434 additions and 110 deletions
|
|
@ -2,154 +2,184 @@ import discord
|
|||
from discord.ext import commands
|
||||
import json
|
||||
import os
|
||||
import asyncio
|
||||
from datetime import datetime
|
||||
from collections import deque
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# Chemins des fichiers
|
||||
SETTINGS_FILE = "data/security_settings.json"
|
||||
WHITELIST_FILE = "data/whitelist.json"
|
||||
|
||||
# Cache TTL en secondes (5 secondes pour avoir une réactivité acceptable)
|
||||
CACHE_TTL = 5
|
||||
|
||||
# Triggers pour détection de liens
|
||||
LINK_TRIGGERS = ("discord.gg/", "http://", "https://", "www.")
|
||||
|
||||
class AntiSpam(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
# Compteurs pour le Spam
|
||||
# Optimisation: deque avec maxlen pour O(1) au lieu de O(n) list filtering
|
||||
self.message_counts = {}
|
||||
self.spam_warnings = {}
|
||||
|
||||
# Compteurs pour les Liens
|
||||
self.link_warnings = {}
|
||||
# Cache avec timestamps pour éviter la lecture fichier à chaque message
|
||||
self._settings_cache = {} # {guild_id: (timestamp, settings_dict)}
|
||||
self._whitelist_cache = {} # {guild_id: (timestamp, whitelist_set)}
|
||||
|
||||
def _get_cached_settings(self, guild_id):
|
||||
"""Récupère les paramètres avec cache (TTL de 5 secondes)"""
|
||||
now = discord.utils.utcnow().timestamp()
|
||||
cached = self._settings_cache.get(guild_id)
|
||||
|
||||
if cached:
|
||||
cached_time, settings = cached
|
||||
if now - cached_time < CACHE_TTL:
|
||||
return settings
|
||||
|
||||
# Cache expiré ou absent - lire le fichier
|
||||
try:
|
||||
if os.path.exists(SETTINGS_FILE):
|
||||
with open(SETTINGS_FILE, "r", encoding='utf-8') as f:
|
||||
all_settings = json.load(f)
|
||||
settings = all_settings.get(str(guild_id), {})
|
||||
else:
|
||||
settings = {}
|
||||
except:
|
||||
settings = {}
|
||||
|
||||
self._settings_cache[guild_id] = (now, settings)
|
||||
return settings
|
||||
|
||||
def _get_cached_whitelist(self, guild_id):
|
||||
"""Récupère la whitelist avec cache (TTL de 5 secondes)"""
|
||||
now = discord.utils.utcnow().timestamp()
|
||||
cached = self._whitelist_cache.get(guild_id)
|
||||
|
||||
if cached:
|
||||
cached_time, whitelist_set = cached
|
||||
if now - cached_time < CACHE_TTL:
|
||||
return whitelist_set
|
||||
|
||||
# Cache expiré ou absent - lire le fichier
|
||||
whitelist_set = set()
|
||||
try:
|
||||
if os.path.exists(WHITELIST_FILE):
|
||||
with open(WHITELIST_FILE, "r", encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
server_id_str = str(guild_id)
|
||||
whitelist_ids = data.get(server_id_str, [])
|
||||
whitelist_set = set(str(uid) for uid in whitelist_ids)
|
||||
except:
|
||||
pass
|
||||
|
||||
self._whitelist_cache[guild_id] = (now, whitelist_set)
|
||||
return whitelist_set
|
||||
|
||||
def is_whitelisted(self, guild_id, user_id):
|
||||
"""Vérifie si l'utilisateur est protégé (Whitelist ou Owner)"""
|
||||
# 1. Le propriétaire est toujours whitelist
|
||||
"""Vérifie l'immunité (Propriétaire ou Whitelist JSON avec cache)"""
|
||||
guild = self.bot.get_guild(guild_id)
|
||||
if guild and user_id == guild.owner_id:
|
||||
return True
|
||||
|
||||
# 2. Vérification fichier Whitelist
|
||||
if not os.path.exists(WHITELIST_FILE): return False
|
||||
try:
|
||||
with open(WHITELIST_FILE, "r", encoding='utf-8') as f:
|
||||
data = json.load(f)
|
||||
return user_id in data.get(str(guild_id), [])
|
||||
except: return False
|
||||
# Utilisation du cache whitelist
|
||||
whitelist = self._get_cached_whitelist(guild_id)
|
||||
return str(user_id) in whitelist
|
||||
|
||||
@commands.Cog.listener()
|
||||
async def on_message(self, message):
|
||||
if message.author.bot or not message.guild: return
|
||||
|
||||
# --- 1. IMMUNITÉ TOTALE ---
|
||||
# Si Whitelisté, on ignore tout (Spam et Liens)
|
||||
if self.is_whitelisted(message.guild.id, message.author.id):
|
||||
# 1. Filtres de base (early return pour performance)
|
||||
if message.author.bot or not message.guild:
|
||||
return
|
||||
|
||||
# --- 2. CHARGEMENT CONFIG ---
|
||||
if not os.path.exists(SETTINGS_FILE): return
|
||||
with open(SETTINGS_FILE, "r", encoding='utf-8') as f:
|
||||
settings = json.load(f).get(str(message.guild.id), {})
|
||||
guild_id = message.guild.id
|
||||
user_id = message.author.id
|
||||
|
||||
# =================================================================
|
||||
# MODULE ANTI-LINK (3 Avertissements -> Mute)
|
||||
# =================================================================
|
||||
if settings.get("anti_link"):
|
||||
# Liste des déclencheurs interdits
|
||||
forbidden = ["discord.gg/", "http://", "https://", "www."]
|
||||
# 2. VÉRIFICATION WHITELIST (Immunité totale)
|
||||
if self.is_whitelisted(guild_id, user_id):
|
||||
return
|
||||
|
||||
# On vérifie si le message contient un lien interdit
|
||||
if any(trigger in message.content.lower() for trigger in forbidden):
|
||||
# Si l'auteur a la permission de gérer les messages, on laisse passer (optionnel, sinon retirer cette ligne)
|
||||
if not message.author.guild_permissions.manage_messages:
|
||||
await self.handle_link_violation(message)
|
||||
return # On arrête là, pas besoin de vérifier le spam si le message est supprimé
|
||||
# --- LECTURE CACHÉ (dynamique mais rapide) ---
|
||||
settings = self._get_cached_settings(guild_id)
|
||||
|
||||
# =================================================================
|
||||
# MODULE ANTI-SPAM (3 Avertissements -> Mute)
|
||||
# =================================================================
|
||||
if settings.get("anti_spam"):
|
||||
user_id = message.author.id
|
||||
now = datetime.now().timestamp()
|
||||
# --- TEST ANTI-LIENS ---
|
||||
# Bloque tout le monde sauf whitelist ET manage_messages
|
||||
anti_link_enabled = settings.get("anti_link", False) if settings else False
|
||||
has_perm = message.author.guild_permissions.manage_messages
|
||||
if anti_link_enabled and not has_perm:
|
||||
content_lower = message.content.lower()
|
||||
if any(trigger in content_lower for trigger in LINK_TRIGGERS):
|
||||
await self.handle_violation(message, "link")
|
||||
return
|
||||
|
||||
# Sortir si pas de settings
|
||||
if not settings:
|
||||
return
|
||||
|
||||
# --- TEST ANTI-SPAM (deque pour O(1)) ---
|
||||
if settings.get("anti_spam") is True:
|
||||
now = discord.utils.utcnow().timestamp()
|
||||
|
||||
# Initialiser ou récupérer le deque pour cet utilisateur
|
||||
if user_id not in self.message_counts:
|
||||
self.message_counts[user_id] = []
|
||||
# maxlen=10 suffit pour la fenêtre de 5 secondes avec seuil typique
|
||||
self.message_counts[user_id] = deque(maxlen=10)
|
||||
|
||||
self.message_counts[user_id].append(now)
|
||||
# Fenêtre de temps : 5 secondes
|
||||
self.message_counts[user_id] = [t for t in self.message_counts[user_id] if now - t < 5]
|
||||
user_deque = self.message_counts[user_id]
|
||||
user_deque.append(now)
|
||||
|
||||
# Seuil dynamique (défaut: 5)
|
||||
limit = settings.get("spam_threshold", 5)
|
||||
# Nettoyer les timestamps expirés (plus vieux que 5 secondes)
|
||||
# Le deque supprime automatiquement les anciens éléments quand il dépasse maxlen
|
||||
# Mais on doit aussi filtrer par temps pour être précis
|
||||
while user_deque and now - user_deque[0] >= 5:
|
||||
user_deque.popleft()
|
||||
|
||||
if len(self.message_counts[user_id]) > limit:
|
||||
await self.handle_spam_violation(message)
|
||||
|
||||
|
||||
# --- GESTION DES VIOLATIONS LIENS ---
|
||||
async def handle_link_violation(self, message):
|
||||
try:
|
||||
await message.delete()
|
||||
except:
|
||||
pass # Message déjà supprimé ou manque de perms
|
||||
threshold = settings.get("spam_threshold", 5)
|
||||
if len(user_deque) > threshold:
|
||||
await self.handle_violation(message, "spam")
|
||||
|
||||
async def handle_violation(self, message, type_violation):
|
||||
user_id = message.author.id
|
||||
warnings = self.link_warnings.get(user_id, 0) + 1
|
||||
self.link_warnings[user_id] = warnings
|
||||
|
||||
if warnings <= 3:
|
||||
if type_violation == "link":
|
||||
try: await message.delete()
|
||||
except: pass
|
||||
self.link_warnings[user_id] = self.link_warnings.get(user_id, 0) + 1
|
||||
current_warns = self.link_warnings[user_id]
|
||||
reason = "Envoi de liens interdits"
|
||||
else:
|
||||
try: await message.channel.purge(limit=5, check=lambda m: m.author == message.author)
|
||||
except: pass
|
||||
self.spam_warnings[user_id] = self.spam_warnings.get(user_id, 0) + 1
|
||||
current_warns = self.spam_warnings[user_id]
|
||||
reason = "Spam excessif"
|
||||
# Réinitialiser le deque après spam détecté
|
||||
self.message_counts[user_id] = deque(maxlen=10)
|
||||
|
||||
if current_warns <= 3:
|
||||
embed = discord.Embed(
|
||||
title="🔗 Liens Interdits",
|
||||
description=f"{message.author.mention}, les liens ne sont pas autorisés.\n**Avertissement : {warnings}/3**",
|
||||
title="🛡️ Sécurité Kuby",
|
||||
description=f"{message.author.mention}, {reason}.\n**Avertissement : {current_warns}/3**",
|
||||
color=0xFFA500
|
||||
)
|
||||
await message.channel.send(embed=embed, delete_after=5)
|
||||
else:
|
||||
await self.sanction_user(message, "Publication de liens interdits")
|
||||
self.link_warnings[user_id] = 0 # Reset après sanction
|
||||
await self.apply_mute(message, reason)
|
||||
if type_violation == "link": self.link_warnings[user_id] = 0
|
||||
else: self.spam_warnings[user_id] = 0
|
||||
|
||||
# --- GESTION DES VIOLATIONS SPAM ---
|
||||
async def handle_spam_violation(self, message):
|
||||
user_id = message.author.id
|
||||
|
||||
# Nettoyage visuel du spam
|
||||
async def apply_mute(self, message, reason):
|
||||
try:
|
||||
await message.channel.purge(limit=5, check=lambda m: m.author == message.author)
|
||||
except: pass
|
||||
|
||||
warnings = self.spam_warnings.get(user_id, 0) + 1
|
||||
self.spam_warnings[user_id] = warnings
|
||||
|
||||
# Reset le compteur de messages pour éviter le spam d'avertissements
|
||||
self.message_counts[user_id] = []
|
||||
|
||||
if warnings <= 3:
|
||||
embed = discord.Embed(
|
||||
title="🛡️ Anti-Spam",
|
||||
description=f"{message.author.mention}, veuillez cesser de spammer.\n**Avertissement : {warnings}/3**",
|
||||
color=0xFFA500
|
||||
)
|
||||
await message.channel.send(embed=embed, delete_after=5)
|
||||
else:
|
||||
await self.sanction_user(message, "Spam excessif")
|
||||
self.spam_warnings[user_id] = 0 # Reset après sanction
|
||||
|
||||
# --- SANCTION COMMUNE (TIMEOUT 5 MIN) ---
|
||||
async def sanction_user(self, message, reason):
|
||||
try:
|
||||
# Durée : 5 minutes
|
||||
duration = discord.utils.utcnow() + asyncio.timedelta(minutes=5)
|
||||
|
||||
# Application du Timeout (Exclusion temporaire)
|
||||
await message.author.timeout(duration, reason=f"Kuby Security: {reason} (3 Warns)")
|
||||
until = discord.utils.utcnow() + timedelta(minutes=5)
|
||||
await message.author.timeout(until, reason=f"Kuby Security: {reason} (3 Warns)")
|
||||
|
||||
embed = discord.Embed(
|
||||
title="⛔ Exclusion Temporaire",
|
||||
description=f"**Utilisateur :** {message.author.mention}\n**Durée :** 5 minutes\n**Raison :** {reason} (Limite atteinte).",
|
||||
description=f"**Membre :** {message.author.mention}\n**Durée :** 5 minutes\n**Raison :** {reason} répétitif.",
|
||||
color=0xFF0000
|
||||
)
|
||||
await message.channel.send(embed=embed)
|
||||
|
||||
except discord.Forbidden:
|
||||
await message.channel.send("⚠️ Je n'ai pas la permission d'exclure ce membre (Vérifiez ma hiérarchie).")
|
||||
except Exception as e:
|
||||
print(f"Erreur Sanction: {e}")
|
||||
print(f"Erreur lors de la sanction : {e}")
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(AntiSpam(bot))
|
||||
10
data/logs/member_events_2026-01-01.json
Normal file
10
data/logs/member_events_2026-01-01.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-01-01T22:00:26.255907",
|
||||
"event_type": "member_join",
|
||||
"member_id": 1456390746167967932,
|
||||
"member_name": "juibu_66388",
|
||||
"member_discriminator": "0",
|
||||
"member_avatar": null
|
||||
}
|
||||
]
|
||||
284
data/logs/messages_2026-01-01.json
Normal file
284
data/logs/messages_2026-01-01.json
Normal file
|
|
@ -0,0 +1,284 @@
|
|||
[
|
||||
{
|
||||
"timestamp": "2026-01-01T21:05:28.276062",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456377795595730994,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:12:06.156108",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456379476211531970,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:12:06.462625",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456379478606348421,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "gg",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:12:12.104726",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456379484264595700,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:35:44.759055",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456385391564296297,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:35:51.064634",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456385392482844682,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:40:18.016792",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456386513947463855,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:40:21.147093",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456386515096703242,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:40:24.322926",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456386516439007288,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:43:53.352930",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456387431472435231,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:44:15.896248",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456387423477956670,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "g",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:44:32.743792",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456387525080776788,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "https://github.com/Omega-Kube/Kuby",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:44:43.533530",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456387651883237437,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "https://github.com/Omega-Kube/Kuby",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T21:51:23.069501",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456389356301582459,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 971446412690722826,
|
||||
"author_name": "gameurpro12",
|
||||
"author_roles": [
|
||||
1369669999345537145,
|
||||
1369669999366770723,
|
||||
1403041729330024508,
|
||||
1369669999366770726
|
||||
],
|
||||
"content": "[DEBUG] anti_link_enabled: True, settings: {'anti_spam': True, 'anti_perm': True, 'anti_salon': True, 'anti_raid': True, 'anti_nuke': True, 'anti_link': True, 'anti_mention': True, 'verification_enabled': True, 'spam_threshold': 5, 'raid_threshold': 3, 'nuke_threshold': 3, 'log_channel_id': 1396088860412346428, 'lockdown_enabled': False, 'auto_ban': True, 'webhook_protection': True, 'mass_delete_protection': True, 'invite_filter': True, 'file_scanning': True, 'ai_moderation': True, 'channel_block_enabled': False, 'server_logs': True, 'anti_channel_delete': True, 'anti_role_create': True}",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
},
|
||||
{
|
||||
"timestamp": "2026-01-01T22:01:31.237385",
|
||||
"event_type": "deleted",
|
||||
"message_id": 1456391913694433361,
|
||||
"channel_id": 1369669999677145098,
|
||||
"channel_name": "╭💬・général",
|
||||
"author_id": 1456390746167967932,
|
||||
"author_name": "juibu_66388",
|
||||
"author_roles": [
|
||||
1369669999345537145
|
||||
],
|
||||
"content": "https://github.com/Omega-Kube/Kuby",
|
||||
"attachments": [],
|
||||
"embeds": [],
|
||||
"details": {}
|
||||
}
|
||||
]
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
"anti_link": true,
|
||||
"anti_mention": true,
|
||||
"verification_enabled": true,
|
||||
"spam_threshold": 1,
|
||||
"spam_threshold": 5,
|
||||
"raid_threshold": 3,
|
||||
"nuke_threshold": 3,
|
||||
"log_channel_id": 1396088860412346428,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue