ChimBot includes a periodic task system that automatically sends random messages to a designated spam channel at scheduled intervals. This feature uses Discord.py’s @tasks.loop() decorator to run recurring tasks.
The periodic spam system is disabled by default and must be manually activated using the $activarspam command.
The spam_periodico() task runs on a scheduled interval:
main.py
@tasks.loop(hours=12) # Executes every 12 hours (2 times per day)async def spam_periodico(): """Envía un mensaje random al canal de spam periódicamente""" try: canal = bot.get_channel(CANAL_SPAM_ID) if canal: mensaje = obtener_mensaje_sin_repetir() await canal.send(mensaje) print(f"[{datetime.now().strftime('%H:%M:%S')}] Mensaje automático enviado: {mensaje[:50]}...") except Exception as e: print(f"Error en spam_periodico: {e}")
# List of random messagesmensajes_random = [ # Example: "your message here", # Example: "another message",]# System to avoid repetitionmensajes_disponibles = []
def obtener_mensaje_sin_repetir(): """Obtiene un mensaje random sin repetir hasta que se agoten todos""" global mensajes_disponibles # If no messages configured, return error message if not mensajes_random: return "No hay mensajes configurados. Agrega mensajes a la lista 'mensajes_random' en el código." # If all messages used, reset the list if not mensajes_disponibles: mensajes_disponibles = mensajes_random.copy() random.shuffle(mensajes_disponibles) # Get and remove a message return mensajes_disponibles.pop()
How It Works
Initial Pool: Copies all messages from mensajes_random
Shuffle: Randomizes the order to prevent predictability
Pop: Removes and returns one message at a time
Reset: When the pool is empty, refills and shuffles again
No Repeats: Guarantees all messages are used before any repeat
The task system includes a pre-loop hook to ensure proper initialization:
main.py
@spam_periodico.before_loopasync def antes_de_spam(): """Espera a que el bot esté listo antes de iniciar el loop""" await bot.wait_until_ready() print("Sistema de spam periódico iniciado (PAUSADO por defecto)") print("Usa $activarspam para activarlo después de probar con $testspam")
The task waits for the bot to fully connect to Discord before starting. This prevents errors from trying to access channels before the bot is ready.
@bot.command(name='activarspam')@commands.has_permissions(administrator=True)async def activar_spam(ctx): """Activa el sistema de spam automático (solo admins)""" if not mensajes_random: await ctx.send("**ERROR:** No hay mensajes configurados. Agrega mensajes primero.") return if spam_periodico.is_running(): await ctx.send("El spam automático ya está activo.") else: spam_periodico.start() await ctx.send("Spam automático **ACTIVADO**. Se enviará un mensaje cada 12 horas.") print(f"[ADMIN] Spam automático activado por {ctx.author}")
@bot.command(name='desactivarspam')@commands.has_permissions(administrator=True)async def desactivar_spam(ctx): """Desactiva el sistema de spam automático (solo admins)""" if spam_periodico.is_running(): spam_periodico.cancel() await ctx.send("Spam automático **DESACTIVADO**.") print(f"[ADMIN] Spam automático desactivado por {ctx.author}") else: await ctx.send("El spam automático ya está desactivado.")
@bot.command(name='statusspam')async def status_spam(ctx): """Muestra el estado del sistema de spam""" estado = "**ACTIVO**" if spam_periodico.is_running() else "**INACTIVO**" mensajes_totales = len(mensajes_random) mensajes_restantes = len(mensajes_disponibles) info = f"""**Estado del Sistema de Spam:**{estado}Mensajes configurados: {mensajes_totales}Mensajes restantes en ciclo: {mensajes_restantes}Frecuencia: Cada 12 horasCanal: <#{CANAL_SPAM_ID}>""" await ctx.send(info)
@bot.command(name='testspam')async def test_spam(ctx): """Comando para probar el sistema de spam manualmente""" if not mensajes_random: await ctx.send("**ERROR:** No hay mensajes configurados. Agrega mensajes a la lista en el código primero.") return canal = bot.get_channel(CANAL_SPAM_ID) if canal: mensaje = obtener_mensaje_sin_repetir() await canal.send(mensaje) await ctx.send(f"Mensaje de prueba enviado a <#{CANAL_SPAM_ID}>") print(f"[TEST] Mensaje enviado: {mensaje[:50]}...") else: await ctx.send("No se encontró el canal de spam.")
The periodic task can also be controlled via natural language when mentioning the bot:
# User: "@ChimBot activate the spam"# Bot interprets and executes: $activarspam# User: "@ChimBot turn off spam"# Bot interprets and executes: $desactivarspam# User: "@ChimBot send a test message"# Bot interprets and executes: $testspam
This is handled by the interpretar_instruccion_ia() function:
main.py
async def interpretar_instruccion_ia(texto, user_id): """Usa IA para interpretar si un mensaje contiene una instrucción de comando""" prompt_interpretacion = f"""Analiza este mensaje y determina si es una INSTRUCCIÓN para ejecutar un comando del bot. Responde SOLO con uno de estos formatos: - "COMANDO:activarspam" si pide activar spam automático - "COMANDO:desactivarspam" si pide desactivar spam - "COMANDO:statusspam" si pide ver estado del spam - "COMANDO:testspam" si pide enviar un mensaje de prueba - "NO_COMANDO" si es una conversación normal sin instrucciones Mensaje: {texto}""" # ... (uses Groq to interpret)
# StartupSistema de spam periódico iniciado (PAUSADO por defecto)Usa $activarspam para activarlo después de probar con $testspam# When activated[ADMIN] Spam automático activado por AdminUser# When message is sent[14:30:45] Mensaje automático enviado: First message...# Test messages[TEST] Mensaje enviado: Test message...# When deactivated[ADMIN] Spam automático desactivado por AdminUser
Generate messages dynamically instead of using a static list:
@tasks.loop(hours=12)async def spam_periodico(): canal = bot.get_channel(CANAL_SPAM_ID) if canal: # Dynamic message with current info mensaje = f"Server has {len(canal.guild.members)} members! 🎉" await canal.send(mensaje)