¿Qué se requiere?
Algunos chicos de una comunidad de Discord empezaron a resolver captchas en el minuto 28 y 58 de cada hora del día. Es una práctica clásica de un venezolano; por esto, el momento en que deben resolver captchas le llaman "Veneco Time" (broma interna).
Suele cada uno colocar su propio temporizador y a veces se desincronizan del tiempo real en el que deben resolver los captchas.
Proyecto: Captcha Reminder Bot

Mi propuesta y solución fue un bot de Discord que notificara cuando es el momento exacto para resolver los captchas a los que tienen un rol específico.
Registro del bot
- Debí entrar en https://discord.com/developers/applications
- Click sobre New Application, me solicitó el nombre y se creó la aplicación.
- Había varias opciones y me interesó armar un bot, fuí a Bot y Add Bot
- En este punto podía cambiarle la imagen, el nombre al bot y Discord me dio un TOKEN, este TOKEN es esencial y lo usé para conectarme.

Para mayor detalle, Discord provee un paso a paso de como realizar esto, yo simplemente lo resumí:

Creando las Bases
Yo estuve trabajando con Node.js y Discord.js.
Si lo prefieres, puedes utilizar otros lenguajes que funcionen del lado del servidor, la librería de Discord.js simplemente es un wrapper para el API de Discord.
Estaba trabajando con node v16.10.0 y Discord.js v13, esta versión de Discord necesita que sea node 16.
- Primero creé el package.json gracias a
npm init
- Instalé el paquete de Discord.js con
npm install discord.js
- Creo un pequeño script y con esto ya puedo conectarme al bot ¡facilito!

Como se ve en la imagen, primero crea una instancia del cliente, logea con el token y cuando todo funciona imprime 'Captcha Bot Ready'.
Los bots de Discord, como muchos otros, funcionan a partir de eventos y websocket por dentro.

Probando el Bot
Para poder incluirlo en un servidor y probar debí generar el URL y se encontraba en el panel de desarrollador, le dí los permisos de bot y applications.commands:

¡Ya en este paso podía ver el bot conectado!
Variables de Entorno
Como en toda aplicación los tokens deben ser tratados como secretos y no hardcodearlos en el código jamás; por esto uso dotenv y un archivo .env.
Simplemente instalé dotenv y empecé a consultar el token por process.env.DISCORD_TOKEN.

Hay mas variables de entorno y estos se consiguen habilitando una opción para ver el Discord como desarrollador:

Y con solo darle click derecho a los elementos puedes extraer su ID. (Guild Id es el id del Server de Discord)
SlashCommands
Recuerdo que antes al armar un bot de Discord debías escuchar todos los mensajes y a partir de eso determinar si por alguna admiración, letra o símbolo saber si querían cambiar algo del bot; por ejemplo el famoso '!ping'
Ahora Discord trae una nueva forma de ejecutar comandos, siempre empiezan con un /[command] y provee un evento específico para escuchar dichas interacciones en tu servidor.

Primero para registrarlos se recomienda crear un archivo a parte, con todos los nombres y descripciones de los comandos:

Me fascina que puedes agregarle parámetros opcionales, requeridos, string, enteros, recibir un canal de Discord y mucho más.
De hecho estaba creando un comando para configurar el canal de Discord al cual enviar las notificaciones, pero ya era complejidad innecesaria.
Luego de crearlo, simplemente ejecutas y queda en la caché del servidor de Discord, o si quieres que sea global debes cambiar Routes.applicationGuildCommands, pero eso tarda más en reflejarse, te dejo a continuación cómo hacerlo:

Cron y su nomenclatura
El significado de cron empezó como un administrador de tareas que permite programar tareas en Unix.
Ahora existen otros sistemas y librerías como node-cron, que replican este comportamiento utilizando su nomenclatura, veamos como hacer una expresión:
Imagínate que cada minuto el sistema está revisando la expresión para hacer un algo, esa es la clave
- Posiciones: Dependiendo de la posición defines que valor quieres verificar:

En este caso estoy diciendo: "En el minuto 3, en la hora 8, del dia 28, del mes 2 (Febrero), no importa el día de la semana que caiga" haz algo.
-
Símbolos: Hay unos símbolos interesantes que ayudan mucho a la hora de hacer expresiones más complejas:
- Asterisco (*): Lo acabas de ver, significa "cualquier(a)".
- Coma (,): Un listado de valores "quiero X, quiero Y solamente".
- Guión (-): Un rango de valores "desde X, hasta Y solamente".
- "Slash" (/): Parte el valor que tiene del lado izquierdo en pasos, es una especie de "cada X"
A continuación un ejemplo del slash y otro de lo que realmente busco hacer:


Y tal cual resulta en el siguiente código con su tarea programada:

Últimos detalles
Para que no sea una molestia incontrolable, le incluí un comando de enable y disable para activar y desactivar la ejecución de la tarea:

Solo escucha el comando de enable/disable para cambiar un flag.
Despliegue
Era hora de desplegar el bot en alguna parte y utilicé un droplet de DigitalOcean que ya estaba en uso.
- Cloné el repositorio en el servidor
- Actualicé node a v16
- Instalé PM2
- Incluí las variables de entorno
PM2
Este programa ayuda a administrar y ejecutar como demonio node.

Variables de Entorno en Producción
Tenía la posibilidad de colocar las variables de entorno en línea con pm2; pero preferí crear un archivo .env con nano arriba, ya que no me estaba funcionando.
Proyecto Completo
