ModeraciónAnti-spamAutoMod8 min de lectura

Bot de moderación automática

Sistema anti-spam, filtro de palabras, protección anti-raid, sistema de warns/mute/ban y audit logs.


Arquitectura del bot de moderación

Un bot de moderación completo necesita: detección automática de infracciones, sistema de sanciones progresivas y registro de acciones.

Paso 1: Sistema anti-spam

javascript
const spamMap = new Map();

client.on('messageCreate', async message => {
  if (message.author.bot) return;

  const key = `${message.guild.id}-${message.author.id}`;
  const userData = spamMap.get(key) || { count: 0, lastMessage: 0, warnings: 0 };

  const now = Date.now();
  if (now - userData.lastMessage < 2000) {
    userData.count++;
  } else {
    userData.count = 1;
  }
  userData.lastMessage = now;
  spamMap.set(key, userData);

  // 5 mensajes en menos de 10 segundos = spam
  if (userData.count >= 5) {
    await message.member.timeout(60000, 'Anti-spam: mensajes muy rápidos');
    await message.channel.send(`${message.author} silenciado por spam.`);
    userData.count = 0;
    spamMap.set(key, userData);
  }
});

// Limpiar el mapa cada 30 segundos
setInterval(() => {
  const now = Date.now();
  for (const [key, data] of spamMap) {
    if (now - data.lastMessage > 10000) spamMap.delete(key);
  }
}, 30000);

Paso 2: Filtro de palabras

javascript
const bannedWords = ['palabra1', 'palabra2', 'insulto'];
const bannedPatterns = [
  /discord\.gg\/[a-zA-Z0-9]+/i,  // Invitaciones
  /https?:\/\/(?!discord\.com)[^\s]+/i  // Links externos
];

client.on('messageCreate', async message => {
  if (message.author.bot) return;
  if (message.member.permissions.has('ManageMessages')) return;

  const content = message.content.toLowerCase();

  const hasBannedWord = bannedWords.some(word => content.includes(word));
  const hasBannedPattern = bannedPatterns.some(pattern => pattern.test(content));

  if (hasBannedWord || hasBannedPattern) {
    await message.delete();
    await message.channel.send({
      content: `${message.author}, tu mensaje fue eliminado por contenido no permitido.`,
    }).then(msg => setTimeout(() => msg.delete(), 5000));

    await addWarning(message.guild.id, message.author.id, 'Contenido prohibido');
  }
});

Paso 3: Protección anti-raid

javascript
const joinTracker = new Map();

client.on('guildMemberAdd', async member => {
  const guildId = member.guild.id;
  const joins = joinTracker.get(guildId) || [];
  joins.push(Date.now());

  // Limpiar joins viejos (últimos 10 segundos)
  const recent = joins.filter(t => Date.now() - t < 10000);
  joinTracker.set(guildId, recent);

  // Si entran más de 10 usuarios en 10 segundos = raid
  if (recent.length >= 10) {
    // Activar modo verificación
    await member.guild.setVerificationLevel(4); // VERY_HIGH
    const logChannel = member.guild.channels.cache.find(c => c.name === 'mod-logs');
    if (logChannel) {
      await logChannel.send('🚨 **RAID DETECTADO** — Verificación elevada automáticamente.');
    }
  }
});

Paso 4: Sistema de warns progresivo

javascript
async function addWarning(guildId, userId, reason) {
  // Guardar en base de datos
  const warns = await db.addWarn(guildId, userId, reason);
  const totalWarns = warns.length;

  const guild = client.guilds.cache.get(guildId);
  const member = await guild.members.fetch(userId);

  // Sanciones progresivas
  if (totalWarns >= 5) {
    await member.ban({ reason: '5 warns acumulados' });
  } else if (totalWarns >= 3) {
    await member.timeout(24 * 60 * 60 * 1000, '3 warns acumulados');
  } else if (totalWarns >= 2) {
    await member.timeout(60 * 60 * 1000, '2 warns acumulados');
  }

  return totalWarns;
}

Paso 5: Comando /warn

javascript
new SlashCommandBuilder()
  .setName('warn')
  .setDescription('Advertir a un usuario')
  .addUserOption(opt => opt.setName('usuario').setRequired(true))
  .addStringOption(opt => opt.setName('razon').setRequired(true))
  .setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers);

// Handler
if (commandName === 'warn') {
  const target = interaction.options.getUser('usuario');
  const reason = interaction.options.getString('razon');
  const total = await addWarning(interaction.guild.id, target.id, reason);

  await interaction.reply(`⚠️ ${target.tag} fue advertido. Total: ${total}/5\nRazón: ${reason}`);
}

Recomendaciones

  • Excluí moderadores del anti-spam y filtros
  • Logueá todas las acciones de moderación en un canal dedicado
  • Permití a los mods revisar y eliminar warns
  • Configurá umbrales ajustables por servidor
  • Implementá un comando /case para ver el historial de un usuario

¿Te resultó útil esta guía?